| // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "vm/dart_entry.h" |
| |
| #include "vm/code_generator.h" |
| #include "vm/compiler.h" |
| #include "vm/object_store.h" |
| #include "vm/resolver.h" |
| #include "vm/simulator.h" |
| #include "vm/stub_code.h" |
| #include "vm/symbols.h" |
| |
| namespace dart { |
| |
| // A cache of VM heap allocated arguments descriptors. |
| RawArray* ArgumentsDescriptor::cached_args_descriptors_[kCachedDescriptorCount]; |
| |
| |
| RawObject* DartEntry::InvokeFunction(const Function& function, |
| const Array& arguments) { |
| const Array& arguments_descriptor = |
| Array::Handle(ArgumentsDescriptor::New(arguments.Length())); |
| return InvokeFunction(function, arguments, arguments_descriptor); |
| } |
| |
| |
| RawObject* DartEntry::InvokeFunction(const Function& function, |
| const Array& arguments, |
| const Array& arguments_descriptor) { |
| const Context& context = |
| Context::ZoneHandle(Isolate::Current()->object_store()->empty_context()); |
| ASSERT(context.isolate() == Isolate::Current()); |
| return InvokeFunction(function, arguments, arguments_descriptor, context); |
| } |
| |
| |
| RawObject* DartEntry::InvokeFunction(const Function& function, |
| const Array& arguments, |
| const Array& arguments_descriptor, |
| const Context& context) { |
| // Get the entrypoint corresponding to the function specified, this |
| // will result in a compilation of the function if it is not already |
| // compiled. |
| if (!function.HasCode()) { |
| const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
| if (!error.IsNull()) { |
| return error.raw(); |
| } |
| } |
| // Now Call the invoke stub which will invoke the dart function. |
| invokestub entrypoint = reinterpret_cast<invokestub>( |
| StubCode::InvokeDartCodeEntryPoint()); |
| const Code& code = Code::Handle(function.CurrentCode()); |
| ASSERT(!code.IsNull()); |
| ASSERT(Isolate::Current()->no_callback_scope_depth() == 0); |
| IsolateRunStateManager run_state_manager; |
| run_state_manager.SetRunState(Isolate::kIsolateRunning); |
| #if defined(USING_SIMULATOR) |
| return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call( |
| reinterpret_cast<int32_t>(entrypoint), |
| static_cast<int32_t>(code.EntryPoint()), |
| reinterpret_cast<int32_t>(&arguments_descriptor), |
| reinterpret_cast<int32_t>(&arguments), |
| reinterpret_cast<int32_t>(&context))); |
| #else |
| return entrypoint(code.EntryPoint(), |
| arguments_descriptor, |
| arguments, |
| context); |
| #endif |
| } |
| |
| |
| RawObject* DartEntry::InvokeClosure(const Array& arguments) { |
| const Array& arguments_descriptor = |
| Array::Handle(ArgumentsDescriptor::New(arguments.Length())); |
| return InvokeClosure(arguments, arguments_descriptor); |
| } |
| |
| |
| RawObject* DartEntry::InvokeClosure(const Array& arguments, |
| const Array& arguments_descriptor) { |
| Instance& instance = Instance::Handle(); |
| instance ^= arguments.At(0); |
| // Get the entrypoint corresponding to the closure function or to the call |
| // method of the instance. This will result in a compilation of the function |
| // if it is not already compiled. |
| Function& function = Function::Handle(); |
| Context& context = Context::Handle(); |
| if (instance.IsCallable(&function, &context)) { |
| // Only invoke the function if its arguments are compatible. |
| const ArgumentsDescriptor args_desc(arguments_descriptor); |
| if (function.AreValidArgumentCounts(args_desc.Count(), |
| args_desc.NamedCount(), |
| NULL)) { |
| // The closure or non-closure object (receiver) is passed as implicit |
| // first argument. It is already included in the arguments array. |
| return InvokeFunction(function, arguments, arguments_descriptor, context); |
| } |
| } |
| // There is no compatible 'call' method, so invoke noSuchMethod. |
| return InvokeNoSuchMethod(instance, |
| Symbols::Call(), |
| arguments, |
| arguments_descriptor); |
| } |
| |
| |
| RawObject* DartEntry::InvokeNoSuchMethod(const Instance& receiver, |
| const String& target_name, |
| const Array& arguments, |
| const Array& arguments_descriptor) { |
| ASSERT(receiver.raw() == arguments.At(0)); |
| // Allocate an Invocation object. |
| const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| |
| Class& invocation_mirror_class = Class::Handle( |
| core_lib.LookupClass( |
| String::Handle(core_lib.PrivateName(Symbols::InvocationMirror())))); |
| ASSERT(!invocation_mirror_class.IsNull()); |
| const String& function_name = |
| String::Handle(core_lib.PrivateName(Symbols::AllocateInvocationMirror())); |
| const Function& allocation_function = Function::Handle( |
| Resolver::ResolveStaticByName(invocation_mirror_class, |
| function_name, |
| Resolver::kIsQualified)); |
| ASSERT(!allocation_function.IsNull()); |
| const int kNumAllocationArgs = 3; |
| const Array& allocation_args = Array::Handle(Array::New(kNumAllocationArgs)); |
| allocation_args.SetAt(0, target_name); |
| allocation_args.SetAt(1, arguments_descriptor); |
| allocation_args.SetAt(2, arguments); |
| const Object& invocation_mirror = Object::Handle( |
| InvokeFunction(allocation_function, allocation_args)); |
| |
| // Now use the invocation mirror object and invoke NoSuchMethod. |
| const int kNumArguments = 2; |
| const int kNumNamedArguments = 0; |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(receiver, |
| Symbols::NoSuchMethod(), |
| kNumArguments, |
| kNumNamedArguments)); |
| ASSERT(!function.IsNull()); |
| const Array& args = Array::Handle(Array::New(kNumArguments)); |
| args.SetAt(0, receiver); |
| args.SetAt(1, invocation_mirror); |
| return InvokeFunction(function, args); |
| } |
| |
| |
| ArgumentsDescriptor::ArgumentsDescriptor(const Array& array) |
| : array_(array) { |
| } |
| |
| |
| intptr_t ArgumentsDescriptor::Count() const { |
| return Smi::CheckedHandle(array_.At(kCountIndex)).Value(); |
| } |
| |
| |
| intptr_t ArgumentsDescriptor::PositionalCount() const { |
| return Smi::CheckedHandle(array_.At(kPositionalCountIndex)).Value(); |
| } |
| |
| |
| bool ArgumentsDescriptor::MatchesNameAt(intptr_t index, |
| const String& other) const { |
| const intptr_t offset = kFirstNamedEntryIndex + |
| (index * kNamedEntrySize) + |
| kNameOffset; |
| return array_.At(offset) == other.raw(); |
| } |
| |
| |
| intptr_t ArgumentsDescriptor::count_offset() { |
| return Array::data_offset() + (kCountIndex * kWordSize); |
| } |
| |
| |
| intptr_t ArgumentsDescriptor::positional_count_offset() { |
| return Array::data_offset() + (kPositionalCountIndex * kWordSize); |
| } |
| |
| |
| intptr_t ArgumentsDescriptor::first_named_entry_offset() { |
| return Array::data_offset() + (kFirstNamedEntryIndex * kWordSize); |
| } |
| |
| |
| RawArray* ArgumentsDescriptor::New(intptr_t num_arguments, |
| const Array& optional_arguments_names) { |
| const intptr_t num_named_args = |
| optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); |
| if (num_named_args == 0) { |
| return ArgumentsDescriptor::New(num_arguments); |
| } |
| const intptr_t num_pos_args = num_arguments - num_named_args; |
| |
| // Build the arguments descriptor array, which consists of the total |
| // argument count; the positional argument count; a sequence of (name, |
| // position) pairs, sorted by name, for each named optional argument; and |
| // a terminating null to simplify iterating in generated code. |
| const intptr_t descriptor_len = LengthFor(num_named_args); |
| Array& descriptor = Array::Handle(Array::New(descriptor_len, Heap::kOld)); |
| |
| // Set total number of passed arguments. |
| descriptor.SetAt(kCountIndex, Smi::Handle(Smi::New(num_arguments))); |
| // Set number of positional arguments. |
| descriptor.SetAt(kPositionalCountIndex, Smi::Handle(Smi::New(num_pos_args))); |
| // Set alphabetically sorted entries for named arguments. |
| String& name = String::Handle(); |
| Smi& pos = Smi::Handle(); |
| for (intptr_t i = 0; i < num_named_args; i++) { |
| name ^= optional_arguments_names.At(i); |
| pos = Smi::New(num_pos_args + i); |
| intptr_t insert_index = kFirstNamedEntryIndex + (kNamedEntrySize * i); |
| // Shift already inserted pairs with "larger" names. |
| String& previous_name = String::Handle(); |
| Smi& previous_pos = Smi::Handle(); |
| while (insert_index > kFirstNamedEntryIndex) { |
| intptr_t previous_index = insert_index - kNamedEntrySize; |
| previous_name ^= descriptor.At(previous_index + kNameOffset); |
| intptr_t result = name.CompareTo(previous_name); |
| ASSERT(result != 0); // Duplicate argument names checked in parser. |
| if (result > 0) break; |
| previous_pos ^= descriptor.At(previous_index + kPositionOffset); |
| descriptor.SetAt(insert_index + kNameOffset, previous_name); |
| descriptor.SetAt(insert_index + kPositionOffset, previous_pos); |
| insert_index = previous_index; |
| } |
| // Insert pair in descriptor array. |
| descriptor.SetAt(insert_index + kNameOffset, name); |
| descriptor.SetAt(insert_index + kPositionOffset, pos); |
| } |
| // Set terminating null. |
| descriptor.SetAt(descriptor_len - 1, Object::Handle()); |
| |
| // Share the immutable descriptor when possible by canonicalizing it. |
| descriptor.MakeImmutable(); |
| descriptor ^= descriptor.Canonicalize(); |
| return descriptor.raw(); |
| } |
| |
| |
| RawArray* ArgumentsDescriptor::New(intptr_t num_arguments) { |
| ASSERT(num_arguments >= 0); |
| if (num_arguments < kCachedDescriptorCount) { |
| return cached_args_descriptors_[num_arguments]; |
| } |
| return NewNonCached(num_arguments); |
| } |
| |
| |
| RawArray* ArgumentsDescriptor::NewNonCached(intptr_t num_arguments, |
| bool canonicalize) { |
| // Build the arguments descriptor array, which consists of the total |
| // argument count; the positional argument count; and |
| // a terminating null to simplify iterating in generated code. |
| const intptr_t descriptor_len = LengthFor(0); |
| Array& descriptor = Array::Handle(Array::New(descriptor_len, Heap::kOld)); |
| const Smi& arg_count = Smi::Handle(Smi::New(num_arguments)); |
| |
| // Set total number of passed arguments. |
| descriptor.SetAt(kCountIndex, arg_count); |
| |
| // Set number of positional arguments. |
| descriptor.SetAt(kPositionalCountIndex, arg_count); |
| |
| // Set terminating null. |
| descriptor.SetAt((descriptor_len - 1), Object::Handle()); |
| |
| // Share the immutable descriptor when possible by canonicalizing it. |
| descriptor.MakeImmutable(); |
| if (canonicalize) { |
| descriptor ^= descriptor.Canonicalize(); |
| } |
| return descriptor.raw(); |
| } |
| |
| |
| void ArgumentsDescriptor::InitOnce() { |
| for (int i = 0; i < kCachedDescriptorCount; i++) { |
| cached_args_descriptors_[i] = ArgumentsDescriptor::NewNonCached(i, false); |
| } |
| } |
| |
| |
| RawObject* DartLibraryCalls::ExceptionCreate(const Library& lib, |
| const String& class_name, |
| const String& constructor_name, |
| const Array& arguments) { |
| const Class& cls = Class::Handle(lib.LookupClassAllowPrivate(class_name)); |
| ASSERT(!cls.IsNull()); |
| // For now, we only support a non-parameterized or raw type. |
| const int kNumExtraArgs = 2; // implicit rcvr and construction phase args. |
| const Instance& exception_object = Instance::Handle(Instance::New(cls)); |
| const Array& constructor_arguments = |
| Array::Handle(Array::New(arguments.Length() + kNumExtraArgs)); |
| constructor_arguments.SetAt(0, exception_object); |
| constructor_arguments.SetAt( |
| 1, Smi::Handle(Smi::New(Function::kCtorPhaseAll))); |
| Object& obj = Object::Handle(); |
| for (intptr_t i = 0; i < arguments.Length(); i++) { |
| obj = arguments.At(i); |
| constructor_arguments.SetAt((i + kNumExtraArgs), obj); |
| } |
| |
| const String& function_name = String::Handle( |
| String::Concat(class_name, constructor_name)); |
| const Function& constructor = |
| Function::Handle(cls.LookupConstructorAllowPrivate(function_name)); |
| ASSERT(!constructor.IsNull()); |
| const Object& retval = |
| Object::Handle(DartEntry::InvokeFunction(constructor, |
| constructor_arguments)); |
| ASSERT(retval.IsNull() || retval.IsError()); |
| if (retval.IsError()) { |
| return retval.raw(); |
| } |
| return exception_object.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::ToString(const Instance& receiver) { |
| const int kNumArguments = 1; // Receiver. |
| const int kNumNamedArguments = 0; // None. |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(receiver, |
| Symbols::toString(), |
| kNumArguments, |
| kNumNamedArguments)); |
| ASSERT(!function.IsNull()); |
| const Array& args = Array::Handle(Array::New(kNumArguments)); |
| args.SetAt(0, receiver); |
| const Object& result = Object::Handle(DartEntry::InvokeFunction(function, |
| args)); |
| ASSERT(result.IsInstance() || result.IsError()); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::Equals(const Instance& left, |
| const Instance& right) { |
| const int kNumArguments = 2; |
| const int kNumNamedArguments = 0; |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(left, |
| Symbols::EqualOperator(), |
| kNumArguments, |
| kNumNamedArguments)); |
| ASSERT(!function.IsNull()); |
| |
| const Array& args = Array::Handle(Array::New(kNumArguments)); |
| args.SetAt(0, left); |
| args.SetAt(1, right); |
| const Object& result = Object::Handle(DartEntry::InvokeFunction(function, |
| args)); |
| ASSERT(result.IsInstance() || result.IsError()); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::LookupReceivePort(Dart_Port port_id) { |
| Isolate* isolate = Isolate::Current(); |
| Function& function = |
| Function::Handle(isolate, |
| isolate->object_store()->lookup_receive_port_function()); |
| const int kNumArguments = 1; |
| if (function.IsNull()) { |
| Library& isolate_lib = Library::Handle(Library::IsolateLibrary()); |
| ASSERT(!isolate_lib.IsNull()); |
| const String& class_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_ReceivePortImpl())); |
| const String& function_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_lookupReceivePort())); |
| function = Resolver::ResolveStatic(isolate_lib, |
| class_name, |
| function_name, |
| kNumArguments, |
| Object::empty_array(), |
| Resolver::kIsQualified); |
| isolate->object_store()->set_lookup_receive_port_function(function); |
| } |
| const Array& args = Array::Handle(Array::New(kNumArguments)); |
| args.SetAt(0, Integer::Handle(Integer::New(port_id))); |
| const Object& result = |
| Object::Handle(DartEntry::InvokeFunction(function, args)); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::HandleMessage(const Object& receive_port, |
| Dart_Port reply_port_id, |
| const Instance& message) { |
| Isolate* isolate = Isolate::Current(); |
| Function& function = |
| Function::Handle(isolate, |
| isolate->object_store()->handle_message_function()); |
| const int kNumArguments = 3; |
| if (function.IsNull()) { |
| Library& isolate_lib = Library::Handle(Library::IsolateLibrary()); |
| ASSERT(!isolate_lib.IsNull()); |
| const String& class_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_ReceivePortImpl())); |
| const String& function_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_handleMessage())); |
| function = Resolver::ResolveStatic(isolate_lib, |
| class_name, |
| function_name, |
| kNumArguments, |
| Object::empty_array(), |
| Resolver::kIsQualified); |
| isolate->object_store()->set_handle_message_function(function); |
| } |
| const Array& args = Array::Handle(isolate, Array::New(kNumArguments)); |
| args.SetAt(0, receive_port); |
| args.SetAt(1, Integer::Handle(isolate, Integer::New(reply_port_id))); |
| args.SetAt(2, message); |
| const Object& result = |
| Object::Handle(isolate, DartEntry::InvokeFunction(function, args)); |
| ASSERT(result.IsNull() || result.IsError()); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::NewSendPort(intptr_t port_id) { |
| Library& isolate_lib = Library::Handle(Library::IsolateLibrary()); |
| ASSERT(!isolate_lib.IsNull()); |
| const String& class_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_SendPortImpl())); |
| const int kNumArguments = 1; |
| const String& function_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_create())); |
| const Function& function = Function::Handle( |
| Resolver::ResolveStatic(isolate_lib, |
| class_name, |
| function_name, |
| kNumArguments, |
| Object::empty_array(), |
| Resolver::kIsQualified)); |
| const Array& args = Array::Handle(Array::New(kNumArguments)); |
| args.SetAt(0, Integer::Handle(Integer::New(port_id))); |
| return DartEntry::InvokeFunction(function, args); |
| } |
| |
| |
| RawObject* DartLibraryCalls::MapSetAt(const Instance& map, |
| const Instance& key, |
| const Instance& value) { |
| const int kNumArguments = 3; |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(map, |
| Symbols::AssignIndexToken(), |
| kNumArguments, |
| 0)); |
| ASSERT(!function.IsNull()); |
| const Array& args = Array::Handle(Array::New(kNumArguments)); |
| args.SetAt(0, map); |
| args.SetAt(1, key); |
| args.SetAt(2, value); |
| const Object& result = Object::Handle(DartEntry::InvokeFunction(function, |
| args)); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::PortGetId(const Instance& port) { |
| const Class& cls = Class::Handle(port.clazz()); |
| const Library& isolate_lib = Library::Handle(Library::IsolateLibrary()); |
| const String& func_name = |
| String::Handle(isolate_lib.PrivateName( |
| String::Handle(Field::GetterName(Symbols::_id())))); |
| const Function& func = Function::Handle(cls.LookupDynamicFunction(func_name)); |
| ASSERT(!func.IsNull()); |
| const Array& args = Array::Handle(Array::New(1)); |
| args.SetAt(0, port); |
| return DartEntry::InvokeFunction(func, args); |
| } |
| |
| |
| } // namespace dart |