From 5f2bcd9d6c98b4bcb0367a331e11db9903bd9e6f Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Fri, 28 Jun 2019 23:05:21 +0000 Subject: [PATCH] [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 Commit-Queue: Alexander Markov --- .../frontend/bytecode_flow_graph_builder.cc | 416 ++++++------------ .../frontend/bytecode_flow_graph_builder.h | 9 + .../frontend/kernel_binary_flowgraph.cc | 34 +- runtime/vm/compiler/frontend/kernel_to_il.cc | 173 ++++++-- runtime/vm/compiler/frontend/kernel_to_il.h | 3 + runtime/vm/constants_kbc.h | 20 + 6 files changed, 311 insertions(+), 344 deletions(-) diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc index beda583c862..8dc9f49d595 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc @@ -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* default_values = + new (Z) ZoneGrowableArray( + Z, num_opt_pos_params + num_opt_named_params); + ZoneGrowableArray* raw_parameters = + new (Z) ZoneGrowableArray(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* default_values = - new (Z) ZoneGrowableArray( - Z, num_opt_pos_params + num_opt_named_params); - ZoneGrowableArray* raw_parameters = - new (Z) ZoneGrowableArray(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([int length]) { - // return (:arg_desc.positional_count == 2) ? new _List(length) - // : new _GrowableList(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(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()); diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h index 833deb208c3..e681a0942b1 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h @@ -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); diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index 89a647eceaa..fe75db77411 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -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(); diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 4b93026c729..3c813ede03a 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -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( diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h index 9ccc1a94f51..c7bc4bd9328 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.h +++ b/runtime/vm/compiler/frontend/kernel_to_il.h @@ -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); diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h index e29cb8334b4..08495728e9d 100644 --- a/runtime/vm/constants_kbc.h +++ b/runtime/vm/constants_kbc.h @@ -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; }