interpreter-assembler.h 19.9 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_
#define V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_

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 13
#include "src/interpreter/bytecodes.h"
#include "src/runtime/runtime.h"
14
#include "src/utils/allocation.h"
15 16 17 18 19

namespace v8 {
namespace internal {
namespace interpreter {

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
  InterpreterAssembler(const InterpreterAssembler&) = delete;
  InterpreterAssembler& operator=(const InterpreterAssembler&) = delete;
27

28 29
  // Returns the 32-bit unsigned count immediate for bytecode operand
  // |operand_index| in the current bytecode.
30
  TNode<Uint32T> BytecodeOperandCount(int operand_index);
31 32
  // Returns the 32-bit unsigned flag for bytecode operand |operand_index|
  // in the current bytecode.
33
  TNode<Uint32T> BytecodeOperandFlag(int operand_index);
34 35
  // Returns the 32-bit zero-extended index immediate for bytecode operand
  // |operand_index| in the current bytecode.
36
  TNode<Uint32T> BytecodeOperandIdxInt32(int operand_index);
37 38
  // Returns the word zero-extended index immediate for bytecode operand
  // |operand_index| in the current bytecode.
39
  TNode<UintPtrT> BytecodeOperandIdx(int operand_index);
40 41
  // Returns the smi index immediate for bytecode operand |operand_index|
  // in the current bytecode.
42
  TNode<Smi> BytecodeOperandIdxSmi(int operand_index);
43 44 45
  // Returns the TaggedIndex immediate for bytecode operand |operand_index|
  // in the current bytecode.
  TNode<TaggedIndex> BytecodeOperandIdxTaggedIndex(int operand_index);
46 47
  // Returns the 32-bit unsigned immediate for bytecode operand |operand_index|
  // in the current bytecode.
48
  TNode<Uint32T> BytecodeOperandUImm(int operand_index);
49 50
  // Returns the word-size unsigned immediate for bytecode operand
  // |operand_index| in the current bytecode.
51
  TNode<UintPtrT> BytecodeOperandUImmWord(int operand_index);
52 53
  // Returns the unsigned smi immediate for bytecode operand |operand_index| in
  // the current bytecode.
54
  TNode<Smi> BytecodeOperandUImmSmi(int operand_index);
55 56
  // Returns the 32-bit signed immediate for bytecode operand |operand_index|
  // in the current bytecode.
57
  TNode<Int32T> BytecodeOperandImm(int operand_index);
58 59
  // Returns the word-size signed immediate for bytecode operand |operand_index|
  // 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 79
  TNode<Context> GetContext();
  void SetContext(TNode<Context> value);
80

81
  // Context at |depth| in the context chain starting at |context|.
82 83
  TNode<Context> GetContextAtDepth(TNode<Context> context,
                                   TNode<Uint32T> depth);
84

85 86 87
  // A RegListNodePair provides an abstraction over lists of registers.
  class RegListNodePair {
   public:
88
    RegListNodePair(TNode<IntPtrT> base_reg_location, TNode<Word32T> reg_count)
89 90
        : base_reg_location_(base_reg_location), reg_count_(reg_count) {}

91 92
    TNode<Word32T> reg_count() const { return reg_count_; }
    TNode<IntPtrT> base_reg_location() const { return base_reg_location_; }
93 94

