summaryrefslogtreecommitdiff
path: root/deps/v8/src/interpreter/interpreter-assembler.h
blob: 86ecea54dd08517a1cd87890d6dd7f0f010bd46f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// 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_

#include "src/allocation.h"
#include "src/base/smart-pointers.h"
#include "src/builtins.h"
#include "src/compiler/code-stub-assembler.h"
#include "src/frames.h"
#include "src/interpreter/bytecodes.h"
#include "src/runtime/runtime.h"

namespace v8 {
namespace internal {
namespace interpreter {

class InterpreterAssembler : public compiler::CodeStubAssembler {
 public:
  InterpreterAssembler(Isolate* isolate, Zone* zone, Bytecode bytecode,
                       OperandScale operand_scale);
  virtual ~InterpreterAssembler();

  // Returns the count immediate for bytecode operand |operand_index| in the
  // current bytecode.
  compiler::Node* BytecodeOperandCount(int operand_index);
  // Returns the 8-bit flag for bytecode operand |operand_index| in the
  // current bytecode.
  compiler::Node* BytecodeOperandFlag(int operand_index);
  // Returns the index immediate for bytecode operand |operand_index| in the
  // current bytecode.
  compiler::Node* BytecodeOperandIdx(int operand_index);
  // Returns the Imm8 immediate for bytecode operand |operand_index| in the
  // current bytecode.
  compiler::Node* BytecodeOperandImm(int operand_index);
  // Returns the register index for bytecode operand |operand_index| in the
  // current bytecode.
  compiler::Node* BytecodeOperandReg(int operand_index);
  // Returns the runtime id immediate for bytecode operand
  // |operand_index| in the current bytecode.
  compiler::Node* BytecodeOperandRuntimeId(int operand_index);

  // Accumulator.
  compiler::Node* GetAccumulator();
  void SetAccumulator(compiler::Node* value);

  // Context.
  compiler::Node* GetContext();
  void SetContext(compiler::Node* value);

  // Loads from and stores to the interpreter register file.
  compiler::Node* LoadRegister(int offset);
  compiler::Node* LoadRegister(Register reg);
  compiler::Node* LoadRegister(compiler::Node* reg_index);
  compiler::Node* StoreRegister(compiler::Node* value, int offset);
  compiler::Node* StoreRegister(compiler::Node* value, Register reg);
  compiler::Node* StoreRegister(compiler::Node* value,
                                compiler::Node* reg_index);

  // Returns the next consecutive register.
  compiler::Node* NextRegister(compiler::Node* reg_index);

  // Returns the location in memory of the register |reg_index| in the
  // interpreter register file.
  compiler::Node* RegisterLocation(compiler::Node* reg_index);

  // Load constant at |index| in the constant pool.
  compiler::Node* LoadConstantPoolEntry(compiler::Node* index);

  // Load a field from an object on the heap.
  compiler::Node* LoadObjectField(compiler::Node* object, int offset);

  // Load |slot_index| from |context|.
  compiler::Node* LoadContextSlot(compiler::Node* context, int slot_index);
  compiler::Node* LoadContextSlot(compiler::Node* context,
                                  compiler::Node* slot_index);
  // Stores |value| into |slot_index| of |context|.
  compiler::Node* StoreContextSlot(compiler::Node* context,
                                   compiler::Node* slot_index,
                                   compiler::Node* value);

  // Load the TypeFeedbackVector for the current function.
  compiler::Node* LoadTypeFeedbackVector();

  // Call JSFunction or Callable |function| with |arg_count|
  // arguments (not including receiver) and the first argument
  // located at |first_arg|.
  compiler::Node* CallJS(compiler::Node* function, compiler::Node* context,
                         compiler::Node* first_arg, compiler::Node* arg_count,
                         TailCallMode tail_call_mode);

  // Call constructor |constructor| with |arg_count| arguments (not
  // including receiver) and the first argument located at
  // |first_arg|. The |new_target| is the same as the
  // |constructor| for the new keyword, but differs for the super
  // keyword.
  compiler::Node* CallConstruct(compiler::Node* constructor,
                                compiler::Node* context,
                                compiler::Node* new_target,
                                compiler::Node* first_arg,
                                compiler::Node* arg_count);

  // Call runtime function with |arg_count| arguments and the first argument
  // located at |first_arg|.
  compiler::Node* CallRuntimeN(compiler::Node* function_id,
                               compiler::Node* context,
                               compiler::Node* first_arg,
                               compiler::Node* arg_count, int return_size = 1);

