• 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   // Goto the given |target| if the context chain starting at |context| has any
86   // extensions up to the given |depth|.
87   void GotoIfHasContextExtensionUpToDepth(TNode<Context> context,
88                                           TNode<Uint32T> depth, Label* target);
89 
90   // A RegListNodePair provides an abstraction over lists of registers.
91   class RegListNodePair {
92    public:
RegListNodePair(TNode<IntPtrT> base_reg_location,TNode<Word32T> reg_count)93     RegListNodePair(TNode<IntPtrT> base_reg_location, TNode<Word32T> reg_count)
94         : base_reg_location_(base_reg_location), reg_count_(reg_count) {}
95 
reg_count()96     TNode<Word32T> reg_count() const { return reg_count_; }
base_reg_location()97     TNode<IntPtrT> base_reg_location() const { return base_reg_location_; }
98 
99    private:
100     TNode<IntPtrT> base_reg_location_;
101     TNode<Word32T> reg_count_;
102   };
103 
104   // Backup/restore register file to/from a fixed array of the correct length.
105   // There is an asymmetry between suspend/export and resume/import.
106   // - Suspend copies arguments and registers to the generator.
107   // - Resume copies only the registers from the generator, the arguments
108   //   are copied by the ResumeGenerator trampoline.
109   TNode<FixedArray> ExportParametersAndRegisterFile(
110       TNode<FixedArray> array, const RegListNodePair& registers,
111       TNode<Int32T> formal_parameter_count);
112   TNode<FixedArray> ImportRegisterFile(TNode<FixedArray> array,
113                                        const RegListNodePair& registers,
114                                        TNode<Int32T> formal_parameter_count);
115 
116   // Loads from and stores to the interpreter register file.
117   TNode<Object> LoadRegister(Register reg);
118   TNode<IntPtrT> LoadAndUntagRegister(Register reg);
119   TNode<Object> LoadRegisterAtOperandIndex(int operand_index);
120   std::pair<TNode<Object>, TNode<Object>> LoadRegisterPairAtOperandIndex(
121       int operand_index);
122   void StoreRegister(TNode<Object> value, Register reg);
123   void StoreRegisterAtOperandIndex(TNode<Object> value, int operand_index);
124   void StoreRegisterPairAtOperandIndex(TNode<Object> value1,
125                                        TNode<Object> value2, int operand_index);
126   void StoreRegisterTripleAtOperandIndex(TNode<Object> value1,
127                                          TNode<Object> value2,
128                                          TNode<Object> value3,
129                                          int operand_index);
130 
131   RegListNodePair GetRegisterListAtOperandIndex(int operand_index);
132   TNode<Object> LoadRegisterFromRegisterList(const RegListNodePair& reg_list,
133                                              int index);
134   TNode<IntPtrT> RegisterLocationInRegisterList(const RegListNodePair& reg_list,
135                                                 int index);
136 
137   // Load constant at the index specified in operand |operand_index| from the
138   // constant pool.
139   TNode<Object> LoadConstantPoolEntryAtOperandIndex(int operand_index);
140   // Load and untag constant at the index specified in operand |operand_index|
141   // from the constant pool.
142   TNode<IntPtrT> LoadAndUntagConstantPoolEntryAtOperandIndex(int operand_index);
143   // Load constant at |index| in the constant pool.
144   TNode<Object> LoadConstantPoolEntry(TNode<WordT> index);
145   // Load and untag constant at |index| in the constant pool.
146   TNode<IntPtrT> LoadAndUntagConstantPoolEntry(TNode<WordT> index);
147 
148   // Load the FeedbackVector for the current function. The retuned node could be
149   // undefined.
150   TNode<HeapObject> LoadFeedbackVector();
151 
152   // Call JSFunction or Callable |function| with |args| arguments, possibly
153   // including the receiver depending on |receiver_mode|. After the call returns
154   // directly dispatches to the next bytecode.
155   void CallJSAndDispatch(TNode<Object> function, TNode<Context> context,
156                          const RegListNodePair& args,
157                          ConvertReceiverMode receiver_mode);
158 
159   // Call JSFunction or Callable |function| with |arg_count| arguments (not
160   // including receiver) passed as |args|, possibly including the receiver
161   // depending on |receiver_mode|. After the call returns directly dispatches to
162   // the next bytecode.
163   template <class... TArgs>
164   void CallJSAndDispatch(TNode<Object> function, TNode<Context> context,
165                          TNode<Word32T> arg_count,
166                          ConvertReceiverMode receiver_mode, TArgs... args);
167 
168   // Call JSFunction or Callable |function| with |args|
169   // arguments (not including receiver), and the final argument being spread.
170   // After the call returns directly dispatches to the next bytecode.
171   void CallJSWithSpreadAndDispatch(TNode<Object> function,
172                                    TNode<Context> context,
173                                    const RegListNodePair& args,
174                                    TNode<UintPtrT> slot_id,
175                                    TNode<HeapObject> maybe_feedback_vector);
176 
177   // Call constructor |target| with |args| arguments (not including receiver).
178   // The |new_target| is the same as the |target| for the new keyword, but
179   // differs for the super keyword.
180   TNode<Object> Construct(TNode<Object> target, TNode<Context> context,
181                           TNode<Object> new_target, const RegListNodePair& args,
182                           TNode<UintPtrT> slot_id,
183                           TNode<HeapObject> maybe_feedback_vector);
184 
185   // Call constructor |target| with |args| arguments (not including
186   // receiver). The last argument is always a spread. The |new_target| is the
187   // same as the |target| for the new keyword, but differs for the super
188   // keyword.
189   TNode<Object> ConstructWithSpread(TNode<Object> target,
190                                     TNode<Context> context,
191                                     TNode<Object> new_target,
192                                     const RegListNodePair& args,
193                                     TNode<UintPtrT> slot_id,
194                                     TNode<HeapObject> maybe_feedback_vector);
195 
196   // Call runtime function with |args| arguments.
197   template <class T = Object>
198   TNode<T> CallRuntimeN(TNode<Uint32T> function_id, TNode<Context> context,
199                         const RegListNodePair& args, int return_count);
200 
201   // Jump forward relative to the current bytecode by the |jump_offset|.
202   void Jump(TNode<IntPtrT> jump_offset);
203 
204   // Jump backward relative to the current bytecode by the |jump_offset|.
205   void JumpBackward(TNode<IntPtrT> jump_offset);
206 
207   // Jump forward relative to the current bytecode by |jump_offset| if the
208   // word values |lhs| and |rhs| are equal.
209   void JumpIfTaggedEqual(TNode<Object> lhs, TNode<Object> rhs,
210                          TNode<IntPtrT> jump_offset);
211 
212   // Jump forward relative to the current bytecode by |jump_offset| if the
213   // word values |lhs| and |rhs| are not equal.
214   void JumpIfTaggedNotEqual(TNode<Object> lhs, TNode<Object> rhs,
215                             TNode<IntPtrT> jump_offset);
216 
217   // Updates the profiler interrupt budget for a return.
218   void UpdateInterruptBudgetOnReturn();
219 
220   // Returns the OSR nesting level from the bytecode header.
221   TNode<Int8T> LoadOsrNestingLevel();
222 
223   // Dispatch to the bytecode.
224   void Dispatch();
225 
226   // Dispatch bytecode as wide operand variant.
227   void DispatchWide(OperandScale operand_scale);
228 
229   // Dispatch to |target_bytecode| at |new_bytecode_offset|.
230   // |target_bytecode| should be equivalent to loading from the offset.
231   void DispatchToBytecode(TNode<WordT> target_bytecode,
232                           TNode<IntPtrT> new_bytecode_offset);
233 
234   // Abort with the given abort reason.
235   void Abort(AbortReason abort_reason);
236   void AbortIfWordNotEqual(TNode<WordT> lhs, TNode<WordT> rhs,
237                            AbortReason abort_reason);
238   // Abort if |register_count| is invalid for given register file array.
239   void AbortIfRegisterCountInvalid(
240       TNode<FixedArrayBase> parameters_and_registers,
241       TNode<IntPtrT> formal_parameter_count, TNode<UintPtrT> register_count);
242 
243   // Dispatch to frame dropper trampoline if necessary.
244   void MaybeDropFrames(TNode<Context> context);
245 
246   // Returns the offset from the BytecodeArrayPointer of the current bytecode.
247   TNode<IntPtrT> BytecodeOffset();
248 
249  protected:
bytecode()250   Bytecode bytecode() const { return bytecode_; }
251   static bool TargetSupportsUnalignedAccess();
252 
253   void ToNumberOrNumeric(Object::Conversion mode);
254 
255  private:
256   // Returns a pointer to the current function's BytecodeArray object.
257   TNode<BytecodeArray> BytecodeArrayTaggedPointer();
258 
259   // Returns a pointer to first entry in the interpreter dispatch table.
260   TNode<ExternalReference> DispatchTablePointer();
261 
262   // Returns the accumulator value without checking whether bytecode
263   // uses it. This is intended to be used only in dispatch and in
264   // tracing as these need to bypass accumulator use validity checks.
265   TNode<Object> GetAccumulatorUnchecked();
266 
267   // Returns the frame pointer for the interpreted frame of the function being
268   // interpreted.
269   TNode<RawPtrT> GetInterpretedFramePointer();
270 
271   // Operations on registers.
272   TNode<IntPtrT> RegisterLocation(Register reg);
273   TNode<IntPtrT> RegisterLocation(TNode<IntPtrT> reg_index);
274   TNode<IntPtrT> NextRegister(TNode<IntPtrT> reg_index);
275   TNode<Object> LoadRegister(TNode<IntPtrT> reg_index);
276   void StoreRegister(TNode<Object> value, TNode<IntPtrT> reg_index);
277 
278   // Saves and restores interpreter bytecode offset to the interpreter stack
279   // frame when performing a call.
280   void CallPrologue();
281   void CallEpilogue();
282 
283   // Increment the dispatch counter for the (current, next) bytecode pair.
284   void TraceBytecodeDispatch(TNode<WordT> target_bytecode);
285 
286   // Traces the current bytecode by calling |function_id|.
287   void TraceBytecode(Runtime::FunctionId function_id);
288 
289   // Updates the bytecode array's interrupt budget by a 32-bit unsigned |weight|
290   // and calls Runtime::kInterrupt if counter reaches zero. If |backward|, then
291   // the interrupt budget is decremented, otherwise it is incremented.
292   void UpdateInterruptBudget(TNode<Int32T> weight, bool backward);
293 
294   // Returns the offset of register |index| relative to RegisterFilePointer().
295   TNode<IntPtrT> RegisterFrameOffset(TNode<IntPtrT> index);
296 
297   // Returns the offset of an operand relative to the current bytecode offset.
298   TNode<IntPtrT> OperandOffset(int operand_index);
299 
300   // Returns a value built from an sequence of bytes in the bytecode
301   // array starting at |relative_offset| from the current bytecode.
302   // The |result_type| determines the size and signedness.  of the
303   // value read. This method should only be used on architectures that
304   // do not support unaligned memory accesses.
305   TNode<Word32T> BytecodeOperandReadUnaligned(
306       int relative_offset, MachineType result_type,
307       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
308 
309   // Returns zero- or sign-extended to word32 value of the operand.
310   TNode<Uint8T> BytecodeOperandUnsignedByte(
311       int operand_index,
312       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
313   TNode<Int8T> BytecodeOperandSignedByte(
314       int operand_index,
315       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
316   TNode<Uint16T> BytecodeOperandUnsignedShort(
317       int operand_index,
318       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
319   TNode<Int16T> BytecodeOperandSignedShort(
320       int operand_index,
321       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
322   TNode<Uint32T> BytecodeOperandUnsignedQuad(
323       int operand_index,
324       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
325   TNode<Int32T> BytecodeOperandSignedQuad(
326       int operand_index,
327       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
328 
329   // Returns zero- or sign-extended to word32 value of the operand of
330   // given size.
331   TNode<Int32T> BytecodeSignedOperand(
332       int operand_index, OperandSize operand_size,
333       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
334   TNode<Uint32T> BytecodeUnsignedOperand(
335       int operand_index, OperandSize operand_size,
336       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
337 
338   // Returns the word-size sign-extended register index for bytecode operand
339   // |operand_index| in the current bytecode. Value is not poisoned on
340   // speculation since the value loaded from the register is poisoned instead.
341   TNode<IntPtrT> BytecodeOperandReg(
342       int operand_index,
343       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
344 
345   // Returns the word zero-extended index immediate for bytecode operand
346   // |operand_index| in the current bytecode for use when loading a .
347   TNode<UintPtrT> BytecodeOperandConstantPoolIdx(
348       int operand_index,
349       LoadSensitivity needs_poisoning = LoadSensitivity::kCritical);
350 
351   // Jump relative to the current bytecode by the |jump_offset|. If |backward|,
352   // then jump backward (subtract the offset), otherwise jump forward (add the
353   // offset). Helper function for Jump and JumpBackward.
354   void Jump(TNode<IntPtrT> jump_offset, bool backward);
355 
356   // Jump forward relative to the current bytecode by |jump_offset| if the
357   // |condition| is true. Helper function for JumpIfTaggedEqual and
358   // JumpIfTaggedNotEqual.
359   void JumpConditional(TNode<BoolT> condition, TNode<IntPtrT> jump_offset);
360 
361   // Save the bytecode offset to the interpreter frame.
362   void SaveBytecodeOffset();
363   // Reload the bytecode offset from the interpreter frame.
364   TNode<IntPtrT> ReloadBytecodeOffset();
365 
366   // Updates and returns BytecodeOffset() advanced by the current bytecode's
367   // size. Traces the exit of the current bytecode.
368   TNode<IntPtrT> Advance();
369 
370   // Updates and returns BytecodeOffset() advanced by delta bytecodes.
371   // Traces the exit of the current bytecode.
372   TNode<IntPtrT> Advance(int delta);
373   TNode<IntPtrT> Advance(TNode<IntPtrT> delta, bool backward = false);
374 
375   // Load the bytecode at |bytecode_offset|.
376   TNode<WordT> LoadBytecode(TNode<IntPtrT> bytecode_offset);
377 
378   // Look ahead for Star and inline it in a branch. Returns a new target
379   // bytecode node for dispatch.
380   TNode<WordT> StarDispatchLookahead(TNode<WordT> target_bytecode);
381 
382   // Build code for Star at the current BytecodeOffset() and Advance() to the
383   // next dispatch offset.
384   void InlineStar();
385 
386   // Dispatch to the bytecode handler with code entry point |handler_entry|.
387   void DispatchToBytecodeHandlerEntry(TNode<RawPtrT> handler_entry,
388                                       TNode<IntPtrT> bytecode_offset);
389 
390   int CurrentBytecodeSize() const;
391 
operand_scale()392   OperandScale operand_scale() const { return operand_scale_; }
393 
394   Bytecode bytecode_;
395   OperandScale operand_scale_;
396   CodeStubAssembler::TVariable<RawPtrT> interpreted_frame_pointer_;
397   CodeStubAssembler::TVariable<BytecodeArray> bytecode_array_;
398   CodeStubAssembler::TVariable<IntPtrT> bytecode_offset_;
399   CodeStubAssembler::TVariable<ExternalReference> dispatch_table_;
400   CodeStubAssembler::TVariable<Object> accumulator_;
401   AccumulatorUse accumulator_use_;
402   bool made_call_;
403   bool reloaded_frame_ptr_;
404   bool bytecode_array_valid_;
405 };
406 
407 }  // namespace interpreter
408 }  // namespace internal
409 }  // namespace v8
410 
411 #endif  // V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_
412