| // Copyright (c) 2020, 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. |
| |
| import "dart:io"; |
| import "package:expect/expect.dart"; |
| |
| // The sizes of these classes are co-prime multiples of the allocation unit to |
| // increase the likelihood that scavenging fails from fragmentation. |
| |
| // header + 13 fields = 7 allocation units |
| class A { |
| dynamic field1; |
| dynamic field2; |
| dynamic field3; |
| dynamic field4; |
| dynamic field5; |
| dynamic field6; |
| dynamic field7; |
| dynamic field8; |
| dynamic field9; |
| dynamic field10; |
| dynamic field11; |
| dynamic field12; |
| dynamic field13; |
| } |
| |
| // header + 17 fields = 9 allocation units |
| class B { |
| dynamic field1; |
| dynamic field2; |
| dynamic field3; |
| dynamic field4; |
| dynamic field5; |
| dynamic field6; |
| dynamic field7; |
| dynamic field8; |
| dynamic field9; |
| dynamic field10; |
| dynamic field11; |
| dynamic field12; |
| dynamic field13; |
| dynamic field14; |
| dynamic field15; |
| dynamic field16; |
| dynamic field17; |
| } |
| |
| // header + 19 fields = 10 allocation units |
| class C { |
| dynamic field1; |
| dynamic field2; |
| dynamic field3; |
| dynamic field4; |
| dynamic field5; |
| dynamic field6; |
| dynamic field7; |
| dynamic field8; |
| dynamic field9; |
| dynamic field10; |
| dynamic field11; |
| dynamic field12; |
| dynamic field13; |
| dynamic field14; |
| dynamic field15; |
| dynamic field16; |
| dynamic field17; |
| dynamic field18; |
| dynamic field19; |
| } |
| |
| makeA(n) { |
| var a = new A(); |
| if (n > 0) { |
| a.field1 = makeB(n - 1); |
| a.field2 = makeC(n - 1); |
| a.field3 = makeB(n - 1); |
| a.field4 = makeC(n - 1); |
| } |
| return a; |
| } |
| |
| makeB(n) { |
| var b = new B(); |
| if (n > 0) { |
| b.field1 = makeC(n - 1); |
| b.field2 = makeA(n - 1); |
| b.field3 = makeC(n - 1); |
| b.field4 = makeA(n - 1); |
| } |
| return b; |
| } |
| |
| makeC(n) { |
| var c = new C(); |
| if (n > 0) { |
| c.field1 = makeA(n - 1); |
| c.field2 = makeB(n - 1); |
| c.field3 = makeA(n - 1); |
| c.field4 = makeB(n - 1); |
| } |
| return c; |
| } |
| |
| readFields(x) { |
| print(x.field1); |
| print(x.field2); |
| print(x.field3); |
| print(x.field4); |
| } |
| |
| main(List<String> argsIn) async { |
| if (argsIn.contains("--testee")) { |
| // Trigger OOM. |
| // Must read the fields to prevent the writes from being optimized away. If |
| // the writes are optimized away, most of the tree is collectible right away |
| // and we timeout instead of triggering OOM. |
| readFields(makeA(50)); |
| readFields(makeB(50)); |
| readFields(makeC(50)); |
| return; |
| } |
| |
| var exec = Platform.executable; |
| var args = Platform.executableArguments + |
| [ |
| "--old_gen_heap_size=15" /*MB*/, |
| "--verbose_gc", |
| "--verify_after_gc", |
| "--verify_store_buffer", |
| Platform.script.toFilePath(), |
| "--testee" |
| ]; |
| print("+ $exec ${args.join(' ')}"); |
| |
| var result = await Process.run(exec, args); |
| print("Command stdout:"); |
| print(result.stdout); |
| print("Command stderr:"); |
| print(result.stderr); |
| |
| Expect.equals(255, result.exitCode, |
| "Should see runtime exception error code, not SEGV"); |
| |
| Expect.isTrue( |
| result.stderr.contains("Unhandled exception:\nOut of Memory") || |
| result.stderr.contains("Unhandled exception:\r\nOut of Memory"), |
| "Should see the Dart OutOfMemoryError"); |
| |
| // --verbose_gc not available in product mode |
| if (!new bool.fromEnvironment("dart.vm.product")) { |
| Expect.isTrue(result.stderr.contains("Aborting scavenge"), |
| "Should abort scavenge at least once"); |
| } |
| |
| Expect.isFalse(result.stderr.contains("error: Out of memory"), |
| "Should not see the C++ OUT_OF_MEMORY()"); |
| } |