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