[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:
Régis Crelier
2018-06-13 23:30:44 +00:00
committed by commit-bot@chromium.org
parent db72134f90
commit 12b33ada44
12 changed files with 269 additions and 26 deletions
+1 -1
View File
@@ -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_[];
+1 -1
View File
@@ -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));
}
+1
View File
@@ -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);
+1 -1
View File
@@ -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
};
+4 -4
View File
@@ -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
View File
@@ -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();
}
+2 -2
View File
@@ -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());
+1 -1
View File
@@ -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);
+6
View File
@@ -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());
+1
View File
@@ -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) \