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