Line data Source code
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/base/optional.h"
9 : #include "src/compiler/gap-resolver.h"
10 : #include "src/compiler/instruction.h"
11 : #include "src/compiler/osr.h"
12 : #include "src/compiler/unwinding-info-writer.h"
13 : #include "src/deoptimizer.h"
14 : #include "src/macro-assembler.h"
15 : #include "src/safepoint-table.h"
16 : #include "src/source-position-table.h"
17 : #include "src/trap-handler/trap-handler.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : class CompilationInfo;
23 :
24 : namespace compiler {
25 :
26 : // Forward declarations.
27 : class DeoptimizationExit;
28 : class FrameAccessState;
29 : class Linkage;
30 : class OutOfLineCode;
31 :
32 : struct BranchInfo {
33 : FlagsCondition condition;
34 : Label* true_label;
35 : Label* false_label;
36 : bool fallthru;
37 : };
38 :
39 :
40 : class InstructionOperandIterator {
41 : public:
42 : InstructionOperandIterator(Instruction* instr, size_t pos)
43 3087693 : : instr_(instr), pos_(pos) {}
44 :
45 : Instruction* instruction() const { return instr_; }
46 20713945 : InstructionOperand* Advance() { return instr_->InputAt(pos_++); }
47 :
48 : private:
49 : Instruction* instr_;
50 : size_t pos_;
51 : };
52 :
53 : // Either a non-null Handle<Object> or a double.
54 : class DeoptimizationLiteral {
55 : public:
56 5511216 : DeoptimizationLiteral() : object_(), number_(0) {}
57 : explicit DeoptimizationLiteral(Handle<Object> object)
58 3863390 : : object_(object), number_(0) {
59 : DCHECK(!object_.is_null());
60 : }
61 : explicit DeoptimizationLiteral(double number) : object_(), number_(number) {}
62 :
63 : Handle<Object> object() const { return object_; }
64 :
65 27665933 : bool operator==(const DeoptimizationLiteral& other) const {
66 34709335 : return object_.equals(other.object_) &&
67 41752737 : bit_cast<uint64_t>(number_) == bit_cast<uint64_t>(other.number_);
68 : }
69 :
70 : Handle<Object> Reify(Isolate* isolate) const;
71 :
72 : private:
73 : Handle<Object> object_;
74 : double number_;
75 : };
76 :
77 : // Generates native code for a sequence of instructions.
78 3904742 : class CodeGenerator final : public GapResolver::Assembler {
79 : public:
80 : explicit CodeGenerator(Zone* codegen_zone, Frame* frame, Linkage* linkage,
81 : InstructionSequence* code, CompilationInfo* info,
82 : base::Optional<OsrHelper> osr_helper,
83 : int start_source_position,
84 : JumpOptimizationInfo* jump_opt);
85 :
86 : // Generate native code. After calling AssembleCode, call FinalizeCode to
87 : // produce the actual code object. If an error occurs during either phase,
88 : // FinalizeCode returns a null handle.
89 : void AssembleCode(); // Does not need to run on main thread.
90 : Handle<Code> FinalizeCode();
91 :
92 : InstructionSequence* code() const { return code_; }
93 : FrameAccessState* frame_access_state() const { return frame_access_state_; }
94 9032964 : const Frame* frame() const { return frame_access_state_->frame(); }
95 : Isolate* isolate() const;
96 : Linkage* linkage() const { return linkage_; }
97 :
98 22998589 : Label* GetLabel(RpoNumber rpo) { return &labels_[rpo.ToSize()]; }
99 :
100 : SourcePosition start_source_position() const {
101 : return start_source_position_;
102 : }
103 :
104 : void AssembleSourcePosition(Instruction* instr);
105 : void AssembleSourcePosition(SourcePosition source_position);
106 :
107 : // Record a safepoint with the given pointer map.
108 : void RecordSafepoint(ReferenceMap* references, Safepoint::Kind kind,
109 : int arguments, Safepoint::DeoptMode deopt_mode);
110 :
111 : Zone* zone() const { return zone_; }
112 :
113 : private:
114 : TurboAssembler* tasm() { return &tasm_; }
115 : GapResolver* resolver() { return &resolver_; }
116 : SafepointTableBuilder* safepoints() { return &safepoints_; }
117 : CompilationInfo* info() const { return info_; }
118 : OsrHelper* osr_helper() { return &(*osr_helper_); }
119 :
120 : // Create the FrameAccessState object. The Frame is immutable from here on.
121 : void CreateFrameAccessState(Frame* frame);
122 :
123 : // Architecture - specific frame finalization.
124 : void FinishFrame(Frame* frame);
125 :
126 : // Checks if {block} will appear directly after {current_block_} when
127 : // assembling code, in which case, a fall-through can be used.
128 : bool IsNextInAssemblyOrder(RpoNumber block) const;
129 :
130 : // Check if a heap object can be materialized by loading from a heap root,
131 : // which is cheaper on some platforms than materializing the actual heap
132 : // object constant.
133 : bool IsMaterializableFromRoot(Handle<HeapObject> object,
134 : Heap::RootListIndex* index_return);
135 :
136 : enum CodeGenResult { kSuccess, kTooManyDeoptimizationBailouts };
137 :
138 : // Assemble instructions for the specified block.
139 : CodeGenResult AssembleBlock(const InstructionBlock* block);
140 :
141 : // Assemble code for the specified instruction.
142 : CodeGenResult AssembleInstruction(Instruction* instr,
143 : const InstructionBlock* block);
144 : void AssembleGaps(Instruction* instr);
145 :
146 : // Returns true if a instruction is a tail call that needs to adjust the stack
147 : // pointer before execution. The stack slot index to the empty slot above the
148 : // adjusted stack pointer is returned in |slot|.
149 : bool GetSlotAboveSPBeforeTailCall(Instruction* instr, int* slot);
150 :
151 : CodeGenResult AssembleDeoptimizerCall(int deoptimization_id,
152 : SourcePosition pos);
153 :
154 : // ===========================================================================
155 : // ============= Architecture-specific code generation methods. ==============
156 : // ===========================================================================
157 :
158 : CodeGenResult AssembleArchInstruction(Instruction* instr);
159 : void AssembleArchJump(RpoNumber target);
160 : void AssembleArchBranch(Instruction* instr, BranchInfo* branch);
161 :
162 : // Generates special branch for deoptimization condition.
163 : void AssembleArchDeoptBranch(Instruction* instr, BranchInfo* branch);
164 :
165 : void AssembleArchBoolean(Instruction* instr, FlagsCondition condition);
166 : void AssembleArchTrap(Instruction* instr, FlagsCondition condition);
167 : void AssembleArchLookupSwitch(Instruction* instr);
168 : void AssembleArchTableSwitch(Instruction* instr);
169 :
170 : // When entering a code that is marked for deoptimization, rather continuing
171 : // with its execution, we jump to a lazy compiled code. We need to do this
172 : // because this code has already been deoptimized and needs to be unlinked
173 : // from the JS functions referring it.
174 : void BailoutIfDeoptimized();
175 :
176 : // Generates an architecture-specific, descriptor-specific prologue
177 : // to set up a stack frame.
178 : void AssembleConstructFrame();
179 :
180 : // Generates an architecture-specific, descriptor-specific return sequence
181 : // to tear down a stack frame.
182 : void AssembleReturn(InstructionOperand* pop);
183 :
184 : void AssembleDeconstructFrame();
185 :
186 : // Generates code to manipulate the stack in preparation for a tail call.
187 : void AssemblePrepareTailCall();
188 :
189 : // Generates code to pop current frame if it is an arguments adaptor frame.
190 : void AssemblePopArgumentsAdaptorFrame(Register args_reg, Register scratch1,
191 : Register scratch2, Register scratch3);
192 :
193 : enum PushTypeFlag {
194 : kImmediatePush = 0x1,
195 : kRegisterPush = 0x2,
196 : kStackSlotPush = 0x4,
197 : kScalarPush = kRegisterPush | kStackSlotPush
198 : };
199 :
200 : typedef base::Flags<PushTypeFlag> PushTypeFlags;
201 :
202 : static bool IsValidPush(InstructionOperand source, PushTypeFlags push_type);
203 :
204 : // Generate a list moves from an instruction that are candidates to be turned
205 : // into push instructions on platforms that support them. In general, the list
206 : // of push candidates are moves to a set of contiguous destination
207 : // InstructionOperand locations on the stack that don't clobber values that
208 : // are needed for resolve the gap or use values generated by the gap,
209 : // i.e. moves that can be hoisted together before the actual gap and assembled
210 : // together.
211 : static void GetPushCompatibleMoves(Instruction* instr,
212 : PushTypeFlags push_type,
213 : ZoneVector<MoveOperands*>* pushes);
214 :
215 : // Called before a tail call |instr|'s gap moves are assembled and allows
216 : // gap-specific pre-processing, e.g. adjustment of the sp for tail calls that
217 : // need it before gap moves or conversion of certain gap moves into pushes.
218 : void AssembleTailCallBeforeGap(Instruction* instr,
219 : int first_unused_stack_slot);
220 : // Called after a tail call |instr|'s gap moves are assembled and allows
221 : // gap-specific post-processing, e.g. adjustment of the sp for tail calls that
222 : // need it after gap moves.
223 : void AssembleTailCallAfterGap(Instruction* instr,
224 : int first_unused_stack_slot);
225 :
226 : void FinishCode();
227 :
228 : // ===========================================================================
229 : // ============== Architecture-specific gap resolver methods. ================
230 : // ===========================================================================
231 :
232 : // Interface used by the gap resolver to emit moves and swaps.
233 : void AssembleMove(InstructionOperand* source,
234 : InstructionOperand* destination) final;
235 : void AssembleSwap(InstructionOperand* source,
236 : InstructionOperand* destination) final;
237 :
238 : // ===========================================================================
239 : // =================== Jump table construction methods. ======================
240 : // ===========================================================================
241 :
242 : class JumpTable;
243 : // Adds a jump table that is emitted after the actual code. Returns label
244 : // pointing to the beginning of the table. {targets} is assumed to be static
245 : // or zone allocated.
246 : Label* AddJumpTable(Label** targets, size_t target_count);
247 : // Emits a jump table.
248 : void AssembleJumpTable(Label** targets, size_t target_count);
249 :
250 : // ===========================================================================
251 : // ================== Deoptimization table construction. =====================
252 : // ===========================================================================
253 :
254 : void RecordCallPosition(Instruction* instr);
255 : Handle<DeoptimizationData> GenerateDeoptimizationData();
256 : int DefineDeoptimizationLiteral(DeoptimizationLiteral literal);
257 : DeoptimizationEntry const& GetDeoptimizationEntry(Instruction* instr,
258 : size_t frame_state_offset);
259 : DeoptimizeKind GetDeoptimizationKind(int deoptimization_id) const;
260 : DeoptimizeReason GetDeoptimizationReason(int deoptimization_id) const;
261 : int BuildTranslation(Instruction* instr, int pc_offset,
262 : size_t frame_state_offset,
263 : OutputFrameStateCombine state_combine);
264 : void BuildTranslationForFrameStateDescriptor(
265 : FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
266 : Translation* translation, OutputFrameStateCombine state_combine);
267 : void TranslateStateValueDescriptor(StateValueDescriptor* desc,
268 : StateValueList* nested,
269 : Translation* translation,
270 : InstructionOperandIterator* iter);
271 : void TranslateFrameStateDescriptorOperands(FrameStateDescriptor* desc,
272 : InstructionOperandIterator* iter,
273 : OutputFrameStateCombine combine,
274 : Translation* translation);
275 : void AddTranslationForOperand(Translation* translation, Instruction* instr,
276 : InstructionOperand* op, MachineType type);
277 : void MarkLazyDeoptSite();
278 :
279 : DeoptimizationExit* AddDeoptimizationExit(Instruction* instr,
280 : size_t frame_state_offset);
281 :
282 : // ===========================================================================
283 :
284 : class DeoptimizationState final : public ZoneObject {
285 : public:
286 : DeoptimizationState(BailoutId bailout_id, int translation_id, int pc_offset,
287 : DeoptimizeKind kind, DeoptimizeReason reason)
288 : : bailout_id_(bailout_id),
289 : translation_id_(translation_id),
290 : pc_offset_(pc_offset),
291 : kind_(kind),
292 3087703 : reason_(reason) {}
293 :
294 : BailoutId bailout_id() const { return bailout_id_; }
295 : int translation_id() const { return translation_id_; }
296 : int pc_offset() const { return pc_offset_; }
297 : DeoptimizeKind kind() const { return kind_; }
298 : DeoptimizeReason reason() const { return reason_; }
299 :
300 : private:
301 : BailoutId bailout_id_;
302 : int translation_id_;
303 : int pc_offset_;
304 : DeoptimizeKind kind_;
305 : DeoptimizeReason reason_;
306 : };
307 :
308 : struct HandlerInfo {
309 : Label* handler;
310 : int pc_offset;
311 : };
312 :
313 : friend class OutOfLineCode;
314 : friend class CodeGeneratorTester;
315 :
316 : Zone* zone_;
317 : FrameAccessState* frame_access_state_;
318 : Linkage* const linkage_;
319 : InstructionSequence* const code_;
320 : UnwindingInfoWriter unwinding_info_writer_;
321 : CompilationInfo* const info_;
322 : Label* const labels_;
323 : Label return_label_;
324 : RpoNumber current_block_;
325 : SourcePosition start_source_position_;
326 : SourcePosition current_source_position_;
327 : TurboAssembler tasm_;
328 : GapResolver resolver_;
329 : SafepointTableBuilder safepoints_;
330 : ZoneVector<HandlerInfo> handlers_;
331 : ZoneDeque<DeoptimizationExit*> deoptimization_exits_;
332 : ZoneDeque<DeoptimizationState*> deoptimization_states_;
333 : ZoneDeque<DeoptimizationLiteral> deoptimization_literals_;
334 : size_t inlined_function_count_;
335 : TranslationBuffer translations_;
336 : int last_lazy_deopt_pc_;
337 :
338 : // kArchCallCFunction could be reached either:
339 : // kArchCallCFunction;
340 : // or:
341 : // kArchSaveCallerRegisters;
342 : // kArchCallCFunction;
343 : // kArchRestoreCallerRegisters;
344 : // The boolean is used to distinguish the two cases. In the latter case, we
345 : // also need to decide if FP registers need to be saved, which is controlled
346 : // by fp_mode_.
347 : bool caller_registers_saved_;
348 : SaveFPRegsMode fp_mode_;
349 :
350 : JumpTable* jump_tables_;
351 : OutOfLineCode* ools_;
352 : base::Optional<OsrHelper> osr_helper_;
353 : int osr_pc_offset_;
354 : int optimized_out_literal_id_;
355 : SourcePositionTableBuilder source_position_table_builder_;
356 : CodeGenResult result_;
357 : };
358 :
359 : } // namespace compiler
360 : } // namespace internal
361 : } // namespace v8
362 :
363 : #endif // V8_COMPILER_CODE_GENERATOR_H
|