Chromium Code Reviews| Index: runtime/lib/mirrors.cc |
| diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc |
| index bafb2ea95300c64a00bdd97ba885710a302e289a..0ef12b107d6335a99e4c21280c45d73a54272275 100644 |
| --- a/runtime/lib/mirrors.cc |
| +++ b/runtime/lib/mirrors.cc |
| @@ -8,6 +8,7 @@ |
| #include "vm/dart_entry.h" |
| #include "vm/exceptions.h" |
| #include "vm/object_store.h" |
| +#include "vm/parser.h" |
| #include "vm/port.h" |
| #include "vm/symbols.h" |
| @@ -28,6 +29,74 @@ static RawInstance* CreateMirror(const String& mirror_class_name, |
| } |
| +// Note a "raw type" is not the same as a RawType. |
| +static RawAbstractType* RawTypeOfClass(const Class& cls) { |
| + Type& type = Type::Handle(Type::New(cls, |
| + Object::null_abstract_type_arguments(), |
| + Scanner::kDummyTokenIndex)); |
| + return ClassFinalizer::FinalizeType(cls, type, ClassFinalizer::kCanonicalize); |
| +} |
| + |
| + |
| +static void ThrowMirroredCompilationError(const String& message) { |
| + Array& args = Array::Handle(Array::New(1)); |
| + args.SetAt(0, message); |
| + |
| + Exceptions::ThrowByType(Exceptions::kMirroredCompilationError, args); |
| + UNREACHABLE(); |
| +} |
| + |
| + |
| +static void ThrowInvokeError(const Error& error) { |
| + if (error.IsLanguageError()) { |
| + // A compilation error that was delayed by lazy compilation. |
| + const LanguageError& compilation_error = LanguageError::Cast(error); |
| + String& message = String::Handle(compilation_error.message()); |
| + ThrowMirroredCompilationError(message); |
| + UNREACHABLE(); |
| + } |
| + Exceptions::PropagateError(error); |
| + UNREACHABLE(); |
| +} |
| + |
| + |
| +// Conventions: |
| +// * For throwing a NSM in a class klass we use its runtime type as receiver, |
| +// i.e., RawTypeOfClass(klass). |
| +// * For throwing a NSM in a library, we just pass the null instance as |
| +// receiver. |
| +static void ThrowNoSuchMethod(const Instance& receiver, |
| + const String& function_name, |
| + const Function& function, |
| + const InvocationMirror::Call call, |
| + const InvocationMirror::Type type) { |
| + const Smi& invocation_type = Smi::Handle(Smi::New( |
| + InvocationMirror::EncodeType(call, type))); |
| + |
| + const Array& args = Array::Handle(Array::New(6)); |
| + args.SetAt(0, receiver); |
| + args.SetAt(1, function_name); |
| + args.SetAt(2, invocation_type); |
| + // Parameter 3 (actual arguments): We omit this parameter to get the same |
| + // error message as one would get by invoking the function non-reflectively. |
| + // Parameter 4 (named arguments): We omit this parameters since we cannot |
| + // invoke functions with named parameters reflectively (using mirrors). |
| + if (!function.IsNull()) { |
| + const int total_num_parameters = function.NumParameters(); |
| + const Array& array = Array::Handle(Array::New(total_num_parameters)); |
| + String& param_name = String::Handle(); |
| + for (int i = 0; i < total_num_parameters; i++) { |
| + param_name = function.ParameterNameAt(i); |
| + array.SetAt(i, param_name); |
| + } |
| + args.SetAt(5, array); |
| + } |
| + |
| + Exceptions::ThrowByType(Exceptions::kNoSuchMethod, args); |
| + UNREACHABLE(); |
| +} |
| + |
| + |
| DEFINE_NATIVE_ENTRY(Mirrors_isLocalPort, 1) { |
| GET_NON_NULL_NATIVE_ARGUMENT(Instance, port, arguments->NativeArgAt(0)); |
| @@ -56,21 +125,51 @@ static RawInstance* CreateParameterMirrorList(const Function& func, |
| const intptr_t index_of_first_named_param = |
| non_implicit_param_count - func.NumOptionalNamedParameters(); |
| const Array& results = Array::Handle(Array::New(non_implicit_param_count)); |
| - const Array& args = Array::Handle(Array::New(6)); |
| + const Array& args = Array::Handle(Array::New(8)); |
| + |
| + // Return for synthetic functions and getters. |
| + if (func.IsGetterFunction() || |
| + func.IsImplicitConstructor() || |
| + func.IsImplicitGetterFunction() || |
| + func.IsImplicitSetterFunction()) { |
| + return results.raw(); |
| + } |
| + |
| args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func))); |
| args.SetAt(2, owner_mirror); |
| + |
| Smi& pos = Smi::Handle(); |
| String& name = String::Handle(); |
| Instance& param = Instance::Handle(); |
| + Bool& is_final = Bool::Handle(); |
| + Object& default_value = Object::Handle(); |
| + |
| + // Reparse the function for the following information: |
| + // * The default value of a parameter. |
| + // * Whether a parameters has been deflared as final. |
| + const Object& result = Object::Handle(Parser::ParseFunctionParameters(func)); |
| + if (result.IsError()) { |
| + ThrowInvokeError(Error::Cast(result)); |
| + UNREACHABLE(); |
| + } |
| + |
| + const Array& param_descriptor = Array::Cast(result); |
| + ASSERT(param_descriptor.Length() == (2 * non_implicit_param_count)); |
| for (intptr_t i = 0; i < non_implicit_param_count; i++) { |
| pos ^= Smi::New(i); |
| name ^= func.ParameterNameAt(implicit_param_count + i); |
| + is_final ^= param_descriptor.At(i * 2); |
| + default_value = param_descriptor.At(i * 2 + 1); |
| + ASSERT(default_value.IsNull() || default_value.IsInstance()); |
| + |
| args.SetAt(1, name); |
|
siva
2013/08/27 00:31:02
document here as to why arg 2 is not set.
|
| args.SetAt(3, pos); |
| args.SetAt(4, (i >= index_of_first_optional_param) ? |
| Bool::True() : Bool::False()); |
| args.SetAt(5, (i >= index_of_first_named_param) ? |
| Bool::True() : Bool::False()); |
| + args.SetAt(6, is_final); |
| + args.SetAt(7, default_value); |
| param ^= CreateMirror(Symbols::_LocalParameterMirrorImpl(), args); |
| results.SetAt(i, param); |
| } |
| @@ -211,15 +310,6 @@ static RawInstance* CreateClassMirror(const Class& cls, |
| } |
| -// Note a "raw type" is not the same as a RawType. |
| -static RawAbstractType* RawTypeOfClass(const Class& cls) { |
| - Type& type = Type::Handle(Type::New(cls, |
| - Object::null_abstract_type_arguments(), |
| - Scanner::kDummyTokenIndex)); |
| - return ClassFinalizer::FinalizeType(cls, type, ClassFinalizer::kCanonicalize); |
| -} |
| - |
| - |
| static RawInstance* CreateLibraryMirror(const Library& lib) { |
| const Array& args = Array::Handle(Array::New(3)); |
| args.SetAt(0, MirrorReference::Handle(MirrorReference::New(lib))); |
| @@ -332,28 +422,6 @@ DEFINE_NATIVE_ENTRY(Mirrors_makeLocalTypeMirror, 1) { |
| } |
| -static void ThrowMirroredCompilationError(const String& message) { |
| - Array& args = Array::Handle(Array::New(1)); |
| - args.SetAt(0, message); |
| - |
| - Exceptions::ThrowByType(Exceptions::kMirroredCompilationError, args); |
| - UNREACHABLE(); |
| -} |
| - |
| - |
| -static void ThrowInvokeError(const Error& error) { |
| - if (error.IsLanguageError()) { |
| - // A compilation error that was delayed by lazy compilation. |
| - const LanguageError& compilation_error = LanguageError::Cast(error); |
| - String& message = String::Handle(compilation_error.message()); |
| - ThrowMirroredCompilationError(message); |
| - UNREACHABLE(); |
| - } |
| - Exceptions::PropagateError(error); |
| - UNREACHABLE(); |
| -} |
| - |
| - |
| DEFINE_NATIVE_ENTRY(MirrorReference_equals, 2) { |
| GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, a, arguments->NativeArgAt(0)); |
| GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, b, arguments->NativeArgAt(1)); |
| @@ -849,64 +917,6 @@ DEFINE_NATIVE_ENTRY(ClosureMirror_function, 1) { |
| } |
| -static void ThrowNoSuchMethod(const Instance& receiver, |
| - const String& function_name, |
| - const Function& function, |
| - const InvocationMirror::Call call, |
| - const InvocationMirror::Type type) { |
| - const Smi& invocation_type = Smi::Handle(Smi::New( |
| - InvocationMirror::EncodeType(call, type))); |
| - |
| - const Array& args = Array::Handle(Array::New(6)); |
| - args.SetAt(0, receiver); |
| - args.SetAt(1, function_name); |
| - args.SetAt(2, invocation_type); |
| - if (!function.IsNull()) { |
| - const int total_num_parameters = function.NumParameters(); |
| - const Array& array = Array::Handle(Array::New(total_num_parameters)); |
| - String& param_name = String::Handle(); |
| - for (int i = 0; i < total_num_parameters; i++) { |
| - param_name = function.ParameterNameAt(i); |
| - array.SetAt(i, param_name); |
| - } |
| - args.SetAt(5, array); |
| - } |
| - |
| - Exceptions::ThrowByType(Exceptions::kNoSuchMethod, args); |
| - UNREACHABLE(); |
| -} |
| - |
| - |
| -static void ThrowNoSuchMethod(const Class& klass, |
| - const String& function_name, |
| - const Function& function, |
| - const InvocationMirror::Call call, |
| - const InvocationMirror::Type type) { |
| - AbstractType& runtime_type = AbstractType::Handle(RawTypeOfClass(klass)); |
| - |
| - ThrowNoSuchMethod(runtime_type, |
| - function_name, |
| - function, |
| - call, |
| - type); |
| - UNREACHABLE(); |
| -} |
| - |
| - |
| -static void ThrowNoSuchMethod(const Library& library, |
| - const String& function_name, |
| - const Function& function, |
| - const InvocationMirror::Call call, |
| - const InvocationMirror::Type type) { |
| - ThrowNoSuchMethod(Instance::null_instance(), |
| - function_name, |
| - function, |
| - call, |
| - type); |
| - UNREACHABLE(); |
| -} |
| - |
| - |
| DEFINE_NATIVE_ENTRY(ClassMirror_invoke, 4) { |
| // Argument 0 is the mirror, which is unused by the native. It exists |
| // because this native is an instance method in order to be polymorphic |
| @@ -928,7 +938,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invoke, 4) { |
| /* named_args */ 0, |
| NULL) || |
| !function.is_visible()) { |
| - ThrowNoSuchMethod(klass, |
| + ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)), |
| function_name, |
| function, |
| InvocationMirror::kStatic, |
| @@ -963,7 +973,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeGetter, 3) { |
| klass.LookupStaticFunctionAllowPrivate(internal_getter_name)); |
| if (getter.IsNull() || !getter.is_visible()) { |
| - ThrowNoSuchMethod(klass, |
| + ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)), |
| getter_name, |
| getter, |
| InvocationMirror::kStatic, |
| @@ -1002,7 +1012,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeSetter, 4) { |
| klass.LookupStaticFunctionAllowPrivate(internal_setter_name)); |
| if (setter.IsNull() || !setter.is_visible()) { |
| - ThrowNoSuchMethod(klass, |
| + ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)), |
| setter_name, |
| setter, |
| InvocationMirror::kStatic, |
| @@ -1073,7 +1083,7 @@ DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 3) { |
| // Pretend we didn't find the constructor at all when the arity is wrong |
| // so as to produce the same NoSuchMethodError as the non-reflective case. |
| constructor = Function::null(); |
| - ThrowNoSuchMethod(klass, |
| + ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)), |
| internal_constructor_name, |
| constructor, |
| InvocationMirror::kConstructor, |
| @@ -1122,7 +1132,7 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_invoke, 4) { |
| 0, |
| NULL) || |
| !function.is_visible()) { |
| - ThrowNoSuchMethod(library, |
| + ThrowNoSuchMethod(Instance::null_instance(), |
| function_name, |
| function, |
| InvocationMirror::kTopLevel, |
| @@ -1183,7 +1193,7 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_invokeGetter, 3) { |
| return field.value(); |
| } |
| if (ambiguity_error_msg.IsNull()) { |
| - ThrowNoSuchMethod(library, |
| + ThrowNoSuchMethod(Instance::null_instance(), |
| getter_name, |
| getter, |
| InvocationMirror::kTopLevel, |
| @@ -1220,7 +1230,7 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_invokeSetter, 4) { |
| &ambiguity_error_msg)); |
| if (setter.IsNull() || !setter.is_visible()) { |
| if (ambiguity_error_msg.IsNull()) { |
| - ThrowNoSuchMethod(library, |
| + ThrowNoSuchMethod(Instance::null_instance(), |
| setter_name, |
| setter, |
| InvocationMirror::kTopLevel, |