1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_CODE_GENERATOR_H_ 6 #define V8_COMPILER_CODE_GENERATOR_H_ 7 8 #include "src/compiler/gap-resolver.h" 9 #include "src/compiler/instruction.h" 10 #include "src/compiler/unwinding-info-writer.h" 11 #include "src/deoptimizer.h" 12 #include "src/macro-assembler.h" 13 #include "src/safepoint-table.h" 14 #include "src/source-position-table.h" 15 16 namespace v8 { 17 namespace internal { 18 19 class CompilationInfo; 20 21 namespace compiler { 22 23 // Forward declarations. 24 class DeoptimizationExit; 25 class FrameAccessState; 26 class Linkage; 27 class OutOfLineCode; 28 29 struct BranchInfo { 30 FlagsCondition condition; 31 Label* true_label; 32 Label* false_label; 33 bool fallthru; 34 }; 35 36 37 class InstructionOperandIterator { 38 public: InstructionOperandIterator(Instruction * instr,size_t pos)39 InstructionOperandIterator(Instruction* instr, size_t pos) 40 : instr_(instr), pos_(pos) {} 41 instruction()42 Instruction* instruction() const { return instr_; } Advance()43 InstructionOperand* Advance() { return instr_->InputAt(pos_++); } 44 45 private: 46 Instruction* instr_; 47 size_t pos_; 48 }; 49 50 51 // Generates native code for a sequence of instructions. 52 class CodeGenerator final : public GapResolver::Assembler { 53 public: 54 explicit CodeGenerator(Frame* frame, Linkage* linkage, 55 InstructionSequence* code, CompilationInfo* info); 56 57 // Generate native code. 58 Handle<Code> GenerateCode(); 59 code()60 InstructionSequence* code() const { return code_; } frame_access_state()61 FrameAccessState* frame_access_state() const { return frame_access_state_; } frame()62 const Frame* frame() const { return frame_access_state_->frame(); } 63 Isolate* isolate() const; linkage()64 Linkage* linkage() const { return linkage_; } 65 GetLabel(RpoNumber rpo)66 Label* GetLabel(RpoNumber rpo) { return &labels_[rpo.ToSize()]; } 67 68 private: masm()69 MacroAssembler* masm() { return &masm_; } resolver()70 GapResolver* resolver() { return &resolver_; } safepoints()71 SafepointTableBuilder* safepoints() { return &safepoints_; } zone()72 Zone* zone() const { return code()->zone(); } info()73 CompilationInfo* info() const { return info_; } 74 75 // Create the FrameAccessState object. The Frame is immutable from here on. 76 void CreateFrameAccessState(Frame* frame); 77 78 // Architecture - specific frame finalization. 79 void FinishFrame(Frame* frame); 80 81 // Checks if {block} will appear directly after {current_block_} when 82 // assembling code, in which case, a fall-through can be used. 83 bool IsNextInAssemblyOrder(RpoNumber block) const; 84 85 // Record a safepoint with the given pointer map. 86 void RecordSafepoint(ReferenceMap* references, Safepoint::Kind kind, 87 int arguments, Safepoint::DeoptMode deopt_mode); 88 89 // Check if a heap object can be materialized by loading from a heap root, 90 // which is cheaper on some platforms than materializing the actual heap 91 // object constant. 92 bool IsMaterializableFromRoot(Handle<HeapObject> object, 93 Heap::RootListIndex* index_return); 94 95 enum CodeGenResult { kSuccess, kTooManyDeoptimizationBailouts }; 96 97 // Assemble instructions for the specified block. 98 CodeGenResult AssembleBlock(const InstructionBlock* block); 99 100 // Assemble code for the specified instruction. 101 CodeGenResult AssembleInstruction(Instruction* instr, 102 const InstructionBlock* block); 103 void AssembleSourcePosition(Instruction* instr); 104 void AssembleGaps(Instruction* instr); 105 106 // Returns true if a instruction is a tail call that needs to adjust the stack 107 // pointer before execution. The stack slot index to the empty slot above the 108 // adjusted stack pointer is returned in |slot|. 109 bool GetSlotAboveSPBeforeTailCall(Instruction* instr, int* slot); 110 111 // =========================================================================== 112 // ============= Architecture-specific code generation methods. ============== 113 // =========================================================================== 114 115 CodeGenResult AssembleArchInstruction(Instruction* instr); 116 void AssembleArchJump(RpoNumber target); 117 void AssembleArchBranch(Instruction* instr, BranchInfo* branch); 118 void AssembleArchBoolean(Instruction* instr, FlagsCondition condition); 119 void AssembleArchLookupSwitch(Instruction* instr); 120 void AssembleArchTableSwitch(Instruction* instr); 121 122 CodeGenResult AssembleDeoptimizerCall(int deoptimization_id, 123 Deoptimizer::BailoutType bailout_type, 124 SourcePosition pos); 125 126 // Generates an architecture-specific, descriptor-specific prologue 127 // to set up a stack frame. 128 void AssembleConstructFrame(); 129 130 // Generates an architecture-specific, descriptor-specific return sequence 131 // to tear down a stack frame. 132 void AssembleReturn(InstructionOperand* pop); 133 134 void AssembleDeconstructFrame(); 135 136 // Generates code to manipulate the stack in preparation for a tail call. 137 void AssemblePrepareTailCall(); 138 139 // Generates code to pop current frame if it is an arguments adaptor frame. 140 void AssemblePopArgumentsAdaptorFrame(Register args_reg, Register scratch1, 141 Register scratch2, Register scratch3); 142 143 enum PushTypeFlag { 144 kImmediatePush = 0x1, 145 kScalarPush = 0x2, 146 kFloat32Push = 0x4, 147 kFloat64Push = 0x8, 148 kFloatPush = kFloat32Push | kFloat64Push 149 }; 150 151 typedef base::Flags<PushTypeFlag> PushTypeFlags; 152 153 static bool IsValidPush(InstructionOperand source, PushTypeFlags push_type); 154 155 // Generate a list moves from an instruction that are candidates to be turned 156 // into push instructions on platforms that support them. In general, the list 157 // of push candidates are moves to a set of contiguous destination 158 // InstructionOperand locations on the stack that don't clobber values that 159 // are needed for resolve the gap or use values generated by the gap, 160 // i.e. moves that can be hoisted together before the actual gap and assembled 161 // together. 162 static void GetPushCompatibleMoves(Instruction* instr, 163 PushTypeFlags push_type, 164 ZoneVector<MoveOperands*>* pushes); 165 166 // Called before a tail call |instr|'s gap moves are assembled and allows 167 // gap-specific pre-processing, e.g. adjustment of the sp for tail calls that 168 // need it before gap moves or conversion of certain gap moves into pushes. 169 void AssembleTailCallBeforeGap(Instruction* instr, 170 int first_unused_stack_slot); 171 // Called after a tail call |instr|'s gap moves are assembled and allows 172 // gap-specific post-processing, e.g. adjustment of the sp for tail calls that 173 // need it after gap moves. 174 void AssembleTailCallAfterGap(Instruction* instr, 175 int first_unused_stack_slot); 176 177 // =========================================================================== 178 // ============== Architecture-specific gap resolver methods. ================ 179 // =========================================================================== 180 181 // Interface used by the gap resolver to emit moves and swaps. 182 void AssembleMove(InstructionOperand* source, 183 InstructionOperand* destination) final; 184 void AssembleSwap(InstructionOperand* source, 185 InstructionOperand* destination) final; 186 187 // =========================================================================== 188 // =================== Jump table construction methods. ====================== 189 // =========================================================================== 190 191 class JumpTable; 192 // Adds a jump table that is emitted after the actual code. Returns label 193 // pointing to the beginning of the table. {targets} is assumed to be static 194 // or zone allocated. 195 Label* AddJumpTable(Label** targets, size_t target_count); 196 // Emits a jump table. 197 void AssembleJumpTable(Label** targets, size_t target_count); 198 199 // =========================================================================== 200 // ================== Deoptimization table construction. ===================== 201 // =========================================================================== 202 203 void RecordCallPosition(Instruction* instr); 204 void PopulateDeoptimizationData(Handle<Code> code); 205 int DefineDeoptimizationLiteral(Handle<Object> literal); 206 DeoptimizationEntry const& GetDeoptimizationEntry(Instruction* instr, 207 size_t frame_state_offset); 208 DeoptimizeReason GetDeoptimizationReason(int deoptimization_id) const; 209 int BuildTranslation(Instruction* instr, int pc_offset, 210 size_t frame_state_offset, 211 OutputFrameStateCombine state_combine); 212 void BuildTranslationForFrameStateDescriptor( 213 FrameStateDescriptor* descriptor, InstructionOperandIterator* iter, 214 Translation* translation, OutputFrameStateCombine state_combine); 215 void TranslateStateValueDescriptor(StateValueDescriptor* desc, 216 Translation* translation, 217 InstructionOperandIterator* iter); 218 void TranslateFrameStateDescriptorOperands(FrameStateDescriptor* desc, 219 InstructionOperandIterator* iter, 220 OutputFrameStateCombine combine, 221 Translation* translation); 222 void AddTranslationForOperand(Translation* translation, Instruction* instr, 223 InstructionOperand* op, MachineType type); 224 void EnsureSpaceForLazyDeopt(); 225 void MarkLazyDeoptSite(); 226 227 DeoptimizationExit* AddDeoptimizationExit(Instruction* instr, 228 size_t frame_state_offset); 229 230 // =========================================================================== 231 232 class DeoptimizationState final : public ZoneObject { 233 public: DeoptimizationState(BailoutId bailout_id,int translation_id,int pc_offset,DeoptimizeReason reason)234 DeoptimizationState(BailoutId bailout_id, int translation_id, int pc_offset, 235 DeoptimizeReason reason) 236 : bailout_id_(bailout_id), 237 translation_id_(translation_id), 238 pc_offset_(pc_offset), 239 reason_(reason) {} 240 bailout_id()241 BailoutId bailout_id() const { return bailout_id_; } translation_id()242 int translation_id() const { return translation_id_; } pc_offset()243 int pc_offset() const { return pc_offset_; } reason()244 DeoptimizeReason reason() const { return reason_; } 245 246 private: 247 BailoutId bailout_id_; 248 int translation_id_; 249 int pc_offset_; 250 DeoptimizeReason reason_; 251 }; 252 253 struct HandlerInfo { 254 Label* handler; 255 int pc_offset; 256 }; 257 258 friend class OutOfLineCode; 259 260 FrameAccessState* frame_access_state_; 261 Linkage* const linkage_; 262 InstructionSequence* const code_; 263 UnwindingInfoWriter unwinding_info_writer_; 264 CompilationInfo* const info_; 265 Label* const labels_; 266 Label return_label_; 267 RpoNumber current_block_; 268 SourcePosition current_source_position_; 269 MacroAssembler masm_; 270 GapResolver resolver_; 271 SafepointTableBuilder safepoints_; 272 ZoneVector<HandlerInfo> handlers_; 273 ZoneDeque<DeoptimizationExit*> deoptimization_exits_; 274 ZoneDeque<DeoptimizationState*> deoptimization_states_; 275 ZoneDeque<Handle<Object>> deoptimization_literals_; 276 size_t inlined_function_count_; 277 TranslationBuffer translations_; 278 int last_lazy_deopt_pc_; 279 JumpTable* jump_tables_; 280 OutOfLineCode* ools_; 281 int osr_pc_offset_; 282 SourcePositionTableBuilder source_position_table_builder_; 283 }; 284 285 } // namespace compiler 286 } // namespace internal 287 } // namespace v8 288 289 #endif // V8_COMPILER_CODE_GENERATOR_H 290