[ VM ] Add back some mirrors related APIs to lookup functions/closures by name.
Change-Id: I6e1c67b987d98c8a3ca61c317ca21d2d8c94da9c
Reviewed-on: https://dart-review.googlesource.com/59301
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 8fc3f17..d7734c1 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1508,6 +1508,51 @@
*/
DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance);
+/**
+ * Returns the name for the provided function or method.
+ *
+ * \return A valid string handle if no error occurs during the
+ * operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function);
+
+/**
+ * Returns a handle to the owner of a function.
+ *
+ * The owner of an instance method or a static method is its defining
+ * class. The owner of a top-level function is its defining
+ * library. The owner of the function of a non-implicit closure is the
+ * function of the method or closure that defines the non-implicit
+ * closure.
+ *
+ * \return A valid handle to the owner of the function, or an error
+ * handle if the argument is not a valid handle to a function.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function);
+
+/**
+ * Determines whether a function handle referes to a static function
+ * of method.
+ *
+ * For the purposes of the embedding API, a top-level function is
+ * implicitly declared static.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is declared static.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
+ bool* is_static);
+
+/**
+ * Retrieves the function of a closure.
+ *
+ * \return A handle to the function of the closure, or an error handle if the
+ * argument is not a closure.
+ */
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
+
/*
* =============================
* Numbers, Integers and Doubles
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index b51735f..3109abd 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2057,6 +2057,69 @@
return Api::NewHandle(T, type.Canonicalize());
}
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) {
+ DARTSCOPE(Thread::Current());
+ const Function& func = Api::UnwrapFunctionHandle(Z, function);
+ if (func.IsNull()) {
+ RETURN_TYPE_ERROR(Z, function, Function);
+ }
+ return Api::NewHandle(T, func.UserVisibleName());
+}
+
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
+ DARTSCOPE(Thread::Current());
+ const Function& func = Api::UnwrapFunctionHandle(Z, function);
+ if (func.IsNull()) {
+ RETURN_TYPE_ERROR(Z, function, Function);
+ }
+ if (func.IsNonImplicitClosureFunction()) {
+ RawFunction* parent_function = func.parent_function();
+ return Api::NewHandle(T, parent_function);
+ }
+ const Class& owner = Class::Handle(Z, func.Owner());
+ ASSERT(!owner.IsNull());
+ if (owner.IsTopLevel()) {
+// Top-level functions are implemented as members of a hidden class. We hide
+// that class here and instead answer the library.
+#if defined(DEBUG)
+ const Library& lib = Library::Handle(Z, owner.library());
+ if (lib.IsNull()) {
+ ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
+ }
+#endif
+ return Api::NewHandle(T, owner.library());
+ } else {
+ return Api::NewHandle(T, owner.RareType());
+ }
+}
+
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
+ bool* is_static) {
+ DARTSCOPE(Thread::Current());
+ if (is_static == NULL) {
+ RETURN_NULL_ERROR(is_static);
+ }
+ const Function& func = Api::UnwrapFunctionHandle(Z, function);
+ if (func.IsNull()) {
+ RETURN_TYPE_ERROR(Z, function, Function);
+ }
+ *is_static = func.is_static();
+ return Api::Success();
+}
+
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure) {
+ DARTSCOPE(Thread::Current());
+ const Instance& closure_obj = Api::UnwrapInstanceHandle(Z, closure);
+ if (closure_obj.IsNull() || !closure_obj.IsClosure()) {
+ RETURN_TYPE_ERROR(Z, closure, Instance);
+ }
+
+ ASSERT(ClassFinalizer::AllClassesFinalized());
+
+ RawFunction* rf = Closure::Cast(closure_obj).function();
+ return Api::NewHandle(T, rf);
+}
+
// --- Numbers, Integers and Doubles ----
DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 7569556..ee787e4 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -788,6 +788,116 @@
"type Instance.");
}
+TEST_CASE(DartAPI_FunctionName) {
+ const char* kScriptChars = "int getInt() { return 1; }\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(lib);
+
+ Dart_Handle closure = Dart_GetClosure(lib, NewString("getInt"));
+ EXPECT_VALID(closure);
+ if (Dart_IsClosure(closure)) {
+ closure = Dart_ClosureFunction(closure);
+ EXPECT_VALID(closure);
+ }
+
+ Dart_Handle name = Dart_FunctionName(closure);
+ EXPECT_VALID(name);
+ const char* result_str = "";
+ Dart_StringToCString(name, &result_str);
+ EXPECT_STREQ(result_str, "getInt");
+}
+
+TEST_CASE(DartAPI_FunctionOwner) {
+ const char* kScriptChars = "int getInt() { return 1; }\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(lib);
+
+ Dart_Handle closure = Dart_GetClosure(lib, NewString("getInt"));
+ EXPECT_VALID(closure);
+ if (Dart_IsClosure(closure)) {
+ closure = Dart_ClosureFunction(closure);
+ EXPECT_VALID(closure);
+ }
+
+ const char* url = "";
+ Dart_Handle owner = Dart_FunctionOwner(closure);
+ EXPECT_VALID(owner);
+ Dart_Handle owner_url = Dart_LibraryUrl(owner);
+ EXPECT_VALID(owner_url);
+ Dart_StringToCString(owner_url, &url);
+
+ const char* lib_url = "";
+ Dart_Handle library_url = Dart_LibraryUrl(lib);
+ EXPECT_VALID(library_url);
+ Dart_StringToCString(library_url, &lib_url);
+
+ EXPECT_STREQ(url, lib_url);
+}
+
+TEST_CASE(DartAPI_FunctionIsStatic) {
+ const char* kScriptChars =
+ "int getInt() { return 1; }\n"
+ "class Foo { String getString() => 'foobar'; }\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(lib);
+
+ Dart_Handle closure = Dart_GetClosure(lib, NewString("getInt"));
+ EXPECT_VALID(closure);
+ if (Dart_IsClosure(closure)) {
+ closure = Dart_ClosureFunction(closure);
+ EXPECT_VALID(closure);
+ }
+
+ bool is_static = false;
+ Dart_Handle result = Dart_FunctionIsStatic(closure, &is_static);
+ EXPECT_VALID(result);
+ EXPECT(is_static);
+
+ // TODO(bkonyi): uncomment when issue 33417 is resolved.
+ /*
+ Dart_Handle klass = Dart_GetType(lib, NewString("Foo"), 0, NULL);
+ EXPECT_VALID(klass);
+
+ Dart_Handle instance = Dart_Allocate(klass);
+
+ closure = Dart_GetField(instance, NewString("getString"));
+ EXPECT_VALID(closure);
+ if (Dart_IsClosure(closure)) {
+ closure = Dart_ClosureFunction(closure);
+ EXPECT_VALID(closure);
+ }
+
+ result = Dart_FunctionIsStatic(closure, &is_static);
+ EXPECT_VALID(result);
+ EXPECT(!is_static);
+*/
+}
+
+TEST_CASE(DartAPI_ClosureFunction) {
+ const char* kScriptChars = "int getInt() { return 1; }\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(lib);
+
+ Dart_Handle closure = Dart_GetClosure(lib, NewString("getInt"));
+ EXPECT_VALID(closure);
+ EXPECT(Dart_IsClosure(closure));
+ Dart_Handle closure_str = Dart_ToString(closure);
+ const char* result = "";
+ Dart_StringToCString(closure_str, &result);
+ EXPECT(strstr(result, "getInt") != NULL);
+
+ Dart_Handle function = Dart_ClosureFunction(closure);
+ EXPECT_VALID(function);
+ EXPECT(Dart_IsFunction(function));
+ Dart_Handle func_str = Dart_ToString(function);
+ Dart_StringToCString(func_str, &result);
+ EXPECT(strstr(result, "getInt"));
+}
+
TEST_CASE(DartAPI_BooleanValues) {
Dart_Handle str = NewString("test");
EXPECT(!Dart_IsBoolean(str));