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