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/dart_entry.h"
6
7#include "platform/safe_stack.h"
8#include "vm/class_finalizer.h"
9#include "vm/debugger.h"
10#include "vm/dispatch_table.h"
11#include "vm/heap/safepoint.h"
12#include "vm/interpreter.h"
13#include "vm/object_store.h"
14#include "vm/resolver.h"
15#include "vm/runtime_entry.h"
16#include "vm/simulator.h"
17#include "vm/stub_code.h"
18#include "vm/symbols.h"
19#include "vm/zone_text_buffer.h"
20
21#if !defined(DART_PRECOMPILED_RUNTIME)
22#include "vm/compiler/frontend/bytecode_reader.h"
23#include "vm/compiler/jit/compiler.h"
24#endif // !defined(DART_PRECOMPILED_RUNTIME)
25
26namespace dart {
27
28DECLARE_FLAG(bool, enable_interpreter);
29DECLARE_FLAG(bool, precompiled_mode);
30
31// A cache of VM heap allocated arguments descriptors.
32ArrayPtr ArgumentsDescriptor::cached_args_descriptors_[kCachedDescriptorCount];
33
34ObjectPtr DartEntry::InvokeFunction(const Function& function,
35 const Array& arguments) {
36 ASSERT(Thread::Current()->IsMutatorThread());
37 const int kTypeArgsLen = 0; // No support to pass type args to generic func.
38 const Array& arguments_descriptor = Array::Handle(
39 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, arguments.Length()));
40 return InvokeFunction(function, arguments, arguments_descriptor);
41}
42
43class ScopedIsolateStackLimits : public ValueObject {
44 public:
45 NO_SANITIZE_SAFE_STACK
46 explicit ScopedIsolateStackLimits(Thread* thread, uword current_sp)
47 : thread_(thread) {
48 ASSERT(thread != NULL);
49 // Save the Thread's current stack limit and adjust the stack limit.
50 ASSERT(thread->isolate() == Isolate::Current());
51 saved_stack_limit_ = thread->saved_stack_limit();
52#if defined(USING_SIMULATOR)
53 thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
54#else
55 thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
56 // TODO(regis): For now, the interpreter is using its own stack limit.
57#endif
58
59#if defined(USING_SAFE_STACK)
60 saved_safestack_limit_ = OSThread::GetCurrentSafestackPointer();
61 thread->set_saved_safestack_limit(saved_safestack_limit_);
62#endif
63 }
64
65 ~ScopedIsolateStackLimits() {
66 ASSERT(thread_->isolate() == Isolate::Current());
67 // Since we started with a stack limit of 0 we should be getting back
68 // to a stack limit of 0 when all nested invocations are done and
69 // we have bottomed out.
70 thread_->SetStackLimit(saved_stack_limit_);
71#if defined(USING_SAFE_STACK)
72 thread_->set_saved_safestack_limit(saved_safestack_limit_);
73#endif
74 }
75
76 private:
77 Thread* thread_;
78#if defined(USING_SAFE_STACK)
79 uword saved_safestack_limit_ = 0;
80#endif
81 uword saved_stack_limit_ = 0;
82};
83
84// Clears/restores Thread::long_jump_base on construction/destruction.
85// Ensures that we do not attempt to long jump across Dart frames.
86class SuspendLongJumpScope : public ThreadStackResource {
87 public:
88 explicit SuspendLongJumpScope(Thread* thread)
89 : ThreadStackResource(thread),
90 saved_long_jump_base_(thread->long_jump_base()) {
91 thread->set_long_jump_base(NULL);
92 }
93
94 ~SuspendLongJumpScope() {
95 ASSERT(thread()->long_jump_base() == NULL);
96 thread()->set_long_jump_base(saved_long_jump_base_);
97 }
98
99 private:
100 LongJumpScope* saved_long_jump_base_;
101};
102
103ObjectPtr DartEntry::InvokeFunction(const Function& function,
104 const Array& arguments,
105 const Array& arguments_descriptor,
106 uword current_sp) {
107 // We use a kernel2kernel constant evaluator in Dart 2.0 AOT compilation
108 // and never start the VM service isolate. So we should never end up invoking
109 // any dart code in the Dart 2.0 AOT compiler.
110 if (FLAG_precompiled_mode) {
111#if !defined(DART_PRECOMPILED_RUNTIME)
112 UNREACHABLE();
113#else
114 if (FLAG_use_bare_instructions) {
115 Thread* thread = Thread::Current();
116 thread->set_global_object_pool(
117 thread->isolate()->object_store()->global_object_pool());
118 const DispatchTable* dispatch_table = thread->isolate()->dispatch_table();
119 if (dispatch_table != nullptr) {
120 thread->set_dispatch_table_array(dispatch_table->ArrayOrigin());
121 }
122 ASSERT(thread->global_object_pool() != Object::null());
123 }
124#endif // !defined(DART_PRECOMPILED_RUNTIME)
125 }
126
127 ASSERT(!function.IsNull());
128
129 // Get the entrypoint corresponding to the function specified, this
130 // will result in a compilation of the function if it is not already
131 // compiled.
132 Thread* thread = Thread::Current();
133 Zone* zone = thread->zone();
134 ASSERT(thread->IsMutatorThread());
135 ScopedIsolateStackLimits stack_limit(thread, current_sp);
136#if !defined(DART_PRECOMPILED_RUNTIME)
137 if (!function.HasCode()) {
138 if (FLAG_enable_interpreter && function.IsBytecodeAllowed(zone)) {
139 if (!function.HasBytecode()) {
140 ErrorPtr error =
141 kernel::BytecodeReader::ReadFunctionBytecode(thread, function);
142 if (error != Error::null()) {
143 return error;
144 }
145 }
146
147 // If we have bytecode but no native code then invoke the interpreter.
148 if (function.HasBytecode() && (FLAG_compilation_counter_threshold != 0)) {
149 ASSERT(thread->no_callback_scope_depth() == 0);
150 SuspendLongJumpScope suspend_long_jump_scope(thread);
151 TransitionToGenerated transition(thread);
152 return Interpreter::Current()->Call(function, arguments_descriptor,
153 arguments, thread);
154 }
155
156 // Fall back to compilation.
157 }
158
159 const Object& result =
160 Object::Handle(zone, Compiler::CompileFunction(thread, function));
161 if (result.IsError()) {
162 return Error::Cast(result).raw();
163 }
164
165 // At this point we should have native code.
166 ASSERT(function.HasCode());
167 }
168#endif // !defined(DART_PRECOMPILED_RUNTIME)
169
170 // Now Call the invoke stub which will invoke the dart function.
171 const Code& code = Code::Handle(zone, function.CurrentCode());
172 return InvokeCode(code, arguments_descriptor, arguments, thread);
173}
174
175extern "C" {
176// Note: The invocation stub follows the C ABI, so we cannot pass C++ struct
177// values like ObjectPtr. In some calling conventions (IA32), ObjectPtr is
178// passed/returned different from a pointer.
179typedef uword /*ObjectPtr*/ (*invokestub)(const Code& target_code,
180 const Array& arguments_descriptor,
181 const Array& arguments,
182 Thread* thread);
183}
184
185NO_SANITIZE_SAFE_STACK
186ObjectPtr DartEntry::InvokeCode(const Code& code,
187 const Array& arguments_descriptor,
188 const Array& arguments,
189 Thread* thread) {
190 ASSERT(!code.IsNull());
191 ASSERT(thread->no_callback_scope_depth() == 0);
192 ASSERT(!Isolate::Current()->null_safety_not_set());
193
194 invokestub entrypoint =
195 reinterpret_cast<invokestub>(StubCode::InvokeDartCode().EntryPoint());
196 SuspendLongJumpScope suspend_long_jump_scope(thread);
197 TransitionToGenerated transition(thread);
198#if defined(USING_SIMULATOR)
199 return bit_copy<ObjectPtr, int64_t>(Simulator::Current()->Call(
200 reinterpret_cast<intptr_t>(entrypoint), reinterpret_cast<intptr_t>(&code),
201 reinterpret_cast<intptr_t>(&arguments_descriptor),
202 reinterpret_cast<intptr_t>(&arguments),
203 reinterpret_cast<intptr_t>(thread)));
204#else
205 return static_cast<ObjectPtr>(
206 entrypoint(code, arguments_descriptor, arguments, thread));
207#endif
208}
209
210ObjectPtr DartEntry::ResolveCallable(const Array& arguments,
211 const Array& arguments_descriptor) {
212 auto thread = Thread::Current();
213 auto isolate = thread->isolate();
214 auto zone = thread->zone();
215
216 const ArgumentsDescriptor args_desc(arguments_descriptor);
217 const intptr_t receiver_index = args_desc.FirstArgIndex();
218 const intptr_t type_args_len = args_desc.TypeArgsLen();
219 const auto& getter_name = Symbols::GetCall();
220
221 auto& instance = Instance::Handle(zone);
222 auto& function = Function::Handle(zone);
223 auto& cls = Class::Handle(zone);
224
225 // The null instance cannot resolve to a callable, so we can stop there.
226 for (instance ^= arguments.At(receiver_index); !instance.IsNull();
227 instance ^= arguments.At(receiver_index)) {
228 // The instance is a callable, so check that its function is compatible.
229 if (instance.IsCallable(&function)) {
230 bool matches = function.AreValidArguments(args_desc, nullptr);
231
232 if (matches && type_args_len > 0 && function.IsClosureFunction()) {
233 // Though the closure function is generic, the closure itself may
234 // not be because it closes over delayed function type arguments.
235 matches = Closure::Cast(instance).IsGeneric(thread);
236 }
237
238 if (matches) {
239 return function.raw();
240 }
241 }
242
243 // Special case: closures are implemented with a call getter instead of a
244 // call method, so checking for a call getter would cause an infinite loop.
245 if (instance.IsClosure()) {
246 break;
247 }
248
249 cls = instance.clazz();
250 // Find a call getter, if any, in the class hierarchy.
251 function = Resolver::ResolveDynamicAnyArgs(zone, cls, getter_name,
252 /*allow_add=*/false);
253 if (function.IsNull()) {
254 break;
255 }
256 if (!OSThread::Current()->HasStackHeadroom()) {
257 const Instance& exception =
258 Instance::Handle(zone, isolate->object_store()->stack_overflow());
259 return UnhandledException::New(exception, StackTrace::Handle(zone));
260 }
261
262 const Array& getter_arguments = Array::Handle(zone, Array::New(1));
263 getter_arguments.SetAt(0, instance);
264 const Object& getter_result = Object::Handle(
265 zone, DartEntry::InvokeFunction(function, getter_arguments));
266 if (getter_result.IsError()) {
267 return getter_result.raw();
268 }
269 ASSERT(getter_result.IsNull() || getter_result.IsInstance());
270
271 // We have a new possibly compatible callable, so set the first argument
272 // accordingly so it gets picked up in the main loop.
273 arguments.SetAt(receiver_index, getter_result);
274 }
275
276 // No compatible callable was found.
277 return Function::null();
278}
279
280ObjectPtr DartEntry::InvokeCallable(const Function& callable_function,
281 const Array& arguments,
282 const Array& arguments_descriptor) {
283 if (!callable_function.IsNull()) {
284 return InvokeFunction(callable_function, arguments, arguments_descriptor);
285 }
286
287 // No compatible callable was found, so invoke noSuchMethod.
288 Thread* thread = Thread::Current();
289 Zone* zone = thread->zone();
290 const ArgumentsDescriptor args_desc(arguments_descriptor);
291 auto& instance =
292 Instance::CheckedHandle(zone, arguments.At(args_desc.FirstArgIndex()));
293 auto& target_name = String::Handle(zone, Symbols::Call().raw());
294 if (instance.IsClosure()) {
295 const auto& closure = Closure::Cast(instance);
296 // For closures, use the name of the closure, not 'call'.
297 const auto& function = Function::Handle(zone, closure.function());
298 target_name = function.QualifiedUserVisibleName();
299 }
300 return InvokeNoSuchMethod(instance, target_name, arguments,
301 arguments_descriptor);
302}
303
304ObjectPtr DartEntry::InvokeClosure(const Array& arguments) {
305 const int kTypeArgsLen = 0; // No support to pass type args to generic func.
306
307 // Closures always have boxed parameters
308 const Array& arguments_descriptor = Array::Handle(
309 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, arguments.Length()));
310 return InvokeClosure(arguments, arguments_descriptor);
311}
312
313ObjectPtr DartEntry::InvokeClosure(const Array& arguments,
314 const Array& arguments_descriptor) {
315 const Object& resolved_result =
316 Object::Handle(ResolveCallable(arguments, arguments_descriptor));
317 if (resolved_result.IsError()) {
318 return resolved_result.raw();
319 }
320
321 const auto& function =
322 Function::Handle(Function::RawCast(resolved_result.raw()));
323 return InvokeCallable(function, arguments, arguments_descriptor);
324}
325
326ObjectPtr DartEntry::InvokeNoSuchMethod(const Instance& receiver,
327 const String& target_name,
328 const Array& arguments,
329 const Array& arguments_descriptor) {
330 const ArgumentsDescriptor args_desc(arguments_descriptor);
331 ASSERT(receiver.raw() == arguments.At(args_desc.FirstArgIndex()));
332 // Allocate an Invocation object.
333 const Library& core_lib = Library::Handle(Library::CoreLibrary());
334
335 Class& invocation_mirror_class = Class::Handle(core_lib.LookupClass(
336 String::Handle(core_lib.PrivateName(Symbols::InvocationMirror()))));
337 ASSERT(!invocation_mirror_class.IsNull());
338 const String& function_name =
339 String::Handle(core_lib.PrivateName(Symbols::AllocateInvocationMirror()));
340 const Function& allocation_function = Function::Handle(
341 invocation_mirror_class.LookupStaticFunction(function_name));
342 ASSERT(!allocation_function.IsNull());
343 const int kNumAllocationArgs = 4;
344 const Array& allocation_args = Array::Handle(Array::New(kNumAllocationArgs));
345 allocation_args.SetAt(0, target_name);
346 allocation_args.SetAt(1, arguments_descriptor);
347 allocation_args.SetAt(2, arguments);
348 allocation_args.SetAt(3, Bool::False()); // Not a super invocation.
349 const Object& invocation_mirror =
350 Object::Handle(InvokeFunction(allocation_function, allocation_args));
351 if (invocation_mirror.IsError()) {
352 Exceptions::PropagateError(Error::Cast(invocation_mirror));
353 UNREACHABLE();
354 }
355
356 // Now use the invocation mirror object and invoke NoSuchMethod.
357 const int kTypeArgsLen = 0;
358 const int kNumArguments = 2;
359 ArgumentsDescriptor nsm_args_desc(Array::Handle(
360 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, kNumArguments)));
361 Function& function = Function::Handle(Resolver::ResolveDynamic(
362 receiver, Symbols::NoSuchMethod(), nsm_args_desc));
363 if (function.IsNull()) {
364 ASSERT(!FLAG_lazy_dispatchers);
365 // If noSuchMethod(invocation) is not found, call Object::noSuchMethod.
366 Thread* thread = Thread::Current();
367 function = Resolver::ResolveDynamicForReceiverClass(
368 Class::Handle(thread->zone(),
369 thread->isolate()->object_store()->object_class()),
370 Symbols::NoSuchMethod(), nsm_args_desc);
371 }
372 ASSERT(!function.IsNull());
373 const Array& args = Array::Handle(Array::New(kNumArguments));
374 args.SetAt(0, receiver);
375 args.SetAt(1, invocation_mirror);
376 return InvokeFunction(function, args);
377}
378
379ArgumentsDescriptor::ArgumentsDescriptor(const Array& array) : array_(array) {}
380
381intptr_t ArgumentsDescriptor::TypeArgsLen() const {
382 return Smi::Value(Smi::RawCast(array_.At(kTypeArgsLenIndex)));
383}
384
385intptr_t ArgumentsDescriptor::Count() const {
386 return Smi::Value(Smi::RawCast(array_.At(kCountIndex)));
387}
388
389intptr_t ArgumentsDescriptor::Size() const {
390 return Smi::Value(Smi::RawCast(array_.At(kSizeIndex)));
391}
392
393intptr_t ArgumentsDescriptor::PositionalCount() const {
394 return Smi::Value(Smi::RawCast(array_.At(kPositionalCountIndex)));
395}
396
397StringPtr ArgumentsDescriptor::NameAt(intptr_t index) const {
398 const intptr_t offset =
399 kFirstNamedEntryIndex + (index * kNamedEntrySize) + kNameOffset;
400 String& result = String::Handle();
401 result ^= array_.At(offset);
402 return result.raw();
403}
404
405intptr_t ArgumentsDescriptor::PositionAt(intptr_t index) const {
406 const intptr_t offset =
407 kFirstNamedEntryIndex + (index * kNamedEntrySize) + kPositionOffset;
408 return Smi::Value(Smi::RawCast(array_.At(offset)));
409}
410
411bool ArgumentsDescriptor::MatchesNameAt(intptr_t index,
412 const String& other) const {
413 return NameAt(index) == other.raw();
414}
415
416ArrayPtr ArgumentsDescriptor::GetArgumentNames() const {
417 const intptr_t num_named_args = NamedCount();
418 if (num_named_args == 0) {
419 return Array::null();
420 }
421
422 Zone* zone = Thread::Current()->zone();
423 const Array& names =
424 Array::Handle(zone, Array::New(num_named_args, Heap::kOld));
425 String& name = String::Handle(zone);
426 const intptr_t num_pos_args = PositionalCount();
427 for (intptr_t i = 0; i < num_named_args; ++i) {
428 const intptr_t index = PositionAt(i) - num_pos_args;
429 name = NameAt(i);
430 ASSERT(names.At(index) == Object::null());
431 names.SetAt(index, name);
432 }
433 return names.raw();
434}
435
436void ArgumentsDescriptor::PrintTo(BaseTextBuffer* buffer) const {
437 buffer->Printf("%" Pd " arg%s", Count(), Count() == 1 ? "" : "s");
438 if (TypeArgsLen() > 0) {
439 buffer->Printf(", %" Pd " type arg%s", TypeArgsLen(),
440 TypeArgsLen() == 1 ? "" : "s");
441 }
442 if (NamedCount() > 0) {
443 buffer->AddString(", names [");
444 auto& str = String::Handle();
445 for (intptr_t i = 0; i < NamedCount(); i++) {
446 if (i != 0) {
447 buffer->AddString(", ");
448 }
449 str = NameAt(i);
450 buffer->Printf("'%s'", str.ToCString());
451 }
452 buffer->Printf("]");
453 }
454}
455
456const char* ArgumentsDescriptor::ToCString() const {
457 ZoneTextBuffer buf(Thread::Current()->zone());
458 PrintTo(&buf);
459 return buf.buffer();
460}
461
462ArrayPtr ArgumentsDescriptor::New(intptr_t type_args_len,
463 intptr_t num_arguments,
464 intptr_t size_arguments,
465 const Array& optional_arguments_names,
466 Heap::Space space) {
467 const intptr_t num_named_args =
468 optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length();
469 if (num_named_args == 0) {
470 return ArgumentsDescriptor::New(type_args_len, num_arguments,
471 size_arguments, space);
472 }
473 ASSERT(type_args_len >= 0);
474 ASSERT(num_arguments >= 0);
475 const intptr_t num_pos_args = num_arguments - num_named_args;
476
477 // Build the arguments descriptor array, which consists of the the type
478 // argument vector length (0 if none); total argument count; the positional
479 // argument count; a sequence of (name, position) pairs, sorted by name, for
480 // each named optional argument; and a terminating null to simplify iterating
481 // in generated code.
482 Thread* thread = Thread::Current();
483 Zone* zone = thread->zone();
484 const intptr_t descriptor_len = LengthFor(num_named_args);
485 Array& descriptor = Array::Handle(zone, Array::New(descriptor_len, space));
486
487 // Set length of type argument vector.
488 descriptor.SetAt(kTypeArgsLenIndex, Smi::Handle(Smi::New(type_args_len)));
489 // Set total number of passed arguments.
490 descriptor.SetAt(kCountIndex, Smi::Handle(Smi::New(num_arguments)));
491 // Set total number of passed arguments.
492 descriptor.SetAt(kSizeIndex, Smi::Handle(Smi::New(size_arguments)));
493
494 // Set number of positional arguments.
495 descriptor.SetAt(kPositionalCountIndex, Smi::Handle(Smi::New(num_pos_args)));
496
497 // Set alphabetically sorted entries for named arguments.
498 String& name = String::Handle(zone);
499 Smi& pos = Smi::Handle(zone);
500 String& previous_name = String::Handle(zone);
501 Smi& previous_pos = Smi::Handle(zone);
502 for (intptr_t i = 0; i < num_named_args; i++) {
503 name ^= optional_arguments_names.At(i);
504 pos = Smi::New(num_pos_args + i);
505 intptr_t insert_index = kFirstNamedEntryIndex + (kNamedEntrySize * i);
506 // Shift already inserted pairs with "larger" names.
507 while (insert_index > kFirstNamedEntryIndex) {
508 intptr_t previous_index = insert_index - kNamedEntrySize;
509 previous_name ^= descriptor.At(previous_index + kNameOffset);
510 intptr_t result = name.CompareTo(previous_name);
511 ASSERT(result != 0); // Duplicate argument names checked in parser.
512 if (result > 0) break;
513 previous_pos ^= descriptor.At(previous_index + kPositionOffset);
514 descriptor.SetAt(insert_index + kNameOffset, previous_name);
515 descriptor.SetAt(insert_index + kPositionOffset, previous_pos);
516 insert_index = previous_index;
517 }
518 // Insert pair in descriptor array.
519 descriptor.SetAt(insert_index + kNameOffset, name);
520 descriptor.SetAt(insert_index + kPositionOffset, pos);
521 }
522 // Set terminating null.
523 descriptor.SetAt(descriptor_len - 1, Object::null_object());
524
525 // Share the immutable descriptor when possible by canonicalizing it.
526 descriptor.MakeImmutable();
527 const char* error_str = NULL;
528 descriptor ^= descriptor.CheckAndCanonicalize(thread, &error_str);
529 if (error_str != NULL) {
530 FATAL1("Failed to canonicalize: %s", error_str);
531 }
532 ASSERT(!descriptor.IsNull());
533 return descriptor.raw();
534}
535
536ArrayPtr ArgumentsDescriptor::New(intptr_t type_args_len,
537 intptr_t num_arguments,
538 intptr_t size_arguments,
539 Heap::Space space) {
540 ASSERT(type_args_len >= 0);
541 ASSERT(num_arguments >= 0);
542
543 if ((type_args_len == 0) && (num_arguments < kCachedDescriptorCount) &&
544 (num_arguments == size_arguments)) {
545 return cached_args_descriptors_[num_arguments];
546 }
547 return NewNonCached(type_args_len, num_arguments, size_arguments, true,
548 space);
549}
550
551ArrayPtr ArgumentsDescriptor::NewNonCached(intptr_t type_args_len,
552 intptr_t num_arguments,
553 intptr_t size_arguments,
554 bool canonicalize,
555 Heap::Space space) {
556 // Build the arguments descriptor array, which consists of the length of the
557 // type argument vector, total argument count; the positional argument count;
558 // and a terminating null to simplify iterating in generated code.
559 Thread* thread = Thread::Current();
560 Zone* zone = thread->zone();
561 const intptr_t descriptor_len = LengthFor(0);
562 Array& descriptor = Array::Handle(zone, Array::New(descriptor_len, space));
563 const Smi& arg_count = Smi::Handle(zone, Smi::New(num_arguments));
564 const Smi& arg_size = Smi::Handle(zone, Smi::New(size_arguments));
565
566 // Set type argument vector length.
567 descriptor.SetAt(kTypeArgsLenIndex,
568 Smi::Handle(zone, Smi::New(type_args_len)));
569
570 // Set total number of passed arguments.
571 descriptor.SetAt(kCountIndex, arg_count);
572
573 // Set total size of passed arguments.
574 descriptor.SetAt(kSizeIndex, arg_size);
575
576 // Set number of positional arguments.
577 descriptor.SetAt(kPositionalCountIndex, arg_count);
578
579 // Set terminating null.
580 descriptor.SetAt((descriptor_len - 1), Object::null_object());
581
582 // Share the immutable descriptor when possible by canonicalizing it.
583 descriptor.MakeImmutable();
584 if (canonicalize) {
585 const char* error_str = NULL;
586 descriptor ^= descriptor.CheckAndCanonicalize(thread, &error_str);
587 if (error_str != NULL) {
588 FATAL1("Failed to canonicalize: %s", error_str);
589 }
590 }
591 ASSERT(!descriptor.IsNull());
592 return descriptor.raw();
593}
594
595void ArgumentsDescriptor::Init() {
596 for (int i = 0; i < kCachedDescriptorCount; i++) {
597 cached_args_descriptors_[i] =
598 NewNonCached(/*type_args_len=*/0, i, i, false, Heap::kOld);
599 }
600}
601
602void ArgumentsDescriptor::Cleanup() {
603 for (int i = 0; i < kCachedDescriptorCount; i++) {
604 // Don't free pointers to RawArray objects managed by the VM.
605 cached_args_descriptors_[i] = NULL;
606 }
607}
608
609ObjectPtr DartLibraryCalls::InstanceCreate(const Library& lib,
610 const String& class_name,
611 const String& constructor_name,
612 const Array& arguments) {
613 const Class& cls = Class::Handle(lib.LookupClassAllowPrivate(class_name));
614 ASSERT(!cls.IsNull());
615 // For now, we only support a non-parameterized or raw type.
616 const int kNumExtraArgs = 1; // implicit rcvr arg.
617 const Instance& exception_object = Instance::Handle(Instance::New(cls));
618 const Array& constructor_arguments =
619 Array::Handle(Array::New(arguments.Length() + kNumExtraArgs));
620 constructor_arguments.SetAt(0, exception_object);
621 Object& obj = Object::Handle();
622 for (intptr_t i = 0; i < arguments.Length(); i++) {
623 obj = arguments.At(i);
624 constructor_arguments.SetAt((i + kNumExtraArgs), obj);
625 }
626
627 const String& function_name =
628 String::Handle(String::Concat(class_name, constructor_name));
629 const Function& constructor =
630 Function::Handle(cls.LookupConstructorAllowPrivate(function_name));
631 ASSERT(!constructor.IsNull());
632 const Object& retval = Object::Handle(
633 DartEntry::InvokeFunction(constructor, constructor_arguments));
634 ASSERT(retval.IsNull() || retval.IsError());
635 if (retval.IsError()) {
636 return retval.raw();
637 }
638 return exception_object.raw();
639}
640
641ObjectPtr DartLibraryCalls::ToString(const Instance& receiver) {
642 const int kTypeArgsLen = 0;
643 const int kNumArguments = 1; // Receiver.
644 ArgumentsDescriptor args_desc(Array::Handle(
645 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, kNumArguments)));
646 const Function& function = Function::Handle(
647 Resolver::ResolveDynamic(receiver, Symbols::toString(), args_desc));
648 ASSERT(!function.IsNull());
649 const Array& args = Array::Handle(Array::New(kNumArguments));
650 args.SetAt(0, receiver);
651 const Object& result =
652 Object::Handle(DartEntry::InvokeFunction(function, args));
653 ASSERT(result.IsInstance() || result.IsError());
654 return result.raw();
655}
656
657ObjectPtr DartLibraryCalls::HashCode(const Instance& receiver) {
658 const int kTypeArgsLen = 0;
659 const int kNumArguments = 1; // Receiver.
660 ArgumentsDescriptor args_desc(Array::Handle(
661 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, kNumArguments)));
662 const Function& function = Function::Handle(
663 Resolver::ResolveDynamic(receiver, Symbols::hashCode(), args_desc));
664 ASSERT(!function.IsNull());
665 const Array& args = Array::Handle(Array::New(kNumArguments));
666 args.SetAt(0, receiver);
667 const Object& result =
668 Object::Handle(DartEntry::InvokeFunction(function, args));
669 ASSERT(result.IsInstance() || result.IsError());
670 return result.raw();
671}
672
673ObjectPtr DartLibraryCalls::Equals(const Instance& left,
674 const Instance& right) {
675 const int kTypeArgsLen = 0;
676 const int kNumArguments = 2;
677 ArgumentsDescriptor args_desc(Array::Handle(
678 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, kNumArguments)));
679 const Function& function = Function::Handle(
680 Resolver::ResolveDynamic(left, Symbols::EqualOperator(), args_desc));
681 ASSERT(!function.IsNull());
682
683 const Array& args = Array::Handle(Array::New(kNumArguments));
684 args.SetAt(0, left);
685 args.SetAt(1, right);
686 const Object& result =
687 Object::Handle(DartEntry::InvokeFunction(function, args));
688 ASSERT(result.IsInstance() || result.IsError());
689 return result.raw();
690}
691
692// On success, returns a RawInstance. On failure, a RawError.
693ObjectPtr DartLibraryCalls::IdentityHashCode(const Instance& object) {
694 const int kNumArguments = 1;
695 Thread* thread = Thread::Current();
696 Zone* zone = thread->zone();
697 const Library& libcore = Library::Handle(zone, Library::CoreLibrary());
698 ASSERT(!libcore.IsNull());
699 const Function& function = Function::Handle(
700 zone, libcore.LookupFunctionAllowPrivate(Symbols::identityHashCode()));
701 ASSERT(!function.IsNull());
702 const Array& args = Array::Handle(zone, Array::New(kNumArguments));
703 args.SetAt(0, object);
704 const Object& result =
705 Object::Handle(zone, DartEntry::InvokeFunction(function, args));
706 ASSERT(result.IsInstance() || result.IsError());
707 return result.raw();
708}
709
710ObjectPtr DartLibraryCalls::LookupHandler(Dart_Port port_id) {
711 Thread* thread = Thread::Current();
712 Zone* zone = thread->zone();
713 Function& function = Function::Handle(
714 zone, thread->isolate()->object_store()->lookup_port_handler());
715 const int kTypeArgsLen = 0;
716 const int kNumArguments = 1;
717 if (function.IsNull()) {
718 Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
719 ASSERT(!isolate_lib.IsNull());
720 const String& class_name = String::Handle(
721 zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
722 const String& function_name = String::Handle(
723 zone, isolate_lib.PrivateName(Symbols::_lookupHandler()));
724 function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
725 kTypeArgsLen, kNumArguments,
726 Object::empty_array());
727 ASSERT(!function.IsNull());
728 thread->isolate()->object_store()->set_lookup_port_handler(function);
729 }
730 Array& args = Array::Handle(
731 zone, thread->isolate()->isolate_object_store()->dart_args_1());
732 if (args.IsNull()) {
733 args = Array::New(kNumArguments);
734 thread->isolate()->isolate_object_store()->set_dart_args_1(args);
735 }
736 args.SetAt(0, Integer::Handle(zone, Integer::New(port_id)));
737 const Object& result =
738 Object::Handle(zone, DartEntry::InvokeFunction(function, args));
739 return result.raw();
740}
741
742ObjectPtr DartLibraryCalls::HandleMessage(const Object& handler,
743 const Instance& message) {
744 Thread* thread = Thread::Current();
745 Zone* zone = thread->zone();
746 Isolate* isolate = thread->isolate();
747 Function& function = Function::Handle(
748 zone, isolate->object_store()->handle_message_function());
749 const int kTypeArgsLen = 0;
750 const int kNumArguments = 2;
751 if (function.IsNull()) {
752 Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
753 ASSERT(!isolate_lib.IsNull());
754 const String& class_name = String::Handle(
755 zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
756 const String& function_name = String::Handle(
757 zone, isolate_lib.PrivateName(Symbols::_handleMessage()));
758 function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
759 kTypeArgsLen, kNumArguments,
760 Object::empty_array());
761 ASSERT(!function.IsNull());
762 isolate->object_store()->set_handle_message_function(function);
763 }
764 Array& args = Array::Handle(
765 zone, thread->isolate()->isolate_object_store()->dart_args_2());
766 if (args.IsNull()) {
767 args = Array::New(kNumArguments);
768 thread->isolate()->isolate_object_store()->set_dart_args_2(args);
769 }
770 args.SetAt(0, handler);
771 args.SetAt(1, message);
772#if !defined(PRODUCT)
773 if (isolate->debugger()->IsStepping()) {
774 // If the isolate is being debugged and the debugger was stepping
775 // through code, enable single stepping so debugger will stop
776 // at the first location the user is interested in.
777 isolate->debugger()->SetResumeAction(Debugger::kStepInto);
778 }
779#endif
780 const Object& result =
781 Object::Handle(zone, DartEntry::InvokeFunction(function, args));
782 ASSERT(result.IsNull() || result.IsError());
783 return result.raw();
784}
785
786ObjectPtr DartLibraryCalls::DrainMicrotaskQueue() {
787 Zone* zone = Thread::Current()->zone();
788 Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
789 ASSERT(!isolate_lib.IsNull());
790 Function& function =
791 Function::Handle(zone, isolate_lib.LookupFunctionAllowPrivate(
792 Symbols::_runPendingImmediateCallback()));
793 const Object& result = Object::Handle(
794 zone, DartEntry::InvokeFunction(function, Object::empty_array()));
795 ASSERT(result.IsNull() || result.IsError());
796 return result.raw();
797}
798
799ObjectPtr DartLibraryCalls::EnsureScheduleImmediate() {
800 Zone* zone = Thread::Current()->zone();
801 const Library& async_lib = Library::Handle(zone, Library::AsyncLibrary());
802 ASSERT(!async_lib.IsNull());
803 const Function& function =
804 Function::Handle(zone, async_lib.LookupFunctionAllowPrivate(
805 Symbols::_ensureScheduleImmediate()));
806 ASSERT(!function.IsNull());
807 const Object& result = Object::Handle(
808 zone, DartEntry::InvokeFunction(function, Object::empty_array()));
809 ASSERT(result.IsNull() || result.IsError());
810 return result.raw();
811}
812
813ObjectPtr DartLibraryCalls::MapSetAt(const Instance& map,
814 const Instance& key,
815 const Instance& value) {
816 const int kTypeArgsLen = 0;
817 const int kNumArguments = 3;
818 ArgumentsDescriptor args_desc(Array::Handle(
819 ArgumentsDescriptor::NewBoxed(kTypeArgsLen, kNumArguments)));
820 const Function& function = Function::Handle(
821 Resolver::ResolveDynamic(map, Symbols::AssignIndexToken(), args_desc));
822 ASSERT(!function.IsNull());
823 const Array& args = Array::Handle(Array::New(kNumArguments));
824 args.SetAt(0, map);
825 args.SetAt(1, key);
826 args.SetAt(2, value);
827 const Object& result =
828 Object::Handle(DartEntry::InvokeFunction(function, args));
829 return result.raw();
830}
831
832} // namespace dart
833