| // Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // VMOptions=--no-enable-fast-object-copy |
| // VMOptions=--enable-fast-object-copy |
| // VMOptions=--no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation |
| // VMOptions=--enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation |
| |
| // The tests in this file will only succeed when isolate groups are enabled |
| // (hence the VMOptions above). |
| |
| import 'dart:async'; |
| import 'dart:isolate'; |
| |
| import 'package:expect/expect.dart'; |
| |
| import 'fast_object_copy_test.dart' show ClassWithNativeFields; |
| |
| class HashThrower { |
| static bool throwOnHashCode = true; |
| |
| const HashThrower(); |
| |
| int get hashCode => throwOnHashCode ? throw 'failing' : 2; |
| bool operator ==(other) => identical(this, other); |
| } |
| |
| Future testWithClosure<T>( |
| void Function(SendPort) entrypoint, T expectedResult) async { |
| final rp = ReceivePort(); |
| try { |
| await Isolate.spawn(entrypoint, rp.sendPort); |
| Expect.equals(expectedResult, await rp.first); |
| } finally { |
| rp.close(); |
| } |
| } |
| |
| class ClosureEntrypointTester { |
| int instanceValue = 42; |
| |
| void send42(SendPort sendPort) => sendPort.send(42); |
| |
| Future run() async { |
| await noCapturedVariablesTest(); |
| await capturedInt(); |
| await capturedInstanceInt(); |
| await captureThisViaMethodTearOff(); |
| await captureInvalidObject(); |
| await captureRehashThrower(); |
| } |
| |
| Future noCapturedVariablesTest() async { |
| print('noCapturedVariablesTest'); |
| await testWithClosure((SendPort s) => s.send(42), 42); |
| } |
| |
| Future capturedInt() async { |
| print('capturedInt'); |
| int value = 42; |
| await testWithClosure((SendPort s) => s.send(value), 42); |
| } |
| |
| Future capturedInstanceInt() async { |
| print('capturedInstanceValue'); |
| await testWithClosure((SendPort s) => s.send(this.instanceValue), 42); |
| } |
| |
| Future captureThisViaMethodTearOff() async { |
| print('captureThisViaMethodTearOff'); |
| await testWithClosure(send42, 42); |
| } |
| |
| Future captureInvalidObject() async { |
| print('captureInvalidObject'); |
| final invalidObject = ClassWithNativeFields(); |
| send42(SendPort sendPort) { |
| '$invalidObject'; // Use an object that cannot be copied. |
| sendPort.send(42); |
| } |
| |
| throwsAsync<ArgumentError>(() => testWithClosure(send42, 42)); |
| } |
| |
| Future captureRehashThrower() async { |
| print('captureRehashThrower'); |
| HashThrower.throwOnHashCode = false; |
| final hashThrower = {HashThrower()}; |
| send42(SendPort sendPort) { |
| '$hashThrower'; // Use an object that cannot be deserialized. |
| sendPort.send(42); |
| } |
| |
| throwsAsync<IsolateSpawnException>(() => testWithClosure(send42, 42)); |
| } |
| |
| Future throwsAsync<T>(Future Function() fun) async { |
| try { |
| await fun(); |
| } catch (e) { |
| if (e is T) return; |
| rethrow; |
| } |
| throw 'Function failed to throw ArgumentError'; |
| } |
| } |
| |
| main() async { |
| await ClosureEntrypointTester().run(); |
| } |