Chromium Code Reviews| Index: runtime/lib/mirrors.cc |
| =================================================================== |
| --- runtime/lib/mirrors.cc (revision 24826) |
| +++ runtime/lib/mirrors.cc (working copy) |
| @@ -13,6 +13,7 @@ |
| #include "vm/message.h" |
| #include "vm/port.h" |
| #include "vm/resolver.h" |
| +#include "vm/symbols.h" |
| namespace dart { |
| @@ -1123,7 +1124,7 @@ |
| } |
| -static Dart_Handle CreateMirroredError(Dart_Handle error) { |
| +static Dart_Handle CreateHandledMirroredError(Dart_Handle error) { |
| ASSERT(Dart_IsError(error)); |
| if (Dart_IsUnhandledExceptionError(error)) { |
| Dart_Handle exc = Dart_ErrorGetException(error); |
| @@ -1271,7 +1272,7 @@ |
| if (Dart_IsError(result)) { |
| // Instead of propagating the error from an invoke directly, we |
| // provide reflective access to the error. |
| - Dart_PropagateError(CreateMirroredError(result)); |
| + Dart_PropagateError(CreateHandledMirroredError(result)); |
| } |
| Dart_Handle wrapped_result = CreateInstanceMirror(result); |
| @@ -1294,7 +1295,7 @@ |
| if (Dart_IsError(result)) { |
| // Instead of propagating the error from a GetField directly, we |
| // provide reflective access to the error. |
| - Dart_PropagateError(CreateMirroredError(result)); |
| + Dart_PropagateError(CreateHandledMirroredError(result)); |
| } |
| Dart_Handle wrapped_result = CreateInstanceMirror(result); |
| @@ -1328,7 +1329,7 @@ |
| if (Dart_IsError(result)) { |
| // Instead of propagating the error from a SetField directly, we |
| // provide reflective access to the error. |
| - Dart_PropagateError(CreateMirroredError(result)); |
| + Dart_PropagateError(CreateHandledMirroredError(result)); |
| } |
| Dart_Handle wrapped_result = CreateInstanceMirror(result); |
| @@ -1364,7 +1365,7 @@ |
| if (Dart_IsError(result)) { |
| // Instead of propagating the error from an apply directly, we |
| // provide reflective access to the error. |
| - Dart_PropagateError(CreateMirroredError(result)); |
| + Dart_PropagateError(CreateHandledMirroredError(result)); |
| } |
| Dart_Handle wrapped_result = CreateInstanceMirror(result); |
| @@ -1376,58 +1377,352 @@ |
| } |
| -void NATIVE_ENTRY_FUNCTION(LocalClassMirrorImpl_invokeConstructor)( |
| - Dart_NativeArguments args) { |
| - Dart_EnterScope(); |
| - Dart_Handle klass_mirror = Dart_GetNativeArgument(args, 0); |
| - Dart_Handle constructor_name = Dart_GetNativeArgument(args, 1); |
| - // The arguments are either simple values or instance mirrors. |
| - Dart_Handle positional_arguments = Dart_GetNativeArgument(args, 2); |
| - Dart_Handle async = Dart_GetNativeArgument(args, 3); |
| +void HandleMirrorsMessage(Isolate* isolate, |
| + Dart_Port reply_port, |
| + const Instance& message) { |
| + UNIMPLEMENTED(); |
| +} |
| - Dart_Handle klass = UnwrapMirror(klass_mirror); |
| - GrowableArray<Dart_Handle> invoke_args; |
| - Dart_Handle result; |
| - if (Dart_IdentityEquals(async, Dart_True())) { |
| - result = UnwrapArgList(positional_arguments, &invoke_args); |
| + |
| +// TODO(11742): This is transitional. |
| +static RawInstance* Reflect(const Instance& reflectee) { |
| + Isolate* isolate = Isolate::Current(); |
| + DARTSCOPE(isolate); |
| + return Instance::RawCast( |
| + Api::UnwrapHandle( |
| + CreateInstanceMirror( |
| + Api::NewHandle(isolate, reflectee.raw())))); |
| +} |
|
siva
2013/07/11 22:53:37
This seems kind of hacky, I realize it is a tempor
rmacnak
2013/07/11 23:59:23
The intention is that there will be no plain VM co
|
| + |
| + |
| +// This is based on the embedding API, but direct use of the cid outside of |
| +// object.h/.c is questionable. |
|
rmacnak
2013/07/09 21:04:54
Questionable
|
| +static bool IsApiError(const Object& object) { |
| + return object.GetClassId() == kApiErrorCid; |
| +} |
| +static bool IsCompilationError(const Object& object) { |
| + return object.GetClassId() == kLanguageErrorCid; |
| +} |
|
siva
2013/07/11 22:53:37
We already have a bunch of IsXXXClassId(index) met
rmacnak
2013/07/11 23:59:23
Now I see that CompilationError is an alias for La
|
| + |
| + |
| +static RawError* CreateMirroredError(const Error& error) { |
| + if (error.IsUnhandledException()) { |
| + const UnhandledException& unhandled_ex = UnhandledException::Cast(error); |
| + Instance& exc = Instance::Handle(unhandled_ex.exception()); |
| + Instance& stack = Instance::Handle(unhandled_ex.stacktrace()); |
| + |
| + Object& exc_string_or_error = |
| + Object::Handle(DartLibraryCalls::ToString(exc)); |
| + Instance& exc_string = Instance::Handle(); |
| + if (exc_string_or_error.IsError()) { |
| + exc_string ^= Instance::null(); |
| + } else { |
| + exc_string ^= exc_string_or_error.raw(); |
| + } |
| + |
| + Instance& mirror_on_exc = Instance::Handle(Reflect(exc)); |
| + |
| + Array& args = Array::Handle(Array::New(3)); |
| + args.SetAt(0, mirror_on_exc); |
| + args.SetAt(1, exc_string); |
| + args.SetAt(2, stack); |
| + |
| + Instance& mirrored_exc = Instance::CheckedHandle( |
| + DartLibraryCalls::ExceptionCreate( |
| + Library::Handle(Library::MirrorsLibrary()), |
| + String::Handle(String::New("MirroredUncaughtExceptionError")), |
|
siva
2013/07/11 22:53:37
You probably want to add MirroredUncaughtException
|
| + Symbols::Dot(), // The unnamed constructor. |
| + args)); |
| + |
| + return UnhandledException::New(mirrored_exc, stack); |
| + } else if (IsApiError(error) || |
| + IsCompilationError(error)) { |
| + String& message = String::Handle(); |
| + if (IsApiError(error)) { |
| + message ^= ApiError::Cast(error).message(); |
| + } else { |
| + message ^= LanguageError::Cast(error).message(); |
| + } |
|
siva
2013/07/11 22:53:37
Once you have all VM code there would be no ApiErr
|
| + |
| + Array& args = Array::Handle(Array::New(1)); |
| + args.SetAt(0, message); |
| + |
| + Instance& mirrored_exc = Instance::CheckedHandle( |
| + DartLibraryCalls::ExceptionCreate( |
| + Library::Handle(Library::MirrorsLibrary()), |
| + String::Handle(String::New("MirroredCompilationError")), |
|
siva
2013/07/11 22:53:37
Ditto comment about adding MirroredCompilationErro
|
| + Symbols::Dot(), // The unnamed constructor. |
| + args)); |
| + |
| + const Instance& stack = Instance::Handle(); |
|
siva
2013/07/11 22:53:37
shadowing local variables like this is not a good
rmacnak
2013/07/11 23:59:23
It's not shadowing. They are in "sibling" scopes.
|
| + return UnhandledException::New(mirrored_exc, stack); |
| } else { |
| - result = UnpackLocalArgList(positional_arguments, &invoke_args); |
| + UNREACHABLE(); |
| + return Error::null(); |
| } |
| - if (Dart_IsError(result)) { |
| - Dart_PropagateError(result); |
| +} |
| + |
| + |
| +static RawObject* ResolveConstructor(const char* current_func, |
|
rmacnak
2013/07/09 21:04:54
This is the same as the embedding API's version. I
|
| + const Class& cls, |
| + const String& class_name, |
| + const String& constr_name, |
| + int num_args) { |
| + // The constructor must be present in the interface. |
| + const Function& constructor = |
| + Function::Handle(cls.LookupFunctionAllowPrivate(constr_name)); |
| + if (constructor.IsNull() || |
| + (!constructor.IsConstructor() && !constructor.IsFactory())) { |
| + const String& lookup_class_name = String::Handle(cls.Name()); |
| + if (!class_name.Equals(lookup_class_name)) { |
| + // When the class name used to build the constructor name is |
| + // different than the name of the class in which we are doing |
| + // the lookup, it can be confusing to the user to figure out |
| + // what's going on. Be a little more explicit for these error |
| + // messages. |
| + const String& message = String::Handle( |
| + String::NewFormatted( |
| + "%s: could not find factory '%s' in class '%s'.", |
| + current_func, |
| + constr_name.ToCString(), |
| + lookup_class_name.ToCString())); |
| + return ApiError::New(message); |
| + } else { |
| + const String& message = String::Handle( |
| + String::NewFormatted("%s: could not find constructor '%s'.", |
| + current_func, constr_name.ToCString())); |
| + return ApiError::New(message); |
| + } |
| } |
| - result = Dart_New(klass, |
| - constructor_name, |
| - invoke_args.length(), |
| - invoke_args.data()); |
| - if (Dart_IsError(result)) { |
| - // Instead of propagating the error from an invoke directly, we |
| - // provide reflective access to the error. |
| - Dart_PropagateError(CreateMirroredError(result)); |
| + int extra_args = (constructor.IsConstructor() ? 2 : 1); |
| + String& error_message = String::Handle(); |
| + if (!constructor.AreValidArgumentCounts(num_args + extra_args, |
| + 0, |
| + &error_message)) { |
| + const String& message = String::Handle( |
| + String::NewFormatted("%s: wrong argument count for " |
| + "constructor '%s': %s.", |
| + current_func, |
| + constr_name.ToCString(), |
| + error_message.ToCString())); |
| + return ApiError::New(message); |
| } |
| + return constructor.raw(); |
| +} |
| - Dart_Handle wrapped_result = CreateInstanceMirror(result); |
| - if (Dart_IsError(wrapped_result)) { |
| - Dart_PropagateError(wrapped_result); |
| + |
| +DEFINE_NATIVE_ENTRY(ClassMirror_name, 1) { |
| + const MirrorReference& klass_ref = |
| + MirrorReference::CheckedHandle(arguments->NativeArgAt(0)); |
| + Class& klass = Class::Handle(); |
| + klass ^= klass_ref.referent(); |
| + return klass.Name(); |
| +} |
| + |
| + |
| +DEFINE_NATIVE_ENTRY(ClassMirror_invoke, 3) { |
| + const MirrorReference& klass_ref = |
| + MirrorReference::CheckedHandle(arguments->NativeArgAt(0)); |
| + Class& klass = Class::Handle(); |
| + klass ^= klass_ref.referent(); |
| + |
| + const String& function_name = |
| + String::CheckedHandle(arguments->NativeArgAt(1)); |
| + |
| + const Array& positional_args = |
| + Array::CheckedHandle(arguments->NativeArgAt(2)); |
| + intptr_t number_of_arguments = positional_args.Length(); |
| + |
| + |
|
siva
2013/07/11 22:53:37
extra blank line?
|
| + intptr_t num_receiver = 0; // 1 for instance methods |
| + const Array& args = |
| + Array::Handle(Array::New(number_of_arguments + num_receiver)); |
| + Object& arg = Object::Handle(); |
| + for (int i = 0; i < number_of_arguments; i++) { |
| + arg = positional_args.At(i); |
| + args.SetAt((i + num_receiver), arg); |
| } |
| - Dart_SetReturnValue(args, wrapped_result); |
| - Dart_ExitScope(); |
| + |
| + const Function& function = Function::Handle( |
| + Resolver::ResolveStatic(klass, |
| + function_name, |
| + number_of_arguments, |
| + Object::empty_array(), |
| + Resolver::kIsQualified)); |
| + if (function.IsNull()) { |
| + const String& klass_name = String::Handle(isolate, klass.Name()); |
| + const String& message = String::Handle( |
| + String::NewFormatted("%s: did not find %d-arg static method '%s.%s'.", |
| + "ClassMirror_invoke", |
| + number_of_arguments, |
| + klass_name.ToCString(), |
| + function_name.ToCString())); |
| + const ApiError& error = ApiError::Handle(ApiError::New(message)); |
| + |
| + Exceptions::PropagateError(error); |
|
siva
2013/07/11 22:53:37
Why are we creating an ApiError and propagating it
rmacnak
2013/07/11 23:59:23
Right. These ApiErrors (wrapped in MirroredCompila
|
| + UNREACHABLE(); |
| + } |
| + Object& result = Object::Handle(DartEntry::InvokeFunction(function, args)); |
| + if (result.IsError()) { |
| + Error& mirrored_error = |
| + Error::Handle(CreateMirroredError(Error::Cast(result))); |
| + Exceptions::PropagateError(mirrored_error); |
| + UNREACHABLE(); |
| + } |
| + return result.raw(); |
| } |
| -void HandleMirrorsMessage(Isolate* isolate, |
| - Dart_Port reply_port, |
| - const Instance& message) { |
| - UNIMPLEMENTED(); |
| +DEFINE_NATIVE_ENTRY(ClassMirror_invokeGetter, 2) { |
| + const MirrorReference& klass_ref = |
| + MirrorReference::CheckedHandle(arguments->NativeArgAt(0)); |
| + Class& klass = Class::Handle(); |
| + klass ^= klass_ref.referent(); |
| + |
| + const String& getter_name = |
| + String::CheckedHandle(arguments->NativeArgAt(1)); |
| + |
| + const Field& field = Field::Handle(klass.LookupStaticField(getter_name)); |
| + if (field.IsNull()) { |
| + const String& internal_getter_name = String::Handle( |
| + Field::GetterName(getter_name)); |
| + const Function& getter = Function::Handle( |
| + klass.LookupStaticFunctionAllowPrivate(internal_getter_name)); |
| + |
| + if (getter.IsNull()) { |
| + const String& message = String::Handle( |
| + String::NewFormatted("%s: did not find static getter '%s'.", |
| + "ClassMirror_invokeGetter", |
| + getter_name.ToCString())); |
| + const ApiError& error = ApiError::Handle(ApiError::New(message)); |
| + Exceptions::PropagateError(error); |
|
siva
2013/07/11 22:53:37
Ditto question about ApiError
|
| + UNREACHABLE(); |
| + } |
| + |
| + // Invoke the getter and return the result. |
| + Object& result = Object::Handle( |
| + DartEntry::InvokeFunction(getter, Object::empty_array())); |
| + if (result.IsError()) { |
| + Error& mirrored_error = |
| + Error::Handle(CreateMirroredError(Error::Cast(result))); |
| + Exceptions::PropagateError(mirrored_error); |
| + UNREACHABLE(); |
| + } |
| + return result.raw(); |
| + } |
| + return field.value(); |
| } |
| -DEFINE_NATIVE_ENTRY(ClassMirror_name, 1) { |
| +DEFINE_NATIVE_ENTRY(ClassMirror_invokeSetter, 3) { |
| const MirrorReference& klass_ref = |
| MirrorReference::CheckedHandle(arguments->NativeArgAt(0)); |
| Class& klass = Class::Handle(); |
| klass ^= klass_ref.referent(); |
| - return klass.Name(); |
| + |
| + const String& setter_name = |
| + String::CheckedHandle(arguments->NativeArgAt(1)); |
| + |
| + const Instance& value = Instance::CheckedHandle(arguments->NativeArgAt(2)); |
| + |
| + // Check for real fields and user-defined setters |
|
siva
2013/07/11 22:53:37
missing '.' at end of comment.
|
| + const Field& field = Field::Handle(klass.LookupStaticField(setter_name)); |
| + if (field.IsNull()) { |
| + const String& internal_setter_name = String::Handle( |
| + Field::SetterName(setter_name)); |
| + const Function& setter = Function::Handle( |
| + klass.LookupStaticFunctionAllowPrivate(internal_setter_name)); |
| + |
| + if (setter.IsNull()) { |
| + const String& message = String::Handle( |
| + String::NewFormatted("%s: did not find static setter '%s'.", |
| + "ClassMirror_invokeSetter", |
| + setter_name.ToCString())); |
| + const ApiError& error = ApiError::Handle(ApiError::New(message)); |
| + Exceptions::PropagateError(error); |
| + UNREACHABLE(); |
| + } |
| + |
| + // Invoke the getter and return the result. |
| + const int kNumArgs = 1; |
| + const Array& args = Array::Handle(isolate, Array::New(kNumArgs)); |
| + args.SetAt(0, value); |
| + |
| + Object& result = Object::Handle( |
| + DartEntry::InvokeFunction(setter, args)); |
| + if (result.IsError()) { |
| + Error& mirrored_error = |
| + Error::Handle(CreateMirroredError(Error::Cast(result))); |
| + Exceptions::PropagateError(mirrored_error); |
| + UNREACHABLE(); |
| + } |
| + return result.raw(); |
| + } |
| + |
| + if (field.is_final()) { |
| + const String& message = String::Handle( |
| + String::NewFormatted("%s: cannot set final field '%s'.", |
| + "ClassMirror_invokeSetter", |
| + setter_name.ToCString())); |
| + const ApiError& error = ApiError::Handle(ApiError::New(message)); |
| + Exceptions::PropagateError(error); |
| + UNREACHABLE(); |
| + } |
| + |
| + field.set_value(value); |
| + return value.raw(); |
| } |
| + |
| +DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 3) { |
| + const MirrorReference& klass_ref = |
| + MirrorReference::CheckedHandle(arguments->NativeArgAt(0)); |
| + Class& klass = Class::Handle(); |
| + klass ^= klass_ref.referent(); |
| + |
| + const String& constructor_name = |
| + String::CheckedHandle(arguments->NativeArgAt(1)); |
| + |
| + const Array& positional_args = |
| + Array::CheckedHandle(arguments->NativeArgAt(2)); |
| + |
| + intptr_t number_of_arguments = positional_args.Length(); |
| + |
| + // By convention, the static function implementing a named constructor 'C' |
| + // for class 'A' is labeled 'A.C', and the static function implementing the |
| + // unnamed constructor for class 'A' is labeled 'A.'. |
| + // This convention prevents users from explicitly calling constructors. |
| + String& klass_name = String::Handle(klass.Name()); |
| + String& internal_constructor_name = |
| + String::Handle(String::Concat(klass_name, Symbols::Dot())); |
| + internal_constructor_name = |
| + String::Concat(internal_constructor_name, constructor_name); |
| + |
| + Object& constructor = Object::Handle(); |
| + constructor = ResolveConstructor("ClassMirror_invokeConstructor", |
| + klass, |
| + klass_name, |
| + internal_constructor_name, |
| + number_of_arguments); |
| + if (constructor.IsError()) { |
| + Exceptions::PropagateError(Error::Cast(constructor)); |
| + UNREACHABLE(); |
| + } |
| + ASSERT(constructor.IsFunction()); |
| + |
| + Object& result = |
| + Object::Handle(DartEntry::InvokeConstructor(klass, |
| + Function::Cast(constructor), |
| + positional_args)); |
| + if (result.IsError()) { |
| + Error& mirrored_error = |
| + Error::Handle(CreateMirroredError(Error::Cast(result))); |
| + Exceptions::PropagateError(mirrored_error); |
| + UNREACHABLE(); |
| + } |
| + // Factories may return null. |
| + ASSERT(result.IsInstance() || result.IsNull()); |
| + return result.raw(); |
| +} |
| + |
| } // namespace dart |