mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:31:57 +00:00
[vm] Support closurization of methods through @pragma entry-points.
Fixes dartbug.com/35720. Also enable native extensions in AOT. Increases Flutter Gallery snapshot size by 0.19%. Change-Id: I1b24c3b9a49a13fd48452e9a89595516a7f01780 Cq-Include-Trybots: luci.dart.try:vm-kernel-optcounter-threshold-linux-release-x64-try, vm-kernel-precomp-linux-debug-x64-try, vm-kernel-precomp-linux-release-simarm-try, vm-kernel-precomp-linux-release-simarm64-try, vm-kernel-precomp-linux-release-x64-try, vm-kernel-precomp-mac-release-simarm64-try, vm-kernel-precomp-win-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/92283 Commit-Queue: Samir Jindel <sjindel@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
a5d396cd25
commit
ae7bf9e999
|
@ -13,7 +13,7 @@ const kNonNullableResultType = "vm:non-nullable-result-type";
|
|||
|
||||
abstract class ParsedPragma {}
|
||||
|
||||
enum PragmaEntryPointType { Always, GetterOnly, SetterOnly }
|
||||
enum PragmaEntryPointType { Default, GetterOnly, SetterOnly, CallOnly }
|
||||
|
||||
class ParsedEntryPointPragma extends ParsedPragma {
|
||||
final PragmaEntryPointType type;
|
||||
|
@ -73,17 +73,20 @@ class ConstantPragmaAnnotationParser extends PragmaAnnotationParser {
|
|||
case kEntryPointPragmaName:
|
||||
PragmaEntryPointType type;
|
||||
if (options is NullConstant) {
|
||||
type = PragmaEntryPointType.Always;
|
||||
type = PragmaEntryPointType.Default;
|
||||
} else if (options is BoolConstant && options.value == true) {
|
||||
type = PragmaEntryPointType.Always;
|
||||
type = PragmaEntryPointType.Default;
|
||||
} else if (options is StringConstant) {
|
||||
if (options.value == "get") {
|
||||
type = PragmaEntryPointType.GetterOnly;
|
||||
} else if (options.value == "set") {
|
||||
type = PragmaEntryPointType.SetterOnly;
|
||||
} else if (options.value == "call") {
|
||||
type = PragmaEntryPointType.CallOnly;
|
||||
} else {
|
||||
throw "Error: string directive to @pragma('$kEntryPointPragmaName', ...) "
|
||||
"must be either 'get' or 'set'.";
|
||||
"must be either 'get' or 'set' for fields "
|
||||
"or 'get' or 'call' for procedures.";
|
||||
}
|
||||
}
|
||||
return type != null ? new ParsedEntryPointPragma(type) : null;
|
||||
|
|
|
@ -58,7 +58,7 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
|
|||
if (!klass.isAbstract) {
|
||||
var type = _annotationsDefineRoot(klass.annotations);
|
||||
if (type != null) {
|
||||
if (type != PragmaEntryPointType.Always) {
|
||||
if (type != PragmaEntryPointType.Default) {
|
||||
throw "Error: pragma entry-point definition on a class must evaluate "
|
||||
"to null, true or false. See entry_points_pragma.md.";
|
||||
}
|
||||
|
@ -73,17 +73,39 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
|
|||
visitProcedure(Procedure proc) {
|
||||
var type = _annotationsDefineRoot(proc.annotations);
|
||||
if (type != null) {
|
||||
if (type != PragmaEntryPointType.Always) {
|
||||
throw "Error: pragma entry-point definition on a procedure (including"
|
||||
"getters and setters) must evaluate to null, true or false. "
|
||||
"See entry_points_pragma.md.";
|
||||
void addSelector(CallKind ck) {
|
||||
entryPoints.addRawCall(proc.isInstanceMember
|
||||
? new InterfaceSelector(proc, callKind: ck)
|
||||
: new DirectSelector(proc, callKind: ck));
|
||||
}
|
||||
var callKind = proc.isGetter
|
||||
|
||||
final defaultCallKind = proc.isGetter
|
||||
? CallKind.PropertyGet
|
||||
: (proc.isSetter ? CallKind.PropertySet : CallKind.Method);
|
||||
entryPoints.addRawCall(proc.isInstanceMember
|
||||
? new InterfaceSelector(proc, callKind: callKind)
|
||||
: new DirectSelector(proc, callKind: callKind));
|
||||
|
||||
switch (type) {
|
||||
case PragmaEntryPointType.CallOnly:
|
||||
addSelector(defaultCallKind);
|
||||
break;
|
||||
case PragmaEntryPointType.SetterOnly:
|
||||
if (!proc.isSetter) {
|
||||
throw "Error: cannot generate a setter for a method or getter ($proc).";
|
||||
}
|
||||
addSelector(CallKind.PropertySet);
|
||||
break;
|
||||
case PragmaEntryPointType.GetterOnly:
|
||||
if (proc.isSetter) {
|
||||
throw "Error: cannot closurize a setter ($proc).";
|
||||
}
|
||||
addSelector(CallKind.PropertyGet);
|
||||
break;
|
||||
case PragmaEntryPointType.Default:
|
||||
addSelector(defaultCallKind);
|
||||
if (!proc.isSetter && !proc.isGetter) {
|
||||
addSelector(CallKind.PropertyGet);
|
||||
}
|
||||
}
|
||||
|
||||
nativeCodeOracle.setMemberReferencedFromNativeCode(proc);
|
||||
}
|
||||
}
|
||||
|
@ -92,9 +114,10 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
|
|||
visitConstructor(Constructor ctor) {
|
||||
var type = _annotationsDefineRoot(ctor.annotations);
|
||||
if (type != null) {
|
||||
if (type != PragmaEntryPointType.Always) {
|
||||
throw "Error: pragma entry-point definition on a constructor must "
|
||||
"evaluate to null, true or false. See entry_points_pragma.md.";
|
||||
if (type != PragmaEntryPointType.Default &&
|
||||
type != PragmaEntryPointType.CallOnly) {
|
||||
throw "Error: pragma entry-point definition on a constructor ($ctor) must"
|
||||
"evaluate to null, true, false or 'call'. See entry_points_pragma.md.";
|
||||
}
|
||||
entryPoints
|
||||
.addRawCall(new DirectSelector(ctor, callKind: CallKind.Method));
|
||||
|
@ -125,12 +148,15 @@ class PragmaEntryPointsVisitor extends RecursiveVisitor {
|
|||
}
|
||||
addSelector(CallKind.PropertySet);
|
||||
break;
|
||||
case PragmaEntryPointType.Always:
|
||||
case PragmaEntryPointType.Default:
|
||||
addSelector(CallKind.PropertyGet);
|
||||
if (!field.isFinal) {
|
||||
addSelector(CallKind.PropertySet);
|
||||
}
|
||||
break;
|
||||
case PragmaEntryPointType.CallOnly:
|
||||
throw "Error: can't generate invocation dispatcher for field $field"
|
||||
"through @pragma('vm:entry-point')";
|
||||
}
|
||||
|
||||
nativeCodeOracle.setMemberReferencedFromNativeCode(field);
|
||||
|
|
|
@ -49,7 +49,7 @@ class ExpressionPragmaAnnotationParser extends PragmaAnnotationParser {
|
|||
case kEntryPointPragmaName:
|
||||
// We ignore the option because we can't properly evaluate it, assume
|
||||
// it's true.
|
||||
return new ParsedEntryPointPragma(PragmaEntryPointType.Always);
|
||||
return new ParsedEntryPointPragma(PragmaEntryPointType.Default);
|
||||
case kExactResultTypePragmaName:
|
||||
if (options is TypeLiteral) {
|
||||
return new ParsedResultTypeByTypePragma(options.type);
|
||||
|
|
|
@ -45,7 +45,7 @@ class B extends self::A {
|
|||
synthetic constructor •() → self::B
|
||||
: super self::A::•()
|
||||
;
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T1::•();
|
||||
}
|
||||
no-such-method-forwarder get bar() → dynamic
|
||||
|
@ -59,7 +59,7 @@ abstract class C extends core::Object {
|
|||
synthetic constructor •() → self::C
|
||||
: super core::Object::•()
|
||||
;
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T2::•();
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class E extends core::Object implements self::A {
|
|||
synthetic constructor •() → self::E
|
||||
: super core::Object::•()
|
||||
;
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T4::•();
|
||||
}
|
||||
no-such-method-forwarder get bar() → dynamic
|
||||
|
@ -88,7 +88,7 @@ class F extends core::Object {
|
|||
synthetic constructor •() → self::F
|
||||
: super core::Object::•()
|
||||
;
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T2::•();
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ class G extends core::Object {
|
|||
synthetic constructor •() → self::G
|
||||
: super core::Object::•()
|
||||
;
|
||||
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
[@vm.procedure-attributes.metadata=hasThisUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T5::•();
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ class H extends core::Object {
|
|||
;
|
||||
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method foo({[@vm.inferred-type.metadata=dart.core::_Smi] dynamic left = null, [@vm.inferred-type.metadata=dart.core::_Smi] dynamic right = null}) → dynamic
|
||||
return new self::T6::•();
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false] method noSuchMethod(core::Invocation invocation) → dynamic {
|
||||
return new self::T7::•();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
abort(); \
|
||||
}
|
||||
|
||||
bool isDartPrecompiledRuntime = true;
|
||||
|
||||
Dart_Handle GetCurrentLibrary() {
|
||||
Dart_Handle libraries = Dart_GetLoadedLibraries();
|
||||
CHECK(libraries);
|
||||
|
@ -36,6 +38,13 @@ Dart_Handle GetCurrentLibrary() {
|
|||
abort();
|
||||
}
|
||||
|
||||
// Some invalid accesses are allowed in AOT since we don't retain @pragma
|
||||
// annotations. Therefore we skip the negative tests in AOT.
|
||||
#define FAIL(name, result) \
|
||||
if (!isDartPrecompiledRuntime) { \
|
||||
Fail(name, result); \
|
||||
}
|
||||
|
||||
void Fail(const char* name, Dart_Handle result) {
|
||||
ASSERT(Dart_IsApiError(result));
|
||||
const char* error = Dart_GetError(result);
|
||||
|
@ -43,37 +52,52 @@ void Fail(const char* name, Dart_Handle result) {
|
|||
ASSERT(strstr(error, "It is illegal to access"));
|
||||
}
|
||||
|
||||
void FailClosurize(const char* name, Dart_Handle result) {
|
||||
#define FAIL_INVOKE_FIELD(name, result) \
|
||||
if (!isDartPrecompiledRuntime) { \
|
||||
FailInvokeField(name, result); \
|
||||
}
|
||||
|
||||
void FailInvokeField(const char* name, Dart_Handle result) {
|
||||
ASSERT(Dart_IsApiError(result));
|
||||
const char* error = Dart_GetError(result);
|
||||
ASSERT(strstr(error, name));
|
||||
ASSERT(strstr(error, "Entry-points do not allow closurizing methods"));
|
||||
ASSERT(strstr(error, "Entry-points do not allow invoking fields"));
|
||||
}
|
||||
|
||||
void FailClosurizeConstructor(const char* name, Dart_Handle result) {
|
||||
ASSERT(Dart_IsUnhandledExceptionError(result));
|
||||
const char* error = Dart_GetError(result);
|
||||
ASSERT(strstr(error, name));
|
||||
ASSERT(strstr(error, "No static getter"));
|
||||
}
|
||||
|
||||
void TestFields(Dart_Handle target) {
|
||||
Fail("fld0", Dart_GetField(target, Dart_NewStringFromCString("fld0")));
|
||||
Fail("fld0",
|
||||
FAIL("fld0", Dart_GetField(target, Dart_NewStringFromCString("fld0")));
|
||||
FAIL("fld0",
|
||||
Dart_SetField(target, Dart_NewStringFromCString("fld0"), Dart_Null()));
|
||||
|
||||
Dart_Handle result =
|
||||
Dart_Invoke(target, Dart_NewStringFromCString("fld0"), 0, nullptr);
|
||||
FailClosurize("fld0", result);
|
||||
FAIL_INVOKE_FIELD(
|
||||
"fld0",
|
||||
Dart_Invoke(target, Dart_NewStringFromCString("fld0"), 0, nullptr));
|
||||
|
||||
CHECK(Dart_GetField(target, Dart_NewStringFromCString("fld1")));
|
||||
CHECK(Dart_SetField(target, Dart_NewStringFromCString("fld1"), Dart_Null()));
|
||||
FailClosurize("fld1", Dart_Invoke(target, Dart_NewStringFromCString("fld1"),
|
||||
0, nullptr));
|
||||
FAIL_INVOKE_FIELD(
|
||||
"fld1",
|
||||
Dart_Invoke(target, Dart_NewStringFromCString("fld1"), 0, nullptr));
|
||||
|
||||
CHECK(Dart_GetField(target, Dart_NewStringFromCString("fld2")));
|
||||
Fail("fld2",
|
||||
FAIL("fld2",
|
||||
Dart_SetField(target, Dart_NewStringFromCString("fld2"), Dart_Null()));
|
||||
FailClosurize("fld2", Dart_Invoke(target, Dart_NewStringFromCString("fld2"),
|
||||
0, nullptr));
|
||||
FAIL_INVOKE_FIELD(
|
||||
"fld2",
|
||||
Dart_Invoke(target, Dart_NewStringFromCString("fld2"), 0, nullptr));
|
||||
|
||||
Fail("fld3", Dart_GetField(target, Dart_NewStringFromCString("fld3")));
|
||||
FAIL("fld3", Dart_GetField(target, Dart_NewStringFromCString("fld3")));
|
||||
CHECK(Dart_SetField(target, Dart_NewStringFromCString("fld3"), Dart_Null()));
|
||||
FailClosurize("fld3", Dart_Invoke(target, Dart_NewStringFromCString("fld3"),
|
||||
0, nullptr));
|
||||
FAIL_INVOKE_FIELD(
|
||||
"fld3",
|
||||
Dart_Invoke(target, Dart_NewStringFromCString("fld3"), 0, nullptr));
|
||||
}
|
||||
|
||||
void RunTests(Dart_NativeArguments arguments) {
|
||||
|
@ -81,14 +105,14 @@ void RunTests(Dart_NativeArguments arguments) {
|
|||
|
||||
//////// Test allocation and constructor invocation.
|
||||
|
||||
Fail("C", Dart_GetClass(lib, Dart_NewStringFromCString("C")));
|
||||
FAIL("C", Dart_GetClass(lib, Dart_NewStringFromCString("C")));
|
||||
|
||||
Dart_Handle D_class = Dart_GetClass(lib, Dart_NewStringFromCString("D"));
|
||||
CHECK(D_class);
|
||||
|
||||
CHECK(Dart_Allocate(D_class));
|
||||
|
||||
Fail("D.", Dart_New(D_class, Dart_Null(), 0, nullptr));
|
||||
FAIL("D.", Dart_New(D_class, Dart_Null(), 0, nullptr));
|
||||
|
||||
CHECK(Dart_New(D_class, Dart_NewStringFromCString("defined"), 0, nullptr));
|
||||
Dart_Handle D =
|
||||
|
@ -97,32 +121,51 @@ void RunTests(Dart_NativeArguments arguments) {
|
|||
|
||||
//////// Test actions against methods
|
||||
|
||||
Fail("fn0", Dart_Invoke(D, Dart_NewStringFromCString("fn0"), 0, nullptr));
|
||||
FailClosurizeConstructor(
|
||||
"defined", Dart_GetField(D_class, Dart_NewStringFromCString("defined")));
|
||||
FailClosurizeConstructor(
|
||||
"fact", Dart_GetField(D_class, Dart_NewStringFromCString("fact")));
|
||||
|
||||
FAIL("fn0", Dart_Invoke(D, Dart_NewStringFromCString("fn0"), 0, nullptr));
|
||||
|
||||
CHECK(Dart_Invoke(D, Dart_NewStringFromCString("fn1"), 0, nullptr));
|
||||
FAIL("fn1", Dart_Invoke(D, Dart_NewStringFromCString("fn1_get"), 0, nullptr));
|
||||
CHECK(Dart_Invoke(D, Dart_NewStringFromCString("fn1_call"), 0, nullptr));
|
||||
|
||||
Fail("get_fn0", Dart_GetField(D, Dart_NewStringFromCString("fn0")));
|
||||
FAIL("fn0", Dart_GetField(D, Dart_NewStringFromCString("fn0")));
|
||||
|
||||
Fail("get_fn1", Dart_GetField(D, Dart_NewStringFromCString("fn1")));
|
||||
CHECK(Dart_GetField(D, Dart_NewStringFromCString("fn1")));
|
||||
CHECK(Dart_GetField(D, Dart_NewStringFromCString("fn1_get")));
|
||||
FAIL("fn1", Dart_GetField(D, Dart_NewStringFromCString("fn1_call")));
|
||||
|
||||
Fail("fn2",
|
||||
FAIL("fn2",
|
||||
Dart_Invoke(D_class, Dart_NewStringFromCString("fn2"), 0, nullptr));
|
||||
|
||||
CHECK(Dart_Invoke(D_class, Dart_NewStringFromCString("fn3"), 0, nullptr));
|
||||
CHECK(
|
||||
Dart_Invoke(D_class, Dart_NewStringFromCString("fn3_call"), 0, nullptr));
|
||||
FAIL("fn3",
|
||||
Dart_Invoke(D_class, Dart_NewStringFromCString("fn3_get"), 0, nullptr));
|
||||
|
||||
FailClosurize("fn2",
|
||||
Dart_GetField(D_class, Dart_NewStringFromCString("fn2")));
|
||||
FAIL("fn2", Dart_GetField(D_class, Dart_NewStringFromCString("fn2")));
|
||||
|
||||
FailClosurize("fn3",
|
||||
Dart_GetField(D_class, Dart_NewStringFromCString("fn3")));
|
||||
CHECK(Dart_GetField(D_class, Dart_NewStringFromCString("fn3")));
|
||||
FAIL("fn3_call",
|
||||
Dart_GetField(D_class, Dart_NewStringFromCString("fn3_call")));
|
||||
CHECK(Dart_GetField(D_class, Dart_NewStringFromCString("fn3_get")));
|
||||
|
||||
Fail("fn0", Dart_Invoke(lib, Dart_NewStringFromCString("fn0"), 0, nullptr));
|
||||
FAIL("fn0", Dart_Invoke(lib, Dart_NewStringFromCString("fn0"), 0, nullptr));
|
||||
|
||||
CHECK(Dart_Invoke(lib, Dart_NewStringFromCString("fn1"), 0, nullptr));
|
||||
FAIL("fn1",
|
||||
Dart_Invoke(lib, Dart_NewStringFromCString("fn1_get"), 0, nullptr));
|
||||
CHECK(Dart_Invoke(lib, Dart_NewStringFromCString("fn1_call"), 0, nullptr));
|
||||
|
||||
FailClosurize("fn0", Dart_GetField(lib, Dart_NewStringFromCString("fn0")));
|
||||
FAIL("fn0", Dart_GetField(lib, Dart_NewStringFromCString("fn0")));
|
||||
|
||||
FailClosurize("fn1", Dart_GetField(lib, Dart_NewStringFromCString("fn1")));
|
||||
CHECK(Dart_GetField(lib, Dart_NewStringFromCString("fn1")));
|
||||
CHECK(Dart_GetField(lib, Dart_NewStringFromCString("fn1_get")));
|
||||
FAIL("fn1", Dart_GetField(lib, Dart_NewStringFromCString("fn1_call")));
|
||||
|
||||
//////// Test actions against fields
|
||||
|
||||
|
@ -146,6 +189,8 @@ Dart_NativeFunction ResolveName(Dart_Handle name,
|
|||
|
||||
DART_EXPORT Dart_Handle
|
||||
entrypoints_verification_test_extension_Init(Dart_Handle parent_library) {
|
||||
isDartPrecompiledRuntime = Dart_IsPrecompiledRuntime();
|
||||
|
||||
if (Dart_IsError(parent_library)) {
|
||||
return parent_library;
|
||||
}
|
||||
|
|
|
@ -55,16 +55,24 @@ getters, setters and constructors):
|
|||
@pragma("vm:entry-point")
|
||||
@pragma("vm:entry-point", true/false)
|
||||
@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
|
||||
@pragma("vm:entry-point", "get")
|
||||
@pragma("vm:entry-point", "call")
|
||||
void foo() { ... }
|
||||
```
|
||||
|
||||
If the second parameter is missing, `null` or `true`, the procedure will
|
||||
available for lookup and invocation directly from native or VM code. If the
|
||||
procedure is a *generative* constructor, the enclosing class must also be
|
||||
If the second parameter is missing, `null` or `true`, the procedure (and its
|
||||
closurized form, excluding constructors and setters) will available for lookup
|
||||
and invocation directly from native or VM code.
|
||||
|
||||
If the procedure is a *generative* constructor, the enclosing class must also be
|
||||
annotated for allocation from native or VM code.
|
||||
|
||||
Note that annotating a procedure does not allow closurizing it, e.g. access a
|
||||
non-getter via `Dart_GetField`.
|
||||
If the annotation is "get" or "call", the procedure will only be available for
|
||||
closurization (access via `Dart_GetField`) or invocation (access via
|
||||
`Dart_Invoke`).
|
||||
|
||||
"@pragma("vm:entry-point", "get") against constructors or setters is disallowed
|
||||
since they cannot be closurized.
|
||||
|
||||
### Fields
|
||||
|
||||
|
@ -86,3 +94,5 @@ the interface of the enclosing class are marked for native invocation. If the
|
|||
'get'/'set' parameter is used, only the getter/setter is marked. For static
|
||||
fields, the implicit getter is always marked. The third form does not make sense
|
||||
for static fields because they do not belong to an interface.
|
||||
|
||||
Note that no form of entry-point annotation allows invoking a field.
|
||||
|
|
|
@ -987,6 +987,7 @@ void Precompiler::AddAnnotatedRoots() {
|
|||
auto& cls = Class::Handle(Z);
|
||||
auto& members = Array::Handle(Z);
|
||||
auto& function = Function::Handle(Z);
|
||||
auto& function2 = Function::Handle(Z);
|
||||
auto& field = Field::Handle(Z);
|
||||
auto& metadata = Array::Handle(Z);
|
||||
auto& reusable_object_handle = Object::Handle(Z);
|
||||
|
@ -1051,13 +1052,23 @@ void Precompiler::AddAnnotatedRoots() {
|
|||
if (function.has_pragma()) {
|
||||
metadata ^= lib.GetMetadata(function);
|
||||
if (metadata.IsNull()) continue;
|
||||
if (FindEntryPointPragma(isolate(), metadata, &reusable_field_handle,
|
||||
&reusable_object_handle) !=
|
||||
EntryPointPragma::kAlways) {
|
||||
continue;
|
||||
auto type =
|
||||
FindEntryPointPragma(isolate(), metadata, &reusable_field_handle,
|
||||
&reusable_object_handle);
|
||||
|
||||
if (type == EntryPointPragma::kAlways ||
|
||||
type == EntryPointPragma::kCallOnly) {
|
||||
AddFunction(function);
|
||||
}
|
||||
|
||||
if ((type == EntryPointPragma::kAlways ||
|
||||
type == EntryPointPragma::kGetterOnly) &&
|
||||
function.kind() != RawFunction::kConstructor &&
|
||||
!function.IsSetterFunction()) {
|
||||
function2 = function.ImplicitClosureFunction();
|
||||
AddFunction(function2);
|
||||
}
|
||||
|
||||
AddFunction(function);
|
||||
if (function.IsGenerativeConstructor()) {
|
||||
AddInstantiatedClass(cls);
|
||||
}
|
||||
|
|
|
@ -3749,7 +3749,7 @@ static RawObject* ResolveConstructor(const char* current_func,
|
|||
current_func, constr_name.ToCString(), error_message.ToCString()));
|
||||
return ApiError::New(message);
|
||||
}
|
||||
RawError* error = constructor.VerifyEntryPoint();
|
||||
RawError* error = constructor.VerifyCallEntryPoint();
|
||||
if (error != Error::null()) return error;
|
||||
return constructor.raw();
|
||||
}
|
||||
|
@ -4043,7 +4043,7 @@ DART_EXPORT Dart_Handle Dart_InvokeConstructor(Dart_Handle object,
|
|||
if (!constructor.IsNull() && constructor.IsGenerativeConstructor() &&
|
||||
constructor.AreValidArgumentCounts(
|
||||
kTypeArgsLen, number_of_arguments + extra_args, 0, NULL)) {
|
||||
CHECK_ERROR_HANDLE(constructor.VerifyEntryPoint());
|
||||
CHECK_ERROR_HANDLE(constructor.VerifyCallEntryPoint());
|
||||
// Create the argument list.
|
||||
// Constructors get the uninitialized object.
|
||||
if (!type_arguments.IsNull()) {
|
||||
|
|
|
@ -572,7 +572,9 @@ void KernelLoader::LoadNativeExtensionLibraries(
|
|||
Instance& constant = Instance::Handle(Z);
|
||||
String& uri_path = String::Handle(Z);
|
||||
Library& library = Library::Handle(Z);
|
||||
#if !defined(DART_PRECOMPILER)
|
||||
Object& result = Object::Handle(Z);
|
||||
#endif
|
||||
|
||||
for (intptr_t i = 0; i < length; ++i) {
|
||||
library ^= potential_extension_libraries_.At(i);
|
||||
|
@ -603,6 +605,7 @@ void KernelLoader::LoadNativeExtensionLibraries(
|
|||
|
||||
if (uri_path.IsNull()) continue;
|
||||
|
||||
#if !defined(DART_PRECOMPILER)
|
||||
if (!I->HasTagHandler()) {
|
||||
H.ReportError("no library handler registered.");
|
||||
}
|
||||
|
@ -614,6 +617,7 @@ void KernelLoader::LoadNativeExtensionLibraries(
|
|||
if (result.IsError()) {
|
||||
H.ReportError(Error::Cast(result), "library handler failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create a dummy library and add it as an import to the current library.
|
||||
// This allows later to discover and reload this native extension, e.g.
|
||||
|
|
|
@ -3294,7 +3294,7 @@ RawObject* Class::InvokeGetter(const String& getter_name,
|
|||
Function::Handle(zone, LookupStaticFunction(internal_getter_name));
|
||||
|
||||
if (field.IsNull() && !getter.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(getter.VerifyEntryPoint());
|
||||
CHECK_ERROR(getter.VerifyCallEntryPoint());
|
||||
}
|
||||
|
||||
if (getter.IsNull() || (respect_reflectable && !getter.is_reflectable())) {
|
||||
|
@ -3302,7 +3302,7 @@ RawObject* Class::InvokeGetter(const String& getter_name,
|
|||
getter = LookupStaticFunction(getter_name);
|
||||
if (!getter.IsNull()) {
|
||||
if (check_is_entrypoint) {
|
||||
CHECK_ERROR(EntryPointClosurizationError(getter_name));
|
||||
CHECK_ERROR(getter.VerifyClosurizedEntryPoint());
|
||||
}
|
||||
if (getter.SafeToClosurize()) {
|
||||
// Looking for a getter but found a regular method: closurize it.
|
||||
|
@ -3360,7 +3360,7 @@ RawObject* Class::InvokeSetter(const String& setter_name,
|
|||
const Function& setter =
|
||||
Function::Handle(zone, LookupStaticFunction(internal_setter_name));
|
||||
if (!setter.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(setter.VerifyEntryPoint());
|
||||
CHECK_ERROR(setter.VerifyCallEntryPoint());
|
||||
}
|
||||
const int kNumArgs = 1;
|
||||
const Array& args = Array::Handle(zone, Array::New(kNumArgs));
|
||||
|
@ -3422,7 +3422,7 @@ RawObject* Class::Invoke(const String& function_name,
|
|||
Function::Handle(zone, LookupStaticFunction(function_name));
|
||||
|
||||
if (!function.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(function.VerifyEntryPoint());
|
||||
CHECK_ERROR(function.VerifyCallEntryPoint());
|
||||
}
|
||||
|
||||
if (function.IsNull()) {
|
||||
|
@ -3432,7 +3432,7 @@ RawObject* Class::Invoke(const String& function_name,
|
|||
check_is_entrypoint));
|
||||
if (getter_result.raw() != Object::sentinel().raw()) {
|
||||
if (check_is_entrypoint) {
|
||||
CHECK_ERROR(EntryPointClosurizationError(function_name));
|
||||
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
|
||||
}
|
||||
// Make room for the closure (receiver) in the argument list.
|
||||
const intptr_t num_args = args.Length();
|
||||
|
@ -10612,7 +10612,35 @@ RawNamespace* Library::ImportAt(intptr_t index) const {
|
|||
}
|
||||
|
||||
void Library::DropDependenciesAndCaches() const {
|
||||
StorePointer(&raw_ptr()->imports_, Object::empty_array().raw());
|
||||
// We need to preserve the "dart-ext:" imports because they are used by
|
||||
// Loader::ReloadNativeExtensions().
|
||||
intptr_t native_import_count = 0;
|
||||
Array& imports = Array::Handle(raw_ptr()->imports_);
|
||||
Namespace& ns = Namespace::Handle();
|
||||
Library& lib = Library::Handle();
|
||||
String& url = String::Handle();
|
||||
for (int i = 0; i < imports.Length(); ++i) {
|
||||
ns = Namespace::RawCast(imports.At(i));
|
||||
if (ns.IsNull()) continue;
|
||||
lib = ns.library();
|
||||
url = lib.url();
|
||||
if (url.StartsWith(Symbols::DartExtensionScheme())) {
|
||||
native_import_count++;
|
||||
}
|
||||
}
|
||||
Array& new_imports =
|
||||
Array::Handle(Array::New(native_import_count, Heap::kOld));
|
||||
for (int i = 0, j = 0; i < imports.Length(); ++i) {
|
||||
ns = Namespace::RawCast(imports.At(i));
|
||||
if (ns.IsNull()) continue;
|
||||
lib = ns.library();
|
||||
url = lib.url();
|
||||
if (url.StartsWith(Symbols::DartExtensionScheme())) {
|
||||
new_imports.SetAt(j++, ns);
|
||||
}
|
||||
}
|
||||
|
||||
StorePointer(&raw_ptr()->imports_, new_imports.raw());
|
||||
StorePointer(&raw_ptr()->exports_, Object::empty_array().raw());
|
||||
StoreNonPointer(&raw_ptr()->num_imports_, 0);
|
||||
StorePointer(&raw_ptr()->resolved_names_, Array::null());
|
||||
|
@ -10831,7 +10859,7 @@ RawObject* Library::InvokeGetter(const String& getter_name,
|
|||
if (obj.IsFunction()) {
|
||||
getter = Function::Cast(obj).raw();
|
||||
if (check_is_entrypoint) {
|
||||
CHECK_ERROR(getter.VerifyEntryPoint());
|
||||
CHECK_ERROR(getter.VerifyCallEntryPoint());
|
||||
}
|
||||
} else {
|
||||
obj = LookupLocalOrReExportObject(getter_name);
|
||||
|
@ -10841,7 +10869,7 @@ RawObject* Library::InvokeGetter(const String& getter_name,
|
|||
if (obj.IsFunction() && check_is_entrypoint) {
|
||||
if (!getter_name.Equals(String::Handle(String::New("main"))) ||
|
||||
raw() != Isolate::Current()->object_store()->root_library()) {
|
||||
CHECK_ERROR(EntryPointClosurizationError(getter_name));
|
||||
CHECK_ERROR(Function::Cast(obj).VerifyClosurizedEntryPoint());
|
||||
}
|
||||
}
|
||||
if (obj.IsFunction() && Function::Cast(obj).SafeToClosurize()) {
|
||||
|
@ -10912,7 +10940,7 @@ RawObject* Library::InvokeSetter(const String& setter_name,
|
|||
}
|
||||
|
||||
if (!setter.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(setter.VerifyEntryPoint());
|
||||
CHECK_ERROR(setter.VerifyCallEntryPoint());
|
||||
}
|
||||
|
||||
const int kNumArgs = 1;
|
||||
|
@ -10950,7 +10978,7 @@ RawObject* Library::Invoke(const String& function_name,
|
|||
}
|
||||
|
||||
if (!function.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(function.VerifyEntryPoint());
|
||||
CHECK_ERROR(function.VerifyCallEntryPoint());
|
||||
}
|
||||
|
||||
if (function.IsNull()) {
|
||||
|
@ -10959,7 +10987,7 @@ RawObject* Library::Invoke(const String& function_name,
|
|||
function_name, false, respect_reflectable, check_is_entrypoint));
|
||||
if (getter_result.raw() != Object::sentinel().raw()) {
|
||||
if (check_is_entrypoint) {
|
||||
CHECK_ERROR(EntryPointClosurizationError(function_name));
|
||||
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
|
||||
}
|
||||
// Make room for the closure (receiver) in arguments.
|
||||
intptr_t numArgs = args.Length();
|
||||
|
@ -15682,7 +15710,7 @@ RawObject* Instance::InvokeGetter(const String& getter_name,
|
|||
Function& function = Function::Handle(
|
||||
zone, Resolver::ResolveDynamicAnyArgs(zone, klass, internal_getter_name));
|
||||
|
||||
if (check_is_entrypoint) {
|
||||
if (!function.IsNull() && check_is_entrypoint) {
|
||||
// The getter must correspond to either an entry-point field or a getter
|
||||
// method explicitly marked.
|
||||
Field& field = Field::Handle(zone);
|
||||
|
@ -15691,8 +15719,8 @@ RawObject* Instance::InvokeGetter(const String& getter_name,
|
|||
}
|
||||
if (!field.IsNull()) {
|
||||
CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kGetterOnly));
|
||||
} else if (!function.IsNull()) {
|
||||
CHECK_ERROR(function.VerifyEntryPoint());
|
||||
} else {
|
||||
CHECK_ERROR(function.VerifyCallEntryPoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15701,7 +15729,7 @@ RawObject* Instance::InvokeGetter(const String& getter_name,
|
|||
function = Resolver::ResolveDynamicAnyArgs(zone, klass, getter_name);
|
||||
|
||||
if (!function.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(EntryPointClosurizationError(getter_name));
|
||||
CHECK_ERROR(function.VerifyClosurizedEntryPoint());
|
||||
}
|
||||
|
||||
if (!function.IsNull() && function.SafeToClosurize()) {
|
||||
|
@ -15750,7 +15778,7 @@ RawObject* Instance::InvokeSetter(const String& setter_name,
|
|||
if (!field.IsNull()) {
|
||||
CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly));
|
||||
} else if (!setter.IsNull()) {
|
||||
CHECK_ERROR(setter.VerifyEntryPoint());
|
||||
CHECK_ERROR(setter.VerifyCallEntryPoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15778,7 +15806,7 @@ RawObject* Instance::Invoke(const String& function_name,
|
|||
zone, Resolver::ResolveDynamicAnyArgs(zone, klass, function_name));
|
||||
|
||||
if (!function.IsNull() && check_is_entrypoint) {
|
||||
CHECK_ERROR(function.VerifyEntryPoint());
|
||||
CHECK_ERROR(function.VerifyCallEntryPoint());
|
||||
}
|
||||
|
||||
// TODO(regis): Support invocation of generic functions with type arguments.
|
||||
|
@ -15798,7 +15826,7 @@ RawObject* Instance::Invoke(const String& function_name,
|
|||
function = Resolver::ResolveDynamicAnyArgs(zone, klass, getter_name);
|
||||
if (!function.IsNull()) {
|
||||
if (check_is_entrypoint) {
|
||||
CHECK_ERROR(EntryPointClosurizationError(function_name));
|
||||
CHECK_ERROR(EntryPointFieldInvocationError(function_name));
|
||||
}
|
||||
ASSERT(function.kind() != RawFunction::kMethodExtractor);
|
||||
// Invoke the getter.
|
||||
|
@ -21681,15 +21709,19 @@ EntryPointPragma FindEntryPointPragma(Isolate* I,
|
|||
if (pragma->raw() == Symbols::Set().raw()) {
|
||||
return EntryPointPragma::kSetterOnly;
|
||||
}
|
||||
if (pragma->raw() == Symbols::Call().raw()) {
|
||||
return EntryPointPragma::kCallOnly;
|
||||
}
|
||||
}
|
||||
return EntryPointPragma::kNever;
|
||||
}
|
||||
|
||||
DART_WARN_UNUSED_RESULT
|
||||
RawError* VerifyEntryPoint(const Library& lib,
|
||||
const Object& member,
|
||||
const Object& annotated,
|
||||
EntryPointPragma kind) {
|
||||
RawError* VerifyEntryPoint(
|
||||
const Library& lib,
|
||||
const Object& member,
|
||||
const Object& annotated,
|
||||
std::initializer_list<EntryPointPragma> allowed_kinds) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
// Annotations are discarded in the AOT snapshot, so we can't determine
|
||||
// precisely if this member was marked as an entry-point. Instead, we use
|
||||
|
@ -21713,13 +21745,23 @@ RawError* VerifyEntryPoint(const Library& lib,
|
|||
EntryPointPragma pragma =
|
||||
FindEntryPointPragma(Isolate::Current(), Array::Cast(metadata),
|
||||
&Field::Handle(), &Object::Handle());
|
||||
const bool is_marked_entrypoint =
|
||||
pragma == kind || pragma == EntryPointPragma::kAlways;
|
||||
bool is_marked_entrypoint = pragma == EntryPointPragma::kAlways;
|
||||
if (!is_marked_entrypoint) {
|
||||
for (const auto allowed_kind : allowed_kinds) {
|
||||
if (pragma == allowed_kind) {
|
||||
is_marked_entrypoint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!is_marked_entrypoint) {
|
||||
const char* member_cstring =
|
||||
member.IsFunction()
|
||||
? Function::Cast(member).ToLibNamePrefixedQualifiedCString()
|
||||
? OS::SCreate(
|
||||
Thread::Current()->zone(), "%s (kind %s)",
|
||||
Function::Cast(member).ToLibNamePrefixedQualifiedCString(),
|
||||
Function::KindToCString(Function::Cast(member).kind()))
|
||||
: member.ToCString();
|
||||
char const* error = OS::SCreate(
|
||||
Thread::Current()->zone(),
|
||||
|
@ -21735,12 +21777,12 @@ RawError* VerifyEntryPoint(const Library& lib,
|
|||
}
|
||||
|
||||
DART_WARN_UNUSED_RESULT
|
||||
RawError* EntryPointClosurizationError(const String& getter_name) {
|
||||
RawError* EntryPointFieldInvocationError(const String& getter_name) {
|
||||
if (!FLAG_verify_entry_points) return Error::null();
|
||||
|
||||
char const* error = OS::SCreate(
|
||||
Thread::Current()->zone(),
|
||||
"ERROR: Entry-points do not allow closurizing methods "
|
||||
"ERROR: Entry-points do not allow invoking fields "
|
||||
"(failure to resolve '%s')\n"
|
||||
"ERROR: See "
|
||||
"https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/"
|
||||
|
@ -21750,50 +21792,67 @@ RawError* EntryPointClosurizationError(const String& getter_name) {
|
|||
return ApiError::New(String::Handle(String::New(error)));
|
||||
}
|
||||
|
||||
RawError* Function::VerifyEntryPoint() const {
|
||||
RawError* Function::VerifyCallEntryPoint() const {
|
||||
if (!FLAG_verify_entry_points) return Error::null();
|
||||
|
||||
const Class& cls = Class::Handle(Owner());
|
||||
const Library& lib = Library::Handle(cls.library());
|
||||
switch (kind()) {
|
||||
case RawFunction::kRegularFunction:
|
||||
case RawFunction::kGetterFunction:
|
||||
case RawFunction::kSetterFunction:
|
||||
case RawFunction::kConstructor:
|
||||
return dart::VerifyEntryPoint(lib, *this, *this,
|
||||
EntryPointPragma::kAlways);
|
||||
{EntryPointPragma::kCallOnly});
|
||||
break;
|
||||
case RawFunction::kImplicitGetter: {
|
||||
const Field& accessed = Field::Handle(accessor_field());
|
||||
return dart::VerifyEntryPoint(lib, *this, accessed,
|
||||
EntryPointPragma::kGetterOnly);
|
||||
case RawFunction::kGetterFunction:
|
||||
return dart::VerifyEntryPoint(
|
||||
lib, *this, *this,
|
||||
{EntryPointPragma::kCallOnly, EntryPointPragma::kGetterOnly});
|
||||
break;
|
||||
}
|
||||
case RawFunction::kImplicitSetter: {
|
||||
const Field& accessed = Field::Handle(accessor_field());
|
||||
return dart::VerifyEntryPoint(lib, *this, accessed,
|
||||
EntryPointPragma::kSetterOnly);
|
||||
case RawFunction::kImplicitGetter:
|
||||
return dart::VerifyEntryPoint(lib, *this, Field::Handle(accessor_field()),
|
||||
{EntryPointPragma::kGetterOnly});
|
||||
break;
|
||||
case RawFunction::kImplicitSetter:
|
||||
return dart::VerifyEntryPoint(lib, *this, Field::Handle(accessor_field()),
|
||||
{EntryPointPragma::kSetterOnly});
|
||||
case RawFunction::kMethodExtractor:
|
||||
return Function::Handle(extracted_method_closure())
|
||||
.VerifyClosurizedEntryPoint();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return dart::VerifyEntryPoint(lib, *this, Object::Handle(),
|
||||
EntryPointPragma::kAlways);
|
||||
return dart::VerifyEntryPoint(lib, *this, Object::Handle(), {});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RawError* Function::VerifyClosurizedEntryPoint() const {
|
||||
if (!FLAG_verify_entry_points) return Error::null();
|
||||
|
||||
const Class& cls = Class::Handle(Owner());
|
||||
const Library& lib = Library::Handle(cls.library());
|
||||
switch (kind()) {
|
||||
case RawFunction::kRegularFunction:
|
||||
case RawFunction::kImplicitClosureFunction:
|
||||
return dart::VerifyEntryPoint(lib, *this, *this,
|
||||
{EntryPointPragma::kGetterOnly});
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
RawError* Field::VerifyEntryPoint(EntryPointPragma pragma) const {
|
||||
if (!FLAG_verify_entry_points) return Error::null();
|
||||
const Class& cls = Class::Handle(Owner());
|
||||
const Library& lib = Library::Handle(cls.library());
|
||||
return dart::VerifyEntryPoint(lib, *this, *this, pragma);
|
||||
return dart::VerifyEntryPoint(lib, *this, *this, {pragma});
|
||||
}
|
||||
|
||||
RawError* Class::VerifyEntryPoint() const {
|
||||
if (!FLAG_verify_entry_points) return Error::null();
|
||||
const Library& lib = Library::Handle(library());
|
||||
if (!lib.IsNull()) {
|
||||
return dart::VerifyEntryPoint(lib, *this, *this, EntryPointPragma::kAlways);
|
||||
return dart::VerifyEntryPoint(lib, *this, *this, {});
|
||||
} else {
|
||||
return Error::null();
|
||||
}
|
||||
|
|
|
@ -2606,7 +2606,10 @@ class Function : public Object {
|
|||
}
|
||||
|
||||
DART_WARN_UNUSED_RESULT
|
||||
RawError* VerifyEntryPoint() const;
|
||||
RawError* VerifyCallEntryPoint() const;
|
||||
|
||||
DART_WARN_UNUSED_RESULT
|
||||
RawError* VerifyClosurizedEntryPoint() const;
|
||||
|
||||
static intptr_t InstanceSize() {
|
||||
return RoundedAllocationSize(sizeof(RawFunction));
|
||||
|
@ -2970,7 +2973,13 @@ class RedirectionData : public Object {
|
|||
friend class HeapProfiler;
|
||||
};
|
||||
|
||||
enum class EntryPointPragma { kAlways, kNever, kGetterOnly, kSetterOnly };
|
||||
enum class EntryPointPragma {
|
||||
kAlways,
|
||||
kNever,
|
||||
kGetterOnly,
|
||||
kSetterOnly,
|
||||
kCallOnly
|
||||
};
|
||||
|
||||
class FfiTrampolineData : public Object {
|
||||
public:
|
||||
|
@ -9414,7 +9423,7 @@ EntryPointPragma FindEntryPointPragma(Isolate* I,
|
|||
Object* reusable_object_handle);
|
||||
|
||||
DART_WARN_UNUSED_RESULT
|
||||
RawError* EntryPointClosurizationError(const String& getter_name);
|
||||
RawError* EntryPointFieldInvocationError(const String& getter_name);
|
||||
|
||||
} // namespace dart
|
||||
|
||||
|
|
|
@ -907,7 +907,8 @@ class RawFunction : public RawObject {
|
|||
RawArray* parameter_types_;
|
||||
RawArray* parameter_names_;
|
||||
RawTypeArguments* type_parameters_; // Array of TypeParameter.
|
||||
RawObject* data_; // Additional data specific to the function kind.
|
||||
RawObject* data_; // Additional data specific to the function kind. See
|
||||
// Function::set_data() for details.
|
||||
RawObject** to_snapshot(Snapshot::Kind kind) {
|
||||
switch (kind) {
|
||||
case Snapshot::kFullAOT:
|
||||
|
|
|
@ -368,6 +368,7 @@ class ObjectPointerVisitor;
|
|||
V(Index, "index") \
|
||||
V(DartScheme, "dart:") \
|
||||
V(DartSchemePrivate, "dart:_") \
|
||||
V(DartExtensionScheme, "dart-ext:") \
|
||||
V(DartInternalPackage, "package:dart_internal/") \
|
||||
V(DartNativeWrappers, "dart:nativewrappers") \
|
||||
V(DartNativeWrappersLibName, "nativewrappers") \
|
||||
|
|
|
@ -37,11 +37,23 @@ class D {
|
|||
@pragma("vm:entry-point")
|
||||
void fn1() {}
|
||||
|
||||
@pragma("vm:entry-point", "get")
|
||||
void fn1_get() {}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
void fn1_call() {}
|
||||
|
||||
static void fn2() {}
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
static void fn3() {}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
static void fn3_call() {}
|
||||
|
||||
@pragma("vm:entry-point", "get")
|
||||
static void fn3_get() {}
|
||||
|
||||
void Function() fld0;
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
|
@ -59,6 +71,12 @@ void fn0() {}
|
|||
@pragma("vm:entry-point")
|
||||
void fn1() {}
|
||||
|
||||
@pragma("vm:entry-point", "get")
|
||||
void fn1_get() {}
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
void fn1_call() {}
|
||||
|
||||
class E extends D {
|
||||
E.ctor();
|
||||
}
|
||||
|
|
|
@ -225,5 +225,5 @@ io/socket_many_connections_test: Skip # Timeout
|
|||
io/web_socket_compression_test: Skip # Timeout
|
||||
io/web_socket_test: Skip # Timeout
|
||||
|
||||
[ $hot_reload || $hot_reload_rollback || $compiler != dartk && $compiler != dartkb ]
|
||||
io/entrypoints_verification_test: Skip # Test runs in JIT mode only
|
||||
[ $hot_reload || $hot_reload_rollback || $compiler != dartk && $compiler != dartkb && $compiler != dartkp || $compiler == dartkp && $system == windows ]
|
||||
io/entrypoints_verification_test: Skip # Cannot run in precompiled Windows because the DLL is linked against dart.exe instead of dart_precompiled_runtime.exe.
|
||||
|
|
Loading…
Reference in a new issue