[VM interpreter] Support NativeCall kernel bytecode.
Change-Id: I89c905d17fb48447239ee4b0c1c8c50060239b88 Reviewed-on: https://dart-review.googlesource.com/59560 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Zach Anderson <zra@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
db72134f90
commit
12b33ada44
@@ -28,7 +28,7 @@ class Bootstrap : public AllStatic {
|
||||
intptr_t kernel_buffer_size);
|
||||
|
||||
static void SetupNativeResolver();
|
||||
static bool IsBootstapResolver(Dart_NativeEntryResolver resolver);
|
||||
static bool IsBootstrapResolver(Dart_NativeEntryResolver resolver);
|
||||
|
||||
// Source path mapping for library URI and 'parts'.
|
||||
static const char* async_source_paths_[];
|
||||
|
||||
@@ -136,7 +136,7 @@ void Bootstrap::SetupNativeResolver() {
|
||||
library.set_native_entry_symbol_resolver(symbol_resolver);
|
||||
}
|
||||
|
||||
bool Bootstrap::IsBootstapResolver(Dart_NativeEntryResolver resolver) {
|
||||
bool Bootstrap::IsBootstrapResolver(Dart_NativeEntryResolver resolver) {
|
||||
return (resolver ==
|
||||
reinterpret_cast<Dart_NativeEntryResolver>(BootstrapNatives::Lookup));
|
||||
}
|
||||
|
||||
@@ -344,6 +344,7 @@ void Precompiler::DoCompileAll(
|
||||
I->object_store()->set_completer_class(null_class);
|
||||
I->object_store()->set_symbol_class(null_class);
|
||||
I->object_store()->set_compiletime_error_class(null_class);
|
||||
I->object_store()->set_growable_list_factory(null_function);
|
||||
I->object_store()->set_simple_instance_of_function(null_function);
|
||||
I->object_store()->set_simple_instance_of_true_function(null_function);
|
||||
I->object_store()->set_simple_instance_of_false_function(null_function);
|
||||
|
||||
@@ -4630,7 +4630,7 @@ void NativeCallInstr::SetupNative() {
|
||||
const Library& library = Library::Handle(zone, cls.library());
|
||||
|
||||
Dart_NativeEntryResolver resolver = library.native_entry_resolver();
|
||||
bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver);
|
||||
bool is_bootstrap_native = Bootstrap::IsBootstrapResolver(resolver);
|
||||
set_is_bootstrap_native(is_bootstrap_native);
|
||||
|
||||
const int num_params =
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
|
||||
|
||||
#include "vm/bootstrap.h"
|
||||
#include "vm/code_descriptors.h"
|
||||
#include "vm/compiler/aot/precompiler.h"
|
||||
#include "vm/compiler/assembler/disassembler_kbc.h"
|
||||
#include "vm/compiler/frontend/prologue_builder.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/longjump.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/resolver.h"
|
||||
@@ -994,6 +997,7 @@ intptr_t BytecodeMetadataHelper::ReadPoolEntries(const Function& function,
|
||||
kContextOffset,
|
||||
kClosureFunction,
|
||||
kEndClosureFunctionScope,
|
||||
kNativeEntry,
|
||||
};
|
||||
|
||||
enum InvocationKind {
|
||||
@@ -1332,6 +1336,10 @@ intptr_t BytecodeMetadataHelper::ReadPoolEntries(const Function& function,
|
||||
pool.SetObjectAt(i, obj);
|
||||
return i; // The caller will close the scope.
|
||||
} break;
|
||||
case ConstantPoolTag::kNativeEntry: {
|
||||
name = H.DartString(builder_->ReadStringReference()).raw();
|
||||
obj = NativeEntry(function, name);
|
||||
} break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@@ -1412,6 +1420,87 @@ void BytecodeMetadataHelper::ReadExceptionsTable(const Code& bytecode) {
|
||||
bytecode.set_exception_handlers(Object::empty_exception_handlers());
|
||||
}
|
||||
}
|
||||
|
||||
RawTypedData* BytecodeMetadataHelper::NativeEntry(const Function& function,
|
||||
const String& external_name) {
|
||||
Zone* zone = builder_->zone_;
|
||||
MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
|
||||
// This list of recognized methods must be kept in sync with the list of
|
||||
// methods handled specially by the NativeCall bytecode in the interpreter.
|
||||
switch (kind) {
|
||||
case MethodRecognizer::kObjectEquals:
|
||||
case MethodRecognizer::kStringBaseLength:
|
||||
case MethodRecognizer::kStringBaseIsEmpty:
|
||||
case MethodRecognizer::kGrowableArrayLength:
|
||||
case MethodRecognizer::kObjectArrayLength:
|
||||
case MethodRecognizer::kImmutableArrayLength:
|
||||
case MethodRecognizer::kTypedDataLength:
|
||||
case MethodRecognizer::kClassIDgetID:
|
||||
case MethodRecognizer::kGrowableArrayCapacity:
|
||||
case MethodRecognizer::kListFactory:
|
||||
case MethodRecognizer::kObjectArrayAllocate:
|
||||
case MethodRecognizer::kLinkedHashMap_getIndex:
|
||||
case MethodRecognizer::kLinkedHashMap_setIndex:
|
||||
case MethodRecognizer::kLinkedHashMap_getData:
|
||||
case MethodRecognizer::kLinkedHashMap_setData:
|
||||
case MethodRecognizer::kLinkedHashMap_getHashMask:
|
||||
case MethodRecognizer::kLinkedHashMap_setHashMask:
|
||||
case MethodRecognizer::kLinkedHashMap_getUsedData:
|
||||
case MethodRecognizer::kLinkedHashMap_setUsedData:
|
||||
case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
|
||||
case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
|
||||
break;
|
||||
default:
|
||||
kind = MethodRecognizer::kUnknown;
|
||||
}
|
||||
NativeFunctionWrapper trampoline = NULL;
|
||||
NativeFunction native_function = NULL;
|
||||
intptr_t argc_tag = 0;
|
||||
if (kind == MethodRecognizer::kUnknown) {
|
||||
if (FLAG_link_natives_lazily) {
|
||||
trampoline = &NativeEntry::BootstrapNativeCallWrapper;
|
||||
native_function =
|
||||
reinterpret_cast<NativeFunction>(&NativeEntry::LinkNativeCall);
|
||||
} else {
|
||||
const Class& cls = Class::Handle(zone, function.Owner());
|
||||
const Library& library = Library::Handle(zone, cls.library());
|
||||
Dart_NativeEntryResolver resolver = library.native_entry_resolver();
|
||||
const bool is_bootstrap_native = Bootstrap::IsBootstrapResolver(resolver);
|
||||
const int num_params =
|
||||
NativeArguments::ParameterCountForResolution(function);
|
||||
bool is_auto_scope = true;
|
||||
native_function = NativeEntry::ResolveNative(library, external_name,
|
||||
num_params, &is_auto_scope);
|
||||
ASSERT(native_function != NULL); // TODO(regis): Should we throw instead?
|
||||
if (is_bootstrap_native) {
|
||||
trampoline = &NativeEntry::BootstrapNativeCallWrapper;
|
||||
} else if (is_auto_scope) {
|
||||
trampoline = &NativeEntry::AutoScopeNativeCallWrapper;
|
||||
} else {
|
||||
trampoline = &NativeEntry::NoScopeNativeCallWrapper;
|
||||
}
|
||||
}
|
||||
argc_tag = NativeArguments::ComputeArgcTag(function);
|
||||
}
|
||||
// TODO(regis): Introduce a new VM class subclassing Object and containing
|
||||
// these four untagged values.
|
||||
#ifdef ARCH_IS_32_BIT
|
||||
const TypedData& native_entry = TypedData::Handle(
|
||||
zone, TypedData::New(kTypedDataUint32ArrayCid, 4, Heap::kOld));
|
||||
native_entry.SetUint32(0 << 2, static_cast<uint32_t>(kind));
|
||||
native_entry.SetUint32(1 << 2, reinterpret_cast<uint32_t>(trampoline));
|
||||
native_entry.SetUint32(2 << 2, reinterpret_cast<uint32_t>(native_function));
|
||||
native_entry.SetUint32(3 << 2, static_cast<uint32_t>(argc_tag));
|
||||
#else
|
||||
const TypedData& native_entry = TypedData::Handle(
|
||||
zone, TypedData::New(kTypedDataUint64ArrayCid, 4, Heap::kOld));
|
||||
native_entry.SetUint64(0 << 3, static_cast<uint64_t>(kind));
|
||||
native_entry.SetUint64(1 << 3, reinterpret_cast<uint64_t>(trampoline));
|
||||
native_entry.SetUint64(2 << 3, reinterpret_cast<uint64_t>(native_function));
|
||||
native_entry.SetUint64(3 << 3, static_cast<uint64_t>(argc_tag));
|
||||
#endif
|
||||
return native_entry.raw();
|
||||
}
|
||||
#endif // defined(DART_USE_INTERPRETER)
|
||||
|
||||
StreamingScopeBuilder::StreamingScopeBuilder(ParsedFunction* parsed_function)
|
||||
|
||||
@@ -686,6 +686,8 @@ class BytecodeMetadataHelper : public MetadataHelper {
|
||||
intptr_t from_index);
|
||||
RawCode* ReadBytecode(const ObjectPool& pool);
|
||||
void ReadExceptionsTable(const Code& bytecode);
|
||||
RawTypedData* NativeEntry(const Function& function,
|
||||
const String& external_name);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -165,10 +165,10 @@ namespace dart {
|
||||
// with arguments SP[-(1+ArgC)], ..., SP[-1].
|
||||
// The ICData indicates whether the first argument is a type argument vector.
|
||||
//
|
||||
// - NativeCall ArgA, ArgB, ArgC
|
||||
// - NativeCall D
|
||||
//
|
||||
// Invoke native function at pool[ArgB] with argc_tag at pool[ArgC] using
|
||||
// wrapper at pool[ArgA].
|
||||
// Invoke native function described by array at pool[D].
|
||||
// array[0] is wrapper, array[1] is function, array[2] is argc_tag.
|
||||
//
|
||||
// - PushPolymorphicInstanceCall ArgC, D
|
||||
//
|
||||
@@ -791,7 +791,7 @@ namespace dart {
|
||||
V(InstanceCall2Opt, A_D, num, num, ___) \
|
||||
V(PushPolymorphicInstanceCall, A_D, num, num, ___) \
|
||||
V(PushPolymorphicInstanceCallByRange, A_D, num, num, ___) \
|
||||
V(NativeCall, A_B_C, num, num, num) \
|
||||
V(NativeCall, D, lit, ___, ___) \
|
||||
V(OneByteStringFromCharCode, A_X, reg, xeg, ___) \
|
||||
V(StringToCharCode, A_X, reg, xeg, ___) \
|
||||
V(AddTOS, 0, ___, ___, ___) \
|
||||
|
||||
+160
-16
@@ -2135,25 +2135,169 @@ RawObject* Interpreter::Call(const Code& code,
|
||||
}
|
||||
|
||||
{
|
||||
BYTECODE(NativeCall, A_B_C);
|
||||
NativeFunctionWrapper trampoline =
|
||||
reinterpret_cast<NativeFunctionWrapper>(LOAD_CONSTANT(rA));
|
||||
Dart_NativeFunction function =
|
||||
reinterpret_cast<Dart_NativeFunction>(LOAD_CONSTANT(rB));
|
||||
intptr_t argc_tag = reinterpret_cast<intptr_t>(LOAD_CONSTANT(rC));
|
||||
const intptr_t num_arguments = NativeArguments::ArgcBits::decode(argc_tag);
|
||||
BYTECODE(NativeCall, __D);
|
||||
RawTypedData* native_entry = static_cast<RawTypedData*>(LOAD_CONSTANT(rD));
|
||||
// TODO(regis): Introduce a new VM class subclassing Object and containing
|
||||
// the four untagged values currently stored as TypeData array elements.
|
||||
MethodRecognizer::Kind kind =
|
||||
static_cast<MethodRecognizer::Kind>(*(reinterpret_cast<uintptr_t*>(
|
||||
native_entry->ptr()->data() + (0 << kWordSizeLog2))));
|
||||
switch (kind) {
|
||||
case MethodRecognizer::kObjectEquals: {
|
||||
SP[-1] = SP[-1] == SP[0] ? Bool::True().raw() : Bool::False().raw();
|
||||
SP--;
|
||||
} break;
|
||||
case MethodRecognizer::kStringBaseLength:
|
||||
case MethodRecognizer::kStringBaseIsEmpty: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[String::length_offset() / kWordSize];
|
||||
if (kind == MethodRecognizer::kStringBaseIsEmpty) {
|
||||
SP[0] =
|
||||
SP[0] == Smi::New(0) ? Bool::True().raw() : Bool::False().raw();
|
||||
}
|
||||
} break;
|
||||
case MethodRecognizer::kGrowableArrayLength: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[GrowableObjectArray::length_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kObjectArrayLength:
|
||||
case MethodRecognizer::kImmutableArrayLength: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[Array::length_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kTypedDataLength: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[TypedData::length_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kClassIDgetID: {
|
||||
SP[0] = InterpreterHelpers::GetClassIdAsSmi(SP[0]);
|
||||
} break;
|
||||
case MethodRecognizer::kGrowableArrayCapacity: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
instance = reinterpret_cast<RawInstance**>(
|
||||
instance->ptr())[GrowableObjectArray::data_offset() / kWordSize];
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[Array::length_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kListFactory: {
|
||||
// factory List<E>([int length]) {
|
||||
// return (:arg_desc.positional_count == 2) ? new _List<E>(length)
|
||||
// : new _GrowableList<E>(0);
|
||||
// }
|
||||
if (InterpreterHelpers::ArgDescPosCount(argdesc_) == 2) {
|
||||
SP[1] = SP[0]; // length
|
||||
SP[2] = SP[-1]; // type
|
||||
Exit(thread, FP, SP + 3, pc);
|
||||
NativeArguments native_args(thread, 2, SP + 1, SP - 1);
|
||||
INVOKE_RUNTIME(DRT_AllocateArray, native_args);
|
||||
SP -= 1; // Result is in SP - 1.
|
||||
} else {
|
||||
// SP[0] is type.
|
||||
*++SP = Smi::New(0); // len
|
||||
*++SP = thread->isolate()->object_store()->growable_list_factory();
|
||||
argdesc_ = ArgumentsDescriptor::New(0, 2); // Returns a cached desc.
|
||||
if (!Invoke(thread, SP - 2, SP, &pc, &FP, &SP)) {
|
||||
HANDLE_EXCEPTION;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case MethodRecognizer::kObjectArrayAllocate: {
|
||||
SP[1] = SP[0]; // length
|
||||
SP[2] = SP[-1]; // type
|
||||
Exit(thread, FP, SP + 3, pc);
|
||||
NativeArguments native_args(thread, 2, SP + 1, SP - 1);
|
||||
INVOKE_RUNTIME(DRT_AllocateArray, native_args);
|
||||
SP -= 1; // Result is in SP - 1.
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_getIndex: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::index_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_setIndex: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
||||
reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::index_offset() / kWordSize] = SP[0];
|
||||
*--SP = null_value;
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_getData: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::data_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_setData: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
||||
reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::data_offset() / kWordSize] = SP[0];
|
||||
*--SP = null_value;
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_getHashMask: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::hash_mask_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_setHashMask: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
||||
reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::hash_mask_offset() / kWordSize] =
|
||||
SP[0];
|
||||
*--SP = null_value;
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_getUsedData: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::used_data_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_setUsedData: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
||||
reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::used_data_offset() / kWordSize] =
|
||||
SP[0];
|
||||
*--SP = null_value;
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_getDeletedKeys: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[0]);
|
||||
SP[0] = reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::deleted_keys_offset() / kWordSize];
|
||||
} break;
|
||||
case MethodRecognizer::kLinkedHashMap_setDeletedKeys: {
|
||||
RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
||||
reinterpret_cast<RawObject**>(
|
||||
instance->ptr())[LinkedHashMap::deleted_keys_offset() / kWordSize] =
|
||||
SP[0];
|
||||
*--SP = null_value;
|
||||
} break;
|
||||
default: {
|
||||
NativeFunctionWrapper trampoline =
|
||||
reinterpret_cast<NativeFunctionWrapper>(
|
||||
*(reinterpret_cast<uintptr_t*>(native_entry->ptr()->data() +
|
||||
(1 << kWordSizeLog2))));
|
||||
Dart_NativeFunction function = reinterpret_cast<Dart_NativeFunction>(
|
||||
*(reinterpret_cast<uintptr_t*>(native_entry->ptr()->data() +
|
||||
(2 << kWordSizeLog2))));
|
||||
intptr_t argc_tag =
|
||||
static_cast<intptr_t>(*(reinterpret_cast<uintptr_t*>(
|
||||
native_entry->ptr()->data() + (3 << kWordSizeLog2))));
|
||||
const intptr_t num_arguments =
|
||||
NativeArguments::ArgcBits::decode(argc_tag);
|
||||
|
||||
*++SP = null_value; // Result slot.
|
||||
*++SP = null_value; // Result slot.
|
||||
|
||||
RawObject** incoming_args = SP - num_arguments;
|
||||
RawObject** return_slot = SP;
|
||||
Exit(thread, FP, SP, pc);
|
||||
NativeArguments args(thread, argc_tag, incoming_args, return_slot);
|
||||
INVOKE_NATIVE(trampoline, function,
|
||||
reinterpret_cast<Dart_NativeArguments>(&args));
|
||||
RawObject** incoming_args = SP - num_arguments;
|
||||
RawObject** return_slot = SP;
|
||||
Exit(thread, FP, SP, pc);
|
||||
NativeArguments args(thread, argc_tag, incoming_args, return_slot);
|
||||
INVOKE_NATIVE(trampoline, function,
|
||||
reinterpret_cast<Dart_NativeArguments>(&args));
|
||||
|
||||
*(SP - num_arguments) = *return_slot;
|
||||
SP -= num_arguments;
|
||||
*(SP - num_arguments) = *return_slot;
|
||||
SP -= num_arguments;
|
||||
}
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ void NativeEntry::PropagateErrors(NativeArguments* arguments) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARCH_DBC)
|
||||
#if defined(TARGET_ARCH_DBC) || defined(DART_USE_INTERPRETER)
|
||||
uword NativeEntry::BootstrapNativeCallWrapperEntry() {
|
||||
uword entry =
|
||||
reinterpret_cast<uword>(NativeEntry::BootstrapNativeCallWrapper);
|
||||
@@ -223,7 +223,7 @@ static NativeFunction ResolveNativeFunction(Zone* zone,
|
||||
const Library& library = Library::Handle(zone, cls.library());
|
||||
|
||||
*is_bootstrap_native =
|
||||
Bootstrap::IsBootstapResolver(library.native_entry_resolver());
|
||||
Bootstrap::IsBootstrapResolver(library.native_entry_resolver());
|
||||
|
||||
const String& native_name = String::Handle(zone, func.native_name());
|
||||
ASSERT(!native_name.IsNull());
|
||||
|
||||
@@ -129,7 +129,7 @@ class NativeEntry : public AllStatic {
|
||||
uword pc);
|
||||
static const uint8_t* ResolveSymbol(uword pc);
|
||||
|
||||
#if defined(TARGET_ARCH_DBC)
|
||||
#if defined(TARGET_ARCH_DBC) || defined(DART_USE_INTERPRETER)
|
||||
static uword BootstrapNativeCallWrapperEntry();
|
||||
static void BootstrapNativeCallWrapper(Dart_NativeArguments args,
|
||||
Dart_NativeFunction func);
|
||||
|
||||
@@ -221,6 +221,12 @@ void ObjectStore::InitKnownObjects() {
|
||||
ASSERT(!cls.IsNull());
|
||||
set_pragma_class(cls);
|
||||
|
||||
cls = core_lib.LookupClassAllowPrivate(Symbols::_GrowableList());
|
||||
ASSERT(!cls.IsNull());
|
||||
growable_list_factory_ =
|
||||
cls.LookupFactoryAllowPrivate(Symbols::_GrowableListFactory());
|
||||
ASSERT(growable_list_factory_ != Function::null());
|
||||
|
||||
// Cache the core private functions used for fast instance of checks.
|
||||
simple_instance_of_function_ =
|
||||
PrivateObjectLookup(Symbols::_simpleInstanceOf());
|
||||
|
||||
@@ -108,6 +108,7 @@ class ObjectPointerVisitor;
|
||||
RW(Function, lookup_port_handler) \
|
||||
RW(TypedData, empty_uint32_array) \
|
||||
RW(Function, handle_message_function) \
|
||||
RW(Function, growable_list_factory) \
|
||||
RW(Function, simple_instance_of_function) \
|
||||
RW(Function, simple_instance_of_true_function) \
|
||||
RW(Function, simple_instance_of_false_function) \
|
||||
|
||||
Reference in New Issue
Block a user