1 | // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/bootstrap_natives.h" |
6 | |
7 | #include "lib/invocation_mirror.h" |
8 | #include "vm/code_patcher.h" |
9 | #include "vm/exceptions.h" |
10 | #include "vm/heap/heap.h" |
11 | #include "vm/native_entry.h" |
12 | #include "vm/object.h" |
13 | #include "vm/object_store.h" |
14 | #include "vm/resolver.h" |
15 | #include "vm/stack_frame.h" |
16 | #include "vm/symbols.h" |
17 | |
18 | namespace dart { |
19 | |
20 | DEFINE_NATIVE_ENTRY(DartAsync_fatal, 0, 1) { |
21 | // The dart:async library code entered an unrecoverable state. |
22 | const Instance& instance = |
23 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
24 | const char* msg = instance.ToCString(); |
25 | OS::PrintErr("Fatal error in dart:async: %s\n" , msg); |
26 | FATAL(msg); |
27 | return Object::null(); |
28 | } |
29 | |
30 | DEFINE_NATIVE_ENTRY(Object_equals, 0, 1) { |
31 | // Implemented in the flow graph builder. |
32 | UNREACHABLE(); |
33 | return Object::null(); |
34 | } |
35 | |
36 | DEFINE_NATIVE_ENTRY(Object_getHash, 0, 1) { |
37 | // Please note that no handle is created for the argument. |
38 | // This is safe since the argument is only used in a tail call. |
39 | // The performance benefit is more than 5% when using hashCode. |
40 | #if defined(HASH_IN_OBJECT_HEADER) |
41 | return Smi::New(Object::GetCachedHash(arguments->NativeArgAt(0))); |
42 | #else |
43 | Heap* heap = isolate->heap(); |
44 | ASSERT(arguments->NativeArgAt(0)->IsDartInstance()); |
45 | return Smi::New(heap->GetHash(arguments->NativeArgAt(0))); |
46 | #endif |
47 | } |
48 | |
49 | DEFINE_NATIVE_ENTRY(Object_setHash, 0, 2) { |
50 | GET_NON_NULL_NATIVE_ARGUMENT(Smi, hash, arguments->NativeArgAt(1)); |
51 | #if defined(HASH_IN_OBJECT_HEADER) |
52 | Object::SetCachedHash(arguments->NativeArgAt(0), hash.Value()); |
53 | #else |
54 | const Instance& instance = |
55 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
56 | Heap* heap = isolate->heap(); |
57 | heap->SetHash(instance.raw(), hash.Value()); |
58 | #endif |
59 | return Object::null(); |
60 | } |
61 | |
62 | DEFINE_NATIVE_ENTRY(Object_toString, 0, 1) { |
63 | const Instance& instance = |
64 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
65 | if (instance.IsString()) { |
66 | return instance.raw(); |
67 | } |
68 | if (instance.IsAbstractType()) { |
69 | return AbstractType::Cast(instance).UserVisibleName(); |
70 | } |
71 | const char* c_str = instance.ToCString(); |
72 | return String::New(c_str); |
73 | } |
74 | |
75 | DEFINE_NATIVE_ENTRY(Object_runtimeType, 0, 1) { |
76 | const Instance& instance = |
77 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
78 | if (instance.IsString()) { |
79 | return Type::StringType(); |
80 | } else if (instance.IsInteger()) { |
81 | return Type::IntType(); |
82 | } else if (instance.IsDouble()) { |
83 | return Type::Double(); |
84 | } |
85 | return instance.GetType(Heap::kNew); |
86 | } |
87 | |
88 | DEFINE_NATIVE_ENTRY(Object_haveSameRuntimeType, 0, 2) { |
89 | const Instance& left = |
90 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
91 | const Instance& right = |
92 | Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); |
93 | |
94 | const intptr_t left_cid = left.GetClassId(); |
95 | const intptr_t right_cid = right.GetClassId(); |
96 | |
97 | if (left_cid != right_cid) { |
98 | if (IsIntegerClassId(left_cid)) { |
99 | return Bool::Get(IsIntegerClassId(right_cid)).raw(); |
100 | } else if (IsStringClassId(right_cid)) { |
101 | return Bool::Get(IsStringClassId(right_cid)).raw(); |
102 | } else { |
103 | return Bool::False().raw(); |
104 | } |
105 | } |
106 | |
107 | const Class& cls = Class::Handle(left.clazz()); |
108 | if (cls.IsClosureClass()) { |
109 | // TODO(vegorov): provide faster implementation for closure classes. |
110 | const AbstractType& left_type = |
111 | AbstractType::Handle(left.GetType(Heap::kNew)); |
112 | const AbstractType& right_type = |
113 | AbstractType::Handle(right.GetType(Heap::kNew)); |
114 | return Bool::Get( |
115 | left_type.IsEquivalent(right_type, TypeEquality::kSyntactical)) |
116 | .raw(); |
117 | } |
118 | |
119 | if (!cls.IsGeneric()) { |
120 | return Bool::True().raw(); |
121 | } |
122 | |
123 | if (left.GetTypeArguments() == right.GetTypeArguments()) { |
124 | return Bool::True().raw(); |
125 | } |
126 | const TypeArguments& left_type_arguments = |
127 | TypeArguments::Handle(left.GetTypeArguments()); |
128 | const TypeArguments& right_type_arguments = |
129 | TypeArguments::Handle(right.GetTypeArguments()); |
130 | const intptr_t num_type_args = cls.NumTypeArguments(); |
131 | const intptr_t num_type_params = cls.NumTypeParameters(); |
132 | return Bool::Get(left_type_arguments.IsSubvectorEquivalent( |
133 | right_type_arguments, num_type_args - num_type_params, |
134 | num_type_params, TypeEquality::kSyntactical)) |
135 | .raw(); |
136 | } |
137 | |
138 | DEFINE_NATIVE_ENTRY(Object_instanceOf, 0, 4) { |
139 | const Instance& instance = |
140 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
141 | const TypeArguments& instantiator_type_arguments = |
142 | TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1)); |
143 | const TypeArguments& function_type_arguments = |
144 | TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(2)); |
145 | const AbstractType& type = |
146 | AbstractType::CheckedHandle(zone, arguments->NativeArgAt(3)); |
147 | ASSERT(type.IsFinalized()); |
148 | const bool is_instance_of = instance.IsInstanceOf( |
149 | type, instantiator_type_arguments, function_type_arguments); |
150 | if (FLAG_trace_type_checks) { |
151 | const char* result_str = is_instance_of ? "true" : "false" ; |
152 | OS::PrintErr("Native Object.instanceOf: result %s\n" , result_str); |
153 | const AbstractType& instance_type = |
154 | AbstractType::Handle(zone, instance.GetType(Heap::kNew)); |
155 | OS::PrintErr(" instance type: %s\n" , |
156 | String::Handle(zone, instance_type.Name()).ToCString()); |
157 | OS::PrintErr(" test type: %s\n" , |
158 | String::Handle(zone, type.Name()).ToCString()); |
159 | } |
160 | return Bool::Get(is_instance_of).raw(); |
161 | } |
162 | |
163 | DEFINE_NATIVE_ENTRY(Object_simpleInstanceOf, 0, 2) { |
164 | // This native is only called when the right hand side passes |
165 | // SimpleInstanceOfType and it is a non-negative test. |
166 | const Instance& instance = |
167 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
168 | const AbstractType& type = |
169 | AbstractType::CheckedHandle(zone, arguments->NativeArgAt(1)); |
170 | ASSERT(type.IsFinalized()); |
171 | ASSERT(type.IsInstantiated()); |
172 | const bool is_instance_of = instance.IsInstanceOf( |
173 | type, Object::null_type_arguments(), Object::null_type_arguments()); |
174 | return Bool::Get(is_instance_of).raw(); |
175 | } |
176 | |
177 | DEFINE_NATIVE_ENTRY(AbstractType_toString, 0, 1) { |
178 | const AbstractType& type = |
179 | AbstractType::CheckedHandle(zone, arguments->NativeArgAt(0)); |
180 | return type.UserVisibleName(); |
181 | } |
182 | |
183 | DEFINE_NATIVE_ENTRY(Type_getHashCode, 0, 1) { |
184 | const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0)); |
185 | intptr_t hash_val = type.Hash(); |
186 | ASSERT(hash_val > 0); |
187 | ASSERT(Smi::IsValid(hash_val)); |
188 | return Smi::New(hash_val); |
189 | } |
190 | |
191 | DEFINE_NATIVE_ENTRY(Type_equality, 0, 2) { |
192 | const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0)); |
193 | const Instance& other = |
194 | Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); |
195 | if (type.raw() == other.raw()) { |
196 | return Bool::True().raw(); |
197 | } |
198 | return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).raw(); |
199 | } |
200 | |
201 | DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) { |
202 | const LibraryPrefix& prefix = |
203 | LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0)); |
204 | return Bool::Get(prefix.is_loaded()).raw(); |
205 | } |
206 | |
207 | DEFINE_NATIVE_ENTRY(LibraryPrefix_setLoaded, 0, 1) { |
208 | const LibraryPrefix& prefix = |
209 | LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0)); |
210 | prefix.set_is_loaded(true); |
211 | return Instance::null(); |
212 | } |
213 | |
214 | DEFINE_NATIVE_ENTRY(LibraryPrefix_loadingUnit, 0, 1) { |
215 | const LibraryPrefix& prefix = |
216 | LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0)); |
217 | const Library& target = Library::Handle(zone, prefix.GetLibrary(0)); |
218 | const LoadingUnit& unit = LoadingUnit::Handle(zone, target.loading_unit()); |
219 | return Smi::New(unit.IsNull() ? LoadingUnit::kIllegalId : unit.id()); |
220 | } |
221 | |
222 | DEFINE_NATIVE_ENTRY(LibraryPrefix_issueLoad, 0, 1) { |
223 | const Smi& id = Smi::CheckedHandle(zone, arguments->NativeArgAt(0)); |
224 | Array& units = Array::Handle(zone, isolate->object_store()->loading_units()); |
225 | if (units.IsNull()) { |
226 | // Not actually split. |
227 | const Library& lib = Library::Handle(zone, Library::CoreLibrary()); |
228 | const String& sel = String::Handle(zone, String::New("_completeLoads" )); |
229 | const Function& func = |
230 | Function::Handle(zone, lib.LookupFunctionAllowPrivate(sel)); |
231 | ASSERT(!func.IsNull()); |
232 | const Array& args = Array::Handle(zone, Array::New(3)); |
233 | args.SetAt(0, id); |
234 | args.SetAt(1, String::Handle(zone)); |
235 | args.SetAt(2, Bool::Get(false)); |
236 | return DartEntry::InvokeFunction(func, args); |
237 | } |
238 | ASSERT(id.Value() != LoadingUnit::kIllegalId); |
239 | LoadingUnit& unit = LoadingUnit::Handle(zone); |
240 | unit ^= units.At(id.Value()); |
241 | return unit.IssueLoad(); |
242 | } |
243 | |
244 | DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) { |
245 | #if defined(ARCH_IS_64_BIT) |
246 | return Bool::True().raw(); |
247 | #else |
248 | return Bool::False().raw(); |
249 | #endif // defined(ARCH_IS_64_BIT) |
250 | } |
251 | |
252 | DEFINE_NATIVE_ENTRY(Internal_unsafeCast, 0, 1) { |
253 | UNREACHABLE(); // Should be erased at Kernel translation time. |
254 | return arguments->NativeArgAt(0); |
255 | } |
256 | |
257 | DEFINE_NATIVE_ENTRY(Internal_reachabilityFence, 0, 1) { |
258 | return Object::null(); |
259 | } |
260 | |
261 | DEFINE_NATIVE_ENTRY(Internal_collectAllGarbage, 0, 0) { |
262 | isolate->heap()->CollectAllGarbage(); |
263 | return Object::null(); |
264 | } |
265 | |
266 | static bool (Zone* zone, |
267 | const Class& instance_cls, |
268 | const TypeArguments& instance_type_args, |
269 | const Class& interface_cls, |
270 | TypeArguments* interface_type_args) { |
271 | Class& cur_cls = Class::Handle(zone, instance_cls.raw()); |
272 | // The following code is a specialization of Class::IsSubtypeOf(). |
273 | Array& interfaces = Array::Handle(zone); |
274 | AbstractType& interface = AbstractType::Handle(zone); |
275 | Class& cur_interface_cls = Class::Handle(zone); |
276 | TypeArguments& cur_interface_type_args = TypeArguments::Handle(zone); |
277 | while (true) { |
278 | // Additional subtyping rules related to 'FutureOr' are not applied. |
279 | if (cur_cls.raw() == interface_cls.raw()) { |
280 | *interface_type_args = instance_type_args.raw(); |
281 | return true; |
282 | } |
283 | interfaces = cur_cls.interfaces(); |
284 | for (intptr_t i = 0; i < interfaces.Length(); i++) { |
285 | interface ^= interfaces.At(i); |
286 | ASSERT(interface.IsFinalized()); |
287 | cur_interface_cls = interface.type_class(); |
288 | cur_interface_type_args = interface.arguments(); |
289 | if (!cur_interface_type_args.IsNull() && |
290 | !cur_interface_type_args.IsInstantiated()) { |
291 | cur_interface_type_args = cur_interface_type_args.InstantiateFrom( |
292 | instance_type_args, Object::null_type_arguments(), kNoneFree, |
293 | Heap::kNew); |
294 | } |
295 | if (ExtractInterfaceTypeArgs(zone, cur_interface_cls, |
296 | cur_interface_type_args, interface_cls, |
297 | interface_type_args)) { |
298 | return true; |
299 | } |
300 | } |
301 | cur_cls = cur_cls.SuperClass(); |
302 | if (cur_cls.IsNull()) { |
303 | return false; |
304 | } |
305 | } |
306 | } |
307 | |
308 | // for documentation see pkg/dart_internal/lib/extract_type_arguments.dart |
309 | DEFINE_NATIVE_ENTRY(Internal_extractTypeArguments, 0, 2) { |
310 | const Instance& instance = |
311 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
312 | const Instance& = |
313 | Instance::CheckedHandle(zone, arguments->NativeArgAt(1)); |
314 | |
315 | Class& interface_cls = Class::Handle(zone); |
316 | intptr_t num_type_args = 0; |
317 | if (arguments->NativeTypeArgCount() >= 1) { |
318 | const AbstractType& function_type_arg = |
319 | AbstractType::Handle(zone, arguments->NativeTypeArgAt(0)); |
320 | if (function_type_arg.IsType() && |
321 | (function_type_arg.arguments() == TypeArguments::null())) { |
322 | interface_cls = function_type_arg.type_class(); |
323 | num_type_args = interface_cls.NumTypeParameters(); |
324 | } |
325 | } |
326 | if (num_type_args == 0) { |
327 | Exceptions::ThrowArgumentError(String::Handle( |
328 | zone, |
329 | String::New( |
330 | "single function type argument must specify a generic class" ))); |
331 | } |
332 | if (instance.IsNull()) { |
333 | Exceptions::ThrowArgumentError(instance); |
334 | } |
335 | // Function 'extract' must be generic and accept the same number of type args, |
336 | // unless we execute Dart 1.0 code. |
337 | if (extract.IsNull() || !extract.IsClosure() || |
338 | ((num_type_args > 0) && // Dart 1.0 if num_type_args == 0. |
339 | (Function::Handle(zone, Closure::Cast(extract).function()) |
340 | .NumTypeParameters() != num_type_args))) { |
341 | Exceptions::ThrowArgumentError(String::Handle( |
342 | zone, |
343 | String::New("argument 'extract' is not a generic function or not one " |
344 | "accepting the correct number of type arguments" ))); |
345 | } |
346 | TypeArguments& = TypeArguments::Handle(zone); |
347 | if (num_type_args > 0) { |
348 | // The passed instance must implement interface_cls. |
349 | TypeArguments& interface_type_args = TypeArguments::Handle(zone); |
350 | interface_type_args = TypeArguments::New(num_type_args); |
351 | Class& instance_cls = Class::Handle(zone, instance.clazz()); |
352 | TypeArguments& instance_type_args = TypeArguments::Handle(zone); |
353 | if (instance_cls.NumTypeArguments() > 0) { |
354 | instance_type_args = instance.GetTypeArguments(); |
355 | } |
356 | if (!ExtractInterfaceTypeArgs(zone, instance_cls, instance_type_args, |
357 | interface_cls, &interface_type_args)) { |
358 | Exceptions::ThrowArgumentError(String::Handle( |
359 | zone, String::New("type of argument 'instance' is not a subtype of " |
360 | "the function type argument" ))); |
361 | } |
362 | if (!interface_type_args.IsNull()) { |
363 | extracted_type_args = TypeArguments::New(num_type_args); |
364 | const intptr_t offset = interface_cls.NumTypeArguments() - num_type_args; |
365 | AbstractType& type_arg = AbstractType::Handle(zone); |
366 | for (intptr_t i = 0; i < num_type_args; i++) { |
367 | type_arg = interface_type_args.TypeAt(offset + i); |
368 | extracted_type_args.SetTypeAt(i, type_arg); |
369 | } |
370 | extracted_type_args = extracted_type_args.Canonicalize(); // Can be null. |
371 | } |
372 | } |
373 | // Call the closure 'extract'. |
374 | Array& args_desc = Array::Handle(zone); |
375 | Array& args = Array::Handle(zone); |
376 | if (extracted_type_args.IsNull()) { |
377 | args_desc = ArgumentsDescriptor::NewBoxed(0, 1); |
378 | args = Array::New(1); |
379 | args.SetAt(0, extract); |
380 | } else { |
381 | args_desc = ArgumentsDescriptor::NewBoxed(num_type_args, 1); |
382 | args = Array::New(2); |
383 | args.SetAt(0, extracted_type_args); |
384 | args.SetAt(1, extract); |
385 | } |
386 | const Object& result = |
387 | Object::Handle(zone, DartEntry::InvokeClosure(args, args_desc)); |
388 | if (result.IsError()) { |
389 | Exceptions::PropagateError(Error::Cast(result)); |
390 | UNREACHABLE(); |
391 | } |
392 | return result.raw(); |
393 | } |
394 | |
395 | DEFINE_NATIVE_ENTRY(Internal_prependTypeArguments, 0, 4) { |
396 | const TypeArguments& function_type_arguments = |
397 | TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)); |
398 | const TypeArguments& parent_type_arguments = |
399 | TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1)); |
400 | GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_parent_len, arguments->NativeArgAt(2)); |
401 | GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_len, arguments->NativeArgAt(3)); |
402 | return function_type_arguments.Prepend( |
403 | zone, parent_type_arguments, smi_parent_len.Value(), smi_len.Value()); |
404 | } |
405 | |
406 | // Check that a set of type arguments satisfy the type parameter bounds on a |
407 | // closure. |
408 | // Arg0: Closure object |
409 | // Arg1: Type arguments to function |
410 | DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) { |
411 | const Closure& closure = |
412 | Closure::CheckedHandle(zone, arguments->NativeArgAt(0)); |
413 | const Function& target = Function::Handle(zone, closure.function()); |
414 | const TypeArguments& bounds = |
415 | TypeArguments::Handle(zone, target.type_parameters()); |
416 | |
417 | // Either the bounds are all-dynamic or the function is not generic. |
418 | if (bounds.IsNull()) return Object::null(); |
419 | |
420 | const TypeArguments& type_args_to_check = |
421 | TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1)); |
422 | |
423 | // This should be guaranteed by the front-end. |
424 | ASSERT(type_args_to_check.IsNull() || |
425 | bounds.Length() <= type_args_to_check.Length()); |
426 | |
427 | // The bounds on the closure may need instantiation. |
428 | const TypeArguments& instantiator_type_args = |
429 | TypeArguments::Handle(zone, closure.instantiator_type_arguments()); |
430 | const TypeArguments& function_type_args = |
431 | TypeArguments::Handle(zone, closure.function_type_arguments()); |
432 | |
433 | AbstractType& supertype = AbstractType::Handle(zone); |
434 | AbstractType& subtype = AbstractType::Handle(zone); |
435 | TypeParameter& parameter = TypeParameter::Handle(zone); |
436 | for (intptr_t i = 0; i < bounds.Length(); ++i) { |
437 | parameter ^= bounds.TypeAt(i); |
438 | supertype = parameter.bound(); |
439 | subtype = type_args_to_check.IsNull() ? Object::dynamic_type().raw() |
440 | : type_args_to_check.TypeAt(i); |
441 | |
442 | ASSERT(!subtype.IsNull()); |
443 | ASSERT(!supertype.IsNull()); |
444 | |
445 | // The supertype may not be instantiated. |
446 | if (!AbstractType::InstantiateAndTestSubtype( |
447 | &subtype, &supertype, instantiator_type_args, function_type_args)) { |
448 | // Throw a dynamic type error. |
449 | TokenPosition location; |
450 | { |
451 | DartFrameIterator iterator(Thread::Current(), |
452 | StackFrameIterator::kNoCrossThreadIteration); |
453 | StackFrame* caller_frame = iterator.NextFrame(); |
454 | ASSERT(caller_frame != NULL); |
455 | location = caller_frame->GetTokenPos(); |
456 | } |
457 | String& parameter_name = String::Handle(zone, parameter.Name()); |
458 | Exceptions::CreateAndThrowTypeError(location, subtype, supertype, |
459 | parameter_name); |
460 | UNREACHABLE(); |
461 | } |
462 | } |
463 | |
464 | return Object::null(); |
465 | } |
466 | |
467 | DEFINE_NATIVE_ENTRY(InvocationMirror_unpackTypeArguments, 0, 2) { |
468 | const TypeArguments& type_arguments = |
469 | TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)); |
470 | const Smi& num_type_arguments = |
471 | Smi::CheckedHandle(zone, arguments->NativeArgAt(1)); |
472 | bool all_dynamic = type_arguments.IsNull(); |
473 | const intptr_t len = |
474 | all_dynamic ? num_type_arguments.Value() : type_arguments.Length(); |
475 | const Array& type_list = Array::Handle( |
476 | zone, Array::New(len, Type::Handle(zone, Type::DartTypeType()))); |
477 | AbstractType& type = AbstractType::Handle(zone); |
478 | for (intptr_t i = 0; i < len; i++) { |
479 | if (all_dynamic) { |
480 | type_list.SetAt(i, Object::dynamic_type()); |
481 | } else { |
482 | type = type_arguments.TypeAt(i); |
483 | type_list.SetAt(i, type); |
484 | } |
485 | } |
486 | type_list.MakeImmutable(); |
487 | return type_list.raw(); |
488 | } |
489 | |
490 | DEFINE_NATIVE_ENTRY(NoSuchMethodError_existingMethodSignature, 0, 3) { |
491 | const Instance& receiver = |
492 | Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
493 | GET_NON_NULL_NATIVE_ARGUMENT(String, method_name, arguments->NativeArgAt(1)); |
494 | GET_NON_NULL_NATIVE_ARGUMENT(Smi, invocation_type, arguments->NativeArgAt(2)); |
495 | InvocationMirror::Level level; |
496 | InvocationMirror::Kind kind; |
497 | InvocationMirror::DecodeType(invocation_type.Value(), &level, &kind); |
498 | |
499 | Function& function = Function::Handle(); |
500 | if (receiver.IsType()) { |
501 | Class& cls = Class::Handle(Type::Cast(receiver).type_class()); |
502 | if (level == InvocationMirror::kConstructor) { |
503 | function = cls.LookupConstructor(method_name); |
504 | if (function.IsNull()) { |
505 | function = cls.LookupFactory(method_name); |
506 | } |
507 | } else { |
508 | function = cls.LookupStaticFunction(method_name); |
509 | } |
510 | } else if (receiver.IsClosure()) { |
511 | function = Closure::Cast(receiver).function(); |
512 | } else { |
513 | Class& cls = Class::Handle(receiver.clazz()); |
514 | if (level == InvocationMirror::kSuper) { |
515 | cls = cls.SuperClass(); |
516 | } |
517 | function = Resolver::ResolveDynamicAnyArgs(zone, cls, method_name, |
518 | /*allow_add=*/false); |
519 | } |
520 | if (!function.IsNull()) { |
521 | return function.UserVisibleSignature(); |
522 | } |
523 | return String::null(); |
524 | } |
525 | |
526 | } // namespace dart |
527 | |