Skip to content

Commit d8d7af1

Browse files
mralephcommit-bot@chromium.org
authored andcommitted
[vm] Migrate away from native 'name' syntax.
As part of deprecating support for native extensions we are also migrating away from legacy VM-specific `native 'name'` syntax towards metadata based encoding which does not require any special syntax. This CL is a step 1 in migration: - introduces support for `@pragma('vm:external-name', 'name')` which serves as a direct replacement for `native 'name'`; - all core libraries and tests are migrated to use the annotation; Once this CL lands and rolls we will edit internal and external embedders to eliminate uses of the native keyword (step 2) and finally remove support for native keyword across our parsers (step 3). TEST=ci Bug: #28791 Change-Id: Id6dea878db82dd4fd81149243c425b5c5dc6df86 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212461 Commit-Queue: Slava Egorov <[email protected]> Reviewed-by: Lasse R.H. Nielsen <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent fbc70d8 commit d8d7af1

File tree

83 files changed

+1869
-1262
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1869
-1262
lines changed

pkg/front_end/testcases/general/invalid_operator.dart.weak.expect

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -564,37 +564,37 @@ library;
564564
// Try adding explicit types.
565565
// operator ==<T>(a) => true;
566566
// ^^
567-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is one of the overridden members.
568-
// bool operator ==(Object other) native "Object_equals";
569-
// ^^
567+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is one of the overridden members.
568+
// external bool operator ==(Object other);
569+
// ^^
570570
//
571571
// pkg/front_end/testcases/general/invalid_operator.dart:6:12: Error: The method 'Operators1.==' has fewer positional arguments than those of overridden method 'Object.=='.
572572
// operator ==() => true;
573573
// ^
574-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
575-
// bool operator ==(Object other) native "Object_equals";
576-
// ^
574+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
575+
// external bool operator ==(Object other);
576+
// ^
577577
//
578578
// pkg/front_end/testcases/general/invalid_operator.dart:27:12: Error: The method 'Operators2.==' has more required arguments than those of overridden method 'Object.=='.
579579
// operator ==(a, b) => true;
580580
// ^
581-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
582-
// bool operator ==(Object other) native "Object_equals";
583-
// ^
581+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
582+
// external bool operator ==(Object other);
583+
// ^
584584
//
585585
// pkg/front_end/testcases/general/invalid_operator.dart:71:12: Error: The method 'Operators4.==' has fewer positional arguments than those of overridden method 'Object.=='.
586586
// operator ==({a}) => true;
587587
// ^
588-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
589-
// bool operator ==(Object other) native "Object_equals";
590-
// ^
588+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
589+
// external bool operator ==(Object other);
590+
// ^
591591
//
592592
// pkg/front_end/testcases/general/invalid_operator.dart:137:12: Error: Declared type variables of 'Operators7.==' doesn't match those on overridden method 'Object.=='.
593593
// operator ==<T>(a) => true;
594594
// ^
595-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
596-
// bool operator ==(Object other) native "Object_equals";
597-
// ^
595+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
596+
// external bool operator ==(Object other);
597+
// ^
598598
//
599599
import self as self;
600600
import "dart:core" as core;

