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/base/smart-pointers.h" 10 #include "src/builtins.h" 11 #include "src/code-stub-assembler.h" 12 #include "src/frames.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 InterpreterAssembler : public CodeStubAssembler { 21 public: 22 InterpreterAssembler(Isolate* isolate, Zone* zone, Bytecode bytecode, 23 OperandScale operand_scale); 24 virtual ~InterpreterAssembler(); 25 26 // Returns the count immediate for bytecode operand |operand_index| in the 27 // current bytecode. 28 compiler::Node* BytecodeOperandCount(int operand_index); 29 // Returns the 8-bit flag for bytecode operand |operand_index| in the 30 // current bytecode. 31 compiler::Node* BytecodeOperandFlag(int operand_index); 32 // Returns the index immediate for bytecode operand |operand_index| in the 33 // current bytecode. 34 compiler::Node* BytecodeOperandIdx(int operand_index); 35 // Returns the Imm8 immediate for bytecode operand |operand_index| in the 36 // current bytecode. 37 compiler::Node* BytecodeOperandImm(int operand_index); 38 // Returns the register index for bytecode operand |operand_index| in the 39 // current bytecode. 40 compiler::Node* BytecodeOperandReg(int operand_index); 41 // Returns the runtime id immediate for bytecode operand 42 // |operand_index| in the current bytecode. 43 compiler::Node* BytecodeOperandRuntimeId(int operand_index); 44 // Returns the intrinsic id immediate for bytecode operand 45 // |operand_index| in the current bytecode. 46 compiler::Node* BytecodeOperandIntrinsicId(int operand_index); 47 48 // Accumulator. 49 compiler::Node* GetAccumulator(); 50 void SetAccumulator(compiler::Node* value); 51 52 // Context. 53 compiler::Node* GetContext(); 54 void SetContext(compiler::Node* value); 55 56 // Number of registers. 57 compiler::Node* RegisterCount(); 58 59 // Backup/restore register file to/from a fixed array of the correct length. 60 compiler::Node* ExportRegisterFile(compiler::Node* array); 61 compiler::Node* ImportRegisterFile(compiler::Node* array); 62 63 // Loads from and stores to the interpreter register file. 64 compiler::Node* LoadRegister(Register reg); 65 compiler::Node* LoadRegister(compiler::Node* reg_index); 66 compiler::Node* StoreRegister(compiler::Node* value, Register reg); 67 compiler::Node* StoreRegister(compiler::Node* value, 68 compiler::Node* reg_index); 69 70 // Returns the next consecutive register. 71 compiler::Node* NextRegister(compiler::Node* reg_index); 72 73 // Returns the location in memory of the register |reg_index| in the 74 // interpreter register file. 75 compiler::Node* RegisterLocation(compiler::Node* reg_index); 76 77 // Load constant at |index| in the constant pool. 78 compiler::Node* LoadConstantPoolEntry(compiler::Node* index); 79 80 // Load |slot_index| from |context|. 81 compiler::Node* LoadContextSlot(compiler::Node* context, int slot_index); 82 compiler::Node* LoadContextSlot(compiler::Node* context, 83 compiler::Node* slot_index); 84 // Stores |value| into |slot_index| of |context|. 85 compiler::Node* StoreContextSlot(compiler::Node* context, 86 compiler::Node* slot_index, 87 compiler::Node* value); 88 89 // Load the TypeFeedbackVector for the current function. 90 compiler::Node* LoadTypeFeedbackVector(); 91 92 // Call JSFunction or Callable |function| with |arg_count| 93 // arguments (not including receiver) and the first argument 94 // located at |first_arg|. 95 compiler::Node* CallJS(compiler::Node* function, compiler::Node* context, 96 compiler::Node* first_arg, compiler::Node* arg_count, 97 TailCallMode tail_call_mode); 98 99 // Call constructor |constructor| with |arg_count| arguments (not 100 // including receiver) and the first argument located at 101 // |first_arg|. The |new_target| is the same as the 102 // |constructor| for the new keyword, but differs for the super 103 // keyword. 104 compiler::Node* CallConstruct(compiler::Node* constructor, 105 compiler::Node* context, 106 compiler::Node* new_target, 107 compiler::Node* first_arg, 108 compiler::Node* arg_count); 109 110 // Call runtime function with |arg_count| arguments and the first argument 111 // located at |first_arg|. 112 compiler::Node* CallRuntimeN(compiler::Node* function_id, 113 compiler::Node* context, 114 compiler::Node* first_arg, 115 compiler::Node* arg_count, int return_size = 1); 116 117 // Jump relative to the current bytecode by |jump_offset|. 118 compiler::Node* Jump(compiler::Node* jump_offset); 119 120 // Jump relative to the current bytecode by |jump_offset| if the 121 // word values |lhs| and |rhs| are equal. 122 void JumpIfWordEqual(compiler::Node* lhs, compiler::Node* rhs, 123 compiler::Node* jump_offset); 124 125 // Jump relative to the current bytecode by |jump_offset| if the 126 // word values |lhs| and |rhs| are not equal. 127 void JumpIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs, 128 compiler::Node* jump_offset); 129 130 // Returns true if the stack guard check triggers an interrupt. 131 compiler::Node* StackCheckTriggeredInterrupt(); 132 133 // Updates the profiler interrupt budget for a return. 134 void UpdateInterruptBudgetOnReturn(); 135 136 // Dispatch to the bytecode. 137 compiler::Node* Dispatch(); 138 139 // Dispatch to bytecode handler. DispatchToBytecodeHandler(compiler::Node * handler)140 compiler::Node* DispatchToBytecodeHandler(compiler::Node* handler) { 141 return DispatchToBytecodeHandler(handler, BytecodeOffset()); 142 } 143 144 // Dispatch bytecode as wide operand variant. 145 void DispatchWide(OperandScale operand_scale); 146 147 // Abort with the given bailout reason. 148 void Abort(BailoutReason bailout_reason); 149 void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs, 150 BailoutReason bailout_reason); 151 152 // Returns the offset from the BytecodeArrayPointer of the current bytecode. 153 compiler::Node* BytecodeOffset(); 154 155 protected: bytecode()156 Bytecode bytecode() const { return bytecode_; } 157 static bool TargetSupportsUnalignedAccess(); 158 159 private: 160 // Returns a tagged pointer to the current function's BytecodeArray object. 161 compiler::Node* BytecodeArrayTaggedPointer(); 162 163 // Returns a raw pointer to first entry in the interpreter dispatch table. 164 compiler::Node* DispatchTableRawPointer(); 165 166 // Returns the accumulator value without checking whether bytecode 167 // uses it. This is intended to be used only in dispatch and in 168 // tracing as these need to bypass accumulator use validity checks. 169 compiler::Node* GetAccumulatorUnchecked(); 170 171 // Returns the frame pointer for the interpreted frame of the function being 172 // interpreted. 173 compiler::Node* GetInterpretedFramePointer(); 174 175 // Saves and restores interpreter bytecode offset to the interpreter stack 176 // frame when performing a call. 177 void CallPrologue() override; 178 void CallEpilogue() override; 179 180 // Increment the dispatch counter for the (current, next) bytecode pair. 181 void TraceBytecodeDispatch(compiler::Node* target_index); 182 183 // Traces the current bytecode by calling |function_id|. 184 void TraceBytecode(Runtime::FunctionId function_id); 185 186 // Updates the bytecode array's interrupt budget by |weight| and calls 187 // Runtime::kInterrupt if counter reaches zero. 188 void UpdateInterruptBudget(compiler::Node* weight); 189 190 // Returns the offset of register |index| relative to RegisterFilePointer(). 191 compiler::Node* RegisterFrameOffset(compiler::Node* index); 192 193 // Returns the offset of an operand relative to the current bytecode offset. 194 compiler::Node* OperandOffset(int operand_index); 195 196 // Returns a value built from an sequence of bytes in the bytecode 197 // array starting at |relative_offset| from the current bytecode. 198 // The |result_type| determines the size and signedness. of the 199 // value read. This method should only be used on architectures that 200 // do not support unaligned memory accesses. 201 compiler::Node* BytecodeOperandReadUnaligned(int relative_offset, 202 MachineType result_type); 203 204 compiler::Node* BytecodeOperandUnsignedByte(int operand_index); 205 compiler::Node* BytecodeOperandSignedByte(int operand_index); 206 compiler::Node* BytecodeOperandUnsignedShort(int operand_index); 207 compiler::Node* BytecodeOperandSignedShort(int operand_index); 208 compiler::Node* BytecodeOperandUnsignedQuad(int operand_index); 209 compiler::Node* BytecodeOperandSignedQuad(int operand_index); 210 211 compiler::Node* BytecodeSignedOperand(int operand_index, 212 OperandSize operand_size); 213 compiler::Node* BytecodeUnsignedOperand(int operand_index, 214 OperandSize operand_size); 215 216 // Jump relative to the current bytecode by |jump_offset| if the 217 // |condition| is true. Helper function for JumpIfWordEqual and 218 // JumpIfWordNotEqual. 219 void JumpConditional(compiler::Node* condition, compiler::Node* jump_offset); 220 221 // Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not 222 // update BytecodeOffset() itself. 223 compiler::Node* Advance(int delta); 224 compiler::Node* Advance(compiler::Node* delta); 225 226 // Starts next instruction dispatch at |new_bytecode_offset|. 227 compiler::Node* DispatchTo(compiler::Node* new_bytecode_offset); 228 229 // Dispatch to the bytecode handler with code offset |handler|. 230 compiler::Node* DispatchToBytecodeHandler(compiler::Node* handler, 231 compiler::Node* bytecode_offset); 232 233 // Dispatch to the bytecode handler with code entry point |handler_entry|. 234 compiler::Node* DispatchToBytecodeHandlerEntry( 235 compiler::Node* handler_entry, compiler::Node* bytecode_offset); 236 operand_scale()237 OperandScale operand_scale() const { return operand_scale_; } 238 239 Bytecode bytecode_; 240 OperandScale operand_scale_; 241 CodeStubAssembler::Variable interpreted_frame_pointer_; 242 CodeStubAssembler::Variable accumulator_; 243 AccumulatorUse accumulator_use_; 244 bool made_call_; 245 246 bool disable_stack_check_across_call_; 247 compiler::Node* stack_pointer_before_call_; 248 249 DISALLOW_COPY_AND_ASSIGN(InterpreterAssembler); 250 }; 251 252 } // namespace interpreter 253 } // namespace internal 254 } // namespace v8 255 256 #endif // V8_INTERPRETER_INTERPRETER_ASSEMBLER_H_ 257