Version 2.12.0-30.0.dev
Merge commit '82320be8d96530cdbdcbea2abd06f113afacd9ff' into 'dev'
diff --git a/DEPS b/DEPS
index 51d9353..bdb73d4 100644
--- a/DEPS
+++ b/DEPS
@@ -116,19 +116,19 @@
"idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
"intl_tag": "0.17.0-nullsafety",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
- "json_rpc_2_rev": "8f189db8f0c299187a0e8fa959dba7e9b0254be5",
+ "json_rpc_2_rev": "b8dfe403fd8528fd14399dee3a6527b55802dd4d",
"linter_tag": "0.1.124",
"logging_rev": "9d2a7fdd05b09bc06474881152b5baaf38fd1329",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"markdown_rev": "6f89681d59541ddb1cf3a58efbdaa2304ffc3f51",
"matcher_rev": "9cae8faa7868bf3a88a7ba45eb0bd128e66ac515",
- "mime_tag": "0.9.7",
+ "mime_rev": "07635f7774447503248fbc6afb3911e9000a477e",
"mockito_rev": "d39ac507483b9891165e422ec98d9fb480037c8b",
"mustache_rev": "664737ecad027e6b96d0d1e627257efa0e46fcb1",
"oauth2_tag": "1.6.0",
"package_config_rev": "9c586d04bd26fef01215fd10e7ab96a3050cfa64",
"path_rev": "62ecd5a78ffe5734d14ed0df76d20309084cd04a",
- "pedantic_rev": "24b38df72430d7e21cb4257828580becb9a39c72",
+ "pedantic_rev": "a884ea2db943b8756cc94385990bd750aec06928",
"ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_rev": "eedbd5fde84f9a1a8da643b475305a81841da599",
"protobuf_rev": "3746c8fd3f2b0147623a8e3db89c3ff4330de760",
@@ -137,7 +137,7 @@
"resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
"root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
"rust_revision": "b7856f695d65a8ebc846754f97d15814bcb1c244",
- "shelf_static_rev": "v0.2.8",
+ "shelf_static_rev": "a6168f162df88b0eef7e328629bf020122d5039e",
"shelf_packages_handler_tag": "2.0.0",
"shelf_proxy_tag": "0.1.0+7",
"shelf_rev": "289309adc6c39aab0a63db676d550c517fc1cc2d",
@@ -368,7 +368,7 @@
Var("dart_root") + "/third_party/pkg/matcher":
Var("dart_git") + "matcher.git" + "@" + Var("matcher_rev"),
Var("dart_root") + "/third_party/pkg/mime":
- Var("dart_git") + "mime.git" + "@" + Var("mime_tag"),
+ Var("dart_git") + "mime.git" + "@" + Var("mime_rev"),
Var("dart_root") + "/third_party/pkg/mockito":
Var("dart_git") + "mockito.git" + "@" + Var("mockito_rev"),
Var("dart_root") + "/third_party/pkg/mustache":
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_elimination_nnbd_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_elimination_nnbd_test.dart
index dcad472..d32c54a 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_elimination_nnbd_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_elimination_nnbd_test.dart
@@ -6,7 +6,7 @@
import 'package:front_end/src/fasta/type_inference/type_schema_elimination.dart'
as typeSchemaElimination;
import 'package:kernel/ast.dart';
-import 'package:kernel/core_types.dart';
+import 'package:kernel/testing/type_parser_environment.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -18,13 +18,10 @@
@reflectiveTest
class TypeSchemaEliminationTest {
- static const DartType unknownType = const UnknownType();
-
- CoreTypes coreTypes = new _MockCoreTypes();
-
- DartType get dynamicType => const DynamicType();
-
- DartType get nullType => new NullType();
+ final Env env = new Env("");
+ final Map<String, DartType Function()> additionalTypes = {
+ "UNKNOWN": () => new UnknownType()
+ };
DartType greatestClosure(DartType schema) {
return typeSchemaElimination.greatestClosure(
@@ -36,116 +33,62 @@
schema, const DynamicType(), const NeverType(Nullability.nonNullable));
}
+ void testGreatest(String type, String expectedClosure) {
+ expect(
+ greatestClosure(env.parseType(type, additionalTypes: additionalTypes)),
+ env.parseType(expectedClosure, additionalTypes: additionalTypes));
+ }
+
+ void testLeast(String type, String expectedClosure) {
+ expect(leastClosure(env.parseType(type, additionalTypes: additionalTypes)),
+ env.parseType(expectedClosure, additionalTypes: additionalTypes));
+ }
+
void test_greatestClosure_contravariant() {
- expect(
- greatestClosure(new FunctionType(
- [unknownType], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '(Never) →* dynamic');
- expect(
- greatestClosure(new FunctionType([], dynamicType, Nullability.legacy,
- namedParameters: [new NamedType('foo', unknownType)]))
- .leakingDebugToString(),
- '({foo: Never}) →* dynamic');
+ testGreatest("(UNKNOWN) ->* dynamic", "(Never) ->* dynamic");
+ testGreatest("({UNKNOWN foo}) ->* dynamic", "({Never foo}) ->* dynamic");
}
void test_greatestClosure_contravariant_contravariant() {
- expect(
- greatestClosure(new FunctionType([
- new FunctionType([unknownType], dynamicType, Nullability.legacy)
- ], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '((dynamic) →* dynamic) →* dynamic');
+ testGreatest("((UNKNOWN) ->* dynamic) ->* dynamic",
+ "((dynamic) ->* dynamic) ->* dynamic");
}
void test_greatestClosure_covariant() {
- expect(
- greatestClosure(new FunctionType([], unknownType, Nullability.legacy))
- .leakingDebugToString(),
- '() →* dynamic');
- expect(
- greatestClosure(new InterfaceType(
- coreTypes.listClass, Nullability.legacy, [unknownType]))
- .leakingDebugToString(),
- 'dart.core::List<dynamic>*');
+ testGreatest("() ->* UNKNOWN", "() ->* dynamic");
+ testGreatest("List<UNKNOWN>*", "List<dynamic>*");
}
void test_greatestClosure_function_multipleUnknown() {
- expect(
- greatestClosure(new FunctionType(
- [unknownType, unknownType], unknownType, Nullability.legacy,
- namedParameters: [
- new NamedType('a', unknownType),
- new NamedType('b', unknownType)
- ])).leakingDebugToString(),
- '(Never, Never, {a: Never, b: Never}) →* dynamic');
+ testGreatest("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
+ "(Never, Never, {Never a, Never b}) ->* dynamic");
}
void test_greatestClosure_simple() {
- expect(greatestClosure(unknownType).leakingDebugToString(), 'dynamic');
+ testGreatest("UNKNOWN", "dynamic");
}
void test_leastClosure_contravariant() {
- expect(
- leastClosure(new FunctionType(
- [unknownType], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '(dynamic) →* dynamic');
- expect(
- leastClosure(new FunctionType([], dynamicType, Nullability.legacy,
- namedParameters: [new NamedType('foo', unknownType)]))
- .leakingDebugToString(),
- '({foo: dynamic}) →* dynamic');
+ testLeast("(UNKNOWN) ->* dynamic", "(dynamic) ->* dynamic");
+ testLeast("({UNKNOWN foo}) ->* dynamic", "({dynamic foo}) ->* dynamic");
}
void test_leastClosure_contravariant_contravariant() {
- expect(
- leastClosure(new FunctionType([
- new FunctionType([unknownType], dynamicType, Nullability.legacy)
- ], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '((Never) →* dynamic) →* dynamic');
+ testLeast("((UNKNOWN) ->* dynamic) ->* dynamic",
+ "((Never) ->* dynamic) ->* dynamic");
}
void test_leastClosure_covariant() {
- expect(
- leastClosure(new FunctionType([], unknownType, Nullability.legacy))
- .leakingDebugToString(),
- '() →* Never');
- expect(
- leastClosure(new InterfaceType(
- coreTypes.listClass, Nullability.legacy, [unknownType]))
- .leakingDebugToString(),
- 'dart.core::List<Never>*');
+ testLeast("() ->* UNKNOWN", "() ->* Never");
+ testLeast("List<UNKNOWN>*", "List<Never>*");
}
void test_leastClosure_function_multipleUnknown() {
- expect(
- leastClosure(new FunctionType(
- [unknownType, unknownType], unknownType, Nullability.legacy,
- namedParameters: [
- new NamedType('a', unknownType),
- new NamedType('b', unknownType)
- ])).leakingDebugToString(),
- '(dynamic, dynamic, {a: dynamic, b: dynamic}) →* Never');
+ testLeast("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
+ "(dynamic, dynamic, {dynamic a, dynamic b}) ->* Never");
}
void test_leastClosure_simple() {
- expect(leastClosure(unknownType).leakingDebugToString(), 'Never');
+ testLeast("UNKNOWN", "Never");
}
}
-
-class _MockCoreTypes implements CoreTypes {
- @override
- final Class listClass = new Class(name: 'List');
-
- @override
- final Class objectClass = new Class(name: 'Object');
-
- _MockCoreTypes() {
- new Library(Uri.parse('dart:core'),
- name: 'dart.core', classes: [listClass, objectClass]);
- }
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_elimination_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_elimination_test.dart
index a4c8ee3..dd4a329 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_elimination_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_elimination_test.dart
@@ -6,7 +6,7 @@
import 'package:front_end/src/fasta/type_inference/type_schema_elimination.dart'
as typeSchemaElimination;
import 'package:kernel/ast.dart';
-import 'package:kernel/core_types.dart';
+import 'package:kernel/testing/type_parser_environment.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -18,134 +18,77 @@
@reflectiveTest
class TypeSchemaEliminationTest {
- static const DartType unknownType = const UnknownType();
-
- CoreTypes coreTypes = new _MockCoreTypes();
-
- DartType get dynamicType => const DynamicType();
-
- DartType get objectType => coreTypes.objectLegacyRawType;
+ final Env env = new Env("");
+ final Map<String, DartType Function()> additionalTypes = {
+ "UNKNOWN": () => new UnknownType()
+ };
DartType greatestClosure(DartType schema) {
return typeSchemaElimination.greatestClosure(
- schema, dynamicType, const NullType());
+ schema, new DynamicType(), new NullType());
}
DartType leastClosure(DartType schema) {
return typeSchemaElimination.leastClosure(
- schema, dynamicType, const NullType());
+ schema, new DynamicType(), new NullType());
+ }
+
+ void testGreatest(String type, String expectedClosure) {
+ expect(
+ greatestClosure(env.parseType(type, additionalTypes: additionalTypes)),
+ env.parseType(expectedClosure, additionalTypes: additionalTypes));
+ }
+
+ void testLeast(String type, String expectedClosure) {
+ expect(leastClosure(env.parseType(type, additionalTypes: additionalTypes)),
+ env.parseType(expectedClosure, additionalTypes: additionalTypes));
}
void test_greatestClosure_contravariant() {
- expect(
- greatestClosure(new FunctionType(
- [unknownType], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '(Null) →* dynamic');
- expect(
- greatestClosure(new FunctionType([], dynamicType, Nullability.legacy,
- namedParameters: [new NamedType('foo', unknownType)]))
- .leakingDebugToString(),
- '({foo: Null}) →* dynamic');
+ testGreatest("(UNKNOWN) ->* dynamic", "(Null) ->* dynamic");
+ testGreatest("({UNKNOWN foo}) ->* dynamic", "({Null foo}) ->* dynamic");
}
void test_greatestClosure_contravariant_contravariant() {
- expect(
- greatestClosure(new FunctionType([
- new FunctionType([unknownType], dynamicType, Nullability.legacy)
- ], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '((dynamic) →* dynamic) →* dynamic');
+ testGreatest("((UNKNOWN) ->* dynamic) ->* dynamic",
+ "((dynamic) ->* dynamic) ->* dynamic");
}
void test_greatestClosure_covariant() {
- expect(
- greatestClosure(new FunctionType([], unknownType, Nullability.legacy))
- .leakingDebugToString(),
- '() →* dynamic');
- expect(
- greatestClosure(new InterfaceType(
- coreTypes.listClass, Nullability.legacy, [unknownType]))
- .leakingDebugToString(),
- 'dart.core::List<dynamic>*');
+ testGreatest("() ->* UNKNOWN", "() ->* dynamic");
+ testGreatest("List<UNKNOWN>*", "List<dynamic>*");
}
void test_greatestClosure_function_multipleUnknown() {
- expect(
- greatestClosure(new FunctionType(
- [unknownType, unknownType], unknownType, Nullability.legacy,
- namedParameters: [
- new NamedType('a', unknownType),
- new NamedType('b', unknownType)
- ])).leakingDebugToString(),
- '(Null, Null, {a: Null, b: Null}) →* dynamic');
+ testGreatest("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
+ "(Null, Null, {Null a, Null b}) ->* dynamic");
}
void test_greatestClosure_simple() {
- expect(greatestClosure(unknownType).leakingDebugToString(), 'dynamic');
+ testGreatest("UNKNOWN", "dynamic");
}
void test_leastClosure_contravariant() {
- expect(
- leastClosure(new FunctionType(
- [unknownType], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '(dynamic) →* dynamic');
- expect(
- leastClosure(new FunctionType([], dynamicType, Nullability.legacy,
- namedParameters: [new NamedType('foo', unknownType)]))
- .leakingDebugToString(),
- '({foo: dynamic}) →* dynamic');
+ testLeast("(UNKNOWN) ->* dynamic", "(dynamic) ->* dynamic");
+ testLeast("({UNKNOWN foo}) ->* dynamic", "({dynamic foo}) ->* dynamic");
}
void test_leastClosure_contravariant_contravariant() {
- expect(
- leastClosure(new FunctionType([
- new FunctionType([unknownType], dynamicType, Nullability.legacy)
- ], dynamicType, Nullability.legacy))
- .leakingDebugToString(),
- '((Null) →* dynamic) →* dynamic');
+ testLeast("((UNKNOWN) ->* UNKNOWN) ->* dynamic",
+ "((Null) ->* dynamic) ->* dynamic");
}
void test_leastClosure_covariant() {
- expect(
- leastClosure(new FunctionType([], unknownType, Nullability.legacy))
- .leakingDebugToString(),
- '() →* Null');
- expect(
- leastClosure(new InterfaceType(
- coreTypes.listClass, Nullability.legacy, [unknownType]))
- .leakingDebugToString(),
- 'dart.core::List<Null>*');
+ testLeast("() ->* UNKNOWN", "() ->* Null");
+ testLeast("List<UNKNOWN>*", "List<Null>*");
}
void test_leastClosure_function_multipleUnknown() {
- expect(
- leastClosure(new FunctionType(
- [unknownType, unknownType], unknownType, Nullability.legacy,
- namedParameters: [
- new NamedType('a', unknownType),
- new NamedType('b', unknownType)
- ])).leakingDebugToString(),
- '(dynamic, dynamic, {a: dynamic, b: dynamic}) →* Null');
+ testLeast("(UNKNOWN, UNKNOWN, {UNKNOWN a, UNKNOWN b}) ->* UNKNOWN",
+ "(dynamic, dynamic, {dynamic a, dynamic b}) ->* Null");
}
void test_leastClosure_simple() {
- expect(leastClosure(unknownType).leakingDebugToString(), 'Null');
+ testLeast("UNKNOWN", "Null");
}
}
-
-class _MockCoreTypes implements CoreTypes {
- @override
- final Class listClass = new Class(name: 'List');
-
- @override
- final Class objectClass = new Class(name: 'Object');
-
- _MockCoreTypes() {
- new Library(Uri.parse('dart:core'),
- name: 'dart.core', classes: [listClass, objectClass]);
- }
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 5255e56..7806bde 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -1784,6 +1784,7 @@
maintains
major
make
+makers
makes
making
malformed
diff --git a/pkg/kernel/lib/testing/type_parser_environment.dart b/pkg/kernel/lib/testing/type_parser_environment.dart
index 8989064..757ee7a 100644
--- a/pkg/kernel/lib/testing/type_parser_environment.dart
+++ b/pkg/kernel/lib/testing/type_parser_environment.dart
@@ -114,8 +114,10 @@
coreTypes = new CoreTypes(component);
}
- DartType parseType(String text) {
- return _libraryEnvironment.parseType(text);
+ DartType parseType(String text,
+ {Map<String, DartType Function()> additionalTypes}) {
+ return _libraryEnvironment.parseType(text,
+ additionalTypes: additionalTypes);
}
void extendWithTypeParameters(String typeParameters) {
@@ -154,13 +156,17 @@
TypeParserEnvironment(this.uri, this.fileUri, [this._parent]);
- Node _kernelFromParsedType(ParsedType type) {
- Node node = type.accept(const _KernelFromParsedType(), this);
+ Node _kernelFromParsedType(ParsedType type,
+ {Map<String, DartType Function()> additionalTypes}) {
+ Node node = type.accept(
+ new _KernelFromParsedType(additionalTypes: additionalTypes), this);
return node;
}
- DartType parseType(String text) {
- return _kernelFromParsedType(type_parser.parse(text).single);
+ DartType parseType(String text,
+ {Map<String, DartType Function()> additionalTypes}) {
+ return _kernelFromParsedType(type_parser.parse(text).single,
+ additionalTypes: additionalTypes);
}
bool isObject(String name) => name == "Object" && "$uri" == "dart:core";
@@ -209,7 +215,9 @@
}
class _KernelFromParsedType implements Visitor<Node, TypeParserEnvironment> {
- const _KernelFromParsedType();
+ final Map<String, DartType Function()> additionalTypes; // Can be null.
+
+ const _KernelFromParsedType({this.additionalTypes});
DartType visitInterfaceType(
ParsedInterfaceType node, TypeParserEnvironment environment) {
@@ -237,6 +245,8 @@
// Don't return a const object to ensure we test implementations that use
// identical.
return new NullType();
+ } else if (additionalTypes != null && additionalTypes.containsKey(name)) {
+ return additionalTypes[name].call();
}
TreeNode declaration = environment.lookupDeclaration(name);
List<ParsedType> arguments = node.arguments;
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 8f0d07d..3428443 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -99,10 +99,6 @@
static const previewPortOption = 'preview-port';
static const sdkPathOption = 'sdk-path';
static const skipImportCheckFlag = 'skip-import-check';
-
- /// TODO(paulberry): remove this flag once internal sources have been updated.
- @Deprecated('The migration tool no longer performs "pub outdated" checks')
- static const skipPubOutdatedFlag = 'skip-pub-outdated';
static const summaryOption = 'summary';
static const verboseFlag = 'verbose';
static const webPreviewFlag = 'web-preview';
@@ -128,36 +124,16 @@
final bool webPreview;
CommandLineOptions(
- {@required
- this.applyChanges,
- @required
- this.directory,
- @required
- this.ignoreErrors,
- @required
- this.ignoreExceptions,
- @required
- this.previewHostname,
- @required
- this.previewPort,
- @required
- this.sdkPath,
- // TODO(paulberry): make this parameter required once internal sources
- // have been updated.
- bool skipImportCheck,
- // TODO(paulberry): remove this flag once internal sources have been
- // updated.
- @Deprecated('The migration tool no longer performs "pub outdated" checks')
- bool skipPubOutdated = false,
- @required
- this.summary,
- @required
- this.webPreview})
- // `skipImportCheck` has replaced `skipPubOutdated`, so if the caller
- // specifies the latter but not the former, carry it over.
- // TODO(paulberry): remove this logic once internal sources have been
- // updated.
- : skipImportCheck = skipImportCheck ?? skipPubOutdated;
+ {@required this.applyChanges,
+ @required this.directory,
+ @required this.ignoreErrors,
+ @required this.ignoreExceptions,
+ @required this.previewHostname,
+ @required this.previewPort,
+ @required this.sdkPath,
+ @required this.skipImportCheck,
+ @required this.summary,
+ @required this.webPreview});
}
// TODO(devoncarew): Refactor so this class extends DartdevCommand.
diff --git a/runtime/tests/vm/dart/scavenger_abort_2_test.dart b/runtime/tests/vm/dart/scavenger_abort_2_test.dart
new file mode 100644
index 0000000..e3183da
--- /dev/null
+++ b/runtime/tests/vm/dart/scavenger_abort_2_test.dart
@@ -0,0 +1,288 @@
+// 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()");
+}
diff --git a/runtime/tests/vm/dart_2/scavenger_abort_2_test.dart b/runtime/tests/vm/dart_2/scavenger_abort_2_test.dart
new file mode 100644
index 0000000..e3183da
--- /dev/null
+++ b/runtime/tests/vm/dart_2/scavenger_abort_2_test.dart
@@ -0,0 +1,288 @@
+// 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()");
+}
diff --git a/runtime/vm/compiler/ffi/marshaller.cc b/runtime/vm/compiler/ffi/marshaller.cc
index c095e9e..6620468 100644
--- a/runtime/vm/compiler/ffi/marshaller.cc
+++ b/runtime/vm/compiler/ffi/marshaller.cc
@@ -4,9 +4,13 @@
#include "vm/compiler/ffi/marshaller.h"
+#include "platform/assert.h"
+#include "platform/globals.h"
#include "vm/compiler/ffi/frame_rebase.h"
+#include "vm/compiler/ffi/native_calling_convention.h"
#include "vm/compiler/ffi/native_location.h"
#include "vm/compiler/ffi/native_type.h"
+#include "vm/log.h"
#include "vm/raw_object.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
@@ -17,6 +21,56 @@
namespace ffi {
+// Argument #0 is the function pointer.
+const intptr_t kNativeParamsStartAt = 1;
+
+// Representations of the arguments and return value of a C signature function.
+static const NativeFunctionType& NativeFunctionSignature(
+ Zone* zone,
+ const Function& c_signature) {
+ ASSERT(c_signature.NumOptionalParameters() == 0);
+ ASSERT(c_signature.NumOptionalPositionalParameters() == 0);
+
+ const intptr_t num_arguments =
+ c_signature.num_fixed_parameters() - kNativeParamsStartAt;
+ auto& argument_representations =
+ *new ZoneGrowableArray<const NativeType*>(zone, num_arguments);
+ for (intptr_t i = 0; i < num_arguments; i++) {
+ AbstractType& arg_type = AbstractType::Handle(
+ zone, c_signature.ParameterTypeAt(i + kNativeParamsStartAt));
+ const auto& rep = NativeType::FromAbstractType(zone, arg_type);
+ argument_representations.Add(&rep);
+ }
+
+ const auto& result_type =
+ AbstractType::Handle(zone, c_signature.result_type());
+ const auto& result_representation =
+ NativeType::FromAbstractType(zone, result_type);
+
+ const auto& result = *new (zone) NativeFunctionType(argument_representations,
+ result_representation);
+ return result;
+}
+
+BaseMarshaller::BaseMarshaller(Zone* zone, const Function& dart_signature)
+ : zone_(zone),
+ dart_signature_(dart_signature),
+ c_signature_(Function::ZoneHandle(zone, dart_signature.FfiCSignature())),
+ native_calling_convention_(NativeCallingConvention::FromSignature(
+ zone,
+ NativeFunctionSignature(zone_, c_signature_))) {
+ ASSERT(dart_signature_.IsZoneHandle());
+}
+
+AbstractTypePtr BaseMarshaller::CType(intptr_t arg_index) const {
+ if (arg_index == kResultIndex) {
+ return c_signature_.result_type();
+ }
+
+ // Skip #0 argument, the function pointer.
+ return c_signature_.ParameterTypeAt(arg_index + kNativeParamsStartAt);
+}
+
bool BaseMarshaller::ContainsHandles() const {
return dart_signature_.FfiCSignatureContainsHandles();
}
@@ -80,14 +134,14 @@
static NativeLocations& TranslateArgumentLocations(
Zone* zone,
const NativeLocations& arg_locs) {
- auto& pushed_locs = *(new NativeLocations(arg_locs.length()));
+ auto& pushed_locs = *(new (zone) NativeLocations(arg_locs.length()));
CallbackArgumentTranslator translator;
for (intptr_t i = 0, n = arg_locs.length(); i < n; i++) {
translator.AllocateArgument(*arg_locs[i]);
}
for (intptr_t i = 0, n = arg_locs.length(); i < n; ++i) {
- pushed_locs.Add(&translator.TranslateArgument(*arg_locs[i], zone));
+ pushed_locs.Add(&translator.TranslateArgument(zone, *arg_locs[i]));
}
return pushed_locs;
@@ -97,16 +151,17 @@
void AllocateArgument(const NativeLocation& arg) {
if (arg.IsStack()) return;
- ASSERT(arg.IsRegisters() || arg.IsFpuRegisters());
if (arg.IsRegisters()) {
argument_slots_required_ += arg.AsRegisters().num_regs();
- } else {
+ } else if (arg.IsFpuRegisters()) {
argument_slots_required_ += 8 / target::kWordSize;
+ } else {
+ UNREACHABLE();
}
}
- const NativeLocation& TranslateArgument(const NativeLocation& arg,
- Zone* zone) {
+ const NativeLocation& TranslateArgument(Zone* zone,
+ const NativeLocation& arg) {
if (arg.IsStack()) {
// Add extra slots after the saved arguments for the return address and
// frame pointer of the dummy arguments frame, which will be between the
@@ -152,10 +207,9 @@
CallbackMarshaller::CallbackMarshaller(Zone* zone,
const Function& dart_signature)
: BaseMarshaller(zone, dart_signature),
- callback_locs_(
- CallbackArgumentTranslator::TranslateArgumentLocations(zone_,
- arg_locs_)) {}
-
+ callback_locs_(CallbackArgumentTranslator::TranslateArgumentLocations(
+ zone_,
+ native_calling_convention_.argument_locations())) {}
} // namespace ffi
} // namespace compiler
diff --git a/runtime/vm/compiler/ffi/marshaller.h b/runtime/vm/compiler/ffi/marshaller.h
index d175ddc..be567b6 100644
--- a/runtime/vm/compiler/ffi/marshaller.h
+++ b/runtime/vm/compiler/ffi/marshaller.h
@@ -11,6 +11,7 @@
#include <platform/globals.h>
+#include "platform/assert.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/ffi/callback.h"
#include "vm/compiler/ffi/native_calling_convention.h"
@@ -24,16 +25,32 @@
namespace ffi {
+// Values below 0 index result (result might be multiple if composite).
+const intptr_t kResultIndex = -1;
+
// Provides the mapping from the native calling convention to the Dart calling
// convention.
//
// This class is set up in a query-able way so that it's underlying logic can
// be extended to support more native ABI features and calling conventions.
-//
-// TODO(36730): Add a way to query arguments that are broken into multiple
-// parts.
-class BaseMarshaller : public NativeCallingConvention {
+class BaseMarshaller : public ZoneAllocated {
public:
+ intptr_t num_args() const {
+ return native_calling_convention_.argument_locations().length();
+ }
+
+ intptr_t StackTopInBytes() const {
+ return native_calling_convention_.StackTopInBytes();
+ }
+
+ // The location of the argument at `arg_index`.
+ const NativeLocation& Location(intptr_t arg_index) const {
+ if (arg_index == kResultIndex) {
+ return native_calling_convention_.return_location();
+ }
+ return *native_calling_convention_.argument_locations().At(arg_index);
+ }
+
// Unboxed representation on how the value is passed or received from regular
// Dart code.
Representation RepInDart(intptr_t arg_index) const {
@@ -62,6 +79,11 @@
return Location(arg_index).payload_type();
}
+ // The C Type (expressed in a Dart Type) of the argument at `arg_index`.
+ //
+ // Excluding the #0 argument which is the function pointer.
+ AbstractTypePtr CType(intptr_t arg_index) const;
+
// Requires boxing or unboxing.
bool IsPointer(intptr_t arg_index) const {
return AbstractType::Handle(zone_, CType(arg_index)).type_class_id() ==
@@ -83,18 +105,16 @@
StringPtr function_name() const { return dart_signature_.name(); }
protected:
- BaseMarshaller(Zone* zone, const Function& dart_signature)
- : NativeCallingConvention(
- zone,
- Function::ZoneHandle(zone, dart_signature.FfiCSignature())),
- dart_signature_(dart_signature) {
- ASSERT(dart_signature_.IsZoneHandle());
- }
+ BaseMarshaller(Zone* zone, const Function& dart_signature);
- private:
+ ~BaseMarshaller() {}
+
+ Zone* zone_;
// Contains the function pointer as argument #0.
// The Dart signature is used for the function and argument names.
const Function& dart_signature_;
+ const Function& c_signature_;
+ const NativeCallingConvention& native_calling_convention_;
};
class CallMarshaller : public BaseMarshaller {
@@ -103,6 +123,9 @@
: BaseMarshaller(zone, dart_signature) {}
dart::Location LocInFfiCall(intptr_t arg_index) const;
+
+ protected:
+ ~CallMarshaller() {}
};
class CallbackMarshaller : public BaseMarshaller {
@@ -125,6 +148,8 @@
}
protected:
+ ~CallbackMarshaller() {}
+
const NativeLocations& callback_locs_;
};
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.cc b/runtime/vm/compiler/ffi/native_calling_convention.cc
index 84081aa..2ac1445 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.cc
+++ b/runtime/vm/compiler/ffi/native_calling_convention.cc
@@ -16,9 +16,6 @@
namespace ffi {
-// Argument #0 is the function pointer.
-const intptr_t kNativeParamsStartAt = 1;
-
const intptr_t kNoFpuRegister = -1;
// In Soft FP, floats and doubles get passed in integer registers.
@@ -44,29 +41,6 @@
return rep;
}
-// Representations of the arguments to a C signature function.
-static ZoneGrowableArray<const NativeType*>& ArgumentRepresentations(
- Zone* zone,
- const Function& signature) {
- const intptr_t num_arguments =
- signature.num_fixed_parameters() - kNativeParamsStartAt;
- auto& result = *new ZoneGrowableArray<const NativeType*>(zone, num_arguments);
- for (intptr_t i = 0; i < num_arguments; i++) {
- AbstractType& arg_type = AbstractType::Handle(
- zone, signature.ParameterTypeAt(i + kNativeParamsStartAt));
- const auto& rep = NativeType::FromAbstractType(zone, arg_type);
- result.Add(&rep);
- }
- return result;
-}
-
-// Representation of the result of a C signature function.
-static NativeType& ResultRepresentation(Zone* zone, const Function& signature) {
- AbstractType& result_type =
- AbstractType::Handle(zone, signature.result_type());
- return NativeType::FromAbstractType(zone, result_type);
-}
-
// Represents the state of a stack frame going into a call, between allocations
// of argument locations.
class ArgumentAllocator : public ValueObject {
@@ -90,9 +64,9 @@
if (CallingConventions::kArgumentIntRegXorFpuReg) {
ASSERT(cpu_regs_used == CallingConventions::kNumArgRegs);
}
+ // Transfer on stack.
}
- } else {
- ASSERT(payload_type_converted.IsInt());
+ } else if (payload_type_converted.IsInt()) {
// Some calling conventions require the callee to make the lowest 32 bits
// in registers non-garbage.
const auto& container_type =
@@ -115,8 +89,12 @@
if (cpu_regs_used + 1 <= CallingConventions::kNumArgRegs) {
return *new (zone_) NativeRegistersLocation(
payload_type, container_type, AllocateCpuRegister());
+ } else {
+ // Transfer on stack.
}
}
+ } else {
+ UNREACHABLE();
}
return AllocateStack(payload_type);
@@ -227,7 +205,7 @@
Zone* zone,
const ZoneGrowableArray<const NativeType*>& arg_reps) {
intptr_t num_arguments = arg_reps.length();
- auto& result = *new NativeLocations(zone, num_arguments);
+ auto& result = *new (zone) NativeLocations(zone, num_arguments);
// Loop through all arguments and assign a register or a stack location.
ArgumentAllocator frame_state(zone);
@@ -239,8 +217,8 @@
}
// Location for the result of a C signature function.
-static NativeLocation& ResultLocation(Zone* zone,
- const NativeType& payload_type) {
+static const NativeLocation& ResultLocation(Zone* zone,
+ const NativeType& payload_type) {
const auto& payload_type_converted = ConvertIfSoftFp(zone, payload_type);
const auto& container_type =
CallingConventions::kReturnRegisterExtension == kExtendedTo4
@@ -263,46 +241,45 @@
CallingConventions::kReturnReg);
}
-NativeCallingConvention::NativeCallingConvention(Zone* zone,
- const Function& c_signature)
- : zone_(ASSERT_NOTNULL(zone)),
- c_signature_(c_signature),
- arg_locs_(
- ArgumentLocations(zone_,
- ArgumentRepresentations(zone_, c_signature_))),
- result_loc_(
- ResultLocation(zone_, ResultRepresentation(zone_, c_signature_))) {}
-
-intptr_t NativeCallingConvention::num_args() const {
- ASSERT(c_signature_.NumOptionalParameters() == 0);
- ASSERT(c_signature_.NumOptionalPositionalParameters() == 0);
-
- // Subtract the #0 argument, the function pointer.
- return c_signature_.num_fixed_parameters() - kNativeParamsStartAt;
-}
-
-AbstractTypePtr NativeCallingConvention::CType(intptr_t arg_index) const {
- if (arg_index == kResultIndex) {
- return c_signature_.result_type();
- }
-
- // Skip #0 argument, the function pointer.
- return c_signature_.ParameterTypeAt(arg_index + kNativeParamsStartAt);
+const NativeCallingConvention& NativeCallingConvention::FromSignature(
+ Zone* zone,
+ const NativeFunctionType& signature) {
+ const auto& argument_locations =
+ ArgumentLocations(zone, signature.argument_types());
+ const auto& return_location = ResultLocation(zone, signature.return_type());
+ return *new (zone)
+ NativeCallingConvention(argument_locations, return_location);
}
intptr_t NativeCallingConvention::StackTopInBytes() const {
- const intptr_t num_arguments = arg_locs_.length();
+ const intptr_t num_arguments = argument_locations_.length();
intptr_t max_height_in_bytes = 0;
for (intptr_t i = 0; i < num_arguments; i++) {
- if (Location(i).IsStack()) {
- const intptr_t height = Location(i).AsStack().offset_in_bytes() +
- Location(i).container_type().SizeInBytes();
- max_height_in_bytes = Utils::Maximum(height, max_height_in_bytes);
- }
+ max_height_in_bytes = Utils::Maximum(
+ max_height_in_bytes, argument_locations_[i]->StackTopInBytes());
}
return Utils::RoundUp(max_height_in_bytes, compiler::target::kWordSize);
}
+const char* NativeCallingConvention::ToCString() const {
+ char buffer[1024];
+ BufferFormatter bf(buffer, 1024);
+ PrintTo(&bf);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
+}
+
+void NativeCallingConvention::PrintTo(BaseTextBuffer* f) const {
+ f->AddString("(");
+ for (intptr_t i = 0; i < argument_locations_.length(); i++) {
+ if (i > 0) {
+ f->AddString(", ");
+ }
+ argument_locations_[i]->PrintTo(f);
+ }
+ f->AddString(") => ");
+ return_location_.PrintTo(f);
+}
+
} // namespace ffi
} // namespace compiler
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.h b/runtime/vm/compiler/ffi/native_calling_convention.h
index 5eae152..4948910 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.h
+++ b/runtime/vm/compiler/ffi/native_calling_convention.h
@@ -23,43 +23,35 @@
using NativeLocations = ZoneGrowableArray<const NativeLocation*>;
-
-// Values below 0 index result (result might be multiple if composite).
-const intptr_t kResultIndex = -1;
-
// Calculates native calling convention, is not aware of Dart calling
// convention constraints.
//
-// This class is meant to be extended or embedded in a class that is aware
-// of Dart calling convention constraints.
+// This class is meant to beembedded in a class that is aware of Dart calling
+// convention constraints.
class NativeCallingConvention : public ZoneAllocated {
public:
- NativeCallingConvention(Zone* zone, const Function& c_signature);
+ static const NativeCallingConvention& FromSignature(
+ Zone* zone,
+ const NativeFunctionType& signature);
- // Excluding the #0 argument which is the function pointer.
- intptr_t num_args() const;
-
- // The C Type (expressed in a Dart Type) of the argument at `arg_index`.
- //
- // Excluding the #0 argument which is the function pointer.
- AbstractTypePtr CType(intptr_t arg_index) const;
-
- // The location of the argument at `arg_index`.
- const NativeLocation& Location(intptr_t arg_index) const {
- if (arg_index == kResultIndex) {
- return result_loc_;
- }
- return *arg_locs_.At(arg_index);
+ const NativeLocations& argument_locations() const {
+ return argument_locations_;
}
+ const NativeLocation& return_location() const { return return_location_; }
intptr_t StackTopInBytes() const;
- protected:
- Zone* const zone_;
- // Contains the function pointer as argument #0.
- const Function& c_signature_;
- const NativeLocations& arg_locs_;
- const NativeLocation& result_loc_;
+ void PrintTo(BaseTextBuffer* f) const;
+ const char* ToCString() const;
+
+ private:
+ NativeCallingConvention(const NativeLocations& argument_locations,
+ const NativeLocation& return_location)
+ : argument_locations_(argument_locations),
+ return_location_(return_location) {}
+
+ const NativeLocations& argument_locations_;
+ const NativeLocation& return_location_;
};
} // namespace ffi
diff --git a/runtime/vm/compiler/ffi/native_location.h b/runtime/vm/compiler/ffi/native_location.h
index 78caa24..6c7e980 100644
--- a/runtime/vm/compiler/ffi/native_location.h
+++ b/runtime/vm/compiler/ffi/native_location.h
@@ -9,6 +9,7 @@
#error "AOT runtime should not use compiler sources (including header files)"
#endif // defined(DART_PRECOMPILED_RUNTIME)
+#include "platform/assert.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/ffi/native_type.h"
#include "vm/growable_array.h"
@@ -34,14 +35,15 @@
// * The container type, equal to or larger than the payload. If the
// container is larger than the payload, the upper bits are defined by sign
// or zero extension.
+// Container type is also used to denote an integer container when floating
+// point values are passed in integer registers.
//
// NativeLocations can express things that dart::Locations cannot express:
// * Multiple consecutive registers.
// * Multiple sizes of FPU registers (e.g. S, D, and Q on Arm32).
// * Arbitrary byte-size stack locations, at byte-size offsets.
// (The Location class uses word-size offsets.)
-// * Pointers including a backing location on the stack.
-// * No location.
+// * Pointers to a memory location.
// * Split between multiple registers and stack.
//
// NativeLocations cannot express the following dart::Locations:
@@ -106,6 +108,9 @@
UNREACHABLE();
}
+ // Return the top of the stack in bytes.
+ virtual intptr_t StackTopInBytes() const { return 0; }
+
// Equality of location, ignores the payload and container native types.
virtual bool Equals(const NativeLocation& other) const { UNREACHABLE(); }
@@ -303,6 +308,10 @@
virtual NativeStackLocation& Split(Zone* zone, intptr_t index) const;
+ virtual intptr_t StackTopInBytes() const {
+ return offset_in_bytes() + container_type().SizeInBytes();
+ }
+
virtual void PrintTo(BaseTextBuffer* f) const;
virtual bool Equals(const NativeLocation& other) const;
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
index 5bb9f4c..c5cd230 100644
--- a/runtime/vm/compiler/ffi/native_type.cc
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -6,8 +6,12 @@
#include "platform/assert.h"
#include "platform/globals.h"
+#include "vm/class_id.h"
#include "vm/compiler/runtime_api.h"
+#include "vm/growable_array.h"
+#include "vm/log.h"
#include "vm/object.h"
+#include "vm/symbols.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/locations.h"
@@ -324,6 +328,25 @@
f->Printf("%s", PrimitiveTypeToCString(representation_));
}
+const char* NativeFunctionType::ToCString() const {
+ char buffer[1024];
+ BufferFormatter bf(buffer, 1024);
+ PrintTo(&bf);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
+}
+
+void NativeFunctionType::PrintTo(BaseTextBuffer* f) const {
+ f->AddString("(");
+ for (intptr_t i = 0; i < argument_types_.length(); i++) {
+ if (i > 0) {
+ f->AddString(", ");
+ }
+ argument_types_[i]->PrintTo(f);
+ }
+ f->AddString(") => ");
+ return_type_.PrintTo(f);
+}
+
const NativeType& NativeType::WidenTo4Bytes(Zone* zone) const {
if (IsInt() && SizeInBytes() <= 2) {
if (IsSigned()) {
diff --git a/runtime/vm/compiler/ffi/native_type.h b/runtime/vm/compiler/ffi/native_type.h
index 66d5f31..693b7c0 100644
--- a/runtime/vm/compiler/ffi/native_type.h
+++ b/runtime/vm/compiler/ffi/native_type.h
@@ -10,6 +10,7 @@
#include "platform/assert.h"
#include "vm/allocation.h"
#include "vm/compiler/runtime_api.h"
+#include "vm/growable_array.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/locations.h"
@@ -66,7 +67,7 @@
virtual bool IsFloat() const { return false; }
virtual bool IsVoid() const { return false; }
- virtual bool IsSigned() const = 0;
+ virtual bool IsSigned() const { return false; }
// The size in bytes of this representation.
//
@@ -84,7 +85,7 @@
virtual bool IsExpressibleAsRepresentation() const { return false; }
// Unboxed Representation if it exists.
- virtual Representation AsRepresentation() const = 0;
+ virtual Representation AsRepresentation() const { UNREACHABLE(); }
// Unboxed Representation, over approximates if needed.
Representation AsRepresentationOverApprox(Zone* zone_) const {
@@ -167,6 +168,25 @@
const PrimitiveType representation_;
};
+using NativeTypes = ZoneGrowableArray<const NativeType*>;
+
+class NativeFunctionType : public ZoneAllocated {
+ public:
+ NativeFunctionType(const NativeTypes& argument_types,
+ const NativeType& return_type)
+ : argument_types_(argument_types), return_type_(return_type) {}
+
+ const NativeTypes& argument_types() const { return argument_types_; }
+ const NativeType& return_type() const { return return_type_; }
+
+ void PrintTo(BaseTextBuffer* f) const;
+ const char* ToCString() const;
+
+ private:
+ const NativeTypes& argument_types_;
+ const NativeType& return_type_;
+};
+
} // namespace ffi
} // namespace compiler
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 5a146e0..0c3d7cd 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1555,8 +1555,6 @@
}
}
-void Debugger::OnIsolateRunnable() {}
-
bool Debugger::SetupStepOverAsyncSuspension(const char** error) {
ActivationFrame* top_frame = TopDartFrame();
if (!IsAtAsyncJump(top_frame)) {
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index e5fd4ac..18691a4 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -470,8 +470,6 @@
void NotifyIsolateCreated();
void Shutdown();
- void OnIsolateRunnable();
-
void NotifyCompilation(const Function& func);
void NotifyDoneLoading();
diff --git a/runtime/vm/heap/become.cc b/runtime/vm/heap/become.cc
index 8b9ac83..77cc4e5 100644
--- a/runtime/vm/heap/become.cc
+++ b/runtime/vm/heap/become.cc
@@ -86,25 +86,35 @@
virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* p = first; p <= last; p++) {
ObjectPtr old_target = *p;
+ ObjectPtr new_target;
if (IsForwardingObject(old_target)) {
- ObjectPtr new_target = GetForwardedObject(old_target);
- if (visiting_object_ == nullptr) {
- *p = new_target;
- } else if (visiting_object_->ptr()->IsCardRemembered()) {
- visiting_object_->ptr()->StoreArrayPointer(p, new_target, thread_);
- } else {
- visiting_object_->ptr()->StorePointer(p, new_target, thread_);
- }
+ new_target = GetForwardedObject(old_target);
+ } else {
+ // Though we do not need to update the slot's value when it is not
+ // forwarded, we do need to recheck the generational barrier. In
+ // particular, the remembered bit may be incorrectly false if this
+ // become was the result of aborting a scavenge while visiting the
+ // remembered set.
+ new_target = old_target;
+ }
+ if (visiting_object_ == nullptr) {
+ *p = new_target;
+ } else if (visiting_object_->ptr()->IsCardRemembered()) {
+ visiting_object_->ptr()->StoreArrayPointer(p, new_target, thread_);
+ } else {
+ visiting_object_->ptr()->StorePointer(p, new_target, thread_);
}
}
}
void VisitingObject(ObjectPtr obj) {
visiting_object_ = obj;
+ // The incoming remembered bit may be unreliable. Clear it so we can
+ // consistently reapply the barrier to all slots.
if ((obj != nullptr) && obj->IsOldObject() && obj->ptr()->IsRemembered()) {
ASSERT(!obj->IsForwardingCorpse());
ASSERT(!obj->IsFreeListElement());
- thread_->StoreBufferAddObjectGC(obj);
+ obj->ptr()->ClearRememberedBit();
}
}
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index e45ebd5..0de6a9f 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -830,7 +830,7 @@
if (raw_obj->IsHeapObject() && raw_obj->IsNewObject()) {
if (!is_remembered_) {
FATAL3(
- "Old object %#" Px "references new object %#" Px
+ "Old object %#" Px " references new object %#" Px
", but it is not"
" in any store buffer. Consider using rr to watch the slot %p and"
" reverse-continue to find the store with a missing barrier.\n",
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 222e5a3..ca08cac 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2061,7 +2061,6 @@
set_is_runnable(true);
#ifndef PRODUCT
if (!Isolate::IsSystemIsolate(this)) {
- debugger()->OnIsolateRunnable();
if (FLAG_pause_isolates_on_unhandled_exceptions) {
debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions);
}
diff --git a/tools/VERSION b/tools/VERSION
index 5928929..a506401 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 29
+PRERELEASE 30
PRERELEASE_PATCH 0
\ No newline at end of file