e16291b973
R=regis@google.com Review URL: https://codereview.chromium.org//17582016 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@24491 260f80e4-7a28-3924-810f-c04153c831b5
905 lines
31 KiB
C++
905 lines
31 KiB
C++
// 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 object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (obj.IsType() || obj.IsClass()) {
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
return Api::NewHandle(isolate, cls.UserVisibleName());
|
|
} else {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
}
|
|
|
|
|
|
DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
|
|
#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 object,
|
|
intptr_t* count) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
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 object,
|
|
intptr_t index) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
|
|
// 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 object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
// 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 object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
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 object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
// A class represents a function type when it is a canonical
|
|
// signature class.
|
|
return cls.IsCanonicalSignatureClass();
|
|
}
|
|
|
|
|
|
DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
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.IsType() || obj.IsClass()) {
|
|
// For backwards compatibility we allow class objects to be passed in
|
|
// for now. This needs to be removed once all code that uses class
|
|
// objects to invoke Dart_Invoke is removed.
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : 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 ||
|
|
func.kind() == RawFunction::kNoSuchMethodDispatcher) {
|
|
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.IsType() || obj.IsClass()) {
|
|
// For backwards compatibility we allow class objects to be passed in
|
|
// for now. This needs to be removed once all code that uses class
|
|
// objects to invoke Dart_Invoke is removed.
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : 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.IsType() || obj.IsClass()) {
|
|
// For backwards compatibility we allow class objects to be passed in
|
|
// for now. This needs to be removed once all code that uses class
|
|
// objects to invoke Dart_Invoke is removed.
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : 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.IsType() || obj.IsClass()) {
|
|
// For backwards compatibility we allow class objects to be passed in
|
|
// for now. This needs to be removed once all code that uses class
|
|
// objects to invoke Dart_Invoke is removed.
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : 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 object) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
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 object,
|
|
Dart_Handle type_variable_name) {
|
|
Isolate* isolate = Isolate::Current();
|
|
DARTSCOPE(isolate);
|
|
const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
|
|
if (!obj.IsType() && !obj.IsClass()) {
|
|
RETURN_TYPE_ERROR(isolate, object, Class/Type);
|
|
}
|
|
const Class& cls = (obj.IsType()) ?
|
|
Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
|
|
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
|