Reapply "[vm] Don't use a fuzzy lookup for recognized methods."

- Fix incorrectly named ALL_INTRINSICS_LIST to ASM_INTRINSICS_LIST and restore setting intrinsic bit for graph intrinsics.
 - Remove more dead code.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/56007
Change-Id: Iebceaab86509e34f47e3d6918706b0e69ed7dfc5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/374842
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2024-07-09 16:33:19 +00:00
committed by Commit Queue
parent a16a6537e5
commit 9ab5245b89
12 changed files with 830 additions and 783 deletions
+2 -2
View File
@@ -3846,7 +3846,7 @@ void Obfuscator::InitializeRenamingMap() {
// Prevent renaming of methods that are looked up by method recognizer.
// TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
// where these are looked up.
#define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
#define PREVENT_RENAMING(library, class_name, function_name, recognized_enum, \
fingerprint) \
do { \
PreventRenaming(#class_name); \
@@ -3858,7 +3858,7 @@ void Obfuscator::InitializeRenamingMap() {
// Prevent renaming of methods that are looked up by method recognizer.
// TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
// where these are looked up.
#define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
#define PREVENT_RENAMING(libary, class_name, function_name, recognized_enum, \
fingerprint) \
do { \
PreventRenaming(#class_name); \
+2 -2
View File
@@ -32,9 +32,9 @@ class AsmIntrinsifier : public AllStatic {
private:
friend class Intrinsifier;
#define DECLARE_FUNCTION(class_name, function_name, enum_name, fp) \
#define DECLARE_FUNCTION(library, class, function, enum_name, fp) \
static void enum_name(Assembler* assembler, Label* normal_ir_body);
ALL_INTRINSICS_LIST(DECLARE_FUNCTION)
ASM_INTRINSICS_LIST(DECLARE_FUNCTION)
#undef DECLARE_FUNCTION
+1 -1
View File
@@ -88,7 +88,7 @@ bool GraphIntrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
const Function& function = parsed_function.function();
switch (function.recognized_kind()) {
#define EMIT_CASE(class_name, function_name, enum_name, fp) \
#define EMIT_CASE(library, class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name: \
if (!Build_##enum_name(graph)) return false; \
break;
+2 -2
View File
@@ -30,14 +30,14 @@ class GraphIntrinsifier : public AllStatic {
FlowGraphCompiler* compiler);
private:
#define DECLARE_FUNCTION(class_name, function_name, enum_name, fp) \
#define DECLARE_FUNCTION(library, class, function, enum_name, fp) \
static void enum_name(Assembler* assembler, Label* normal_ir_body);
GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
#undef DECLARE_FUNCTION
#define DECLARE_FUNCTION(class_name, function_name, enum_name, fp) \
#define DECLARE_FUNCTION(library, class, function, enum_name, fp) \
static bool Build_##enum_name(FlowGraph* flow_graph);
GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
+2 -101
View File
@@ -75,100 +75,6 @@ bool Intrinsifier::CanIntrinsify(const ParsedFunction& parsed_function) {
return true;
}
struct IntrinsicDesc {
const char* class_name;
const char* function_name;
};
struct LibraryIntrinsicsDesc {
Library& library;
const IntrinsicDesc* intrinsics;
};
#define DEFINE_INTRINSIC(class_name, function_name, destination, fp) \
{#class_name, #function_name},
// clang-format off
static const IntrinsicDesc core_intrinsics[] = {
CORE_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
CORE_INTEGER_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
GRAPH_CORE_INTRINSICS_LIST(DEFINE_INTRINSIC)
{nullptr, nullptr},
};
static const IntrinsicDesc typed_data_intrinsics[] = {
GRAPH_TYPED_DATA_INTRINSICS_LIST(DEFINE_INTRINSIC)
{nullptr, nullptr},
};
static const IntrinsicDesc developer_intrinsics[] = {
DEVELOPER_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
{nullptr, nullptr},
};
static const IntrinsicDesc internal_intrinsics[] = {
INTERNAL_LIB_INTRINSIC_LIST(DEFINE_INTRINSIC)
{nullptr, nullptr},
};
// clang-format on
void Intrinsifier::InitializeState() {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Library& lib = Library::Handle(zone);
Class& cls = Class::Handle(zone);
Function& func = Function::Handle(zone);
String& str = String::Handle(zone);
String& str2 = String::Handle(zone);
Error& error = Error::Handle(zone);
const intptr_t kNumLibs = 4;
const LibraryIntrinsicsDesc intrinsics[kNumLibs] = {
{Library::Handle(zone, Library::CoreLibrary()), core_intrinsics},
{Library::Handle(zone, Library::TypedDataLibrary()),
typed_data_intrinsics},
{Library::Handle(zone, Library::DeveloperLibrary()),
developer_intrinsics},
{Library::Handle(zone, Library::InternalLibrary()), internal_intrinsics},
};
for (intptr_t i = 0; i < kNumLibs; i++) {
lib = intrinsics[i].library.ptr();
for (const IntrinsicDesc* intrinsic = intrinsics[i].intrinsics;
intrinsic->class_name != nullptr; intrinsic++) {
func = Function::null();
if (strcmp(intrinsic->class_name, "::") == 0) {
str = String::New(intrinsic->function_name);
func = lib.LookupFunctionAllowPrivate(str);
} else {
str = String::New(intrinsic->class_name);
cls = lib.LookupClassAllowPrivate(str);
ASSERT(FLAG_precompiled_mode || !cls.IsNull());
if (!cls.IsNull()) {
error = cls.EnsureIsFinalized(thread);
if (!error.IsNull()) {
OS::PrintErr("%s\n", error.ToErrorCString());
}
ASSERT(error.IsNull());
str = String::New(intrinsic->function_name);
if (intrinsic->function_name[0] == '.') {
str2 = String::New(intrinsic->class_name);
str = String::Concat(str2, str);
}
func = cls.LookupFunctionAllowPrivate(str);
}
}
if (!func.IsNull()) {
func.set_is_intrinsic(true);
} else if (!FLAG_precompiled_mode) {
FATAL("Intrinsifier failed to find method %s in class %s\n",
intrinsic->function_name, intrinsic->class_name);
}
}
}
#undef SETUP_FUNCTION
}
// Returns true if fall-through code can be omitted.
bool Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
FlowGraphCompiler* compiler) {
@@ -197,7 +103,7 @@ bool Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
#define EMIT_BREAKPOINT()
#endif
#define EMIT_CASE(class_name, function_name, enum_name, fp) \
#define EMIT_CASE(library, class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name: { \
compiler->assembler()->Comment("Intrinsic"); \
Label normal_ir_body; \
@@ -221,12 +127,7 @@ bool Intrinsifier::Intrinsify(const ParsedFunction& parsed_function,
}
switch (function.recognized_kind()) {
ALL_INTRINSICS_NO_INTEGER_LIB_LIST(EMIT_CASE);
default:
break;
}
switch (function.recognized_kind()) {
CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE)
ASM_INTRINSICS_LIST(EMIT_CASE);
default:
break;
}
-2
View File
@@ -31,8 +31,6 @@ class Intrinsifier : public AllStatic {
static bool Intrinsify(const ParsedFunction& parsed_function,
FlowGraphCompiler* compiler);
static void InitializeState();
private:
static bool CanIntrinsify(const ParsedFunction& parsed_function);
};
+56 -50
View File
@@ -115,14 +115,12 @@ intptr_t MethodRecognizer::MethodKindToReceiverCid(Kind kind) {
}
static const struct {
const char* const class_name;
const char* const function_name;
const char* const enum_name;
const uint32_t fp;
} recognized_methods[MethodRecognizer::kNumRecognizedMethods] = {
{"", "", "Unknown", 0},
#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp) \
{"" #class_name, "" #function_name, #enum_name, fp},
{"", "Unknown"},
#define RECOGNIZE_METHOD(library, class_name, function_name, enum_name, fp) \
{"" #function_name, #enum_name},
RECOGNIZED_LIST(RECOGNIZE_METHOD)
#undef RECOGNIZE_METHOD
};
@@ -160,40 +158,60 @@ bool MethodRecognizer::IsMarkedAsRecognized(const Function& function,
return String::Cast(options).Equals(kind);
}
static bool IsAssemblerIntrinsic(MethodRecognizer::Kind kind) {
switch (kind) {
#define RECOGNIZE_METHOD(library, class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name:
ASM_INTRINSICS_LIST(RECOGNIZE_METHOD)
#undef RECOGNIZE_METHOD
return true;
default:
return false;
}
}
static bool IsGraphIntrinsic(MethodRecognizer::Kind kind) {
switch (kind) {
#define RECOGNIZE_METHOD(library, class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name:
GRAPH_INTRINSICS_LIST(RECOGNIZE_METHOD)
#undef RECOGNIZE_METHOD
return true;
default:
return false;
}
}
void MethodRecognizer::InitializeState() {
GrowableArray<Library*> libs(3);
Libraries(&libs);
Library& lib = Library::Handle();
Function& func = Function::Handle();
bool fingerprints_match = true;
for (intptr_t i = 1; i < MethodRecognizer::kNumRecognizedMethods; i++) {
const MethodRecognizer::Kind kind = static_cast<MethodRecognizer::Kind>(i);
func = Library::GetFunction(libs, recognized_methods[i].class_name,
recognized_methods[i].function_name);
if (!func.IsNull()) {
fingerprints_match =
func.CheckSourceFingerprint(recognized_methods[i].fp) &&
fingerprints_match;
func.set_recognized_kind(kind);
switch (kind) {
#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name: \
func.reset_unboxed_parameters_and_return(); \
break;
ALL_INTRINSICS_LIST(RECOGNIZE_METHOD)
#undef RECOGNIZE_METHOD
default:
break;
}
} else if (!FLAG_precompiled_mode) {
fingerprints_match = false;
OS::PrintErr("Missing %s::%s\n", recognized_methods[i].class_name,
recognized_methods[i].function_name);
}
#define RECOGNIZE_METHOD(library, class_name, function_name, enum_name, fp) \
lib = Library::library(); \
func = Library::GetFunction(lib, #class_name, #function_name); \
if (!func.IsNull()) { \
fingerprints_match = \
func.CheckSourceFingerprint(fp) && fingerprints_match; \
func.set_recognized_kind(k##enum_name); \
if (IsAssemblerIntrinsic(k##enum_name)) { \
func.reset_unboxed_parameters_and_return(); \
func.set_is_intrinsic(true); \
} else if (IsGraphIntrinsic(k##enum_name)) { \
func.set_is_intrinsic(true); \
} \
} else if (!FLAG_precompiled_mode) { \
fingerprints_match = false; \
OS::PrintErr("Missing %s %s::%s\n", #library, #class_name, \
#function_name); \
}
RECOGNIZED_LIST(RECOGNIZE_METHOD)
#undef RECOGNIZE_METHOD
#define SET_FUNCTION_BIT(class_name, function_name, dest, fp, setter, value) \
func = Library::GetFunction(libs, #class_name, #function_name); \
#define SET_FUNCTION_BIT(library, class_name, function_name, dest, fp, setter, \
value) \
lib = Library::library(); \
func = Library::GetFunction(lib, #class_name, #function_name); \
if (!func.IsNull()) { \
fingerprints_match = \
func.CheckSourceFingerprint(fp) && fingerprints_match; \
@@ -203,8 +221,9 @@ void MethodRecognizer::InitializeState() {
fingerprints_match = false; \
}
#define SET_IS_POLYMORPHIC_TARGET(class_name, function_name, dest, fp) \
SET_FUNCTION_BIT(class_name, function_name, dest, fp, \
#define SET_IS_POLYMORPHIC_TARGET(library, class_name, function_name, dest, \
fp) \
SET_FUNCTION_BIT(library, class_name, function_name, dest, fp, \
set_is_polymorphic_target, true)
POLYMORPHIC_TARGET_LIST(SET_IS_POLYMORPHIC_TARGET);
@@ -224,20 +243,6 @@ void MethodRecognizer::InitializeState() {
}
}
void MethodRecognizer::Libraries(GrowableArray<Library*>* libs) {
libs->Add(&Library::ZoneHandle(Library::CoreLibrary()));
libs->Add(&Library::ZoneHandle(Library::CollectionLibrary()));
libs->Add(&Library::ZoneHandle(Library::MathLibrary()));
libs->Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
libs->Add(&Library::ZoneHandle(Library::ConvertLibrary()));
libs->Add(&Library::ZoneHandle(Library::InternalLibrary()));
libs->Add(&Library::ZoneHandle(Library::IsolateLibrary()));
libs->Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
libs->Add(&Library::ZoneHandle(Library::AsyncLibrary()));
libs->Add(&Library::ZoneHandle(Library::FfiLibrary()));
libs->Add(&Library::ZoneHandle(Library::NativeWrappersLibrary()));
}
static Token::Kind RecognizeTokenKindHelper(const String& name) {
if (name.ptr() == Symbols::Plus().ptr()) {
return Token::kADD;
@@ -299,7 +304,8 @@ Token::Kind MethodTokenRecognizer::RecognizeTokenKind(const String& name) {
}
}
#define RECOGNIZE_FACTORY(symbol, class_name, constructor_name, cid, fp) \
#define RECOGNIZE_FACTORY(symbol, library, class_name, constructor_name, cid, \
fp) \
{Symbols::k##symbol##Id, cid, fp, #symbol ", " #cid}, // NOLINT
static const struct {
+1 -4
View File
@@ -26,7 +26,7 @@ class MethodRecognizer : public AllStatic {
public:
enum Kind {
kUnknown,
#define DEFINE_ENUM_LIST(class_name, function_name, enum_name, fp) k##enum_name,
#define DEFINE_ENUM_LIST(library, class, function, enum_name, fp) k##enum_name,
RECOGNIZED_LIST(DEFINE_ENUM_LIST)
#undef DEFINE_ENUM_LIST
kNumRecognizedMethods
@@ -49,9 +49,6 @@ class MethodRecognizer : public AllStatic {
static bool IsMarkedAsRecognized(const Function& function,
const char* kind = nullptr);
static void InitializeState();
private:
static void Libraries(GrowableArray<Library*>* libs);
};
// Recognizes token corresponding to a method name.
File diff suppressed because it is too large Load Diff
+42 -64
View File
@@ -2442,9 +2442,6 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group,
ClassFinalizer::VerifyBootstrapClasses();
// Set up the intrinsic state of all functions (core, math and typed data).
compiler::Intrinsifier::InitializeState();
// Adds static const fields (class ids) to the class 'ClassID');
lib = Library::LookupLibrary(thread, Symbols::DartInternal());
ASSERT(!lib.IsNull());
@@ -15313,7 +15310,7 @@ ErrorPtr Library::FinalizeAllClasses() {
#endif // !defined(DART_PRECOMPILED_RUNTIME)
// Return Function::null() if function does not exist in libs.
FunctionPtr Library::GetFunction(const GrowableArray<Library*>& libs,
FunctionPtr Library::GetFunction(const Library& lib,
const char* class_name,
const char* function_name) {
Thread* thread = Thread::Current();
@@ -15322,28 +15319,22 @@ FunctionPtr Library::GetFunction(const GrowableArray<Library*>& libs,
String& class_str = String::Handle(zone);
String& func_str = String::Handle(zone);
Class& cls = Class::Handle(zone);
for (intptr_t l = 0; l < libs.length(); l++) {
const Library& lib = *libs[l];
if (strcmp(class_name, "::") == 0) {
cls = lib.toplevel_class();
} else {
class_str = String::New(class_name);
cls = lib.LookupClassAllowPrivate(class_str);
}
if (!cls.IsNull()) {
if (cls.EnsureIsFinalized(thread) == Error::null()) {
func_str = String::New(function_name);
if (function_name[0] == '.') {
func_str = String::Concat(class_str, func_str);
}
func = cls.LookupFunctionAllowPrivate(func_str);
if (strcmp(class_name, "::") == 0) {
cls = lib.toplevel_class();
} else {
class_str = String::New(class_name);
cls = lib.LookupClassAllowPrivate(class_str);
}
if (!cls.IsNull()) {
if (cls.EnsureIsFinalized(thread) == Error::null()) {
func_str = String::New(function_name);
if (function_name[0] == '.') {
func_str = String::Concat(class_str, func_str);
}
}
if (!func.IsNull()) {
return func.ptr();
func = cls.LookupFunctionAllowPrivate(func_str);
}
}
return Function::null();
return func.ptr();
}
ObjectPtr Library::GetFunctionClosure(const String& name) const {
@@ -15373,12 +15364,14 @@ ObjectPtr Library::GetFunctionClosure(const String& name) const {
#if defined(DEBUG) && !defined(DART_PRECOMPILED_RUNTIME)
void Library::CheckFunctionFingerprints() {
GrowableArray<Library*> all_libs;
Library& lib = Library::Handle();
Function& func = Function::Handle();
bool fingerprints_match = true;
#define CHECK_FINGERPRINTS_INNER(class_name, function_name, dest, fp, kind) \
func = GetFunction(all_libs, #class_name, #function_name); \
#define CHECK_FINGERPRINTS_INNER(library, class_name, function_name, dest, fp, \
kind) \
lib = Library::library(); \
func = Library::GetFunction(lib, #class_name, #function_name); \
if (func.IsNull()) { \
fingerprints_match = false; \
OS::PrintErr("Function not found %s.%s\n", #class_name, #function_name); \
@@ -15387,40 +15380,25 @@ void Library::CheckFunctionFingerprints() {
func.CheckSourceFingerprint(fp, kind) && fingerprints_match; \
}
#define CHECK_FINGERPRINTS(class_name, function_name, dest, fp) \
CHECK_FINGERPRINTS_INNER(class_name, function_name, dest, fp, nullptr)
#define CHECK_FINGERPRINTS_ASM_INTRINSIC(class_name, function_name, dest, fp) \
CHECK_FINGERPRINTS_INNER(class_name, function_name, dest, fp, "asm-intrinsic")
#define CHECK_FINGERPRINTS_GRAPH_INTRINSIC(class_name, function_name, dest, \
fp) \
CHECK_FINGERPRINTS_INNER(class_name, function_name, dest, fp, \
#define CHECK_FINGERPRINTS(library, class_name, function_name, dest, fp) \
CHECK_FINGERPRINTS_INNER(library, class_name, function_name, dest, fp, \
nullptr)
#define CHECK_FINGERPRINTS_ASM_INTRINSIC(library, class_name, function_name, \
dest, fp) \
CHECK_FINGERPRINTS_INNER(library, class_name, function_name, dest, fp, \
"asm-intrinsic")
#define CHECK_FINGERPRINTS_GRAPH_INTRINSIC(library, class_name, function_name, \
dest, fp) \
CHECK_FINGERPRINTS_INNER(library, class_name, function_name, dest, fp, \
"graph-intrinsic")
#define CHECK_FINGERPRINTS_OTHER(class_name, function_name, dest, fp) \
CHECK_FINGERPRINTS_INNER(class_name, function_name, dest, fp, "other")
#define CHECK_FINGERPRINTS_OTHER(library, class_name, function_name, dest, fp) \
CHECK_FINGERPRINTS_INNER(library, class_name, function_name, dest, fp, \
"other")
all_libs.Add(&Library::ZoneHandle(Library::CoreLibrary()));
CORE_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
CORE_INTEGER_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
GRAPH_CORE_INTRINSICS_LIST(CHECK_FINGERPRINTS_GRAPH_INTRINSIC);
all_libs.Add(&Library::ZoneHandle(Library::AsyncLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::MathLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::CollectionLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::ConvertLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::InternalLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::IsolateLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::FfiLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::NativeWrappersLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
INTERNAL_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
OTHER_RECOGNIZED_LIST(CHECK_FINGERPRINTS_OTHER);
POLYMORPHIC_TARGET_LIST(CHECK_FINGERPRINTS);
GRAPH_TYPED_DATA_INTRINSICS_LIST(CHECK_FINGERPRINTS_GRAPH_INTRINSIC);
all_libs.Clear();
all_libs.Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
DEVELOPER_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
POLYMORPHIC_TARGET_LIST(CHECK_FINGERPRINTS)
ASM_INTRINSICS_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC)
GRAPH_INTRINSICS_LIST(CHECK_FINGERPRINTS_GRAPH_INTRINSIC)
OTHER_RECOGNIZED_LIST(CHECK_FINGERPRINTS_OTHER)
#undef CHECK_FINGERPRINTS_INNER
#undef CHECK_FINGERPRINTS
@@ -15428,19 +15406,19 @@ void Library::CheckFunctionFingerprints() {
#undef CHECK_FINGERPRINTS_GRAPH_INTRINSIC
#undef CHECK_FINGERPRINTS_OTHER
#define CHECK_FACTORY_FINGERPRINTS(symbol, class_name, factory_name, cid, fp) \
func = GetFunction(all_libs, #class_name, #factory_name); \
#define CHECK_FACTORY_FINGERPRINTS(symbol, library, class_name, factory_name, \
cid, fp) \
lib = Library::library(); \
func = GetFunction(lib, #class_name, #factory_name); \
if (func.IsNull()) { \
fingerprints_match = false; \
OS::PrintErr("Function not found %s.%s\n", #class_name, #factory_name); \
OS::PrintErr("Function not found %s.%s.%s\n", #library, #class_name, \
#factory_name); \
} else { \
fingerprints_match = \
func.CheckSourceFingerprint(fp) && fingerprints_match; \
}
all_libs.Clear();
all_libs.Add(&Library::ZoneHandle(Library::CoreLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
RECOGNIZED_LIST_FACTORY_LIST(CHECK_FACTORY_FINGERPRINTS);
#undef CHECK_FACTORY_FINGERPRINTS
+2 -2
View File
@@ -5382,8 +5382,8 @@ class Library : public Object {
// helper methods and classes. Allow look up of private classes.
static ClassPtr LookupCoreClass(const String& class_name);
// Return Function::null() if function does not exist in libs.
static FunctionPtr GetFunction(const GrowableArray<Library*>& libs,
// Return Function::null() if function does not exist in lib.
static FunctionPtr GetFunction(const Library& lib,
const char* class_name,
const char* function_name);
@@ -0,0 +1,9 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:developer';
main() {
log("An uninteresting message");
}