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 | |
26 | namespace dart { |
27 | |
28 | DECLARE_FLAG(bool, enable_interpreter); |
29 | DECLARE_FLAG(bool, precompiled_mode); |
30 | |
31 | // A cache of VM heap allocated arguments descriptors. |
32 | ArrayPtr ArgumentsDescriptor::cached_args_descriptors_[kCachedDescriptorCount]; |
33 | |
34 | ObjectPtr 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 | |
43 | class 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. |
86 | class 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 | |
103 | ObjectPtr 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 | |
175 | extern "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. |
179 | typedef uword /*ObjectPtr*/ (*invokestub)(const Code& target_code, |
180 | const Array& arguments_descriptor, |
181 | const Array& arguments, |
182 | Thread* thread); |
183 | } |
184 | |
185 | NO_SANITIZE_SAFE_STACK |
186 | ObjectPtr 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 | |
210 | ObjectPtr 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 | |
280 | ObjectPtr 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 | |
304 | ObjectPtr 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 | |
313 | ObjectPtr 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 | |
326 | ObjectPtr 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 | |
379 | ArgumentsDescriptor::ArgumentsDescriptor(const Array& array) : array_(array) {} |
380 | |
381 | intptr_t ArgumentsDescriptor::TypeArgsLen() const { |
382 | return Smi::Value(Smi::RawCast(array_.At(kTypeArgsLenIndex))); |
383 | } |
384 | |
385 | intptr_t ArgumentsDescriptor::Count() const { |
386 | return Smi::Value(Smi::RawCast(array_.At(kCountIndex))); |
387 | } |
388 | |
389 | intptr_t ArgumentsDescriptor::Size() const { |
390 | return Smi::Value(Smi::RawCast(array_.At(kSizeIndex))); |
391 | } |
392 | |
393 | intptr_t ArgumentsDescriptor::PositionalCount() const { |
394 | return Smi::Value(Smi::RawCast(array_.At(kPositionalCountIndex))); |
395 | } |
396 | |
397 | StringPtr 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 | |
405 | intptr_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 | |
411 | bool ArgumentsDescriptor::MatchesNameAt(intptr_t index, |
412 | const String& other) const { |
413 | return NameAt(index) == other.raw(); |
414 | } |
415 | |
416 | ArrayPtr 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 | |
436 | void 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 | |
456 | const char* ArgumentsDescriptor::ToCString() const { |
457 | ZoneTextBuffer buf(Thread::Current()->zone()); |
458 | PrintTo(&buf); |
459 | return buf.buffer(); |
460 | } |
461 | |
462 | ArrayPtr 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 | |
536 | ArrayPtr 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 | |
551 | ArrayPtr 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 | |
595 | void 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 | |
602 | void 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 | |
609 | ObjectPtr 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 = 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 | |
641 | ObjectPtr 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 | |
657 | ObjectPtr 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 | |
673 | ObjectPtr 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. |
693 | ObjectPtr 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 | |
710 | ObjectPtr 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 | |
742 | ObjectPtr 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 | |
786 | ObjectPtr 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 | |
799 | ObjectPtr 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 | |
813 | ObjectPtr 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 | |