pkg/front_end/testcases/general/invalid_operator.dart.weak.outline.expect

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -564,37 +564,37 @@ library;
564564
// Try adding explicit types.
565565
// operator ==<T>(a) => true;
566566
// ^^
567-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is one of the overridden members.
568-
// bool operator ==(Object other) native "Object_equals";
569-
// ^^
567+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is one of the overridden members.
568+
// external bool operator ==(Object other);
569+
// ^^
570570
//
571571
// pkg/front_end/testcases/general/invalid_operator.dart:6:12: Error: The method 'Operators1.==' has fewer positional arguments than those of overridden method 'Object.=='.
572572
// operator ==() => true;
573573
// ^
574-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
575-
// bool operator ==(Object other) native "Object_equals";
576-
// ^
574+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
575+
// external bool operator ==(Object other);
576+
// ^
577577
//
578578
// pkg/front_end/testcases/general/invalid_operator.dart:27:12: Error: The method 'Operators2.==' has more required arguments than those of overridden method 'Object.=='.
579579
// operator ==(a, b) => true;
580580
// ^
581-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
582-
// bool operator ==(Object other) native "Object_equals";
583-
// ^
581+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
582+
// external bool operator ==(Object other);
583+
// ^
584584
//
585585
// pkg/front_end/testcases/general/invalid_operator.dart:71:12: Error: The method 'Operators4.==' has fewer positional arguments than those of overridden method 'Object.=='.
586586
// operator ==({a}) => true;
587587
// ^
588-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
589-
// bool operator ==(Object other) native "Object_equals";
590-
// ^
588+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
589+
// external bool operator ==(Object other);
590+
// ^
591591
//
592592
// pkg/front_end/testcases/general/invalid_operator.dart:137:12: Error: Declared type variables of 'Operators7.==' doesn't match those on overridden method 'Object.=='.
593593
// operator ==<T>(a) => true;
594594
// ^
595-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
596-
// bool operator ==(Object other) native "Object_equals";
597-
// ^
595+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
596+
// external bool operator ==(Object other);
597+
// ^
598598
//
599599
import self as self;
600600
import "dart:core" as core;

pkg/front_end/testcases/nnbd/issue42603.dart.strong.expect

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ library /*isNonNullableByDefault*/;
99
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
1010
// bool operator ==() => true;
1111
// ^
12-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
13-
// bool operator ==(Object other) native "Object_equals";
14-
// ^
12+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
13+
// external bool operator ==(Object other);
14+
// ^
1515
//
1616
// pkg/front_end/testcases/nnbd/issue42603.dart:22:17: Error: The method 'F.==' has more required arguments than those of overridden method 'E.=='.
1717
// bool operator ==(Object? other) => super == other;

pkg/front_end/testcases/nnbd/issue42603.dart.weak.expect

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ library /*isNonNullableByDefault*/;
99
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
1010
// bool operator ==() => true;
1111
// ^
12-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
13-
// bool operator ==(Object other) native "Object_equals";
14-
// ^
12+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
13+
// external bool operator ==(Object other);
14+
// ^
1515
//
1616
// pkg/front_end/testcases/nnbd/issue42603.dart:22:17: Error: The method 'F.==' has more required arguments than those of overridden method 'E.=='.
1717
// bool operator ==(Object? other) => super == other;

pkg/front_end/testcases/nnbd/issue42603.dart.weak.outline.expect

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ library /*isNonNullableByDefault*/;
99
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
1010
// bool operator ==() => true;
1111
// ^
12-
// sdk/lib/_internal/vm/lib/object_patch.dart:26:17: Context: This is the overridden method ('==').
13-
// bool operator ==(Object other) native "Object_equals";
14-
// ^
12+
// sdk/lib/_internal/vm/lib/object_patch.dart:29:26: Context: This is the overridden method ('==').
13+
// external bool operator ==(Object other);
14+
// ^
1515
//
1616
// pkg/front_end/testcases/nnbd/issue42603.dart:22:17: Error: The method 'F.==' has more required arguments than those of overridden method 'E.=='.
1717
// bool operator ==(Object? other) => super == other;

pkg/kernel/lib/external_name.dart

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,56 @@
55
library kernel.external_name;
66

77
import 'ast.dart';
8+
import 'core_types.dart';
89

