diff --git a/runtime/bin/entrypoints_verification_test.cc b/runtime/bin/entrypoints_verification_test.cc index dc58dc222d6..869dfd6616b 100644 --- a/runtime/bin/entrypoints_verification_test.cc +++ b/runtime/bin/entrypoints_verification_test.cc @@ -2,9 +2,9 @@ // 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. -#include -#include -#include +#include +#include +#include // TODO(dartbug.com/40579): This requires static linking to either link // dart.exe or dart_precompiled_runtime.exe on Windows. @@ -12,179 +12,99 @@ #include "include/dart_api.h" #include "include/dart_native_api.h" -static bool is_dart_precompiled_runtime = true; - -bool IsTreeShaken(const char* name, Dart_Handle handle, const char* error) { - // No tree shaking in the JIT runtime. - if (!is_dart_precompiled_runtime) return false; - if (Dart_IsApiError(handle)) { - // All tree-shaking related API errors should include the expected name. - if (strstr(error, name) == nullptr) return false; - // Node was tree shaken (e.g., 'Class C not found in library...'). - if (strstr(error, " not found in ") != nullptr) return true; - // Constructor was tree shaken. - if (strstr(error, "Dart_New: could not find ") != nullptr) return true; - } else if (Dart_IsUnhandledExceptionError(handle)) { - // TFA replaces operations with a throw in some cases. If obfuscation - // is turned on and the member has no entry point annotation, then its - // name may be obfuscated in the result and so cannot be depended on. - if (strstr(error, "Attempt to execute code removed by ") != nullptr) { - return true; - } - // All other tree-shaking related unhandled exceptions are NSM errors - // that should include the expected name. - if (strstr(error, name) == nullptr) return false; - if (strstr(error, "NoSuchMethodError: ") == nullptr) { - return false; - } - if (strstr(error, "No top-level method '") != nullptr) return true; - if (strstr(error, "No top-level getter '") != nullptr) return true; - if (strstr(error, "No top-level setter '") != nullptr) return true; - if (strstr(error, "No static method '") != nullptr) return true; - if (strstr(error, "No static getter '") != nullptr) return true; - if (strstr(error, "No static setter '") != nullptr) return true; - if (strstr(error, "' has no instance method '") != nullptr) return true; - if (strstr(error, "' has no instance getter '") != nullptr) return true; - if (strstr(error, "' has no instance setter '") != nullptr) return true; - } - // Not an tree shaking-related error. - return false; -} - -#if defined(_MSC_VER) -#define FATAL(fmt, ...) \ - do { \ - fprintf(stderr, "Failed at %s:%d: " fmt "!\n", __FILE__, __LINE__, \ - __VA_ARGS__); \ - abort(); \ - } while (false) -#else -#define FATAL(fmt, ...) \ - do { \ - fprintf(stderr, "Failed at %s:%d: " fmt "!\n", __FILE__, __LINE__, \ - ##__VA_ARGS__); \ - abort(); \ - } while (false) -#endif - #define CHECK(H) \ do { \ - fprintf(stderr, "Checking %s...\n", #H); \ Dart_Handle __handle__ = H; \ if (Dart_IsError(__handle__)) { \ const char* message = Dart_GetError(__handle__); \ - FATAL("\n%s", message); \ - } else { \ - fprintf(stderr, " Check passed.\n\n"); \ + fprintf(stderr, "Check \"" #H "\" failed: %s", message); \ + abort(); \ } \ } while (false) -#define ASSERT_SUBSTRING(needle, haystack) \ - do { \ - if (strstr(haystack, needle) == nullptr) { \ - FATAL("expected '%s' within:\n%s\n", needle, haystack); \ - } \ - } while (false) +#define ASSERT(E) \ + if (!(E)) { \ + fprintf(stderr, "Assertion \"" #E "\" failed at %s:%d!\n", __FILE__, \ + __LINE__); \ + abort(); \ + } -#define FAIL(name, result) \ - do { \ - fprintf(stderr, "Expect failure to access '%s'\n", name); \ - if (!Dart_IsError(result)) { \ - FATAL("No error for accessing %s", name); \ - } \ - const char* error = Dart_GetError(result); \ - if (IsTreeShaken(name, result, error)) { \ - fprintf(stderr, " Received error due to tree shaking: %s\n\n", error); \ - } else if (!Dart_IsApiError(result)) { \ - FATAL("Not an API error for accessing %s: %s", name, error); \ - } else { \ - ASSERT_SUBSTRING(name, error); \ - ASSERT_SUBSTRING("ERROR: ", error); \ - ASSERT_SUBSTRING("' from native code, it must be annotated.", error); \ - fprintf(stderr, " Received expected error: %s\n\n", error); \ - } \ - } while (false) +static bool is_dart_precompiled_runtime = true; // Some invalid accesses are allowed in AOT since we don't retain @pragma -// annotations. Only use this if there's no other way to detect missing -// annotations, e.g., a function with no code signals that the precompiler -// did not preserve the code object because the function is not annotated -// as a "call" entry point. -#define FAIL_UNLESS_PRECOMPILED(name, result) \ - do { \ - if (!is_dart_precompiled_runtime) { \ - FAIL(name, result); \ - } else { \ - CHECK(result); \ - } \ - } while (false); +// annotations. Therefore we skip the negative tests in AOT. +#define FAIL(name, result) \ + if (!is_dart_precompiled_runtime) { \ + Fail(name, result); \ + } -#define FAIL_CLOSURIZE_CONSTRUCTOR(name, result) \ - do { \ - fprintf(stderr, "Expect failure to closurize constructor '%s'\n", name); \ - if (!Dart_IsError(result)) { \ - FATAL("No error for closurizing %s", name); \ - } \ - const char* error = Dart_GetError(result); \ - if (!Dart_IsUnhandledExceptionError(result)) { \ - FATAL("Not an unhandled exception error for closurizing %s: %s", name, \ - error); \ - } else { \ - ASSERT_SUBSTRING(name, error); \ - ASSERT_SUBSTRING("No static getter", error); \ - fprintf(stderr, " Received expected error: %s\n\n", error); \ - } \ - } while (false) +void Fail(const char* name, Dart_Handle result) { + ASSERT(Dart_IsApiError(result)); + const char* error = Dart_GetError(result); + ASSERT(strstr(error, name)); + ASSERT(strstr(error, "It is illegal to access")); +} -#define TEST_FIELDS(target) \ - do { \ - /* Since the fields start off initialized to a non-null value and then */ \ - /* are updated with a null value, check invocation prior to set. */ \ - FAIL("fld0", Dart_GetField(target, Dart_NewStringFromCString("fld0"))); \ - FAIL("fld0", \ - Dart_Invoke(target, Dart_NewStringFromCString("fld0"), 0, nullptr)); \ - FAIL("fld0", Dart_SetField(target, Dart_NewStringFromCString("fld0"), \ - Dart_Null())); \ - CHECK(Dart_GetField(target, Dart_NewStringFromCString("fld1"))); \ - CHECK(Dart_Invoke(target, Dart_NewStringFromCString("fld1"), 0, nullptr)); \ - CHECK(Dart_SetField(target, Dart_NewStringFromCString("fld1"), \ - Dart_Null())); \ - CHECK(Dart_GetField(target, Dart_NewStringFromCString("fld2"))); \ - CHECK(Dart_Invoke(target, Dart_NewStringFromCString("fld2"), 0, nullptr)); \ - if (Dart_IsLibrary(target) || Dart_IsType(target)) { \ - /* There are no implicit setters for static fields, so the pragma */ \ - /* must be checked; in precompiled mode, that means a false positive. */ \ - FAIL_UNLESS_PRECOMPILED( \ - "fld2", Dart_SetField(target, Dart_NewStringFromCString("fld2"), \ - Dart_Null())); \ - } else { \ - FAIL("fld2", Dart_SetField(target, Dart_NewStringFromCString("fld2"), \ - Dart_Null())); \ - } \ - FAIL("fld3", Dart_GetField(target, Dart_NewStringFromCString("fld3"))); \ - FAIL("fld3", \ - Dart_Invoke(target, Dart_NewStringFromCString("fld3"), 0, nullptr)); \ - CHECK(Dart_SetField(target, Dart_NewStringFromCString("fld3"), \ - Dart_Null())); \ - } while (false) +#define FAIL_INVOKE_FIELD(name, result) \ + if (!is_dart_precompiled_runtime) { \ + FailInvokeField(name, result); \ + } + +static 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 invoking fields")); +} + +static 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")); +} + +static void TestFields(Dart_Handle target) { + FAIL("fld0", Dart_GetField(target, Dart_NewStringFromCString("fld0"))); + FAIL("fld0", + Dart_SetField(target, Dart_NewStringFromCString("fld0"), Dart_Null())); + + 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())); + FAIL_INVOKE_FIELD( + "fld1", + Dart_Invoke(target, Dart_NewStringFromCString("fld1"), 0, nullptr)); + + CHECK(Dart_GetField(target, Dart_NewStringFromCString("fld2"))); + FAIL("fld2", + Dart_SetField(target, Dart_NewStringFromCString("fld2"), Dart_Null())); + FAIL_INVOKE_FIELD( + "fld2", + Dart_Invoke(target, Dart_NewStringFromCString("fld2"), 0, nullptr)); + + FAIL("fld3", Dart_GetField(target, Dart_NewStringFromCString("fld3"))); + CHECK(Dart_SetField(target, Dart_NewStringFromCString("fld3"), Dart_Null())); + FAIL_INVOKE_FIELD( + "fld3", + Dart_Invoke(target, Dart_NewStringFromCString("fld3"), 0, nullptr)); +} DART_EXPORT void RunTests() { is_dart_precompiled_runtime = Dart_IsPrecompiledRuntime(); Dart_Handle lib = Dart_RootLibrary(); - //////// Test class access. + //////// Test allocation and constructor invocation. FAIL("C", Dart_GetClass(lib, Dart_NewStringFromCString("C"))); Dart_Handle D_class = Dart_GetClass(lib, Dart_NewStringFromCString("D")); CHECK(D_class); - Dart_Handle F_class = Dart_GetClass(lib, Dart_NewStringFromCString("F")); - CHECK(F_class); - - //////// Test allocation and constructor invocation. - CHECK(Dart_Allocate(D_class)); FAIL("D.", Dart_New(D_class, Dart_Null(), 0, nullptr)); @@ -196,39 +116,30 @@ DART_EXPORT void RunTests() { //////// Test actions against methods - fprintf(stderr, "\n\nTesting methods with library target\n\n\n"); - - FAIL("noop", Dart_Invoke(lib, Dart_NewStringFromCString("noop"), 0, nullptr)); - - FAIL("fn0", Dart_Invoke(lib, Dart_NewStringFromCString("fn0"), 0, nullptr)); - - CHECK(Dart_Invoke(lib, Dart_NewStringFromCString("fn1"), 0, nullptr)); - FAIL("fn1_get", - Dart_Invoke(lib, Dart_NewStringFromCString("fn1_get"), 0, nullptr)); - CHECK(Dart_Invoke(lib, Dart_NewStringFromCString("fn1_call"), 0, nullptr)); - - FAIL("fn0", Dart_GetField(lib, Dart_NewStringFromCString("fn0"))); - - CHECK(Dart_GetField(lib, Dart_NewStringFromCString("fn1"))); - CHECK(Dart_GetField(lib, Dart_NewStringFromCString("fn1_get"))); - FAIL("fn1_call", Dart_GetField(lib, Dart_NewStringFromCString("fn1_call"))); - - fprintf(stderr, "\n\nTesting methods with class target\n\n\n"); - - FAIL_CLOSURIZE_CONSTRUCTOR( + FailClosurizeConstructor( "defined", Dart_GetField(D_class, Dart_NewStringFromCString("defined"))); - FAIL_CLOSURIZE_CONSTRUCTOR( + 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("fn0", Dart_GetField(D, Dart_NewStringFromCString("fn0"))); + + 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", 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_get", + FAIL("fn3", Dart_Invoke(D_class, Dart_NewStringFromCString("fn3_get"), 0, nullptr)); FAIL("fn2", Dart_GetField(D_class, Dart_NewStringFromCString("fn2"))); @@ -238,27 +149,25 @@ DART_EXPORT void RunTests() { Dart_GetField(D_class, Dart_NewStringFromCString("fn3_call"))); CHECK(Dart_GetField(D_class, Dart_NewStringFromCString("fn3_get"))); - fprintf(stderr, "\n\nTesting methods with instance target\n\n\n"); + FAIL("fn0", Dart_Invoke(lib, Dart_NewStringFromCString("fn0"), 0, nullptr)); - CHECK(Dart_Invoke(D, Dart_NewStringFromCString("fn1"), 0, nullptr)); - FAIL("fn1_get", - Dart_Invoke(D, Dart_NewStringFromCString("fn1_get"), 0, nullptr)); - CHECK(Dart_Invoke(D, Dart_NewStringFromCString("fn1_call"), 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)); - FAIL("fn0", Dart_GetField(D, Dart_NewStringFromCString("fn0"))); + FAIL("fn0", Dart_GetField(lib, Dart_NewStringFromCString("fn0"))); - CHECK(Dart_GetField(D, Dart_NewStringFromCString("fn1"))); - CHECK(Dart_GetField(D, Dart_NewStringFromCString("fn1_get"))); - FAIL("fn1_call", Dart_GetField(D, Dart_NewStringFromCString("fn1_call"))); + 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 - fprintf(stderr, "\n\nTesting fields with library target\n\n\n"); - TEST_FIELDS(lib); + TestFields(D); - fprintf(stderr, "\n\nTesting fields with class target\n\n\n"); - TEST_FIELDS(F_class); + Dart_Handle F_class = Dart_GetClass(lib, Dart_NewStringFromCString("F")); + TestFields(F_class); - fprintf(stderr, "\n\nTesting fields with instance target\n\n\n"); - TEST_FIELDS(D); + TestFields(lib); } diff --git a/runtime/docs/compiler/aot/entry_point_pragma.md b/runtime/docs/compiler/aot/entry_point_pragma.md index e0317579726..fc68848a9d8 100644 --- a/runtime/docs/compiler/aot/entry_point_pragma.md +++ b/runtime/docs/compiler/aot/entry_point_pragma.md @@ -4,10 +4,6 @@ The annotation `@pragma("vm:entry-point", ...)` **must** be placed on a class or member to indicate that it may be resolved, allocated or invoked directly from native or VM code _in AOT mode_. -To reduce the differences between JIT and AOT mode, entry point annotations are -also checked in JIT mode except for uses of the `dart:mirrors` library and -debugging uses via the VM service. - ## Background Dart VM precompiler (AOT compiler) performs whole-program optimizations such as @@ -92,14 +88,11 @@ three forms may be attached to static fields. int foo; ``` -If the second parameter is missing, `null` or `true`, the field is marked for +If the second parameter is missing, `null` or `true, the field is marked for native access and for non-static fields the corresponding getter and setter in the interface of the enclosing class are marked for native invocation. If the -"get" or "set" parameter is used, only the getter or setter is marked. For -static fields, the implicit getter is always marked if the field is marked -for native access. +'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. -A field containing a closure may only be invoked using Dart_Invoke if the -getter is marked, in which case it is the same as retrieving the closure from -the field using Dart_GetField and then invoking the closure using -Dart_InvokeClosure. +Note that no form of entry-point annotation allows invoking a field. diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc index 7231276cbe6..9ced70beded 100644 --- a/runtime/lib/isolate.cc +++ b/runtime/lib/isolate.cc @@ -714,7 +714,7 @@ ObjectPtr IsolateSpawnState::ResolveFunction() { // Check whether the root library defines a main function. const Library& lib = Library::Handle(zone, IG->object_store()->root_library()); - const String& main = Symbols::main(); + const String& main = String::Handle(zone, String::New("main")); Function& func = Function::Handle(zone, lib.LookupFunctionAllowPrivate(main)); if (func.IsNull()) { // Check whether main is reexported from the root library. diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index 17a485afe7e..8525f68d5cd 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -1221,8 +1221,6 @@ DEFINE_NATIVE_ENTRY(TypeVariableMirror_upper_bound, 0, 1) { return param.bound(); } -static constexpr bool kNoStrictEntryPointChecks = false; - DEFINE_NATIVE_ENTRY(InstanceMirror_invoke, 0, 5) { // Argument 0 is the mirror, which is unused by the native. It exists // because this native is an instance method in order to be polymorphic @@ -1232,8 +1230,7 @@ DEFINE_NATIVE_ENTRY(InstanceMirror_invoke, 0, 5) { arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(3)); GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4)); - RETURN_OR_PROPAGATE(reflectee.Invoke(function_name, args, arg_names, - kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(reflectee.Invoke(function_name, args, arg_names)); } DEFINE_NATIVE_ENTRY(InstanceMirror_invokeGetter, 0, 3) { @@ -1242,8 +1239,7 @@ DEFINE_NATIVE_ENTRY(InstanceMirror_invokeGetter, 0, 3) { // with its cousins. GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(1)); GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2)); - RETURN_OR_PROPAGATE( - reflectee.InvokeGetter(getter_name, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(reflectee.InvokeGetter(getter_name)); } DEFINE_NATIVE_ENTRY(InstanceMirror_invokeSetter, 0, 4) { @@ -1253,8 +1249,7 @@ DEFINE_NATIVE_ENTRY(InstanceMirror_invokeSetter, 0, 4) { GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(1)); GET_NON_NULL_NATIVE_ARGUMENT(String, setter_name, arguments->NativeArgAt(2)); GET_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(3)); - RETURN_OR_PROPAGATE( - reflectee.InvokeSetter(setter_name, value, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(reflectee.InvokeSetter(setter_name, value)); } DEFINE_NATIVE_ENTRY(InstanceMirror_computeType, 0, 1) { @@ -1314,8 +1309,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invoke, 0, 5) { arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(3)); GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4)); - RETURN_OR_PROPAGATE( - klass.Invoke(function_name, args, arg_names, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(klass.Invoke(function_name, args, arg_names)); } DEFINE_NATIVE_ENTRY(ClassMirror_invokeGetter, 0, 3) { @@ -1330,8 +1324,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeGetter, 0, 3) { UNREACHABLE(); } GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2)); - RETURN_OR_PROPAGATE( - klass.InvokeGetter(getter_name, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(klass.InvokeGetter(getter_name, true)); } DEFINE_NATIVE_ENTRY(ClassMirror_invokeSetter, 0, 4) { @@ -1342,8 +1335,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeSetter, 0, 4) { const Class& klass = Class::Handle(ref.GetClassReferent()); GET_NON_NULL_NATIVE_ARGUMENT(String, setter_name, arguments->NativeArgAt(2)); GET_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(3)); - RETURN_OR_PROPAGATE( - klass.InvokeSetter(setter_name, value, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(klass.InvokeSetter(setter_name, value)); } DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 0, 5) { @@ -1496,8 +1488,7 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_invoke, 0, 5) { arguments->NativeArgAt(2)); GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(3)); GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4)); - RETURN_OR_PROPAGATE(library.Invoke(function_name, args, arg_names, - kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(library.Invoke(function_name, args, arg_names)); } DEFINE_NATIVE_ENTRY(LibraryMirror_invokeGetter, 0, 3) { @@ -1507,8 +1498,7 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_invokeGetter, 0, 3) { GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1)); const Library& library = Library::Handle(ref.GetLibraryReferent()); GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2)); - RETURN_OR_PROPAGATE( - library.InvokeGetter(getter_name, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(library.InvokeGetter(getter_name, true)); } DEFINE_NATIVE_ENTRY(LibraryMirror_invokeSetter, 0, 4) { @@ -1519,8 +1509,7 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_invokeSetter, 0, 4) { const Library& library = Library::Handle(ref.GetLibraryReferent()); GET_NON_NULL_NATIVE_ARGUMENT(String, setter_name, arguments->NativeArgAt(2)); GET_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(3)); - RETURN_OR_PROPAGATE( - library.InvokeSetter(setter_name, value, kNoStrictEntryPointChecks)); + RETURN_OR_PROPAGATE(library.InvokeSetter(setter_name, value)); } DEFINE_NATIVE_ENTRY(MethodMirror_owner, 0, 2) { diff --git a/runtime/tests/vm/dart/entrypoints_verification_test.dart b/runtime/tests/vm/dart/entrypoints_verification_test.dart index e74bbd6f4da..a64e3472c68 100644 --- a/runtime/tests/vm/dart/entrypoints_verification_test.dart +++ b/runtime/tests/vm/dart/entrypoints_verification_test.dart @@ -2,19 +2,21 @@ // 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. // +// VMOptions=--verify-entry-points=true // SharedObjects=entrypoints_verification_test import 'dart:ffi'; import './dylib_utils.dart'; -main(List args) { +main() { final helper = dlopenPlatformSpecific('entrypoints_verification_test'); final runTest = helper.lookupFunction('RunTests'); runTest(); -} -final void Function() noop = () {}; + new C(); + new D(); +} class C {} @@ -50,16 +52,16 @@ class D { @pragma("vm:entry-point", "get") static void fn3_get() {} - void Function()? fld0 = noop; + void Function()? fld0; @pragma("vm:entry-point") - void Function()? fld1 = noop; + void Function()? fld1; @pragma("vm:entry-point", "get") - void Function()? fld2 = noop; + void Function()? fld2; @pragma("vm:entry-point", "set") - void Function()? fld3 = noop; + void Function()? fld3; } void fn0() {} @@ -79,25 +81,25 @@ class E extends D { @pragma("vm:entry-point") class F { - static void Function()? fld0 = noop; + static void Function()? fld0; @pragma("vm:entry-point") - static void Function()? fld1 = noop; + static void Function()? fld1; @pragma("vm:entry-point", "get") - static void Function()? fld2 = noop; + static void Function()? fld2; @pragma("vm:entry-point", "set") - static void Function()? fld3 = noop; + static void Function()? fld3; } -void Function()? fld0 = noop; +void Function()? fld0; @pragma("vm:entry-point") -void Function()? fld1 = noop; +void Function()? fld1; @pragma("vm:entry-point", "get") -void Function()? fld2 = noop; +void Function()? fld2; @pragma("vm:entry-point", "set") -void Function()? fld3 = noop; +void Function()? fld3; diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc index 66f007c234a..2a6952b7770 100644 --- a/runtime/vm/benchmark_test.cc +++ b/runtime/vm/benchmark_test.cc @@ -176,7 +176,6 @@ base class Class extends NativeFieldWrapperClass1 { external int method(int param1, int param2); } -@pragma('vm:entry-point', 'call') void benchmark(int count) { Class c = Class(); c.init(); @@ -337,9 +336,7 @@ BENCHMARK(FrameLookup) { return StackFrame.accessFrame(); } } - @pragma('vm:entry-point') class StackFrameTest { - @pragma('vm:entry-point', 'call') static int testMain() { First obj = new First(); return obj.method1(1); @@ -433,7 +430,6 @@ BENCHMARK(CreateMirrorSystem) { const char* kScriptChars = "import 'dart:mirrors';\n" "\n" - "@pragma('vm:entry-point', 'call')\n" "void benchmark() {\n" " currentMirrorSystem();\n" "}\n"; @@ -539,7 +535,6 @@ BENCHMARK(SimpleMessage) { BENCHMARK(LargeMap) { const char* kScript = - "@pragma('vm:entry-point', 'call')\n" "makeMap() {\n" " Map m = {};\n" " for (int i = 0; i < 100000; ++i) m[i*13+i*(i>>7)] = i;\n" diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index 94e90ac87f8..61811efad53 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc @@ -738,7 +738,7 @@ void Precompiler::AddRoots() { UNREACHABLE(); } - const String& name = Symbols::main(); + const String& name = String::Handle(String::New("main")); Function& main = Function::Handle(lib.LookupFunctionAllowPrivate(name)); if (main.IsNull()) { const Object& obj = Object::Handle(lib.LookupReExport(name)); @@ -1381,10 +1381,20 @@ const char* Precompiler::MustRetainFunction(const Function& function) { // * Native functions (for LinkNativeCall) // * Selector matches a symbol used in Resolver::ResolveDynamic calls // in dart_entry.cc or dart_api_impl.cc. + // * _Closure.call (used in async stack handling) if (function.is_old_native()) { return "native function"; } + // Use the same check for _Closure.call as in stack_trace.{h|cc}. + const auto& selector = String::Handle(Z, function.name()); + if (selector.ptr() == Symbols::call().ptr()) { + const auto& name = String::Handle(Z, function.QualifiedScrubbedName()); + if (name.Equals(Symbols::_ClosureCall())) { + return "_Closure.call"; + } + } + // We have to retain functions which can be a target of a SwitchableCall // at AOT runtime, since the AOT runtime needs to be able to find the // function object in the class. diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc index 212cfbfd905..43a6867250b 100644 --- a/runtime/vm/compiler/backend/il_test_helper.cc +++ b/runtime/vm/compiler/backend/il_test_helper.cc @@ -81,15 +81,12 @@ TypeParameterPtr GetFunctionTypeParameter(const Function& fun, intptr_t index) { return param.ptr(); } -ObjectPtr Invoke(const Library& lib, - const char* name, - bool check_is_entrypoint) { +ObjectPtr Invoke(const Library& lib, const char* name) { Thread* thread = Thread::Current(); Dart_Handle api_lib = Api::NewHandle(thread, lib.ptr()); Dart_Handle result; { TransitionVMToNative transition(thread); - SetFlagScope sfs(&FLAG_verify_entry_points, check_is_entrypoint); result = Dart_Invoke(api_lib, NewString(name), /*argc=*/0, /*argv=*/nullptr); EXPECT_VALID(result); diff --git a/runtime/vm/compiler/backend/il_test_helper.h b/runtime/vm/compiler/backend/il_test_helper.h index 5bd608728d8..25f140ba70d 100644 --- a/runtime/vm/compiler/backend/il_test_helper.h +++ b/runtime/vm/compiler/backend/il_test_helper.h @@ -65,9 +65,7 @@ ClassPtr GetClass(const Library& lib, const char* name); TypeParameterPtr GetClassTypeParameter(const Class& klass, intptr_t index); TypeParameterPtr GetFunctionTypeParameter(const Function& fun, intptr_t index); -ObjectPtr Invoke(const Library& lib, - const char* name, - bool check_is_entrypoint = false); +ObjectPtr Invoke(const Library& lib, const char* name); InstructionsPtr BuildInstructions( std::function fun); diff --git a/runtime/vm/compiler/backend/inliner_test.cc b/runtime/vm/compiler/backend/inliner_test.cc index 93a07b674b0..d758d064e28 100644 --- a/runtime/vm/compiler/backend/inliner_test.cc +++ b/runtime/vm/compiler/backend/inliner_test.cc @@ -580,9 +580,7 @@ external InspectStack(); @pragma('vm:never-inline') void nop() {} -@pragma('vm:entry-point', 'get') int prologueCount = 0; -@pragma('vm:entry-point', 'get') int epilogueCount = 0; @pragma('vm:never-inline') diff --git a/runtime/vm/compiler/backend/redundancy_elimination_test.cc b/runtime/vm/compiler/backend/redundancy_elimination_test.cc index e04a92557fe..06a3efc2543 100644 --- a/runtime/vm/compiler/backend/redundancy_elimination_test.cc +++ b/runtime/vm/compiler/backend/redundancy_elimination_test.cc @@ -1940,7 +1940,6 @@ ISOLATE_UNIT_TEST_CASE(Ffi_StructSinking) { external int a; } - @pragma('vm:entry-point') int test(int addr) => Pointer.fromAddress(addr)[0].a; )"; diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc index b41522c92c1..26f62a4425d 100644 --- a/runtime/vm/compiler_test.cc +++ b/runtime/vm/compiler_test.cc @@ -176,16 +176,13 @@ ISOLATE_UNIT_TEST_CASE(RegenerateAllocStubs) { TEST_CASE(EvalExpression) { const char* kScriptChars = - R"( - int ten = 2 * 5; - get dot => '.'; - class A { - var apa = 'Herr Nilsson'; - calc(x) => '${x*ten}'; - } - @pragma('vm:entry-point', 'call') - makeObj() => new A(); - )"; + "int ten = 2 * 5; \n" + "get dot => '.'; \n" + "class A { \n" + " var apa = 'Herr Nilsson'; \n" + " calc(x) => '${x*ten}'; \n" + "} \n" + "makeObj() => new A(); \n"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle obj_handle = diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc index cdec10dd936..ce51db403b4 100644 --- a/runtime/vm/custom_isolate_test.cc +++ b/runtime/vm/custom_isolate_test.cc @@ -29,7 +29,6 @@ static const char* kCustomIsolateScriptChars = import 'dart:isolate'; final RawReceivePort mainPort = new RawReceivePort(); - @pragma('vm:entry-point', 'get') final SendPort mainSendPort = mainPort.sendPort; @pragma('vm:external-name', 'native_echo') @@ -56,7 +55,6 @@ static const char* kCustomIsolateScriptChars = SendPort spawn(); } - @pragma('vm:entry-point', 'call') isolateMain() { echo('Running isolateMain'); mainPort.handler = (message) { diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index d109c2454fe..bd3b4a4f203 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -4200,10 +4200,8 @@ static ObjectPtr ResolveConstructor(const char* current_func, current_func, constr_name.ToCString(), error_message.ToCString())); return ApiError::New(message); } - if (FLAG_verify_entry_points) { - ErrorPtr error = constructor.VerifyEntryPoint(EntryPointPragma::kCallOnly); - if (error != Error::null()) return error; - } + ErrorPtr error = constructor.VerifyCallEntryPoint(); + if (error != Error::null()) return error; return constructor.ptr(); } @@ -4266,9 +4264,7 @@ DART_EXPORT Dart_Handle Dart_New(Dart_Handle type, Instance& new_object = Instance::Handle(Z); if (constructor.IsGenerativeConstructor()) { - if (FLAG_verify_entry_points) { - CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); - } + CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); #if defined(DEBUG) if (!cls.is_allocated() && (Dart::vm_snapshot_kind() == Snapshot::kFullAOT)) { @@ -4387,9 +4383,7 @@ DART_EXPORT Dart_Handle Dart_Allocate(Dart_Handle type) { const TypeArguments& type_arguments = TypeArguments::Handle(Z, type_obj.GetInstanceTypeArguments(T)); - if (FLAG_verify_entry_points) { - CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); - } + CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); #if defined(DEBUG) if (!cls.is_allocated() && (Dart::vm_snapshot_kind() == Snapshot::kFullAOT)) { return Api::NewError("Precompilation dropped '%s'", cls.ToCString()); @@ -4419,9 +4413,7 @@ Dart_AllocateWithNativeFields(Dart_Handle type, RETURN_NULL_ERROR(native_fields); } const Class& cls = Class::Handle(Z, type_obj.type_class()); - if (FLAG_verify_entry_points) { - CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); - } + CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); #if defined(DEBUG) if (!cls.is_allocated() && (Dart::vm_snapshot_kind() == Snapshot::kFullAOT)) { return Api::NewError("Precompilation dropped '%s'", cls.ToCString()); @@ -4513,10 +4505,7 @@ DART_EXPORT Dart_Handle Dart_InvokeConstructor(Dart_Handle object, if (!constructor.IsNull() && constructor.IsGenerativeConstructor() && constructor.AreValidArgumentCounts( kTypeArgsLen, number_of_arguments + extra_args, 0, nullptr)) { - if (FLAG_verify_entry_points) { - CHECK_ERROR_HANDLE( - constructor.VerifyEntryPoint(EntryPointPragma::kCallOnly)); - } + CHECK_ERROR_HANDLE(constructor.VerifyCallEntryPoint()); // Create the argument list. Dart_Handle result; Array& args = Array::Handle(Z); @@ -4596,8 +4585,8 @@ DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, return result; } return Api::NewHandle( - T, cls.Invoke(function_name, args, arg_names, check_is_entrypoint, - respect_reflectable)); + T, cls.Invoke(function_name, args, arg_names, respect_reflectable, + check_is_entrypoint)); } else if (obj.IsNull() || obj.IsInstance()) { // Since we have allocated an object it would mean that the type of the // receiver is already resolved and finalized, hence it is not necessary @@ -4612,8 +4601,8 @@ DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, } args.SetAt(0, instance); return Api::NewHandle( - T, instance.Invoke(function_name, args, arg_names, check_is_entrypoint, - respect_reflectable)); + T, instance.Invoke(function_name, args, arg_names, respect_reflectable, + check_is_entrypoint)); } else if (obj.IsLibrary()) { // Check whether class finalization is needed. const Library& lib = Library::Cast(obj); @@ -4635,8 +4624,8 @@ DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, } return Api::NewHandle( - T, lib.Invoke(function_name, args, arg_names, check_is_entrypoint, - respect_reflectable)); + T, lib.Invoke(function_name, args, arg_names, respect_reflectable, + check_is_entrypoint)); } else { return Api::NewError( "%s expects argument 'target' to be an object, type, or library.", @@ -4686,6 +4675,7 @@ DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name) { RETURN_TYPE_ERROR(Z, name, String); } const Object& obj = Object::Handle(Z, Api::UnwrapHandle(container)); + const bool throw_nsm_if_absent = true; const bool respect_reflectable = false; const bool check_is_entrypoint = FLAG_verify_entry_points; @@ -4700,8 +4690,9 @@ DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name) { const Library& lib = Library::Handle(Z, cls.library()); field_name = lib.PrivateName(field_name); } - return Api::NewHandle(T, cls.InvokeGetter(field_name, check_is_entrypoint, - respect_reflectable)); + return Api::NewHandle( + T, cls.InvokeGetter(field_name, throw_nsm_if_absent, + respect_reflectable, check_is_entrypoint)); } else if (obj.IsNull() || obj.IsInstance()) { Instance& instance = Instance::Handle(Z); instance ^= obj.ptr(); @@ -4711,8 +4702,8 @@ DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name) { field_name = lib.PrivateName(field_name); } return Api::NewHandle(T, - instance.InvokeGetter(field_name, check_is_entrypoint, - respect_reflectable)); + instance.InvokeGetter(field_name, respect_reflectable, + check_is_entrypoint)); } else if (obj.IsLibrary()) { const Library& lib = Library::Cast(obj); // Check that the library is loaded. @@ -4724,8 +4715,9 @@ DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name) { if (Library::IsPrivate(field_name)) { field_name = lib.PrivateName(field_name); } - return Api::NewHandle(T, lib.InvokeGetter(field_name, check_is_entrypoint, - respect_reflectable)); + return Api::NewHandle( + T, lib.InvokeGetter(field_name, throw_nsm_if_absent, + respect_reflectable, check_is_entrypoint)); } else if (obj.IsError()) { return container; } else { @@ -4775,8 +4767,8 @@ DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, field_name = lib.PrivateName(field_name); } return Api::NewHandle( - T, cls.InvokeSetter(field_name, value_instance, check_is_entrypoint, - respect_reflectable)); + T, cls.InvokeSetter(field_name, value_instance, respect_reflectable, + check_is_entrypoint)); } else if (obj.IsNull() || obj.IsInstance()) { Instance& instance = Instance::Handle(Z); instance ^= obj.ptr(); @@ -4787,7 +4779,7 @@ DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, } return Api::NewHandle( T, instance.InvokeSetter(field_name, value_instance, - check_is_entrypoint, respect_reflectable)); + respect_reflectable, check_is_entrypoint)); } else if (obj.IsLibrary()) { // To access a top-level we may need to use the Field or the // setter Function. The setter function may either be in the @@ -4804,8 +4796,8 @@ DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, field_name = lib.PrivateName(field_name); } return Api::NewHandle( - T, lib.InvokeSetter(field_name, value_instance, check_is_entrypoint, - respect_reflectable)); + T, lib.InvokeSetter(field_name, value_instance, respect_reflectable, + check_is_entrypoint)); } else if (obj.IsError()) { return container; } @@ -5489,9 +5481,7 @@ DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, cls_name.ToCString(), lib_name.ToCString()); } cls.EnsureDeclarationLoaded(); - if (FLAG_verify_entry_points) { - CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); - } + CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); return Api::NewHandle(T, cls.RareType()); } @@ -5521,9 +5511,7 @@ static Dart_Handle GetTypeCommon(Dart_Handle library, name_str.ToCString(), lib_name.ToCString()); } cls.EnsureDeclarationLoaded(); - if (FLAG_verify_entry_points) { - CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); - } + CHECK_ERROR_HANDLE(cls.VerifyEntryPoint()); Type& type = Type::Handle(); if (cls.NumTypeArguments() == 0) { diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index 258efa8a574..b164ae00c97 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc @@ -16,7 +16,6 @@ #include "vm/dart.h" #include "vm/dart_api_state.h" #include "vm/debugger_api_impl_test.h" -#include "vm/flags.h" #include "vm/heap/verifier.h" #include "vm/lockers.h" #include "vm/timeline.h" @@ -45,7 +44,6 @@ UNIT_TEST_CASE(DartAPI_DartInitializeAfterCleanup) { { TestIsolateScope scope; const char* kScriptChars = - "@pragma('vm:entry-point', 'call')\n" "int testMain() {\n" " return 42;\n" "}\n"; @@ -139,7 +137,6 @@ UNIT_TEST_CASE(DartAPI_DartInitializeHeapSizes) { TEST_CASE(Dart_KillIsolate) { const char* kScriptChars = - "@pragma('vm:entry-point', 'call')\n" "int testMain() {\n" " return 42;\n" "}\n"; @@ -164,7 +161,6 @@ class InfiniteLoopTask : public ThreadPool::Task { virtual void Run() { TestIsolateScope scope; const char* kScriptChars = - "@pragma('vm:entry-point', 'call')\n" "testMain() {\n" " while(true) {};" "}\n"; @@ -215,7 +211,6 @@ TEST_CASE(Dart_KillIsolatePriority) { TEST_CASE(DartAPI_ErrorHandleBasics) { const char* kScriptChars = - "@pragma('vm:entry-point', 'call')\n" "void testMain() {\n" " throw new Exception(\"bad news\");\n" "}\n"; @@ -238,7 +233,7 @@ TEST_CASE(DartAPI_ErrorHandleBasics) { EXPECT_STREQ("myerror", Dart_GetError(error)); EXPECT_STREQ(ZONE_STR("Unhandled exception:\n" "Exception: bad news\n" - "#0 testMain (%s:3:3)", + "#0 testMain (%s:2:3)", TestCase::url()), Dart_GetError(exception)); @@ -254,7 +249,6 @@ TEST_CASE(DartAPI_StackTraceInfo) { const char* kScriptChars = "bar() => throw new Error();\n" "foo() => bar();\n" - "@pragma('vm:entry-point', 'call')\n" "testMain() => foo();\n"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); @@ -311,7 +305,7 @@ TEST_CASE(DartAPI_StackTraceInfo) { EXPECT_STREQ("testMain", cstr); Dart_StringToCString(script_url, &cstr); EXPECT_SUBSTRING("test-lib", cstr); - EXPECT_EQ(4, line_number); + EXPECT_EQ(3, line_number); EXPECT_EQ(15, column_number); // Out-of-bounds frames. @@ -324,7 +318,6 @@ TEST_CASE(DartAPI_StackTraceInfo) { TEST_CASE(DartAPI_DeepStackTraceInfo) { const char* kScriptChars = "foo(n) => n == 1 ? throw new Error() : foo(n-1);\n" - "@pragma('vm:entry-point', 'call')\n" "testMain() => foo(100);\n"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); @@ -390,7 +383,7 @@ TEST_CASE(DartAPI_DeepStackTraceInfo) { EXPECT_STREQ("testMain", cstr); Dart_StringToCString(script_url, &cstr); EXPECT_SUBSTRING("test-lib", cstr); - EXPECT_EQ(3, line_number); + EXPECT_EQ(2, line_number); EXPECT_EQ(15, column_number); // Out-of-bounds frames. @@ -406,11 +399,8 @@ void VerifyStackOverflowStackTraceInfo(const char* script, int expected_line_number, int expected_column_number) { Dart_Handle lib = TestCase::LoadTestScript(script, nullptr); - Dart_Handle error; - { - SetFlagScope sfs(&FLAG_verify_entry_points, false); - error = Dart_Invoke(lib, NewString(entry_func_name), 0, nullptr); - } + Dart_Handle error = Dart_Invoke(lib, NewString(entry_func_name), 0, nullptr); + EXPECT(Dart_IsError(error)); Dart_StackTrace stacktrace; @@ -487,7 +477,6 @@ TEST_CASE(DartAPI_StackOverflowStackTraceInfoArrowFunction) { TEST_CASE(DartAPI_OutOfMemoryStackTraceInfo) { const char* kScriptChars = "var number_of_ints = 134000000;\n" - "@pragma('vm:entry-point', 'call')" "testMain() {\n" " new List(number_of_ints)\n" "}\n"; @@ -577,7 +566,7 @@ void CurrentStackTraceNative(Dart_NativeArguments args) { EXPECT_STREQ("testMain", cstr); Dart_StringToCString(script_url, &cstr); EXPECT_STREQ(test_lib, cstr); - EXPECT_EQ(6, line_number); + EXPECT_EQ(5, line_number); EXPECT_EQ(15, column_number); // Out-of-bounds frames. @@ -604,7 +593,6 @@ TEST_CASE(DartAPI_CurrentStackTraceInfo) { @pragma("vm:external-name", "CurrentStackTraceNative") external inspectStack(); foo(n) => n == 1 ? inspectStack() : foo(n-1); -@pragma("vm:entry-point", "call") testMain() => foo(100); )"; @@ -747,7 +735,6 @@ exitRightNow() { @pragma("vm:external-name", "Test_nativeFunc") external void nativeFunc(closure); -@pragma("vm:entry-point", "call") void Func1() { nativeFunc(() => exitRightNow()); } @@ -778,7 +765,6 @@ sendAndExitNow() { @pragma("vm:external-name", "Test_nativeFunc") external void nativeFunc(closure); -@pragma("vm:entry-point", "call") void Func1() { nativeFunc(() => sendAndExitNow()); } @@ -838,7 +824,6 @@ raiseCompileError() { @pragma("vm:external-name", "Test_nativeFunc") external void nativeFunc(closure); -@pragma("vm:entry-point", "call") void Func1() { nativeFunc(() => raiseCompileError()); } @@ -882,7 +867,6 @@ void throwException() { @pragma("vm:external-name", "Test_nativeFunc") external void nativeFunc(closure); -@pragma("vm:entry-point", "call") void Func2() { nativeFunc(() => throwException()); } @@ -1105,7 +1089,6 @@ TEST_CASE(DartAPI_InstanceGetType) { TEST_CASE(DartAPI_FunctionName) { const char* kScriptChars = "int getInt() { return 1; }\n"; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); @@ -1126,7 +1109,6 @@ TEST_CASE(DartAPI_FunctionName) { TEST_CASE(DartAPI_FunctionOwner) { const char* kScriptChars = "int getInt() { return 1; }\n"; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); @@ -1163,7 +1145,6 @@ TEST_CASE(DartAPI_IsTearOff) { " int bar() => 24;\n" "}\n" "Baz getBaz() => Baz();\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); @@ -1212,7 +1193,6 @@ TEST_CASE(DartAPI_FunctionIsStatic) { "int getInt() { return 1; }\n" "class Foo { String getString() => 'foobar'; }\n"; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); @@ -1249,7 +1229,6 @@ TEST_CASE(DartAPI_FunctionIsStatic) { TEST_CASE(DartAPI_ClosureFunction) { const char* kScriptChars = "int getInt() { return 1; }\n"; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); @@ -1280,7 +1259,6 @@ TEST_CASE(DartAPI_GetStaticMethodClosure) { " }\n" "}\n"; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); Dart_Handle foo_cls = Dart_GetClass(lib, NewString("Foo")); @@ -1401,7 +1379,6 @@ TEST_CASE(DartAPI_NumberValues) { "double getDouble() { return 1.0; }\n" "bool getBool() { return false; }\n" "getNull() { return null; }\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle result; // Create a test library and Load up a test script in it. Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); @@ -1664,14 +1641,12 @@ TEST_CASE(DartAPI_MalformedStringToUTF8) { // Strings are allowed to have individual or out of order surrogates, even // if that doesn't make sense as renderable characters. const char* kScriptChars = - "@pragma('vm:entry-point', 'call')" "String lowSurrogate() {" " return '\\u{1D11E}'[1];" "}" "String highSurrogate() {" " return '\\u{1D11E}'[0];" "}" - "@pragma('vm:entry-point', 'call')" "String reversed() => lowSurrogate() + highSurrogate();"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); @@ -1708,7 +1683,6 @@ TEST_CASE(DartAPI_MalformedStringToUTF8) { TEST_CASE(DartAPI_CopyUTF8EncodingOfString) { const char* kScriptChars = - "@pragma('vm:entry-point', 'call')" "String lowSurrogate() {" " return '\\u{1D11E}'[1];" "}"; @@ -1774,7 +1748,6 @@ TEST_CASE(DartAPI_ListAccess) { "List immutable() {" " return const [0, 1, 2];" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle result; // Create a test library and Load up a test script in it. @@ -1915,7 +1888,6 @@ TEST_CASE(DartAPI_ListAccess) { TEST_CASE(DartAPI_MapAccess) { EXPECT(!Dart_IsMap(Dart_Null())); const char* kScriptChars = - "@pragma('vm:entry-point', 'call')" "Map testMain() {" " return {" " 'a' : 1," @@ -2008,7 +1980,6 @@ TEST_CASE(DartAPI_MapAccess) { TEST_CASE(DartAPI_IsFuture) { const char* kScriptChars = "import 'dart:async';" - "@pragma('vm:entry-point', 'call')" "Future testMain() {" " return new Completer().future;" "}"; @@ -2036,7 +2007,6 @@ TEST_CASE(DartAPI_TypedDataViewListGetAsBytes) { const char* kScriptChars = "import 'dart:typed_data';\n" - "@pragma('vm:entry-point', 'call')\n" "List testMain(int size) {\n" " var a = new Int8List(size);\n" " var view = new Int8List.view(a.buffer, 0, size);\n" @@ -2069,7 +2039,6 @@ TEST_CASE(DartAPI_TypedDataViewListIsTypedData) { const char* kScriptChars = "import 'dart:typed_data';\n" - "@pragma('vm:entry-point', 'call')\n" "List testMain(int size) {\n" " var a = new Int8List(size);\n" " var view = new Int8List.view(a.buffer, 0, size);\n" @@ -2093,7 +2062,6 @@ TEST_CASE(DartAPI_UnmodifiableTypedDataViewListIsTypedData) { const char* kScriptChars = "import 'dart:typed_data';\n" - "@pragma('vm:entry-point', 'call')\n" "List testMain(int size) {\n" " var a = new Int8List(size);\n" " var view = a.asUnmodifiableView();\n" @@ -2370,11 +2338,9 @@ TEST_CASE(DartAPI_ExternalByteDataFinalizer) { // wrapper. const char* kScriptChars = "var array;\n" - "@pragma('vm:entry-point', 'call')\n" "extractAndSaveArray(byteData) {\n" " array = byteData.buffer.asUint8List();\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "releaseArray() {\n" " array = null;\n" "}\n"; @@ -2554,10 +2520,7 @@ static void TestDirectAccess(Dart_Handle lib, // Invoke the dart function that sets initial values. Dart_Handle dart_args[1]; dart_args[0] = array; - { - SetFlagScope sfs(&FLAG_verify_entry_points, false); - result = Dart_Invoke(lib, NewString("setMain"), 1, dart_args); - } + result = Dart_Invoke(lib, NewString("setMain"), 1, dart_args); EXPECT_VALID(result); // Now Get a direct access to this typed data object and check it's contents. @@ -2592,10 +2555,7 @@ static void TestDirectAccess(Dart_Handle lib, EXPECT_VALID(result); // Invoke the dart function in order to check the modified values. - { - SetFlagScope sfs(&FLAG_verify_entry_points, false); - result = Dart_Invoke(lib, NewString("testMain"), 1, dart_args); - } + result = Dart_Invoke(lib, NewString("testMain"), 1, dart_args); EXPECT_VALID(result); } @@ -2856,14 +2816,12 @@ class Expect { if (!threw) throw 'did not throw'; } } -@pragma('vm:entry-point', 'call') testList(data) { for (var i = 0; i < data.length; i++) { Expect.equals(i, data[i]); Expect.throws(() => data[i] = 0); } } -@pragma('vm:entry-point', 'call') testBytes(data) { for (var i = 0; i < data.length; i++) { Expect.equals(i, data.getUint8(i)); @@ -3024,7 +2982,6 @@ testBytes(data) { TEST_CASE(DartAPI_UnmodifiableTypedData_PassByReference) { const char* kScriptChars = R"( import 'dart:isolate'; -@pragma('vm:entry-point', 'call') test(original) { var port = new RawReceivePort(); port.handler = (msg) { @@ -3154,7 +3111,6 @@ TEST_CASE(DartAPI_ExternalClampedTypedDataAccess) { TEST_CASE(DartAPI_ExternalUint8ClampedArrayAccess) { const char* kScriptChars = - "@pragma('vm:entry-point', 'call')\n" "testClamped(List a) {\n" " if (a[1] != 11) return false;\n" " a[1] = 3;\n" @@ -3290,7 +3246,6 @@ static void CheckFloat32x4Data(Dart_Handle obj) { TEST_CASE(DartAPI_Float32x4List) { const char* kScriptChars = "import 'dart:typed_data';\n" - "@pragma('vm:entry-point', 'call')\n" "Float32x4List float32x4() {\n" " return new Float32x4List(10);\n" "}\n"; @@ -3751,7 +3706,6 @@ TEST_CASE(DartAPI_FinalizableHandle) { } TEST_CASE(DartAPI_WeakPersistentHandleErrors) { - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_EnterScope(); // nullptr callback. @@ -3812,7 +3766,6 @@ TEST_CASE(DartAPI_WeakPersistentHandleErrors) { } TEST_CASE(DartAPI_FinalizableHandleErrors) { - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_EnterScope(); // nullptr callback. @@ -4947,7 +4900,6 @@ TEST_CASE(DartAPI_TypeGetNonParametricTypes) { "Type getMyClass0Type() { return new MyClass0().runtimeType; }\n" "Type getMyClass1Type() { return new MyClass1().runtimeType; }\n" "Type getMyClass2Type() { return new MyClass2().runtimeType; }\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); bool instanceOf = false; @@ -5062,7 +5014,6 @@ TEST_CASE(DartAPI_TypeGetParameterizedTypes) { "Type getListIntType() { return type>(); }\n" "Type getListType() { return List; }\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core")); EXPECT_VALID(corelib); @@ -5277,7 +5228,6 @@ TEST_CASE(DartAPI_FieldAccess) { "}\n"; // Shared setup. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("Fields"), 0, nullptr); @@ -5441,9 +5391,7 @@ TEST_CASE(DartAPI_FieldAccess) { } TEST_CASE(DartAPI_SetField_FunnyValue) { - const char* kScriptChars = - "@pragma('vm:entry-point')\n" - "var top;\n"; + const char* kScriptChars = "var top;\n"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle name = NewString("top"); @@ -5475,9 +5423,7 @@ TEST_CASE(DartAPI_SetField_FunnyValue) { } TEST_CASE(DartAPI_SetField_BadType) { - const char* kScriptChars = - "@pragma('vm:entry-point', 'set')\n" - "late int foo;\n"; + const char* kScriptChars = "late int foo;\n"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle name = NewString("foo"); Dart_Handle result = Dart_SetField(lib, name, Dart_True()); @@ -5508,7 +5454,6 @@ TEST_CASE(DartAPI_InjectNativeFields2) { " static int? fld3;\n" " static const int fld4 = 10;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "NativeFields testMain() {\n" " NativeFields obj = new NativeFields(10, 20);\n" " return obj;\n" @@ -5541,7 +5486,6 @@ TEST_CASE(DartAPI_InjectNativeFields3) { " static int? fld3;\n" " static const int fld4 = 10;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "NativeFields testMain() {\n" " NativeFields obj = new NativeFields(10, 20);\n" " return obj;\n" @@ -5585,7 +5529,6 @@ TEST_CASE(DartAPI_InjectNativeFields4) { " static int? fld3;\n" " static const int fld4 = 10;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "NativeFields testMain() {\n" " NativeFields obj = new NativeFields(10, 20);\n" " return obj;\n" @@ -5689,7 +5632,6 @@ TEST_CASE(DartAPI_TestNativeFieldsAccess) { @pragma('vm:external-name', 'TestNativeFieldsAccess_invalidAccess') external invalidAccess(); } - @pragma('vm:entry-point', 'call') NativeFields testMain() { NativeFields obj = new NativeFields(10, 20); obj.initNativeFlds(); @@ -5719,7 +5661,6 @@ TEST_CASE(DartAPI_InjectNativeFieldsSuperClass) { "base class NativeFields extends NativeFieldsSuper {\n" " fld() => fld1;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "int testMain() {\n" " NativeFields obj = new NativeFields();\n" " return obj.fld();\n" @@ -5740,7 +5681,6 @@ TEST_CASE(DartAPI_InjectNativeFieldsSuperClass) { } static void TestNativeFields(Dart_Handle retobj) { - SetFlagScope sfs(&FLAG_verify_entry_points, false); // Access and set various instance fields of the object. Dart_Handle result = Dart_GetField(retobj, NewString("fld3")); EXPECT(Dart_IsError(result)); @@ -5828,7 +5768,6 @@ TEST_CASE(DartAPI_ImplicitNativeFieldAccess) { " static int? fld3;\n" " static const int fld4 = 10;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "NativeFields testMain() {\n" " NativeFields obj = new NativeFields(10, 20);\n" " return obj;\n" @@ -5856,12 +5795,10 @@ TEST_CASE(DartAPI_NegativeNativeFieldAccess) { " static int? fld3;\n" " static const int fld4 = 10;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "NativeFields testMain1() {\n" " NativeFields obj = new NativeFields(10, 20);\n" " return obj;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "Function testMain2() {\n" " return () {};\n" "}\n"; @@ -5931,7 +5868,6 @@ TEST_CASE(DartAPI_GetStaticField_RunsInitializer) { "}\n"; Dart_Handle result; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("TestClass"), 0, nullptr); @@ -5975,7 +5911,6 @@ TEST_CASE(DartAPI_GetField_CheckIsolate) { int64_t value = 0; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("TestClass"), 0, nullptr); @@ -5998,7 +5933,6 @@ TEST_CASE(DartAPI_SetField_CheckIsolate) { int64_t value = 0; // Create a test library and Load up a test script in it. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("TestClass"), 0, nullptr); @@ -6044,7 +5978,6 @@ TEST_CASE(DartAPI_New) { "}\n" "\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("MyClass"), 0, nullptr); @@ -6265,7 +6198,6 @@ TEST_CASE(DartAPI_New_Issue42939) { "}\n" "\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("MyClass"), 0, nullptr); @@ -6319,7 +6251,6 @@ TEST_CASE(DartAPI_New_Issue44205) { "Type getIntType() { return int; }\n" "\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); Dart_Handle int_wrapper_type = @@ -6366,7 +6297,6 @@ TEST_CASE(DartAPI_InvokeConstructor_Issue44205) { "Type getIntType() { return int; }\n" "\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); Dart_Handle int_wrapper_type = @@ -6408,7 +6338,6 @@ TEST_CASE(DartAPI_InvokeClosure_Issue44205) { " final int fld2;\n" " static const int fld4 = 10;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "Function testMain1() {\n" " InvokeClosure obj = new InvokeClosure(10, 20);\n" " return obj.method1(10);\n" @@ -6442,7 +6371,6 @@ TEST_CASE(DartAPI_NewListOfType) { "void expectListOfDynamic(List _) {}\n" "void expectListOfVoid(List _) {}\n" "void expectListOfNever(List _) {}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle zxhandle_type = @@ -6516,7 +6444,6 @@ TEST_CASE(DartAPI_NewListOfTypeFilled) { " final List handles;\n" " ChannelReadResult(this.handles);\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle zxhandle_type = @@ -6611,7 +6538,6 @@ TEST_CASE(DartAPI_Invoke) { "}\n"; // Shared setup. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("Methods"), 0, nullptr); @@ -6719,7 +6645,6 @@ TEST_CASE(DartAPI_Invoke_PrivateStatic) { "\n"; // Shared setup. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("Methods"), 0, nullptr); @@ -6738,189 +6663,9 @@ TEST_CASE(DartAPI_Invoke_PrivateStatic) { EXPECT_STREQ("hidden static !!!", str); } -TEST_CASE(DartAPI_MissingEntryPoints) { - const char* kScriptChars = R"( -class C { - final cx = 1; - int cy = 2; - @pragma('vm:entry-point', 'get') - int cz = 3; - @pragma('vm:entry-point', 'set') - int cw = 4; - - void c1() {} - - @pragma('vm:entry-point', 'call') - void c2() {} - - @pragma('vm:entry-point', 'get') - void c3() {} -} - -@pragma('vm:entry-point') -class D { - static final dx = 1; - static int dy = 2; - @pragma('vm:entry-point', 'get') - static int dz = 3; - @pragma('vm:entry-point', 'set') - static int dw = 4; - - static void d1() {} - - @pragma('vm:entry-point', 'call') - static void d2() {} - - @pragma('vm:entry-point', 'get') - static void d3() { - print('Okay to closurize.'); - } -} - -final x = 1; -int y = 2; -@pragma('vm:entry-point', 'get') -int z = 3; -@pragma('vm:entry-point', 'set') -int w = 4; - -void test1() {} - -@pragma('vm:entry-point', 'call') -void test2() {} - -@pragma('vm:entry-point', 'get') -void test3() {} - -@pragma('vm:entry-point', 'call') -C newC() => C(); - )"; - - // Shared setup. - SetFlagScope sfs(&FLAG_verify_entry_points, true); - Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); - EXPECT_VALID(lib); - Dart_Handle instance = Dart_Invoke(lib, NewString("newC"), 0, nullptr); - EXPECT_VALID(instance); - Dart_Handle d_class = Dart_GetClass(lib, NewString("D")); - EXPECT_VALID(d_class); - Dart_Handle value = Dart_NewInteger(0); - Dart_Handle name; - - // Top level method, not annotated for calling or closurization. - name = NewString("test1"); - EXPECT_ERROR(Dart_Invoke(lib, name, 0, nullptr), "entry_point_pragma.md"); - EXPECT_ERROR(Dart_GetField(lib, name), "entry_point_pragma.md"); - - // Top level method annotated for calling, not closurization. - name = NewString("test2"); - EXPECT_VALID(Dart_Invoke(lib, name, 0, nullptr)); - EXPECT_ERROR(Dart_GetField(lib, name), "entry_point_pragma.md"); - - // Top level method annotated for closurization, not calling. - name = NewString("test3"); - EXPECT_ERROR(Dart_Invoke(lib, name, 0, nullptr), "entry_point_pragma.md"); - EXPECT_VALID(Dart_GetField(lib, name)); - - // Final top level field, not annotated for getting. - name = NewString("x"); - EXPECT_ERROR(Dart_GetField(lib, name), "entry_point_pragma.md"); - - // Top level field, not annotated for getting or setting. - name = NewString("y"); - EXPECT_ERROR(Dart_GetField(lib, name), "entry_point_pragma.md"); - EXPECT_ERROR(Dart_SetField(lib, name, value), "entry_point_pragma.md"); - - // Top level field annotated for getting, not setting. - name = NewString("z"); - EXPECT_VALID(Dart_GetField(lib, name)); - EXPECT_ERROR(Dart_SetField(lib, name, value), "entry_point_pragma.md"); - - // Top level field annotated for setting, not getting. - name = NewString("w"); - EXPECT_ERROR(Dart_GetField(lib, name), "entry_point_pragma.md"); - EXPECT_VALID(Dart_SetField(lib, name, value)); - - // Instance method, not annotated for calling or closurization. - name = NewString("c1"); - EXPECT_ERROR(Dart_Invoke(instance, name, 0, nullptr), - "entry_point_pragma.md"); - EXPECT_ERROR(Dart_GetField(instance, name), "entry_point_pragma.md"); - - // Instance method annotated for calling, not closurization. - name = NewString("c2"); - EXPECT_VALID(Dart_Invoke(instance, name, 0, nullptr)); - EXPECT_ERROR(Dart_GetField(instance, name), "entry_point_pragma.md"); - - // Instance method annotated for closurization, not calling. - name = NewString("c3"); - EXPECT_ERROR(Dart_Invoke(instance, name, 0, nullptr), - "entry_point_pragma.md"); - EXPECT_VALID(Dart_GetField(instance, name)); - - // Final instance field, not annotated for getting. - name = NewString("cx"); - EXPECT_ERROR(Dart_GetField(instance, name), "entry_point_pragma.md"); - - // Instance field, not annotated for getting or setting. - name = NewString("cy"); - EXPECT_ERROR(Dart_GetField(instance, name), "entry_point_pragma.md"); - EXPECT_ERROR(Dart_SetField(instance, name, value), "entry_point_pragma.md"); - - // Instance field annotated for getting, not setting. - name = NewString("cz"); - EXPECT_VALID(Dart_GetField(instance, name)); - EXPECT_ERROR(Dart_SetField(instance, name, value), "entry_point_pragma.md"); - - // Instance field annotated for setting, not getting. - name = NewString("cw"); - EXPECT_ERROR(Dart_GetField(instance, name), "entry_point_pragma.md"); - EXPECT_VALID(Dart_SetField(instance, name, value)); - - // Class, not annotated for access. - name = NewString("C"); - EXPECT_ERROR(Dart_GetClass(lib, name), "entry_point_pragma.md"); - - // Static method, not annotated for calling or closurization. - name = NewString("d1"); - EXPECT_ERROR(Dart_Invoke(d_class, name, 0, nullptr), "entry_point_pragma.md"); - EXPECT_ERROR(Dart_GetField(d_class, name), "entry_point_pragma.md"); - - // Instance method annotated for calling, not closurization. - name = NewString("d2"); - EXPECT_VALID(Dart_Invoke(d_class, name, 0, nullptr)); - EXPECT_ERROR(Dart_GetField(d_class, name), "entry_point_pragma.md"); - - // Instance method annotated for closurization, not calling. - name = NewString("d3"); - EXPECT_ERROR(Dart_Invoke(d_class, name, 0, nullptr), "entry_point_pragma.md"); - EXPECT_VALID(Dart_GetField(d_class, name)); - - // Final static field, getter. - name = NewString("dx"); - EXPECT_ERROR(Dart_GetField(d_class, name), "entry_point_pragma.md"); - - // Static field, not annotated for getting or setting. - name = NewString("dy"); - value = Dart_NewInteger(0); - EXPECT_ERROR(Dart_GetField(d_class, name), "entry_point_pragma.md"); - EXPECT_ERROR(Dart_SetField(d_class, name, value), "entry_point_pragma.md"); - - // Static field annotated for getting, not setting. - name = NewString("dz"); - EXPECT_VALID(Dart_GetField(d_class, name)); - EXPECT_ERROR(Dart_SetField(d_class, name, value), "entry_point_pragma.md"); - - // Static field annotated for setting, not getting. - name = NewString("dw"); - EXPECT_ERROR(Dart_GetField(d_class, name), "entry_point_pragma.md"); - EXPECT_VALID(Dart_SetField(d_class, name, value)); -} - TEST_CASE(DartAPI_Invoke_FunnyArgs) { const char* kScriptChars = "test(arg) => 'hello $arg';\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle func_name = NewString("test"); Dart_Handle args[1]; @@ -6994,7 +6739,6 @@ TEST_CASE(DartAPI_Invoke_BadArgs) { #endif // defined(PRODUCT) // Shared setup. - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); Dart_Handle type = Dart_GetNonNullableType(lib, NewString("Methods"), 0, nullptr); @@ -7049,7 +6793,6 @@ TEST_CASE(DartAPI_Invoke_BadArgs) { } TEST_CASE(DartAPI_Invoke_Null) { - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle result = Dart_Invoke(Dart_Null(), NewString("toString"), 0, nullptr); EXPECT_VALID(result); @@ -7112,7 +6855,6 @@ TEST_CASE(DartAPI_InvokeNoSuchMethod) { " return new TestClass();\n" " }\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle result; Dart_Handle instance; // Create a test library and Load up a test script in it. @@ -7171,7 +6913,6 @@ TEST_CASE(DartAPI_InvokeClosure) { Dart_Handle result; CHECK_API_SCOPE(thread); - SetFlagScope sfs(&FLAG_verify_entry_points, false); // Create a test library and Load up a test script in it. Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); @@ -7229,11 +6970,9 @@ TEST_CASE(DartAPI_ThrowException) { const char* kScriptChars = R"( @pragma('vm:external-name', 'ThrowException_native') - @pragma('vm:entry-point', 'call') external int test(); )"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle result; intptr_t size = thread->ZoneSizeInBytes(); Dart_EnterScope(); // Start a Dart API scope for invoking API functions. @@ -7428,7 +7167,6 @@ int testMain(String extstr) { obj2); })"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, native_args_lookup); const char* ascii_str = "string"; @@ -7464,7 +7202,6 @@ class MyObject { @pragma("vm:external-name", "Name_Does_Not_Matter") external int method1(int i, int j); } -@pragma('vm:entry-point', 'call') testMain() { MyObject obj = new MyObject(); return obj.method1(77, 125); @@ -7489,7 +7226,6 @@ TEST_CASE(DartAPI_TypeToNullability) { " static var name = 'Class';\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); const Dart_Handle name = NewString("Class"); @@ -7526,7 +7262,6 @@ TEST_CASE(DartAPI_GetNullableType) { " static var name = '_Class';\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); // Lookup a class. @@ -7587,7 +7322,6 @@ TEST_CASE(DartAPI_GetNonNullableType) { " static var name = '_Class';\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); // Lookup a class. @@ -7650,7 +7384,6 @@ TEST_CASE(DartAPI_InstanceOf) { " return new InstanceOfTest();\n" " }\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle result; // Create a test library and Load up a test script in it. Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); @@ -7879,7 +7612,6 @@ TEST_CASE(DartAPI_SetNativeResolver) { external static baz(); } )"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle error = Dart_NewApiError("incoming error"); Dart_Handle result; @@ -8229,7 +7961,6 @@ VM_UNIT_TEST_CASE(DartAPI_NewNativePort) { TestIsolateScope __test_isolate__; const char* kScriptChars = "import 'dart:isolate';\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port) {\n" " var receivePort = new RawReceivePort();\n" " var replyPort = receivePort.sendPort;\n" @@ -8304,7 +8035,6 @@ static void NewNativePort_sendInteger321(Dart_Port dest_port_id, TEST_CASE(DartAPI_NativePortPostInteger) { const char* kScriptChars = "import 'dart:isolate';\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port) {\n" " var receivePort = new RawReceivePort();\n" " var replyPort = receivePort.sendPort;\n" @@ -8382,7 +8112,6 @@ TEST_CASE(DartAPI_NativePortPostTransferrableTypedData) { const char* kScriptChars = "import 'dart:typed_data';\n" "import 'dart:isolate';\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port1, SendPort port2) {\n" " final td1 =" " TransferableTypedData.fromList([Uint8List(10)..[0] = 42]);\n" @@ -8446,7 +8175,6 @@ TEST_CASE(DartAPI_NativePortPostExternalTypedData) { const char* kScriptChars = "import 'dart:typed_data';\n" "import 'dart:isolate';\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port, Uint8List data) {\n" " port.send(data);\n" "}\n"; @@ -8488,7 +8216,6 @@ TEST_CASE(DartAPI_NativePortPostUserClass) { const char* kScriptChars = "import 'dart:isolate';\n" "class ABC {}\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port) {\n" " port.send(new ABC());\n" "}\n"; @@ -8539,7 +8266,6 @@ static void NewNativePort_nativeReceiveNull(Dart_Port dest_port_id, TEST_CASE(DartAPI_NativePortReceiveNull) { const char* kScriptChars = "import 'dart:isolate';\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port) {\n" " var receivePort = new RawReceivePort();\n" " var replyPort = receivePort.sendPort;\n" @@ -8592,7 +8318,6 @@ static void NewNativePort_nativeReceiveInteger(Dart_Port dest_port_id, TEST_CASE(DartAPI_NativePortReceiveInteger) { const char* kScriptChars = "import 'dart:isolate';\n" - "@pragma('vm:entry-point', 'call')" "void callPort(SendPort port) {\n" " var receivePort = new RawReceivePort();\n" " var replyPort = receivePort.sendPort;\n" @@ -8799,7 +8524,6 @@ static void IsolateShutdownRunDartCodeTestCallback(void* isolate_group_data, ASSERT(add_result == 0); } Dart_EnterScope(); - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = Dart_RootLibrary(); EXPECT_VALID(lib); Dart_Handle arg1 = Dart_NewInteger(90); @@ -8979,7 +8703,6 @@ TEST_CASE(DartAPI_NativeFunctionClosure) { } } } - @pragma('vm:entry-point', 'call') int testMain() { Test obj = new Test(); Expect.equals(1, obj.foo1()); @@ -9129,7 +8852,6 @@ TEST_CASE(DartAPI_NativeStaticFunctionClosure) { } } } - @pragma('vm:entry-point', 'call') int testMain() { Test obj = new Test(); Expect.equals(0, Test.foo1()); @@ -9641,7 +9363,6 @@ TEST_CASE(DartAPI_StringFromExternalTypedData) { "testView16(external) {\n" " return test(external.buffer.asUint16List());\n" "}\n"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); { @@ -10220,7 +9941,6 @@ TEST_CASE(DartAPI_InvokeVMServiceMethod) { } return false; } - @pragma('vm:entry-point', 'call') bool validateResult(Uint8List bytes) { final map = json.decode(utf8.decode(bytes)); validate(map['jsonrpc'] == '2.0'); @@ -10642,7 +10362,6 @@ TEST_CASE(DartAPI_HeapSampling_UserDefinedClass) { const char* kScriptChars = R"( class Bar {} final list = []; - @pragma('vm:entry-point', 'call') foo() { for (int i = 0; i < 100000; ++i) { list.add(Bar()); @@ -10777,7 +10496,6 @@ TEST_CASE(DartAPI_HeapSampling_NonTrivialSamplingPeriod) { const char* kScriptChars = R"( final list = []; - @pragma('vm:entry-point', 'call') foo() { for (int i = 0; i < 1000; ++i) { list.add(List.filled(100, 0)); diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index 73d0db677df..ba2bb6b0e88 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -714,7 +714,8 @@ const Context& ActivationFrame::GetSavedCurrentContext() { const auto variable_index = VariableIndex(var_info.index()); obj = GetStackVar(variable_index); if (obj.IsClosure()) { - ASSERT(function().IsClosureCallDispatcher()); + ASSERT(function().name() == Symbols::call().ptr()); + ASSERT(function().IsInvokeFieldDispatcher()); // Closure.call frames. ctx_ = Closure::Cast(obj).GetContext(); } else if (obj.IsContext()) { diff --git a/runtime/vm/exceptions_test.cc b/runtime/vm/exceptions_test.cc index 8cbd25de742..3528493472a 100644 --- a/runtime/vm/exceptions_test.cc +++ b/runtime/vm/exceptions_test.cc @@ -104,7 +104,6 @@ TEST_CASE(UnhandledExceptions) { UnhandledExceptions.invoke(); return 2; } - @pragma('vm:entry-point', 'call') static int method2() { throw new Second(); } @@ -122,7 +121,6 @@ TEST_CASE(UnhandledExceptions) { UnhandledExceptions.equals(3, Second.method3(1)); } )"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, native_lookup); EXPECT_VALID(Dart_Invoke(lib, NewString("testMain"), 0, nullptr)); } diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h index 02d46c56a36..aa06ebc9868 100644 --- a/runtime/vm/flag_list.h +++ b/runtime/vm/flag_list.h @@ -246,7 +246,7 @@ constexpr bool FLAG_support_il_printer = false; R(eliminate_type_checks, true, bool, true, \ "Eliminate type checks when allowed by static type analysis.") \ D(support_rr, bool, false, "Support running within RR.") \ - P(verify_entry_points, bool, true, \ + P(verify_entry_points, bool, false, \ "Throw API error on invalid member access through native API. See " \ "entry_point_pragma.md") \ C(branch_coverage, false, false, bool, false, "Enable branch coverage") \ diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc index bc611fa61c9..d30886b35d0 100644 --- a/runtime/vm/isolate_reload_test.cc +++ b/runtime/vm/isolate_reload_test.cc @@ -1163,7 +1163,6 @@ TEST_CASE(IsolateReload_LibraryShow) { "main() {\n" " return importedFunc();\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "mainInt() {\n" " return importedIntFunc();\n" "}\n"; @@ -1183,7 +1182,6 @@ TEST_CASE(IsolateReload_LibraryShow) { "main() {\n" " return importedFunc();\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "mainInt() {\n" " return importedIntFunc();\n" "}\n"; @@ -6407,7 +6405,6 @@ TEST_CASE(IsolateReload_ImplicitGetterWithLoadGuard) { A a = A(3); - @pragma('vm:entry-point', 'call') main() { int sum = 0; // Trigger OSR and optimize this function. @@ -6484,7 +6481,6 @@ TEST_CASE(IsolateReload_KeepPragma1) { // Old version of closure function bar() has a pragma. const char* kScript = "import 'file:///test:isolate_reload_helper';\n" - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " @pragma('vm:prefer-inline')\n" " void bar() {}\n" @@ -6500,7 +6496,6 @@ TEST_CASE(IsolateReload_KeepPragma1) { // New version of closure function bar() doesn't have a pragma. const char* kReloadScript = "import 'file:///test:isolate_reload_helper';\n" - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " void bar() {}\n" " return bar;\n" @@ -6611,7 +6606,6 @@ TEST_CASE(IsolateReload_KeepPragma2) { // Old version of closure function bar() has a pragma. const char* kScript = "import 'file:///test:isolate_reload_helper';\n" - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " @pragma('vm:prefer-inline')\n" " void bar() {}\n" @@ -6627,7 +6621,6 @@ TEST_CASE(IsolateReload_KeepPragma2) { // New version of closure function bar() has a different pragma. const char* kReloadScript = "import 'file:///test:isolate_reload_helper';\n" - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " @pragma('vm:never-inline')\n" " void bar() {}\n" @@ -6668,7 +6661,6 @@ TEST_CASE(IsolateReload_KeepPragma3) { // Old version of closure function bar() doesn't have a pragma. const char* kScript = "import 'file:///test:isolate_reload_helper';\n" - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " void bar() {}\n" " return bar;\n" @@ -6683,7 +6675,6 @@ TEST_CASE(IsolateReload_KeepPragma3) { // New version of closure function bar() has a pragma. const char* kReloadScript = "import 'file:///test:isolate_reload_helper';\n" - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " @pragma('vm:never-inline')\n" " void bar() {}\n" diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc index c4a8f3e7432..9189b861075 100644 --- a/runtime/vm/isolate_test.cc +++ b/runtime/vm/isolate_test.cc @@ -43,7 +43,6 @@ void IsolateSpawn(const char* platform_script_value) { "}\n", platform_script_value); - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle test_lib = TestCase::LoadTestScript(scriptChars, nullptr); free(scriptChars); @@ -243,7 +242,6 @@ ISOLATE_UNIT_TEST_CASE(Isolate_MayExit_True) { EXPECT_EQ(false, thread->is_unwind_in_progress()); - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_EnterScope(); Dart_Handle lib = @@ -268,7 +266,6 @@ ISOLATE_UNIT_TEST_CASE(Isolate_MayExit_False) { EXPECT_EQ(false, thread->is_unwind_in_progress()); - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_EnterScope(); Dart_Handle lib = diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc index ec5d4009cbc..704c6b2ac8c 100644 --- a/runtime/vm/json_test.cc +++ b/runtime/vm/json_test.cc @@ -236,7 +236,6 @@ TEST_CASE(JSON_JSONStream_DartString) { "var wrongEncoding = '\\u{1D11E}' + surrogates[0] + '\\u{1D11E}';" "var nullInMiddle = 'This has\\u0000 four words.';"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr); EXPECT_VALID(lib); diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc index 2bf17b04aba..d57a16b5a79 100644 --- a/runtime/vm/kernel_isolate.cc +++ b/runtime/vm/kernel_isolate.cc @@ -165,7 +165,8 @@ class RunKernelTask : public ThreadPool::Task { return false; } ASSERT(!root_library.IsNull()); - const String& entry_name = Symbols::main(); + const String& entry_name = String::Handle(Z, String::New("main")); + ASSERT(!entry_name.IsNull()); const Function& entry = Function::Handle( Z, root_library.LookupFunctionAllowPrivate(entry_name)); if (entry.IsNull()) { diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 0de7818de15..d35413a98c1 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -4674,205 +4674,10 @@ static ObjectPtr ThrowTypeError(const TokenPosition token_pos, return DartEntry::InvokeFunction(throwNew, args); } -static bool WriteQualifiedMemberName(Zone* zone, - BaseTextBuffer* buffer, - const Object& member) { - if (member.IsFunction()) { - const auto& fun = Function::Cast(member); - const auto& cls = Class::Handle(zone, fun.Owner()); - if (WriteQualifiedMemberName(zone, buffer, cls)) { - buffer->AddString("."); - } - buffer->AddString(fun.UserVisibleNameCString()); - if (!fun.IsRegularFunction()) { - buffer->Printf(" (kind %s)", Function::KindToCString(fun.kind())); - } - } else if (member.IsField()) { - const auto& field = Field::Cast(member); - const auto& cls = Class::Handle(field.Owner()); - if (WriteQualifiedMemberName(zone, buffer, cls)) { - buffer->AddString("."); - } - const auto& name = String::Handle(field.name()); - buffer->AddString(name.ToCString()); - } else if (member.IsClass()) { - const Class& cls = Class::Cast(member); - const Library& lib = Library::Handle(cls.library()); - if (!lib.IsNull()) { - const String& name = String::Handle(lib.url()); - buffer->Printf("%s::", name.ToCString()); - } - if (!cls.IsTopLevel()) { - buffer->AddString(cls.UserVisibleNameCString()); - } - return !cls.IsTopLevel(); - } - return false; -} - -DART_WARN_UNUSED_RESULT -static ErrorPtr VerifyEntryPoint(const Library& lib, - const Object& member, - const Object& annotated, - EntryPointPragma expected) { - ASSERT(expected != EntryPointPragma::kNever); - auto* const thread = Thread::Current(); - auto* const zone = thread->zone(); - // Special cases for certain types of functions that should delegate to - // different members within the same class. - if (member.IsFunction()) { - const auto& fun = Function::Cast(member); - if (fun.IsMethodExtractor()) { - ASSERT(expected == EntryPointPragma::kGetterOnly); - // To be able to call a method extractor, the original method needs to - // be annotated for closure retrieval. - const auto& closure = - Function::Handle(zone, fun.extracted_method_closure()); - return VerifyEntryPoint( - lib, closure, annotated.IsNull() ? annotated : closure, expected); - } else if (fun.IsImplicitClosureFunction()) { - // Check the annotations on the parent function instead. - const auto& parent = Function::Handle(zone, fun.parent_function()); - return VerifyEntryPoint( - lib, parent, annotated.IsNull() ? annotated : parent, expected); - } else if (fun.IsImplicitGetterOrSetter()) { - ASSERT(fun.IsImplicitSetterFunction() || - expected == EntryPointPragma::kGetterOnly); - ASSERT(!fun.IsImplicitSetterFunction() || - expected == EntryPointPragma::kSetterOnly); - // For implicit getters or setters, the field must be properly annotated. - const auto& field = Field::Handle(zone, fun.accessor_field()); -#if defined(DART_PRECOMPILED_RUNTIME) - if (!fun.HasCode()) { - return VerifyEntryPoint(lib, field, Object::null_object(), expected); - } -#endif - return VerifyEntryPoint(lib, field, - annotated.IsNull() ? annotated : field, expected); - } - } - - // For method and fields, the expected pragma should always be more specific. - ASSERT_EQUAL(member.IsClass(), expected == EntryPointPragma::kAlways); - - // A null annotated object is used to signal an error should always be thrown. - if (!annotated.IsNull()) { - bool is_marked_entrypoint = false; -#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 - // "has_pragma()" as a proxy, since that bit is usually retained. - if (annotated.IsClass()) { - is_marked_entrypoint = Class::Cast(annotated).has_pragma(); - } else if (annotated.IsField()) { - is_marked_entrypoint = Field::Cast(annotated).has_pragma(); - } else if (annotated.IsFunction()) { - const auto& f = Function::Cast(annotated); - is_marked_entrypoint = f.has_pragma(); - if (expected == EntryPointPragma::kCallOnly && !f.HasCode()) { - // If the function does not have code attached, that means it was not - // properly annotated to allow native invocation. - is_marked_entrypoint = false; - } else if (expected == EntryPointPragma::kGetterOnly && - !f.HasImplicitClosureFunction()) { - // If the function does not have an implicit closure function, that - // means it was not properly annotated to allow native closurization. - is_marked_entrypoint = false; - } - } else { - FATAL("Unexpected annotated node %s", annotated.ToCString()); - } -#else - const auto& metadata = Object::Handle(zone, lib.GetMetadata(annotated)); - if (metadata.IsError()) { - return Error::RawCast(metadata.ptr()); - } - ASSERT(!metadata.IsNull() && metadata.IsArray()); - const EntryPointPragma pragma = - FindEntryPointPragma(thread->isolate_group(), Array::Cast(metadata), - &Field::Handle(zone), &Object::Handle(zone)); - ASSERT(pragma != EntryPointPragma::kCallOnly || annotated.IsFunction()); - is_marked_entrypoint = - pragma == EntryPointPragma::kAlways || pragma == expected; -#endif - if (is_marked_entrypoint) { - return Error::null(); - } - } - - ZoneTextBuffer buffer(zone); - switch (expected) { - case EntryPointPragma::kAlways: - buffer.AddString("ERROR: To access '"); - WriteQualifiedMemberName(zone, &buffer, member); - buffer.AddString("' from native code, it must be annotated.\n"); - break; - case EntryPointPragma::kCallOnly: - ASSERT(member.IsFunction()); - buffer.AddString("ERROR: To invoke '"); - WriteQualifiedMemberName(zone, &buffer, member); - buffer.AddString("' from native code, it must be annotated.\n"); - break; - case EntryPointPragma::kGetterOnly: - if (member.IsField() || - (member.IsFunction() && Function::Cast(member).IsGetterFunction())) { - buffer.AddString("ERROR: To retrieve the value of '"); - WriteQualifiedMemberName(zone, &buffer, member); - buffer.AddString("' from native code, it must be annotated.\n"); - } else { - const auto& function = Function::Cast(member); - // Other types of functions cannot be closurized. - if (!function.IsRegularFunction()) { - // Other types of functions reaching here are internal errors. - buffer.AddString("Cannot get closure value for method '"); - WriteQualifiedMemberName(zone, &buffer, function); - buffer.Printf("' of kind %s", - Function::KindToCString(function.kind())); - FATAL("%s", buffer.buffer()); - } - buffer.AddString("ERROR: To closurize '"); - WriteQualifiedMemberName(zone, &buffer, function); - buffer.AddString("' from native code, it must be annotated.\n"); - } - break; - case EntryPointPragma::kSetterOnly: - if (member.IsField() || - (member.IsFunction() && Function::Cast(member).IsSetterFunction())) { - buffer.AddString("ERROR: To set the value of '"); - WriteQualifiedMemberName(zone, &buffer, member); - buffer.AddString("' from native code, it must be annotated.\n"); - } else { - // Other types of functions reaching here are internal errors. - buffer.AddString("Cannot set value of '"); - WriteQualifiedMemberName(zone, &buffer, member); - buffer.AddString("'"); - FATAL("%s", buffer.buffer()); - } - break; - default: - FATAL("Unexpected EntryPointPragma value %" Pd, - static_cast(expected)); - } - buffer.AddString( - "ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/" - "docs/compiler/aot/entry_point_pragma.md\n"); - OS::PrintErr("%s", buffer.buffer()); - return ApiError::New(String::Handle(String::New(buffer.buffer()))); -} - -#if defined(DART_PRECOMPILED_RUNTIME) -DART_WARN_UNUSED_RESULT -static ErrorPtr EntryPointFunctionInvocationError(const Function& function) { - // Ensures a failure by passing null for the annotated object. - return VerifyEntryPoint(Library::Handle(Library::null()), function, - Object::null_object(), EntryPointPragma::kCallOnly); -} -#endif - ObjectPtr Class::InvokeGetter(const String& getter_name, - bool check_is_entrypoint, + bool throw_nsm_if_absent, bool respect_reflectable, - bool for_invocation) const { + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); @@ -4881,27 +4686,28 @@ ObjectPtr Class::InvokeGetter(const String& getter_name, // Note static fields do not have implicit getters. const Field& field = Field::Handle(zone, LookupStaticField(getter_name)); + if (!field.IsNull() && check_is_entrypoint) { + CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); + } + if (field.IsNull() || field.IsUninitialized()) { const String& internal_getter_name = String::Handle(zone, Field::GetterName(getter_name)); Function& getter = Function::Handle(zone, LookupStaticFunction(internal_getter_name)); + if (field.IsNull() && !getter.IsNull() && check_is_entrypoint) { + CHECK_ERROR(getter.VerifyCallEntryPoint()); + } + if (getter.IsNull() || (respect_reflectable && !getter.is_reflectable())) { - if (for_invocation) { - // LookupStaticFunction(getter_name) has already failed in Invoke(). - // Instead of throwing an NSM, indicate that no getter was found - // by returning a value that cannot be returned by a getter (here, - // the sentinel value). - return Object::sentinel().ptr(); - } else if (getter.IsNull()) { + if (getter.IsNull()) { getter = LookupStaticFunction(getter_name); if (!getter.IsNull()) { + if (check_is_entrypoint) { + CHECK_ERROR(getter.VerifyClosurizedEntryPoint()); + } if (getter.SafeToClosurize()) { - if (check_is_entrypoint) { - CHECK_ERROR( - getter.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); - } // Looking for a getter but found a regular method: closurize it. const Function& closure_function = Function::Handle(zone, getter.ImplicitClosureFunction()); @@ -4909,32 +4715,29 @@ ObjectPtr Class::InvokeGetter(const String& getter_name, } } } - - return ThrowNoSuchMethod(AbstractType::Handle(zone, RareType()), - getter_name, Object::null_array(), - Object::null_array(), InvocationMirror::kStatic, - InvocationMirror::kGetter); - } - - if (check_is_entrypoint) { - CHECK_ERROR(getter.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); + if (throw_nsm_if_absent) { + return ThrowNoSuchMethod( + AbstractType::Handle(zone, RareType()), getter_name, + Object::null_array(), Object::null_array(), + InvocationMirror::kStatic, InvocationMirror::kGetter); + } + // Fall through case: Indicate that we didn't find any function or field + // using a special null instance. This is different from a field being + // null. Callers make sure that this null does not leak into Dartland. + return Object::sentinel().ptr(); } // Invoke the getter and return the result. return DartEntry::InvokeFunction(getter, Object::empty_array()); } - if (check_is_entrypoint) { - CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); - } - return field.StaticValue(); } ObjectPtr Class::InvokeSetter(const String& setter_name, const Instance& value, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); @@ -4945,9 +4748,17 @@ ObjectPtr Class::InvokeSetter(const String& setter_name, const String& internal_setter_name = String::Handle(zone, Field::SetterName(setter_name)); + if (!field.IsNull() && check_is_entrypoint) { + CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); + } + + AbstractType& parameter_type = AbstractType::Handle(zone); if (field.IsNull()) { const Function& setter = Function::Handle(zone, LookupStaticFunction(internal_setter_name)); + if (!setter.IsNull() && check_is_entrypoint) { + CHECK_ERROR(setter.VerifyCallEntryPoint()); + } const int kNumArgs = 1; const Array& args = Array::Handle(zone, Array::New(kNumArgs)); args.SetAt(0, value); @@ -4957,15 +4768,14 @@ ObjectPtr Class::InvokeSetter(const String& setter_name, InvocationMirror::kStatic, InvocationMirror::kSetter); } - const auto& type = AbstractType::Handle(zone, setter.ParameterTypeAt(0)); - if (!value.RuntimeTypeIsSubtypeOf(type, Object::null_type_arguments(), + parameter_type = setter.ParameterTypeAt(0); + if (!value.RuntimeTypeIsSubtypeOf(parameter_type, + Object::null_type_arguments(), Object::null_type_arguments())) { const String& argument_name = String::Handle(zone, setter.ParameterNameAt(0)); - return ThrowTypeError(setter.token_pos(), value, type, argument_name); - } - if (check_is_entrypoint) { - CHECK_ERROR(setter.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); + return ThrowTypeError(setter.token_pos(), value, parameter_type, + argument_name); } // Invoke the setter and return the result. return DartEntry::InvokeFunction(setter, args); @@ -4981,14 +4791,13 @@ ObjectPtr Class::InvokeSetter(const String& setter_name, InvocationMirror::kSetter); } - const auto& type = AbstractType::Handle(zone, field.type()); - if (!value.RuntimeTypeIsSubtypeOf(type, Object::null_type_arguments(), + parameter_type = field.type(); + if (!value.RuntimeTypeIsSubtypeOf(parameter_type, + Object::null_type_arguments(), Object::null_type_arguments())) { const String& argument_name = String::Handle(zone, field.name()); - return ThrowTypeError(field.token_pos(), value, type, argument_name); - } - if (check_is_entrypoint) { - CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); + return ThrowTypeError(field.token_pos(), value, parameter_type, + argument_name); } field.SetStaticValue(value); return value.ptr(); @@ -5035,8 +4844,8 @@ static ArrayPtr CreateCallableArgumentsFromStatic( ObjectPtr Class::Invoke(const String& function_name, const Array& args, const Array& arg_names, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); CHECK_ERROR(EnsureIsFinalized(thread)); @@ -5052,15 +4861,19 @@ ObjectPtr Class::Invoke(const String& function_name, Function& function = Function::Handle(zone, LookupStaticFunction(function_name)); + if (!function.IsNull() && check_is_entrypoint) { + CHECK_ERROR(function.VerifyCallEntryPoint()); + } + if (function.IsNull()) { // Didn't find a method: try to find a getter and invoke call on its result. - const Object& getter_result = - Object::Handle(zone, InvokeGetter(function_name, check_is_entrypoint, - respect_reflectable, - /*for_invocation=*/true)); - if (getter_result.IsError()) { - return getter_result.ptr(); - } else if (getter_result.ptr() != Object::sentinel().ptr()) { + const Object& getter_result = Object::Handle( + zone, InvokeGetter(function_name, false, respect_reflectable, + check_is_entrypoint)); + if (getter_result.ptr() != Object::sentinel().ptr()) { + if (check_is_entrypoint) { + CHECK_ERROR(EntryPointFieldInvocationError(function_name)); + } const auto& call_args_descriptor_array = Array::Handle( zone, ArgumentsDescriptor::NewBoxed(args_descriptor.TypeArgsLen(), args_descriptor.Count() + 1, @@ -5088,9 +4901,6 @@ ObjectPtr Class::Invoke(const String& function_name, if (type_error != Error::null()) { return type_error; } - if (check_is_entrypoint) { - CHECK_ERROR(function.VerifyEntryPoint(EntryPointPragma::kCallOnly)); - } return DartEntry::InvokeFunction(function, args, args_descriptor_array); } @@ -6828,13 +6638,12 @@ FieldPtr Class::LookupStaticFieldAllowPrivate(const String& name) const { } const char* Class::ToCString() const { - ZoneTextBuffer buffer(Thread::Current()->zone()); + NoSafepointScope no_safepoint; const Library& lib = Library::Handle(library()); - if (!lib.IsNull()) { - buffer.Printf("%s ", lib.ToCString()); - } - buffer.Printf("Class: %s", String::Handle(Name()).ToCString()); - return buffer.buffer(); + const char* library_name = lib.IsNull() ? "" : lib.ToCString(); + const char* class_name = String::Handle(Name()).ToCString(); + return OS::SCreate(Thread::Current()->zone(), "%s Class: %s", library_name, + class_name); } // Thomas Wang, Integer Hash Functions. @@ -9899,7 +9708,7 @@ ObjectPtr Function::DoArgumentTypesMatch( #if defined(DART_PRECOMPILED_RUNTIME) if (signature() == FunctionType::null()) { // Precompiler deleted signature because of missing entry point pragma. - return EntryPointFunctionInvocationError(*this); + return EntryPointMemberInvocationError(*this); } #endif Thread* thread = Thread::Current(); @@ -9922,7 +9731,7 @@ ObjectPtr Function::DoArgumentTypesMatch( #if defined(DART_PRECOMPILED_RUNTIME) if (signature() == FunctionType::null()) { // Precompiler deleted signature because of missing entry point pragma. - return EntryPointFunctionInvocationError(*this); + return EntryPointMemberInvocationError(*this); } #endif Thread* thread = Thread::Current(); @@ -9949,7 +9758,7 @@ ObjectPtr Function::DoArgumentTypesMatch( #if defined(DART_PRECOMPILED_RUNTIME) if (signature() == FunctionType::null()) { // Precompiler deleted signature because of missing entry point pragma. - return EntryPointFunctionInvocationError(*this); + return EntryPointMemberInvocationError(*this); } #endif Thread* thread = Thread::Current(); @@ -10763,22 +10572,13 @@ bool Function::SafeToClosurize() const { #endif } -bool Function::IsDynamicClosureCallDispatcher() const { +bool Function::IsDynamicClosureCallDispatcher(Thread* thread) const { if (!IsInvokeFieldDispatcher()) return false; - if (!Class::IsClosureClass(Owner())) return false; - return name() == Symbols::DynamicCall().ptr(); -} - -bool Function::IsClosureCallDispatcher() const { - if (!IsInvokeFieldDispatcher()) return false; - if (!Class::IsClosureClass(Owner())) return false; - return name() == Symbols::call().ptr(); -} - -bool Function::IsClosureCallGetter() const { - if (!IsGetterFunction()) return false; - if (!Class::IsClosureClass(Owner())) return false; - return name() == Symbols::GetCall().ptr(); + if (thread->isolate_group()->object_store()->closure_class() != Owner()) { + return false; + } + const auto& handle = String::Handle(thread->zone(), name()); + return handle.Equals(Symbols::DynamicCall()); } FunctionPtr Function::ImplicitClosureFunction() const { @@ -11874,6 +11674,14 @@ bool Function::NeedsMonomorphicCheckedEntry(Zone* zone) const { bool Function::HasDynamicCallers(Zone* zone) const { #if !defined(DART_PRECOMPILED_RUNTIME) + // Issue(dartbug.com/42719): + // Right now the metadata of _Closure.call says there are no dynamic callers - + // even though there can be. To be conservative we return true. + if ((name() == Symbols::GetCall().ptr() || name() == Symbols::call().ptr()) && + Class::IsClosureClass(Owner())) { + return true; + } + // Use the results of TFA to determine whether this function is ever // called dynamically, i.e. using switchable calls. kernel::ProcedureAttributesMetadata metadata; @@ -14841,8 +14649,6 @@ static ObjectPtr InvokeInstanceFunction( const String& target_name, const Array& args, const Array& args_descriptor_array, - bool check_is_entrypoint, - EntryPointPragma pragma, bool respect_reflectable, const TypeArguments& instantiator_type_args) { // Note "args" is already the internal arguments with the receiver as the @@ -14859,30 +14665,21 @@ static ObjectPtr InvokeInstanceFunction( if (type_error != Error::null()) { return type_error; } - if (check_is_entrypoint) { - CHECK_ERROR(function.VerifyEntryPoint(pragma)); - } return DartEntry::InvokeFunction(function, args, args_descriptor_array); } -static bool IsLookupOfMainFunctionInRootLibrary(const Library& lib, - const String& name) { - return name.Equals(Symbols::main()) && - lib.ptr() == IsolateGroup::Current()->object_store()->root_library(); -} - ObjectPtr Library::InvokeGetter(const String& getter_name, - bool check_is_entrypoint, + bool throw_nsm_if_absent, bool respect_reflectable, - bool for_invocation) const { + bool check_is_entrypoint) const { Object& obj = Object::Handle(LookupLocalOrReExportObject(getter_name)); Function& getter = Function::Handle(); if (obj.IsField()) { const Field& field = Field::Cast(obj); + if (check_is_entrypoint) { + CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); + } if (!field.IsUninitialized()) { - if (check_is_entrypoint) { - CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); - } return field.StaticValue(); } // An uninitialized field was found. Check for a getter in the field's @@ -14898,53 +14695,51 @@ ObjectPtr Library::InvokeGetter(const String& getter_name, obj = LookupLocalOrReExportObject(internal_getter_name); if (obj.IsFunction()) { getter = Function::Cast(obj).ptr(); - } else if (!for_invocation) { - // No need to re-lookup the getter name if coming from Invoke(), since - // it already failed there. + if (check_is_entrypoint) { + CHECK_ERROR(getter.VerifyCallEntryPoint()); + } + } else { obj = LookupLocalOrReExportObject(getter_name); - if (obj.IsFunction()) { - const auto& function = Function::Cast(obj); - if (function.SafeToClosurize()) { - // The main function of the root library always has a retained - // implicit static closure. - if (check_is_entrypoint && - !IsLookupOfMainFunctionInRootLibrary(*this, getter_name)) { - CHECK_ERROR( - function.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); - } - // Looking for a getter but found a regular method: closurize it. - const auto& closure_function = - Function::Handle(function.ImplicitClosureFunction()); - return closure_function.ImplicitStaticClosure(); + // Normally static top-level methods cannot be closurized through the + // native API even if they are marked as entry-points, with the one + // exception of "main". + if (obj.IsFunction() && check_is_entrypoint) { + if (!getter_name.Equals(String::Handle(String::New("main"))) || + ptr() != IsolateGroup::Current()->object_store()->root_library()) { + CHECK_ERROR(Function::Cast(obj).VerifyClosurizedEntryPoint()); } } + if (obj.IsFunction() && Function::Cast(obj).SafeToClosurize()) { + // Looking for a getter but found a regular method: closurize it. + const Function& closure_function = + Function::Handle(Function::Cast(obj).ImplicitClosureFunction()); + return closure_function.ImplicitStaticClosure(); + } } } if (getter.IsNull() || (respect_reflectable && !getter.is_reflectable())) { - if (for_invocation) { - // Instead of throwing an NSM, indicate that no getter was found by - // returning a value that cannot be returned by a getter (here, - // the sentinel value). - return Object::sentinel().ptr(); + if (throw_nsm_if_absent) { + return ThrowNoSuchMethod(Object::null_string(), getter_name, + Object::null_array(), Object::null_array(), + InvocationMirror::kTopLevel, + InvocationMirror::kGetter); } - return ThrowNoSuchMethod(Object::null_string(), getter_name, - Object::null_array(), Object::null_array(), - InvocationMirror::kTopLevel, - InvocationMirror::kGetter); + + // Fall through case: Indicate that we didn't find any function or field + // using a special null instance. This is different from a field being null. + // Callers make sure that this null does not leak into Dartland. + return Object::sentinel().ptr(); } - if (check_is_entrypoint) { - CHECK_ERROR(getter.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); - } // Invoke the getter and return the result. return DartEntry::InvokeFunction(getter, Object::empty_array()); } ObjectPtr Library::InvokeSetter(const String& setter_name, const Instance& value, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Object& obj = Object::Handle(LookupLocalOrReExportObject(setter_name)); const String& internal_setter_name = String::Handle(Field::SetterName(setter_name)); @@ -14952,6 +14747,9 @@ ObjectPtr Library::InvokeSetter(const String& setter_name, AbstractType& argument_type = AbstractType::Handle(value.GetType(Heap::kOld)); if (obj.IsField()) { const Field& field = Field::Cast(obj); + if (check_is_entrypoint) { + CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); + } setter_type = field.type(); if (!argument_type.IsNullType() && !setter_type.IsDynamicType() && !value.IsInstanceOf(setter_type, Object::null_type_arguments(), @@ -14968,9 +14766,6 @@ ObjectPtr Library::InvokeSetter(const String& setter_name, InvocationMirror::kTopLevel, InvocationMirror::kSetter); } - if (check_is_entrypoint) { - CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); - } field.SetStaticValue(value); return value.ptr(); } @@ -14981,6 +14776,10 @@ ObjectPtr Library::InvokeSetter(const String& setter_name, setter ^= obj.ptr(); } + if (!setter.IsNull() && check_is_entrypoint) { + CHECK_ERROR(setter.VerifyCallEntryPoint()); + } + const int kNumArgs = 1; const Array& args = Array::Handle(Array::New(kNumArgs)); args.SetAt(0, value); @@ -14997,17 +14796,14 @@ ObjectPtr Library::InvokeSetter(const String& setter_name, return ThrowTypeError(setter.token_pos(), value, setter_type, setter_name); } - if (check_is_entrypoint) { - CHECK_ERROR(setter.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); - } return DartEntry::InvokeFunction(setter, args); } ObjectPtr Library::Invoke(const String& function_name, const Array& args, const Array& arg_names, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); @@ -15026,15 +14822,19 @@ ObjectPtr Library::Invoke(const String& function_name, function ^= result.ptr(); } + if (!function.IsNull() && check_is_entrypoint) { + CHECK_ERROR(function.VerifyCallEntryPoint()); + } + if (function.IsNull()) { // Didn't find a method: try to find a getter and invoke call on its result. - const Object& getter_result = - Object::Handle(zone, InvokeGetter(function_name, check_is_entrypoint, - respect_reflectable, - /*for_invocation=*/true)); - if (getter_result.IsError()) { - return getter_result.ptr(); - } else if (getter_result.ptr() != Object::sentinel().ptr()) { + const Object& getter_result = Object::Handle( + zone, InvokeGetter(function_name, false, respect_reflectable, + check_is_entrypoint)); + if (getter_result.ptr() != Object::sentinel().ptr()) { + if (check_is_entrypoint) { + CHECK_ERROR(EntryPointFieldInvocationError(function_name)); + } const auto& call_args_descriptor_array = Array::Handle( zone, ArgumentsDescriptor::NewBoxed(args_descriptor.TypeArgsLen(), args_descriptor.Count() + 1, @@ -15066,11 +14866,6 @@ ObjectPtr Library::Invoke(const String& function_name, if (type_error != Error::null()) { return type_error; } - // The main function of the root library is always callable. - if (check_is_entrypoint && - !IsLookupOfMainFunctionInRootLibrary(*this, function_name)) { - CHECK_ERROR(function.VerifyEntryPoint(EntryPointPragma::kCallOnly)); - } return DartEntry::InvokeFunction(function, args, args_descriptor_array); } @@ -20743,8 +20538,8 @@ const char* UnwindError::ToCString() const { } ObjectPtr Instance::InvokeGetter(const String& getter_name, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); @@ -20762,15 +20557,30 @@ ObjectPtr Instance::InvokeGetter(const String& getter_name, Resolver::ResolveDynamicAnyArgs(zone, klass, internal_getter_name, /*allow_add=*/!FLAG_precompiled_mode)); + 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); + if (function.kind() == UntaggedFunction::kImplicitGetter) { + field = function.accessor_field(); + } + if (!field.IsNull()) { + CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); + } else { + CHECK_ERROR(function.VerifyCallEntryPoint()); + } + } + // Check for method extraction when method extractors are not lazily created. if (function.IsNull() && FLAG_precompiled_mode) { function = Resolver::ResolveDynamicAnyArgs(zone, klass, getter_name, /*allow_add=*/false); + if (!function.IsNull() && check_is_entrypoint) { + CHECK_ERROR(function.VerifyClosurizedEntryPoint()); + } + if (!function.IsNull() && function.SafeToClosurize()) { - if (check_is_entrypoint) { - CHECK_ERROR(function.VerifyEntryPoint(EntryPointPragma::kGetterOnly)); - } const Function& closure_function = Function::Handle(zone, function.ImplicitClosureFunction()); return closure_function.ImplicitInstanceClosure(*this); @@ -20786,15 +20596,14 @@ ObjectPtr Instance::InvokeGetter(const String& getter_name, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, args.Length(), Heap::kNew)); return InvokeInstanceFunction(thread, *this, function, internal_getter_name, - args, args_descriptor, check_is_entrypoint, - EntryPointPragma::kGetterOnly, - respect_reflectable, inst_type_args); + args, args_descriptor, respect_reflectable, + inst_type_args); } ObjectPtr Instance::InvokeSetter(const String& setter_name, const Instance& value, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); @@ -20812,6 +20621,20 @@ ObjectPtr Instance::InvokeSetter(const String& setter_name, Resolver::ResolveDynamicAnyArgs(zone, klass, internal_setter_name, /*allow_add=*/!FLAG_precompiled_mode)); + if (check_is_entrypoint) { + // The setter must correspond to either an entry-point field or a setter + // method explicitly marked. + Field& field = Field::Handle(zone); + if (setter.kind() == UntaggedFunction::kImplicitSetter) { + field = setter.accessor_field(); + } + if (!field.IsNull()) { + CHECK_ERROR(field.VerifyEntryPoint(EntryPointPragma::kSetterOnly)); + } else if (!setter.IsNull()) { + CHECK_ERROR(setter.VerifyCallEntryPoint()); + } + } + const int kTypeArgsLen = 0; const int kNumArgs = 2; const Array& args = Array::Handle(zone, Array::New(kNumArgs)); @@ -20822,16 +20645,15 @@ ObjectPtr Instance::InvokeSetter(const String& setter_name, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, args.Length(), Heap::kNew)); return InvokeInstanceFunction(thread, *this, setter, internal_setter_name, - args, args_descriptor, check_is_entrypoint, - EntryPointPragma::kSetterOnly, - respect_reflectable, inst_type_args); + args, args_descriptor, respect_reflectable, + inst_type_args); } ObjectPtr Instance::Invoke(const String& function_name, const Array& args, const Array& arg_names, - bool check_is_entrypoint, - bool respect_reflectable) const { + bool respect_reflectable, + bool check_is_entrypoint) const { Thread* thread = Thread::Current(); Zone* zone = thread->zone(); Class& klass = Class::Handle(zone, clazz()); @@ -20842,6 +20664,10 @@ ObjectPtr Instance::Invoke(const String& function_name, Resolver::ResolveDynamicAnyArgs(zone, klass, function_name, /*allow_add=*/!FLAG_precompiled_mode)); + if (!function.IsNull() && check_is_entrypoint) { + CHECK_ERROR(function.VerifyCallEntryPoint()); + } + // We don't pass any explicit type arguments, which will be understood as // using dynamic for any function type arguments by lower layers. const int kTypeArgsLen = 0; @@ -20862,6 +20688,9 @@ ObjectPtr Instance::Invoke(const String& function_name, Resolver::ResolveDynamicAnyArgs(zone, klass, getter_name, /*allow_add=*/!FLAG_precompiled_mode); if (!function.IsNull()) { + if (check_is_entrypoint) { + CHECK_ERROR(EntryPointFieldInvocationError(function_name)); + } ASSERT(function.kind() != UntaggedFunction::kMethodExtractor); // Invoke the getter. const int kNumArgs = 1; @@ -20873,8 +20702,6 @@ ObjectPtr Instance::Invoke(const String& function_name, const Object& getter_result = Object::Handle( zone, InvokeInstanceFunction(thread, *this, function, getter_name, getter_args, getter_args_descriptor, - check_is_entrypoint, - EntryPointPragma::kGetterOnly, respect_reflectable, inst_type_args)); if (getter_result.IsError()) { return getter_result.ptr(); @@ -20887,9 +20714,8 @@ ObjectPtr Instance::Invoke(const String& function_name, // Found an ordinary method. return InvokeInstanceFunction(thread, *this, function, function_name, args, - args_descriptor, check_is_entrypoint, - EntryPointPragma::kCallOnly, - respect_reflectable, inst_type_args); + args_descriptor, respect_reflectable, + inst_type_args); } ObjectPtr Instance::HashCode() const { @@ -27798,6 +27624,100 @@ EntryPointPragma FindEntryPointPragma(IsolateGroup* IG, return EntryPointPragma::kNever; } +DART_WARN_UNUSED_RESULT +ErrorPtr VerifyEntryPoint( + const Library& lib, + const Object& member, + const Object& annotated, + std::initializer_list 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 + // "has_pragma()" as a proxy, since that bit is usually retained. + bool is_marked_entrypoint = true; + if (annotated.IsClass() && !Class::Cast(annotated).has_pragma()) { + is_marked_entrypoint = false; + } else if (annotated.IsField() && !Field::Cast(annotated).has_pragma()) { + is_marked_entrypoint = false; + } else if (annotated.IsFunction() && + !Function::Cast(annotated).has_pragma()) { + is_marked_entrypoint = false; + } +#else + Object& metadata = Object::Handle(Object::empty_array().ptr()); + if (!annotated.IsNull()) { + metadata = lib.GetMetadata(annotated); + } + if (metadata.IsError()) return Error::RawCast(metadata.ptr()); + ASSERT(!metadata.IsNull() && metadata.IsArray()); + EntryPointPragma pragma = + FindEntryPointPragma(IsolateGroup::Current(), Array::Cast(metadata), + &Field::Handle(), &Object::Handle()); + 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) { + return EntryPointMemberInvocationError(member); + } + return Error::null(); +} + +DART_WARN_UNUSED_RESULT +ErrorPtr 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 invoking fields " + "(failure to resolve '%s')\n" + "ERROR: See " + "https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/" + "aot/entry_point_pragma.md\n", + getter_name.ToCString()); + OS::PrintErr("%s", error); + return ApiError::New(String::Handle(String::New(error))); +} + +DART_WARN_UNUSED_RESULT +ErrorPtr EntryPointMemberInvocationError(const Object& member) { + const char* member_cstring = + member.IsFunction() + ? OS::SCreate( + Thread::Current()->zone(), "%s (kind %s)", + Function::Cast(member).ToLibNamePrefixedQualifiedCString(), + Function::KindToCString(Function::Cast(member).kind())) + : member.ToCString(); + if (!FLAG_verify_entry_points) { + // Print a warning, but do not return an error. + char const* warning = OS::SCreate( + Thread::Current()->zone(), + "WARNING: '%s' is accessed through Dart C API without being marked as " + "an entry point; its tree-shaken signature cannot be verified.\n" + "WARNING: See " + "https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/" + "aot/entry_point_pragma.md\n", + member_cstring); + OS::PrintErr("%s", warning); + return Error::null(); + } + char const* error = OS::SCreate( + Thread::Current()->zone(), + "ERROR: It is illegal to access '%s' through Dart C API.\n" + "ERROR: See " + "https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/" + "aot/entry_point_pragma.md\n", + member_cstring); + OS::PrintErr("%s", error); + return ApiError::New(String::Handle(String::New(error))); +} + #if !defined(DART_PRECOMPILED_RUNTIME) // Note: see also [NeedsDynamicInvocationForwarder] which ensures that we // never land in a function which expects parameters in registers from a @@ -27864,34 +27784,74 @@ intptr_t Function::MaxNumberOfParametersInRegisters(Zone* zone) const { } #endif // !defined(DART_PRECOMPILED_RUNTIME) -ErrorPtr Function::VerifyEntryPoint(EntryPointPragma pragma) const { -#if defined(DART_PRECOMPILED_RUNTIME) - const Library& lib = Library::Handle(); -#else +ErrorPtr Function::VerifyCallEntryPoint() const { + if (!FLAG_verify_entry_points) return Error::null(); + const Class& cls = Class::Handle(Owner()); const Library& lib = Library::Handle(cls.library()); -#endif - return dart::VerifyEntryPoint(lib, *this, *this, pragma); + switch (kind()) { + case UntaggedFunction::kRegularFunction: + case UntaggedFunction::kSetterFunction: + case UntaggedFunction::kConstructor: + return dart::VerifyEntryPoint(lib, *this, *this, + {EntryPointPragma::kCallOnly}); + break; + case UntaggedFunction::kGetterFunction: + return dart::VerifyEntryPoint( + lib, *this, *this, + {EntryPointPragma::kCallOnly, EntryPointPragma::kGetterOnly}); + break; + case UntaggedFunction::kImplicitGetter: + return dart::VerifyEntryPoint(lib, *this, Field::Handle(accessor_field()), + {EntryPointPragma::kGetterOnly}); + break; + case UntaggedFunction::kImplicitSetter: + return dart::VerifyEntryPoint(lib, *this, Field::Handle(accessor_field()), + {EntryPointPragma::kSetterOnly}); + case UntaggedFunction::kMethodExtractor: + return Function::Handle(extracted_method_closure()) + .VerifyClosurizedEntryPoint(); + break; + default: + return dart::VerifyEntryPoint(lib, *this, Object::Handle(), {}); + break; + } +} + +ErrorPtr 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 UntaggedFunction::kRegularFunction: + return dart::VerifyEntryPoint(lib, *this, *this, + {EntryPointPragma::kGetterOnly}); + case UntaggedFunction::kImplicitClosureFunction: { + const Function& parent = Function::Handle(parent_function()); + return dart::VerifyEntryPoint(lib, parent, parent, + {EntryPointPragma::kGetterOnly}); + } + default: + UNREACHABLE(); + } } ErrorPtr Field::VerifyEntryPoint(EntryPointPragma pragma) const { -#if defined(DART_PRECOMPILED_RUNTIME) - const Library& lib = Library::Handle(); -#else + if (!FLAG_verify_entry_points) return Error::null(); const Class& cls = Class::Handle(Owner()); const Library& lib = Library::Handle(cls.library()); -#endif - return dart::VerifyEntryPoint(lib, *this, *this, pragma); + return dart::VerifyEntryPoint(lib, *this, *this, {pragma}); } ErrorPtr Class::VerifyEntryPoint() const { -#if defined(DART_PRECOMPILED_RUNTIME) - const Library& lib = Library::Handle(); -#else + if (!FLAG_verify_entry_points) return Error::null(); const Library& lib = Library::Handle(library()); - if (lib.IsNull()) return Error::null(); -#endif - return dart::VerifyEntryPoint(lib, *this, *this, EntryPointPragma::kAlways); + if (!lib.IsNull()) { + return dart::VerifyEntryPoint(lib, *this, *this, {}); + } else { + return Error::null(); + } } AbstractTypePtr RecordType::FieldTypeAt(intptr_t index) const { diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 5f6ff4f2276..dad3244e246 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -1878,16 +1878,16 @@ class Class : public Object { ObjectPtr Invoke(const String& selector, const Array& arguments, const Array& argument_names, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; ObjectPtr InvokeGetter(const String& selector, - bool check_is_entrypoint = true, + bool throw_nsm_if_absent, bool respect_reflectable = true, - bool for_invocation = false) const; + bool check_is_entrypoint = false) const; ObjectPtr InvokeSetter(const String& selector, const Instance& argument, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; // Evaluate the given expression as if it appeared in a static method of this // class and return the resulting value, or an error object if evaluating the @@ -2973,14 +2973,6 @@ enum class FfiCallbackKind : uint8_t { kAsyncCallback, }; -enum class EntryPointPragma { - kAlways, - kNever, - kGetterOnly, - kSetterOnly, - kCallOnly -}; - class Function : public Object { public: StringPtr name() const { return untag()->name(); } @@ -3320,17 +3312,14 @@ class Function : public Object { IsDynamicInvocationForwarderName(name()); } - // Returns true if this function is _Closure.dyn:call, which implements - // dynamically checked closure calls. - bool IsDynamicClosureCallDispatcher() const; - - // Returns true if this function is _Closure.call, which implements the - // Function interface for closures. - bool IsClosureCallDispatcher() const; - - // Returns true if this function is _Closure.get:call, which returns the - // closure object for invocation. - bool IsClosureCallGetter() const; + // Performs all the checks that don't require the current thread first, to + // avoid retrieving it unless they all pass. If you have a handle on the + // current thread, call the version that takes one instead. + bool IsDynamicClosureCallDispatcher() const { + if (!IsDynamicInvokeFieldDispatcher()) return false; + return IsDynamicClosureCallDispatcher(Thread::Current()); + } + bool IsDynamicClosureCallDispatcher(Thread* thread) const; bool IsDynamicInvocationForwarder() const { return kind() == UntaggedFunction::kDynamicInvocationForwarder; @@ -4004,7 +3993,10 @@ class Function : public Object { bool IsUnmodifiableTypedDataViewFactory() const; DART_WARN_UNUSED_RESULT - ErrorPtr VerifyEntryPoint(EntryPointPragma pragma) const; + ErrorPtr VerifyCallEntryPoint() const; + + DART_WARN_UNUSED_RESULT + ErrorPtr VerifyClosurizedEntryPoint() const; static intptr_t InstanceSize() { return RoundedAllocationSize(sizeof(UntaggedFunction)); @@ -4373,6 +4365,14 @@ class ClosureData : public Object { friend class Precompiler; // To wrap parent functions in WSRs. }; +enum class EntryPointPragma { + kAlways, + kNever, + kGetterOnly, + kSetterOnly, + kCallOnly +}; + class FfiTrampolineData : public Object { public: static intptr_t InstanceSize() { @@ -5129,16 +5129,16 @@ class Library : public Object { ObjectPtr Invoke(const String& selector, const Array& arguments, const Array& argument_names, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; ObjectPtr InvokeGetter(const String& selector, - bool check_is_entrypoint = true, + bool throw_nsm_if_absent, bool respect_reflectable = true, - bool for_invocation = false) const; + bool check_is_entrypoint = false) const; ObjectPtr InvokeSetter(const String& selector, const Instance& argument, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; // Evaluate the given expression as if it appeared in an top-level method of // this library and return the resulting value, or an error object if @@ -8393,15 +8393,15 @@ class Instance : public Object { ObjectPtr Invoke(const String& selector, const Array& arguments, const Array& argument_names, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; ObjectPtr InvokeGetter(const String& selector, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; ObjectPtr InvokeSetter(const String& selector, const Instance& argument, - bool check_is_entrypoint = true, - bool respect_reflectable = true) const; + bool respect_reflectable = true, + bool check_is_entrypoint = false) const; ObjectPtr EvaluateCompiledExpression( const Class& klass, @@ -13671,6 +13671,12 @@ EntryPointPragma FindEntryPointPragma(IsolateGroup* isolate_group, Field* reusable_field_handle, Object* reusable_object_handle); +DART_WARN_UNUSED_RESULT +ErrorPtr EntryPointFieldInvocationError(const String& getter_name); + +DART_WARN_UNUSED_RESULT +ErrorPtr EntryPointMemberInvocationError(const Object& member); + #undef PRECOMPILER_WSR_FIELD_DECLARATION } // namespace dart diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index 4d68968b5e3..cf9a390f3bf 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -5591,7 +5591,6 @@ TEST_CASE(FunctionWithBreakpointNotInlined) { " a();\n" // This is line 5. " }\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "test() {\n" " new A().b();\n" "}"; @@ -5635,7 +5634,7 @@ TEST_CASE(FunctionWithBreakpointNotInlined) { void SetBreakpoint(Dart_NativeArguments args) { // Refers to the DeoptimizeFramesWhenSettingBreakpoint function below. - const int kBreakpointLine = 10; + const int kBreakpointLine = 9; // This will force deoptimization of functions on stack. // Function on stack has to be optimized, since we want to trigger debuggers @@ -5658,9 +5657,7 @@ static Dart_NativeFunction SetBreakpointResolver(Dart_Handle name, } TEST_CASE(DeoptimizeFramesWhenSettingBreakpoint) { - const char* kOriginalScript = - "@pragma('vm:entry-point', 'call')\n" - "test() {}"; + const char* kOriginalScript = "test() {}"; Dart_Handle lib = TestCase::LoadTestScript(kOriginalScript, nullptr); EXPECT_VALID(lib); @@ -5689,7 +5686,6 @@ TEST_CASE(DeoptimizeFramesWhenSettingBreakpoint) { @pragma("vm:external-name", "setBreakpoint") external setBreakpoint(); baz() {} - @pragma('vm:entry-point', 'call') test() { if (true) { setBreakpoint(); @@ -5774,7 +5770,6 @@ TEST_CASE(DartAPI_BreakpointLockRace) { " a();\n" // This is line 5. " }\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "test() {\n" " new A().b();\n" "}"; @@ -6443,7 +6438,6 @@ TEST_CASE(InstanceEquality) { TEST_CASE(HashCode) { // Ensure C++ overrides of Instance::HashCode match the Dart implementations. const char* kScript = - "@pragma('vm:entry-point', 'call')\n" "foo() {\n" " return \"foo\".hashCode;\n" "}"; @@ -6476,21 +6470,18 @@ static bool HashCodeEqualsCanonicalizeHash( uint32_t hashcode_canonicalize_vm = kCalculateCanonicalizeHash, bool check_identity = true, bool check_hashcode = true) { - CStringUniquePtr kScriptChars(OS::SCreate(nullptr, - R"( - %s - - @pragma('vm:entry-point', 'call') - valueHashCode() { - return value().hashCode; - } - - @pragma('vm:entry-point', 'call') - valueIdentityHashCode() { - return identityHashCode(value()); - } - )", - value_script)); + CStringUniquePtr kScriptChars( + OS::SCreate(nullptr, + "%s" + "\n" + "valueHashCode() {\n" + " return value().hashCode;\n" + "}\n" + "\n" + "valueIdentityHashCode() {\n" + " return identityHashCode(value());\n" + "}\n", + value_script)); Dart_Handle lib = TestCase::LoadTestScript(kScriptChars.get(), nullptr); EXPECT_VALID(lib); @@ -6550,12 +6541,9 @@ static bool HashCodeEqualsCanonicalizeHash( TEST_CASE(HashCode_Double) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - value() { - return 1.0; - } - )"; + "value() {\n" + " return 1.0;\n" + "}\n"; // Double VM CanonicalizeHash is not equal to hashCode, because doubles // cannot be used as keys in constant sets and maps. However, doubles // _can_ be used for lookups in which case they are equal to their integer @@ -6570,110 +6558,83 @@ TEST_CASE(HashCode_Double) { TEST_CASE(HashCode_Mint) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - value() { - return 0x8000000; - } - )"; + "value() {\n" + " return 0x8000000;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript)); } TEST_CASE(HashCode_Null) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - value() { - return null; - } - )"; + "value() {\n" + " return null;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript)); } TEST_CASE(HashCode_Smi) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - value() { - return 123; - } - )"; + "value() {\n" + " return 123;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript)); } TEST_CASE(HashCode_String) { - const char* kScript = R"( - @pragma('vm:entry-point', 'call') - value() { - return 'asdf'; - } - )"; + const char* kScript = + "value() {\n" + " return 'asdf';\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript)); } TEST_CASE(HashCode_Symbol) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - value() { - return #A; - } - )"; - + "value() {\n" + " return #A;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kCalculateCanonicalizeHash, /*check_identity=*/false)); } TEST_CASE(HashCode_True) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - value() { - return true; - } - )"; + "value() {\n" + " return true;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript)); } TEST_CASE(HashCode_Type_Dynamic) { const char* kScript = - R"( - const type = dynamic; - - @pragma('vm:entry-point', 'call') - value() { - return type; - } - )"; + "const type = dynamic;\n" + "\n" + "value() {\n" + " return type;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kCalculateCanonicalizeHash, /*check_identity=*/false)); } TEST_CASE(HashCode_Type_Int) { const char* kScript = - R"( - const type = int; - - @pragma('vm:entry-point', 'call') - value() { - return type; - } - )"; + "const type = int;\n" + "\n" + "value() {\n" + " return type;\n" + "}\n"; EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kCalculateCanonicalizeHash, /*check_identity=*/false)); } TEST_CASE(Map_iteration) { const char* kScript = - R"( - @pragma('vm:entry-point', 'call') - makeMap() { - var map = {'x': 3, 'y': 4, 'z': 5, 'w': 6}; - map.remove('y'); - map.remove('w'); - return map; - } - )"; + "makeMap() {\n" + " var map = {'x': 3, 'y': 4, 'z': 5, 'w': 6};\n" + " map.remove('y');\n" + " map.remove('w');\n" + " return map;\n" + "}"; Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr); EXPECT_VALID(h_lib); Dart_Handle h_result = Dart_Invoke(h_lib, NewString("makeMap"), 0, nullptr); @@ -6859,31 +6820,25 @@ final Map expiredExperimentalFlagsNonConst = { ExperimentalFlag.variance: false, }; -@pragma('vm:entry-point', 'call') makeNonConstMap() { return expiredExperimentalFlagsNonConst; } -@pragma('vm:entry-point', 'call') firstKey() { return ExperimentalFlag.alternativeInvalidationStrategy; } -@pragma('vm:entry-point', 'call') firstKeyHashCode() { return firstKey().hashCode; } -@pragma('vm:entry-point', 'call') firstKeyIdentityHashCode() { return identityHashCode(firstKey()); } -@pragma('vm:entry-point', 'call') bool lookupSpreadCollections(Map map) => map[ExperimentalFlag.spreadCollections]; -@pragma('vm:entry-point', 'call') bool? lookupNull(Map map) => map[null]; )"; Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr); @@ -6961,17 +6916,15 @@ static void HashBaseNonConstEqualsConst(const char* script, bool check_data = true) { Dart_Handle lib = TestCase::LoadTestScript(script, nullptr); EXPECT_VALID(lib); - Dart_Handle non_const_result; - Dart_Handle const_result; - { - SetFlagScope sfs(&FLAG_verify_entry_points, false); - Dart_Handle init_result = Dart_Invoke(lib, NewString("init"), 0, nullptr); - EXPECT_VALID(init_result); - non_const_result = Dart_Invoke(lib, NewString("nonConstValue"), 0, nullptr); - EXPECT_VALID(non_const_result); - const_result = Dart_Invoke(lib, NewString("constValue"), 0, nullptr); - EXPECT_VALID(const_result); - } + Dart_Handle init_result = Dart_Invoke(lib, NewString("init"), 0, nullptr); + EXPECT_VALID(init_result); + Dart_Handle non_const_result = + Dart_Invoke(lib, NewString("nonConstValue"), 0, nullptr); + EXPECT_VALID(non_const_result); + Dart_Handle const_result = + Dart_Invoke(lib, NewString("constValue"), 0, nullptr); + EXPECT_VALID(const_result); + TransitionNativeToVM transition(Thread::Current()); const auto& non_const_object = Object::Handle(Api::UnwrapHandle(non_const_result)); @@ -7161,7 +7114,6 @@ void init() { TEST_CASE(Set_iteration) { const char* kScript = R"( -@pragma('vm:entry-point', 'call') makeSet() { var set = {'x', 'y', 'z', 'w'}; set.remove('y'); @@ -7218,12 +7170,10 @@ static SetPtr ConstructImmutableSet(const Array& input_data, TEST_CASE(ConstSet_vm) { const char* kScript = R"( -@pragma('vm:entry-point', 'call') makeNonConstSet() { return {1, 2, 3, 5, 8, 13}; } -@pragma('vm:entry-point', 'call') bool containsFive(Set set) => set.contains(5); )"; Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr); diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index 20db17db5a6..7a8f9f3edf3 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -334,7 +334,7 @@ bool ParsedFunction::IsGenericCovariantImplParameter(intptr_t i) const { ParsedFunction::DynamicClosureCallVars* ParsedFunction::EnsureDynamicClosureCallVars() { - ASSERT(function().IsDynamicClosureCallDispatcher()); + ASSERT(function().IsDynamicClosureCallDispatcher(thread())); if (dynamic_closure_call_vars_ != nullptr) return dynamic_closure_call_vars_; const auto& saved_args_desc = Array::Handle(zone(), function().saved_args_desc()); diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc index 6106ff3e87e..74fbfee00f0 100644 --- a/runtime/vm/profiler_test.cc +++ b/runtime/vm/profiler_test.cc @@ -6,7 +6,6 @@ #include "vm/dart_api_impl.h" #include "vm/dart_api_state.h" -#include "vm/flags.h" #include "vm/globals.h" #include "vm/profiler.h" #include "vm/profiler_service.h" @@ -243,11 +242,8 @@ static void Invoke(const Library& lib, Thread* thread = Thread::Current(); Dart_Handle api_lib = Api::NewHandle(thread, lib.ptr()); TransitionVMToNative transition(thread); - { - SetFlagScope sfs(&FLAG_verify_entry_points, false); - Dart_Handle result = Dart_Invoke(api_lib, NewString(name), argc, argv); - EXPECT_VALID(result); - } + Dart_Handle result = Dart_Invoke(api_lib, NewString(name), argc, argv); + EXPECT_VALID(result); } class AllocationFilter : public SampleFilter { diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index cea121d3090..39f52edc49d 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -2815,20 +2815,18 @@ static void Invoke(Thread* thread, JSONStream* js) { const Array& args = Array::Handle(zone, Array::MakeFixedLength(growable_args)); const Array& arg_names = Object::empty_array(); - // For debugging calls via vm-service, don't require entry point annotations. - const bool check_is_entrypoint = false; if (receiver.IsLibrary()) { const Library& lib = Library::Cast(receiver); - const Object& result = Object::Handle( - zone, lib.Invoke(selector, args, arg_names, check_is_entrypoint)); + const Object& result = + Object::Handle(zone, lib.Invoke(selector, args, arg_names)); result.PrintJSON(js, true); return; } if (receiver.IsClass()) { const Class& cls = Class::Cast(receiver); - const Object& result = Object::Handle( - zone, cls.Invoke(selector, args, arg_names, check_is_entrypoint)); + const Object& result = + Object::Handle(zone, cls.Invoke(selector, args, arg_names)); result.PrintJSON(js, true); return; } @@ -2836,8 +2834,8 @@ static void Invoke(Thread* thread, JSONStream* js) { // We don't use Instance::Cast here because it doesn't allow null. Instance& instance = Instance::Handle(zone); instance ^= receiver.ptr(); - const Object& result = Object::Handle( - zone, instance.Invoke(selector, args, arg_names, check_is_entrypoint)); + const Object& result = + Object::Handle(zone, instance.Invoke(selector, args, arg_names)); result.PrintJSON(js, true); return; } diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc index c484409143c..acabf22706c 100644 --- a/runtime/vm/service_isolate.cc +++ b/runtime/vm/service_isolate.cc @@ -459,7 +459,7 @@ class RunServiceTask : public ThreadPool::Task { return Utils::StrDup("Service isolate is not supported by embedder."); } ASSERT(!root_library.IsNull()); - const String& entry_name = Symbols::main(); + const String& entry_name = String::Handle(Z, String::New("main")); ASSERT(!entry_name.IsNull()); const Function& entry = Function::Handle( Z, root_library.LookupFunctionAllowPrivate(entry_name)); diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc index c80b2c66f81..7e254d6a932 100644 --- a/runtime/vm/service_test.cc +++ b/runtime/vm/service_test.cc @@ -237,7 +237,6 @@ ISOLATE_UNIT_TEST_CASE(Service_Code) { " x();\n" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Isolate* isolate = thread->isolate(); isolate->set_is_runnable(true); Dart_Handle lib; @@ -363,7 +362,6 @@ ISOLATE_UNIT_TEST_CASE(Service_PcDescriptors) { " x();\n" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Isolate* isolate = thread->isolate(); isolate->set_is_runnable(true); Dart_Handle lib; @@ -435,7 +433,6 @@ ISOLATE_UNIT_TEST_CASE(Service_LocalVarDescriptors) { " x();\n" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Isolate* isolate = thread->isolate(); isolate->set_is_runnable(true); Dart_Handle lib; @@ -503,7 +500,6 @@ ISOLATE_UNIT_TEST_CASE(Service_PersistentHandles) { " return global;\n" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Isolate* isolate = thread->isolate(); isolate->set_is_runnable(true); @@ -595,7 +591,6 @@ ISOLATE_UNIT_TEST_CASE(Service_EmbedderRootHandler) { " x = (x / 13).floor();\n" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib; { TransitionVMToNative transition(thread); @@ -641,7 +636,6 @@ ISOLATE_UNIT_TEST_CASE(Service_EmbedderIsolateHandler) { " x = (x / 13).floor();\n" "}"; - SetFlagScope sfs(&FLAG_verify_entry_points, false); Dart_Handle lib; { TransitionVMToNative transition(thread); @@ -693,7 +687,6 @@ static void EnableProfiler() { ISOLATE_UNIT_TEST_CASE(Service_Profile) { EnableProfiler(); const char* kScript = - "@pragma('vm:entry-point', 'set')\n" "var port;\n" // Set to our mock port by C++. "\n" "var x = 7;\n" diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc index 50c4d673b29..f1139ac5b8b 100644 --- a/runtime/vm/snapshot_test.cc +++ b/runtime/vm/snapshot_test.cc @@ -723,9 +723,7 @@ VM_UNIT_TEST_CASE(FullSnapshot) { " if (x != y) throw new ArgumentError('not equal');\n" " }\n" "}\n" - "@pragma('vm:entry-point')\n" "class FieldsTest {\n" - " @pragma('vm:entry-point', 'call')\n" " static Fields testMain() {\n" " Expect.equals(true, Fields.bigint_sfld == 0xfffffffffff);\n" " Fields obj = new Fields(10, 20);\n" @@ -797,11 +795,8 @@ static std::unique_ptr GetSerialized(Dart_Handle lib, Dart_Handle result; { TransitionVMToNative transition(Thread::Current()); - { - SetFlagScope sfs(&FLAG_verify_entry_points, false); - result = Dart_Invoke(lib, NewString(dart_function), 0, nullptr); - EXPECT_VALID(result); - } + result = Dart_Invoke(lib, NewString(dart_function), 0, nullptr); + EXPECT_VALID(result); } Object& obj = Object::Handle(Api::UnwrapHandle(result)); @@ -843,39 +838,30 @@ static void CheckStringInvalid(Dart_Handle dart_string) { VM_UNIT_TEST_CASE(DartGeneratedMessages) { static const char* kCustomIsolateScriptChars = "final int kArrayLength = 10;\n" - "@pragma('vm:entry-point', 'call')\n" "getSmi() {\n" " return 42;\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getAsciiString() {\n" " return \"Hello, world!\";\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getNonAsciiString() {\n" " return \"Blåbærgrød\";\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getNonBMPString() {\n" " return \"\\u{10000}\\u{1F601}\\u{1F637}\\u{20000}\";\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getLeadSurrogateString() {\n" " return String.fromCharCodes([0xd800]);\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getTrailSurrogateString() {\n" " return \"\\u{10000}\".substring(1);\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getSurrogatesString() {\n" " return String.fromCharCodes([0xdc00, 0xdc00, 0xd800, 0xd800]);\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getCrappyString() {\n" " return String.fromCharCodes([0xd800, 32, 0xdc00, 32]);\n" "}\n" - "@pragma('vm:entry-point', 'call')\n" "getList() {\n" " return List.filled(kArrayLength, null);\n" "}\n"; diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc index b2f8724cecc..2f8cb5bed35 100644 --- a/runtime/vm/stack_frame_test.cc +++ b/runtime/vm/stack_frame_test.cc @@ -234,9 +234,7 @@ TEST_CASE(ValidateStackFrameIteration) { " StackFrame.validateFrame(5, \"StackFrameTest_testMain\");" " }" "}" - "@pragma('vm:entry-point')\n" "class StackFrameTest {" - " @pragma('vm:entry-point', 'call')\n" " static testMain() {" " Second obj = new Second();" " obj.method1(1);" @@ -263,7 +261,6 @@ TEST_CASE(ValidateNoSuchMethodStackFrameIteration) { " @pragma('vm:external-name', 'StackFrame_validateFrame')\n" " external static validateFrame(int index, String name);" "} " - "@pragma('vm:entry-point')\n" "class StackFrame2Test {" " StackFrame2Test() {}" " noSuchMethod(Invocation im) {" @@ -284,7 +281,6 @@ TEST_CASE(ValidateNoSuchMethodStackFrameIteration) { " StackFrame.validateFrame(3, \"StackFrame2Test_testMain\");" " return 5;" " }" - " @pragma('vm:entry-point', 'call')\n" " static testMain() {" " /* Declare |obj| dynamic so that noSuchMethod can be" " * called in strong mode. */" diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index 8a26f385fad..3902536a47d 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -529,7 +529,6 @@ class ObjectPointerVisitor; V(index_temp, ":index_temp") \ V(isLeaf, "isLeaf") \ V(isPaused, "isPaused") \ - V(main, "main") \ V(match_end_index, ":match_end_index") \ V(match_start_index, ":match_start_index") \ V(name, "name") \ diff --git a/sdk/lib/_internal/vm/bin/builtin.dart b/sdk/lib/_internal/vm/bin/builtin.dart index b84147a1fb0..82bce74adc6 100644 --- a/sdk/lib/_internal/vm/bin/builtin.dart +++ b/sdk/lib/_internal/vm/bin/builtin.dart @@ -14,7 +14,6 @@ import 'dart:typed_data'; // Embedder sets this to true if the --trace-loading flag was passed on the // command line. -@pragma("vm:entry-point", "set") bool _traceLoading = false; // Before handling an embedder entrypoint we finalize the setup of the @@ -31,7 +30,7 @@ void _print(arg) { _printString(arg.toString()); } -@pragma("vm:entry-point", "call") +@pragma("vm:entry-point") _getPrintClosure() => _print; // The current working directory when the embedder was launched. @@ -61,7 +60,7 @@ Map? _packageMap = null; // Special handling for Windows paths so that they are compatible with URI // handling. // Embedder sets this to true if we are running on Windows. -@pragma("vm:entry-point", "set") +@pragma("vm:entry-point") bool _isWindows = false; // Logging from builtin.dart is prefixed with a '*'. diff --git a/sdk/lib/_internal/vm/bin/secure_socket_patch.dart b/sdk/lib/_internal/vm/bin/secure_socket_patch.dart index 9c5d2130b92..f6c2bdfafd4 100644 --- a/sdk/lib/_internal/vm/bin/secure_socket_patch.dart +++ b/sdk/lib/_internal/vm/bin/secure_socket_patch.dart @@ -189,7 +189,7 @@ base class _SecureFilterImpl extends NativeFieldWrapperClass1 @pragma("vm:external-name", "SecureSocket_FilterPointer") external int _pointer(); - @pragma("vm:entry-point") + @pragma("vm:entry-point", "get") List<_ExternalBuffer>? buffers; } diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart index 583992e0a67..9f73a27ebd9 100644 --- a/sdk/lib/_internal/vm/lib/errors_patch.dart +++ b/sdk/lib/_internal/vm/lib/errors_patch.dart @@ -108,7 +108,6 @@ class _TypeError extends Error implements TypeError { final String _message; } -@pragma("vm:entry-point") class _InternalError { @pragma("vm:entry-point") const _InternalError(this._msg); diff --git a/sdk/lib/_internal/vm/lib/print_patch.dart b/sdk/lib/_internal/vm/lib/print_patch.dart index 972283970ea..bd6ab4546ef 100644 --- a/sdk/lib/_internal/vm/lib/print_patch.dart +++ b/sdk/lib/_internal/vm/lib/print_patch.dart @@ -19,5 +19,5 @@ void _unsupportedPrint(String line) { // _printClosure can be overwritten by the embedder to supply a different // print implementation. -@pragma("vm:entry-point", "set") +@pragma("vm:entry-point") _PrintClosure _printClosure = _unsupportedPrint; diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart index eae4fce4f38..35e90539b6e 100644 --- a/sdk/lib/core/errors.dart +++ b/sdk/lib/core/errors.dart @@ -159,7 +159,6 @@ class TypeError extends Error {} /// so the [ArgumentError.value] constructor is the preferred constructor. /// Use [ArgumentError.new] only when the value cannot be provided for some /// reason. -@pragma("vm:entry-point") class ArgumentError extends Error { /// Whether value was provided. final bool _hasValue; diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart index c8f92cf331b..c7a064d8ba1 100644 --- a/sdk/lib/core/exceptions.dart +++ b/sdk/lib/core/exceptions.dart @@ -39,7 +39,6 @@ class _Exception implements Exception { /// Exception thrown when a string or some other data does not have an expected /// format and cannot be parsed or processed. -@pragma("vm:entry-point") class FormatException implements Exception { /// A message describing the format error. final String message; diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart index 6252b27c103..df37688c791 100644 --- a/sdk/lib/io/secure_socket.dart +++ b/sdk/lib/io/secure_socket.dart @@ -1218,7 +1218,7 @@ class _RawSecureSocket extends Stream /// and one writing. All updates to start and end are done by Dart code. class _ExternalBuffer { // This will be an ExternalByteArray, backed by C allocated data. - @pragma("vm:entry-point") + @pragma("vm:entry-point", "set") List? data; @pragma("vm:entry-point") @@ -1367,7 +1367,6 @@ abstract class _SecureFilter { /// A secure networking exception caused by a failure in the /// TLS/SSL protocol. -@pragma("vm:entry-point") class TlsException implements IOException { final String type; final String message; diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart index e20cf666e2b..eebfe3ee363 100644 --- a/sdk/lib/isolate/isolate.dart +++ b/sdk/lib/isolate/isolate.dart @@ -73,7 +73,6 @@ class IsolateSpawnException implements Exception { /// An `Isolate` object cannot be sent over a `SendPort`, but the control port /// and capabilities can be sent, and can be used to create a new functioning /// `Isolate` object in the receiving port's isolate. -@pragma('vm:entry-point') final class Isolate { /// Argument to `ping` and `kill`: Ask for immediate action. static const int immediate = 0; diff --git a/tests/lib/lib_kernel.status b/tests/lib/lib_kernel.status index 5b4993c4be3..2faf2b7a760 100644 --- a/tests/lib/lib_kernel.status +++ b/tests/lib/lib_kernel.status @@ -42,7 +42,7 @@ isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel iss isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335. isolate/issue_21398_parent_isolate2_test/01: Skip # Times out. Deferred loading kernel issue 28335. isolate/static_function_test: Skip # Times out. Issue 31855. CompileTimeError. Issue 31402 -mirrors/invocation_fuzz_test/smi: Crash +mirrors/invocation_fuzz_test: Crash mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes. [ $compiler == dartk && $hot_reload_rollback ]