   private:
95 96
    TNode<IntPtrT> base_reg_location_;
    TNode<Word32T> reg_count_;
97 98
  };

99
  // Backup/restore register file to/from a fixed array of the correct length.
100 101 102 103
  // There is an asymmetry between suspend/export and resume/import.
  // - Suspend copies arguments and registers to the generator.
  // - Resume copies only the registers from the generator, the arguments
  //   are copied by the ResumeGenerator trampoline.
104
  TNode<FixedArray> ExportParametersAndRegisterFile(
105 106
      TNode<FixedArray> array, const RegListNodePair& registers,
      TNode<Int32T> formal_parameter_count);
107 108 109
  TNode<FixedArray> ImportRegisterFile(TNode<FixedArray> array,
                                       const RegListNodePair& registers,
                                       TNode<Int32T> formal_parameter_count);
110

111
  // Loads from and stores to the interpreter register file.
112 113 114 115 116 117 118 119 120 121 122 123
  TNode<Object> LoadRegister(Register reg);
  TNode<IntPtrT> LoadAndUntagRegister(Register reg);
  TNode<Object> LoadRegisterAtOperandIndex(int operand_index);
  std::pair<TNode<Object>, TNode<Object>> LoadRegisterPairAtOperandIndex(
      int operand_index);
  void StoreRegister(TNode<Object> value, Register reg);
  void StoreRegisterAtOperandIndex(TNode<Object> value, int operand_index);
  void StoreRegisterPairAtOperandIndex(TNode<Object> value1,
                                       TNode<Object> value2, int operand_index);
  void StoreRegisterTripleAtOperandIndex(TNode<Object> value1,
                                         TNode<Object> value2,
                                         TNode<Object> value3,
124 125 126
                                         int operand_index);

  RegListNodePair GetRegisterListAtOperandIndex(int operand_index);
127 128
  TNode<Object> LoadRegisterFromRegisterList(const RegListNodePair& reg_list,
                                             int index);
129 130
  TNode<IntPtrT> RegisterLocationInRegisterList(const RegListNodePair& reg_list,
                                                int index);
131 132 133

