[vm/bytecode] Reuse flow graph building for recognized methods

Change-Id: Ia5aaad97d18d53fc0313713f00ff3403a41ac9c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107680
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2019-06-28 23:05:21 +00:00
committed by commit-bot@chromium.org
parent 0abff7b2bb
commit 5f2bcd9d6c
6 changed files with 311 additions and 344 deletions
@@ -252,6 +252,110 @@ void BytecodeFlowGraphBuilder::AllocateFixedParameters() {
parsed_function()->SetRawParameters(parameters);
}
const KBCInstr*
BytecodeFlowGraphBuilder::AllocateParametersAndLocalsForEntryOptional() {
ASSERT(KernelBytecode::IsEntryOptionalOpcode(bytecode_instr_));
const intptr_t num_fixed_params = DecodeOperandA().value();
const intptr_t num_opt_pos_params = DecodeOperandB().value();
const intptr_t num_opt_named_params = DecodeOperandC().value();
ASSERT(num_fixed_params == function().num_fixed_parameters());
ASSERT(num_opt_pos_params == function().NumOptionalPositionalParameters());
ASSERT(num_opt_named_params == function().NumOptionalNamedParameters());
ASSERT((num_opt_pos_params == 0) || (num_opt_named_params == 0));
const intptr_t num_load_const = num_opt_pos_params + 2 * num_opt_named_params;
const KBCInstr* instr = KernelBytecode::Next(bytecode_instr_);
const KBCInstr* frame_instr = instr;
for (intptr_t i = 0; i < num_load_const; ++i) {
frame_instr = KernelBytecode::Next(frame_instr);
}
ASSERT(KernelBytecode::IsFrameOpcode(frame_instr));
const intptr_t num_extra_locals = KernelBytecode::DecodeD(frame_instr);
const intptr_t num_params =
num_fixed_params + num_opt_pos_params + num_opt_named_params;
const intptr_t total_locals = num_params + num_extra_locals;
AllocateLocalVariables(Operand(total_locals), num_params);
ZoneGrowableArray<const Instance*>* default_values =
new (Z) ZoneGrowableArray<const Instance*>(
Z, num_opt_pos_params + num_opt_named_params);
ZoneGrowableArray<LocalVariable*>* raw_parameters =
new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_params);
intptr_t param = 0;
for (; param < num_fixed_params; ++param) {
LocalVariable* param_var = AllocateParameter(param, VariableIndex(-param));
raw_parameters->Add(param_var);
}
for (intptr_t i = 0; i < num_opt_pos_params; ++i, ++param) {
const KBCInstr* load_value_instr = instr;
instr = KernelBytecode::Next(instr);
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value_instr));
ASSERT(KernelBytecode::DecodeA(load_value_instr) == param);
const Object& default_value =
ConstantAt(Operand(KernelBytecode::DecodeE(load_value_instr))).value();
LocalVariable* param_var = AllocateParameter(param, VariableIndex(-param));
raw_parameters->Add(param_var);
default_values->Add(
&Instance::ZoneHandle(Z, Instance::RawCast(default_value.raw())));
}
if (num_opt_named_params > 0) {
default_values->EnsureLength(num_opt_named_params, nullptr);
raw_parameters->EnsureLength(num_params, nullptr);
ASSERT(scratch_var_ != nullptr);
for (intptr_t i = 0; i < num_opt_named_params; ++i, ++param) {
const KBCInstr* load_name_instr = instr;
const KBCInstr* load_value_instr = KernelBytecode::Next(load_name_instr);
instr = KernelBytecode::Next(load_value_instr);
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_name_instr));
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value_instr));
const String& param_name = String::Cast(
ConstantAt(Operand(KernelBytecode::DecodeE(load_name_instr)))
.value());
ASSERT(param_name.IsSymbol());
const Object& default_value =
ConstantAt(Operand(KernelBytecode::DecodeE(load_value_instr)))
.value();
intptr_t param_index = num_fixed_params;
for (; param_index < num_params; ++param_index) {
if (function().ParameterNameAt(param_index) == param_name.raw()) {
break;
}
}
ASSERT(param_index < num_params);
ASSERT(default_values->At(param_index - num_fixed_params) == nullptr);
(*default_values)[param_index - num_fixed_params] =
&Instance::ZoneHandle(Z, Instance::RawCast(default_value.raw()));
const intptr_t local_index = KernelBytecode::DecodeA(load_name_instr);
ASSERT(local_index == KernelBytecode::DecodeA(load_value_instr));
LocalVariable* param_var =
AllocateParameter(param_index, VariableIndex(-param));
ASSERT(raw_parameters->At(param_index) == nullptr);
(*raw_parameters)[param_index] = param_var;
}
}
ASSERT(instr == frame_instr);
parsed_function()->set_default_parameter_values(default_values);
parsed_function()->SetRawParameters(raw_parameters);
return KernelBytecode::Next(frame_instr);
}
LocalVariable* BytecodeFlowGraphBuilder::LocalVariableAt(intptr_t local_index) {
ASSERT(!is_generating_interpreter());
if (local_index < 0) {
@@ -469,104 +573,14 @@ void BytecodeFlowGraphBuilder::BuildEntryOptional() {
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
}
const intptr_t num_fixed_params = DecodeOperandA().value();
const intptr_t num_opt_pos_params = DecodeOperandB().value();
const intptr_t num_opt_named_params = DecodeOperandC().value();
ASSERT(num_fixed_params == function().num_fixed_parameters());
ASSERT(num_opt_pos_params == function().NumOptionalPositionalParameters());
ASSERT(num_opt_named_params == function().NumOptionalNamedParameters());
const KBCInstr* next_instr = AllocateParametersAndLocalsForEntryOptional();
ASSERT((num_opt_pos_params == 0) || (num_opt_named_params == 0));
const intptr_t num_load_const = num_opt_pos_params + 2 * num_opt_named_params;
const KBCInstr* instr = KernelBytecode::Next(bytecode_instr_);
const KBCInstr* frame_instr = instr;
for (intptr_t i = 0; i < num_load_const; ++i) {
frame_instr = KernelBytecode::Next(frame_instr);
}
ASSERT(KernelBytecode::IsFrameOpcode(frame_instr));
const intptr_t num_extra_locals = KernelBytecode::DecodeD(frame_instr);
const intptr_t num_params =
num_fixed_params + num_opt_pos_params + num_opt_named_params;
const intptr_t total_locals = num_params + num_extra_locals;
AllocateLocalVariables(Operand(total_locals), num_params);
ZoneGrowableArray<const Instance*>* default_values =
new (Z) ZoneGrowableArray<const Instance*>(
Z, num_opt_pos_params + num_opt_named_params);
ZoneGrowableArray<LocalVariable*>* raw_parameters =
new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_params);
LocalVariable* temp_var = nullptr;
intptr_t param = 0;
for (; param < num_fixed_params; ++param) {
LocalVariable* param_var = AllocateParameter(param, VariableIndex(-param));
raw_parameters->Add(param_var);
}
for (intptr_t i = 0; i < num_opt_pos_params; ++i, ++param) {
const KBCInstr* load_value_instr = instr;
instr = KernelBytecode::Next(instr);
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value_instr));
ASSERT(KernelBytecode::DecodeA(load_value_instr) == param);
const Object& default_value =
ConstantAt(Operand(KernelBytecode::DecodeE(load_value_instr))).value();
LocalVariable* param_var = AllocateParameter(param, VariableIndex(-param));
raw_parameters->Add(param_var);
default_values->Add(
&Instance::ZoneHandle(Z, Instance::RawCast(default_value.raw())));
}
if (num_opt_named_params > 0) {
default_values->EnsureLength(num_opt_named_params, nullptr);
raw_parameters->EnsureLength(num_params, nullptr);
if (function().HasOptionalNamedParameters()) {
ASSERT(scratch_var_ != nullptr);
temp_var = scratch_var_;
for (intptr_t i = 0; i < num_opt_named_params; ++i, ++param) {
const KBCInstr* load_name_instr = instr;
const KBCInstr* load_value_instr = KernelBytecode::Next(load_name_instr);
instr = KernelBytecode::Next(load_value_instr);
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_name_instr));
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value_instr));
const String& param_name = String::Cast(
ConstantAt(Operand(KernelBytecode::DecodeE(load_name_instr)))
.value());
ASSERT(param_name.IsSymbol());
const Object& default_value =
ConstantAt(Operand(KernelBytecode::DecodeE(load_value_instr)))
.value();
intptr_t param_index = num_fixed_params;
for (; param_index < num_params; ++param_index) {
if (function().ParameterNameAt(param_index) == param_name.raw()) {
break;
}
}
ASSERT(param_index < num_params);
ASSERT(default_values->At(param_index - num_fixed_params) == nullptr);
(*default_values)[param_index - num_fixed_params] =
&Instance::ZoneHandle(Z, Instance::RawCast(default_value.raw()));
const intptr_t local_index = KernelBytecode::DecodeA(load_name_instr);
ASSERT(local_index == KernelBytecode::DecodeA(load_value_instr));
LocalVariable* param_var =
AllocateParameter(param_index, VariableIndex(-param));
ASSERT(raw_parameters->At(param_index) == nullptr);
(*raw_parameters)[param_index] = param_var;
}
}
ASSERT(instr == frame_instr);
parsed_function()->set_default_parameter_values(default_values);
parsed_function()->SetRawParameters(raw_parameters);
Fragment copy_args_prologue;
// Code generated for EntryOptional is considered a prologue code.
@@ -599,7 +613,7 @@ void BytecodeFlowGraphBuilder::BuildEntryOptional() {
PrologueInfo(prologue_entry->block_id(), prologue_exit->block_id() - 1);
// Skip LoadConstant and Frame instructions.
next_pc_ = pc_ + (KernelBytecode::Next(instr) - bytecode_instr_);
next_pc_ = pc_ + (next_instr - bytecode_instr_);
ASSERT(IsStackEmpty());
}
@@ -892,194 +906,17 @@ void BytecodeFlowGraphBuilder::BuildNativeCall() {
}
ASSERT(function().is_native());
B->InlineBailout("BytecodeFlowGraphBuilder::BuildNativeCall");
// TODO(alexmarkov): find a way to avoid code duplication with
// FlowGraphBuilder::NativeFunctionBody.
const MethodRecognizer::Kind kind =
MethodRecognizer::RecognizeKind(function());
switch (kind) {
case MethodRecognizer::kObjectEquals:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->StrictCompare(Token::kEQ_STRICT);
break;
case MethodRecognizer::kStringBaseLength:
case MethodRecognizer::kStringBaseIsEmpty:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::String_length());
if (kind == MethodRecognizer::kStringBaseIsEmpty) {
code_ += B->IntConstant(0);
code_ += B->StrictCompare(Token::kEQ_STRICT);
}
break;
case MethodRecognizer::kGrowableArrayLength:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::GrowableObjectArray_length());
break;
case MethodRecognizer::kObjectArrayLength:
case MethodRecognizer::kImmutableArrayLength:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::Array_length());
break;
case MethodRecognizer::kTypedListLength:
case MethodRecognizer::kTypedListViewLength:
case MethodRecognizer::kByteDataViewLength:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::TypedDataBase_length());
break;
case MethodRecognizer::kClassIDgetID:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadClassId();
break;
case MethodRecognizer::kGrowableArrayCapacity:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::GrowableObjectArray_data());
code_ += B->LoadNativeField(Slot::Array_length());
break;
case MethodRecognizer::kListFactory: {
ASSERT((function().NumParameters() == 2) && !function().IsGeneric() &&
function().HasOptionalParameters());
ASSERT(scratch_var_ != nullptr);
// Generate code that performs:
//
// factory List<E>([int length]) {
// return (:arg_desc.positional_count == 2) ? new _List<E>(length)
// : new _GrowableList<E>(0);
// }
const auto& core_lib = Library::Handle(Z, Library::CoreLibrary());
TargetEntryInstr *allocate_non_growable, *allocate_growable;
code_ += B->Drop(); // Drop 'length'.
code_ += B->Drop(); // Drop 'type arguments'.
code_ += B->LoadArgDescriptor();
code_ += B->LoadNativeField(Slot::ArgumentsDescriptor_positional_count());
code_ += B->IntConstant(2);
code_ +=
B->BranchIfStrictEqual(&allocate_non_growable, &allocate_growable);
JoinEntryInstr* join = B->BuildJoinEntry();
{
const auto& cls = Class::Handle(
Z, core_lib.LookupClass(
Library::PrivateCoreLibName(Symbols::_List())));
ASSERT(!cls.IsNull());
const auto& func = Function::ZoneHandle(
Z, cls.LookupFactoryAllowPrivate(Symbols::_ListFactory()));
ASSERT(!func.IsNull());
code_ = Fragment(allocate_non_growable);
code_ += B->LoadLocal(LocalVariableAt(0));
code_ += B->LoadLocal(LocalVariableAt(1));
auto* call = new (Z) StaticCallInstr(
TokenPosition::kNoSource, func, 0, Array::null_array(),
GetArguments(2), *ic_data_array_, B->GetNextDeoptId(),
ICData::kStatic);
code_ <<= call;
B->Push(call);
code_ += B->StoreLocal(TokenPosition::kNoSource, scratch_var_);
code_ += B->Drop();
code_ += B->Goto(join);
}
{
const auto& cls = Class::Handle(
Z, core_lib.LookupClass(
Library::PrivateCoreLibName(Symbols::_GrowableList())));
ASSERT(!cls.IsNull());
const auto& func = Function::ZoneHandle(
Z, cls.LookupFactoryAllowPrivate(Symbols::_GrowableListFactory()));
ASSERT(!func.IsNull());
code_ = Fragment(allocate_growable);
code_ += B->LoadLocal(LocalVariableAt(0));
code_ += B->IntConstant(0);
auto* call = new (Z) StaticCallInstr(
TokenPosition::kNoSource, func, 0, Array::null_array(),
GetArguments(2), *ic_data_array_, B->GetNextDeoptId(),
ICData::kStatic);
code_ <<= call;
B->Push(call);
code_ += B->StoreLocal(TokenPosition::kNoSource, scratch_var_);
code_ += B->Drop();
code_ += B->Goto(join);
}
code_ = Fragment(join);
code_ += B->LoadLocal(scratch_var_);
break;
}
case MethodRecognizer::kObjectArrayAllocate:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->CreateArray();
break;
case MethodRecognizer::kLinkedHashMap_getIndex:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::LinkedHashMap_index());
break;
case MethodRecognizer::kLinkedHashMap_setIndex:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_index());
code_ += B->NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getData:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::LinkedHashMap_data());
break;
case MethodRecognizer::kLinkedHashMap_setData:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_data());
code_ += B->NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getHashMask:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::LinkedHashMap_hash_mask());
break;
case MethodRecognizer::kLinkedHashMap_setHashMask:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_hash_mask(),
kNoStoreBarrier);
code_ += B->NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getUsedData:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::LinkedHashMap_used_data());
break;
case MethodRecognizer::kLinkedHashMap_setUsedData:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_used_data(),
kNoStoreBarrier);
code_ += B->NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
ASSERT((function().NumParameters() == 1) && !function().IsGeneric());
code_ += B->LoadNativeField(Slot::LinkedHashMap_deleted_keys());
break;
case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
ASSERT((function().NumParameters() == 2) && !function().IsGeneric());
code_ += B->StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_deleted_keys(),
kNoStoreBarrier);
code_ += B->NullConstant();
break;
default: {
B->InlineBailout("BytecodeFlowGraphBuilder::BuildNativeCall");
const auto& name = String::ZoneHandle(Z, function().native_name());
const intptr_t num_args =
function().NumParameters() + (function().IsGeneric() ? 1 : 0);
ArgumentArray arguments = GetArguments(num_args);
auto* call =
new (Z) NativeCallInstr(&name, &function(), FLAG_link_natives_lazily,
function().end_token_pos(), arguments);
code_ <<= call;
B->Push(call);
break;
}
}
const auto& name = String::ZoneHandle(Z, function().native_name());
const intptr_t num_args =
function().NumParameters() + (function().IsGeneric() ? 1 : 0);
ArgumentArray arguments = GetArguments(num_args);
auto* call =
new (Z) NativeCallInstr(&name, &function(), FLAG_link_natives_lazily,
function().end_token_pos(), arguments);
code_ <<= call;
B->Push(call);
}
void BytecodeFlowGraphBuilder::BuildAllocate() {
@@ -1894,6 +1731,25 @@ void BytecodeFlowGraphBuilder::CollectControlFlow(
}
}
void BytecodeFlowGraphBuilder::CreateParameterVariables() {
const Bytecode& bytecode = Bytecode::Handle(Z, function().bytecode());
object_pool_ = bytecode.object_pool();
bytecode_instr_ = reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
if (KernelBytecode::IsEntryOptionalOpcode(bytecode_instr_)) {
scratch_var_ = parsed_function_->EnsureExpressionTemp();
AllocateParametersAndLocalsForEntryOptional();
} else if (KernelBytecode::IsEntryOpcode(bytecode_instr_)) {
AllocateLocalVariables(DecodeOperandD());
AllocateFixedParameters();
} else if (KernelBytecode::IsEntryFixedOpcode(bytecode_instr_)) {
AllocateLocalVariables(DecodeOperandE());
AllocateFixedParameters();
} else {
UNREACHABLE();
}
}
FlowGraph* BytecodeFlowGraphBuilder::BuildGraph() {
const Bytecode& bytecode = Bytecode::Handle(Z, function().bytecode());
@@ -44,6 +44,9 @@ class BytecodeFlowGraphBuilder {
FlowGraph* BuildGraph();
// Create parameter variables without building a flow graph.
void CreateParameterVariables();
protected:
// Returns `true` if building a flow graph for a bytecode interpreter, or
// `false` if compiling a function from bytecode.
@@ -122,6 +125,12 @@ class BytecodeFlowGraphBuilder {
LocalVariable* AllocateParameter(intptr_t param_index,
VariableIndex var_index);
void AllocateFixedParameters();
// Allocates parameters and local variables in case of EntryOptional.
// Returns pointer to the instruction after EntryOptional/LoadConstant/Frame
// bytecodes.
const KBCInstr* AllocateParametersAndLocalsForEntryOptional();
LocalVariable* LocalVariableAt(intptr_t local_index);
void StoreLocal(Operand local_index);
void LoadLocal(Operand local_index);
@@ -774,12 +774,6 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(
bool is_constructor) {
const Function& dart_function = parsed_function()->function();
// The prologue builder needs the default parameter values.
SetupDefaultParameterValues();
// TypeArgumentsHandling / BuildDefaultTypeHandling needs
// default function type arguments.
ReadDefaultFunctionTypeArguments(dart_function);
intptr_t type_parameters_offset = 0;
LocalVariable* first_parameter = nullptr;
TokenPosition token_position = TokenPosition::kNoSource;
@@ -961,9 +955,16 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraph() {
}
ASSERT(function.HasBytecode());
BytecodeFlowGraphBuilder bytecode_compiler(
flow_graph_builder_, parsed_function(),
&(flow_graph_builder_->ic_data_array_));
if (B->IsRecognizedMethodForFlowGraph(function)) {
bytecode_compiler.CreateParameterVariables();
return B->BuildGraphOfRecognizedMethod(function);
}
return bytecode_compiler.BuildGraph();
}
@@ -983,13 +984,12 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraph() {
case RawFunction::kRegularFunction:
case RawFunction::kGetterFunction:
case RawFunction::kSetterFunction:
case RawFunction::kClosureFunction: {
ReadUntilFunctionNode();
return BuildGraphOfFunction(false);
}
case RawFunction::kClosureFunction:
case RawFunction::kConstructor: {
ReadUntilFunctionNode();
return BuildGraphOfFunction(!function.IsFactory());
if (B->IsRecognizedMethodForFlowGraph(function)) {
return B->BuildGraphOfRecognizedMethod(function);
}
return BuildGraphOfFunction(function.IsGenerativeConstructor());
}
case RawFunction::kImplicitGetter:
case RawFunction::kImplicitStaticGetter:
@@ -1053,6 +1053,11 @@ void StreamingFlowGraphBuilder::ParseKernelASTFunction() {
case RawFunction::kSetterFunction:
case RawFunction::kClosureFunction:
case RawFunction::kConstructor:
case RawFunction::kImplicitClosureFunction:
ReadUntilFunctionNode();
SetupDefaultParameterValues();
ReadDefaultFunctionTypeArguments(function);
break;
case RawFunction::kImplicitGetter:
case RawFunction::kImplicitStaticGetter:
case RawFunction::kImplicitSetter:
@@ -1062,11 +1067,6 @@ void StreamingFlowGraphBuilder::ParseKernelASTFunction() {
case RawFunction::kInvokeFieldDispatcher:
case RawFunction::kFfiTrampoline:
break;
case RawFunction::kImplicitClosureFunction:
ReadUntilFunctionNode();
SetupDefaultParameterValues();
ReadDefaultFunctionTypeArguments(function);
break;
case RawFunction::kDynamicInvocationForwarder:
if (PeekTag() != kField) {
ReadUntilFunctionNode();
+126 -47
View File
@@ -741,13 +741,99 @@ FlowGraph* FlowGraphBuilder::BuildGraph() {
Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
LocalVariable* first_parameter) {
ASSERT(function.is_native());
// We explicitly build the graph for native functions in the same way that the
// from-source backend does. We should find a way to have a single component
// to build these graphs so that this code is not duplicated.
ASSERT(!IsRecognizedMethodForFlowGraph(function));
Fragment body;
String& name = String::ZoneHandle(Z, function.native_name());
if (function.IsGeneric()) {
body += LoadLocal(parsed_function_->RawTypeArgumentsVariable());
body += PushArgument();
}
for (intptr_t i = 0; i < function.NumParameters(); ++i) {
body += LoadLocal(parsed_function_->RawParameterVariable(i));
body += PushArgument();
}
body += NativeCall(&name, &function);
// We typecheck results of native calls for type safety.
body +=
Return(TokenPosition::kNoSource, /* omit_result_type_check = */ false);
return body;
}
bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
const Function& function) {
const MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
switch (kind) {
// On simdbc we fall back to natives.
#if !defined(TARGET_ARCH_DBC)
case MethodRecognizer::kTypedData_ByteDataView_factory:
case MethodRecognizer::kTypedData_Int8ArrayView_factory:
case MethodRecognizer::kTypedData_Uint8ArrayView_factory:
case MethodRecognizer::kTypedData_Uint8ClampedArrayView_factory:
case MethodRecognizer::kTypedData_Int16ArrayView_factory:
case MethodRecognizer::kTypedData_Uint16ArrayView_factory:
case MethodRecognizer::kTypedData_Int32ArrayView_factory:
case MethodRecognizer::kTypedData_Uint32ArrayView_factory:
case MethodRecognizer::kTypedData_Int64ArrayView_factory:
case MethodRecognizer::kTypedData_Uint64ArrayView_factory:
case MethodRecognizer::kTypedData_Float32ArrayView_factory:
case MethodRecognizer::kTypedData_Float64ArrayView_factory:
case MethodRecognizer::kTypedData_Float32x4ArrayView_factory:
case MethodRecognizer::kTypedData_Int32x4ArrayView_factory:
case MethodRecognizer::kTypedData_Float64x2ArrayView_factory:
#endif // !defined(TARGET_ARCH_DBC)
case MethodRecognizer::kObjectEquals:
case MethodRecognizer::kStringBaseLength:
case MethodRecognizer::kStringBaseIsEmpty:
case MethodRecognizer::kGrowableArrayLength:
case MethodRecognizer::kObjectArrayLength:
case MethodRecognizer::kImmutableArrayLength:
case MethodRecognizer::kTypedListLength:
case MethodRecognizer::kTypedListViewLength:
case MethodRecognizer::kByteDataViewLength:
case MethodRecognizer::kByteDataViewOffsetInBytes:
case MethodRecognizer::kTypedDataViewOffsetInBytes:
case MethodRecognizer::kByteDataViewTypedData:
case MethodRecognizer::kTypedDataViewTypedData:
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:
return true;
default:
return false;
}
}
FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
const Function& function) {
ASSERT(IsRecognizedMethodForFlowGraph(function));
graph_entry_ =
new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
auto normal_entry = BuildFunctionEntry(graph_entry_);
graph_entry_->set_normal_entry(normal_entry);
PrologueInfo prologue_info(-1, -1);
BlockEntryInstr* instruction_cursor =
BuildPrologue(normal_entry, &prologue_info);
Fragment body(instruction_cursor);
body += CheckStackOverflowInPrologue(function.token_pos());
const MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
bool omit_result_type_check = true;
switch (kind) {
// On simdbc we fall back to natives.
#if !defined(TARGET_ARCH_DBC)
@@ -812,13 +898,13 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
break;
#endif // !defined(TARGET_ARCH_DBC)
case MethodRecognizer::kObjectEquals:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body += StrictCompare(Token::kEQ_STRICT);
break;
case MethodRecognizer::kStringBaseLength:
case MethodRecognizer::kStringBaseIsEmpty:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::String_length());
if (kind == MethodRecognizer::kStringBaseIsEmpty) {
body += IntConstant(0);
@@ -826,36 +912,36 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
}
break;
case MethodRecognizer::kGrowableArrayLength:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::GrowableObjectArray_length());
break;
case MethodRecognizer::kObjectArrayLength:
case MethodRecognizer::kImmutableArrayLength:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::Array_length());
break;
case MethodRecognizer::kTypedListLength:
case MethodRecognizer::kTypedListViewLength:
case MethodRecognizer::kByteDataViewLength:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::TypedDataBase_length());
break;
case MethodRecognizer::kByteDataViewOffsetInBytes:
case MethodRecognizer::kTypedDataViewOffsetInBytes:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::TypedDataView_offset_in_bytes());
break;
case MethodRecognizer::kByteDataViewTypedData:
case MethodRecognizer::kTypedDataViewTypedData:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::TypedDataView_data());
break;
case MethodRecognizer::kClassIDgetID:
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadClassId();
break;
case MethodRecognizer::kGrowableArrayCapacity:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::GrowableObjectArray_data());
body += LoadNativeField(Slot::Array_length());
break;
@@ -885,9 +971,9 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
ASSERT(!func.IsNull());
Fragment allocate(allocate_non_growable);
allocate += LoadLocal(scopes_->type_arguments_variable);
allocate += LoadLocal(parsed_function_->RawParameterVariable(0));
allocate += PushArgument();
allocate += LoadLocal(first_parameter);
allocate += LoadLocal(parsed_function_->RawParameterVariable(1));
allocate += PushArgument();
allocate +=
StaticCall(TokenPosition::kNoSource, func, 2, ICData::kStatic);
@@ -907,7 +993,7 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
ASSERT(!func.IsNull());
Fragment allocate(allocate_growable);
allocate += LoadLocal(scopes_->type_arguments_variable);
allocate += LoadLocal(parsed_function_->RawParameterVariable(0));
allocate += PushArgument();
allocate += IntConstant(0);
allocate += PushArgument();
@@ -924,85 +1010,78 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
break;
}
case MethodRecognizer::kObjectArrayAllocate:
body += LoadLocal(scopes_->type_arguments_variable);
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body += CreateArray();
break;
case MethodRecognizer::kLinkedHashMap_getIndex:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::LinkedHashMap_index());
break;
case MethodRecognizer::kLinkedHashMap_setIndex:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body += StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_index());
body += NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getData:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::LinkedHashMap_data());
break;
case MethodRecognizer::kLinkedHashMap_setData:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body += StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_data());
body += NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getHashMask:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::LinkedHashMap_hash_mask());
break;
case MethodRecognizer::kLinkedHashMap_setHashMask:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body +=
StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_hash_mask(), kNoStoreBarrier);
body += NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getUsedData:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::LinkedHashMap_used_data());
break;
case MethodRecognizer::kLinkedHashMap_setUsedData:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body +=
StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_used_data(), kNoStoreBarrier);
body += NullConstant();
break;
case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadNativeField(Slot::LinkedHashMap_deleted_keys());
break;
case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
body += LoadLocal(parsed_function_->receiver_var());
body += LoadLocal(first_parameter);
body += LoadLocal(parsed_function_->RawParameterVariable(0));
body += LoadLocal(parsed_function_->RawParameterVariable(1));
body += StoreInstanceField(TokenPosition::kNoSource,
Slot::LinkedHashMap_deleted_keys(),
kNoStoreBarrier);
body += NullConstant();
break;
default: {
String& name = String::ZoneHandle(Z, function.native_name());
if (function.IsGeneric()) {
body += LoadLocal(parsed_function_->RawTypeArgumentsVariable());
body += PushArgument();
}
for (intptr_t i = 0; i < function.NumParameters(); ++i) {
body += LoadLocal(parsed_function_->RawParameterVariable(i));
body += PushArgument();
}
body += NativeCall(&name, &function);
// We typecheck results of native calls for type safety.
omit_result_type_check = false;
UNREACHABLE();
break;
}
}
return body + Return(TokenPosition::kNoSource, omit_result_type_check);
body += Return(TokenPosition::kNoSource, /* omit_result_type_check = */ true);
return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
prologue_info);
}
Fragment FlowGraphBuilder::BuildTypedDataViewFactoryConstructor(
@@ -107,6 +107,9 @@ class FlowGraphBuilder : public BaseFlowGraphBuilder {
Fragment NativeFunctionBody(const Function& function,
LocalVariable* first_parameter);
bool IsRecognizedMethodForFlowGraph(const Function& function);
FlowGraph* BuildGraphOfRecognizedMethod(const Function& function);
Fragment BuildTypedDataViewFactoryConstructor(const Function& function,
classid_t cid);
+20
View File
@@ -901,6 +901,26 @@ class KernelBytecode {
return DecodeOpcode(instr) == KernelBytecode::kCheckStack;
}
DART_FORCE_INLINE static bool IsEntryOpcode(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kEntry:
case KernelBytecode::kEntry_Wide:
return true;
default:
return false;
}
}
DART_FORCE_INLINE static bool IsEntryFixedOpcode(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
case KernelBytecode::kEntryFixed:
case KernelBytecode::kEntryFixed_Wide:
return true;
default:
return false;
}
}
DART_FORCE_INLINE static bool IsEntryOptionalOpcode(const KBCInstr* instr) {
return DecodeOpcode(instr) == KernelBytecode::kEntryOptional;
}