blob: e3183da1a6bca145f527657fc25655c0905e3880 [file] [log] [blame]
// 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;
// Prevent fields from being optimized away as write-only.
String toString() {
return field1 +
field2 +
field3 +
field4 +
field5 +
field6 +
field7 +
field8 +
field9 +
field10 +
field11 +
field12 +
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;
// Prevent fields from being optimized away as write-only.
String toString() {
return field1 +
field2 +
field3 +
field4 +
field5 +
field6 +
field7 +
field8 +
field9 +
field10 +
field11 +
field12 +
field13 +
field14 +
field15 +
field16 +
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;
// Prevent fields from being optimized away as write-only.
String toString() {
return field1 +
field2 +
field3 +
field4 +
field5 +
field6 +
field7 +
field8 +
field9 +
field10 +
field11 +
field12 +
field13 +
field14 +
field15 +
field16 +
field17 +
field18 +
field19;
}
}
class Old {
dynamic next;
dynamic new1;
dynamic new2;
dynamic new3;
dynamic new4;
dynamic new5;
dynamic new6;
dynamic new7;
dynamic new8;
dynamic new9;
dynamic new10;
dynamic new11;
dynamic new12;
dynamic new13;
dynamic new14;
dynamic new15;
dynamic new16;
dynamic new17;
dynamic new18;
dynamic new19;
dynamic new20;
dynamic new21;
dynamic new22;
dynamic new23;
dynamic new24;
dynamic new25;
dynamic new26;
dynamic new27;
dynamic new28;
dynamic new29;
dynamic new30;
dynamic new31;
// Prevent fields from being optimized away as write-only.
String toString() {
return new1 +
new2 +
new3 +
new4 +
new5 +
new6 +
new7 +
new8 +
new9 +
new10 +
new11 +
new12 +
new13 +
new14 +
new15 +
new16 +
new17 +
new18 +
new19 +
new20 +
new21 +
new22 +
new23 +
new24 +
new25 +
new26 +
new27 +
new28 +
new29 +
new30 +
new31;
}
}
fill(old) {
// Note the allocation order is different from the field order. The objects
// will be scavenged in field order, causing the objects to be rearranged to
// produce new-space fragmentation.
old.new1 = new C();
old.new4 = new C();
old.new7 = new C();
old.new10 = new C();
old.new13 = new C();
old.new16 = new C();
old.new2 = new B();
old.new5 = new B();
old.new8 = new B();
old.new11 = new B();
old.new14 = new B();
old.new17 = new B();
old.new3 = new A();
old.new6 = new A();
old.new9 = new A();
old.new12 = new A();
old.new15 = new A();
old.new18 = new A();
}
makeOld() {
// 2/4 MB worth of Old.
print("PHASE1");
var head;
for (var i = 0; i < 16384; i++) {
var old = new Old();
old.next = head;
head = old;
}
// 32/64 MB worth of new objects, all directly reachable from the
// remembered set.
print("PHASE2");
for (var old = head; old != null; old = old.next) {
fill(old);
}
print("PHASE3");
return head;
}
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.
print(makeOld());
return;
}
var exec = Platform.executable;
var args = Platform.executableArguments +
[
"--new_gen_semi_max_size=4" /*MB*/,
"--old_gen_heap_size=15" /*MB*/,
"--verbose_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");
Expect.isFalse(result.stderr.contains("error: Out of memory"),
"Should not see the C++ OUT_OF_MEMORY()");
}