[ VM / Dart API ] Added additional methods required for Flutter background execution.
Change-Id: Id620ece49124da50bf50af3c1a390fb1f6186691
Reviewed-on: https://dart-review.googlesource.com/61118
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 d7734c1..4d54a54 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1509,6 +1509,14 @@
DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance);
/**
+ * Returns the name for the provided class type.
+ *
+ * \return A valid string handle if no error occurs during the
+ * operation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type);
+
+/**
* Returns the name for the provided function or method.
*
* \return A valid string handle if no error occurs during the
@@ -1553,6 +1561,15 @@
*/
DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
+/**
+ * Returns a handle to the library which contains class.
+ *
+ * \return A valid handle to the library with owns class, null if the class
+ * has no library or an error handle if the argument is not a valid handle
+ * to a class type.
+ */
+DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type);
+
/*
* =============================
* Numbers, Integers and Doubles
@@ -1686,6 +1703,20 @@
DART_EXPORT Dart_Handle Dart_GetClosure(Dart_Handle library,
Dart_Handle function_name);
+/**
+ * Returns a closure of static function 'function_name' in the class 'class_name'
+ * in the exported namespace of specified 'library'.
+ *
+ * \param library Library object
+ * \param cls_type Type object representing a Class
+ * \param function_name Name of the static function in the class
+ *
+ * \return A valid Dart instance if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
+ Dart_Handle cls_type,
+ Dart_Handle function_name);
+
/*
* ========
* Booleans
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index ebee057..761e198 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2066,6 +2066,20 @@
return Api::NewHandle(T, func.UserVisibleName());
}
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type) {
+ DARTSCOPE(Thread::Current());
+ const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
+ if (type_obj.IsNull()) {
+ RETURN_TYPE_ERROR(Z, cls_type, Type);
+ }
+ const Class& klass = Class::Handle(Z, type_obj.type_class());
+ if (klass.IsNull()) {
+ return Api::NewError(
+ "cls_type must be a Type object which represents a Class.");
+ }
+ return Api::NewHandle(T, klass.UserVisibleName());
+}
+
DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
DARTSCOPE(Thread::Current());
const Function& func = Api::UnwrapFunctionHandle(Z, function);
@@ -2120,6 +2134,21 @@
return Api::NewHandle(T, rf);
}
+DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type) {
+ DARTSCOPE(Thread::Current());
+ const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
+ const Class& klass = Class::Handle(Z, type_obj.type_class());
+ if (klass.IsNull()) {
+ return Api::NewError(
+ "cls_type must be a Type object which represents a Class.");
+ }
+ const Library& library = Library::Handle(klass.library());
+ if (library.IsNull()) {
+ return Dart_Null();
+ }
+ return Api::NewHandle(Thread::Current(), library.raw());
+}
+
// --- Numbers, Integers and Doubles ----
DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
@@ -2300,6 +2329,53 @@
return Api::NewHandle(T, lib.GetFunctionClosure(name));
}
+DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
+ Dart_Handle cls_type,
+ Dart_Handle function_name) {
+ DARTSCOPE(Thread::Current());
+ const Library& lib = Api::UnwrapLibraryHandle(Z, library);
+ if (lib.IsNull()) {
+ RETURN_TYPE_ERROR(Z, library, Library);
+ }
+
+ const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
+ if (type_obj.IsNull()) {
+ RETURN_TYPE_ERROR(Z, cls_type, Type);
+ }
+
+ const Class& klass = Class::Handle(Z, type_obj.type_class());
+ if (klass.IsNull()) {
+ return Api::NewError(
+ "cls_type must be a Type object which represents a Class");
+ }
+
+ const String& func_name = Api::UnwrapStringHandle(Z, function_name);
+ if (func_name.IsNull()) {
+ RETURN_TYPE_ERROR(Z, function_name, String);
+ }
+
+ Function& func =
+ Function::Handle(Z, klass.LookupStaticFunctionAllowPrivate(func_name));
+ if (func.IsNull()) {
+ return Dart_Null();
+ }
+
+ if (!func.is_static()) {
+ return Api::NewError("function_name must refer to a static method.");
+ }
+
+ if (func.kind() != RawFunction::kRegularFunction) {
+ return Api::NewError(
+ "function_name must be the name of a regular function.");
+ }
+ func ^= func.ImplicitClosureFunction();
+ if (func.IsNull()) {
+ return Dart_Null();
+ }
+
+ return Api::NewHandle(T, func.ImplicitStaticClosure());
+}
+
// --- Booleans ----
DART_EXPORT Dart_Handle Dart_True() {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index b88dd39..8b7fe6b 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -898,6 +898,77 @@
EXPECT(strstr(result, "getInt"));
}
+TEST_CASE(DartAPI_GetStaticMethodClosure) {
+ const char* kScriptChars =
+ "class Foo {\n"
+ " static int getInt() {\n"
+ " return 1;\n"
+ " }\n"
+ " double getDouble() {\n"
+ " return 1.0;\n"
+ " }\n"
+ "}\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 foo_cls = Dart_GetClass(lib, NewString("Foo"));
+ EXPECT_VALID(foo_cls);
+
+ Dart_Handle closure =
+ Dart_GetStaticMethodClosure(lib, foo_cls, 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_SUBSTRING("getInt", result);
+
+ 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_SUBSTRING("getInt", result);
+
+ Dart_Handle cls = Dart_FunctionOwner(function);
+ EXPECT_VALID(cls);
+ EXPECT(Dart_IsInstance(cls));
+ Dart_Handle cls_str = Dart_ClassName(cls);
+ Dart_StringToCString(cls_str, &result);
+ EXPECT_SUBSTRING("Foo", result);
+
+ EXPECT_ERROR(Dart_ClassName(Dart_Null()),
+ "Dart_ClassName expects argument 'cls_type' to be non-null.");
+ EXPECT_ERROR(
+ Dart_GetStaticMethodClosure(Dart_Null(), foo_cls, NewString("getInt")),
+ "Dart_GetStaticMethodClosure expects argument 'library' to be non-null.");
+ EXPECT_ERROR(
+ Dart_GetStaticMethodClosure(lib, Dart_Null(), NewString("getInt")),
+ "Dart_GetStaticMethodClosure expects argument 'cls_type' to be "
+ "non-null.");
+ EXPECT_ERROR(Dart_GetStaticMethodClosure(lib, foo_cls, Dart_Null()),
+ "Dart_GetStaticMethodClosure expects argument 'function_name' "
+ "to be non-null.");
+}
+
+TEST_CASE(DartAPI_ClassLibrary) {
+ Dart_Handle lib = Dart_LookupLibrary(NewString("dart:core"));
+ EXPECT_VALID(lib);
+ Dart_Handle type = Dart_GetType(lib, NewString("int"), 0, NULL);
+ EXPECT_VALID(type);
+ Dart_Handle result = Dart_ClassLibrary(type);
+ EXPECT_VALID(result);
+ Dart_Handle lib_url = Dart_LibraryUrl(result);
+ const char* str = NULL;
+ Dart_StringToCString(lib_url, &str);
+ EXPECT_STREQ("dart:core", str);
+
+ // Case with no library.
+ type = Dart_GetType(lib, NewString("dynamic"), 0, NULL);
+ EXPECT_VALID(type);
+ EXPECT(Dart_IsNull(Dart_ClassLibrary(type)));
+}
+
TEST_CASE(DartAPI_BooleanValues) {
Dart_Handle str = NewString("test");
EXPECT(!Dart_IsBoolean(str));