  // Load constant at the index specified in operand |operand_index| from the
  // constant pool.
134
  TNode<Object> LoadConstantPoolEntryAtOperandIndex(int operand_index);
135 136
  // Load and untag constant at the index specified in operand |operand_index|
  // 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 144
  // Load the FeedbackVector for the current function. The retuned node could be
  // undefined.
145
  TNode<HeapObject> LoadFeedbackVector();
146

147
  // Call JSFunction or Callable |function| with |args| arguments, possibly
148 149
  // including the receiver depending on |receiver_mode|. After the call returns
  // 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 155 156 157 158
  // Call JSFunction or Callable |function| with |arg_count| arguments (not
  // including receiver) passed as |args|, possibly including the receiver
  // depending on |receiver_mode|. After the call returns directly dispatches to
  // the next bytecode.
  template <class... TArgs>
159 160
  void CallJSAndDispatch(TNode<Object> function, TNode<Context> context,
                         TNode<Word32T> arg_count,
161 162
                         ConvertReceiverMode receiver_mode, TArgs... args);

163 164 165
  // Call JSFunction or Callable |function| with |args|
  // arguments (not including receiver), and the final argument being spread.
  // After the call returns directly dispatches to the next bytecode.
166 167
  void CallJSWithSpreadAndDispatch(TNode<Object> function,
                                   TNode<Context> context,
168
                                   const RegListNodePair& args,
169
                                   TNode<UintPtrT> slot_id,
170
                                   TNode<HeapObject> maybe_feedback_vector);
171

172 173 174
  // Call constructor |target| with |args| arguments (not including receiver).
  // The |new_target| is the same as the |target| for the new keyword, but
  // differs for the super keyword.
175 176 177 178
  TNode<Object> Construct(TNode<Object> target, TNode<Context> context,
                          TNode<Object> new_target, const RegListNodePair& args,
                          TNode<UintPtrT> slot_id,
                          TNode<HeapObject> maybe_feedback_vector);
179

180 181 182 183
  // Call constructor |target| with |args| arguments (not including
  // receiver). The last argument is always a spread. The |new_target| is the
  // same as the |target| for the new keyword, but differs for the super
  // keyword.
184 185 186 187 188 189
  TNode<Object> ConstructWithSpread(TNode<Object> target,
                                    TNode<Context> context,
                                    TNode<Object> new_target,
                                    const RegListNodePair& args,
                                    TNode<UintPtrT> slot_id,
                                    TNode<HeapObject> maybe_feedback_vector);
190

191 192 193 194
  // Call runtime function with |args| arguments.
  template <class T = Object>
  TNode<T> CallRuntimeN(TNode<Uint32T> function_id, TNode<Context> context,
                        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 205
  void JumpIfTaggedEqual(TNode<Object> lhs, TNode<Object> rhs,
                         TNode<IntPtrT> jump_offset);
206

207 208 209 210 211 212 213 214 215 216 217
  // Jump forward relative to the current bytecode by offest specified in
  // operand |operand_index| if the word values |lhs| and |rhs| are equal.
  void JumpIfTaggedEqual(TNode<Object> lhs, TNode<Object> rhs,
                         int operand_index);

  // Jump forward relative to the current bytecode by offest specified from the
  // constant pool if the word values |lhs| and |rhs| are equal.
  // The constant's index is specified in operand |operand_index|.
  void JumpIfTaggedEqualConstant(TNode<Object> lhs, TNode<Object> rhs,
                                 int operand_index);

218
  // Jump forward relative to the current bytecode by |jump_offset| if the
219
  // word values |lhs| and |rhs| are not equal.
220 221
  void JumpIfTaggedNotEqual(TNode<Object> lhs, TNode<Object> rhs,
                            TNode<IntPtrT> jump_offset);
222

223 224 225 226 227 228 229 230 231 232 233
  // Jump forward relative to the current bytecode by offest specified in
  // operand |operand_index| if the word values |lhs| and |rhs| are not equal.
  void JumpIfTaggedNotEqual(TNode<Object> lhs, TNode<Object> rhs,
                            int operand_index);

  // Jump forward relative to the current bytecode by offest specified from the
  // constant pool if the word values |lhs| and |rhs| are not equal.
  // The constant's index is specified in operand |operand_index|.
  void JumpIfTaggedNotEqualConstant(TNode<Object> lhs, TNode<Object> rhs,
                                    int operand_index);

234 235
  // Updates the profiler interrupt budget for a return.
  void UpdateInterruptBudgetOnReturn();
236

237
  // Returns the OSR nesting level from the bytecode header.
238
  TNode<Int8T> LoadOsrNestingLevel();
239

240
  // Dispatch to the bytecode.
241
  void Dispatch();
242

243 244 245
  // Dispatch bytecode as wide operand variant.
  void DispatchWide(OperandScale operand_scale);

246 247
  // Dispatch to |target_bytecode| at |new_bytecode_offset|.
  // |target_bytecode| should be equivalent to loading from the offset.
248 249
  void DispatchToBytecode(TNode<WordT> target_bytecode,
                          TNode<IntPtrT> new_bytecode_offset);
250

251 252 253 254 255 256
  // Dispatches to |target_bytecode| at BytecodeOffset(). Includes short-star
  // lookahead if the current bytecode_ is likely followed by a short-star
  // instruction.
  void DispatchToBytecodeWithOptionalStarLookahead(
      TNode<WordT> target_bytecode);

257 258
  // Abort with the given abort reason.
  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 264
      TNode<FixedArrayBase> parameters_and_registers,
      TNode<IntPtrT> formal_parameter_count, TNode<UintPtrT> register_count);
265

266 267 268
  // Perform OnStackReplacement.
  void OnStackReplacement(TNode<Context> context, TNode<IntPtrT> relative_jump);

269
  // Returns the offset from the BytecodeArrayPointer of the current bytecode.
270
  TNode<IntPtrT> BytecodeOffset();
271

272
 protected:
273
  Bytecode bytecode() const { return bytecode_; }
274 275
  static bool TargetSupportsUnalignedAccess();

276 277
  void ToNumberOrNumeric(Object::Conversion mode);

278 279 280 281 282
  void StoreRegisterForShortStar(TNode<Object> value, TNode<WordT> opcode);

