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_BYTECODES_H_ 6 #define V8_INTERPRETER_BYTECODES_H_ 7 8 #include <cstdint> 9 #include <iosfwd> 10 #include <string> 11 12 #include "src/globals.h" 13 #include "src/interpreter/bytecode-operands.h" 14 15 // This interface and it's implementation are independent of the 16 // libv8_base library as they are used by the interpreter and the 17 // standalone mkpeephole table generator program. 18 19 namespace v8 { 20 namespace internal { 21 namespace interpreter { 22 23 // The list of bytecodes which are interpreted by the interpreter. 24 // Format is V(<bytecode>, <accumulator_use>, <operands>). 25 #define BYTECODE_LIST(V) \ 26 /* Extended width operands */ \ 27 V(Wide, AccumulatorUse::kNone) \ 28 V(ExtraWide, AccumulatorUse::kNone) \ 29 \ 30 /* Loading the accumulator */ \ 31 V(LdaZero, AccumulatorUse::kWrite) \ 32 V(LdaSmi, AccumulatorUse::kWrite, OperandType::kImm) \ 33 V(LdaUndefined, AccumulatorUse::kWrite) \ 34 V(LdaNull, AccumulatorUse::kWrite) \ 35 V(LdaTheHole, AccumulatorUse::kWrite) \ 36 V(LdaTrue, AccumulatorUse::kWrite) \ 37 V(LdaFalse, AccumulatorUse::kWrite) \ 38 V(LdaConstant, AccumulatorUse::kWrite, OperandType::kIdx) \ 39 \ 40 /* Globals */ \ 41 V(LdaGlobal, AccumulatorUse::kWrite, OperandType::kIdx, OperandType::kIdx) \ 42 V(LdaGlobalInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx, \ 43 OperandType::kIdx) \ 44 V(StaGlobalSloppy, AccumulatorUse::kRead, OperandType::kIdx, \ 45 OperandType::kIdx) \ 46 V(StaGlobalStrict, AccumulatorUse::kRead, OperandType::kIdx, \ 47 OperandType::kIdx) \ 48 \ 49 /* Context operations */ \ 50 V(PushContext, AccumulatorUse::kRead, OperandType::kRegOut) \ 51 V(PopContext, AccumulatorUse::kNone, OperandType::kReg) \ 52 V(LdaContextSlot, AccumulatorUse::kWrite, OperandType::kReg, \ 53 OperandType::kIdx, OperandType::kUImm) \ 54 V(LdaImmutableContextSlot, AccumulatorUse::kWrite, OperandType::kReg, \ 55 OperandType::kIdx, OperandType::kUImm) \ 56 V(LdaCurrentContextSlot, AccumulatorUse::kWrite, OperandType::kIdx) \ 57 V(LdaImmutableCurrentContextSlot, AccumulatorUse::kWrite, OperandType::kIdx) \ 58 V(StaContextSlot, AccumulatorUse::kRead, OperandType::kReg, \ 59 OperandType::kIdx, OperandType::kUImm) \ 60 V(StaCurrentContextSlot, AccumulatorUse::kRead, OperandType::kIdx) \ 61 \ 62 /* Load-Store lookup slots */ \ 63 V(LdaLookupSlot, AccumulatorUse::kWrite, OperandType::kIdx) \ 64 V(LdaLookupContextSlot, AccumulatorUse::kWrite, OperandType::kIdx, \ 65 OperandType::kIdx, OperandType::kUImm) \ 66 V(LdaLookupGlobalSlot, AccumulatorUse::kWrite, OperandType::kIdx, \ 67 OperandType::kIdx, OperandType::kUImm) \ 68 V(LdaLookupSlotInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx) \ 69 V(LdaLookupContextSlotInsideTypeof, AccumulatorUse::kWrite, \ 70 OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \ 71 V(LdaLookupGlobalSlotInsideTypeof, AccumulatorUse::kWrite, \ 72 OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \ 73 V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx) \ 74 V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx) \ 75 \ 76 /* Register-accumulator transfers */ \ 77 V(Ldar, AccumulatorUse::kWrite, OperandType::kReg) \ 78 V(Star, AccumulatorUse::kRead, OperandType::kRegOut) \ 79 \ 80 /* Register-register transfers */ \ 81 V(Mov, AccumulatorUse::kNone, OperandType::kReg, OperandType::kRegOut) \ 82 \ 83 /* Property loads (LoadIC) operations */ \ 84 V(LdaNamedProperty, AccumulatorUse::kWrite, OperandType::kReg, \ 85 OperandType::kIdx, OperandType::kIdx) \ 86 V(LdaKeyedProperty, AccumulatorUse::kReadWrite, OperandType::kReg, \ 87 OperandType::kIdx) \ 88 \ 89 /* Operations on module variables */ \ 90 V(LdaModuleVariable, AccumulatorUse::kWrite, OperandType::kImm, \ 91 OperandType::kUImm) \ 92 V(StaModuleVariable, AccumulatorUse::kRead, OperandType::kImm, \ 93 OperandType::kUImm) \ 94 \ 95 /* Propery stores (StoreIC) operations */ \ 96 V(StaNamedPropertySloppy, AccumulatorUse::kRead, OperandType::kReg, \ 97 OperandType::kIdx, OperandType::kIdx) \ 98 V(StaNamedPropertyStrict, AccumulatorUse::kRead, OperandType::kReg, \ 99 OperandType::kIdx, OperandType::kIdx) \ 100 V(StaNamedOwnProperty, AccumulatorUse::kRead, OperandType::kReg, \ 101 OperandType::kIdx, OperandType::kIdx) \ 102 V(StaKeyedPropertySloppy, AccumulatorUse::kRead, OperandType::kReg, \ 103 OperandType::kReg, OperandType::kIdx) \ 104 V(StaKeyedPropertyStrict, AccumulatorUse::kRead, OperandType::kReg, \ 105 OperandType::kReg, OperandType::kIdx) \ 106 V(StaDataPropertyInLiteral, AccumulatorUse::kRead, OperandType::kReg, \ 107 OperandType::kReg, OperandType::kFlag8, OperandType::kIdx) \ 108 \ 109 /* Binary Operators */ \ 110 V(Add, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \ 111 V(Sub, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \ 112 V(Mul, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \ 113 V(Div, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \ 114 V(Mod, AccumulatorUse::kReadWrite, OperandType::kReg, OperandType::kIdx) \ 115 V(BitwiseOr, AccumulatorUse::kReadWrite, OperandType::kReg, \ 116 OperandType::kIdx) \ 117 V(BitwiseXor, AccumulatorUse::kReadWrite, OperandType::kReg, \ 118 OperandType::kIdx) \ 119 V(BitwiseAnd, AccumulatorUse::kReadWrite, OperandType::kReg, \ 120 OperandType::kIdx) \ 121 V(ShiftLeft, AccumulatorUse::kReadWrite, OperandType::kReg, \ 122 OperandType::kIdx) \ 123 V(ShiftRight, AccumulatorUse::kReadWrite, OperandType::kReg, \ 124 OperandType::kIdx) \ 125 V(ShiftRightLogical, AccumulatorUse::kReadWrite, OperandType::kReg, \ 126 OperandType::kIdx) \ 127 \ 128 /* Binary operators with immediate operands */ \ 129 V(AddSmi, AccumulatorUse::kWrite, OperandType::kImm, OperandType::kReg, \ 130 OperandType::kIdx) \ 131 V(SubSmi, AccumulatorUse::kWrite, OperandType::kImm, OperandType::kReg, \ 132 OperandType::kIdx) \ 133 V(BitwiseOrSmi, AccumulatorUse::kWrite, OperandType::kImm, \ 134 OperandType::kReg, OperandType::kIdx) \ 135 V(BitwiseAndSmi, AccumulatorUse::kWrite, OperandType::kImm, \ 136 OperandType::kReg, OperandType::kIdx) \ 137 V(ShiftLeftSmi, AccumulatorUse::kWrite, OperandType::kImm, \ 138 OperandType::kReg, OperandType::kIdx) \ 139 V(ShiftRightSmi, AccumulatorUse::kWrite, OperandType::kImm, \ 140 OperandType::kReg, OperandType::kIdx) \ 141 \ 142 /* Unary Operators */ \ 143 V(Inc, AccumulatorUse::kReadWrite, OperandType::kIdx) \ 144 V(Dec, AccumulatorUse::kReadWrite, OperandType::kIdx) \ 145 V(ToBooleanLogicalNot, AccumulatorUse::kReadWrite) \ 146 V(LogicalNot, AccumulatorUse::kReadWrite) \ 147 V(TypeOf, AccumulatorUse::kReadWrite) \ 148 V(DeletePropertyStrict, AccumulatorUse::kReadWrite, OperandType::kReg) \ 149 V(DeletePropertySloppy, AccumulatorUse::kReadWrite, OperandType::kReg) \ 150 \ 151 /* GetSuperConstructor operator */ \ 152 V(GetSuperConstructor, AccumulatorUse::kRead, OperandType::kRegOut) \ 153 \ 154 /* Call operations */ \ 155 V(Call, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kRegList, \ 156 OperandType::kRegCount, OperandType::kIdx) \ 157 V(CallProperty, AccumulatorUse::kWrite, OperandType::kReg, \ 158 OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \ 159 V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kReg, \ 160 OperandType::kRegList, OperandType::kRegCount) \ 161 V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \ 162 OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \ 163 V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \ 164 OperandType::kRegList, OperandType::kRegCount) \ 165 V(CallRuntimeForPair, AccumulatorUse::kNone, OperandType::kRuntimeId, \ 166 OperandType::kRegList, OperandType::kRegCount, OperandType::kRegOutPair) \ 167 V(CallJSRuntime, AccumulatorUse::kWrite, OperandType::kIdx, \ 168 OperandType::kRegList, OperandType::kRegCount) \ 169 \ 170 /* Intrinsics */ \ 171 V(InvokeIntrinsic, AccumulatorUse::kWrite, OperandType::kIntrinsicId, \ 172 OperandType::kRegList, OperandType::kRegCount) \ 173 \ 174 /* Construct operators */ \ 175 V(Construct, AccumulatorUse::kReadWrite, OperandType::kReg, \ 176 OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \ 177 V(ConstructWithSpread, AccumulatorUse::kReadWrite, OperandType::kReg, \ 178 OperandType::kRegList, OperandType::kRegCount) \ 179 \ 180 /* Test Operators */ \ 181 V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg, \ 182 OperandType::kIdx) \ 183 V(TestNotEqual, AccumulatorUse::kReadWrite, OperandType::kReg, \ 184 OperandType::kIdx) \ 185 V(TestEqualStrict, AccumulatorUse::kReadWrite, OperandType::kReg, \ 186 OperandType::kIdx) \ 187 V(TestLessThan, AccumulatorUse::kReadWrite, OperandType::kReg, \ 188 OperandType::kIdx) \ 189 V(TestGreaterThan, AccumulatorUse::kReadWrite, OperandType::kReg, \ 190 OperandType::kIdx) \ 191 V(TestLessThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg, \ 192 OperandType::kIdx) \ 193 V(TestGreaterThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg, \ 194 OperandType::kIdx) \ 195 V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg) \ 196 V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg) \ 197 \ 198 /* TestEqual with Null or Undefined */ \ 199 V(TestUndetectable, AccumulatorUse::kWrite, OperandType::kReg) \ 200 V(TestNull, AccumulatorUse::kWrite, OperandType::kReg) \ 201 V(TestUndefined, AccumulatorUse::kWrite, OperandType::kReg) \ 202 \ 203 /* Cast operators */ \ 204 V(ToName, AccumulatorUse::kRead, OperandType::kRegOut) \ 205 V(ToNumber, AccumulatorUse::kRead, OperandType::kRegOut) \ 206 V(ToObject, AccumulatorUse::kRead, OperandType::kRegOut) \ 207 \ 208 /* Literals */ \ 209 V(CreateRegExpLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \ 210 OperandType::kIdx, OperandType::kFlag8) \ 211 V(CreateArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \ 212 OperandType::kIdx, OperandType::kFlag8) \ 213 V(CreateObjectLiteral, AccumulatorUse::kNone, OperandType::kIdx, \ 214 OperandType::kIdx, OperandType::kFlag8, OperandType::kRegOut) \ 215 \ 216 /* Closure allocation */ \ 217 V(CreateClosure, AccumulatorUse::kWrite, OperandType::kIdx, \ 218 OperandType::kIdx, OperandType::kFlag8) \ 219 \ 220 /* Context allocation */ \ 221 V(CreateBlockContext, AccumulatorUse::kReadWrite, OperandType::kIdx) \ 222 V(CreateCatchContext, AccumulatorUse::kReadWrite, OperandType::kReg, \ 223 OperandType::kIdx, OperandType::kIdx) \ 224 V(CreateFunctionContext, AccumulatorUse::kWrite, OperandType::kUImm) \ 225 V(CreateEvalContext, AccumulatorUse::kWrite, OperandType::kUImm) \ 226 V(CreateWithContext, AccumulatorUse::kReadWrite, OperandType::kReg, \ 227 OperandType::kIdx) \ 228 \ 229 /* Arguments allocation */ \ 230 V(CreateMappedArguments, AccumulatorUse::kWrite) \ 231 V(CreateUnmappedArguments, AccumulatorUse::kWrite) \ 232 V(CreateRestParameter, AccumulatorUse::kWrite) \ 233 \ 234 /* Control Flow -- carefully ordered for efficient checks */ \ 235 /* - [Unconditional jumps] */ \ 236 V(JumpLoop, AccumulatorUse::kNone, OperandType::kUImm, OperandType::kImm) \ 237 /* - [Forward jumps] */ \ 238 V(Jump, AccumulatorUse::kNone, OperandType::kUImm) \ 239 /* - [Start constant jumps] */ \ 240 V(JumpConstant, AccumulatorUse::kNone, OperandType::kIdx) \ 241 /* - [Conditional jumps] */ \ 242 /* - [Conditional constant jumps] */ \ 243 V(JumpIfNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 244 V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 245 V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 246 V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 247 V(JumpIfJSReceiverConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 248 V(JumpIfNotHoleConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 249 /* - [Start ToBoolean jumps] */ \ 250 V(JumpIfToBooleanTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 251 V(JumpIfToBooleanFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \ 252 /* - [End constant jumps] */ \ 253 /* - [Conditional immediate jumps] */ \ 254 V(JumpIfToBooleanTrue, AccumulatorUse::kRead, OperandType::kUImm) \ 255 V(JumpIfToBooleanFalse, AccumulatorUse::kRead, OperandType::kUImm) \ 256 /* - [End ToBoolean jumps] */ \ 257 V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kUImm) \ 258 V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kUImm) \ 259 V(JumpIfNull, AccumulatorUse::kRead, OperandType::kUImm) \ 260 V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kUImm) \ 261 V(JumpIfJSReceiver, AccumulatorUse::kRead, OperandType::kUImm) \ 262 V(JumpIfNotHole, AccumulatorUse::kRead, OperandType::kUImm) \ 263 \ 264 /* Complex flow control For..in */ \ 265 V(ForInPrepare, AccumulatorUse::kNone, OperandType::kReg, \ 266 OperandType::kRegOutTriple) \ 267 V(ForInContinue, AccumulatorUse::kWrite, OperandType::kReg, \ 268 OperandType::kReg) \ 269 V(ForInNext, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \ 270 OperandType::kRegPair, OperandType::kIdx) \ 271 V(ForInStep, AccumulatorUse::kWrite, OperandType::kReg) \ 272 \ 273 /* Perform a stack guard check */ \ 274 V(StackCheck, AccumulatorUse::kNone) \ 275 \ 276 /* Update the pending message */ \ 277 V(SetPendingMessage, AccumulatorUse::kReadWrite) \ 278 \ 279 /* Non-local flow control */ \ 280 V(Throw, AccumulatorUse::kRead) \ 281 V(ReThrow, AccumulatorUse::kRead) \ 282 V(Return, AccumulatorUse::kRead) \ 283 \ 284 /* Generators */ \ 285 V(SuspendGenerator, AccumulatorUse::kRead, OperandType::kReg) \ 286 V(ResumeGenerator, AccumulatorUse::kWrite, OperandType::kReg) \ 287 \ 288 /* Debugger */ \ 289 V(Debugger, AccumulatorUse::kNone) \ 290 \ 291 /* Debug Breakpoints - one for each possible size of unscaled bytecodes */ \ 292 /* and one for each operand widening prefix bytecode */ \ 293 V(DebugBreak0, AccumulatorUse::kRead) \ 294 V(DebugBreak1, AccumulatorUse::kRead, OperandType::kReg) \ 295 V(DebugBreak2, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg) \ 296 V(DebugBreak3, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \ 297 OperandType::kReg) \ 298 V(DebugBreak4, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \ 299 OperandType::kReg, OperandType::kReg) \ 300 V(DebugBreak5, AccumulatorUse::kRead, OperandType::kRuntimeId, \ 301 OperandType::kReg, OperandType::kReg) \ 302 V(DebugBreak6, AccumulatorUse::kRead, OperandType::kRuntimeId, \ 303 OperandType::kReg, OperandType::kReg, OperandType::kReg) \ 304 V(DebugBreakWide, AccumulatorUse::kRead) \ 305 V(DebugBreakExtraWide, AccumulatorUse::kRead) \ 306 \ 307 /* Illegal bytecode (terminates execution) */ \ 308 V(Illegal, AccumulatorUse::kNone) \ 309 \ 310 /* No operation (used to maintain source positions for peephole */ \ 311 /* eliminated bytecodes). */ \ 312 V(Nop, AccumulatorUse::kNone) 313 314 // List of debug break bytecodes. 315 #define DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \ 316 V(DebugBreak0) \ 317 V(DebugBreak1) \ 318 V(DebugBreak2) \ 319 V(DebugBreak3) \ 320 V(DebugBreak4) \ 321 V(DebugBreak5) \ 322 V(DebugBreak6) 323 324 #define DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) \ 325 V(DebugBreakWide) \ 326 V(DebugBreakExtraWide) 327 328 #define DEBUG_BREAK_BYTECODE_LIST(V) \ 329 DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \ 330 DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) 331 332 // Lists of jump bytecodes. 333 334 #define JUMP_UNCONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 335 V(JumpLoop) \ 336 V(Jump) 337 338 #define JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V) V(JumpConstant) 339 340 #define JUMP_TOBOOLEAN_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 341 V(JumpIfToBooleanTrue) \ 342 V(JumpIfToBooleanFalse) 343 344 #define JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \ 345 V(JumpIfToBooleanTrueConstant) \ 346 V(JumpIfToBooleanFalseConstant) 347 348 #define JUMP_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 349 JUMP_TOBOOLEAN_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 350 V(JumpIfTrue) \ 351 V(JumpIfFalse) \ 352 V(JumpIfNull) \ 353 V(JumpIfUndefined) \ 354 V(JumpIfJSReceiver) \ 355 V(JumpIfNotHole) 356 357 #define JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \ 358 JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \ 359 V(JumpIfNullConstant) \ 360 V(JumpIfUndefinedConstant) \ 361 V(JumpIfTrueConstant) \ 362 V(JumpIfFalseConstant) \ 363 V(JumpIfJSReceiverConstant) \ 364 V(JumpIfNotHoleConstant) 365 366 #define JUMP_CONSTANT_BYTECODE_LIST(V) \ 367 JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V) \ 368 JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) 369 370 #define JUMP_IMMEDIATE_BYTECODE_LIST(V) \ 371 JUMP_UNCONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 372 JUMP_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) 373 374 #define JUMP_TO_BOOLEAN_BYTECODE_LIST(V) \ 375 JUMP_TOBOOLEAN_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 376 JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) 377 378 #define JUMP_UNCONDITIONAL_BYTECODE_LIST(V) \ 379 JUMP_UNCONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 380 JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V) 381 382 #define JUMP_CONDITIONAL_BYTECODE_LIST(V) \ 383 JUMP_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \ 384 JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) 385 386 #define JUMP_FORWARD_BYTECODE_LIST(V) \ 387 V(Jump) \ 388 V(JumpConstant) \ 389 JUMP_CONDITIONAL_BYTECODE_LIST(V) 390 391 #define JUMP_BYTECODE_LIST(V) \ 392 JUMP_FORWARD_BYTECODE_LIST(V) \ 393 V(JumpLoop) 394 395 // Enumeration of interpreter bytecodes. 396 enum class Bytecode : uint8_t { 397 #define DECLARE_BYTECODE(Name, ...) k##Name, 398 BYTECODE_LIST(DECLARE_BYTECODE) 399 #undef DECLARE_BYTECODE 400 #define COUNT_BYTECODE(x, ...) +1 401 // The COUNT_BYTECODE macro will turn this into kLast = -1 +1 +1... which will 402 // evaluate to the same value as the last real bytecode. 403 kLast = -1 BYTECODE_LIST(COUNT_BYTECODE) 404 #undef COUNT_BYTECODE 405 }; 406 407 class V8_EXPORT_PRIVATE Bytecodes final { 408 public: 409 // The maximum number of operands a bytecode may have. 410 static const int kMaxOperands = 4; 411 412 // Returns string representation of |bytecode|. 413 static const char* ToString(Bytecode bytecode); 414 415 // Returns string representation of |bytecode|. 416 static std::string ToString(Bytecode bytecode, OperandScale operand_scale); 417 418 // Returns byte value of bytecode. ToByte(Bytecode bytecode)419 static uint8_t ToByte(Bytecode bytecode) { 420 DCHECK_LE(bytecode, Bytecode::kLast); 421 return static_cast<uint8_t>(bytecode); 422 } 423 424 // Returns bytecode for |value|. FromByte(uint8_t value)425 static Bytecode FromByte(uint8_t value) { 426 Bytecode bytecode = static_cast<Bytecode>(value); 427 DCHECK(bytecode <= Bytecode::kLast); 428 return bytecode; 429 } 430 431 // Returns the prefix bytecode representing an operand scale to be 432 // applied to a a bytecode. OperandScaleToPrefixBytecode(OperandScale operand_scale)433 static Bytecode OperandScaleToPrefixBytecode(OperandScale operand_scale) { 434 switch (operand_scale) { 435 case OperandScale::kQuadruple: 436 return Bytecode::kExtraWide; 437 case OperandScale::kDouble: 438 return Bytecode::kWide; 439 default: 440 UNREACHABLE(); 441 return Bytecode::kIllegal; 442 } 443 } 444 445 // Returns true if the operand scale requires a prefix bytecode. OperandScaleRequiresPrefixBytecode(OperandScale operand_scale)446 static bool OperandScaleRequiresPrefixBytecode(OperandScale operand_scale) { 447 return operand_scale != OperandScale::kSingle; 448 } 449 450 // Returns the scaling applied to scalable operands if bytecode is 451 // is a scaling prefix. PrefixBytecodeToOperandScale(Bytecode bytecode)452 static OperandScale PrefixBytecodeToOperandScale(Bytecode bytecode) { 453 switch (bytecode) { 454 case Bytecode::kExtraWide: 455 case Bytecode::kDebugBreakExtraWide: 456 return OperandScale::kQuadruple; 457 case Bytecode::kWide: 458 case Bytecode::kDebugBreakWide: 459 return OperandScale::kDouble; 460 default: 461 UNREACHABLE(); 462 return OperandScale::kSingle; 463 } 464 } 465 466 // Returns how accumulator is used by |bytecode|. GetAccumulatorUse(Bytecode bytecode)467 static AccumulatorUse GetAccumulatorUse(Bytecode bytecode) { 468 DCHECK(bytecode <= Bytecode::kLast); 469 return kAccumulatorUse[static_cast<size_t>(bytecode)]; 470 } 471 472 // Returns true if |bytecode| reads the accumulator. ReadsAccumulator(Bytecode bytecode)473 static bool ReadsAccumulator(Bytecode bytecode) { 474 return BytecodeOperands::ReadsAccumulator(GetAccumulatorUse(bytecode)); 475 } 476 477 // Returns true if |bytecode| writes the accumulator. WritesAccumulator(Bytecode bytecode)478 static bool WritesAccumulator(Bytecode bytecode) { 479 return BytecodeOperands::WritesAccumulator(GetAccumulatorUse(bytecode)); 480 } 481 482 // Return true if |bytecode| writes the accumulator with a boolean value. WritesBooleanToAccumulator(Bytecode bytecode)483 static bool WritesBooleanToAccumulator(Bytecode bytecode) { 484 switch (bytecode) { 485 case Bytecode::kLdaTrue: 486 case Bytecode::kLdaFalse: 487 case Bytecode::kToBooleanLogicalNot: 488 case Bytecode::kLogicalNot: 489 case Bytecode::kTestEqual: 490 case Bytecode::kTestNotEqual: 491 case Bytecode::kTestEqualStrict: 492 case Bytecode::kTestLessThan: 493 case Bytecode::kTestLessThanOrEqual: 494 case Bytecode::kTestGreaterThan: 495 case Bytecode::kTestGreaterThanOrEqual: 496 case Bytecode::kTestInstanceOf: 497 case Bytecode::kTestIn: 498 case Bytecode::kTestUndetectable: 499 case Bytecode::kForInContinue: 500 case Bytecode::kTestUndefined: 501 case Bytecode::kTestNull: 502 return true; 503 default: 504 return false; 505 } 506 } 507 508 // Return true if |bytecode| is an accumulator load without effects, 509 // e.g. LdaConstant, LdaTrue, Ldar. IsAccumulatorLoadWithoutEffects(Bytecode bytecode)510 static constexpr bool IsAccumulatorLoadWithoutEffects(Bytecode bytecode) { 511 return bytecode == Bytecode::kLdar || bytecode == Bytecode::kLdaZero || 512 bytecode == Bytecode::kLdaSmi || bytecode == Bytecode::kLdaNull || 513 bytecode == Bytecode::kLdaTrue || bytecode == Bytecode::kLdaFalse || 514 bytecode == Bytecode::kLdaUndefined || 515 bytecode == Bytecode::kLdaTheHole || 516 bytecode == Bytecode::kLdaConstant || 517 bytecode == Bytecode::kLdaContextSlot || 518 bytecode == Bytecode::kLdaCurrentContextSlot || 519 bytecode == Bytecode::kLdaImmutableContextSlot || 520 bytecode == Bytecode::kLdaImmutableCurrentContextSlot; 521 } 522 523 // Return true if |bytecode| is a register load without effects, 524 // e.g. Mov, Star. IsRegisterLoadWithoutEffects(Bytecode bytecode)525 static constexpr bool IsRegisterLoadWithoutEffects(Bytecode bytecode) { 526 return bytecode == Bytecode::kMov || bytecode == Bytecode::kPopContext || 527 bytecode == Bytecode::kPushContext || bytecode == Bytecode::kStar; 528 } 529 530 // Returns true if the bytecode is a conditional jump taking 531 // an immediate byte operand (OperandType::kImm). IsConditionalJumpImmediate(Bytecode bytecode)532 static constexpr bool IsConditionalJumpImmediate(Bytecode bytecode) { 533 return bytecode >= Bytecode::kJumpIfToBooleanTrue && 534 bytecode <= Bytecode::kJumpIfNotHole; 535 } 536 537 // Returns true if the bytecode is a conditional jump taking 538 // a constant pool entry (OperandType::kIdx). IsConditionalJumpConstant(Bytecode bytecode)539 static constexpr bool IsConditionalJumpConstant(Bytecode bytecode) { 540 return bytecode >= Bytecode::kJumpIfNullConstant && 541 bytecode <= Bytecode::kJumpIfToBooleanFalseConstant; 542 } 543 544 // Returns true if the bytecode is a conditional jump taking 545 // any kind of operand. IsConditionalJump(Bytecode bytecode)546 static constexpr bool IsConditionalJump(Bytecode bytecode) { 547 return bytecode >= Bytecode::kJumpIfNullConstant && 548 bytecode <= Bytecode::kJumpIfNotHole; 549 } 550 551 // Returns true if the bytecode is an unconditional jump. IsUnconditionalJump(Bytecode bytecode)552 static constexpr bool IsUnconditionalJump(Bytecode bytecode) { 553 return bytecode >= Bytecode::kJumpLoop && 554 bytecode <= Bytecode::kJumpConstant; 555 } 556 557 // Returns true if the bytecode is a jump or a conditional jump taking 558 // an immediate byte operand (OperandType::kImm). IsJumpImmediate(Bytecode bytecode)559 static constexpr bool IsJumpImmediate(Bytecode bytecode) { 560 return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpLoop || 561 IsConditionalJumpImmediate(bytecode); 562 } 563 564 // Returns true if the bytecode is a jump or conditional jump taking a 565 // constant pool entry (OperandType::kIdx). IsJumpConstant(Bytecode bytecode)566 static constexpr bool IsJumpConstant(Bytecode bytecode) { 567 return bytecode >= Bytecode::kJumpConstant && 568 bytecode <= Bytecode::kJumpIfToBooleanFalseConstant; 569 } 570 571 // Returns true if the bytecode is a jump that internally coerces the 572 // accumulator to a boolean. IsJumpIfToBoolean(Bytecode bytecode)573 static constexpr bool IsJumpIfToBoolean(Bytecode bytecode) { 574 return bytecode >= Bytecode::kJumpIfToBooleanTrueConstant && 575 bytecode <= Bytecode::kJumpIfToBooleanFalse; 576 } 577 578 // Returns true if the bytecode is a jump or conditional jump taking 579 // any kind of operand. IsJump(Bytecode bytecode)580 static constexpr bool IsJump(Bytecode bytecode) { 581 return bytecode >= Bytecode::kJumpLoop && 582 bytecode <= Bytecode::kJumpIfNotHole; 583 } 584 585 // Returns true if the bytecode is a forward jump or conditional jump taking 586 // any kind of operand. IsForwardJump(Bytecode bytecode)587 static constexpr bool IsForwardJump(Bytecode bytecode) { 588 return bytecode >= Bytecode::kJump && bytecode <= Bytecode::kJumpIfNotHole; 589 } 590 591 // Returns true if the bytecode is a conditional jump, a jump, or a return. IsJumpOrReturn(Bytecode bytecode)592 static constexpr bool IsJumpOrReturn(Bytecode bytecode) { 593 return bytecode == Bytecode::kReturn || IsJump(bytecode); 594 } 595 596 // Return true if |bytecode| is a jump without effects, 597 // e.g. any jump excluding those that include type coercion like 598 // JumpIfTrueToBoolean. IsJumpWithoutEffects(Bytecode bytecode)599 static constexpr bool IsJumpWithoutEffects(Bytecode bytecode) { 600 return IsJump(bytecode) && !IsJumpIfToBoolean(bytecode); 601 } 602 603 // Returns true if |bytecode| has no effects. These bytecodes only manipulate 604 // interpreter frame state and will never throw. IsWithoutExternalSideEffects(Bytecode bytecode)605 static constexpr bool IsWithoutExternalSideEffects(Bytecode bytecode) { 606 return (IsAccumulatorLoadWithoutEffects(bytecode) || 607 IsRegisterLoadWithoutEffects(bytecode) || 608 bytecode == Bytecode::kNop || IsJumpWithoutEffects(bytecode)); 609 } 610 611 // Returns true if the bytecode is Ldar or Star. IsLdarOrStar(Bytecode bytecode)612 static constexpr bool IsLdarOrStar(Bytecode bytecode) { 613 return bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar; 614 } 615 616 // Returns true if |bytecode| puts a name in the accumulator. PutsNameInAccumulator(Bytecode bytecode)617 static constexpr bool PutsNameInAccumulator(Bytecode bytecode) { 618 return bytecode == Bytecode::kTypeOf; 619 } 620 621 // Returns true if the bytecode is a call or a constructor call. IsCallOrConstruct(Bytecode bytecode)622 static constexpr bool IsCallOrConstruct(Bytecode bytecode) { 623 return bytecode == Bytecode::kCall || bytecode == Bytecode::kCallProperty || 624 bytecode == Bytecode::kTailCall || 625 bytecode == Bytecode::kConstruct || 626 bytecode == Bytecode::kCallWithSpread || 627 bytecode == Bytecode::kConstructWithSpread || 628 bytecode == Bytecode::kInvokeIntrinsic || 629 bytecode == Bytecode::kCallJSRuntime; 630 } 631 632 // Returns true if the bytecode is a call to the runtime. IsCallRuntime(Bytecode bytecode)633 static constexpr bool IsCallRuntime(Bytecode bytecode) { 634 return bytecode == Bytecode::kCallRuntime || 635 bytecode == Bytecode::kCallRuntimeForPair || 636 bytecode == Bytecode::kInvokeIntrinsic; 637 } 638 639 // Returns true if the bytecode is a scaling prefix bytecode. IsPrefixScalingBytecode(Bytecode bytecode)640 static constexpr bool IsPrefixScalingBytecode(Bytecode bytecode) { 641 return bytecode == Bytecode::kExtraWide || bytecode == Bytecode::kWide || 642 bytecode == Bytecode::kDebugBreakExtraWide || 643 bytecode == Bytecode::kDebugBreakWide; 644 } 645 646 // Returns the number of values which |bytecode| returns. ReturnCount(Bytecode bytecode)647 static constexpr size_t ReturnCount(Bytecode bytecode) { 648 return bytecode == Bytecode::kReturn ? 1 : 0; 649 } 650 651 // Returns the number of operands expected by |bytecode|. NumberOfOperands(Bytecode bytecode)652 static int NumberOfOperands(Bytecode bytecode) { 653 DCHECK(bytecode <= Bytecode::kLast); 654 return kOperandCount[static_cast<size_t>(bytecode)]; 655 } 656 657 // Returns the i-th operand of |bytecode|. GetOperandType(Bytecode bytecode,int i)658 static OperandType GetOperandType(Bytecode bytecode, int i) { 659 DCHECK_LE(bytecode, Bytecode::kLast); 660 DCHECK_LT(i, NumberOfOperands(bytecode)); 661 DCHECK_GE(i, 0); 662 return GetOperandTypes(bytecode)[i]; 663 } 664 665 // Returns a pointer to an array of operand types terminated in 666 // OperandType::kNone. GetOperandTypes(Bytecode bytecode)667 static const OperandType* GetOperandTypes(Bytecode bytecode) { 668 DCHECK(bytecode <= Bytecode::kLast); 669 return kOperandTypes[static_cast<size_t>(bytecode)]; 670 } 671 OperandIsScalableSignedByte(Bytecode bytecode,int operand_index)672 static bool OperandIsScalableSignedByte(Bytecode bytecode, 673 int operand_index) { 674 DCHECK(bytecode <= Bytecode::kLast); 675 return kOperandTypeInfos[static_cast<size_t>(bytecode)][operand_index] == 676 OperandTypeInfo::kScalableSignedByte; 677 } 678 OperandIsScalableUnsignedByte(Bytecode bytecode,int operand_index)679 static bool OperandIsScalableUnsignedByte(Bytecode bytecode, 680 int operand_index) { 681 DCHECK(bytecode <= Bytecode::kLast); 682 return kOperandTypeInfos[static_cast<size_t>(bytecode)][operand_index] == 683 OperandTypeInfo::kScalableUnsignedByte; 684 } 685 OperandIsScalable(Bytecode bytecode,int operand_index)686 static bool OperandIsScalable(Bytecode bytecode, int operand_index) { 687 return OperandIsScalableSignedByte(bytecode, operand_index) || 688 OperandIsScalableUnsignedByte(bytecode, operand_index); 689 } 690 691 // Returns true if the bytecode has wider operand forms. 692 static bool IsBytecodeWithScalableOperands(Bytecode bytecode); 693 694 // Returns the size of the i-th operand of |bytecode|. GetOperandSize(Bytecode bytecode,int i,OperandScale operand_scale)695 static OperandSize GetOperandSize(Bytecode bytecode, int i, 696 OperandScale operand_scale) { 697 CHECK_LT(i, NumberOfOperands(bytecode)); 698 return GetOperandSizes(bytecode, operand_scale)[i]; 699 } 700 701 // Returns the operand sizes of |bytecode| with scale |operand_scale|. GetOperandSizes(Bytecode bytecode,OperandScale operand_scale)702 static const OperandSize* GetOperandSizes(Bytecode bytecode, 703 OperandScale operand_scale) { 704 DCHECK(bytecode <= Bytecode::kLast); 705 DCHECK_GE(operand_scale, OperandScale::kSingle); 706 DCHECK_LE(operand_scale, OperandScale::kLast); 707 STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 && 708 OperandScale::kLast == OperandScale::kQuadruple); 709 int scale_index = static_cast<int>(operand_scale) >> 1; 710 return kOperandSizes[static_cast<size_t>(bytecode)][scale_index]; 711 } 712 713 // Returns the offset of the i-th operand of |bytecode| relative to the start 714 // of the bytecode. 715 static int GetOperandOffset(Bytecode bytecode, int i, 716 OperandScale operand_scale); 717 718 // Returns the size of the bytecode including its operands for the 719 // given |operand_scale|. Size(Bytecode bytecode,OperandScale operand_scale)720 static int Size(Bytecode bytecode, OperandScale operand_scale) { 721 DCHECK(bytecode <= Bytecode::kLast); 722 STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 && 723 OperandScale::kLast == OperandScale::kQuadruple); 724 int scale_index = static_cast<int>(operand_scale) >> 1; 725 return kBytecodeSizes[static_cast<size_t>(bytecode)][scale_index]; 726 } 727 728 // Returns a debug break bytecode to replace |bytecode|. 729 static Bytecode GetDebugBreak(Bytecode bytecode); 730 731 // Returns the equivalent jump bytecode without the accumulator coercion. 732 static Bytecode GetJumpWithoutToBoolean(Bytecode bytecode); 733 734 // Returns true if there is a call in the most-frequently executed path 735 // through the bytecode's handler. 736 static bool MakesCallAlongCriticalPath(Bytecode bytecode); 737 738 // Returns true if the bytecode is a debug break. 739 static bool IsDebugBreak(Bytecode bytecode); 740 741 // Returns true if |operand_type| is any type of register operand. 742 static bool IsRegisterOperandType(OperandType operand_type); 743 744 // Returns true if |operand_type| represents a register used as an input. 745 static bool IsRegisterInputOperandType(OperandType operand_type); 746 747 // Returns true if |operand_type| represents a register used as an output. 748 static bool IsRegisterOutputOperandType(OperandType operand_type); 749 750 // Returns true if the handler for |bytecode| should look ahead and inline a 751 // dispatch to a Star bytecode. 752 static bool IsStarLookahead(Bytecode bytecode, OperandScale operand_scale); 753 754 // Returns the number of registers represented by a register operand. For 755 // instance, a RegPair represents two registers. Should not be called for 756 // kRegList which has a variable number of registers based on the following 757 // kRegCount operand. GetNumberOfRegistersRepresentedBy(OperandType operand_type)758 static int GetNumberOfRegistersRepresentedBy(OperandType operand_type) { 759 switch (operand_type) { 760 case OperandType::kReg: 761 case OperandType::kRegOut: 762 return 1; 763 case OperandType::kRegPair: 764 case OperandType::kRegOutPair: 765 return 2; 766 case OperandType::kRegOutTriple: 767 return 3; 768 case OperandType::kRegList: 769 UNREACHABLE(); 770 return 0; 771 default: 772 return 0; 773 } 774 return 0; 775 } 776 777 // Returns the size of |operand| for |operand_scale|. 778 static OperandSize SizeOfOperand(OperandType operand, OperandScale scale); 779 780 // Returns true if |operand_type| is a runtime-id operand (kRuntimeId). 781 static bool IsRuntimeIdOperandType(OperandType operand_type); 782 783 // Returns true if |operand_type| is unsigned, false if signed. 784 static bool IsUnsignedOperandType(OperandType operand_type); 785 786 // Returns true if a handler is generated for a bytecode at a given 787 // operand scale. All bytecodes have handlers at OperandScale::kSingle, 788 // but only bytecodes with scalable operands have handlers with larger 789 // OperandScale values. 790 static bool BytecodeHasHandler(Bytecode bytecode, OperandScale operand_scale); 791 792 // Return the operand scale required to hold a signed operand with |value|. ScaleForSignedOperand(int32_t value)793 static OperandScale ScaleForSignedOperand(int32_t value) { 794 if (value >= kMinInt8 && value <= kMaxInt8) { 795 return OperandScale::kSingle; 796 } else if (value >= kMinInt16 && value <= kMaxInt16) { 797 return OperandScale::kDouble; 798 } else { 799 return OperandScale::kQuadruple; 800 } 801 } 802 803 // Return the operand scale required to hold an unsigned operand with |value|. ScaleForUnsignedOperand(uint32_t value)804 static OperandScale ScaleForUnsignedOperand(uint32_t value) { 805 if (value <= kMaxUInt8) { 806 return OperandScale::kSingle; 807 } else if (value <= kMaxUInt16) { 808 return OperandScale::kDouble; 809 } else { 810 return OperandScale::kQuadruple; 811 } 812 } 813 814 // Return the operand size required to hold an unsigned operand with |value|. SizeForUnsignedOperand(uint32_t value)815 static OperandSize SizeForUnsignedOperand(uint32_t value) { 816 if (value <= kMaxUInt8) { 817 return OperandSize::kByte; 818 } else if (value <= kMaxUInt16) { 819 return OperandSize::kShort; 820 } else { 821 return OperandSize::kQuad; 822 } 823 } 824 825 private: 826 static const OperandType* const kOperandTypes[]; 827 static const OperandTypeInfo* const kOperandTypeInfos[]; 828 static const int kOperandCount[]; 829 static const int kNumberOfRegisterOperands[]; 830 static const AccumulatorUse kAccumulatorUse[]; 831 static const bool kIsScalable[]; 832 static const int kBytecodeSizes[][3]; 833 static const OperandSize* const kOperandSizes[][3]; 834 }; 835 836 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 837 const Bytecode& bytecode); 838 839 } // namespace interpreter 840 } // namespace internal 841 } // namespace v8 842 843 #endif // V8_INTERPRETER_BYTECODES_H_ 844