blob: 0b79720ecff98bfa16d293f3e8fec790f2b5e204 [file] [log] [blame]
// 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 "platform/safe_stack.h"
#include "vm/class_finalizer.h"
#include "vm/debugger.h"
#include "vm/dispatch_table.h"
#include "vm/heap/safepoint.h"
#include "vm/object_store.h"
#include "vm/resolver.h"
#include "vm/runtime_entry.h"
#include "vm/simulator.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
#include "vm/zone_text_buffer.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/jit/compiler.h"
#endif // !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
DECLARE_FLAG(bool, precompiled_mode);
// A cache of VM heap allocated arguments descriptors.
ArrayPtr ArgumentsDescriptor::cached_args_descriptors_[kCachedDescriptorCount];
ObjectPtr DartEntry::InvokeFunction(const Function& function,
const Array& arguments) {
ASSERT(Thread::Current()->IsMutatorThread());
const int kTypeArgsLen = 0; // No support to pass type args to generic func.
const Array& arguments_descriptor = Array::Handle(
ArgumentsDescriptor::NewBoxed(kTypeArgsLen, arguments.Length()));
return InvokeFunction(function, arguments, arguments_descriptor);
}
class ScopedIsolateStackLimits : public ValueObject {
public:
NO_SANITIZE_SAFE_STACK
explicit ScopedIsolateStackLimits(Thread* thread, uword current_sp)
: thread_(thread) {
ASSERT(thread != NULL);
// Save the Thread's current stack limit and adjust the stack limit.
ASSERT(thread->isolate() == Isolate::Current());
saved_stack_limit_ = thread->saved_stack_limit();
#if defined(USING_SIMULATOR)
thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
#else
thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
#endif
#if defined(USING_SAFE_STACK)
saved_safestack_limit_ = OSThread::GetCurrentSafestackPointer();
thread->set_saved_safestack_limit(saved_safestack_limit_);
#endif
}
~ScopedIsolateStackLimits() {
ASSERT(thread_->isolate() == Isolate::Current());
// Since we started with a stack limit of 0 we should be getting back
// to a stack limit of 0 when all nested invocations are done and
// we have bottomed out.
thread_->SetStackLimit(saved_stack_limit_);
#if defined(USING_SAFE_STACK)
thread_->set_saved_safestack_limit(saved_safestack_limit_);
#endif
}
private:
Thread* thread_;
#if defined(USING_SAFE_STACK)
uword saved_safestack_limit_ = 0;
#endif
uword saved_stack_limit_ = 0;
};
// Clears/restores Thread::long_jump_base on construction/destruction.
// Ensures that we do not attempt to long jump across Dart frames.
class SuspendLongJumpScope : public ThreadStackResource {
public:
explicit SuspendLongJumpScope(Thread* thread)
: ThreadStackResource(thread),
saved_long_jump_base_(thread->long_jump_base()) {
thread->set_long_jump_base(NULL);
}
~SuspendLongJumpScope() {
ASSERT(thread()->long_jump_base() == NULL);
thread()->set_long_jump_base(saved_long_jump_base_);
}
private:
LongJumpScope* saved_long_jump_base_;
};
ObjectPtr DartEntry::InvokeFunction(const Function& function,
const Array& arguments,
const Array& arguments_descriptor,
uword current_sp) {
// We use a kernel2kernel constant evaluator in Dart 2.0 AOT compilation
// and never start the VM service isolate. So we should never end up invoking
// any dart code in the Dart 2.0 AOT compiler.
if (FLAG_precompiled_mode) {
#if !defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
Thread* thread = Thread::Current();
thread->set_global_object_pool(
thread->isolate_group()->object_store()->global_object_pool());
const DispatchTable* dispatch_table = thread->isolate()->dispatch_table();
if (dispatch_table != nullptr) {
thread->set_dispatch_table_array(dispatch_table->ArrayOrigin());
}
ASSERT(thread->global_object_pool() != Object::null());
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
ASSERT(!function.IsNull());
// Get the entrypoint corresponding to the function specified, this
// will result in a compilation of the function if it is not already
// compiled.
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
ASSERT(thread->IsMutatorThread());
ScopedIsolateStackLimits stack_limit(thread, current_sp);
#if !defined(DART_PRECOMPILED_RUNTIME)
if (!function.HasCode()) {
const Object& result =
Object::Handle(zone, Compiler::CompileFunction(thread, function));
if (result.IsError()) {
return Error::Cast(result).ptr();
}
// At this point we should have native code.
ASSERT(function.HasCode());
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
// Now Call the invoke stub which will invoke the dart function.
const Code& code = Code::Handle(zone, function.CurrentCode());
return InvokeCode(code, function.entry_point(), arguments_descriptor,
arguments, thread);
}
extern "C" {
// Note: The invocation stub follows the C ABI, so we cannot pass C++ struct
// values like ObjectPtr. In some calling conventions (IA32), ObjectPtr is
// passed/returned different from a pointer.
typedef uword /*ObjectPtr*/ (*invokestub)(const Code& target_code,
const Array& arguments_descriptor,
const Array& arguments,
Thread* thread);
typedef uword /*ObjectPtr*/ (*invokestub_bare_instructions)(
uword entry_point,
const Array& arguments_descriptor,
const Array& arguments,
Thread* thread);
}
NO_SANITIZE_SAFE_STACK
ObjectPtr DartEntry::InvokeCode(const Code& code,
uword entry_point,
const Array& arguments_descriptor,
const Array& arguments,
Thread* thread) {
ASSERT(!code.IsNull());
ASSERT(thread->no_callback_scope_depth() == 0);
ASSERT(!thread->isolate_group()->null_safety_not_set());
const uword stub = StubCode::InvokeDartCode().EntryPoint();
SuspendLongJumpScope suspend_long_jump_scope(thread);
TransitionToGenerated transition(thread);
#if defined(USING_SIMULATOR)
return bit_copy<ObjectPtr, int64_t>(Simulator::Current()->Call(
static_cast<intptr_t>(stub),
FLAG_precompiled_mode ? static_cast<intptr_t>(entry_point)
: reinterpret_cast<intptr_t>(&code),
reinterpret_cast<intptr_t>(&arguments_descriptor),
reinterpret_cast<intptr_t>(&arguments),
reinterpret_cast<intptr_t>(thread)));
#else
if (FLAG_precompiled_mode) {
return static_cast<ObjectPtr>(
(reinterpret_cast<invokestub_bare_instructions>(stub))(
entry_point, arguments_descriptor, arguments, thread));
} else {
return static_cast<ObjectPtr>((reinterpret_cast<invokestub>(stub))(
code, arguments_descriptor, arguments, thread));
}
#endif
}
ObjectPtr DartEntry::ResolveCallable(Thread* thread,
const Array& arguments,
const Array& arguments_descriptor) {
auto isolate_group = thread->isolate_group();
auto zone = thread->zone();
const ArgumentsDescriptor args_desc(arguments_descriptor);
const intptr_t receiver_index = args_desc.FirstArgIndex();
const intptr_t type_args_len = args_desc.TypeArgsLen();
const auto& getter_name = Symbols::GetCall();
auto& instance = Instance::Handle(zone);
auto& function = Function::Handle(zone);
auto& cls = Class::Handle(zone);
// The null instance cannot resolve to a callable, so we can stop there.
for (instance ^= arguments.At(receiver_index); !instance.IsNull();
instance ^= arguments.At(receiver_index)) {
// The instance is a callable, so check that its function is compatible.
if (instance.IsCallable(&function)) {
bool matches = function.AreValidArguments(args_desc, nullptr);
if (matches && type_args_len > 0 && function.IsClosureFunction()) {
// Though the closure function is generic, the closure itself may
// not be because it closes over delayed function type arguments.
matches = Closure::Cast(instance).IsGeneric();
}
if (matches) {
return function.ptr();
}
}
// Special case: closures are implemented with a call getter instead of a
// call method, so checking for a call getter would cause an infinite loop.
if (instance.IsClosure()) {
break;
}
cls = instance.clazz();
// Find a call getter, if any, in the class hierarchy.
function = Resolver::ResolveDynamicAnyArgs(zone, cls, getter_name,
/*allow_add=*/false);
if (function.IsNull()) {
break;
}
if (!OSThread::Current()->HasStackHeadroom()) {
const Instance& exception = Instance::Handle(
zone, isolate_group->object_store()->stack_overflow());
return UnhandledException::New(exception, StackTrace::Handle(zone));
}
const Array& getter_arguments = Array::Handle(zone, Array::New(1));
getter_arguments.SetAt(0, instance);
const Object& getter_result = Object::Handle(
zone, DartEntry::InvokeFunction(function, getter_arguments));
if (getter_result.IsError()) {
return getter_result.ptr();
}
ASSERT(getter_result.IsNull() || getter_result.IsInstance());
// We have a new possibly compatible callable, so set the first argument
// accordingly so it gets picked up in the main loop.
arguments.SetAt(receiver_index, getter_result);
}
// No compatible callable was found.
return Function::null();
}
ObjectPtr DartEntry::InvokeCallable(Thread* thread,
const Function& callable_function,
const Array& arguments,
const Array& arguments_descriptor) {
auto const zone = thread->zone();
const ArgumentsDescriptor args_desc(arguments_descriptor);
if (callable_function.IsNull()) {
// No compatible callable was found, so invoke noSuchMethod.
auto& instance =
Instance::CheckedHandle(zone, arguments.At(args_desc.FirstArgIndex()));
// For closures, use the name of the closure, not 'call'.
const String* target_name = &Symbols::Call();
if (instance.IsClosure()) {
auto const& function =
Function::Handle(zone, Closure::Cast(instance).function());
target_name = &String::Handle(function.QualifiedUserVisibleName());
}
return InvokeNoSuchMethod(thread, instance, *target_name, arguments,
arguments_descriptor);
}
const auto& result = Object::Handle(
zone, callable_function.DoArgumentTypesMatch(arguments, args_desc));
if (result.IsError()) {
return result.ptr();
}
return InvokeFunction(callable_function, arguments, arguments_descriptor);
}
ObjectPtr DartEntry::InvokeClosure(Thread* thread, const Array& arguments) {
auto const zone = thread->zone();
const int kTypeArgsLen = 0; // No support to pass type args to generic func.
// Closures always have boxed parameters
const Array& arguments_descriptor = Array::Handle(
zone, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, arguments.Length()));
return InvokeClosure(thread, arguments, arguments_descriptor);
}
ObjectPtr DartEntry::InvokeClosure(Thread* thread,
const Array& arguments,
const Array& arguments_descriptor) {
auto const zone = thread->zone();
const Object& resolved_result = Object::Handle(
zone, ResolveCallable(thread, arguments, arguments_descriptor));
if (resolved_result.IsError()) {
return resolved_result.ptr();
}
const auto& function =
Function::Handle(zone, Function::RawCast(resolved_result.ptr()));
return InvokeCallable(thread, function, arguments, arguments_descriptor);
}
ObjectPtr DartEntry::InvokeNoSuchMethod(Thread* thread,
const Instance& receiver,
const String& target_name,
const Array& arguments,
const Array& arguments_descriptor) {
auto const zone = thread->zone();
const ArgumentsDescriptor args_desc(arguments_descriptor);
ASSERT(
CompressedInstancePtr(receiver.ptr()).Decompress(thread->heap_base()) ==
arguments.At(args_desc.FirstArgIndex()));
// Allocate an Invocation object.
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
Class& invocation_mirror_class = Class::Handle(
zone, core_lib.LookupClass(String::Handle(
zone, core_lib.PrivateName(Symbols::InvocationMirror()))));
ASSERT(!invocation_mirror_class.IsNull());
const auto& error = invocation_mirror_class.EnsureIsFinalized(thread);
ASSERT(error == Error::null());
const String& function_name = String::Handle(
zone, core_lib.PrivateName(Symbols::AllocateInvocationMirror()));
const Function& allocation_function = Function::Handle(
zone, invocation_mirror_class.LookupStaticFunction(function_name));
ASSERT(!allocation_function.IsNull());
const int kNumAllocationArgs = 4;
const Array& allocation_args =
Array::Handle(zone, Array::New(kNumAllocationArgs));
allocation_args.SetAt(0, target_name);
allocation_args.SetAt(1, arguments_descriptor);
allocation_args.SetAt(2, arguments);
allocation_args.SetAt(3, Bool::False()); // Not a super invocation.
const Object& invocation_mirror = Object::Handle(
zone, InvokeFunction(allocation_function, allocation_args));
if (invocation_mirror.IsError()) {
Exceptions::PropagateError(Error::Cast(invocation_mirror));
UNREACHABLE();
}
// Now use the invocation mirror object and invoke NoSuchMethod.
const int kNumArguments = 2;
const Function& function = Function::Handle(
zone,
core_lib.LookupFunctionAllowPrivate(Symbols::_objectNoSuchMethod()));
ASSERT(!function.IsNull());
const Array& args = Array::Handle(zone, 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::TypeArgsLen() const {
return Smi::Value(Smi::RawCast(array_.At(kTypeArgsLenIndex)));
}
intptr_t ArgumentsDescriptor::Count() const {
return Smi::Value(Smi::RawCast(array_.At(kCountIndex)));
}
intptr_t ArgumentsDescriptor::Size() const {
return Smi::Value(Smi::RawCast(array_.At(kSizeIndex)));
}
intptr_t ArgumentsDescriptor::PositionalCount() const {
return Smi::Value(Smi::RawCast(array_.At(kPositionalCountIndex)));
}
StringPtr ArgumentsDescriptor::NameAt(intptr_t index) const {
const intptr_t offset =
kFirstNamedEntryIndex + (index * kNamedEntrySize) + kNameOffset;
String& result = String::Handle();
result ^= array_.At(offset);
return result.ptr();
}
intptr_t ArgumentsDescriptor::PositionAt(intptr_t index) const {
const intptr_t offset =
kFirstNamedEntryIndex + (index * kNamedEntrySize) + kPositionOffset;
return Smi::Value(Smi::RawCast(array_.At(offset)));
}
bool ArgumentsDescriptor::MatchesNameAt(intptr_t index,
const String& other) const {
return NameAt(index) == other.ptr();
}
ArrayPtr ArgumentsDescriptor::GetArgumentNames() const {
const intptr_t num_named_args = NamedCount();
if (num_named_args == 0) {
return Array::null();
}
Zone* zone = Thread::Current()->zone();
const Array& names =
Array::Handle(zone, Array::New(num_named_args, Heap::kOld));
String& name = String::Handle(zone);
const intptr_t num_pos_args = PositionalCount();
for (intptr_t i = 0; i < num_named_args; ++i) {
const intptr_t index = PositionAt(i) - num_pos_args;
name = NameAt(i);
ASSERT(names.At(index) == Object::null());
names.SetAt(index, name);
}
return names.ptr();
}
void ArgumentsDescriptor::PrintTo(BaseTextBuffer* buffer,
bool show_named_positions) const {
if (TypeArgsLen() > 0) {
buffer->Printf("<%" Pd ">", TypeArgsLen());
}
buffer->Printf("(%" Pd "", Count());
if (NamedCount() > 0) {
buffer->AddString(" {");
auto& str = String::Handle();
for (intptr_t i = 0; i < NamedCount(); i++) {
if (i != 0) {
buffer->AddString(", ");
}
str = NameAt(i);
buffer->Printf("%s", str.ToCString());
if (show_named_positions) {
buffer->Printf(" (%" Pd ")", PositionAt(i));
}
}
buffer->Printf("}");
}
buffer->Printf(")");
}
const char* ArgumentsDescriptor::ToCString() const {
ZoneTextBuffer buf(Thread::Current()->zone());
PrintTo(&buf);
return buf.buffer();
}
ArrayPtr ArgumentsDescriptor::New(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
const Array& optional_arguments_names,
Heap::Space space) {
const intptr_t num_named_args =
optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length();
if (num_named_args == 0) {
return ArgumentsDescriptor::New(type_args_len, num_arguments,
size_arguments, space);
}
ASSERT(type_args_len >= 0);
ASSERT(num_arguments >= 0);
const intptr_t num_pos_args = num_arguments - num_named_args;
// Build the arguments descriptor array, which consists of the type
// argument vector length (0 if none); 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.
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const intptr_t descriptor_len = LengthFor(num_named_args);
Array& descriptor = Array::Handle(zone, Array::New(descriptor_len, space));
// Set length of type argument vector.
descriptor.SetAt(kTypeArgsLenIndex, Smi::Handle(Smi::New(type_args_len)));
// Set total number of passed arguments.
descriptor.SetAt(kCountIndex, Smi::Handle(Smi::New(num_arguments)));
// Set total number of passed arguments.
descriptor.SetAt(kSizeIndex, Smi::Handle(Smi::New(size_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(zone);
Smi& pos = Smi::Handle(zone);
String& previous_name = String::Handle(zone);
Smi& previous_pos = Smi::Handle(zone);
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.
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::null_object());
// Share the immutable descriptor when possible by canonicalizing it.
descriptor.MakeImmutable();
descriptor ^= descriptor.Canonicalize(thread);
ASSERT(!descriptor.IsNull());
return descriptor.ptr();
}
ArrayPtr ArgumentsDescriptor::New(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
Heap::Space space) {
ASSERT(type_args_len >= 0);
ASSERT(num_arguments >= 0);
if ((type_args_len == 0) && (num_arguments < kCachedDescriptorCount) &&
(num_arguments == size_arguments)) {
return cached_args_descriptors_[num_arguments];
}
return NewNonCached(type_args_len, num_arguments, size_arguments, true,
space);
}
ArrayPtr ArgumentsDescriptor::NewNonCached(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
bool canonicalize,
Heap::Space space) {
// Build the arguments descriptor array, which consists of the length of the
// type argument vector, total argument count; the positional argument count;
// and a terminating null to simplify iterating in generated code.
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const intptr_t descriptor_len = LengthFor(0);
Array& descriptor = Array::Handle(zone, Array::New(descriptor_len, space));
const Smi& arg_count = Smi::Handle(zone, Smi::New(num_arguments));
const Smi& arg_size = Smi::Handle(zone, Smi::New(size_arguments));
// Set type argument vector length.
descriptor.SetAt(kTypeArgsLenIndex,
Smi::Handle(zone, Smi::New(type_args_len)));
// Set total number of passed arguments.
descriptor.SetAt(kCountIndex, arg_count);
// Set total size of passed arguments.
descriptor.SetAt(kSizeIndex, arg_size);
// Set number of positional arguments.
descriptor.SetAt(kPositionalCountIndex, arg_count);
// Set terminating null.
descriptor.SetAt((descriptor_len - 1), Object::null_object());
// Share the immutable descriptor when possible by canonicalizing it.
descriptor.MakeImmutable();
if (canonicalize) {
descriptor ^= descriptor.Canonicalize(thread);
}
ASSERT(!descriptor.IsNull());
return descriptor.ptr();
}
void ArgumentsDescriptor::Init() {
for (int i = 0; i < kCachedDescriptorCount; i++) {
cached_args_descriptors_[i] =
NewNonCached(/*type_args_len=*/0, i, i, false, Heap::kOld);
}
}
void ArgumentsDescriptor::Cleanup() {
for (int i = 0; i < kCachedDescriptorCount; i++) {
// Don't free pointers to RawArray objects managed by the VM.
cached_args_descriptors_[i] = NULL;
}
}
ObjectPtr DartLibraryCalls::InstanceCreate(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 = 1; // implicit rcvr arg.
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);
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.ptr();
}
return exception_object.ptr();
}
ObjectPtr DartLibraryCalls::ToString(const Instance& receiver) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const auto& function = Function::Handle(
zone,
thread->isolate_group()->object_store()->_object_to_string_function());
ASSERT(!function.IsNull());
const int kNumArguments = 1;
const Array& args = Array::Handle(zone, Array::New(kNumArguments));
args.SetAt(0, receiver);
const Object& result =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
ASSERT(result.IsInstance() || result.IsError());
return result.ptr();
}
ObjectPtr DartLibraryCalls::HashCode(const Instance& receiver) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const auto& function = Function::Handle(
zone,
thread->isolate_group()->object_store()->_object_hash_code_function());
ASSERT(!function.IsNull());
const int kNumArguments = 1;
const Array& args = Array::Handle(zone, Array::New(kNumArguments));
args.SetAt(0, receiver);
const Object& result =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
ASSERT(result.IsInstance() || result.IsError());
return result.ptr();
}
ObjectPtr DartLibraryCalls::Equals(const Instance& left,
const Instance& right) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const auto& function = Function::Handle(
zone, thread->isolate_group()->object_store()->_object_equals_function());
ASSERT(!function.IsNull());
const int kNumArguments = 2;
const Array& args = Array::Handle(zone, Array::New(kNumArguments));
args.SetAt(0, left);
args.SetAt(1, right);
const Object& result =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
ASSERT(result.IsInstance() || result.IsError());
return result.ptr();
}
ObjectPtr DartLibraryCalls::LookupHandler(Dart_Port port_id) {
Thread* const thread = Thread::Current();
Zone* const zone = thread->zone();
const auto& function = Function::Handle(
zone, thread->isolate_group()->object_store()->lookup_port_handler());
ASSERT(!function.IsNull());
Array& args = Array::Handle(
zone, thread->isolate()->isolate_object_store()->dart_args_1());
ASSERT(!args.IsNull());
args.SetAt(0, Integer::Handle(zone, Integer::New(port_id)));
const Object& result =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
return result.ptr();
}
ObjectPtr DartLibraryCalls::LookupOpenPorts() {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Function& function = Function::Handle(
zone, thread->isolate_group()->object_store()->lookup_open_ports());
ASSERT(!function.IsNull());
const Object& result = Object::Handle(
zone, DartEntry::InvokeFunction(function, Object::empty_array()));
return result.ptr();
}
static void DebuggerSetResumeIfStepping(Isolate* isolate) {
#if !defined(PRODUCT)
if (isolate->debugger()->IsStepping()) {
// If the isolate is being debugged and the debugger was stepping
// through code, enable single stepping so debugger will stop
// at the first location the user is interested in.
isolate->debugger()->SetResumeAction(Debugger::kStepInto);
}
#endif
}
ObjectPtr DartLibraryCalls::HandleMessage(Dart_Port port_id,
const Instance& message) {
auto* const thread = Thread::Current();
auto* const zone = thread->zone();
auto* const isolate = thread->isolate();
auto* const object_store = thread->isolate_group()->object_store();
const auto& function =
Function::Handle(zone, object_store->handle_message_function());
ASSERT(!function.IsNull());
Array& args =
Array::Handle(zone, isolate->isolate_object_store()->dart_args_2());
ASSERT(!args.IsNull());
args.SetAt(0, Integer::Handle(zone, Integer::New(port_id)));
args.SetAt(1, message);
DebuggerSetResumeIfStepping(isolate);
const Object& handler =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
return handler.ptr();
}
ObjectPtr DartLibraryCalls::HandleFinalizerMessage(
const FinalizerBase& finalizer) {
if (FLAG_trace_finalizers) {
THR_Print("Running finalizer %p callback on isolate %p\n",
finalizer.ptr()->untag(), finalizer.isolate());
}
auto* const thread = Thread::Current();
auto* const zone = thread->zone();
auto* const isolate = thread->isolate();
auto* const object_store = thread->isolate_group()->object_store();
auto& function = Function::Handle(zone);
if (finalizer.IsFinalizer()) {
function ^= object_store->handle_finalizer_message_function();
} else {
ASSERT(finalizer.IsNativeFinalizer());
function ^= object_store->handle_native_finalizer_message_function();
}
ASSERT(!function.IsNull());
Array& args =
Array::Handle(zone, isolate->isolate_object_store()->dart_args_1());
ASSERT(!args.IsNull());
args.SetAt(0, finalizer);
DebuggerSetResumeIfStepping(isolate);
const Object& handler =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
return handler.ptr();
}
ObjectPtr DartLibraryCalls::DrainMicrotaskQueue() {
Zone* zone = Thread::Current()->zone();
Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
Function& function =
Function::Handle(zone, isolate_lib.LookupFunctionAllowPrivate(
Symbols::_runPendingImmediateCallback()));
const Object& result = Object::Handle(
zone, DartEntry::InvokeFunction(function, Object::empty_array()));
ASSERT(result.IsNull() || result.IsError());
return result.ptr();
}
ObjectPtr DartLibraryCalls::EnsureScheduleImmediate() {
Zone* zone = Thread::Current()->zone();
const Library& async_lib = Library::Handle(zone, Library::AsyncLibrary());
ASSERT(!async_lib.IsNull());
const Function& function =
Function::Handle(zone, async_lib.LookupFunctionAllowPrivate(
Symbols::_ensureScheduleImmediate()));
ASSERT(!function.IsNull());
const Object& result = Object::Handle(
zone, DartEntry::InvokeFunction(function, Object::empty_array()));
ASSERT(result.IsNull() || result.IsError());
return result.ptr();
}
static ObjectPtr RehashObjects(Zone* zone,
const Library& library,
const Object& array_or_growable_array) {
ASSERT(array_or_growable_array.IsArray() ||
array_or_growable_array.IsGrowableObjectArray());
const auto& rehashing_function = Function::Handle(
zone, library.LookupFunctionAllowPrivate(Symbols::_rehashObjects()));
ASSERT(!rehashing_function.IsNull());
const auto& arguments = Array::Handle(zone, Array::New(1));
arguments.SetAt(0, array_or_growable_array);
return DartEntry::InvokeFunction(rehashing_function, arguments);
}
ObjectPtr DartLibraryCalls::RehashObjectsInDartCollection(
Thread* thread,
const Object& array_or_growable_array) {
auto zone = thread->zone();
const auto& collections_lib =
Library::Handle(zone, Library::CollectionLibrary());
return RehashObjects(zone, collections_lib, array_or_growable_array);
}
ObjectPtr DartLibraryCalls::RehashObjectsInDartCore(
Thread* thread,
const Object& array_or_growable_array) {
auto zone = thread->zone();
const auto& core_lib = Library::Handle(zone, Library::CoreLibrary());
return RehashObjects(zone, core_lib, array_or_growable_array);
}
} // namespace dart