// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_ #define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_ #include "vm/compiler/backend/il.h" #include "vm/compiler/frontend/base_flow_graph_builder.h" #include "vm/constants_kbc.h" #if !defined(DART_PRECOMPILED_RUNTIME) namespace dart { namespace kernel { // This class builds flow graph from bytecode. It is used either to compile // from bytecode, or generate bytecode interpreter (the latter is not // fully implemented yet). // TODO(alexmarkov): extend this class and IL to generate an interpreter in // addition to compiling bytecode. class BytecodeFlowGraphBuilder { public: BytecodeFlowGraphBuilder(BaseFlowGraphBuilder* flow_graph_builder, ParsedFunction* parsed_function, ZoneGrowableArray* ic_data_array) : flow_graph_builder_(flow_graph_builder), zone_(flow_graph_builder->zone_), is_generating_interpreter_( false), // TODO(alexmarkov): pass as argument parsed_function_(parsed_function), ic_data_array_(ic_data_array), object_pool_(ObjectPool::Handle(zone_)), bytecode_length_(0), pc_(0), position_(TokenPosition::kNoSource), local_vars_(zone_, 0), parameters_(zone_, 0), exception_var_(nullptr), stacktrace_var_(nullptr), scratch_var_(nullptr), prologue_info_(-1, -1), throw_no_such_method_(nullptr) {} FlowGraph* BuildGraph(); protected: // Returns `true` if building a flow graph for a bytecode interpreter, or // `false` if compiling a function from bytecode. bool is_generating_interpreter() const { return is_generating_interpreter_; } private: // Operand of bytecode instruction, either intptr_t value (if compiling // bytecode) or Definition (if generating interpreter). class Operand { public: explicit Operand(Definition* definition) : definition_(definition), value_(0) { ASSERT(definition != nullptr); } explicit Operand(intptr_t value) : definition_(nullptr), value_(value) {} Definition* definition() const { ASSERT(definition_ != nullptr); return definition_; } intptr_t value() const { ASSERT(definition_ == nullptr); return value_; } private: Definition* definition_; intptr_t value_; }; // Constant from a constant pool. // It is either Object (if compiling bytecode) or Definition // (if generating interpreter). class Constant { public: explicit Constant(Definition* definition) : definition_(definition), value_(Object::null_object()) { ASSERT(definition != nullptr); } explicit Constant(Zone* zone, const Object& value) : definition_(nullptr), value_(value) {} Definition* definition() const { ASSERT(definition_ != nullptr); return definition_; } const Object& value() const { ASSERT(definition_ == nullptr); return value_; } private: Definition* definition_; const Object& value_; }; Operand DecodeOperandA(); Operand DecodeOperandB(); Operand DecodeOperandC(); Operand DecodeOperandD(); Operand DecodeOperandE(); Operand DecodeOperandF(); Operand DecodeOperandX(); Operand DecodeOperandY(); Operand DecodeOperandT(); Constant ConstantAt(Operand entry_index, intptr_t add_index = 0); void PushConstant(Constant constant); Constant PopConstant(); void LoadStackSlots(intptr_t num_slots); void AllocateLocalVariables(Operand frame_size, intptr_t num_param_locals = 0); LocalVariable* AllocateParameter(intptr_t param_index, VariableIndex var_index); void AllocateFixedParameters(); LocalVariable* LocalVariableAt(intptr_t local_index); void StoreLocal(Operand local_index); void LoadLocal(Operand local_index); Value* Pop(); intptr_t GetStackDepth() const; bool IsStackEmpty() const; ArgumentArray GetArguments(int count); void PropagateStackState(intptr_t target_pc); void DropUnusedValuesFromStack(); void BuildJumpIfStrictCompare(Token::Kind cmp_kind); void BuildPrimitiveOp(const String& name, Token::Kind token_kind, const AbstractType& static_receiver_type, int num_args); void BuildIntOp(const String& name, Token::Kind token_kind, int num_args); void BuildDoubleOp(const String& name, Token::Kind token_kind, int num_args); void BuildInterfaceCallCommon(bool is_unchecked_call); void BuildInstruction(KernelBytecode::Opcode opcode); #define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3) \ void Build##name(); KERNEL_BYTECODES_LIST(DECLARE_BUILD_METHOD) #undef DECLARE_BUILD_METHOD void ProcessICDataInObjectPool(const ObjectPool& object_pool); intptr_t GetTryIndex(const PcDescriptors& descriptors, intptr_t pc); JoinEntryInstr* EnsureControlFlowJoin(const PcDescriptors& descriptors, intptr_t pc); bool RequiresScratchVar(const KBCInstr* instr); void CollectControlFlow(const PcDescriptors& descriptors, const ExceptionHandlers& handlers, GraphEntryInstr* graph_entry); Thread* thread() const { return flow_graph_builder_->thread_; } Isolate* isolate() const { return thread()->isolate(); } ParsedFunction* parsed_function() { ASSERT(!is_generating_interpreter()); return parsed_function_; } const Function& function() { return parsed_function()->function(); } BaseFlowGraphBuilder* flow_graph_builder_; Zone* zone_; bool is_generating_interpreter_; // The following members are available only when compiling bytecode. ParsedFunction* parsed_function_; ZoneGrowableArray* ic_data_array_; ObjectPool& object_pool_; const KBCInstr* raw_bytecode_ = nullptr; intptr_t bytecode_length_; intptr_t pc_; intptr_t next_pc_ = -1; const KBCInstr* bytecode_instr_ = nullptr; TokenPosition position_; // TODO(alexmarkov): Set/update. Fragment code_; ZoneGrowableArray local_vars_; ZoneGrowableArray parameters_; LocalVariable* exception_var_; LocalVariable* stacktrace_var_; LocalVariable* scratch_var_; IntMap jump_targets_; IntMap stack_states_; PrologueInfo prologue_info_; JoinEntryInstr* throw_no_such_method_; }; } // namespace kernel } // namespace dart #endif // !defined(DART_PRECOMPILED_RUNTIME) #endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_