  // Jump relative to the current bytecode by |jump_offset|.
  void Jump(compiler::Node* jump_offset);

  // Jump relative to the current bytecode by |jump_offset| if the
  // |condition| is true. Helper function for JumpIfWordEqual and
  // JumpIfWordNotEqual.
  void JumpConditional(compiler::Node* condition, compiler::Node* jump_offset);

  // Jump relative to the current bytecode by |jump_offset| if the
  // word values |lhs| and |rhs| are equal.
  void JumpIfWordEqual(compiler::Node* lhs, compiler::Node* rhs,
                       compiler::Node* jump_offset);

  // Jump relative to the current bytecode by |jump_offset| if the
  // word values |lhs| and |rhs| are not equal.
  void JumpIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
                          compiler::Node* jump_offset);

  // Perform a stack guard check.
  void StackCheck();

  // Returns from the function.
  void InterpreterReturn();

  // Dispatch to the bytecode.
  void Dispatch();

  // Dispatch to bytecode handler.
  void DispatchToBytecodeHandler(compiler::Node* handler,
                                 compiler::Node* bytecode_offset);
  void DispatchToBytecodeHandler(compiler::Node* handler) {
    DispatchToBytecodeHandler(handler, BytecodeOffset());
  }

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

  // Abort with the given bailout reason.
  void Abort(BailoutReason bailout_reason);

 protected:
  Bytecode bytecode() const { return bytecode_; }
  static bool TargetSupportsUnalignedAccess();

 private:
  // Returns a raw pointer to start of the register file on the stack.
  compiler::Node* RegisterFileRawPointer();
  // Returns a tagged pointer to the current function's BytecodeArray object.
  compiler::Node* BytecodeArrayTaggedPointer();
  // Returns the offset from the BytecodeArrayPointer of the current bytecode.
  compiler::Node* BytecodeOffset();
  // Returns a raw pointer to first entry in the interpreter dispatch table.
  compiler::Node* DispatchTableRawPointer();

  // 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.
  compiler::Node* GetAccumulatorUnchecked();

  // Saves and restores interpreter bytecode offset to the interpreter stack
  // frame when performing a call.
  void CallPrologue() override;
  void CallEpilogue() override;

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

  // Updates the bytecode array's interrupt budget by |weight| and calls
  // Runtime::kInterrupt if counter reaches zero.
  void UpdateInterruptBudget(compiler::Node* weight);

  // Returns the offset of register |index| relative to RegisterFilePointer().
  compiler::Node* RegisterFrameOffset(compiler::Node* index);

  // Returns the offset of an operand relative to the current bytecode offset.
  compiler::Node* OperandOffset(int operand_index);

  // 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.
  compiler::Node* BytecodeOperandReadUnaligned(int relative_offset,
                                               MachineType result_type);

  compiler::Node* BytecodeOperandUnsignedByte(int operand_index);
  compiler::Node* BytecodeOperandSignedByte(int operand_index);
  compiler::Node* BytecodeOperandUnsignedShort(int operand_index);
  compiler::Node* BytecodeOperandSignedShort(int operand_index);
  compiler::Node* BytecodeOperandUnsignedQuad(int operand_index);
  compiler::Node* BytecodeOperandSignedQuad(int operand_index);

  compiler::Node* BytecodeSignedOperand(int operand_index,
                                        OperandSize operand_size);
  compiler::Node* BytecodeUnsignedOperand(int operand_index,
                                          OperandSize operand_size);

  // Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
  // update BytecodeOffset() itself.
  compiler::Node* Advance(int delta);
  compiler::Node* Advance(compiler::Node* delta);

  // Starts next instruction dispatch at |new_bytecode_offset|.
  void DispatchTo(compiler::Node* new_bytecode_offset);

  // Abort operations for debug code.
  void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
                           BailoutReason bailout_reason);

  OperandScale operand_scale() const { return operand_scale_; }

  Bytecode bytecode_;
  OperandScale operand_scale_;
  CodeStubAssembler::Variable accumulator_;
  AccumulatorUse accumulator_use_;
  CodeStubAssembler::Variable context_;
  CodeStubAssembler::Variable bytecode_array_;

  bool disable_stack_check_across_call_;
  compiler::Node* stack_pointer_before_call_;

  DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler);
};

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

#endif  // V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_