910
/// Returns external (native) name of given [Member].
10-
String? getExternalName(Member procedure) {
11+
String? getExternalName(CoreTypes coreTypes, Member procedure) {
1112
// Native procedures are marked as external and have an annotation,
1213
// which looks like this:
1314
//
15+
// @pragma("vm:external-name", "<name-of-native>")
16+
// external Object foo(arg0, ...);
17+
//
18+
// Previously the following encoding was used, which is still supported
19+
// until all users are migrated away from it:
20+
//
1421
// import 'dart:_internal' as internal;
1522
//
1623
// @internal.ExternalName("<name-of-native>")
1724
// external Object foo(arg0, ...);
1825
//
26+
1927
if (!procedure.isExternal) {
2028
return null;
2129
}
2230
for (final Expression annotation in procedure.annotations) {
23-
final String? value = _getExternalNameValue(annotation);
31+
final String? value = _getExternalNameValue(coreTypes, annotation);
2432
if (value != null) {
2533
return value;
2634
}
2735
}
2836
return null;
2937
}
3038

31-
/// Returns native extension URIs for given [library].
32-
List<String> getNativeExtensionUris(Library library) {
33-
final List<String> uris = <String>[];
34-
for (Expression annotation in library.annotations) {
35-
final String? value = _getExternalNameValue(annotation);
36-
if (value != null) {
37-
uris.add(value);
38-
}
39-
}
40-
return uris;
41-
}
42-
43-
String? _getExternalNameValue(Expression annotation) {
44-
if (annotation is ConstructorInvocation) {
45-
if (_isExternalName(annotation.target.enclosingClass)) {
46-
return (annotation.arguments.positional.single as StringLiteral).value;
47-
}
48-
} else if (annotation is ConstantExpression) {
39+
String? _getExternalNameValue(CoreTypes coreTypes, Expression annotation) {
40+
if (annotation is ConstantExpression) {
4941
final Constant constant = annotation.constant;
5042
if (constant is InstanceConstant) {
5143
if (_isExternalName(constant.classNode)) {
5244
return (constant.fieldValues.values.single as StringConstant).value;
45+
} else if (_isPragma(constant.classNode)) {
46+
final String pragmaName =
47+
(constant.fieldValues[coreTypes.pragmaName.getterReference]
48+
as StringConstant)
49+
.value;
50+
final Constant? pragmaOptionsValue =
51+
constant.fieldValues[coreTypes.pragmaOptions.getterReference];
52+
final String? pragmaOptions = pragmaOptionsValue is StringConstant
53+
? pragmaOptionsValue.value
54+
: null;
55+
if (pragmaName == _externalNamePragma && pragmaOptions != null) {
56+
return pragmaOptions;
57+
}
5358
}
5459
}
5560
}
@@ -59,3 +64,9 @@ String? _getExternalNameValue(Expression annotation) {
5964
bool _isExternalName(Class klass) =>
6065
klass.name == 'ExternalName' &&
6166
klass.enclosingLibrary.importUri.toString() == 'dart:_internal';
67+
68+
bool _isPragma(Class klass) =>
69+
klass.name == 'pragma' &&
70+
klass.enclosingLibrary.importUri.toString() == 'dart:core';
71+
72+
const String _externalNamePragma = 'vm:external-name';

pkg/vm/lib/transformations/type_flow/signature_shaking.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:kernel/ast.dart';
6+
import 'package:kernel/core_types.dart';
67
import 'package:kernel/external_name.dart';
78
import 'package:kernel/type_environment.dart';
89

@@ -200,6 +201,7 @@ class _ParameterInfo {
200201

201202
class _Collect extends RecursiveVisitor {
202203
final SignatureShaker shaker;
204+
final CoreTypes coreTypes;
203205

204206
/// Parameters of the current function.
205207
final Map<VariableDeclaration, _ParameterInfo> localParameters = {};
@@ -209,7 +211,8 @@ class _Collect extends RecursiveVisitor {
209211
/// via [_ParameterInfo.useDependencies] and not marked as read immediately.
210212
final Set<VariableGet> useDependencies = {};
211213

212-
_Collect(this.shaker);
214+
_Collect(this.shaker)
215+
: coreTypes = shaker.typeFlowAnalysis.environment.coreTypes;
213216

214217
void enterFunction(Member member) {
215218
final _ProcedureInfo? info = shaker._infoForMember(member);
@@ -233,7 +236,7 @@ class _Collect extends RecursiveVisitor {
233236
shaker.typeFlowAnalysis.nativeCodeOracle
234237
.isMemberReferencedFromNativeCode(member) ||
235238
shaker.typeFlowAnalysis.nativeCodeOracle.isRecognized(member) ||
236-
getExternalName(member) != null ||
239+
getExternalName(coreTypes, member) != null ||
237240
member.name.text == '==') {
238241
info.eligible = false;
239242
}

pkg/vm/lib/transformations/type_flow/unboxing_info.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,5 +205,5 @@ class UnboxingInfoManager {
205205
_nativeCodeOracle.hasDisableUnboxedParameters(member);
206206
}
207207

208-
bool _isNative(Member member) => getExternalName(member) != null;
208+
bool _isNative(Member member) => getExternalName(_coreTypes, member) != null;
209209
}

runtime/docs/pragmas.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ These pragmas are part of the VM's API and are safe for use in external code.
1010
| `vm:never-inline` | [Never inline a function or method](compiler/pragmas_recognized_by_compiler.md#requesting-a-function-never-be-inlined) |
1111
| `vm:prefer-inline` | [Inline a function or method when possible](compiler/pragmas_recognized_by_compiler.md#requesting-a-function-be-inlined) |
1212
| `vm:notify-debugger-on-exception` | Marks a function that catches exceptions, making the VM treat any caught exception as if they were uncaught. This can be used to notify an attached debugger during debugging, without pausing the app during regular execution. |
13+
| `vm:external-name` | Allows to specify an external (native) name for an `external` function. This name is used to lookup native implementation via native resolver associated with the current library through embedding APIs. This is a replacement for legacy VM specific `native "name"` syntax. |
1314

1415
## Unsafe pragmas for general use
1516

runtime/vm/benchmark_test.cc

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,23 @@ static Dart_NativeFunction bm_uda_lookup(Dart_Handle name,
166166

167167
BENCHMARK(UseDartApi) {
168168
const int kNumIterations = 1000000;
169-
const char* kScriptChars =
170-
"import 'dart:nativewrappers';\n"
171-
"class Class extends NativeFieldWrapperClass1 {\n"
172-
" void init() native 'init';\n"
173-
" int method(int param1, int param2) native 'method';\n"
174-
"}\n"
175-
"\n"
176-
"void benchmark(int count) {\n"
177-
" Class c = Class();\n"
178-
" c.init();\n"
179-
" for (int i = 0; i < count; i++) {\n"
180-
" c.method(i,7);\n"
181-
" }\n"
182-
"}\n";
169+
const char* kScriptChars = R"(
170+
import 'dart:nativewrappers';
171+
172+
class Class extends NativeFieldWrapperClass1 {
173+
@pragma("vm:external-name", "init")
174+
external void init();
175+
@pragma("vm:external-name", "method")
176+
external int method(int param1, int param2);
177+
}
178+
179+
void benchmark(int count) {
180+
Class c = Class();
181+
c.init();
182+
for (int i = 0; i < count; i++) {
183+
c.method(i,7);
184+
}
185+
})";
183186

184187
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, bm_uda_lookup,
185188
RESOLVED_USER_TEST_URI, false);

runtime/vm/code_descriptors_test.cc

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,24 @@ static Dart_NativeFunction native_resolver(Dart_Handle name,
4040
}
4141

4242
TEST_CASE(StackMapGC) {
43-
const char* kScriptChars =
44-
"class A {"
45-
" static void func(var i, var k) native 'NativeFunc';"
46-
" static foo() {"
47-
" var i;"
48-
" var s1;"
49-
" var k;"
50-
" var s2;"
51-
" var s3;"
52-
" i = 10; s1 = 'abcd'; k = 20; s2 = 'B'; s3 = 'C';"
53-
" func(i, k);"
54-
" return i + k; }"
55-
" static void moo() {"
56-
" var i = A.foo();"
57-
" if (i != 30) throw '$i != 30';"
58-
" }\n"
59-
"}\n";
43+
const char* kScriptChars = R"(
44+
class A {
45+
@pragma("vm:external-name", "NativeFunc")
46+
external static void func(var i, var k);
47+
static foo() {
48+
var i;
49+
var s1;
50+
var k;
51+
var s2;
52+
var s3;
53+
i = 10; s1 = 'abcd'; k = 20; s2 = 'B'; s3 = 'C';
54+
func(i, k);
55+
return i + k; }
56+
static void moo() {
57+
var i = A.foo();
58+
if (i != 30) throw '$i != 30';
59+
}
60+
})";
6061
// First setup the script and compile the script.
6162
TestCase::LoadTestScript(kScriptChars, native_resolver);
6263
TransitionNativeToVM transition(thread);

0 commit comments

Comments
 (0)