• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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_INTERPRETER_INTERPRETER_ASSEMBLER_H_
6 #define V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_
7 
8 #include "src/allocation.h"
9 #include "src/builtins/builtins.h"
10 #include "src/code-stub-assembler.h"
11 #include "src/globals.h"
12 #include "src/interpreter/bytecode-register.h"
13 #include "src/interpreter/bytecodes.h"
14 #include "src/runtime/runtime.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace interpreter {
19 
20 class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
21  public:
22   InterpreterAssembler(compiler::CodeAssemblerState* state, Bytecode bytecode,
23                        OperandScale operand_scale);
24   ~InterpreterAssembler();
25 
26   // Returns the 32-bit unsigned count immediate for bytecode operand
27   // |operand_index| in the current bytecode.
28   compiler::Node* BytecodeOperandCount(int operand_index);
29   // Returns the 32-bit unsigned flag for bytecode operand |operand_index|
30   // in the current bytecode.
31   compiler::Node* BytecodeOperandFlag(int operand_index);
32   // Returns the 32-bit zero-extended index immediate for bytecode operand
33   // |operand_index| in the current bytecode.
34   compiler::Node* BytecodeOperandIdxInt32(int operand_index);
35   // Returns the word zero-extended index immediate for bytecode operand
36   // |operand_index| in the current bytecode.
37   compiler::Node* BytecodeOperandIdx(int operand_index);
38   // Returns the smi index immediate for bytecode operand |operand_index|
39   // in the current bytecode.
40   compiler::Node* BytecodeOperandIdxSmi(int operand_index);
41   // Returns the 32-bit unsigned immediate for bytecode operand |operand_index|
42   // in the current bytecode.
43   compiler::Node* BytecodeOperandUImm(int operand_index);
44   // Returns the word-size unsigned immediate for bytecode operand
45   // |operand_index| in the current bytecode.
46   compiler::Node* BytecodeOperandUImmWord(int operand_index);
47   // Returns the unsigned smi immediate for bytecode operand |operand_index| in
48   // the current bytecode.
49   compiler::Node* BytecodeOperandUImmSmi(int operand_index);
50   // Returns the 32-bit signed immediate for bytecode operand |operand_index|
51   // in the current bytecode.
52   compiler::Node* BytecodeOperandImm(int operand_index);
53   // Returns the word-size signed immediate for bytecode operand |operand_index|
54   // in the current bytecode.
55   compiler::Node* BytecodeOperandImmIntPtr(int operand_index);
56   // Returns the smi immediate for bytecode operand |operand_index| in the
57   // current bytecode.
58   compiler::Node* BytecodeOperandImmSmi(int operand_index);
59   // Returns the 32-bit unsigned runtime id immediate for bytecode operand
60   // |operand_index| in the current bytecode.
61   compiler::Node* BytecodeOperandRuntimeId(int operand_index);
62   // Returns the 32-bit unsigned native context index immediate for bytecode
63   // operand |operand_index| in the current bytecode.
64   compiler::Node* BytecodeOperandNativeContextIndex(int operand_index);
65   // Returns the 32-bit unsigned intrinsic id immediate for bytecode operand
66   // |operand_index| in the current bytecode.
67   compiler::Node* BytecodeOperandIntrinsicId(int operand_index);
68 
69   // Accumulator.
70   compiler::Node* GetAccumulator();
71   void SetAccumulator(compiler::Node* value);
72 
73   // Context.
74   compiler::Node* GetContext();
75   void SetContext(compiler::Node* value);
76 
77   // Context at |depth| in the context chain starting at |context|.
78   compiler::Node* GetContextAtDepth(compiler::Node* context,
79                                     compiler::Node* depth);
80 
81   // Goto the given |target| if the context chain starting at |context| has any
82   // extensions up to the given |depth|.
83   void GotoIfHasContextExtensionUpToDepth(compiler::Node* context,
84                                           compiler::Node* depth, Label* target);
85 
86   // A RegListNodePair provides an abstraction over lists of registers.
87   class RegListNodePair {
88    public:
RegListNodePair(Node * base_reg_location,Node * reg_count)89     RegListNodePair(Node* base_reg_location, Node* reg_count)
90         : base_reg_location_(base_reg_location), reg_count_(reg_count) {}
91 
reg_count()92     compiler::Node* reg_count() const { return reg_count_; }
base_reg_location()93     compiler::Node* base_reg_location() const { return base_reg_location_; }
94 
95    private:
96     compiler::Node* base_reg_location_;
97     compiler::Node* reg_count_;
98   };
99 
100   // Backup/restore register file to/from a fixed array of the correct length.
101   // There is an asymmetry between suspend/export and resume/import.
102   // - Suspend copies arguments and registers to the generator.
103   // - Resume copies only the registers from the generator, the arguments
104   //   are copied by the ResumeGenerator trampoline.
105   compiler::Node* ExportParametersAndRegisterFile(
106       TNode<FixedArray> array, const RegListNodePair& registers,
107       TNode<Int32T> formal_parameter_count);
108   compiler::Node* ImportRegisterFile(TNode<FixedArray> array,
109                                      const RegListNodePair& registers,
110                                      TNode<Int32T> formal_parameter_count);
111 
112   // Loads from and stores to the interpreter register file.
113   compiler::Node* LoadRegister(Register reg);
114   compiler::Node* LoadAndUntagRegister(Register reg);
115   compiler::Node* LoadRegisterAtOperandIndex(int operand_index);
116   std::pair<compiler::Node*, compiler::Node*> LoadRegisterPairAtOperandIndex(
117       int operand_index);
118   void StoreRegister(compiler::Node* value, Register reg);
119   void StoreAndTagRegister(compiler::Node* value, Register reg);
120   void StoreRegisterAtOperandIndex(compiler::Node* value, int operand_index);
121   void StoreRegisterPairAtOperandIndex(compiler::Node* value1,
122                                        compiler::Node* value2,
123                                        int operand_index);
124   void StoreRegisterTripleAtOperandIndex(compiler::Node* value1,
125                                          compiler::Node* value2,
126                                          compiler::Node* value3,
127                                          int operand_index);
128 
129   RegListNodePair GetRegisterListAtOperandIndex(int operand_index);
130   Node* LoadRegisterFromRegisterList(const RegListNodePair& reg_list,
131                                      int index);
132   Node* RegisterLocationInRegisterList(const RegListNodePair& reg_list,
133                                        int index);
134 
135   // Load constant at the index specified in operand |operand_index| from the
136   // constant pool.
137   compiler::Node* LoadConstantPoolEntryAtOperandIndex(int operand_index);
138   // Load and untag constant at the index specified in operand |operand_index|
139   // from the constant pool.
140   compiler::Node* LoadAndUntagConstantPoolEntryAtOperandIndex(
141       int operand_index);
142   // Load constant at |index| in the constant pool.
143   compiler::Node* LoadConstantPoolEntry(compiler::Node* index);
144   // Load and untag constant at |index| in the constant pool.
145   compiler::Node* LoadAndUntagConstantPoolEntry(compiler::Node* index);
146 
147   // Load the FeedbackVector for the current function.
148   compiler::TNode<FeedbackVector> LoadFeedbackVector();
149 
150   // Increment the call count for a CALL_IC or construct call.
151   // The call count is located at feedback_vector[slot_id + 1].
152   void IncrementCallCount(compiler::Node* feedback_vector,
153                           compiler::Node* slot_id);
154 
155   // Collect the callable |target| feedback for either a CALL_IC or
156   // an INSTANCEOF_IC in the |feedback_vector| at |slot_id|.
157   void CollectCallableFeedback(compiler::Node* target, compiler::Node* context,
158                                compiler::Node* feedback_vector,
159                                compiler::Node* slot_id);
160 
161   // Collect CALL_IC feedback for |target| function in the
162   // |feedback_vector| at |slot_id|, and the call counts in
163   // the |feedback_vector| at |slot_id+1|.
164   void CollectCallFeedback(compiler::Node* target, compiler::Node* context,
165                            compiler::Node* feedback_vector,
166                            compiler::Node* slot_id);
167 
168   // Call JSFunction or Callable |function| with |args| arguments, possibly
169   // including the receiver depending on |receiver_mode|. After the call returns
170   // directly dispatches to the next bytecode.
171   void CallJSAndDispatch(compiler::Node* function, compiler::Node* context,
172                          const RegListNodePair& args,
173                          ConvertReceiverMode receiver_mode);
174 
175   // Call JSFunction or Callable |function| with |arg_count| arguments (not
176   // including receiver) passed as |args|, possibly including the receiver
177   // depending on |receiver_mode|. After the call returns directly dispatches to
178   // the next bytecode.
179   template <class... TArgs>
180   void CallJSAndDispatch(Node* function, Node* context, Node* arg_count,
181                          ConvertReceiverMode receiver_mode, TArgs... args);
182 
183   // Call JSFunction or Callable |function| with |args|
184   // arguments (not including receiver), and the final argument being spread.
185   // After the call returns directly dispatches to the next bytecode.
186   void CallJSWithSpreadAndDispatch(compiler::Node* function,
187                                    compiler::Node* context,
188                                    const RegListNodePair& args,
189                                    compiler::Node* slot_id,
190                                    compiler::Node* feedback_vector);
191 
192   // Call constructor |target| with |args| arguments (not including receiver).
193   // The |new_target| is the same as the |target| for the new keyword, but
194   // differs for the super keyword.
195   compiler::Node* Construct(compiler::Node* target, compiler::Node* context,
196                             compiler::Node* new_target,
197                             const RegListNodePair& args,
198                             compiler::Node* slot_id,
199                             compiler::Node* feedback_vector);
200 
201   // Call constructor |target| with |args| arguments (not including
202   // receiver). The last argument is always a spread. The |new_target| is the
203   // same as the |target| for the new keyword, but differs for the super
204   // keyword.
205   compiler::Node* ConstructWithSpread(compiler::Node* target,
206                                       compiler::Node* context,
207                                       compiler::Node* new_target,
208                                       const RegListNodePair& args,
209                                       compiler::Node* slot_id,
210                                       compiler::Node* feedback_vector);
211 
212   // Call runtime function with |args| arguments which will return |return_size|
213   // number of values.
214   compiler::Node* CallRuntimeN(compiler::Node* function_id,
215                                compiler::Node* context,
216                                const RegListNodePair& args,
217                                int return_size = 1);
218 
219   // Jump forward relative to the current bytecode by the |jump_offset|.
220   compiler::Node* Jump(compiler::Node* jump_offset);
221 
222   // Jump backward relative to the current bytecode by the |jump_offset|.
223   compiler::Node* JumpBackward(compiler::Node* jump_offset);
224 
225   // Jump forward relative to the current bytecode by |jump_offset| if the
226   // word values |lhs| and |rhs| are equal.
227   void JumpIfWordEqual(compiler::Node* lhs, compiler::Node* rhs,
228                        compiler::Node* jump_offset);
229 
230   // Jump forward relative to the current bytecode by |jump_offset| if the
231   // word values |lhs| and |rhs| are not equal.
232   void JumpIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
233                           compiler::Node* jump_offset);
234 
235   // Updates the profiler interrupt budget for a return.
236   void UpdateInterruptBudgetOnReturn();
237 
238   // Returns the OSR nesting level from the bytecode header.
239   compiler::Node* LoadOSRNestingLevel();
240 
241   // Dispatch to the bytecode.
242   compiler::Node* Dispatch();
243 
244   // Dispatch bytecode as wide operand variant.
245   void DispatchWide(OperandScale operand_scale);
246 
247   // Dispatch to |target_bytecode| at |new_bytecode_offset|.
248   // |target_bytecode| should be equivalent to loading from the offset.
249   compiler::Node* DispatchToBytecode(compiler::Node* target_bytecode,
250                                      compiler::Node* new_bytecode_offset);
251 
252   // Abort with the given abort reason.
253   void Abort(AbortReason abort_reason);
254   void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
255                            AbortReason abort_reason);
256   // Abort if |register_count| is invalid for given register file array.
257   void AbortIfRegisterCountInvalid(compiler::Node* parameters_and_registers,
258                                    compiler::Node* formal_parameter_count,
259                                    compiler::Node* register_count);
260 
261   // Dispatch to frame dropper trampoline if necessary.
262   void MaybeDropFrames(compiler::Node* context);
263 
264   // Returns the offset from the BytecodeArrayPointer of the current bytecode.
265   compiler::Node* BytecodeOffset();
266 
267  protected:
bytecode()268   Bytecode bytecode() const { return bytecode_; }
269   static bool TargetSupportsUnalignedAccess();
270 
271   void ToNumberOrNumeric(Object::Conversion mode);
272 
273   // Lazily deserializes the current bytecode's handler and tail-calls into it.
274   void DeserializeLazyAndDispatch();
275 
276  private:
277   // Returns a tagged pointer to the current function's BytecodeArray object.
278   compiler::Node* BytecodeArrayTaggedPointer();
279 
280   // Returns a raw pointer to first entry in the interpreter dispatch table.
281   compiler::Node* DispatchTableRawPointer();
282 
283   // Returns the accumulator value without checking whether bytecode
284   // uses it. This is intended to be used only in dispatch and in
285   // tracing as these need to bypass accumulator use validity checks.
286   compiler::Node* GetAccumulatorUnchecked();
287 
288   // Returns the frame pointer for the interpreted frame of the function being
289   // interpreted.
290   compiler::Node* GetInterpretedFramePointer();
291 
292   // Operations on registers.
293   compiler::Node* RegisterLocation(Register reg);
294   compiler::Node* RegisterLocation(compiler::Node* reg_index);
295   compiler::Node* NextRegister(compiler::Node* reg_index);
296   compiler::Node* LoadRegister(Node* reg_index);
297   void StoreRegister(compiler::Node* value, compiler::Node* reg_index);
298 
299   // Saves and restores interpreter bytecode offset to the interpreter stack
300   // frame when performing a call.
301   void CallPrologue();
302   void CallEpilogue();
303 
304   // Increment the dispatch counter for the (current, next) bytecode pair.
305   void TraceBytecodeDispatch(compiler::Node* target_index);
306 
307   // Traces the current bytecode by calling |function_id|.
308   void TraceBytecode(Runtime::FunctionId function_id);
309 
310   // Updates the bytecode array's interrupt budget by a 32-bit unsigned |weight|
311   // and calls Runtime::kInterrupt if counter reaches zero. If |backward|, then
312   // the interrupt budget is decremented, otherwise it is incremented.
313   void UpdateInterruptBudget(compiler::Node* weight, bool backward);
314 
315   // Returns the offset of register |index| relative to RegisterFilePointer().
316   compiler::Node* RegisterFrameOffset(compiler::Node* index);
317 
318   // Returns the offset of an operand relative to the current bytecode offset.
319   compiler::Node* OperandOffset(int operand_index);
320 
321   // Returns a value built from an sequence of bytes in the bytecode
322   // array starting at |relative_offset| from the current bytecode.
323   // The |result_type| determines the size and signedness.  of the
324   // value read. This method should only be used on architectures that
325   // do not support unaligned memory accesses.
326   compiler::Node* BytecodeOperandReadUnaligned(
327       int relative_offset, MachineType result_type,
328       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
329 
330   // Returns zero- or sign-extended to word32 value of the operand.
331   compiler::Node* BytecodeOperandUnsignedByte(
332       int operand_index,
333       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
334   compiler::Node* BytecodeOperandSignedByte(
335       int operand_index,
336       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
337   compiler::Node* BytecodeOperandUnsignedShort(
338       int operand_index,
339       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
340   compiler::Node* BytecodeOperandSignedShort(
341       int operand_index,
342       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
343   compiler::Node* BytecodeOperandUnsignedQuad(
344       int operand_index,
345       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
346   compiler::Node* BytecodeOperandSignedQuad(
347       int operand_index,
348       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
349 
350   // Returns zero- or sign-extended to word32 value of the operand of
351   // given size.
352   compiler::Node* BytecodeSignedOperand(
353       int operand_index, OperandSize operand_size,
354       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
355   compiler::Node* BytecodeUnsignedOperand(
356       int operand_index, OperandSize operand_size,
357       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
358 
359   // Returns the word-size sign-extended register index for bytecode operand
360   // |operand_index| in the current bytecode. Value is not poisoned on
361   // speculation since the value loaded from the register is poisoned instead.
362   compiler::Node* BytecodeOperandReg(
363       int operand_index,
364       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
365 
366   // Returns the word zero-extended index immediate for bytecode operand
367   // |operand_index| in the current bytecode for use when loading a .
368   compiler::Node* BytecodeOperandConstantPoolIdx(
369       int operand_index,
370       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
371 
372   // Jump relative to the current bytecode by the |jump_offset|. If |backward|,
373   // then jump backward (subtract the offset), otherwise jump forward (add the
374   // offset). Helper function for Jump and JumpBackward.
375   compiler::Node* Jump(compiler::Node* jump_offset, bool backward);
376 
377   // Jump forward relative to the current bytecode by |jump_offset| if the
378   // |condition| is true. Helper function for JumpIfWordEqual and
379   // JumpIfWordNotEqual.
380   void JumpConditional(compiler::Node* condition, compiler::Node* jump_offset);
381 
382   // Save the bytecode offset to the interpreter frame.
383   void SaveBytecodeOffset();
384   // Reload the bytecode offset from the interpreter frame.
385   Node* ReloadBytecodeOffset();
386 
387   // Updates and returns BytecodeOffset() advanced by the current bytecode's
388   // size. Traces the exit of the current bytecode.
389   compiler::Node* Advance();
390 
391   // Updates and returns BytecodeOffset() advanced by delta bytecodes.
392   // Traces the exit of the current bytecode.
393   compiler::Node* Advance(int delta);
394   compiler::Node* Advance(compiler::Node* delta, bool backward = false);
395 
396   // Load the bytecode at |bytecode_offset|.
397   compiler::Node* LoadBytecode(compiler::Node* bytecode_offset);
398 
399   // Look ahead for Star and inline it in a branch. Returns a new target
400   // bytecode node for dispatch.
401   compiler::Node* StarDispatchLookahead(compiler::Node* target_bytecode);
402 
403   // Build code for Star at the current BytecodeOffset() and Advance() to the
404   // next dispatch offset.
405   void InlineStar();
406 
407   // Dispatch to the bytecode handler with code offset |handler|.
408   compiler::Node* DispatchToBytecodeHandler(compiler::Node* handler,
409                                             compiler::Node* bytecode_offset,
410                                             compiler::Node* target_bytecode);
411 
412   // Dispatch to the bytecode handler with code entry point |handler_entry|.
413   compiler::Node* DispatchToBytecodeHandlerEntry(
414       compiler::Node* handler_entry, compiler::Node* bytecode_offset,
415       compiler::Node* target_bytecode);
416 
417   int CurrentBytecodeSize() const;
418 
operand_scale()419   OperandScale operand_scale() const { return operand_scale_; }
420 
421   Bytecode bytecode_;
422   OperandScale operand_scale_;
423   CodeStubAssembler::Variable interpreted_frame_pointer_;
424   CodeStubAssembler::Variable bytecode_array_;
425   CodeStubAssembler::Variable bytecode_offset_;
426   CodeStubAssembler::Variable dispatch_table_;
427   CodeStubAssembler::Variable accumulator_;
428   AccumulatorUse accumulator_use_;
429   bool made_call_;
430   bool reloaded_frame_ptr_;
431   bool bytecode_array_valid_;
432   bool disable_stack_check_across_call_;
433   compiler::Node* stack_pointer_before_call_;
434 
435   DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler);
436 };
437 
438 }  // namespace interpreter
439 }  // namespace internal
440 }  // namespace v8
441 
442 #endif  // V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_
443