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_BACKEND_CODE_GENERATOR_H_
6 : #define V8_COMPILER_BACKEND_CODE_GENERATOR_H_
7 :
8 : #include "src/base/optional.h"
9 : #include "src/compiler/backend/gap-resolver.h"
10 : #include "src/compiler/backend/instruction.h"
11 : #include "src/compiler/backend/unwinding-info-writer.h"
12 : #include "src/compiler/osr.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 OptimizedCompilationInfo;
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 : class InstructionOperandIterator {
40 : public:
41 : InstructionOperandIterator(Instruction* instr, size_t pos)
42 3329978 : : instr_(instr), pos_(pos) {}
43 :
44 : Instruction* instruction() const { return instr_; }
45 21934400 : InstructionOperand* Advance() { return instr_->InputAt(pos_++); }
46 :
47 : private:
48 : Instruction* instr_;
49 : size_t pos_;
50 : };
51 :
52 : enum class DeoptimizationLiteralKind { kObject, kNumber, kString };
53 :
54 : // Either a non-null Handle<Object>, a double or a StringConstantBase.
55 : class DeoptimizationLiteral {
56 : public:
57 6322688 : DeoptimizationLiteral() : object_(), number_(0), string_(nullptr) {}
58 : explicit DeoptimizationLiteral(Handle<Object> object)
59 4781746 : : kind_(DeoptimizationLiteralKind::kObject), object_(object) {
60 : DCHECK(!object_.is_null());
61 : }
62 : explicit DeoptimizationLiteral(double number)
63 : : kind_(DeoptimizationLiteralKind::kNumber), number_(number) {}
64 : explicit DeoptimizationLiteral(const StringConstantBase* string)
65 : : kind_(DeoptimizationLiteralKind::kString), string_(string) {}
66 :
67 : Handle<Object> object() const { return object_; }
68 : const StringConstantBase* string() const { return string_; }
69 :
70 : bool operator==(const DeoptimizationLiteral& other) const {
71 93708856 : return kind_ == other.kind_ && object_.equals(other.object_) &&
72 56003078 : bit_cast<uint64_t>(number_) == bit_cast<uint64_t>(other.number_) &&
73 : bit_cast<intptr_t>(string_) == bit_cast<intptr_t>(other.string_);
74 : }
75 :
76 : Handle<Object> Reify(Isolate* isolate) const;
77 :
78 : DeoptimizationLiteralKind kind() const { return kind_; }
79 :
80 : private:
81 : DeoptimizationLiteralKind kind_;
82 :
83 : Handle<Object> object_;
84 : double number_ = 0;
85 : const StringConstantBase* string_ = nullptr;
86 : };
87 :
88 : // Generates native code for a sequence of instructions.
89 7893168 : class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
90 : public:
91 : explicit CodeGenerator(Zone* codegen_zone, Frame* frame, Linkage* linkage,
92 : InstructionSequence* instructions,
93 : OptimizedCompilationInfo* info, Isolate* isolate,
94 : base::Optional<OsrHelper> osr_helper,
95 : int start_source_position,
96 : JumpOptimizationInfo* jump_opt,
97 : PoisoningMitigationLevel poisoning_level,
98 : const AssemblerOptions& options, int32_t builtin_index,
99 : std::unique_ptr<AssemblerBuffer> = {});
100 :
101 : // Generate native code. After calling AssembleCode, call FinalizeCode to
102 : // produce the actual code object. If an error occurs during either phase,
103 : // FinalizeCode returns an empty MaybeHandle.
104 : void AssembleCode(); // Does not need to run on main thread.
105 : MaybeHandle<Code> FinalizeCode();
106 :
107 : OwnedVector<byte> GetSourcePositionTable();
108 : OwnedVector<trap_handler::ProtectedInstructionData>
109 : GetProtectedInstructions();
110 :
111 : InstructionSequence* instructions() const { return instructions_; }
112 : FrameAccessState* frame_access_state() const { return frame_access_state_; }
113 : const Frame* frame() const { return frame_access_state_->frame(); }
114 : Isolate* isolate() const { return isolate_; }
115 : Linkage* linkage() const { return linkage_; }
116 :
117 34939741 : Label* GetLabel(RpoNumber rpo) { return &labels_[rpo.ToSize()]; }
118 :
119 : void AddProtectedInstructionLanding(uint32_t instr_offset,
120 : uint32_t landing_offset);
121 :
122 : bool wasm_runtime_exception_support() const;
123 :
124 : SourcePosition start_source_position() const {
125 : return start_source_position_;
126 : }
127 :
128 : void AssembleSourcePosition(Instruction* instr);
129 : void AssembleSourcePosition(SourcePosition source_position);
130 :
131 : // Record a safepoint with the given pointer map.
132 : void RecordSafepoint(ReferenceMap* references, Safepoint::Kind kind,
133 : Safepoint::DeoptMode deopt_mode);
134 :
135 : Zone* zone() const { return zone_; }
136 41424706 : TurboAssembler* tasm() { return &tasm_; }
137 987049 : SafepointTableBuilder* safepoint_table_builder() { return &safepoints_; }
138 : size_t GetSafepointTableOffset() const { return safepoints_.GetCodeOffset(); }
139 : size_t GetHandlerTableOffset() const { return handler_table_offset_; }
140 :
141 1 : const ZoneVector<int>& block_starts() const { return block_starts_; }
142 9 : const ZoneVector<int>& instr_starts() const { return instr_starts_; }
143 :
144 : static constexpr int kBinarySearchSwitchMinimalCases = 4;
145 :
146 : private:
147 48726440 : GapResolver* resolver() { return &resolver_; }
148 16381853 : SafepointTableBuilder* safepoints() { return &safepoints_; }
149 : OptimizedCompilationInfo* info() const { return info_; }
150 : OsrHelper* osr_helper() { return &(*osr_helper_); }
151 :
152 : // Create the FrameAccessState object. The Frame is immutable from here on.
153 : void CreateFrameAccessState(Frame* frame);
154 :
155 : // Architecture - specific frame finalization.
156 : void FinishFrame(Frame* frame);
157 :
158 : // Checks if {block} will appear directly after {current_block_} when
159 : // assembling code, in which case, a fall-through can be used.
160 : bool IsNextInAssemblyOrder(RpoNumber block) const;
161 :
162 : // Check if a heap object can be materialized by loading from a heap root,
163 : // which is cheaper on some platforms than materializing the actual heap
164 : // object constant.
165 : bool IsMaterializableFromRoot(Handle<HeapObject> object,
166 : RootIndex* index_return);
167 :
168 : enum CodeGenResult { kSuccess, kTooManyDeoptimizationBailouts };
169 :
170 : // Assemble instructions for the specified block.
171 : CodeGenResult AssembleBlock(const InstructionBlock* block);
172 :
173 : // Inserts mask update at the beginning of an instruction block if the
174 : // predecessor blocks ends with a masking branch.
175 : void TryInsertBranchPoisoning(const InstructionBlock* block);
176 :
177 : // Initializes the masking register in the prologue of a function.
178 : void InitializeSpeculationPoison();
179 : // Reset the masking register during execution of a function.
180 : void ResetSpeculationPoison();
181 : // Generates a mask from the pc passed in {kJavaScriptCallCodeStartRegister}.
182 : void GenerateSpeculationPoisonFromCodeStartRegister();
183 :
184 : // Assemble code for the specified instruction.
185 : CodeGenResult AssembleInstruction(Instruction* instr,
186 : const InstructionBlock* block);
187 : void AssembleGaps(Instruction* instr);
188 :
189 : // Compute branch info from given instruction. Returns a valid rpo number
190 : // if the branch is redundant, the returned rpo number point to the target
191 : // basic block.
192 : RpoNumber ComputeBranchInfo(BranchInfo* branch, Instruction* instr);
193 :
194 : // Returns true if a instruction is a tail call that needs to adjust the stack
195 : // pointer before execution. The stack slot index to the empty slot above the
196 : // adjusted stack pointer is returned in |slot|.
197 : bool GetSlotAboveSPBeforeTailCall(Instruction* instr, int* slot);
198 :
199 : // Determines how to call helper stubs depending on the code kind.
200 : StubCallMode DetermineStubCallMode() const;
201 :
202 : CodeGenResult AssembleDeoptimizerCall(int deoptimization_id,
203 : SourcePosition pos);
204 :
205 : // ===========================================================================
206 : // ============= Architecture-specific code generation methods. ==============
207 : // ===========================================================================
208 :
209 : CodeGenResult AssembleArchInstruction(Instruction* instr);
210 : void AssembleArchJump(RpoNumber target);
211 : void AssembleArchBranch(Instruction* instr, BranchInfo* branch);
212 :
213 : // Generates special branch for deoptimization condition.
214 : void AssembleArchDeoptBranch(Instruction* instr, BranchInfo* branch);
215 :
216 : void AssembleArchBoolean(Instruction* instr, FlagsCondition condition);
217 : void AssembleArchTrap(Instruction* instr, FlagsCondition condition);
218 : void AssembleArchBinarySearchSwitchRange(Register input, RpoNumber def_block,
219 : std::pair<int32_t, Label*>* begin,
220 : std::pair<int32_t, Label*>* end);
221 : void AssembleArchBinarySearchSwitch(Instruction* instr);
222 : void AssembleArchLookupSwitch(Instruction* instr);
223 : void AssembleArchTableSwitch(Instruction* instr);
224 :
225 : // Generates code that checks whether the {kJavaScriptCallCodeStartRegister}
226 : // contains the expected pointer to the start of the instruction stream.
227 : void AssembleCodeStartRegisterCheck();
228 :
229 : void AssembleBranchPoisoning(FlagsCondition condition, Instruction* instr);
230 :
231 : // When entering a code that is marked for deoptimization, rather continuing
232 : // with its execution, we jump to a lazy compiled code. We need to do this
233 : // because this code has already been deoptimized and needs to be unlinked
234 : // from the JS functions referring it.
235 : void BailoutIfDeoptimized();
236 :
237 : // Generates code to poison the stack pointer and implicit register arguments
238 : // like the context register and the function register.
239 : void AssembleRegisterArgumentPoisoning();
240 :
241 : // Generates an architecture-specific, descriptor-specific prologue
242 : // to set up a stack frame.
243 : void AssembleConstructFrame();
244 :
245 : // Generates an architecture-specific, descriptor-specific return sequence
246 : // to tear down a stack frame.
247 : void AssembleReturn(InstructionOperand* pop);
248 :
249 : void AssembleDeconstructFrame();
250 :
251 : // Generates code to manipulate the stack in preparation for a tail call.
252 : void AssemblePrepareTailCall();
253 :
254 : // Generates code to pop current frame if it is an arguments adaptor frame.
255 : void AssemblePopArgumentsAdaptorFrame(Register args_reg, Register scratch1,
256 : Register scratch2, Register scratch3);
257 :
258 : enum PushTypeFlag {
259 : kImmediatePush = 0x1,
260 : kRegisterPush = 0x2,
261 : kStackSlotPush = 0x4,
262 : kScalarPush = kRegisterPush | kStackSlotPush
263 : };
264 :
265 : using PushTypeFlags = base::Flags<PushTypeFlag>;
266 :
267 : static bool IsValidPush(InstructionOperand source, PushTypeFlags push_type);
268 :
269 : // Generate a list moves from an instruction that are candidates to be turned
270 : // into push instructions on platforms that support them. In general, the list
271 : // of push candidates are moves to a set of contiguous destination
272 : // InstructionOperand locations on the stack that don't clobber values that
273 : // are needed for resolve the gap or use values generated by the gap,
274 : // i.e. moves that can be hoisted together before the actual gap and assembled
275 : // together.
276 : static void GetPushCompatibleMoves(Instruction* instr,
277 : PushTypeFlags push_type,
278 : ZoneVector<MoveOperands*>* pushes);
279 :
280 : class MoveType {
281 : public:
282 : enum Type {
283 : kRegisterToRegister,
284 : kRegisterToStack,
285 : kStackToRegister,
286 : kStackToStack,
287 : kConstantToRegister,
288 : kConstantToStack
289 : };
290 :
291 : // Detect what type of move or swap needs to be performed. Note that these
292 : // functions do not take into account the representation (Tagged, FP,
293 : // ...etc).
294 :
295 : static Type InferMove(InstructionOperand* source,
296 : InstructionOperand* destination);
297 : static Type InferSwap(InstructionOperand* source,
298 : InstructionOperand* destination);
299 : };
300 : // Called before a tail call |instr|'s gap moves are assembled and allows
301 : // gap-specific pre-processing, e.g. adjustment of the sp for tail calls that
302 : // need it before gap moves or conversion of certain gap moves into pushes.
303 : void AssembleTailCallBeforeGap(Instruction* instr,
304 : int first_unused_stack_slot);
305 : // Called after a tail call |instr|'s gap moves are assembled and allows
306 : // gap-specific post-processing, e.g. adjustment of the sp for tail calls that
307 : // need it after gap moves.
308 : void AssembleTailCallAfterGap(Instruction* instr,
309 : int first_unused_stack_slot);
310 :
311 : void FinishCode();
312 : void MaybeEmitOutOfLineConstantPool();
313 :
314 : // ===========================================================================
315 : // ============== Architecture-specific gap resolver methods. ================
316 : // ===========================================================================
317 :
318 : // Interface used by the gap resolver to emit moves and swaps.
319 : void AssembleMove(InstructionOperand* source,
320 : InstructionOperand* destination) final;
321 : void AssembleSwap(InstructionOperand* source,
322 : InstructionOperand* destination) final;
323 :
324 : // ===========================================================================
325 : // =================== Jump table construction methods. ======================
326 : // ===========================================================================
327 :
328 : class JumpTable;
329 : // Adds a jump table that is emitted after the actual code. Returns label
330 : // pointing to the beginning of the table. {targets} is assumed to be static
331 : // or zone allocated.
332 : Label* AddJumpTable(Label** targets, size_t target_count);
333 : // Emits a jump table.
334 : void AssembleJumpTable(Label** targets, size_t target_count);
335 :
336 : // ===========================================================================
337 : // ================== Deoptimization table construction. =====================
338 : // ===========================================================================
339 :
340 : void RecordCallPosition(Instruction* instr);
341 : Handle<DeoptimizationData> GenerateDeoptimizationData();
342 : int DefineDeoptimizationLiteral(DeoptimizationLiteral literal);
343 : DeoptimizationEntry const& GetDeoptimizationEntry(Instruction* instr,
344 : size_t frame_state_offset);
345 : DeoptimizeKind GetDeoptimizationKind(int deoptimization_id) const;
346 : DeoptimizeReason GetDeoptimizationReason(int deoptimization_id) const;
347 : int BuildTranslation(Instruction* instr, int pc_offset,
348 : size_t frame_state_offset,
349 : OutputFrameStateCombine state_combine);
350 : void BuildTranslationForFrameStateDescriptor(
351 : FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
352 : Translation* translation, OutputFrameStateCombine state_combine);
353 : void TranslateStateValueDescriptor(StateValueDescriptor* desc,
354 : StateValueList* nested,
355 : Translation* translation,
356 : InstructionOperandIterator* iter);
357 : void TranslateFrameStateDescriptorOperands(FrameStateDescriptor* desc,
358 : InstructionOperandIterator* iter,
359 : Translation* translation);
360 : void AddTranslationForOperand(Translation* translation, Instruction* instr,
361 : InstructionOperand* op, MachineType type);
362 : void MarkLazyDeoptSite();
363 :
364 : DeoptimizationExit* AddDeoptimizationExit(Instruction* instr,
365 : size_t frame_state_offset);
366 :
367 : // ===========================================================================
368 :
369 : class DeoptimizationState final : public ZoneObject {
370 : public:
371 : DeoptimizationState(BailoutId bailout_id, int translation_id, int pc_offset,
372 : DeoptimizeKind kind, DeoptimizeReason reason)
373 : : bailout_id_(bailout_id),
374 : translation_id_(translation_id),
375 : pc_offset_(pc_offset),
376 : kind_(kind),
377 3329980 : reason_(reason) {}
378 :
379 : BailoutId bailout_id() const { return bailout_id_; }
380 : int translation_id() const { return translation_id_; }
381 : int pc_offset() const { return pc_offset_; }
382 : DeoptimizeKind kind() const { return kind_; }
383 : DeoptimizeReason reason() const { return reason_; }
384 :
385 : private:
386 : BailoutId bailout_id_;
387 : int translation_id_;
388 : int pc_offset_;
389 : DeoptimizeKind kind_;
390 : DeoptimizeReason reason_;
391 : };
392 :
393 : struct HandlerInfo {
394 : Label* handler;
395 : int pc_offset;
396 : };
397 :
398 : friend class OutOfLineCode;
399 : friend class CodeGeneratorTester;
400 :
401 : Zone* zone_;
402 : Isolate* isolate_;
403 : FrameAccessState* frame_access_state_;
404 : Linkage* const linkage_;
405 : InstructionSequence* const instructions_;
406 : UnwindingInfoWriter unwinding_info_writer_;
407 : OptimizedCompilationInfo* const info_;
408 : Label* const labels_;
409 : Label return_label_;
410 : RpoNumber current_block_;
411 : SourcePosition start_source_position_;
412 : SourcePosition current_source_position_;
413 : TurboAssembler tasm_;
414 : GapResolver resolver_;
415 : SafepointTableBuilder safepoints_;
416 : ZoneVector<HandlerInfo> handlers_;
417 : ZoneDeque<DeoptimizationExit*> deoptimization_exits_;
418 : ZoneDeque<DeoptimizationState*> deoptimization_states_;
419 : ZoneDeque<DeoptimizationLiteral> deoptimization_literals_;
420 : size_t inlined_function_count_ = 0;
421 : TranslationBuffer translations_;
422 : int handler_table_offset_ = 0;
423 : int last_lazy_deopt_pc_ = 0;
424 :
425 : // kArchCallCFunction could be reached either:
426 : // kArchCallCFunction;
427 : // or:
428 : // kArchSaveCallerRegisters;
429 : // kArchCallCFunction;
430 : // kArchRestoreCallerRegisters;
431 : // The boolean is used to distinguish the two cases. In the latter case, we
432 : // also need to decide if FP registers need to be saved, which is controlled
433 : // by fp_mode_.
434 : bool caller_registers_saved_;
435 : SaveFPRegsMode fp_mode_;
436 :
437 : JumpTable* jump_tables_;
438 : OutOfLineCode* ools_;
439 : base::Optional<OsrHelper> osr_helper_;
440 : int osr_pc_offset_;
441 : int optimized_out_literal_id_;
442 : SourcePositionTableBuilder source_position_table_builder_;
443 : ZoneVector<trap_handler::ProtectedInstructionData> protected_instructions_;
444 : CodeGenResult result_;
445 : PoisoningMitigationLevel poisoning_level_;
446 : ZoneVector<int> block_starts_;
447 : ZoneVector<int> instr_starts_;
448 : };
449 :
450 : } // namespace compiler
451 : } // namespace internal
452 : } // namespace v8
453 :
454 : #endif // V8_COMPILER_BACKEND_CODE_GENERATOR_H_
|