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
18namespace dart {
19
20DEFINE_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
30DEFINE_NATIVE_ENTRY(Object_equals, 0, 1) {
31 // Implemented in the flow graph builder.
32 UNREACHABLE();
33 return Object::null();
34}
35
36DEFINE_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
49DEFINE_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
62DEFINE_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
75DEFINE_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
88DEFINE_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
138DEFINE_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
163DEFINE_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
177DEFINE_NATIVE_ENTRY(AbstractType_toString, 0, 1) {
178 const AbstractType& type =
179 AbstractType::CheckedHandle(zone, arguments->NativeArgAt(0));
180 return type.UserVisibleName();
181}
182
183DEFINE_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
191DEFINE_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
201DEFINE_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
207DEFINE_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
214DEFINE_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
222DEFINE_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
244DEFINE_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
252DEFINE_NATIVE_ENTRY(Internal_unsafeCast, 0, 1) {
253 UNREACHABLE(); // Should be erased at Kernel translation time.
254 return arguments->NativeArgAt(0);
255}
256
257DEFINE_NATIVE_ENTRY(Internal_reachabilityFence, 0, 1) {
258 return Object::null();
259}
260
261DEFINE_NATIVE_ENTRY(Internal_collectAllGarbage, 0, 0) {
262 isolate->heap()->CollectAllGarbage();
263 return Object::null();
264}
265
266static bool ExtractInterfaceTypeArgs(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
309DEFINE_NATIVE_ENTRY(Internal_extractTypeArguments, 0, 2) {
310 const Instance& instance =
311 Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
312 const Instance& extract =
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& extracted_type_args = 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
395DEFINE_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
410DEFINE_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
467DEFINE_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
490DEFINE_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