  // Load the bytecode at |bytecode_offset|.
  TNode<WordT> LoadBytecode(TNode<IntPtrT> bytecode_offset);

283
 private:
284 285
  // Returns a pointer to the current function's BytecodeArray object.
  TNode<BytecodeArray> BytecodeArrayTaggedPointer();
286

287 288
  // Returns a pointer to first entry in the interpreter dispatch table.
  TNode<ExternalReference> DispatchTablePointer();
289

290 291 292
  // Returns the accumulator value without checking whether bytecode
  // uses it. This is intended to be used only in dispatch and in
  // tracing as these need to bypass accumulator use validity checks.
293
  TNode<Object> GetAccumulatorUnchecked();
294

295 296
  // Returns the frame pointer for the interpreted frame of the function being
  // interpreted.
297
  TNode<RawPtrT> GetInterpretedFramePointer();
298

299
  // Operations on registers.
300 301 302 303 304
  TNode<IntPtrT> RegisterLocation(Register reg);
  TNode<IntPtrT> RegisterLocation(TNode<IntPtrT> reg_index);
  TNode<IntPtrT> NextRegister(TNode<IntPtrT> reg_index);
  TNode<Object> LoadRegister(TNode<IntPtrT> reg_index);
  void StoreRegister(TNode<Object> value, TNode<IntPtrT> reg_index);
305

306 307
  // Saves and restores interpreter bytecode offset to the interpreter stack
  // frame when performing a call.
308 309
  void CallPrologue();
  void CallEpilogue();
310

311
  // Increment the dispatch counter for the (current, next) bytecode pair.
312
  void TraceBytecodeDispatch(TNode<WordT> target_bytecode);
313

314 315 316
  // Traces the current bytecode by calling |function_id|.
  void TraceBytecode(Runtime::FunctionId function_id);

317 318 319
  // Updates the bytecode array's interrupt budget by a 32-bit unsigned |weight|
  // and calls Runtime::kInterrupt if counter reaches zero. If |backward|, then
  // the interrupt budget is decremented, otherwise it is incremented.
320
  void UpdateInterruptBudget(TNode<Int32T> weight, bool backward);
321

322
  // Returns the offset of register |index| relative to RegisterFilePointer().
323
  TNode<IntPtrT> RegisterFrameOffset(TNode<IntPtrT> index);
324

325
  // Returns the offset of an operand relative to the current bytecode offset.
326
  TNode<IntPtrT> OperandOffset(int operand_index);
327 328 329 330 331 332

  // Returns a value built from an sequence of bytes in the bytecode
  // array starting at |relative_offset| from the current bytecode.
  // The |result_type| determines the size and signedness.  of the
  // value read. This method should only be used on architectures that
  // do not support unaligned memory accesses.
333 334
  TNode<Word32T> BytecodeOperandReadUnaligned(int relative_offset,
                                              MachineType result_type);
335 336

  // Returns zero- or sign-extended to word32 value of the operand.
337 338 339 340 341 342
  TNode<Uint8T> BytecodeOperandUnsignedByte(int operand_index);
  TNode<Int8T> BytecodeOperandSignedByte(int operand_index);
  TNode<Uint16T> BytecodeOperandUnsignedShort(int operand_index);
  TNode<Int16T> BytecodeOperandSignedShort(int operand_index);
  TNode<Uint32T> BytecodeOperandUnsignedQuad(int operand_index);
  TNode<Int32T> BytecodeOperandSignedQuad(int operand_index);
343

344 345
  // Returns zero- or sign-extended to word32 value of the operand of
  // given size.
346 347 348 349
  TNode<Int32T> BytecodeSignedOperand(int operand_index,
                                      OperandSize operand_size);
  TNode<Uint32T> BytecodeUnsignedOperand(int operand_index,
                                         OperandSize operand_size);
350

351
  // Returns the word-size sign-extended register index for bytecode operand
352 353
  // |operand_index| in the current bytecode.
  TNode<IntPtrT> BytecodeOperandReg(int operand_index);
354 355

