| // 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/stub_code.h" |
| #include "vm/symbols.h" |
| |
| namespace dart { |
| |
| RawObject* DartEntry::InvokeDynamic( |
| const Instance& receiver, |
| const Function& function, |
| const GrowableArray<const Object*>& arguments, |
| const Array& optional_arguments_names) { |
| // 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(); |
| } |
| } |
| |
| // Set up arguments to include the receiver as the first argument. |
| const int num_arguments = arguments.length() + 1; |
| GrowableArray<const Object*> args(num_arguments); |
| const Object& arg0 = Object::ZoneHandle(receiver.raw()); |
| args.Add(&arg0); |
| for (int i = 1; i < num_arguments; i++) { |
| args.Add(arguments[i - 1]); |
| } |
| // Now Call the invoke stub which will invoke the dart function. |
| invokestub entrypoint = reinterpret_cast<invokestub>( |
| StubCode::InvokeDartCodeEntryPoint()); |
| const Context& context = |
| Context::ZoneHandle(Isolate::Current()->object_store()->empty_context()); |
| ASSERT(context.isolate() == Isolate::Current()); |
| const Code& code = Code::Handle(function.CurrentCode()); |
| ASSERT(!code.IsNull()); |
| return entrypoint( |
| code.EntryPoint(), |
| ArgumentsDescriptor(num_arguments, optional_arguments_names), |
| args.data(), |
| context); |
| } |
| |
| |
| RawObject* DartEntry::InvokeStatic( |
| const Function& function, |
| const GrowableArray<const Object*>& arguments, |
| const Array& optional_arguments_names) { |
| // Get the entrypoint corresponding to the function specified, this |
| // will result in a compilation of the function if it is not already |
| // compiled. |
| ASSERT(!function.IsNull()); |
| 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 Context& context = |
| Context::ZoneHandle(Isolate::Current()->object_store()->empty_context()); |
| ASSERT(context.isolate() == Isolate::Current()); |
| const Code& code = Code::Handle(function.CurrentCode()); |
| ASSERT(!code.IsNull()); |
| return entrypoint( |
| code.EntryPoint(), |
| ArgumentsDescriptor(arguments.length(), optional_arguments_names), |
| arguments.data(), |
| context); |
| } |
| |
| |
| RawObject* DartEntry::InvokeClosure( |
| const Instance& closure, |
| const GrowableArray<const Object*>& arguments, |
| const Array& optional_arguments_names) { |
| // Get the entrypoint corresponding to the closure specified, this |
| // will result in a compilation of the closure if it is not already |
| // compiled. |
| ASSERT(Class::Handle(closure.clazz()).signature_function() != Object::null()); |
| const Function& function = Function::Handle(Closure::function(closure)); |
| const Context& context = Context::Handle(Closure::context(closure)); |
| ASSERT(!function.IsNull()); |
| if (!function.HasCode()) { |
| const Error& error = Error::Handle(Compiler::CompileFunction(function)); |
| if (!error.IsNull()) { |
| return error.raw(); |
| } |
| } |
| // Set up arguments to include the closure as the first argument. |
| const int num_arguments = arguments.length() + 1; |
| GrowableArray<const Object*> args(num_arguments); |
| const Object& arg0 = Object::ZoneHandle(closure.raw()); |
| args.Add(&arg0); |
| for (int i = 1; i < num_arguments; i++) { |
| args.Add(arguments[i - 1]); |
| } |
| // Now Call the invoke stub which will invoke the closure. |
| invokestub entrypoint = reinterpret_cast<invokestub>( |
| StubCode::InvokeDartCodeEntryPoint()); |
| ASSERT(context.isolate() == Isolate::Current()); |
| const Code& code = Code::Handle(function.CurrentCode()); |
| ASSERT(!code.IsNull()); |
| return entrypoint( |
| code.EntryPoint(), |
| ArgumentsDescriptor(num_arguments, optional_arguments_names), |
| args.data(), |
| context); |
| } |
| |
| |
| const Array& DartEntry::ArgumentsDescriptor( |
| int num_arguments, |
| const Array& optional_arguments_names) { |
| const intptr_t num_named_args = |
| optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length(); |
| const intptr_t num_pos_args = num_arguments - num_named_args; |
| |
| // Build the argument descriptor array, which consists of the total number of |
| // arguments, the number of positional arguments, alphabetically sorted |
| // pairs of name/position, and a terminating null. |
| const int descriptor_len = 3 + (2 * num_named_args); |
| Array& descriptor = Array::ZoneHandle(Array::New(descriptor_len, Heap::kOld)); |
| |
| // Set total number of passed arguments. |
| descriptor.SetAt(0, Smi::Handle(Smi::New(num_arguments))); |
| // Set number of positional arguments. |
| descriptor.SetAt(1, Smi::Handle(Smi::New(num_pos_args))); |
| // Set alphabetically sorted pairs of name/position for named arguments. |
| String& name = String::Handle(); |
| Smi& pos = Smi::Handle(); |
| for (int i = 0; i < num_named_args; i++) { |
| name ^= optional_arguments_names.At(i); |
| pos = Smi::New(num_pos_args + i); |
| int j = i; |
| // Shift already inserted pairs with "larger" names. |
| String& name_j = String::Handle(); |
| Smi& pos_j = Smi::Handle(); |
| while (--j >= 0) { |
| name_j ^= descriptor.At(2 + (2 * j)); |
| const intptr_t result = name.CompareTo(name_j); |
| ASSERT(result != 0); // Duplicate argument names checked in parser. |
| if (result > 0) break; |
| pos_j ^= descriptor.At(3 + (2 * j)); |
| descriptor.SetAt(2 + (2 * (j + 1)), name_j); |
| descriptor.SetAt(3 + (2 * (j + 1)), pos_j); |
| } |
| // Insert pair in descriptor array. |
| descriptor.SetAt(2 + (2 * (j + 1)), name); |
| descriptor.SetAt(3 + (2 * (j + 1)), 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; |
| } |
| |
| |
| RawObject* DartLibraryCalls::ExceptionCreate( |
| const Library& lib, |
| const String& class_name, |
| const GrowableArray<const Object*>& 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 Instance& exception_object = Instance::Handle(Instance::New(cls)); |
| GrowableArray<const Object*> constructor_arguments(arguments.length() + 2); |
| constructor_arguments.Add(&exception_object); |
| constructor_arguments.Add(&Smi::Handle(Smi::New(Function::kCtorPhaseAll))); |
| constructor_arguments.AddArray(arguments); |
| |
| const String& period = String::Handle(Symbols::Dot()); |
| String& constructor_name = String::Handle(String::Concat(class_name, period)); |
| Function& constructor = |
| Function::Handle(cls.LookupConstructor(constructor_name)); |
| ASSERT(!constructor.IsNull()); |
| const Array& kNoArgumentNames = Array::Handle(); |
| const Object& retval = Object::Handle( |
| DartEntry::InvokeStatic(constructor, constructor_arguments, |
| kNoArgumentNames)); |
| ASSERT(retval.IsNull() || retval.IsError()); |
| if (retval.IsError()) { |
| return retval.raw(); |
| } |
| return exception_object.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::ToString(const Instance& receiver) { |
| const String& function_name = |
| String::Handle(Symbols::New("toString")); |
| GrowableArray<const Object*> arguments; |
| const int kNumArguments = 1; // Receiver. |
| const int kNumNamedArguments = 0; // None. |
| const Array& kNoArgumentNames = Array::Handle(); |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(receiver, |
| function_name, |
| kNumArguments, |
| kNumNamedArguments)); |
| ASSERT(!function.IsNull()); |
| const Object& result = Object::Handle( |
| DartEntry::InvokeDynamic(receiver, |
| function, |
| arguments, |
| kNoArgumentNames)); |
| ASSERT(result.IsInstance() || result.IsError()); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::Equals(const Instance& left, |
| const Instance& right) { |
| const String& function_name = String::Handle(Symbols::EqualOperator()); |
| GrowableArray<const Object*> arguments; |
| arguments.Add(&right); |
| const int kNumArguments = 2; |
| const int kNumNamedArguments = 0; |
| const Array& kNoArgumentNames = Array::Handle(); |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(left, |
| function_name, |
| kNumArguments, |
| kNumNamedArguments)); |
| ASSERT(!function.IsNull()); |
| const Object& result = Object::Handle( |
| DartEntry::InvokeDynamic(left, function, arguments, kNoArgumentNames)); |
| ASSERT(result.IsInstance() || result.IsError()); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::HandleMessage(Dart_Port dest_port_id, |
| Dart_Port reply_port_id, |
| const Instance& message) { |
| Library& isolate_lib = Library::Handle(Library::IsolateLibrary()); |
| ASSERT(!isolate_lib.IsNull()); |
| const String& public_class_name = |
| String::Handle(Symbols::New("_ReceivePortImpl")); |
| const String& class_name = |
| String::Handle(isolate_lib.PrivateName(public_class_name)); |
| const String& function_name = |
| String::Handle(Symbols::New("_handleMessage")); |
| const int kNumArguments = 3; |
| const Array& kNoArgumentNames = Array::Handle(); |
| const Function& function = Function::Handle( |
| Resolver::ResolveStatic(isolate_lib, |
| class_name, |
| function_name, |
| kNumArguments, |
| kNoArgumentNames, |
| Resolver::kIsQualified)); |
| GrowableArray<const Object*> arguments(kNumArguments); |
| arguments.Add(&Integer::Handle(Integer::New(dest_port_id))); |
| arguments.Add(&Integer::Handle(Integer::New(reply_port_id))); |
| arguments.Add(&message); |
| const Object& result = Object::Handle( |
| DartEntry::InvokeStatic(function, arguments, kNoArgumentNames)); |
| 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& public_class_name = |
| String::Handle(String::New("_SendPortImpl")); |
| const String& class_name = |
| String::Handle(isolate_lib.PrivateName(public_class_name)); |
| const String& function_name = String::Handle(Symbols::New("_create")); |
| const int kNumArguments = 1; |
| const Array& kNoArgumentNames = Array::Handle(); |
| const Function& function = Function::Handle( |
| Resolver::ResolveStatic(isolate_lib, |
| class_name, |
| function_name, |
| kNumArguments, |
| kNoArgumentNames, |
| Resolver::kIsQualified)); |
| GrowableArray<const Object*> arguments(kNumArguments); |
| arguments.Add(&Integer::Handle(Integer::New(port_id))); |
| return DartEntry::InvokeStatic(function, arguments, kNoArgumentNames); |
| } |
| |
| |
| RawObject* DartLibraryCalls::MapSetAt(const Instance& map, |
| const Instance& key, |
| const Instance& value) { |
| String& name = String::Handle(String::New("[]=")); |
| const Function& function = Function::Handle( |
| Resolver::ResolveDynamic(map, name, 3, 0)); |
| ASSERT(!function.IsNull()); |
| GrowableArray<const Object*> args(2); |
| args.Add(&key); |
| args.Add(&value); |
| const Array& kNoArgumentNames = Array::Handle(); |
| const Object& result = Object::Handle( |
| DartEntry::InvokeDynamic(map, function, args, kNoArgumentNames)); |
| return result.raw(); |
| } |
| |
| |
| RawObject* DartLibraryCalls::PortGetId(const Instance& port) { |
| const String& field_name = String::Handle(Symbols::New("_id")); |
| const Class& cls = Class::Handle(port.clazz()); |
| const String& func_name = String::Handle(Field::GetterName(field_name)); |
| const Function& func = Function::Handle(cls.LookupDynamicFunction(func_name)); |
| ASSERT(!func.IsNull()); |
| GrowableArray<const Object*> arguments; |
| const Array& kNoArgumentNames = Array::Handle(); |
| return DartEntry::InvokeDynamic(port, func, arguments, kNoArgumentNames); |
| } |
| |
| |
| } // namespace dart |