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