dart-sdk/runtime/vm/dart_entry.cc
Alexander Markov 5129cff930 [vm/aot] Discard Code objects from the heap
While deserializing AOT snapshot, Code objects which do not contain
valuable information besides entry point and stack maps are discarded
and not allocated on the heap (they are replaced with
StubCode::UnknownDartCode()).

PC -> Code/CompressedStackMaps lookup is implemented using a separate
table (InstructionsTable).

Flutter gallery in release-sizeopt mode:
Heap size of snapshot objects: arm -26.89%, arm64 -27.68%

Large Flutter application in release mode with --dwarf-stack-traces:
Heap size of snapshot objects: -24.3%.
Discarded Code objects: 72.5% of all Code objects.

Issue: https://github.com/dart-lang/sdk/issues/44852.

TEST=existing tests; "--dwarf_stack_traces --no-retain_function_objects
--no-retain_code_objects" mode is enabled for a few tests.

Change-Id: I5fe3e283630c8e8f4442319d5dcae38d174dd0d8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/189560
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2021-04-13 02:36:16 +00:00

849 lines
33 KiB
C++

// 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
if (FLAG_use_bare_instructions) {
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(!IsolateGroup::Current()->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 && FLAG_use_bare_instructions)
? 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 && FLAG_use_bare_instructions) {
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(thread);
}
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(receiver.ptr() == 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 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();
Function& function = Function::Handle(
zone,
thread->isolate_group()->object_store()->_object_to_string_function());
if (function.IsNull()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
function = core_lib.LookupFunctionAllowPrivate(Symbols::_objectToString());
ASSERT(!function.IsNull());
thread->isolate_group()->object_store()->set__object_to_string_function(
function);
}
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();
Function& function = Function::Handle(
zone,
thread->isolate_group()->object_store()->_object_hash_code_function());
if (function.IsNull()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
function = core_lib.LookupFunctionAllowPrivate(Symbols::_objectHashCode());
ASSERT(!function.IsNull());
thread->isolate_group()->object_store()->set__object_hash_code_function(
function);
}
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();
Function& function = Function::Handle(
zone, thread->isolate_group()->object_store()->_object_equals_function());
if (function.IsNull()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!core_lib.IsNull());
function = core_lib.LookupFunctionAllowPrivate(Symbols::_objectEquals());
ASSERT(!function.IsNull());
thread->isolate_group()->object_store()->set__object_equals_function(
function);
}
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();
}
// On success, returns an InstancePtr. On failure, an ErrorPtr.
ObjectPtr DartLibraryCalls::IdentityHashCode(const Instance& object) {
const int kNumArguments = 1;
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Library& libcore = Library::Handle(zone, Library::CoreLibrary());
ASSERT(!libcore.IsNull());
const Function& function = Function::Handle(
zone, libcore.LookupFunctionAllowPrivate(Symbols::identityHashCode()));
ASSERT(!function.IsNull());
const Array& args = Array::Handle(zone, Array::New(kNumArguments));
args.SetAt(0, object);
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* thread = Thread::Current();
Zone* zone = thread->zone();
Function& function = Function::Handle(
zone, thread->isolate_group()->object_store()->lookup_port_handler());
const int kTypeArgsLen = 0;
const int kNumArguments = 1;
if (function.IsNull()) {
Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name = String::Handle(
zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
const String& function_name = String::Handle(
zone, isolate_lib.PrivateName(Symbols::_lookupHandler()));
function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
kTypeArgsLen, kNumArguments,
Object::empty_array());
ASSERT(!function.IsNull());
thread->isolate_group()->object_store()->set_lookup_port_handler(function);
}
Array& args = Array::Handle(
zone, thread->isolate()->isolate_object_store()->dart_args_1());
if (args.IsNull()) {
args = Array::New(kNumArguments);
thread->isolate()->isolate_object_store()->set_dart_args_1(args);
}
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());
const int kTypeArgsLen = 0;
const int kNumArguments = 0;
if (function.IsNull()) {
Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name = String::Handle(
zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
const String& function_name = String::Handle(
zone, isolate_lib.PrivateName(Symbols::_lookupOpenPorts()));
function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
kTypeArgsLen, kNumArguments,
Object::empty_array());
ASSERT(!function.IsNull());
thread->isolate_group()->object_store()->set_lookup_open_ports(function);
}
const Object& result = Object::Handle(
zone, DartEntry::InvokeFunction(function, Object::empty_array()));
return result.ptr();
}
ObjectPtr DartLibraryCalls::HandleMessage(const Object& handler,
const Instance& message) {
auto thread = Thread::Current();
auto zone = thread->zone();
auto isolate = thread->isolate();
auto object_store = thread->isolate_group()->object_store();
Function& function =
Function::Handle(zone, object_store->handle_message_function());
const int kTypeArgsLen = 0;
const int kNumArguments = 2;
if (function.IsNull()) {
Library& isolate_lib = Library::Handle(zone, Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name = String::Handle(
zone, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
const String& function_name = String::Handle(
zone, isolate_lib.PrivateName(Symbols::_handleMessage()));
function = Resolver::ResolveStatic(isolate_lib, class_name, function_name,
kTypeArgsLen, kNumArguments,
Object::empty_array());
ASSERT(!function.IsNull());
object_store->set_handle_message_function(function);
}
Array& args =
Array::Handle(zone, isolate->isolate_object_store()->dart_args_2());
if (args.IsNull()) {
args = Array::New(kNumArguments);
isolate->isolate_object_store()->set_dart_args_2(args);
}
args.SetAt(0, handler);
args.SetAt(1, message);
#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
const Object& result =
Object::Handle(zone, DartEntry::InvokeFunction(function, args));
ASSERT(result.IsNull() || result.IsError());
return result.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();
}
} // namespace dart