Index: runtime/vm/mirrors_api_impl.cc |
=================================================================== |
--- runtime/vm/mirrors_api_impl.cc (revision 0) |
+++ runtime/vm/mirrors_api_impl.cc (revision 0) |
@@ -0,0 +1,869 @@ |
+// Copyright (c) 2013, 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. |
+ |
+#include "include/dart_mirrors_api.h" |
+ |
+#include "platform/assert.h" |
+#include "vm/class_finalizer.h" |
+#include "vm/dart.h" |
+#include "vm/dart_api_impl.h" |
+#include "vm/dart_api_state.h" |
+#include "vm/dart_entry.h" |
+#include "vm/exceptions.h" |
+#include "vm/growable_array.h" |
+#include "vm/object.h" |
+#include "vm/resolver.h" |
+#include "vm/stack_frame.h" |
+#include "vm/symbols.h" |
+ |
+namespace dart { |
+ |
+// When we want to return a handle to a type to the user, we handle |
+// class-types differently than some other types. |
+static Dart_Handle TypeToHandle(Isolate* isolate, |
+ const char* function_name, |
+ const AbstractType& type) { |
+ if (type.IsMalformed()) { |
+ const Error& error = Error::Handle(type.malformed_error()); |
+ return Api::NewError("%s: malformed type encountered: %s.", |
+ function_name, error.ToErrorCString()); |
+ } else if (type.HasResolvedTypeClass()) { |
+ const Class& cls = Class::Handle(isolate, type.type_class()); |
+#if defined(DEBUG) |
+ const Library& lib = Library::Handle(cls.library()); |
+ if (lib.IsNull()) { |
+ ASSERT(cls.IsDynamicClass() || cls.IsVoidClass()); |
+ } |
+#endif |
+ return Api::NewHandle(isolate, cls.raw()); |
+ } else if (type.IsTypeParameter()) { |
+ return Api::NewHandle(isolate, type.raw()); |
+ } else { |
+ return Api::NewError("%s: unexpected type '%s' encountered.", |
+ function_name, type.ToCString()); |
+ } |
+} |
+ |
+ |
+// --- Classes and Interfaces Reflection --- |
+ |
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ return Api::NewHandle(isolate, cls.UserVisibleName()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ |
+#if defined(DEBUG) |
+ const Library& lib = Library::Handle(cls.library()); |
+ if (lib.IsNull()) { |
+ // ASSERT(cls.IsDynamicClass() || cls.IsVoidClass()); |
+ if (!cls.IsDynamicClass() && !cls.IsVoidClass()) { |
+ fprintf(stderr, "NO LIBRARY: %s\n", cls.ToCString()); |
+ } |
+ } |
+#endif |
+ |
+ return Api::NewHandle(isolate, cls.library()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle clazz, |
+ intptr_t* count) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ |
+ const Array& interface_types = Array::Handle(isolate, cls.interfaces()); |
+ if (interface_types.IsNull()) { |
+ *count = 0; |
+ } else { |
+ *count = interface_types.Length(); |
+ } |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle clazz, |
+ intptr_t index) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ |
+ // Finalize all classes. |
+ Dart_Handle state = Api::CheckIsolateState(isolate); |
+ if (::Dart_IsError(state)) { |
+ return state; |
+ } |
+ |
+ const Array& interface_types = Array::Handle(isolate, cls.interfaces()); |
+ if (index < 0 || index >= interface_types.Length()) { |
+ return Api::NewError("%s: argument 'index' out of bounds.", CURRENT_FUNC); |
+ } |
+ Type& interface_type = Type::Handle(isolate); |
+ interface_type ^= interface_types.At(index); |
+ if (interface_type.HasResolvedTypeClass()) { |
+ return Api::NewHandle(isolate, interface_type.type_class()); |
+ } |
+ const String& type_name = |
+ String::Handle(isolate, interface_type.TypeClassName()); |
+ return Api::NewError("%s: internal error: found unresolved type class '%s'.", |
+ CURRENT_FUNC, type_name.ToCString()); |
+} |
+ |
+ |
+DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ // For now we represent typedefs as non-canonical signature classes. |
+ // I anticipate this may change if we make typedefs more general. |
+ return cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ |
+ if (!cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass()) { |
+ const String& cls_name = String::Handle(cls.UserVisibleName()); |
+ return Api::NewError("%s: class '%s' is not a typedef class. " |
+ "See Dart_ClassIsTypedef.", |
+ CURRENT_FUNC, cls_name.ToCString()); |
+ } |
+ |
+ const Function& func = Function::Handle(isolate, cls.signature_function()); |
+ return Api::NewHandle(isolate, func.signature_class()); |
+} |
+ |
+ |
+DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ // A class represents a function type when it is a canonical |
+ // signature class. |
+ return cls.IsCanonicalSignatureClass(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ if (!cls.IsCanonicalSignatureClass()) { |
+ const String& cls_name = String::Handle(cls.UserVisibleName()); |
+ return Api::NewError("%s: class '%s' is not a function-type class. " |
+ "See Dart_ClassIsFunctionType.", |
+ CURRENT_FUNC, cls_name.ToCString()); |
+ } |
+ return Api::NewHandle(isolate, cls.signature_function()); |
+} |
+ |
+ |
+// --- Function and Variable Reflection --- |
+ |
+// Outside of the vm, we expose setter names with a trailing '='. |
+static bool HasExternalSetterSuffix(const String& name) { |
+ return name.CharAt(name.Length() - 1) == '='; |
+} |
+ |
+ |
+static RawString* RemoveExternalSetterSuffix(const String& name) { |
+ ASSERT(HasExternalSetterSuffix(name)); |
+ return String::SubString(name, 0, name.Length() - 1); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target)); |
+ if (obj.IsError()) { |
+ return target; |
+ } |
+ |
+ const GrowableObjectArray& names = |
+ GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()); |
+ Function& func = Function::Handle(); |
+ String& name = String::Handle(); |
+ |
+ if (obj.IsClass()) { |
+ const Class& cls = Class::Cast(obj); |
+ const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate)); |
+ if (!error.IsNull()) { |
+ return Api::NewHandle(isolate, error.raw()); |
+ } |
+ const Array& func_array = Array::Handle(cls.functions()); |
+ |
+ // Some special types like 'dynamic' have a null functions list. |
+ if (!func_array.IsNull()) { |
+ for (intptr_t i = 0; i < func_array.Length(); ++i) { |
+ func ^= func_array.At(i); |
+ |
+ // Skip implicit getters and setters. |
+ if (func.kind() == RawFunction::kImplicitGetter || |
+ func.kind() == RawFunction::kImplicitSetter || |
+ func.kind() == RawFunction::kConstImplicitGetter || |
+ func.kind() == RawFunction::kMethodExtractor) { |
+ continue; |
+ } |
+ |
+ name = func.UserVisibleName(); |
+ names.Add(name); |
+ } |
+ } |
+ } else if (obj.IsLibrary()) { |
+ const Library& lib = Library::Cast(obj); |
+ DictionaryIterator it(lib); |
+ Object& obj = Object::Handle(); |
+ while (it.HasNext()) { |
+ obj = it.GetNext(); |
+ if (obj.IsFunction()) { |
+ func ^= obj.raw(); |
+ name = func.UserVisibleName(); |
+ names.Add(name); |
+ } |
+ } |
+ } else { |
+ return Api::NewError( |
+ "%s expects argument 'target' to be a class or library.", |
+ CURRENT_FUNC); |
+ } |
+ return Api::NewHandle(isolate, Array::MakeArray(names)); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target, |
+ Dart_Handle function_name) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target)); |
+ if (obj.IsError()) { |
+ return target; |
+ } |
+ const String& func_name = Api::UnwrapStringHandle(isolate, function_name); |
+ if (func_name.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function_name, String); |
+ } |
+ |
+ Function& func = Function::Handle(isolate); |
+ String& tmp_name = String::Handle(isolate); |
+ if (obj.IsClass()) { |
+ const Class& cls = Class::Cast(obj); |
+ |
+ // Case 1. Lookup the unmodified function name. |
+ func = cls.LookupFunctionAllowPrivate(func_name); |
+ |
+ // Case 2. Lookup the function without the external setter suffix |
+ // '='. Make sure to do this check after the regular lookup, so |
+ // that we don't interfere with operator lookups (like ==). |
+ if (func.IsNull() && HasExternalSetterSuffix(func_name)) { |
+ tmp_name = RemoveExternalSetterSuffix(func_name); |
+ tmp_name = Field::SetterName(tmp_name); |
+ func = cls.LookupFunctionAllowPrivate(tmp_name); |
+ } |
+ |
+ // Case 3. Lookup the funciton with the getter prefix prepended. |
+ if (func.IsNull()) { |
+ tmp_name = Field::GetterName(func_name); |
+ func = cls.LookupFunctionAllowPrivate(tmp_name); |
+ } |
+ |
+ // Case 4. Lookup the function with a . appended to find the |
+ // unnamed constructor. |
+ if (func.IsNull()) { |
+ tmp_name = String::Concat(func_name, Symbols::Dot()); |
+ func = cls.LookupFunctionAllowPrivate(tmp_name); |
+ } |
+ } else if (obj.IsLibrary()) { |
+ const Library& lib = Library::Cast(obj); |
+ |
+ // Case 1. Lookup the unmodified function name. |
+ func = lib.LookupFunctionAllowPrivate(func_name); |
+ |
+ // Case 2. Lookup the function without the external setter suffix |
+ // '='. Make sure to do this check after the regular lookup, so |
+ // that we don't interfere with operator lookups (like ==). |
+ if (func.IsNull() && HasExternalSetterSuffix(func_name)) { |
+ tmp_name = RemoveExternalSetterSuffix(func_name); |
+ tmp_name = Field::SetterName(tmp_name); |
+ func = lib.LookupFunctionAllowPrivate(tmp_name); |
+ } |
+ |
+ // Case 3. Lookup the function with the getter prefix prepended. |
+ if (func.IsNull()) { |
+ tmp_name = Field::GetterName(func_name); |
+ func = lib.LookupFunctionAllowPrivate(tmp_name); |
+ } |
+ } else { |
+ return Api::NewError( |
+ "%s expects argument 'target' to be a class or library.", |
+ CURRENT_FUNC); |
+ } |
+ |
+#if defined(DEBUG) |
+ if (!func.IsNull()) { |
+ // We only provide access to a subset of function kinds. |
+ RawFunction::Kind func_kind = func.kind(); |
+ ASSERT(func_kind == RawFunction::kRegularFunction || |
+ func_kind == RawFunction::kGetterFunction || |
+ func_kind == RawFunction::kSetterFunction || |
+ func_kind == RawFunction::kConstructor); |
+ } |
+#endif |
+ return Api::NewHandle(isolate, func.raw()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ return Api::NewHandle(isolate, func.UserVisibleName()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ if (func.IsNonImplicitClosureFunction()) { |
+ RawFunction* parent_function = func.parent_function(); |
+ return Api::NewHandle(isolate, parent_function); |
+ } |
+ const Class& owner = Class::Handle(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(owner.library()); |
+ if (lib.IsNull()) { |
+ ASSERT(owner.IsDynamicClass() || owner.IsVoidClass()); |
+ } |
+#endif |
+ return Api::NewHandle(isolate, owner.library()); |
+ } else { |
+ return Api::NewHandle(isolate, owner.raw()); |
+ } |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionIsAbstract(Dart_Handle function, |
+ bool* is_abstract) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_abstract == NULL) { |
+ RETURN_NULL_ERROR(is_abstract); |
+ } |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ *is_abstract = func.is_abstract(); |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function, |
+ bool* is_static) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_static == NULL) { |
+ RETURN_NULL_ERROR(is_static); |
+ } |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ *is_static = func.is_static(); |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function, |
+ bool* is_constructor) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_constructor == NULL) { |
+ RETURN_NULL_ERROR(is_constructor); |
+ } |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ *is_constructor = func.kind() == RawFunction::kConstructor; |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function, |
+ bool* is_getter) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_getter == NULL) { |
+ RETURN_NULL_ERROR(is_getter); |
+ } |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ *is_getter = func.IsGetterFunction(); |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function, |
+ bool* is_setter) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_setter == NULL) { |
+ RETURN_NULL_ERROR(is_setter); |
+ } |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ *is_setter = (func.kind() == RawFunction::kSetterFunction); |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionReturnType(Dart_Handle function) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ |
+ if (func.kind() == RawFunction::kConstructor) { |
+ // Special case the return type for constructors. Inside the vm |
+ // we mark them as returning dynamic, but for the purposes of |
+ // reflection, they return the type of the class being |
+ // constructed. |
+ return Api::NewHandle(isolate, func.Owner()); |
+ } else { |
+ const AbstractType& return_type = |
+ AbstractType::Handle(isolate, func.result_type()); |
+ return TypeToHandle(isolate, "Dart_FunctionReturnType", return_type); |
+ } |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionParameterCounts( |
+ Dart_Handle function, |
+ int64_t* fixed_param_count, |
+ int64_t* opt_param_count) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (fixed_param_count == NULL) { |
+ RETURN_NULL_ERROR(fixed_param_count); |
+ } |
+ if (opt_param_count == NULL) { |
+ RETURN_NULL_ERROR(opt_param_count); |
+ } |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ |
+ // We hide implicit parameters, such as a method's receiver. This is |
+ // consistent with Invoke or New, which don't expect their callers to |
+ // provide them in the argument lists they are handed. |
+ *fixed_param_count = func.num_fixed_parameters() - |
+ func.NumImplicitParameters(); |
+ // TODO(regis): Separately report named and positional optional param counts. |
+ *opt_param_count = func.NumOptionalParameters(); |
+ |
+ ASSERT(*fixed_param_count >= 0); |
+ ASSERT(*opt_param_count >= 0); |
+ |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_FunctionParameterType(Dart_Handle function, |
+ int parameter_index) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Function& func = Api::UnwrapFunctionHandle(isolate, function); |
+ if (func.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, function, Function); |
+ } |
+ |
+ const intptr_t num_implicit_params = func.NumImplicitParameters(); |
+ const intptr_t num_params = func.NumParameters() - num_implicit_params; |
+ if (parameter_index < 0 || parameter_index >= num_params) { |
+ return Api::NewError( |
+ "%s: argument 'parameter_index' out of range. " |
+ "Expected 0..%"Pd" but saw %d.", |
+ CURRENT_FUNC, num_params, parameter_index); |
+ } |
+ const AbstractType& param_type = |
+ AbstractType::Handle(isolate, func.ParameterTypeAt( |
+ num_implicit_params + parameter_index)); |
+ return TypeToHandle(isolate, "Dart_FunctionParameterType", param_type); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_GetVariableNames(Dart_Handle target) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target)); |
+ if (obj.IsError()) { |
+ return target; |
+ } |
+ |
+ const GrowableObjectArray& names = |
+ GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()); |
+ Field& field = Field::Handle(isolate); |
+ String& name = String::Handle(isolate); |
+ |
+ if (obj.IsClass()) { |
+ const Class& cls = Class::Cast(obj); |
+ const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate)); |
+ if (!error.IsNull()) { |
+ return Api::NewHandle(isolate, error.raw()); |
+ } |
+ const Array& field_array = Array::Handle(cls.fields()); |
+ |
+ // Some special types like 'dynamic' have a null fields list. |
+ // |
+ // TODO(turnidge): Fix 'dynamic' so that it does not have a null |
+ // fields list. This will have to wait until the empty array is |
+ // allocated in the vm isolate. |
+ if (!field_array.IsNull()) { |
+ for (intptr_t i = 0; i < field_array.Length(); ++i) { |
+ field ^= field_array.At(i); |
+ name = field.UserVisibleName(); |
+ names.Add(name); |
+ } |
+ } |
+ } else if (obj.IsLibrary()) { |
+ const Library& lib = Library::Cast(obj); |
+ DictionaryIterator it(lib); |
+ Object& obj = Object::Handle(isolate); |
+ while (it.HasNext()) { |
+ obj = it.GetNext(); |
+ if (obj.IsField()) { |
+ field ^= obj.raw(); |
+ name = field.UserVisibleName(); |
+ names.Add(name); |
+ } |
+ } |
+ } else { |
+ return Api::NewError( |
+ "%s expects argument 'target' to be a class or library.", |
+ CURRENT_FUNC); |
+ } |
+ return Api::NewHandle(isolate, Array::MakeArray(names)); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_LookupVariable(Dart_Handle target, |
+ Dart_Handle variable_name) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target)); |
+ if (obj.IsError()) { |
+ return target; |
+ } |
+ const String& var_name = Api::UnwrapStringHandle(isolate, variable_name); |
+ if (var_name.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, variable_name, String); |
+ } |
+ if (obj.IsClass()) { |
+ const Class& cls = Class::Cast(obj); |
+ return Api::NewHandle(isolate, cls.LookupField(var_name)); |
+ } |
+ if (obj.IsLibrary()) { |
+ const Library& lib = Library::Cast(obj); |
+ return Api::NewHandle(isolate, lib.LookupFieldAllowPrivate(var_name)); |
+ } |
+ return Api::NewError( |
+ "%s expects argument 'target' to be a class or library.", |
+ CURRENT_FUNC); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_VariableName(Dart_Handle variable) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Field& var = Api::UnwrapFieldHandle(isolate, variable); |
+ if (var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, variable, Field); |
+ } |
+ return Api::NewHandle(isolate, var.UserVisibleName()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_VariableIsStatic(Dart_Handle variable, |
+ bool* is_static) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_static == NULL) { |
+ RETURN_NULL_ERROR(is_static); |
+ } |
+ const Field& var = Api::UnwrapFieldHandle(isolate, variable); |
+ if (var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, variable, Field); |
+ } |
+ *is_static = var.is_static(); |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_VariableIsFinal(Dart_Handle variable, |
+ bool* is_final) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ if (is_final == NULL) { |
+ RETURN_NULL_ERROR(is_final); |
+ } |
+ const Field& var = Api::UnwrapFieldHandle(isolate, variable); |
+ if (var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, variable, Field); |
+ } |
+ *is_final = var.is_final(); |
+ return Api::Success(); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_VariableType(Dart_Handle variable) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Field& var = Api::UnwrapFieldHandle(isolate, variable); |
+ if (var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, variable, Field); |
+ } |
+ |
+ const AbstractType& type = AbstractType::Handle(isolate, var.type()); |
+ return TypeToHandle(isolate, "Dart_VariableType", type); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle clazz) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ |
+ const intptr_t num_type_params = cls.NumTypeParameters(); |
+ const TypeArguments& type_params = |
+ TypeArguments::Handle(cls.type_parameters()); |
+ |
+ const GrowableObjectArray& names = |
+ GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()); |
+ TypeParameter& type_param = TypeParameter::Handle(isolate); |
+ String& name = String::Handle(isolate); |
+ for (intptr_t i = 0; i < num_type_params; i++) { |
+ type_param ^= type_params.TypeAt(i); |
+ name = type_param.name(); |
+ names.Add(name); |
+ } |
+ return Api::NewHandle(isolate, Array::MakeArray(names)); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_LookupTypeVariable( |
+ Dart_Handle clazz, |
+ Dart_Handle type_variable_name) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
+ if (cls.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, clazz, Class); |
+ } |
+ const String& var_name = Api::UnwrapStringHandle(isolate, type_variable_name); |
+ if (var_name.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, type_variable_name, String); |
+ } |
+ |
+ const intptr_t num_type_params = cls.NumTypeParameters(); |
+ const TypeArguments& type_params = |
+ TypeArguments::Handle(cls.type_parameters()); |
+ |
+ TypeParameter& type_param = TypeParameter::Handle(isolate); |
+ String& name = String::Handle(isolate); |
+ for (intptr_t i = 0; i < num_type_params; i++) { |
+ type_param ^= type_params.TypeAt(i); |
+ name = type_param.name(); |
+ if (name.Equals(var_name)) { |
+ return Api::NewHandle(isolate, type_param.raw()); |
+ } |
+ } |
+ const String& cls_name = String::Handle(cls.UserVisibleName()); |
+ return Api::NewError( |
+ "%s: Could not find type variable named '%s' for class %s.\n", |
+ CURRENT_FUNC, var_name.ToCString(), cls_name.ToCString()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_TypeVariableName(Dart_Handle type_variable) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const TypeParameter& type_var = |
+ Api::UnwrapTypeParameterHandle(isolate, type_variable); |
+ if (type_var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter); |
+ } |
+ return Api::NewHandle(isolate, type_var.name()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_TypeVariableOwner(Dart_Handle type_variable) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const TypeParameter& type_var = |
+ Api::UnwrapTypeParameterHandle(isolate, type_variable); |
+ if (type_var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter); |
+ } |
+ const Class& owner = Class::Handle(type_var.parameterized_class()); |
+ ASSERT(!owner.IsNull() && owner.IsClass()); |
+ return Api::NewHandle(isolate, owner.raw()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_TypeVariableUpperBound(Dart_Handle type_variable) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const TypeParameter& type_var = |
+ Api::UnwrapTypeParameterHandle(isolate, type_variable); |
+ if (type_var.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter); |
+ } |
+ const AbstractType& bound = AbstractType::Handle(type_var.bound()); |
+ return TypeToHandle(isolate, "Dart_TypeVariableUpperBound", bound); |
+} |
+ |
+ |
+// --- Libraries Reflection --- |
+ |
+DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Library& lib = Api::UnwrapLibraryHandle(isolate, library); |
+ if (lib.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, library, Library); |
+ } |
+ const String& name = String::Handle(isolate, lib.name()); |
+ ASSERT(!name.IsNull()); |
+ return Api::NewHandle(isolate, name.raw()); |
+} |
+ |
+ |
+DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Library& lib = Api::UnwrapLibraryHandle(isolate, library); |
+ if (lib.IsNull()) { |
+ RETURN_TYPE_ERROR(isolate, library, Library); |
+ } |
+ |
+ const GrowableObjectArray& names = |
+ GrowableObjectArray::Handle(isolate, GrowableObjectArray::New()); |
+ ClassDictionaryIterator it(lib); |
+ Class& cls = Class::Handle(); |
+ String& name = String::Handle(); |
+ while (it.HasNext()) { |
+ cls = it.GetNextClass(); |
+ if (cls.IsSignatureClass()) { |
+ if (!cls.IsCanonicalSignatureClass()) { |
+ // This is a typedef. Add it to the list of class names. |
+ name = cls.UserVisibleName(); |
+ names.Add(name); |
+ } else { |
+ // Skip canonical signature classes. These are not named. |
+ } |
+ } else { |
+ name = cls.UserVisibleName(); |
+ names.Add(name); |
+ } |
+ } |
+ return Api::NewHandle(isolate, Array::MakeArray(names)); |
+} |
+ |
+ |
+// --- Closures Reflection --- |
+ |
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure) { |
+ Isolate* isolate = Isolate::Current(); |
+ DARTSCOPE(isolate); |
+ const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure); |
+ if (closure_obj.IsNull() || !closure_obj.IsClosure()) { |
+ RETURN_TYPE_ERROR(isolate, closure, Instance); |
+ } |
+ |
+ ASSERT(ClassFinalizer::AllClassesFinalized()); |
+ |
+ RawFunction* rf = Closure::function(closure_obj); |
+ return Api::NewHandle(isolate, rf); |
+} |
+ |
+ |
+// --- Metadata Reflection ---- |
+ |
+DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle object) { |
+ Isolate* isolate = Isolate::Current(); |
+ CHECK_ISOLATE(isolate); |
+ DARTSCOPE(isolate); |
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); |
+ Class& cls = Class::Handle(isolate); |
+ if (obj.IsClass()) { |
+ cls ^= obj.raw(); |
+ } else if (obj.IsFunction()) { |
+ cls = Function::Cast(obj).origin(); |
+ } else if (obj.IsField()) { |
+ cls = Field::Cast(obj).origin(); |
+ } else { |
+ return Api::NewHandle(isolate, Object::empty_array().raw()); |
+ } |
+ const Library& lib = Library::Handle(cls.library()); |
+ return Api::NewHandle(isolate, lib.GetMetadata(obj)); |
+} |
+ |
+} // namespace dart |