| Index: runtime/vm/flow_graph_compiler.h
|
| ===================================================================
|
| --- runtime/vm/flow_graph_compiler.h (revision 17245)
|
| +++ runtime/vm/flow_graph_compiler.h (working copy)
|
| @@ -15,9 +15,15 @@
|
| namespace dart {
|
|
|
| // Forward declarations.
|
| +class Code;
|
| +class DeoptInfoBuilder;
|
| +class FlowGraph;
|
| class FlowGraphCompiler;
|
| -class DeoptInfoBuilder;
|
| +class Function;
|
| +template <typename T> class GrowableArray;
|
| +class ParsedFunction;
|
|
|
| +
|
| class ParallelMoveResolver : public ValueObject {
|
| public:
|
| explicit ParallelMoveResolver(FlowGraphCompiler* compiler);
|
| @@ -143,16 +149,375 @@
|
| };
|
|
|
|
|
| +struct CidTarget {
|
| + intptr_t cid;
|
| + Function* target;
|
| + intptr_t count;
|
| + CidTarget(intptr_t cid_arg,
|
| + Function* target_arg,
|
| + intptr_t count_arg)
|
| + : cid(cid_arg), target(target_arg), count(count_arg) {}
|
| +};
|
| +
|
| +
|
| +class FlowGraphCompiler : public ValueObject {
|
| + private:
|
| + struct BlockInfo : public ZoneAllocated {
|
| + public:
|
| + BlockInfo() : label() { }
|
| + Label label;
|
| + };
|
| +
|
| + public:
|
| + FlowGraphCompiler(Assembler* assembler,
|
| + const FlowGraph& flow_graph,
|
| + bool is_optimizing);
|
| +
|
| + ~FlowGraphCompiler();
|
| +
|
| + static bool SupportsUnboxedMints();
|
| +
|
| + // Accessors.
|
| + Assembler* assembler() const { return assembler_; }
|
| + const ParsedFunction& parsed_function() const { return parsed_function_; }
|
| + const GrowableArray<BlockEntryInstr*>& block_order() const {
|
| + return block_order_;
|
| + }
|
| + DescriptorList* pc_descriptors_list() const {
|
| + return pc_descriptors_list_;
|
| + }
|
| + BlockEntryInstr* current_block() const { return current_block_; }
|
| + void set_current_block(BlockEntryInstr* value) {
|
| + current_block_ = value;
|
| + }
|
| + static bool CanOptimize();
|
| + bool CanOptimizeFunction() const;
|
| + bool is_optimizing() const { return is_optimizing_; }
|
| +
|
| + const GrowableArray<BlockInfo*>& block_info() const { return block_info_; }
|
| + ParallelMoveResolver* parallel_move_resolver() {
|
| + return ¶llel_move_resolver_;
|
| + }
|
| +
|
| + // Constructor is lighweight, major initialization work should occur here.
|
| + // This makes it easier to measure time spent in the compiler.
|
| + void InitCompiler();
|
| +
|
| + void CompileGraph();
|
| +
|
| + void VisitBlocks();
|
| +
|
| + // Bail out of the flow graph compiler. Does not return to the caller.
|
| + void Bailout(const char* reason);
|
| +
|
| + void LoadDoubleOrSmiToFpu(FpuRegister result,
|
| + Register reg,
|
| + Register temp,
|
| + Label* not_double_or_smi);
|
| +
|
| + // Returns 'true' if code generation for this function is complete, i.e.,
|
| + // no fall-through to regular code is needed.
|
| + bool TryIntrinsify();
|
| +
|
| + void GenerateCallRuntime(intptr_t token_pos,
|
| + const RuntimeEntry& entry,
|
| + LocationSummary* locs);
|
| +
|
| + void GenerateCall(intptr_t token_pos,
|
| + const ExternalLabel* label,
|
| + PcDescriptors::Kind kind,
|
| + LocationSummary* locs);
|
| +
|
| + void GenerateDartCall(intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + const ExternalLabel* label,
|
| + PcDescriptors::Kind kind,
|
| + LocationSummary* locs);
|
| +
|
| + void GenerateAssertAssignable(intptr_t token_pos,
|
| + const AbstractType& dst_type,
|
| + const String& dst_name,
|
| + LocationSummary* locs);
|
| +
|
| + void GenerateInstanceOf(intptr_t token_pos,
|
| + const AbstractType& type,
|
| + bool negate_result,
|
| + LocationSummary* locs);
|
| +
|
| + void GenerateInstanceCall(intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + intptr_t argument_count,
|
| + const Array& argument_names,
|
| + LocationSummary* locs,
|
| + const ICData& ic_data);
|
| +
|
| + void GenerateStaticCall(intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + const Function& function,
|
| + intptr_t argument_count,
|
| + const Array& argument_names,
|
| + LocationSummary* locs);
|
| +
|
| + void GenerateNumberTypeCheck(Register kClassIdReg,
|
| + const AbstractType& type,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| + void GenerateStringTypeCheck(Register kClassIdReg,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| + void GenerateListTypeCheck(Register kClassIdReg,
|
| + Label* is_instance_lbl);
|
| +
|
| + void EmitComment(Instruction* instr);
|
| +
|
| + void EmitOptimizedInstanceCall(ExternalLabel* target_label,
|
| + const ICData& ic_data,
|
| + const Array& arguments_descriptor,
|
| + intptr_t argument_count,
|
| + intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + LocationSummary* locs);
|
| +
|
| + void EmitInstanceCall(ExternalLabel* target_label,
|
| + const ICData& ic_data,
|
| + const Array& arguments_descriptor,
|
| + intptr_t argument_count,
|
| + intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + LocationSummary* locs);
|
| +
|
| + void EmitMegamorphicInstanceCall(const ICData& ic_data,
|
| + const Array& arguments_descriptor,
|
| + intptr_t argument_count,
|
| + intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + LocationSummary* locs);
|
| +
|
| + void EmitTestAndCall(const ICData& ic_data,
|
| + Register class_id_reg,
|
| + intptr_t arg_count,
|
| + const Array& arg_names,
|
| + Label* deopt,
|
| + intptr_t deopt_id,
|
| + intptr_t token_index,
|
| + LocationSummary* locs);
|
| +
|
| + void EmitDoubleCompareBranch(Condition true_condition,
|
| + FpuRegister left,
|
| + FpuRegister right,
|
| + BranchInstr* branch);
|
| + void EmitDoubleCompareBool(Condition true_condition,
|
| + FpuRegister left,
|
| + FpuRegister right,
|
| + Register result);
|
| +
|
| + void EmitEqualityRegConstCompare(Register reg,
|
| + const Object& obj,
|
| + bool needs_number_check);
|
| + void EmitEqualityRegRegCompare(Register left,
|
| + Register right,
|
| + bool needs_number_check);
|
| + // Implement equality: if any of the arguments is null do identity check.
|
| + // Fallthrough calls super equality.
|
| + void EmitSuperEqualityCallPrologue(Register result, Label* skip_call);
|
| +
|
| + intptr_t StackSize() const;
|
| +
|
| + // Returns assembler label associated with the given block entry.
|
| + Label* GetBlockLabel(BlockEntryInstr* block_entry) const;
|
| +
|
| + // Returns true if there is a next block after the current one in
|
| + // the block order and if it is the given block.
|
| + bool IsNextBlock(BlockEntryInstr* block_entry) const;
|
| +
|
| + void AddExceptionHandler(intptr_t try_index,
|
| + intptr_t outer_try_index,
|
| + intptr_t pc_offset,
|
| + const Array& handler_types);
|
| + void AddCurrentDescriptor(PcDescriptors::Kind kind,
|
| + intptr_t deopt_id,
|
| + intptr_t token_pos);
|
| +
|
| + void RecordSafepoint(LocationSummary* locs);
|
| +
|
| + Label* AddDeoptStub(intptr_t deopt_id, DeoptReasonId reason);
|
| +
|
| + void AddDeoptIndexAtCall(intptr_t deopt_id, intptr_t token_pos);
|
| +
|
| + void AddSlowPathCode(SlowPathCode* slow_path);
|
| +
|
| + void FinalizeExceptionHandlers(const Code& code);
|
| + void FinalizePcDescriptors(const Code& code);
|
| + void FinalizeDeoptInfo(const Code& code);
|
| + void FinalizeStackmaps(const Code& code);
|
| + void FinalizeVarDescriptors(const Code& code);
|
| + void FinalizeComments(const Code& code);
|
| + void FinalizeStaticCallTargetsTable(const Code& code);
|
| +
|
| + const Class& double_class() const { return double_class_; }
|
| +
|
| + void SaveLiveRegisters(LocationSummary* locs);
|
| + void RestoreLiveRegisters(LocationSummary* locs);
|
| +
|
| + // Returns true if the compiled function has a finally clause.
|
| + bool HasFinally() const;
|
| +
|
| + intptr_t CurrentTryIndex() const {
|
| + if (current_block_ == NULL) {
|
| + return CatchClauseNode::kInvalidTryIndex;
|
| + }
|
| + return current_block_->try_index();
|
| + }
|
| +
|
| + bool may_reoptimize() const { return may_reoptimize_; }
|
| +
|
| + static const int kLocalsOffsetFromFP = (-1 * kWordSize);
|
| +
|
| + static Condition FlipCondition(Condition condition);
|
| +
|
| + static bool EvaluateCondition(Condition condition, intptr_t l, intptr_t r);
|
| +
|
| + // Array/list element address computations.
|
| + static intptr_t DataOffsetFor(intptr_t cid);
|
| + static intptr_t ElementSizeFor(intptr_t cid);
|
| + static FieldAddress ElementAddressForIntIndex(intptr_t cid,
|
| + Register array,
|
| + intptr_t offset);
|
| + static FieldAddress ElementAddressForRegIndex(intptr_t cid,
|
| + Register array,
|
| + Register index);
|
| + static Address ExternalElementAddressForIntIndex(intptr_t cid,
|
| + Register array,
|
| + intptr_t offset);
|
| + static Address ExternalElementAddressForRegIndex(intptr_t cid,
|
| + Register array,
|
| + Register index);
|
| +
|
| + private:
|
| + void EmitFrameEntry();
|
| +
|
| + void AddStaticCallTarget(const Function& function);
|
| +
|
| + void GenerateDeferredCode();
|
| +
|
| + void EmitInstructionPrologue(Instruction* instr);
|
| + void EmitInstructionEpilogue(Instruction* instr);
|
| +
|
| + // Emit code to load a Value into register 'dst'.
|
| + void LoadValue(Register dst, Value* value);
|
| +
|
| + void EmitStaticCall(const Function& function,
|
| + const Array& arguments_descriptor,
|
| + intptr_t argument_count,
|
| + intptr_t deopt_id,
|
| + intptr_t token_pos,
|
| + LocationSummary* locs);
|
| +
|
| + // Type checking helper methods.
|
| + void CheckClassIds(Register class_id_reg,
|
| + const GrowableArray<intptr_t>& class_ids,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| +
|
| + RawSubtypeTestCache* GenerateInlineInstanceof(intptr_t token_pos,
|
| + const AbstractType& type,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| +
|
| + RawSubtypeTestCache* GenerateInstantiatedTypeWithArgumentsTest(
|
| + intptr_t token_pos,
|
| + const AbstractType& dst_type,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| +
|
| + bool GenerateInstantiatedTypeNoArgumentsTest(intptr_t token_pos,
|
| + const AbstractType& dst_type,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| +
|
| + RawSubtypeTestCache* GenerateUninstantiatedTypeTest(
|
| + intptr_t token_pos,
|
| + const AbstractType& dst_type,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_label);
|
| +
|
| + RawSubtypeTestCache* GenerateSubtype1TestCacheLookup(
|
| + intptr_t token_pos,
|
| + const Class& type_class,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| +
|
| + enum TypeTestStubKind {
|
| + kTestTypeOneArg,
|
| + kTestTypeTwoArgs,
|
| + kTestTypeThreeArgs,
|
| + };
|
| +
|
| + RawSubtypeTestCache* GenerateCallSubtypeTestStub(TypeTestStubKind test_kind,
|
| + Register instance_reg,
|
| + Register type_arguments_reg,
|
| + Register temp_reg,
|
| + Label* is_instance_lbl,
|
| + Label* is_not_instance_lbl);
|
| +
|
| + // Returns true if checking against this type is a direct class id comparison.
|
| + bool TypeCheckAsClassEquality(const AbstractType& type);
|
| +
|
| + void GenerateBoolToJump(Register bool_reg, Label* is_true, Label* is_false);
|
| +
|
| + void CopyParameters();
|
| +
|
| + void GenerateInlinedGetter(intptr_t offset);
|
| + void GenerateInlinedSetter(intptr_t offset);
|
| +
|
| + // Perform a greedy local register allocation. Consider all registers free.
|
| + void AllocateRegistersLocally(Instruction* instr);
|
| +
|
| + // Map a block number in a forward iteration into the block number in the
|
| + // corresponding reverse iteration. Used to obtain an index into
|
| + // block_order for reverse iterations.
|
| + intptr_t reverse_index(intptr_t index) const {
|
| + return block_order_.length() - index - 1;
|
| + }
|
| +
|
| + // Returns 'sorted' array in decreasing count order.
|
| + // The expected number of elements to sort is less than 10.
|
| + static void SortICDataByCount(const ICData& ic_data,
|
| + GrowableArray<CidTarget>* sorted);
|
| +
|
| + class Assembler* assembler_;
|
| + const ParsedFunction& parsed_function_;
|
| + const GrowableArray<BlockEntryInstr*>& block_order_;
|
| +
|
| + // Compiler specific per-block state. Indexed by postorder block number
|
| + // for convenience. This is not the block's index in the block order,
|
| + // which is reverse postorder.
|
| + BlockEntryInstr* current_block_;
|
| + ExceptionHandlerList* exception_handlers_list_;
|
| + DescriptorList* pc_descriptors_list_;
|
| + StackmapTableBuilder* stackmap_table_builder_;
|
| + GrowableArray<BlockInfo*> block_info_;
|
| + GrowableArray<CompilerDeoptInfo*> deopt_infos_;
|
| + GrowableArray<SlowPathCode*> slow_path_code_;
|
| + // Stores: [code offset, function, null(code)].
|
| + const GrowableObjectArray& static_calls_target_table_;
|
| + const bool is_optimizing_;
|
| + // Set to true if optimized code has IC calls.
|
| + bool may_reoptimize_;
|
| +
|
| + const Class& double_class_;
|
| +
|
| + ParallelMoveResolver parallel_move_resolver_;
|
| +
|
| + // Currently instructions generate deopt stubs internally by
|
| + // calling AddDeoptStub. To communicate deoptimization environment
|
| + // that should be used when deoptimizing we store it in this variable.
|
| + // In future AddDeoptStub should be moved out of the instruction template.
|
| + Environment* pending_deoptimization_env_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FlowGraphCompiler);
|
| +};
|
| +
|
| } // namespace dart
|
|
|
| -#if defined(TARGET_ARCH_IA32)
|
| -#include "vm/flow_graph_compiler_ia32.h"
|
| -#elif defined(TARGET_ARCH_X64)
|
| -#include "vm/flow_graph_compiler_x64.h"
|
| -#elif defined(TARGET_ARCH_ARM)
|
| -#include "vm/flow_graph_compiler_arm.h"
|
| -#else
|
| -#error Unknown architecture.
|
| -#endif
|
| -
|
| #endif // VM_FLOW_GRAPH_COMPILER_H_
|
|
|