  // Returns the word zero-extended index immediate for bytecode operand
356 357 358
  // |operand_index| in the current bytecode for use when loading a constant
  // pool element.
  TNode<UintPtrT> BytecodeOperandConstantPoolIdx(int operand_index);
359

360 361 362
  // Jump relative to the current bytecode by the |jump_offset|. If |backward|,
  // then jump backward (subtract the offset), otherwise jump forward (add the
  // offset). Helper function for Jump and JumpBackward.
363
  void Jump(TNode<IntPtrT> jump_offset, bool backward);
364 365

  // Jump forward relative to the current bytecode by |jump_offset| if the
366 367
  // |condition| is true. Helper function for JumpIfTaggedEqual and
  // JumpIfTaggedNotEqual.
368
  void JumpConditional(TNode<BoolT> condition, TNode<IntPtrT> jump_offset);
369

370 371 372 373 374 375 376 377 378 379 380 381 382
  // Jump forward relative to the current bytecode by offest specified in
  // operand |operand_index| if the |condition| is true. Helper function for
  // JumpIfTaggedEqual and JumpIfTaggedNotEqual.
  void JumpConditionalByImmediateOperand(TNode<BoolT> condition,
                                         int operand_index);

  // Jump forward relative to the current bytecode by offest specified from the
  // constant pool if the |condition| is true. The constant's index is specified
  // in operand |operand_index|. Helper function for JumpIfTaggedEqualConstant
  // and JumpIfTaggedNotEqualConstant.
  void JumpConditionalByConstantOperand(TNode<BoolT> condition,
                                        int operand_index);

383 384
  // Save the bytecode offset to the interpreter frame.
  void SaveBytecodeOffset();
385
  // Reload the bytecode offset from the interpreter frame.
386
  TNode<IntPtrT> ReloadBytecodeOffset();
387

388 389
  // Updates and returns BytecodeOffset() advanced by the current bytecode's
  // size. Traces the exit of the current bytecode.
390
  TNode<IntPtrT> Advance();
391 392 393

  // Updates and returns BytecodeOffset() advanced by delta bytecodes.
  // Traces the exit of the current bytecode.
394
  TNode<IntPtrT> Advance(int delta);
395
  TNode<IntPtrT> Advance(TNode<IntPtrT> delta, bool backward = false);
396

397 398 399 400
  // Look ahead for short Star and inline it in a branch, including subsequent
  // dispatch. Anything after this point can assume that the following
  // instruction was not a short Star.
  void StarDispatchLookahead(TNode<WordT> target_bytecode);
401

402 403 404
  // Build code for short Star at the current BytecodeOffset() and Advance() to
  // the next dispatch offset.
  void InlineShortStar(TNode<WordT> target_bytecode);
405

406
  // Dispatch to the bytecode handler with code entry point |handler_entry|.
407 408
  void DispatchToBytecodeHandlerEntry(TNode<RawPtrT> handler_entry,
                                      TNode<IntPtrT> bytecode_offset);
409

410 411
  int CurrentBytecodeSize() const;

412 413
  OperandScale operand_scale() const { return operand_scale_; }

414
  Bytecode bytecode_;
415
  OperandScale operand_scale_;
416 417 418 419 420
  CodeStubAssembler::TVariable<RawPtrT> interpreted_frame_pointer_;
  CodeStubAssembler::TVariable<BytecodeArray> bytecode_array_;
  CodeStubAssembler::TVariable<IntPtrT> bytecode_offset_;
  CodeStubAssembler::TVariable<ExternalReference> dispatch_table_;
  CodeStubAssembler::TVariable<Object> accumulator_;
421
  ImplicitRegisterUse implicit_register_use_;
422
  bool made_call_;
423
  bool reloaded_frame_ptr_;
424
  bool bytecode_array_valid_;
425 426 427 428 429 430 431
};

}  // namespace interpreter
}  // namespace internal
}  // namespace v8

#endif  // V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_