Index: runtime/lib/mirrors.cc |
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc |
index bafb2ea95300c64a00bdd97ba885710a302e289a..896d861479a04a38d568c26cd28a1078deaafa29 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,53 @@ 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)); |
- args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func))); |
- args.SetAt(2, owner_mirror); |
+ 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(); |
+ } |
+ |
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(); |
+ } |
+ |
+ args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func))); |
+ args.SetAt(2, owner_mirror); |
+ |
+ 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()); |
+ |
+ // Arguments 0 (referent) and 2 (owner) are the same for all parameters. See |
+ // above. |
args.SetAt(1, name); |
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 +312,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 +424,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 +919,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 +940,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 +975,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 +1014,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 +1085,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 +1134,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 +1195,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 +1232,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, |