PortableBaselineInterpret.cpp (329309B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * JavaScript "portable baseline interpreter": an interpreter that is 9 * capable of running ICs, but without any native code. 10 * 11 * See the [SMDOC] in vm/PortableBaselineInterpret.h for a high-level 12 * overview. 13 */ 14 15 #include "vm/PortableBaselineInterpret.h" 16 17 #include "mozilla/Maybe.h" 18 19 #include <algorithm> 20 #include <cmath> 21 22 #include "fdlibm.h" 23 #include "jsapi.h" 24 25 #include "builtin/DataViewObject.h" 26 #include "builtin/MapObject.h" 27 #include "builtin/Object.h" 28 #include "builtin/RegExp.h" 29 #include "builtin/String.h" 30 #include "debugger/DebugAPI.h" 31 #include "jit/BaselineFrame.h" 32 #include "jit/BaselineIC.h" 33 #include "jit/BaselineJIT.h" 34 #include "jit/CacheIR.h" 35 #include "jit/CacheIRCompiler.h" 36 #include "jit/CacheIRReader.h" 37 #include "jit/JitFrames.h" 38 #include "jit/JitScript.h" 39 #include "jit/JSJitFrameIter.h" 40 #include "jit/VMFunctions.h" 41 #include "proxy/DeadObjectProxy.h" 42 #include "proxy/DOMProxy.h" 43 #include "util/Unicode.h" 44 #include "vm/AsyncFunction.h" 45 #include "vm/AsyncIteration.h" 46 #include "vm/DateObject.h" 47 #include "vm/EnvironmentObject.h" 48 #include "vm/EqualityOperations.h" 49 #include "vm/GeneratorObject.h" 50 #include "vm/Interpreter.h" 51 #include "vm/Iteration.h" 52 #include "vm/JitActivation.h" 53 #include "vm/JSObject.h" 54 #include "vm/JSScript.h" 55 #include "vm/ObjectFuse.h" 56 #include "vm/Opcodes.h" 57 #include "vm/PlainObject.h" 58 #include "vm/Shape.h" 59 #include "vm/TypeofEqOperand.h" // TypeofEqOperand 60 #include "vm/WrapperObject.h" 61 62 #include "debugger/DebugAPI-inl.h" 63 #include "jit/BaselineFrame-inl.h" 64 #include "jit/JitScript-inl.h" 65 #include "vm/EnvironmentObject-inl.h" 66 #include "vm/Interpreter-inl.h" 67 #include "vm/JSScript-inl.h" 68 #include "vm/PlainObject-inl.h" 69 70 namespace js { 71 namespace pbl { 72 73 using namespace js::jit; 74 75 /* 76 * Debugging: enable `TRACE_INTERP` for an extremely detailed dump of 77 * what PBL is doing at every opcode step. 78 */ 79 80 // #define TRACE_INTERP 81 82 #ifdef TRACE_INTERP 83 # define TRACE_PRINTF(...) \ 84 do { \ 85 printf(__VA_ARGS__); \ 86 fflush(stdout); \ 87 } while (0) 88 #else 89 # define TRACE_PRINTF(...) \ 90 do { \ 91 } while (0) 92 #endif 93 94 #define PBL_HYBRID_ICS_DEFAULT true 95 96 // Whether we are using the "hybrid" strategy for ICs (see the [SMDOC] 97 // in PortableBaselineInterpret.h for more). This is currently a 98 // constant, but may become configurable in the future. 99 static const bool kHybridICsInterp = PBL_HYBRID_ICS_DEFAULT; 100 101 // Whether to compile interpreter dispatch loops using computed gotos 102 // or direct switches. 103 #if !defined(__wasi__) && !defined(TRACE_INTERP) 104 # define ENABLE_COMPUTED_GOTO_DISPATCH 105 #endif 106 107 // Whether to compile in interrupt checks in the main interpreter loop. 108 #ifndef __wasi__ 109 // On WASI, with a single thread, there is no possibility for an 110 // interrupt to come asynchronously. 111 # define ENABLE_INTERRUPT_CHECKS 112 #endif 113 114 // Whether to compile in coverage counting in the main interpreter loop. 115 #ifndef __wasi__ 116 # define ENABLE_COVERAGE 117 #endif 118 119 /* 120 * ----------------------------------------------- 121 * Stack handling 122 * ----------------------------------------------- 123 */ 124 125 // Large enough for an exit frame. 126 static const size_t kStackMargin = 1024; 127 128 /* 129 * A 64-bit value on the auxiliary stack. May either be a raw uint64_t 130 * or a `Value` (JS NaN-boxed value). 131 */ 132 struct StackVal { 133 uint64_t value; 134 135 explicit StackVal(uint64_t v) : value(v) {} 136 explicit StackVal(const Value& v) : value(v.asRawBits()) {} 137 138 uint64_t asUInt64() const { return value; } 139 Value asValue() const { return Value::fromRawBits(value); } 140 }; 141 142 /* 143 * A native-pointer-sized value on the auxiliary stack. This is 144 * separate from the above because we support running on 32-bit 145 * systems as well! May either be a `void*` (or cast to a 146 * `CalleeToken`, which is a typedef for a `void*`), or a `uint32_t`, 147 * which always fits in a native pointer width on our supported 148 * platforms. (See static_assert below.) 149 */ 150 struct StackValNative { 151 static_assert(sizeof(uintptr_t) >= sizeof(uint32_t), 152 "Must be at least a 32-bit system to use PBL."); 153 154 uintptr_t value; 155 156 explicit StackValNative(void* v) : value(reinterpret_cast<uintptr_t>(v)) {} 157 explicit StackValNative(uint32_t v) : value(v) {} 158 159 void* asVoidPtr() const { return reinterpret_cast<void*>(value); } 160 CalleeToken asCalleeToken() const { 161 return reinterpret_cast<CalleeToken>(value); 162 } 163 }; 164 165 // Assert that the stack alignment is no more than the size of a 166 // StackValNative -- we rely on this when setting up call frames. 167 static_assert(JitStackAlignment <= sizeof(StackValNative)); 168 169 #define PUSH(val) *--sp = (val) 170 #define POP() (*sp++) 171 #define POPN(n) sp += (n) 172 173 #define PUSHNATIVE(val) \ 174 do { \ 175 StackValNative* nativeSP = reinterpret_cast<StackValNative*>(sp); \ 176 *--nativeSP = (val); \ 177 sp = reinterpret_cast<StackVal*>(nativeSP); \ 178 } while (0) 179 #define POPNNATIVE(n) \ 180 sp = reinterpret_cast<StackVal*>(reinterpret_cast<StackValNative*>(sp) + (n)) 181 182 /* 183 * Helper class to manage the auxiliary stack and push/pop frames. 184 */ 185 struct Stack { 186 StackVal* fp; 187 StackVal* base; 188 StackVal* top; 189 StackVal* unwindingSP; 190 StackVal* unwindingFP; 191 192 explicit Stack(PortableBaselineStack& pbs) 193 : fp(reinterpret_cast<StackVal*>(pbs.top)), 194 base(reinterpret_cast<StackVal*>(pbs.base)), 195 top(reinterpret_cast<StackVal*>(pbs.top)), 196 unwindingSP(nullptr), 197 unwindingFP(nullptr) {} 198 199 MOZ_ALWAYS_INLINE bool check(StackVal* sp, size_t size, bool margin = true) { 200 return reinterpret_cast<uintptr_t>(base) + size + 201 (margin ? kStackMargin : 0) <= 202 reinterpret_cast<uintptr_t>(sp); 203 } 204 205 [[nodiscard]] MOZ_ALWAYS_INLINE StackVal* allocate(StackVal* sp, 206 size_t size) { 207 if (!check(sp, size, false)) { 208 return nullptr; 209 } 210 sp = reinterpret_cast<StackVal*>(reinterpret_cast<uintptr_t>(sp) - size); 211 return sp; 212 } 213 214 uint32_t frameSize(StackVal* sp, BaselineFrame* curFrame) const { 215 return sizeof(StackVal) * (reinterpret_cast<StackVal*>(fp) - sp); 216 } 217 218 [[nodiscard]] MOZ_ALWAYS_INLINE BaselineFrame* pushFrame(StackVal* sp, 219 JSContext* cx, 220 JSObject* envChain) { 221 TRACE_PRINTF("pushFrame: sp = %p fp = %p\n", sp, fp); 222 if (sp == base) { 223 return nullptr; 224 } 225 PUSHNATIVE(StackValNative(fp)); 226 fp = sp; 227 TRACE_PRINTF("pushFrame: new fp = %p\n", fp); 228 229 BaselineFrame* frame = 230 reinterpret_cast<BaselineFrame*>(allocate(sp, BaselineFrame::Size())); 231 if (!frame) { 232 return nullptr; 233 } 234 235 frame->setFlags(BaselineFrame::Flags::RUNNING_IN_INTERPRETER); 236 frame->setEnvironmentChain(envChain); 237 JSScript* script = frame->script(); 238 frame->setICScript(script->jitScript()->icScript()); 239 frame->setInterpreterFieldsForPrologue(script); 240 #ifdef DEBUG 241 frame->setDebugFrameSize(0); 242 #endif 243 return frame; 244 } 245 246 StackVal* popFrame() { 247 StackVal* newTOS = 248 reinterpret_cast<StackVal*>(reinterpret_cast<StackValNative*>(fp) + 1); 249 fp = reinterpret_cast<StackVal*>( 250 reinterpret_cast<StackValNative*>(fp)->asVoidPtr()); 251 MOZ_ASSERT(fp); 252 TRACE_PRINTF("popFrame: fp = %p\n", fp); 253 return newTOS; 254 } 255 256 void setFrameSize(StackVal* sp, BaselineFrame* prevFrame) { 257 #ifdef DEBUG 258 MOZ_ASSERT(fp != nullptr); 259 uintptr_t frameSize = 260 reinterpret_cast<uintptr_t>(fp) - reinterpret_cast<uintptr_t>(sp); 261 MOZ_ASSERT(reinterpret_cast<uintptr_t>(fp) >= 262 reinterpret_cast<uintptr_t>(sp)); 263 TRACE_PRINTF("pushExitFrame: fp = %p cur() = %p -> frameSize = %d\n", fp, 264 sp, int(frameSize)); 265 MOZ_ASSERT(frameSize >= BaselineFrame::Size()); 266 prevFrame->setDebugFrameSize(frameSize); 267 #endif 268 } 269 270 [[nodiscard]] MOZ_ALWAYS_INLINE StackVal* pushExitFrame( 271 StackVal* sp, BaselineFrame* prevFrame) { 272 uint8_t* prevFP = 273 reinterpret_cast<uint8_t*>(prevFrame) + BaselineFrame::Size(); 274 TRACE_PRINTF( 275 "pushExitFrame: prevFrame = %p sp = %p BaselineFrame::Size() = %d -> " 276 "computed prevFP = %p actual fp = %p\n", 277 prevFrame, sp, int(BaselineFrame::Size()), prevFP, fp); 278 MOZ_ASSERT(reinterpret_cast<StackVal*>(prevFP) == fp); 279 setFrameSize(sp, prevFrame); 280 281 if (!check(sp, sizeof(StackVal) * 4, false)) { 282 return nullptr; 283 } 284 285 PUSHNATIVE(StackValNative( 286 MakeFrameDescriptorForJitCall(FrameType::BaselineJS, 0))); 287 PUSHNATIVE(StackValNative(nullptr)); // fake return address. 288 PUSHNATIVE(StackValNative(prevFP)); 289 StackVal* exitFP = sp; 290 fp = exitFP; 291 TRACE_PRINTF(" -> fp = %p\n", fp); 292 PUSHNATIVE(StackValNative(uint32_t(ExitFrameType::Bare))); 293 return exitFP; 294 } 295 296 void popExitFrame(StackVal* fp) { 297 StackVal* prevFP = reinterpret_cast<StackVal*>( 298 reinterpret_cast<StackValNative*>(fp)->asVoidPtr()); 299 MOZ_ASSERT(prevFP); 300 this->fp = prevFP; 301 TRACE_PRINTF("popExitFrame: fp -> %p\n", fp); 302 } 303 304 BaselineFrame* frameFromFP() { 305 return reinterpret_cast<BaselineFrame*>(reinterpret_cast<uintptr_t>(fp) - 306 BaselineFrame::Size()); 307 } 308 309 static HandleValue handle(StackVal* sp) { 310 return HandleValue::fromMarkedLocation(reinterpret_cast<Value*>(sp)); 311 } 312 static MutableHandleValue handleMut(StackVal* sp) { 313 return MutableHandleValue::fromMarkedLocation(reinterpret_cast<Value*>(sp)); 314 } 315 }; 316 317 /* 318 * ----------------------------------------------- 319 * Interpreter state 320 * ----------------------------------------------- 321 */ 322 323 struct ICRegs { 324 static const int kMaxICVals = 16; 325 // Values can be split across two OR'd halves: unboxed bits and 326 // tags. We mostly rely on the CacheIRWriter/Reader typed OperandId 327 // system to ensure "type safety" in CacheIR w.r.t. unboxing: the 328 // existence of an ObjOperandId implies that the value is unboxed, 329 // so `icVals` contains a pointer (reinterpret-casted to a 330 // `uint64_t`) and `icTags` contains the tag bits. An operator that 331 // requires a tagged Value can OR the two together (this corresponds 332 // to `useValueRegister` rather than `useRegister` in the native 333 // baseline compiler). 334 uint64_t icVals[kMaxICVals]; 335 uint64_t icTags[kMaxICVals]; // Shifted tags. 336 int extraArgs; 337 }; 338 339 struct State { 340 RootedValue value0; 341 RootedValue value1; 342 RootedValue value2; 343 RootedValue value3; 344 RootedValue res; 345 RootedObject obj0; 346 RootedObject obj1; 347 RootedObject obj2; 348 RootedString str0; 349 RootedString str1; 350 RootedString str2; 351 RootedScript script0; 352 Rooted<PropertyName*> name0; 353 Rooted<jsid> id0; 354 Rooted<JSAtom*> atom0; 355 RootedFunction fun0; 356 Rooted<Scope*> scope0; 357 358 explicit State(JSContext* cx) 359 : value0(cx), 360 value1(cx), 361 value2(cx), 362 value3(cx), 363 res(cx), 364 obj0(cx), 365 obj1(cx), 366 obj2(cx), 367 str0(cx), 368 str1(cx), 369 str2(cx), 370 script0(cx), 371 name0(cx), 372 id0(cx), 373 atom0(cx), 374 fun0(cx), 375 scope0(cx) {} 376 }; 377 378 /* 379 * ----------------------------------------------- 380 * RAII helpers for pushing exit frames. 381 * 382 * (See [SMDOC] in PortableBaselineInterpret.h for more.) 383 * ----------------------------------------------- 384 */ 385 386 class VMFrameManager { 387 JSContext* cx; 388 BaselineFrame* frame; 389 friend class VMFrame; 390 391 public: 392 VMFrameManager(JSContext*& cx_, BaselineFrame* frame_) 393 : cx(cx_), frame(frame_) { 394 // Once the manager exists, we need to create an exit frame to 395 // have access to the cx (unless the caller promises it is not 396 // calling into the rest of the runtime). 397 cx_ = nullptr; 398 } 399 400 void switchToFrame(BaselineFrame* frame) { this->frame = frame; } 401 402 // Provides the JSContext, but *only* if no calls into the rest of 403 // the runtime (that may invoke a GC or stack walk) occur. Avoids 404 // the overhead of pushing an exit frame. 405 JSContext* cxForLocalUseOnly() const { return cx; } 406 }; 407 408 class VMFrame { 409 JSContext* cx; 410 Stack& stack; 411 StackVal* exitFP; 412 void* prevSavedStack; 413 414 public: 415 VMFrame(VMFrameManager& mgr, Stack& stack_, StackVal* sp) 416 : cx(mgr.cx), stack(stack_) { 417 exitFP = stack.pushExitFrame(sp, mgr.frame); 418 if (!exitFP) { 419 return; 420 } 421 cx->activation()->asJit()->setJSExitFP(reinterpret_cast<uint8_t*>(exitFP)); 422 prevSavedStack = cx->portableBaselineStack().top; 423 cx->portableBaselineStack().top = reinterpret_cast<void*>(spBelowFrame()); 424 } 425 426 StackVal* spBelowFrame() { 427 return reinterpret_cast<StackVal*>(reinterpret_cast<uintptr_t>(exitFP) - 428 sizeof(StackValNative)); 429 } 430 431 ~VMFrame() { 432 stack.popExitFrame(exitFP); 433 cx->portableBaselineStack().top = prevSavedStack; 434 } 435 436 JSContext* getCx() const { return cx; } 437 operator JSContext*() const { return cx; } 438 439 bool success() const { return exitFP != nullptr; } 440 }; 441 442 #define PUSH_EXIT_FRAME_OR_RET(value, init_sp) \ 443 VMFrame cx(ctx.frameMgr, ctx.stack, init_sp); \ 444 if (!cx.success()) { \ 445 return value; \ 446 } \ 447 StackVal* sp = cx.spBelowFrame(); /* shadow the definition */ \ 448 (void)sp; /* avoid unused-variable warnings */ 449 450 #define PUSH_IC_FRAME() \ 451 ctx.error = PBIResult::Error; \ 452 PUSH_EXIT_FRAME_OR_RET(IC_ERROR_SENTINEL(), ctx.sp()) 453 #define PUSH_FALLBACK_IC_FRAME() \ 454 ctx.error = PBIResult::Error; \ 455 PUSH_EXIT_FRAME_OR_RET(IC_ERROR_SENTINEL(), sp) 456 #define PUSH_EXIT_FRAME() \ 457 frame->interpreterPC() = pc; \ 458 SYNCSP(); \ 459 PUSH_EXIT_FRAME_OR_RET(PBIResult::Error, sp) 460 461 /* 462 * ----------------------------------------------- 463 * IC Interpreter 464 * ----------------------------------------------- 465 */ 466 467 // Bundled state for passing to ICs, in order to reduce the number of 468 // arguments and hence make the call more ABI-efficient. (On some 469 // platforms, e.g. Wasm on Wasmtime on x86-64, we have as few as four 470 // register arguments available before args go through the stack.) 471 struct ICCtx { 472 BaselineFrame* frame; 473 VMFrameManager frameMgr; 474 State& state; 475 ICRegs icregs; 476 Stack& stack; 477 StackVal* sp_; 478 PBIResult error; 479 uint64_t arg2; 480 481 ICCtx(JSContext* cx, BaselineFrame* frame_, State& state_, Stack& stack_) 482 : frame(frame_), 483 frameMgr(cx, frame_), 484 state(state_), 485 icregs(), 486 stack(stack_), 487 sp_(nullptr), 488 error(PBIResult::Ok), 489 arg2(0) {} 490 491 StackVal* sp() { return sp_; } 492 }; 493 494 #define IC_ERROR_SENTINEL() (JS::MagicValue(JS_GENERIC_MAGIC).asRawBits()) 495 496 // Universal signature for an IC stub function. 497 typedef uint64_t (*ICStubFunc)(uint64_t arg0, uint64_t arg1, ICStub* stub, 498 ICCtx& ctx); 499 500 #define PBL_CALL_IC(jitcode, ctx, stubvalue, result, arg0, arg1, arg2value, \ 501 hasarg2) \ 502 do { \ 503 ctx.arg2 = arg2value; \ 504 ICStubFunc func = reinterpret_cast<ICStubFunc>(jitcode); \ 505 result = func(arg0, arg1, stubvalue, ctx); \ 506 } while (0) 507 508 typedef PBIResult (*PBIFunc)(JSContext* cx_, State& state, Stack& stack, 509 StackVal* sp, JSObject* envChain, Value* ret, 510 jsbytecode* pc, ImmutableScriptData* isd, 511 jsbytecode* restartEntryPC, 512 BaselineFrame* restartFrame, 513 StackVal* restartEntryFrame, 514 PBIResult restartCode); 515 516 static uint64_t CallNextIC(uint64_t arg0, uint64_t arg1, ICStub* stub, 517 ICCtx& ctx); 518 519 static double DoubleMinMax(bool isMax, double first, double second) { 520 if (std::isnan(first) || std::isnan(second)) { 521 return JS::GenericNaN(); 522 } else if (first == 0 && second == 0) { 523 // -0 and 0 compare as equal, but we have to distinguish 524 // them here: min(-0, 0) = -0, max(-0, 0) = 0. 525 bool firstPos = !std::signbit(first); 526 bool secondPos = !std::signbit(second); 527 bool sign = isMax ? (firstPos || secondPos) : (firstPos && secondPos); 528 return sign ? 0.0 : -0.0; 529 } else { 530 return isMax ? ((first >= second) ? first : second) 531 : ((first <= second) ? first : second); 532 } 533 } 534 535 // Interpreter for CacheIR. 536 uint64_t ICInterpretOps(uint64_t arg0, uint64_t arg1, ICStub* stub, 537 ICCtx& ctx) { 538 { 539 #define DECLARE_CACHEOP_CASE(name) __label__ cacheop_##name 540 541 #ifdef ENABLE_COMPUTED_GOTO_DISPATCH 542 543 # define CACHEOP_CASE(name) cacheop_##name : CACHEOP_TRACE(name) 544 # define CACHEOP_CASE_FALLTHROUGH(name) CACHEOP_CASE(name) 545 546 # define DISPATCH_CACHEOP() \ 547 cacheop = cacheIRReader.readOp(); \ 548 goto* addresses[long(cacheop)]; 549 550 #else // ENABLE_COMPUTED_GOTO_DISPATCH 551 552 # define CACHEOP_CASE(name) \ 553 case CacheOp::name: \ 554 cacheop_##name : CACHEOP_TRACE(name) 555 # define CACHEOP_CASE_FALLTHROUGH(name) \ 556 [[fallthrough]]; \ 557 CACHEOP_CASE(name) 558 559 # define DISPATCH_CACHEOP() \ 560 cacheop = cacheIRReader.readOp(); \ 561 goto dispatch; 562 563 #endif // !ENABLE_COMPUTED_GOTO_DISPATCH 564 565 #define READ_REG(index) ctx.icregs.icVals[(index)] 566 #define READ_VALUE_REG(index) \ 567 Value::fromRawBits(ctx.icregs.icVals[(index)] | ctx.icregs.icTags[(index)]) 568 #define WRITE_REG(index, value, tag) \ 569 do { \ 570 ctx.icregs.icVals[(index)] = (value); \ 571 ctx.icregs.icTags[(index)] = uint64_t(JSVAL_TAG_##tag) << JSVAL_TAG_SHIFT; \ 572 } while (0) 573 #define WRITE_VALUE_REG(index, value) \ 574 do { \ 575 ctx.icregs.icVals[(index)] = (value).asRawBits(); \ 576 ctx.icregs.icTags[(index)] = 0; \ 577 } while (0) 578 579 DECLARE_CACHEOP_CASE(ReturnFromIC); 580 DECLARE_CACHEOP_CASE(GuardToObject); 581 DECLARE_CACHEOP_CASE(GuardIsNullOrUndefined); 582 DECLARE_CACHEOP_CASE(GuardIsNull); 583 DECLARE_CACHEOP_CASE(GuardIsUndefined); 584 DECLARE_CACHEOP_CASE(GuardIsNotUninitializedLexical); 585 DECLARE_CACHEOP_CASE(GuardToBoolean); 586 DECLARE_CACHEOP_CASE(GuardToString); 587 DECLARE_CACHEOP_CASE(GuardToSymbol); 588 DECLARE_CACHEOP_CASE(GuardToBigInt); 589 DECLARE_CACHEOP_CASE(GuardIsNumber); 590 DECLARE_CACHEOP_CASE(GuardToInt32); 591 DECLARE_CACHEOP_CASE(GuardToNonGCThing); 592 DECLARE_CACHEOP_CASE(GuardBooleanToInt32); 593 DECLARE_CACHEOP_CASE(GuardToInt32Index); 594 DECLARE_CACHEOP_CASE(Int32ToIntPtr); 595 DECLARE_CACHEOP_CASE(GuardToInt32ModUint32); 596 DECLARE_CACHEOP_CASE(GuardNonDoubleType); 597 DECLARE_CACHEOP_CASE(GuardShape); 598 DECLARE_CACHEOP_CASE(GuardFuse); 599 DECLARE_CACHEOP_CASE(GuardObjectFuseProperty); 600 DECLARE_CACHEOP_CASE(GuardProto); 601 DECLARE_CACHEOP_CASE(GuardNullProto); 602 DECLARE_CACHEOP_CASE(GuardClass); 603 DECLARE_CACHEOP_CASE(GuardAnyClass); 604 DECLARE_CACHEOP_CASE(GuardGlobalGeneration); 605 DECLARE_CACHEOP_CASE(HasClassResult); 606 DECLARE_CACHEOP_CASE(GuardCompartment); 607 DECLARE_CACHEOP_CASE(GuardIsExtensible); 608 DECLARE_CACHEOP_CASE(GuardIsNativeObject); 609 DECLARE_CACHEOP_CASE(GuardIsProxy); 610 DECLARE_CACHEOP_CASE(GuardIsNotProxy); 611 DECLARE_CACHEOP_CASE(GuardIsNotArrayBufferMaybeShared); 612 DECLARE_CACHEOP_CASE(GuardIsTypedArray); 613 DECLARE_CACHEOP_CASE(GuardHasProxyHandler); 614 DECLARE_CACHEOP_CASE(GuardIsNotDOMProxy); 615 DECLARE_CACHEOP_CASE(GuardSpecificObject); 616 DECLARE_CACHEOP_CASE(GuardObjectIdentity); 617 DECLARE_CACHEOP_CASE(GuardSpecificFunction); 618 DECLARE_CACHEOP_CASE(GuardFunctionScript); 619 DECLARE_CACHEOP_CASE(GuardSpecificAtom); 620 DECLARE_CACHEOP_CASE(GuardSpecificSymbol); 621 DECLARE_CACHEOP_CASE(GuardSpecificInt32); 622 DECLARE_CACHEOP_CASE(GuardNoDenseElements); 623 DECLARE_CACHEOP_CASE(GuardStringToIndex); 624 DECLARE_CACHEOP_CASE(GuardStringToInt32); 625 DECLARE_CACHEOP_CASE(GuardStringToNumber); 626 DECLARE_CACHEOP_CASE(BooleanToNumber); 627 DECLARE_CACHEOP_CASE(GuardHasGetterSetter); 628 DECLARE_CACHEOP_CASE(GuardInt32IsNonNegative); 629 DECLARE_CACHEOP_CASE(GuardDynamicSlotIsSpecificObject); 630 DECLARE_CACHEOP_CASE(GuardDynamicSlotIsNotObject); 631 DECLARE_CACHEOP_CASE(GuardFixedSlotValue); 632 DECLARE_CACHEOP_CASE(GuardDynamicSlotValue); 633 DECLARE_CACHEOP_CASE(LoadFixedSlot); 634 DECLARE_CACHEOP_CASE(LoadDynamicSlot); 635 DECLARE_CACHEOP_CASE(GuardNoAllocationMetadataBuilder); 636 DECLARE_CACHEOP_CASE(GuardFunctionHasJitEntry); 637 DECLARE_CACHEOP_CASE(GuardFunctionHasNoJitEntry); 638 DECLARE_CACHEOP_CASE(GuardFunctionIsNonBuiltinCtor); 639 DECLARE_CACHEOP_CASE(GuardFunctionIsConstructor); 640 DECLARE_CACHEOP_CASE(GuardNotClassConstructor); 641 DECLARE_CACHEOP_CASE(GuardArrayIsPacked); 642 DECLARE_CACHEOP_CASE(GuardArgumentsObjectFlags); 643 DECLARE_CACHEOP_CASE(LoadObject); 644 DECLARE_CACHEOP_CASE(LoadProtoObject); 645 DECLARE_CACHEOP_CASE(LoadProto); 646 DECLARE_CACHEOP_CASE(LoadEnclosingEnvironment); 647 DECLARE_CACHEOP_CASE(LoadWrapperTarget); 648 DECLARE_CACHEOP_CASE(LoadValueTag); 649 DECLARE_CACHEOP_CASE(LoadArgumentFixedSlot); 650 DECLARE_CACHEOP_CASE(LoadArgumentDynamicSlot); 651 DECLARE_CACHEOP_CASE(TruncateDoubleToUInt32); 652 DECLARE_CACHEOP_CASE(MegamorphicLoadSlotResult); 653 DECLARE_CACHEOP_CASE(MegamorphicLoadSlotByValueResult); 654 DECLARE_CACHEOP_CASE(MegamorphicSetElement); 655 DECLARE_CACHEOP_CASE(StoreFixedSlot); 656 DECLARE_CACHEOP_CASE(StoreDynamicSlot); 657 DECLARE_CACHEOP_CASE(AddAndStoreFixedSlot); 658 DECLARE_CACHEOP_CASE(AddAndStoreDynamicSlot); 659 DECLARE_CACHEOP_CASE(AllocateAndStoreDynamicSlot); 660 DECLARE_CACHEOP_CASE(StoreDenseElement); 661 DECLARE_CACHEOP_CASE(StoreDenseElementHole); 662 DECLARE_CACHEOP_CASE(ArrayPush); 663 DECLARE_CACHEOP_CASE(IsObjectResult); 664 DECLARE_CACHEOP_CASE(Int32MinMax); 665 DECLARE_CACHEOP_CASE(StoreTypedArrayElement); 666 DECLARE_CACHEOP_CASE(CallInt32ToString); 667 DECLARE_CACHEOP_CASE(CallScriptedFunction); 668 DECLARE_CACHEOP_CASE(CallNativeFunction); 669 DECLARE_CACHEOP_CASE(MetaScriptedThisShape); 670 DECLARE_CACHEOP_CASE(LoadFixedSlotResult); 671 DECLARE_CACHEOP_CASE(LoadDynamicSlotResult); 672 DECLARE_CACHEOP_CASE(LoadDenseElementResult); 673 DECLARE_CACHEOP_CASE(LoadInt32ArrayLengthResult); 674 DECLARE_CACHEOP_CASE(LoadInt32ArrayLength); 675 DECLARE_CACHEOP_CASE(LoadArgumentsObjectArgResult); 676 DECLARE_CACHEOP_CASE(LinearizeForCharAccess); 677 DECLARE_CACHEOP_CASE(LoadStringCharResult); 678 DECLARE_CACHEOP_CASE(LoadStringCharCodeResult); 679 DECLARE_CACHEOP_CASE(LoadStringLengthResult); 680 DECLARE_CACHEOP_CASE(LoadObjectResult); 681 DECLARE_CACHEOP_CASE(LoadStringResult); 682 DECLARE_CACHEOP_CASE(LoadSymbolResult); 683 DECLARE_CACHEOP_CASE(LoadInt32Result); 684 DECLARE_CACHEOP_CASE(LoadDoubleResult); 685 DECLARE_CACHEOP_CASE(LoadBigIntResult); 686 DECLARE_CACHEOP_CASE(LoadBooleanResult); 687 DECLARE_CACHEOP_CASE(LoadInt32Constant); 688 DECLARE_CACHEOP_CASE(LoadConstantStringResult); 689 DECLARE_CACHEOP_CASE(Int32AddResult); 690 DECLARE_CACHEOP_CASE(Int32SubResult); 691 DECLARE_CACHEOP_CASE(Int32MulResult); 692 DECLARE_CACHEOP_CASE(Int32DivResult); 693 DECLARE_CACHEOP_CASE(Int32ModResult); 694 DECLARE_CACHEOP_CASE(Int32BitOrResult); 695 DECLARE_CACHEOP_CASE(Int32BitXorResult); 696 DECLARE_CACHEOP_CASE(Int32BitAndResult); 697 DECLARE_CACHEOP_CASE(Int32PowResult); 698 DECLARE_CACHEOP_CASE(Int32IncResult); 699 DECLARE_CACHEOP_CASE(LoadInt32TruthyResult); 700 DECLARE_CACHEOP_CASE(LoadStringTruthyResult); 701 DECLARE_CACHEOP_CASE(LoadObjectTruthyResult); 702 DECLARE_CACHEOP_CASE(LoadValueResult); 703 DECLARE_CACHEOP_CASE(LoadOperandResult); 704 DECLARE_CACHEOP_CASE(ConcatStringsResult); 705 DECLARE_CACHEOP_CASE(CompareStringResult); 706 DECLARE_CACHEOP_CASE(CompareInt32Result); 707 DECLARE_CACHEOP_CASE(CompareNullUndefinedResult); 708 DECLARE_CACHEOP_CASE(AssertPropertyLookup); 709 DECLARE_CACHEOP_CASE(GuardIsNonResizableTypedArray); 710 DECLARE_CACHEOP_CASE(GuardIndexIsNotDenseElement); 711 DECLARE_CACHEOP_CASE(LoadFixedSlotTypedResult); 712 DECLARE_CACHEOP_CASE(LoadDenseElementHoleResult); 713 DECLARE_CACHEOP_CASE(LoadDenseElementExistsResult); 714 DECLARE_CACHEOP_CASE(LoadTypedArrayElementExistsResult); 715 DECLARE_CACHEOP_CASE(LoadDenseElementHoleExistsResult); 716 DECLARE_CACHEOP_CASE(LoadTypedArrayElementResult); 717 DECLARE_CACHEOP_CASE(RegExpFlagResult); 718 DECLARE_CACHEOP_CASE(GuardNumberToIntPtrIndex); 719 DECLARE_CACHEOP_CASE(CallRegExpMatcherResult); 720 DECLARE_CACHEOP_CASE(CallRegExpSearcherResult); 721 DECLARE_CACHEOP_CASE(RegExpSearcherLastLimitResult); 722 DECLARE_CACHEOP_CASE(RegExpHasCaptureGroupsResult); 723 DECLARE_CACHEOP_CASE(RegExpBuiltinExecMatchResult); 724 DECLARE_CACHEOP_CASE(RegExpBuiltinExecTestResult); 725 DECLARE_CACHEOP_CASE(CallSubstringKernelResult); 726 DECLARE_CACHEOP_CASE(StringReplaceStringResult); 727 DECLARE_CACHEOP_CASE(StringSplitStringResult); 728 DECLARE_CACHEOP_CASE(GetFirstDollarIndexResult); 729 DECLARE_CACHEOP_CASE(StringToAtom); 730 DECLARE_CACHEOP_CASE(GuardTagNotEqual); 731 DECLARE_CACHEOP_CASE(IdToStringOrSymbol); 732 DECLARE_CACHEOP_CASE(MegamorphicStoreSlot); 733 DECLARE_CACHEOP_CASE(MegamorphicHasPropResult); 734 DECLARE_CACHEOP_CASE(ObjectToIteratorResult); 735 DECLARE_CACHEOP_CASE(ArrayJoinResult); 736 DECLARE_CACHEOP_CASE(ObjectKeysResult); 737 DECLARE_CACHEOP_CASE(PackedArrayPopResult); 738 DECLARE_CACHEOP_CASE(PackedArrayShiftResult); 739 DECLARE_CACHEOP_CASE(PackedArraySliceResult); 740 DECLARE_CACHEOP_CASE(IsArrayResult); 741 DECLARE_CACHEOP_CASE(IsPackedArrayResult); 742 DECLARE_CACHEOP_CASE(IsCallableResult); 743 DECLARE_CACHEOP_CASE(IsConstructorResult); 744 DECLARE_CACHEOP_CASE(IsCrossRealmArrayConstructorResult); 745 DECLARE_CACHEOP_CASE(IsTypedArrayResult); 746 DECLARE_CACHEOP_CASE(IsTypedArrayConstructorResult); 747 DECLARE_CACHEOP_CASE(ArrayBufferViewByteOffsetInt32Result); 748 DECLARE_CACHEOP_CASE(ArrayBufferViewByteOffsetDoubleResult); 749 DECLARE_CACHEOP_CASE(TypedArrayByteLengthInt32Result); 750 DECLARE_CACHEOP_CASE(TypedArrayByteLengthDoubleResult); 751 DECLARE_CACHEOP_CASE(NewStringIteratorResult); 752 DECLARE_CACHEOP_CASE(NewRegExpStringIteratorResult); 753 DECLARE_CACHEOP_CASE(ObjectCreateResult); 754 DECLARE_CACHEOP_CASE(NewArrayFromLengthResult); 755 DECLARE_CACHEOP_CASE(NewTypedArrayFromArrayBufferResult); 756 DECLARE_CACHEOP_CASE(NewTypedArrayFromArrayResult); 757 DECLARE_CACHEOP_CASE(NewTypedArrayFromLengthResult); 758 DECLARE_CACHEOP_CASE(StringFromCharCodeResult); 759 DECLARE_CACHEOP_CASE(StringFromCodePointResult); 760 DECLARE_CACHEOP_CASE(StringIncludesResult); 761 DECLARE_CACHEOP_CASE(StringIndexOfResult); 762 DECLARE_CACHEOP_CASE(StringLastIndexOfResult); 763 DECLARE_CACHEOP_CASE(StringStartsWithResult); 764 DECLARE_CACHEOP_CASE(StringEndsWithResult); 765 DECLARE_CACHEOP_CASE(StringToLowerCaseResult); 766 DECLARE_CACHEOP_CASE(StringToUpperCaseResult); 767 DECLARE_CACHEOP_CASE(StringTrimResult); 768 DECLARE_CACHEOP_CASE(StringTrimStartResult); 769 DECLARE_CACHEOP_CASE(StringTrimEndResult); 770 DECLARE_CACHEOP_CASE(MathAbsInt32Result); 771 DECLARE_CACHEOP_CASE(MathAbsNumberResult); 772 DECLARE_CACHEOP_CASE(MathClz32Result); 773 DECLARE_CACHEOP_CASE(MathSignInt32Result); 774 DECLARE_CACHEOP_CASE(MathSignNumberResult); 775 DECLARE_CACHEOP_CASE(MathSignNumberToInt32Result); 776 DECLARE_CACHEOP_CASE(MathImulResult); 777 DECLARE_CACHEOP_CASE(MathSqrtNumberResult); 778 DECLARE_CACHEOP_CASE(MathFRoundNumberResult); 779 DECLARE_CACHEOP_CASE(MathRandomResult); 780 DECLARE_CACHEOP_CASE(MathHypot2NumberResult); 781 DECLARE_CACHEOP_CASE(MathHypot3NumberResult); 782 DECLARE_CACHEOP_CASE(MathHypot4NumberResult); 783 DECLARE_CACHEOP_CASE(MathAtan2NumberResult); 784 DECLARE_CACHEOP_CASE(MathFloorNumberResult); 785 DECLARE_CACHEOP_CASE(MathCeilNumberResult); 786 DECLARE_CACHEOP_CASE(MathTruncNumberResult); 787 DECLARE_CACHEOP_CASE(MathCeilToInt32Result); 788 DECLARE_CACHEOP_CASE(MathFloorToInt32Result); 789 DECLARE_CACHEOP_CASE(MathTruncToInt32Result); 790 DECLARE_CACHEOP_CASE(MathRoundToInt32Result); 791 DECLARE_CACHEOP_CASE(NumberMinMax); 792 DECLARE_CACHEOP_CASE(Int32MinMaxArrayResult); 793 DECLARE_CACHEOP_CASE(NumberMinMaxArrayResult); 794 DECLARE_CACHEOP_CASE(MathFunctionNumberResult); 795 DECLARE_CACHEOP_CASE(NumberParseIntResult); 796 DECLARE_CACHEOP_CASE(DoubleParseIntResult); 797 DECLARE_CACHEOP_CASE(ObjectToStringResult); 798 DECLARE_CACHEOP_CASE(CallNativeSetter); 799 DECLARE_CACHEOP_CASE(CallSetArrayLength); 800 DECLARE_CACHEOP_CASE(CallNumberToString); 801 DECLARE_CACHEOP_CASE(Int32ToStringWithBaseResult); 802 DECLARE_CACHEOP_CASE(BooleanToString); 803 DECLARE_CACHEOP_CASE(BindFunctionResult); 804 DECLARE_CACHEOP_CASE(SpecializedBindFunctionResult); 805 DECLARE_CACHEOP_CASE(CallGetSparseElementResult); 806 DECLARE_CACHEOP_CASE(LoadArgumentsObjectLengthResult); 807 DECLARE_CACHEOP_CASE(LoadArgumentsObjectLength); 808 DECLARE_CACHEOP_CASE(LoadBoundFunctionNumArgs); 809 DECLARE_CACHEOP_CASE(LoadBoundFunctionTarget); 810 DECLARE_CACHEOP_CASE(LoadArrayBufferByteLengthInt32Result); 811 DECLARE_CACHEOP_CASE(LoadArrayBufferByteLengthDoubleResult); 812 DECLARE_CACHEOP_CASE(LinearizeForCodePointAccess); 813 DECLARE_CACHEOP_CASE(LoadArrayBufferViewLengthInt32Result); 814 DECLARE_CACHEOP_CASE(LoadArrayBufferViewLengthDoubleResult); 815 DECLARE_CACHEOP_CASE(LoadStringAtResult); 816 DECLARE_CACHEOP_CASE(LoadStringCodePointResult); 817 DECLARE_CACHEOP_CASE(CallNativeGetterResult); 818 DECLARE_CACHEOP_CASE(LoadUndefinedResult); 819 DECLARE_CACHEOP_CASE(LoadDoubleConstant); 820 DECLARE_CACHEOP_CASE(LoadBooleanConstant); 821 DECLARE_CACHEOP_CASE(LoadUndefined); 822 DECLARE_CACHEOP_CASE(LoadConstantString); 823 DECLARE_CACHEOP_CASE(LoadInstanceOfObjectResult); 824 DECLARE_CACHEOP_CASE(LoadTypeOfObjectResult); 825 DECLARE_CACHEOP_CASE(DoubleAddResult); 826 DECLARE_CACHEOP_CASE(DoubleSubResult); 827 DECLARE_CACHEOP_CASE(DoubleMulResult); 828 DECLARE_CACHEOP_CASE(DoubleDivResult); 829 DECLARE_CACHEOP_CASE(DoubleModResult); 830 DECLARE_CACHEOP_CASE(DoublePowResult); 831 DECLARE_CACHEOP_CASE(Int32LeftShiftResult); 832 DECLARE_CACHEOP_CASE(Int32RightShiftResult); 833 DECLARE_CACHEOP_CASE(Int32URightShiftResult); 834 DECLARE_CACHEOP_CASE(Int32NotResult); 835 DECLARE_CACHEOP_CASE(LoadDoubleTruthyResult); 836 DECLARE_CACHEOP_CASE(NewPlainObjectResult); 837 DECLARE_CACHEOP_CASE(NewArrayObjectResult); 838 DECLARE_CACHEOP_CASE(CompareObjectResult); 839 DECLARE_CACHEOP_CASE(CompareSymbolResult); 840 DECLARE_CACHEOP_CASE(CompareDoubleResult); 841 DECLARE_CACHEOP_CASE(IndirectTruncateInt32Result); 842 DECLARE_CACHEOP_CASE(CallScriptedSetter); 843 DECLARE_CACHEOP_CASE(CallBoundScriptedFunction); 844 DECLARE_CACHEOP_CASE(CallScriptedGetterResult); 845 846 // Define the computed-goto table regardless of dispatch strategy so 847 // we don't get unused-label errors. (We need some of the labels 848 // even without this for the predict-next mechanism, so we can't 849 // conditionally elide labels either.) 850 static const void* const addresses[long(CacheOp::NumOpcodes)] = { 851 #define OP(name, ...) &&cacheop_##name, 852 CACHE_IR_OPS(OP) 853 #undef OP 854 }; 855 (void)addresses; 856 857 #define CACHEOP_TRACE(name) \ 858 TRACE_PRINTF("cacheop (frame %p stub %p): " #name "\n", ctx.frame, cstub); 859 860 #define FAIL_IC() goto next_ic; 861 862 // We set a fixed bound on the number of icVals which is smaller than what IC 863 // generators may use. As a result we can't evaluate an IC if it defines too 864 // many values. Note that we don't need to check this when reading from icVals 865 // because we should have bailed out before the earlier write which defined the 866 // same value. Similarly, we don't need to check writes to locations which we've 867 // just read from. 868 #define BOUNDSCHECK(resultId) \ 869 if (resultId.id() >= ICRegs::kMaxICVals) FAIL_IC(); 870 871 #define PREDICT_NEXT(name) \ 872 if (cacheIRReader.peekOp() == CacheOp::name) { \ 873 cacheIRReader.readOp(); \ 874 cacheop = CacheOp::name; \ 875 goto cacheop_##name; \ 876 } 877 878 #define PREDICT_RETURN() \ 879 if (cacheIRReader.peekOp() == CacheOp::ReturnFromIC) { \ 880 TRACE_PRINTF("stub successful, predicted return\n"); \ 881 return retValue; \ 882 } 883 884 ICCacheIRStub* cstub = stub->toCacheIRStub(); 885 const CacheIRStubInfo* stubInfo = cstub->stubInfo(); 886 CacheIRReader cacheIRReader(stubInfo); 887 uint64_t retValue = 0; 888 CacheOp cacheop; 889 890 WRITE_VALUE_REG(0, Value::fromRawBits(arg0)); 891 WRITE_VALUE_REG(1, Value::fromRawBits(arg1)); 892 WRITE_VALUE_REG(2, Value::fromRawBits(ctx.arg2)); 893 894 DISPATCH_CACHEOP(); 895 896 #ifndef ENABLE_COMPUTED_GOTO_DISPATCH 897 dispatch: 898 switch (cacheop) 899 #endif 900 { 901 902 CACHEOP_CASE(ReturnFromIC) { 903 TRACE_PRINTF("stub successful!\n"); 904 return retValue; 905 } 906 907 CACHEOP_CASE(GuardToObject) { 908 ValOperandId inputId = cacheIRReader.valOperandId(); 909 Value v = READ_VALUE_REG(inputId.id()); 910 TRACE_PRINTF("GuardToObject: icVal %" PRIx64 "\n", 911 READ_REG(inputId.id())); 912 if (!v.isObject()) { 913 FAIL_IC(); 914 } 915 WRITE_REG(inputId.id(), reinterpret_cast<uint64_t>(&v.toObject()), 916 OBJECT); 917 PREDICT_NEXT(GuardShape); 918 PREDICT_NEXT(GuardSpecificFunction); 919 DISPATCH_CACHEOP(); 920 } 921 922 CACHEOP_CASE(GuardIsNullOrUndefined) { 923 ValOperandId inputId = cacheIRReader.valOperandId(); 924 Value v = READ_VALUE_REG(inputId.id()); 925 if (!v.isNullOrUndefined()) { 926 FAIL_IC(); 927 } 928 DISPATCH_CACHEOP(); 929 } 930 931 CACHEOP_CASE(GuardIsNull) { 932 ValOperandId inputId = cacheIRReader.valOperandId(); 933 Value v = READ_VALUE_REG(inputId.id()); 934 if (!v.isNull()) { 935 FAIL_IC(); 936 } 937 DISPATCH_CACHEOP(); 938 } 939 940 CACHEOP_CASE(GuardIsUndefined) { 941 ValOperandId inputId = cacheIRReader.valOperandId(); 942 Value v = READ_VALUE_REG(inputId.id()); 943 if (!v.isUndefined()) { 944 FAIL_IC(); 945 } 946 DISPATCH_CACHEOP(); 947 } 948 949 CACHEOP_CASE(GuardIsNotUninitializedLexical) { 950 ValOperandId valId = cacheIRReader.valOperandId(); 951 Value val = READ_VALUE_REG(valId.id()); 952 if (val == MagicValue(JS_UNINITIALIZED_LEXICAL)) { 953 FAIL_IC(); 954 } 955 DISPATCH_CACHEOP(); 956 } 957 958 CACHEOP_CASE(GuardToBoolean) { 959 ValOperandId inputId = cacheIRReader.valOperandId(); 960 Value v = READ_VALUE_REG(inputId.id()); 961 if (!v.isBoolean()) { 962 FAIL_IC(); 963 } 964 WRITE_REG(inputId.id(), v.toBoolean() ? 1 : 0, BOOLEAN); 965 DISPATCH_CACHEOP(); 966 } 967 968 CACHEOP_CASE(GuardToString) { 969 ValOperandId inputId = cacheIRReader.valOperandId(); 970 Value v = READ_VALUE_REG(inputId.id()); 971 if (!v.isString()) { 972 FAIL_IC(); 973 } 974 WRITE_REG(inputId.id(), reinterpret_cast<uint64_t>(v.toString()), 975 STRING); 976 PREDICT_NEXT(GuardToString); 977 DISPATCH_CACHEOP(); 978 } 979 980 CACHEOP_CASE(GuardToSymbol) { 981 ValOperandId inputId = cacheIRReader.valOperandId(); 982 Value v = READ_VALUE_REG(inputId.id()); 983 if (!v.isSymbol()) { 984 FAIL_IC(); 985 } 986 WRITE_REG(inputId.id(), reinterpret_cast<uint64_t>(v.toSymbol()), 987 SYMBOL); 988 PREDICT_NEXT(GuardSpecificSymbol); 989 DISPATCH_CACHEOP(); 990 } 991 992 CACHEOP_CASE(GuardToBigInt) { 993 ValOperandId inputId = cacheIRReader.valOperandId(); 994 Value v = READ_VALUE_REG(inputId.id()); 995 if (!v.isBigInt()) { 996 FAIL_IC(); 997 } 998 WRITE_REG(inputId.id(), reinterpret_cast<uint64_t>(v.toBigInt()), 999 BIGINT); 1000 DISPATCH_CACHEOP(); 1001 } 1002 1003 CACHEOP_CASE(GuardIsNumber) { 1004 ValOperandId inputId = cacheIRReader.valOperandId(); 1005 Value v = READ_VALUE_REG(inputId.id()); 1006 if (!v.isNumber()) { 1007 FAIL_IC(); 1008 } 1009 DISPATCH_CACHEOP(); 1010 } 1011 1012 CACHEOP_CASE(GuardToInt32) { 1013 ValOperandId inputId = cacheIRReader.valOperandId(); 1014 Value v = READ_VALUE_REG(inputId.id()); 1015 TRACE_PRINTF("GuardToInt32 (%d): icVal %" PRIx64 "\n", inputId.id(), 1016 READ_REG(inputId.id())); 1017 if (!v.isInt32()) { 1018 FAIL_IC(); 1019 } 1020 // N.B.: we don't need to unbox because the low 32 bits are 1021 // already the int32 itself, and we are careful when using 1022 // `Int32Operand`s to only use those bits. 1023 1024 PREDICT_NEXT(GuardToInt32); 1025 DISPATCH_CACHEOP(); 1026 } 1027 1028 CACHEOP_CASE(GuardToNonGCThing) { 1029 ValOperandId inputId = cacheIRReader.valOperandId(); 1030 Value input = READ_VALUE_REG(inputId.id()); 1031 if (input.isGCThing()) { 1032 FAIL_IC(); 1033 } 1034 DISPATCH_CACHEOP(); 1035 } 1036 1037 CACHEOP_CASE(GuardBooleanToInt32) { 1038 ValOperandId inputId = cacheIRReader.valOperandId(); 1039 Int32OperandId resultId = cacheIRReader.int32OperandId(); 1040 BOUNDSCHECK(resultId); 1041 Value v = READ_VALUE_REG(inputId.id()); 1042 if (!v.isBoolean()) { 1043 FAIL_IC(); 1044 } 1045 WRITE_REG(resultId.id(), v.toBoolean() ? 1 : 0, INT32); 1046 DISPATCH_CACHEOP(); 1047 } 1048 1049 CACHEOP_CASE(GuardToInt32Index) { 1050 ValOperandId inputId = cacheIRReader.valOperandId(); 1051 Int32OperandId resultId = cacheIRReader.int32OperandId(); 1052 BOUNDSCHECK(resultId); 1053 Value val = READ_VALUE_REG(inputId.id()); 1054 if (val.isInt32()) { 1055 WRITE_REG(resultId.id(), val.toInt32(), INT32); 1056 DISPATCH_CACHEOP(); 1057 } else if (val.isDouble()) { 1058 double doubleVal = val.toDouble(); 1059 if (int32_t(doubleVal) == doubleVal) { 1060 WRITE_REG(resultId.id(), int32_t(doubleVal), INT32); 1061 DISPATCH_CACHEOP(); 1062 } 1063 } 1064 FAIL_IC(); 1065 } 1066 1067 CACHEOP_CASE(Int32ToIntPtr) { 1068 Int32OperandId inputId = cacheIRReader.int32OperandId(); 1069 IntPtrOperandId resultId = cacheIRReader.intPtrOperandId(); 1070 BOUNDSCHECK(resultId); 1071 int32_t input = int32_t(READ_REG(inputId.id())); 1072 // Note that this must sign-extend to pointer width: 1073 WRITE_REG(resultId.id(), intptr_t(input), OBJECT); 1074 DISPATCH_CACHEOP(); 1075 } 1076 1077 CACHEOP_CASE(GuardToInt32ModUint32) { 1078 ValOperandId inputId = cacheIRReader.valOperandId(); 1079 Int32OperandId resultId = cacheIRReader.int32OperandId(); 1080 BOUNDSCHECK(resultId); 1081 Value input = READ_VALUE_REG(inputId.id()); 1082 if (input.isInt32()) { 1083 WRITE_REG(resultId.id(), input.toInt32(), INT32); 1084 DISPATCH_CACHEOP(); 1085 } else if (input.isDouble()) { 1086 double doubleVal = input.toDouble(); 1087 // Accept any double that fits in an int64_t but truncate the top 32 1088 // bits. 1089 if (doubleVal >= double(INT64_MIN) && 1090 doubleVal <= double(INT64_MAX)) { 1091 WRITE_REG(resultId.id(), int64_t(doubleVal), INT32); 1092 DISPATCH_CACHEOP(); 1093 } 1094 } 1095 FAIL_IC(); 1096 } 1097 1098 CACHEOP_CASE(GuardNonDoubleType) { 1099 ValOperandId inputId = cacheIRReader.valOperandId(); 1100 ValueType type = cacheIRReader.valueType(); 1101 Value val = READ_VALUE_REG(inputId.id()); 1102 switch (type) { 1103 case ValueType::String: 1104 if (!val.isString()) { 1105 FAIL_IC(); 1106 } 1107 break; 1108 case ValueType::Symbol: 1109 if (!val.isSymbol()) { 1110 FAIL_IC(); 1111 } 1112 break; 1113 case ValueType::BigInt: 1114 if (!val.isBigInt()) { 1115 FAIL_IC(); 1116 } 1117 break; 1118 case ValueType::Int32: 1119 if (!val.isInt32()) { 1120 FAIL_IC(); 1121 } 1122 break; 1123 case ValueType::Boolean: 1124 if (!val.isBoolean()) { 1125 FAIL_IC(); 1126 } 1127 break; 1128 case ValueType::Undefined: 1129 if (!val.isUndefined()) { 1130 FAIL_IC(); 1131 } 1132 break; 1133 case ValueType::Null: 1134 if (!val.isNull()) { 1135 FAIL_IC(); 1136 } 1137 break; 1138 default: 1139 MOZ_CRASH("Unexpected type"); 1140 } 1141 DISPATCH_CACHEOP(); 1142 } 1143 1144 CACHEOP_CASE(GuardShape) { 1145 ObjOperandId objId = cacheIRReader.objOperandId(); 1146 uint32_t shapeOffset = cacheIRReader.stubOffset(); 1147 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1148 uintptr_t expectedShape = stubInfo->getStubRawWord(cstub, shapeOffset); 1149 if (reinterpret_cast<uintptr_t>(obj->shape()) != expectedShape) { 1150 FAIL_IC(); 1151 } 1152 DISPATCH_CACHEOP(); 1153 } 1154 1155 CACHEOP_CASE(GuardFuse) { 1156 RealmFuses::FuseIndex fuseIndex = cacheIRReader.realmFuseIndex(); 1157 if (!ctx.frameMgr.cxForLocalUseOnly() 1158 ->realm() 1159 ->realmFuses.getFuseByIndex(fuseIndex) 1160 ->intact()) { 1161 FAIL_IC(); 1162 } 1163 DISPATCH_CACHEOP(); 1164 } 1165 1166 CACHEOP_CASE(GuardObjectFuseProperty) { 1167 auto args = cacheIRReader.argsForGuardObjectFuseProperty(); 1168 #ifdef DEBUG 1169 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(args.objId.id())); 1170 uintptr_t objFuseOwner = 1171 stubInfo->getStubRawWord(cstub, args.objFuseOwnerOffset); 1172 MOZ_ASSERT(uintptr_t(obj) == objFuseOwner); 1173 #endif 1174 auto* objFuse = reinterpret_cast<ObjectFuse*>( 1175 stubInfo->getStubRawWord(cstub, args.objFuseOffset)); 1176 uint32_t generation = 1177 stubInfo->getStubRawInt32(cstub, args.expectedGenerationOffset); 1178 uint32_t propIndex = 1179 stubInfo->getStubRawInt32(cstub, args.propIndexOffset); 1180 uint32_t propMask = 1181 stubInfo->getStubRawInt32(cstub, args.propMaskOffset); 1182 uint32_t propSlot = 1183 ObjectFuse::propertySlotFromIndexAndMask(propIndex, propMask); 1184 if (!objFuse->checkPropertyIsConstant(generation, propSlot)) { 1185 FAIL_IC(); 1186 } 1187 DISPATCH_CACHEOP(); 1188 } 1189 1190 CACHEOP_CASE(GuardProto) { 1191 ObjOperandId objId = cacheIRReader.objOperandId(); 1192 uint32_t protoOffset = cacheIRReader.stubOffset(); 1193 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1194 JSObject* proto = reinterpret_cast<JSObject*>( 1195 stubInfo->getStubRawWord(cstub, protoOffset)); 1196 if (obj->staticPrototype() != proto) { 1197 FAIL_IC(); 1198 } 1199 PREDICT_NEXT(LoadProto); 1200 DISPATCH_CACHEOP(); 1201 } 1202 1203 CACHEOP_CASE(GuardNullProto) { 1204 ObjOperandId objId = cacheIRReader.objOperandId(); 1205 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1206 if (obj->taggedProto().raw()) { 1207 FAIL_IC(); 1208 } 1209 DISPATCH_CACHEOP(); 1210 } 1211 1212 CACHEOP_CASE(GuardClass) { 1213 ObjOperandId objId = cacheIRReader.objOperandId(); 1214 GuardClassKind kind = cacheIRReader.guardClassKind(); 1215 JSObject* object = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1216 switch (kind) { 1217 case GuardClassKind::Array: 1218 case GuardClassKind::PlainObject: 1219 case GuardClassKind::FixedLengthArrayBuffer: 1220 case GuardClassKind::ImmutableArrayBuffer: 1221 case GuardClassKind::ResizableArrayBuffer: 1222 case GuardClassKind::FixedLengthSharedArrayBuffer: 1223 case GuardClassKind::GrowableSharedArrayBuffer: 1224 case GuardClassKind::FixedLengthDataView: 1225 case GuardClassKind::ImmutableDataView: 1226 case GuardClassKind::ResizableDataView: 1227 case GuardClassKind::MappedArguments: 1228 case GuardClassKind::UnmappedArguments: 1229 case GuardClassKind::Set: 1230 case GuardClassKind::Map: 1231 case GuardClassKind::BoundFunction: 1232 case GuardClassKind::Date: 1233 case GuardClassKind::WeakMap: 1234 case GuardClassKind::WeakSet: 1235 if (object->getClass() != jit::ClassFor(kind)) { 1236 FAIL_IC(); 1237 } 1238 break; 1239 case GuardClassKind::WindowProxy: 1240 if (object->getClass() != ctx.frameMgr.cxForLocalUseOnly() 1241 ->runtime() 1242 ->maybeWindowProxyClass()) { 1243 FAIL_IC(); 1244 } 1245 break; 1246 case GuardClassKind::JSFunction: 1247 if (!object->is<JSFunction>()) { 1248 FAIL_IC(); 1249 } 1250 break; 1251 } 1252 DISPATCH_CACHEOP(); 1253 } 1254 1255 CACHEOP_CASE(GuardAnyClass) { 1256 ObjOperandId objId = cacheIRReader.objOperandId(); 1257 uint32_t claspOffset = cacheIRReader.stubOffset(); 1258 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1259 JSClass* clasp = reinterpret_cast<JSClass*>( 1260 stubInfo->getStubRawWord(cstub, claspOffset)); 1261 if (obj->getClass() != clasp) { 1262 FAIL_IC(); 1263 } 1264 DISPATCH_CACHEOP(); 1265 } 1266 1267 CACHEOP_CASE(GuardGlobalGeneration) { 1268 uint32_t expectedOffset = cacheIRReader.stubOffset(); 1269 uint32_t generationAddrOffset = cacheIRReader.stubOffset(); 1270 uint32_t expected = stubInfo->getStubRawInt32(cstub, expectedOffset); 1271 uint32_t* generationAddr = reinterpret_cast<uint32_t*>( 1272 stubInfo->getStubRawWord(cstub, generationAddrOffset)); 1273 if (*generationAddr != expected) { 1274 FAIL_IC(); 1275 } 1276 DISPATCH_CACHEOP(); 1277 } 1278 1279 CACHEOP_CASE(HasClassResult) { 1280 ObjOperandId objId = cacheIRReader.objOperandId(); 1281 uint32_t claspOffset = cacheIRReader.stubOffset(); 1282 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1283 JSClass* clasp = reinterpret_cast<JSClass*>( 1284 stubInfo->getStubRawWord(cstub, claspOffset)); 1285 retValue = BooleanValue(obj->getClass() == clasp).asRawBits(); 1286 PREDICT_RETURN(); 1287 DISPATCH_CACHEOP(); 1288 } 1289 1290 CACHEOP_CASE(GuardCompartment) { 1291 ObjOperandId objId = cacheIRReader.objOperandId(); 1292 uint32_t globalOffset = cacheIRReader.stubOffset(); 1293 uint32_t compartmentOffset = cacheIRReader.stubOffset(); 1294 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1295 JSObject* global = reinterpret_cast<JSObject*>( 1296 stubInfo->getStubRawWord(cstub, globalOffset)); 1297 JS::Compartment* compartment = reinterpret_cast<JS::Compartment*>( 1298 stubInfo->getStubRawWord(cstub, compartmentOffset)); 1299 if (IsDeadProxyObject(global)) { 1300 FAIL_IC(); 1301 } 1302 if (obj->compartment() != compartment) { 1303 FAIL_IC(); 1304 } 1305 DISPATCH_CACHEOP(); 1306 } 1307 1308 CACHEOP_CASE(GuardIsExtensible) { 1309 ObjOperandId objId = cacheIRReader.objOperandId(); 1310 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1311 if (obj->nonProxyIsExtensible()) { 1312 FAIL_IC(); 1313 } 1314 DISPATCH_CACHEOP(); 1315 } 1316 1317 CACHEOP_CASE(GuardIsNativeObject) { 1318 ObjOperandId objId = cacheIRReader.objOperandId(); 1319 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1320 if (!obj->is<NativeObject>()) { 1321 FAIL_IC(); 1322 } 1323 DISPATCH_CACHEOP(); 1324 } 1325 1326 CACHEOP_CASE(GuardIsProxy) { 1327 ObjOperandId objId = cacheIRReader.objOperandId(); 1328 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1329 if (!obj->is<ProxyObject>()) { 1330 FAIL_IC(); 1331 } 1332 DISPATCH_CACHEOP(); 1333 } 1334 1335 CACHEOP_CASE(GuardIsNotProxy) { 1336 ObjOperandId objId = cacheIRReader.objOperandId(); 1337 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1338 if (obj->is<ProxyObject>()) { 1339 FAIL_IC(); 1340 } 1341 DISPATCH_CACHEOP(); 1342 } 1343 1344 CACHEOP_CASE(GuardIsNotArrayBufferMaybeShared) { 1345 ObjOperandId objId = cacheIRReader.objOperandId(); 1346 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1347 const JSClass* clasp = obj->getClass(); 1348 if (clasp == &FixedLengthArrayBufferObject::class_ || 1349 clasp == &FixedLengthSharedArrayBufferObject::class_ || 1350 clasp == &ResizableArrayBufferObject::class_ || 1351 clasp == &GrowableSharedArrayBufferObject::class_) { 1352 FAIL_IC(); 1353 } 1354 DISPATCH_CACHEOP(); 1355 } 1356 1357 CACHEOP_CASE(GuardIsTypedArray) { 1358 ObjOperandId objId = cacheIRReader.objOperandId(); 1359 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1360 if (!IsTypedArrayClass(obj->getClass())) { 1361 FAIL_IC(); 1362 } 1363 DISPATCH_CACHEOP(); 1364 } 1365 1366 CACHEOP_CASE(GuardIsNonResizableTypedArray) { 1367 ObjOperandId objId = cacheIRReader.objOperandId(); 1368 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1369 if (!IsFixedLengthTypedArrayClass(obj->getClass()) && 1370 !IsImmutableTypedArrayClass(obj->getClass())) { 1371 FAIL_IC(); 1372 } 1373 DISPATCH_CACHEOP(); 1374 } 1375 1376 CACHEOP_CASE(GuardHasProxyHandler) { 1377 ObjOperandId objId = cacheIRReader.objOperandId(); 1378 uint32_t handlerOffset = cacheIRReader.stubOffset(); 1379 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1380 BaseProxyHandler* handler = reinterpret_cast<BaseProxyHandler*>( 1381 stubInfo->getStubRawWord(cstub, handlerOffset)); 1382 if (obj->as<ProxyObject>().handler() != handler) { 1383 FAIL_IC(); 1384 } 1385 DISPATCH_CACHEOP(); 1386 } 1387 1388 CACHEOP_CASE(GuardIsNotDOMProxy) { 1389 ObjOperandId objId = cacheIRReader.objOperandId(); 1390 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1391 if (obj->as<ProxyObject>().handler()->family() == 1392 GetDOMProxyHandlerFamily()) { 1393 FAIL_IC(); 1394 } 1395 DISPATCH_CACHEOP(); 1396 } 1397 1398 CACHEOP_CASE(GuardSpecificObject) { 1399 ObjOperandId objId = cacheIRReader.objOperandId(); 1400 uint32_t expectedOffset = cacheIRReader.stubOffset(); 1401 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1402 JSObject* expected = reinterpret_cast<JSObject*>( 1403 stubInfo->getStubRawWord(cstub, expectedOffset)); 1404 if (obj != expected) { 1405 FAIL_IC(); 1406 } 1407 DISPATCH_CACHEOP(); 1408 } 1409 1410 CACHEOP_CASE(GuardObjectIdentity) { 1411 ObjOperandId obj1Id = cacheIRReader.objOperandId(); 1412 ObjOperandId obj2Id = cacheIRReader.objOperandId(); 1413 JSObject* obj1 = reinterpret_cast<JSObject*>(READ_REG(obj1Id.id())); 1414 JSObject* obj2 = reinterpret_cast<JSObject*>(READ_REG(obj2Id.id())); 1415 if (obj1 != obj2) { 1416 FAIL_IC(); 1417 } 1418 DISPATCH_CACHEOP(); 1419 } 1420 1421 CACHEOP_CASE(GuardSpecificFunction) { 1422 auto args = cacheIRReader.argsForGuardSpecificFunction(); 1423 uintptr_t expected = 1424 stubInfo->getStubRawWord(cstub, args.expectedOffset); 1425 if (expected != READ_REG(args.funId.id())) { 1426 FAIL_IC(); 1427 } 1428 PREDICT_NEXT(LoadArgumentFixedSlot); 1429 DISPATCH_CACHEOP(); 1430 } 1431 1432 CACHEOP_CASE(GuardFunctionScript) { 1433 auto args = cacheIRReader.argsForGuardFunctionScript(); 1434 auto* fun = reinterpret_cast<JSFunction*>(READ_REG(args.objId.id())); 1435 BaseScript* expected = reinterpret_cast<BaseScript*>( 1436 stubInfo->getStubRawWord(cstub, args.expectedOffset)); 1437 1438 if (!fun->hasBaseScript() || fun->baseScript() != expected) { 1439 FAIL_IC(); 1440 } 1441 1442 PREDICT_NEXT(CallScriptedFunction); 1443 DISPATCH_CACHEOP(); 1444 } 1445 1446 CACHEOP_CASE(GuardSpecificAtom) { 1447 StringOperandId strId = cacheIRReader.stringOperandId(); 1448 uint32_t expectedOffset = cacheIRReader.stubOffset(); 1449 uintptr_t expected = stubInfo->getStubRawWord(cstub, expectedOffset); 1450 if (expected != READ_REG(strId.id())) { 1451 // TODO: BaselineCacheIRCompiler also checks for equal strings 1452 FAIL_IC(); 1453 } 1454 DISPATCH_CACHEOP(); 1455 } 1456 1457 CACHEOP_CASE(GuardSpecificSymbol) { 1458 SymbolOperandId symId = cacheIRReader.symbolOperandId(); 1459 uint32_t expectedOffset = cacheIRReader.stubOffset(); 1460 uintptr_t expected = stubInfo->getStubRawWord(cstub, expectedOffset); 1461 if (expected != READ_REG(symId.id())) { 1462 FAIL_IC(); 1463 } 1464 DISPATCH_CACHEOP(); 1465 } 1466 1467 CACHEOP_CASE(GuardSpecificInt32) { 1468 Int32OperandId numId = cacheIRReader.int32OperandId(); 1469 int32_t expected = cacheIRReader.int32Immediate(); 1470 if (expected != int32_t(READ_REG(numId.id()))) { 1471 FAIL_IC(); 1472 } 1473 DISPATCH_CACHEOP(); 1474 } 1475 1476 CACHEOP_CASE(GuardNoDenseElements) { 1477 ObjOperandId objId = cacheIRReader.objOperandId(); 1478 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1479 if (obj->as<NativeObject>().getDenseInitializedLength() != 0) { 1480 FAIL_IC(); 1481 } 1482 DISPATCH_CACHEOP(); 1483 } 1484 1485 CACHEOP_CASE(GuardStringToIndex) { 1486 StringOperandId strId = cacheIRReader.stringOperandId(); 1487 Int32OperandId resultId = cacheIRReader.int32OperandId(); 1488 BOUNDSCHECK(resultId); 1489 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 1490 int32_t result; 1491 if (str->hasIndexValue()) { 1492 uint32_t index = str->getIndexValue(); 1493 MOZ_ASSERT(index <= INT32_MAX); 1494 result = index; 1495 } else { 1496 result = GetIndexFromString(str); 1497 if (result < 0) { 1498 FAIL_IC(); 1499 } 1500 } 1501 WRITE_REG(resultId.id(), result, INT32); 1502 DISPATCH_CACHEOP(); 1503 } 1504 1505 CACHEOP_CASE(GuardStringToInt32) { 1506 StringOperandId strId = cacheIRReader.stringOperandId(); 1507 Int32OperandId resultId = cacheIRReader.int32OperandId(); 1508 BOUNDSCHECK(resultId); 1509 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 1510 int32_t result; 1511 // Use indexed value as fast path if possible. 1512 if (str->hasIndexValue()) { 1513 uint32_t index = str->getIndexValue(); 1514 MOZ_ASSERT(index <= INT32_MAX); 1515 result = index; 1516 } else { 1517 if (!GetInt32FromStringPure(ctx.frameMgr.cxForLocalUseOnly(), str, 1518 &result)) { 1519 FAIL_IC(); 1520 } 1521 } 1522 WRITE_REG(resultId.id(), result, INT32); 1523 DISPATCH_CACHEOP(); 1524 } 1525 1526 CACHEOP_CASE(GuardStringToNumber) { 1527 StringOperandId strId = cacheIRReader.stringOperandId(); 1528 NumberOperandId resultId = cacheIRReader.numberOperandId(); 1529 BOUNDSCHECK(resultId); 1530 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 1531 Value result; 1532 // Use indexed value as fast path if possible. 1533 if (str->hasIndexValue()) { 1534 uint32_t index = str->getIndexValue(); 1535 MOZ_ASSERT(index <= INT32_MAX); 1536 result = Int32Value(index); 1537 } else { 1538 double value; 1539 if (!StringToNumberPure(ctx.frameMgr.cxForLocalUseOnly(), str, 1540 &value)) { 1541 FAIL_IC(); 1542 } 1543 result = DoubleValue(value); 1544 } 1545 WRITE_VALUE_REG(resultId.id(), result); 1546 DISPATCH_CACHEOP(); 1547 } 1548 1549 CACHEOP_CASE(BooleanToNumber) { 1550 BooleanOperandId booleanId = cacheIRReader.booleanOperandId(); 1551 NumberOperandId resultId = cacheIRReader.numberOperandId(); 1552 BOUNDSCHECK(resultId); 1553 uint64_t boolean = READ_REG(booleanId.id()); 1554 MOZ_ASSERT((boolean & ~1) == 0); 1555 WRITE_VALUE_REG(resultId.id(), Int32Value(boolean)); 1556 DISPATCH_CACHEOP(); 1557 } 1558 1559 CACHEOP_CASE(GuardHasGetterSetter) { 1560 ObjOperandId objId = cacheIRReader.objOperandId(); 1561 uint32_t idOffset = cacheIRReader.stubOffset(); 1562 uint32_t getterSetterOffset = cacheIRReader.stubOffset(); 1563 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1564 jsid id = jsid::fromRawBits(stubInfo->getStubRawWord(cstub, idOffset)); 1565 Value getterSetterVal = Value::fromRawBits( 1566 stubInfo->getStubRawInt64(cstub, getterSetterOffset)); 1567 auto* getterSetter = getterSetterVal.toGCThing()->as<GetterSetter>(); 1568 if (!ObjectHasGetterSetterPure(ctx.frameMgr.cxForLocalUseOnly(), obj, 1569 id, getterSetter)) { 1570 FAIL_IC(); 1571 } 1572 DISPATCH_CACHEOP(); 1573 } 1574 1575 CACHEOP_CASE(GuardInt32IsNonNegative) { 1576 Int32OperandId indexId = cacheIRReader.int32OperandId(); 1577 int32_t index = int32_t(READ_REG(indexId.id())); 1578 if (index < 0) { 1579 FAIL_IC(); 1580 } 1581 DISPATCH_CACHEOP(); 1582 } 1583 1584 CACHEOP_CASE(GuardDynamicSlotIsSpecificObject) { 1585 ObjOperandId objId = cacheIRReader.objOperandId(); 1586 ObjOperandId expectedId = cacheIRReader.objOperandId(); 1587 uint32_t slotOffset = cacheIRReader.stubOffset(); 1588 JSObject* expected = 1589 reinterpret_cast<JSObject*>(READ_REG(expectedId.id())); 1590 uintptr_t slot = stubInfo->getStubRawInt32(cstub, slotOffset); 1591 NativeObject* nobj = 1592 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 1593 HeapSlot* slots = nobj->getSlotsUnchecked(); 1594 // Note that unlike similar opcodes, GuardDynamicSlotIsSpecificObject 1595 // takes a slot index rather than a byte offset. 1596 Value actual = slots[slot]; 1597 if (actual != ObjectValue(*expected)) { 1598 FAIL_IC(); 1599 } 1600 DISPATCH_CACHEOP(); 1601 } 1602 1603 CACHEOP_CASE(GuardDynamicSlotIsNotObject) { 1604 ObjOperandId objId = cacheIRReader.objOperandId(); 1605 uint32_t slotOffset = cacheIRReader.stubOffset(); 1606 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1607 uint32_t slot = stubInfo->getStubRawInt32(cstub, slotOffset); 1608 NativeObject* nobj = &obj->as<NativeObject>(); 1609 HeapSlot* slots = nobj->getSlotsUnchecked(); 1610 // Note that unlike similar opcodes, GuardDynamicSlotIsNotObject takes a 1611 // slot index rather than a byte offset. 1612 Value actual = slots[slot]; 1613 if (actual.isObject()) { 1614 FAIL_IC(); 1615 } 1616 DISPATCH_CACHEOP(); 1617 } 1618 1619 CACHEOP_CASE(GuardFixedSlotValue) { 1620 ObjOperandId objId = cacheIRReader.objOperandId(); 1621 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1622 uint32_t valOffset = cacheIRReader.stubOffset(); 1623 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1624 uint32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1625 Value val = 1626 Value::fromRawBits(stubInfo->getStubRawInt64(cstub, valOffset)); 1627 GCPtr<Value>* slot = reinterpret_cast<GCPtr<Value>*>( 1628 reinterpret_cast<uintptr_t>(obj) + offset); 1629 Value actual = slot->get(); 1630 if (actual != val) { 1631 FAIL_IC(); 1632 } 1633 DISPATCH_CACHEOP(); 1634 } 1635 1636 CACHEOP_CASE(GuardDynamicSlotValue) { 1637 ObjOperandId objId = cacheIRReader.objOperandId(); 1638 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1639 uint32_t valOffset = cacheIRReader.stubOffset(); 1640 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1641 uint32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1642 Value val = 1643 Value::fromRawBits(stubInfo->getStubRawInt64(cstub, valOffset)); 1644 NativeObject* nobj = &obj->as<NativeObject>(); 1645 HeapSlot* slots = nobj->getSlotsUnchecked(); 1646 Value actual = slots[offset / sizeof(Value)]; 1647 if (actual != val) { 1648 FAIL_IC(); 1649 } 1650 DISPATCH_CACHEOP(); 1651 } 1652 1653 CACHEOP_CASE(LoadFixedSlot) { 1654 ValOperandId resultId = cacheIRReader.valOperandId(); 1655 BOUNDSCHECK(resultId); 1656 ObjOperandId objId = cacheIRReader.objOperandId(); 1657 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1658 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1659 uint32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1660 GCPtr<Value>* slot = reinterpret_cast<GCPtr<Value>*>( 1661 reinterpret_cast<uintptr_t>(obj) + offset); 1662 Value actual = slot->get(); 1663 WRITE_VALUE_REG(resultId.id(), actual); 1664 DISPATCH_CACHEOP(); 1665 } 1666 1667 CACHEOP_CASE(LoadDynamicSlot) { 1668 ValOperandId resultId = cacheIRReader.valOperandId(); 1669 BOUNDSCHECK(resultId); 1670 ObjOperandId objId = cacheIRReader.objOperandId(); 1671 uint32_t slotOffset = cacheIRReader.stubOffset(); 1672 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1673 uint32_t slot = stubInfo->getStubRawInt32(cstub, slotOffset); 1674 NativeObject* nobj = &obj->as<NativeObject>(); 1675 HeapSlot* slots = nobj->getSlotsUnchecked(); 1676 // Note that unlike similar opcodes, LoadDynamicSlot takes a slot index 1677 // rather than a byte offset. 1678 Value actual = slots[slot]; 1679 WRITE_VALUE_REG(resultId.id(), actual); 1680 DISPATCH_CACHEOP(); 1681 } 1682 1683 CACHEOP_CASE(GuardNoAllocationMetadataBuilder) { 1684 uint32_t builderAddrOffset = cacheIRReader.stubOffset(); 1685 uintptr_t builderAddr = 1686 stubInfo->getStubRawWord(cstub, builderAddrOffset); 1687 if (*reinterpret_cast<uintptr_t*>(builderAddr) != 0) { 1688 FAIL_IC(); 1689 } 1690 DISPATCH_CACHEOP(); 1691 } 1692 1693 CACHEOP_CASE(GuardFunctionHasJitEntry) { 1694 ObjOperandId funId = cacheIRReader.objOperandId(); 1695 JSObject* fun = reinterpret_cast<JSObject*>(READ_REG(funId.id())); 1696 uint16_t flags = FunctionFlags::HasJitEntryFlags(); 1697 if (!fun->as<JSFunction>().flags().hasFlags(flags)) { 1698 FAIL_IC(); 1699 } 1700 DISPATCH_CACHEOP(); 1701 } 1702 1703 CACHEOP_CASE(GuardFunctionHasNoJitEntry) { 1704 ObjOperandId funId = cacheIRReader.objOperandId(); 1705 JSObject* fun = reinterpret_cast<JSObject*>(READ_REG(funId.id())); 1706 uint16_t flags = FunctionFlags::HasJitEntryFlags(); 1707 if (fun->as<JSFunction>().flags().hasFlags(flags)) { 1708 FAIL_IC(); 1709 } 1710 DISPATCH_CACHEOP(); 1711 } 1712 1713 CACHEOP_CASE(GuardFunctionIsNonBuiltinCtor) { 1714 ObjOperandId funId = cacheIRReader.objOperandId(); 1715 JSObject* fun = reinterpret_cast<JSObject*>(READ_REG(funId.id())); 1716 if (!fun->as<JSFunction>().isNonBuiltinConstructor()) { 1717 FAIL_IC(); 1718 } 1719 DISPATCH_CACHEOP(); 1720 } 1721 1722 CACHEOP_CASE(GuardFunctionIsConstructor) { 1723 ObjOperandId funId = cacheIRReader.objOperandId(); 1724 JSObject* fun = reinterpret_cast<JSObject*>(READ_REG(funId.id())); 1725 if (!fun->as<JSFunction>().isConstructor()) { 1726 FAIL_IC(); 1727 } 1728 DISPATCH_CACHEOP(); 1729 } 1730 1731 CACHEOP_CASE(GuardNotClassConstructor) { 1732 ObjOperandId funId = cacheIRReader.objOperandId(); 1733 JSObject* fun = reinterpret_cast<JSObject*>(READ_REG(funId.id())); 1734 if (fun->as<JSFunction>().isClassConstructor()) { 1735 FAIL_IC(); 1736 } 1737 DISPATCH_CACHEOP(); 1738 } 1739 1740 CACHEOP_CASE(GuardArrayIsPacked) { 1741 ObjOperandId arrayId = cacheIRReader.objOperandId(); 1742 JSObject* array = reinterpret_cast<JSObject*>(READ_REG(arrayId.id())); 1743 if (!IsPackedArray(array)) { 1744 FAIL_IC(); 1745 } 1746 DISPATCH_CACHEOP(); 1747 } 1748 1749 CACHEOP_CASE(GuardArgumentsObjectFlags) { 1750 ObjOperandId objId = cacheIRReader.objOperandId(); 1751 uint8_t flags = cacheIRReader.readByte(); 1752 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1753 if (obj->as<ArgumentsObject>().hasFlags(flags)) { 1754 FAIL_IC(); 1755 } 1756 DISPATCH_CACHEOP(); 1757 } 1758 1759 CACHEOP_CASE(LoadObject) { 1760 ObjOperandId resultId = cacheIRReader.objOperandId(); 1761 BOUNDSCHECK(resultId); 1762 uint32_t objOffset = cacheIRReader.stubOffset(); 1763 intptr_t obj = stubInfo->getStubRawWord(cstub, objOffset); 1764 WRITE_REG(resultId.id(), obj, OBJECT); 1765 PREDICT_NEXT(GuardShape); 1766 DISPATCH_CACHEOP(); 1767 } 1768 1769 CACHEOP_CASE(LoadProtoObject) { 1770 auto args = cacheIRReader.argsForLoadProtoObject(); 1771 BOUNDSCHECK(args.resultId); 1772 intptr_t obj = stubInfo->getStubRawWord(cstub, args.protoObjOffset); 1773 WRITE_REG(args.resultId.id(), obj, OBJECT); 1774 PREDICT_NEXT(GuardShape); 1775 DISPATCH_CACHEOP(); 1776 } 1777 1778 CACHEOP_CASE(LoadProto) { 1779 ObjOperandId objId = cacheIRReader.objOperandId(); 1780 ObjOperandId resultId = cacheIRReader.objOperandId(); 1781 BOUNDSCHECK(resultId); 1782 NativeObject* nobj = 1783 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 1784 WRITE_REG(resultId.id(), 1785 reinterpret_cast<uint64_t>(nobj->staticPrototype()), OBJECT); 1786 DISPATCH_CACHEOP(); 1787 } 1788 1789 CACHEOP_CASE(LoadEnclosingEnvironment) { 1790 ObjOperandId objId = cacheIRReader.objOperandId(); 1791 ObjOperandId resultId = cacheIRReader.objOperandId(); 1792 BOUNDSCHECK(resultId); 1793 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1794 JSObject* env = &obj->as<EnvironmentObject>().enclosingEnvironment(); 1795 WRITE_REG(resultId.id(), reinterpret_cast<uint64_t>(env), OBJECT); 1796 DISPATCH_CACHEOP(); 1797 } 1798 1799 CACHEOP_CASE(LoadWrapperTarget) { 1800 ObjOperandId objId = cacheIRReader.objOperandId(); 1801 ObjOperandId resultId = cacheIRReader.objOperandId(); 1802 bool fallible = cacheIRReader.readBool(); 1803 BOUNDSCHECK(resultId); 1804 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1805 JSObject* target = obj->as<ProxyObject>().private_().toObjectOrNull(); 1806 if (fallible && !target) { 1807 FAIL_IC(); 1808 } 1809 WRITE_REG(resultId.id(), reinterpret_cast<uintptr_t>(target), OBJECT); 1810 DISPATCH_CACHEOP(); 1811 } 1812 1813 CACHEOP_CASE(LoadValueTag) { 1814 ValOperandId valId = cacheIRReader.valOperandId(); 1815 ValueTagOperandId resultId = cacheIRReader.valueTagOperandId(); 1816 BOUNDSCHECK(resultId); 1817 Value val = READ_VALUE_REG(valId.id()); 1818 WRITE_REG(resultId.id(), val.asRawBits() >> JSVAL_TAG_SHIFT, INT32); 1819 DISPATCH_CACHEOP(); 1820 } 1821 1822 CACHEOP_CASE(LoadArgumentFixedSlot) { 1823 ValOperandId resultId = cacheIRReader.valOperandId(); 1824 BOUNDSCHECK(resultId); 1825 uint8_t slotIndex = cacheIRReader.readByte(); 1826 StackVal* sp = ctx.sp(); 1827 Value val = sp[slotIndex].asValue(); 1828 TRACE_PRINTF(" -> slot %d: val %" PRIx64 "\n", int(slotIndex), 1829 val.asRawBits()); 1830 WRITE_VALUE_REG(resultId.id(), val); 1831 DISPATCH_CACHEOP(); 1832 } 1833 1834 CACHEOP_CASE(LoadArgumentDynamicSlot) { 1835 ValOperandId resultId = cacheIRReader.valOperandId(); 1836 BOUNDSCHECK(resultId); 1837 Int32OperandId argcId = cacheIRReader.int32OperandId(); 1838 uint8_t slotIndex = cacheIRReader.readByte(); 1839 int32_t argc = int32_t(READ_REG(argcId.id())); 1840 StackVal* sp = ctx.sp(); 1841 Value val = sp[slotIndex + argc].asValue(); 1842 WRITE_VALUE_REG(resultId.id(), val); 1843 DISPATCH_CACHEOP(); 1844 } 1845 1846 CACHEOP_CASE(TruncateDoubleToUInt32) { 1847 NumberOperandId inputId = cacheIRReader.numberOperandId(); 1848 Int32OperandId resultId = cacheIRReader.int32OperandId(); 1849 BOUNDSCHECK(resultId); 1850 Value input = READ_VALUE_REG(inputId.id()); 1851 WRITE_REG(resultId.id(), JS::ToInt32(input.toNumber()), INT32); 1852 DISPATCH_CACHEOP(); 1853 } 1854 1855 CACHEOP_CASE(MegamorphicLoadSlotResult) { 1856 ObjOperandId objId = cacheIRReader.objOperandId(); 1857 uint32_t nameOffset = cacheIRReader.stubOffset(); 1858 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1859 jsid name = 1860 jsid::fromRawBits(stubInfo->getStubRawWord(cstub, nameOffset)); 1861 if (!obj->shape()->isNative()) { 1862 FAIL_IC(); 1863 } 1864 Value result; 1865 if (!GetNativeDataPropertyPureWithCacheLookup( 1866 ctx.frameMgr.cxForLocalUseOnly(), obj, name, nullptr, 1867 &result)) { 1868 FAIL_IC(); 1869 } 1870 retValue = result.asRawBits(); 1871 DISPATCH_CACHEOP(); 1872 } 1873 1874 CACHEOP_CASE(MegamorphicLoadSlotByValueResult) { 1875 ObjOperandId objId = cacheIRReader.objOperandId(); 1876 ValOperandId idId = cacheIRReader.valOperandId(); 1877 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1878 Value id = READ_VALUE_REG(idId.id()); 1879 if (!obj->shape()->isNative()) { 1880 FAIL_IC(); 1881 } 1882 Value values[2] = {id}; 1883 if (!GetNativeDataPropertyByValuePure(ctx.frameMgr.cxForLocalUseOnly(), 1884 obj, nullptr, values)) { 1885 FAIL_IC(); 1886 } 1887 retValue = values[1].asRawBits(); 1888 DISPATCH_CACHEOP(); 1889 } 1890 1891 CACHEOP_CASE(MegamorphicSetElement) { 1892 auto args = cacheIRReader.argsForMegamorphicSetElement(); 1893 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(args.objId.id())); 1894 Value id = READ_VALUE_REG(args.idId.id()); 1895 Value rhs = READ_VALUE_REG(args.rhsId.id()); 1896 { 1897 PUSH_IC_FRAME(); 1898 ReservedRooted<JSObject*> obj0(&ctx.state.obj0, obj); 1899 ReservedRooted<Value> value0(&ctx.state.value0, id); 1900 ReservedRooted<Value> value1(&ctx.state.value1, rhs); 1901 if (!SetElementMegamorphic<false>(cx, obj0, value0, value1, 1902 args.strict)) { 1903 ctx.error = PBIResult::Error; 1904 return IC_ERROR_SENTINEL(); 1905 } 1906 } 1907 DISPATCH_CACHEOP(); 1908 } 1909 1910 CACHEOP_CASE(StoreFixedSlot) { 1911 ObjOperandId objId = cacheIRReader.objOperandId(); 1912 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1913 ValOperandId rhsId = cacheIRReader.valOperandId(); 1914 uintptr_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1915 NativeObject* nobj = 1916 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 1917 GCPtr<Value>* slot = reinterpret_cast<GCPtr<Value>*>( 1918 reinterpret_cast<uintptr_t>(nobj) + offset); 1919 Value val = READ_VALUE_REG(rhsId.id()); 1920 slot->set(val); 1921 PREDICT_RETURN(); 1922 DISPATCH_CACHEOP(); 1923 } 1924 1925 CACHEOP_CASE(StoreDynamicSlot) { 1926 ObjOperandId objId = cacheIRReader.objOperandId(); 1927 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1928 ValOperandId rhsId = cacheIRReader.valOperandId(); 1929 uint32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1930 NativeObject* nobj = 1931 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 1932 HeapSlot* slots = nobj->getSlotsUnchecked(); 1933 Value val = READ_VALUE_REG(rhsId.id()); 1934 size_t dynSlot = offset / sizeof(Value); 1935 size_t slot = dynSlot + nobj->numFixedSlots(); 1936 slots[dynSlot].set(nobj, HeapSlot::Slot, slot, val); 1937 PREDICT_RETURN(); 1938 DISPATCH_CACHEOP(); 1939 } 1940 1941 CACHEOP_CASE(AddAndStoreFixedSlot) { 1942 ObjOperandId objId = cacheIRReader.objOperandId(); 1943 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1944 ValOperandId rhsId = cacheIRReader.valOperandId(); 1945 uint32_t newShapeOffset = cacheIRReader.stubOffset(); 1946 bool preserveWrapper = cacheIRReader.readBool(); 1947 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1948 if (preserveWrapper && 1949 !PreserveWrapper(ctx.frameMgr.cxForLocalUseOnly(), obj)) { 1950 FAIL_IC(); 1951 } 1952 int32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1953 Value rhs = READ_VALUE_REG(rhsId.id()); 1954 Shape* newShape = reinterpret_cast<Shape*>( 1955 stubInfo->getStubRawWord(cstub, newShapeOffset)); 1956 obj->setShape(newShape); 1957 GCPtr<Value>* slot = reinterpret_cast<GCPtr<Value>*>( 1958 reinterpret_cast<uintptr_t>(obj) + offset); 1959 slot->init(rhs); 1960 PREDICT_RETURN(); 1961 DISPATCH_CACHEOP(); 1962 } 1963 1964 CACHEOP_CASE(AddAndStoreDynamicSlot) { 1965 ObjOperandId objId = cacheIRReader.objOperandId(); 1966 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1967 ValOperandId rhsId = cacheIRReader.valOperandId(); 1968 uint32_t newShapeOffset = cacheIRReader.stubOffset(); 1969 bool preserveWrapper = cacheIRReader.readBool(); 1970 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1971 if (preserveWrapper && 1972 !PreserveWrapper(ctx.frameMgr.cxForLocalUseOnly(), obj)) { 1973 FAIL_IC(); 1974 } 1975 int32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 1976 Value rhs = READ_VALUE_REG(rhsId.id()); 1977 Shape* newShape = reinterpret_cast<Shape*>( 1978 stubInfo->getStubRawWord(cstub, newShapeOffset)); 1979 NativeObject* nobj = &obj->as<NativeObject>(); 1980 obj->setShape(newShape); 1981 HeapSlot* slots = nobj->getSlotsUnchecked(); 1982 size_t dynSlot = offset / sizeof(Value); 1983 size_t slot = dynSlot + nobj->numFixedSlots(); 1984 slots[dynSlot].init(nobj, HeapSlot::Slot, slot, rhs); 1985 PREDICT_RETURN(); 1986 DISPATCH_CACHEOP(); 1987 } 1988 1989 CACHEOP_CASE(AllocateAndStoreDynamicSlot) { 1990 ObjOperandId objId = cacheIRReader.objOperandId(); 1991 uint32_t offsetOffset = cacheIRReader.stubOffset(); 1992 ValOperandId rhsId = cacheIRReader.valOperandId(); 1993 uint32_t newShapeOffset = cacheIRReader.stubOffset(); 1994 uint32_t numNewSlotsOffset = cacheIRReader.stubOffset(); 1995 bool preserveWrapper = cacheIRReader.readBool(); 1996 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 1997 if (preserveWrapper && 1998 !PreserveWrapper(ctx.frameMgr.cxForLocalUseOnly(), obj)) { 1999 FAIL_IC(); 2000 } 2001 int32_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 2002 Value rhs = READ_VALUE_REG(rhsId.id()); 2003 Shape* newShape = reinterpret_cast<Shape*>( 2004 stubInfo->getStubRawWord(cstub, newShapeOffset)); 2005 int32_t numNewSlots = 2006 stubInfo->getStubRawInt32(cstub, numNewSlotsOffset); 2007 NativeObject* nobj = &obj->as<NativeObject>(); 2008 // We have to (re)allocate dynamic slots. Do this first, as it's the 2009 // only fallible operation here. Note that growSlotsPure is fallible but 2010 // does not GC. Otherwise this is the same as AddAndStoreDynamicSlot 2011 // above. 2012 if (!NativeObject::growSlotsPure(ctx.frameMgr.cxForLocalUseOnly(), nobj, 2013 numNewSlots)) { 2014 FAIL_IC(); 2015 } 2016 obj->setShape(newShape); 2017 HeapSlot* slots = nobj->getSlotsUnchecked(); 2018 size_t dynSlot = offset / sizeof(Value); 2019 size_t slot = dynSlot + nobj->numFixedSlots(); 2020 slots[dynSlot].init(nobj, HeapSlot::Slot, slot, rhs); 2021 PREDICT_RETURN(); 2022 DISPATCH_CACHEOP(); 2023 } 2024 2025 CACHEOP_CASE(StoreDenseElement) { 2026 ObjOperandId objId = cacheIRReader.objOperandId(); 2027 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2028 ValOperandId rhsId = cacheIRReader.valOperandId(); 2029 bool expectPackedElements = cacheIRReader.readBool(); 2030 NativeObject* nobj = 2031 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2032 ObjectElements* elems = nobj->getElementsHeader(); 2033 int32_t index = int32_t(READ_REG(indexId.id())); 2034 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) { 2035 FAIL_IC(); 2036 } 2037 if (expectPackedElements && !elems->isPacked()) { 2038 FAIL_IC(); 2039 } 2040 HeapSlot* slot = &elems->elements()[index]; 2041 if (!expectPackedElements && slot->get().isMagic()) { 2042 FAIL_IC(); 2043 } 2044 Value val = READ_VALUE_REG(rhsId.id()); 2045 slot->set(nobj, HeapSlot::Element, index + elems->numShiftedElements(), 2046 val); 2047 PREDICT_RETURN(); 2048 DISPATCH_CACHEOP(); 2049 } 2050 2051 CACHEOP_CASE(StoreDenseElementHole) { 2052 ObjOperandId objId = cacheIRReader.objOperandId(); 2053 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2054 ValOperandId rhsId = cacheIRReader.valOperandId(); 2055 bool handleAdd = cacheIRReader.readBool(); 2056 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 2057 uint32_t index = uint32_t(READ_REG(indexId.id())); 2058 Value rhs = READ_VALUE_REG(rhsId.id()); 2059 NativeObject* nobj = &obj->as<NativeObject>(); 2060 uint32_t initLength = nobj->getDenseInitializedLength(); 2061 if (index < initLength) { 2062 nobj->setDenseElement(index, rhs); 2063 } else if (!handleAdd || index > initLength) { 2064 FAIL_IC(); 2065 } else { 2066 if (index >= nobj->getDenseCapacity()) { 2067 if (!NativeObject::addDenseElementPure( 2068 ctx.frameMgr.cxForLocalUseOnly(), nobj)) { 2069 FAIL_IC(); 2070 } 2071 } 2072 nobj->setDenseInitializedLength(initLength + 1); 2073 2074 // Baseline always updates the length field by directly accessing its 2075 // offset in ObjectElements. If the object is not an ArrayObject then 2076 // this field is never read, so it's okay to skip the update here in 2077 // that case. 2078 if (nobj->is<ArrayObject>()) { 2079 ArrayObject* aobj = &nobj->as<ArrayObject>(); 2080 uint32_t len = aobj->length(); 2081 if (len <= index) { 2082 aobj->setLength(ctx.frameMgr.cxForLocalUseOnly(), len + 1); 2083 } 2084 } 2085 2086 nobj->initDenseElement(index, rhs); 2087 } 2088 PREDICT_RETURN(); 2089 DISPATCH_CACHEOP(); 2090 } 2091 2092 CACHEOP_CASE(ArrayPush) { 2093 ObjOperandId objId = cacheIRReader.objOperandId(); 2094 ValOperandId rhsId = cacheIRReader.valOperandId(); 2095 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 2096 Value rhs = READ_VALUE_REG(rhsId.id()); 2097 ArrayObject* aobj = &obj->as<ArrayObject>(); 2098 uint32_t initLength = aobj->getDenseInitializedLength(); 2099 if (aobj->length() != initLength) { 2100 FAIL_IC(); 2101 } 2102 if (initLength >= aobj->getDenseCapacity()) { 2103 if (!NativeObject::addDenseElementPure( 2104 ctx.frameMgr.cxForLocalUseOnly(), aobj)) { 2105 FAIL_IC(); 2106 } 2107 } 2108 aobj->setDenseInitializedLength(initLength + 1); 2109 aobj->setLengthToInitializedLength(); 2110 aobj->initDenseElement(initLength, rhs); 2111 retValue = Int32Value(initLength + 1).asRawBits(); 2112 PREDICT_RETURN(); 2113 DISPATCH_CACHEOP(); 2114 } 2115 2116 CACHEOP_CASE(IsObjectResult) { 2117 ValOperandId inputId = cacheIRReader.valOperandId(); 2118 Value val = READ_VALUE_REG(inputId.id()); 2119 retValue = BooleanValue(val.isObject()).asRawBits(); 2120 PREDICT_RETURN(); 2121 DISPATCH_CACHEOP(); 2122 } 2123 2124 CACHEOP_CASE(Int32MinMax) { 2125 bool isMax = cacheIRReader.readBool(); 2126 Int32OperandId firstId = cacheIRReader.int32OperandId(); 2127 Int32OperandId secondId = cacheIRReader.int32OperandId(); 2128 Int32OperandId resultId = cacheIRReader.int32OperandId(); 2129 BOUNDSCHECK(resultId); 2130 int32_t lhs = int32_t(READ_REG(firstId.id())); 2131 int32_t rhs = int32_t(READ_REG(secondId.id())); 2132 int32_t result = ((lhs > rhs) ^ isMax) ? rhs : lhs; 2133 WRITE_REG(resultId.id(), result, INT32); 2134 DISPATCH_CACHEOP(); 2135 } 2136 2137 CACHEOP_CASE(StoreTypedArrayElement) { 2138 auto args = cacheIRReader.argsForStoreTypedArrayElement(); 2139 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(args.objId.id())); 2140 uintptr_t index = uintptr_t(READ_REG(args.indexId.id())); 2141 uint64_t rhs = READ_REG(args.rhsId); 2142 if (obj->as<TypedArrayObject>().length().isNothing()) { 2143 FAIL_IC(); 2144 } 2145 if (index >= obj->as<TypedArrayObject>().length().value()) { 2146 if (!args.handleOOB) { 2147 FAIL_IC(); 2148 } 2149 } else { 2150 Value v; 2151 switch (args.elementType) { 2152 case Scalar::Int8: 2153 case Scalar::Uint8: 2154 case Scalar::Int16: 2155 case Scalar::Uint16: 2156 case Scalar::Int32: 2157 case Scalar::Uint32: 2158 case Scalar::Uint8Clamped: 2159 v = Int32Value(rhs); 2160 break; 2161 2162 case Scalar::Float16: 2163 case Scalar::Float32: 2164 case Scalar::Float64: 2165 v = Value::fromRawBits(rhs); 2166 MOZ_ASSERT(v.isNumber()); 2167 break; 2168 2169 case Scalar::BigInt64: 2170 case Scalar::BigUint64: 2171 v = BigIntValue(reinterpret_cast<JS::BigInt*>(rhs)); 2172 break; 2173 2174 case Scalar::MaxTypedArrayViewType: 2175 case Scalar::Int64: 2176 case Scalar::Simd128: 2177 MOZ_CRASH("Unsupported TypedArray type"); 2178 } 2179 2180 // SetTypedArrayElement doesn't do anything that can actually GC or 2181 // need a new context when the value can only be Int32, Double, or 2182 // BigInt, as the above switch statement enforces. 2183 FakeRooted<TypedArrayObject*> obj0(nullptr, 2184 &obj->as<TypedArrayObject>()); 2185 FakeRooted<Value> value0(nullptr, v); 2186 ObjectOpResult result; 2187 MOZ_ASSERT(args.elementType == obj0->type()); 2188 MOZ_ALWAYS_TRUE(SetTypedArrayElement(ctx.frameMgr.cxForLocalUseOnly(), 2189 obj0, index, value0, result)); 2190 MOZ_ALWAYS_TRUE(result.ok()); 2191 } 2192 DISPATCH_CACHEOP(); 2193 } 2194 2195 CACHEOP_CASE(LoadTypedArrayElementExistsResult) { 2196 auto args = cacheIRReader.argsForLoadTypedArrayElementExistsResult(); 2197 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(args.objId.id())); 2198 uintptr_t index = uintptr_t(READ_REG(args.indexId.id())); 2199 if (obj->as<TypedArrayObject>().length().isNothing()) { 2200 FAIL_IC(); 2201 } 2202 retValue = 2203 BooleanValue(index < obj->as<TypedArrayObject>().length().value()) 2204 .asRawBits(); 2205 DISPATCH_CACHEOP(); 2206 } 2207 2208 CACHEOP_CASE(LoadTypedArrayElementResult) { 2209 auto args = cacheIRReader.argsForLoadTypedArrayElementResult(); 2210 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(args.objId.id())); 2211 uintptr_t index = uintptr_t(READ_REG(args.indexId.id())); 2212 if (obj->as<TypedArrayObject>().length().isNothing()) { 2213 FAIL_IC(); 2214 } 2215 if (index >= obj->as<TypedArrayObject>().length().value()) { 2216 FAIL_IC(); 2217 } 2218 Value v; 2219 if (!obj->as<TypedArrayObject>().getElementPure(index, &v)) { 2220 FAIL_IC(); 2221 } 2222 if (args.forceDoubleForUint32) { 2223 if (v.isInt32()) { 2224 v.setNumber(v.toInt32()); 2225 } 2226 } 2227 retValue = v.asRawBits(); 2228 PREDICT_RETURN(); 2229 DISPATCH_CACHEOP(); 2230 } 2231 2232 CACHEOP_CASE(CallInt32ToString) { 2233 Int32OperandId inputId = cacheIRReader.int32OperandId(); 2234 StringOperandId resultId = cacheIRReader.stringOperandId(); 2235 BOUNDSCHECK(resultId); 2236 int32_t input = int32_t(READ_REG(inputId.id())); 2237 JSLinearString* str = 2238 Int32ToStringPure(ctx.frameMgr.cxForLocalUseOnly(), input); 2239 if (str) { 2240 WRITE_REG(resultId.id(), reinterpret_cast<uintptr_t>(str), STRING); 2241 } else { 2242 FAIL_IC(); 2243 } 2244 DISPATCH_CACHEOP(); 2245 } 2246 2247 CACHEOP_CASE(CallScriptedFunction) 2248 CACHEOP_CASE_FALLTHROUGH(CallNativeFunction) { 2249 bool isNative = cacheop == CacheOp::CallNativeFunction; 2250 TRACE_PRINTF("CallScriptedFunction / CallNativeFunction (native: %d)\n", 2251 isNative); 2252 ObjOperandId calleeId = cacheIRReader.objOperandId(); 2253 Int32OperandId argcId = cacheIRReader.int32OperandId(); 2254 CallFlags flags = cacheIRReader.callFlags(); 2255 uint32_t argcFixed = cacheIRReader.uint32Immediate(); 2256 bool ignoresRv = false; 2257 if (isNative) { 2258 ignoresRv = cacheIRReader.readBool(); 2259 } 2260 2261 TRACE_PRINTF("isConstructing = %d needsUninitializedThis = %d\n", 2262 int(flags.isConstructing()), 2263 int(flags.needsUninitializedThis())); 2264 2265 JSFunction* callee = 2266 reinterpret_cast<JSFunction*>(READ_REG(calleeId.id())); 2267 uint32_t argc = uint32_t(READ_REG(argcId.id())); 2268 (void)argcFixed; 2269 2270 if (!isNative) { 2271 if (!callee->hasBaseScript() || 2272 !callee->baseScript()->hasBytecode() || 2273 !callee->baseScript()->hasJitScript()) { 2274 FAIL_IC(); 2275 } 2276 } 2277 2278 // For now, fail any different-realm cases. 2279 if (!flags.isSameRealm()) { 2280 TRACE_PRINTF("failing: not same realm\n"); 2281 FAIL_IC(); 2282 } 2283 // And support only "standard" arg formats. 2284 if (flags.getArgFormat() != CallFlags::Standard) { 2285 TRACE_PRINTF("failing: not standard arg format\n"); 2286 FAIL_IC(); 2287 } 2288 2289 // Fail constructing on a non-constructor callee. 2290 if (flags.isConstructing() && !callee->isConstructor()) { 2291 TRACE_PRINTF("failing: constructing a non-constructor\n"); 2292 FAIL_IC(); 2293 } 2294 2295 // Handle arg-underflow (but only for scripted targets). 2296 uint32_t undefArgs = (!isNative && (argc < callee->nargs())) 2297 ? (callee->nargs() - argc) 2298 : 0; 2299 uint32_t extra = 1 + flags.isConstructing() + isNative; 2300 uint32_t totalArgs = argc + undefArgs + extra; 2301 StackVal* origArgs = ctx.sp(); 2302 2303 { 2304 PUSH_IC_FRAME(); 2305 2306 if (!ctx.stack.check(sp, sizeof(StackVal) * (totalArgs + 6))) { 2307 ReportOverRecursed(ctx.frameMgr.cxForLocalUseOnly()); 2308 ctx.error = PBIResult::Error; 2309 return IC_ERROR_SENTINEL(); 2310 } 2311 2312 // Create `this` if we are constructing and this is a 2313 // scripted function. 2314 Value thisVal; 2315 // Force JIT scripts to stick around, so we don't have to 2316 // fail the IC after GC'ing. This is critical, because 2317 // `stub` is not rooted (we don't have a BaselineStub frame 2318 // in PBL, only an exit frame directly below a baseline 2319 // function frame), so we cannot fall back to the next stub 2320 // once we pass this point. 2321 AutoKeepJitScripts keepJitScripts(cx); 2322 if (flags.isConstructing() && !isNative) { 2323 if (flags.needsUninitializedThis()) { 2324 thisVal = MagicValue(JS_UNINITIALIZED_LEXICAL); 2325 } else { 2326 ReservedRooted<JSObject*> calleeObj(&ctx.state.obj0, callee); 2327 ReservedRooted<JSObject*> newTargetRooted( 2328 &ctx.state.obj1, &origArgs[0].asValue().toObject()); 2329 ReservedRooted<Value> result(&ctx.state.value0); 2330 if (!CreateThisFromIC(cx, calleeObj, newTargetRooted, &result)) { 2331 ctx.error = PBIResult::Error; 2332 return IC_ERROR_SENTINEL(); 2333 } 2334 thisVal = result; 2335 // `callee` may have moved. 2336 callee = &calleeObj->as<JSFunction>(); 2337 } 2338 } 2339 // This will not be an Exit frame but a BaselineStub frame, so 2340 // replace the ExitFrameType with the ICStub pointer. 2341 POPNNATIVE(1); 2342 PUSHNATIVE(StackValNative(cstub)); 2343 2344 // `origArgs` is (in index order, i.e. increasing address order) 2345 // - normal, scripted: arg[argc-1] ... arg[0] thisv 2346 // - ctor, scripted: newTarget arg[argc-1] ... arg[0] thisv 2347 // - normal, native: arg[argc-1] ... arg[0] thisv callee 2348 // - ctor, native: newTarget arg[argc-1] ... arg[0] thisv callee 2349 // 2350 // and we need to push them in reverse order -- from sp 2351 // upward (in increasing address order) -- with args filled 2352 // in with `undefined` if fewer than the number of formals. 2353 2354 // Push args: newTarget if constructing, extra undef's added 2355 // if underflow, then original args, and `callee` if 2356 // native. Replace `this` if constructing. 2357 if (flags.isConstructing()) { 2358 PUSH(origArgs[0]); 2359 origArgs++; 2360 } 2361 for (uint32_t i = 0; i < undefArgs; i++) { 2362 PUSH(StackVal(UndefinedValue())); 2363 } 2364 for (uint32_t i = 0; i < argc + 1 + isNative; i++) { 2365 PUSH(origArgs[i]); 2366 } 2367 if (flags.isConstructing() && !isNative) { 2368 sp[0] = StackVal(thisVal); 2369 } 2370 Value* args = reinterpret_cast<Value*>(sp); 2371 2372 if (isNative) { 2373 PUSHNATIVE(StackValNative(argc)); 2374 PUSHNATIVE( 2375 StackValNative(MakeFrameDescriptor(FrameType::BaselineStub))); 2376 2377 // We *also* need an exit frame (the native baseline 2378 // execution would invoke a trampoline here). 2379 StackVal* trampolinePrevFP = ctx.stack.fp; 2380 PUSHNATIVE(StackValNative(nullptr)); // fake return address. 2381 PUSHNATIVE(StackValNative(ctx.stack.fp)); 2382 ctx.stack.fp = sp; 2383 PUSHNATIVE(StackValNative( 2384 uint32_t(flags.isConstructing() ? ExitFrameType::ConstructNative 2385 : ExitFrameType::CallNative))); 2386 cx.getCx()->activation()->asJit()->setJSExitFP( 2387 reinterpret_cast<uint8_t*>(ctx.stack.fp)); 2388 cx.getCx()->portableBaselineStack().top = 2389 reinterpret_cast<void*>(sp); 2390 2391 JSNative native = ignoresRv 2392 ? callee->jitInfo()->ignoresReturnValueMethod 2393 : callee->native(); 2394 bool success = native(cx, argc, args); 2395 2396 ctx.stack.fp = trampolinePrevFP; 2397 POPNNATIVE(4); 2398 2399 if (!success) { 2400 ctx.error = PBIResult::Error; 2401 return IC_ERROR_SENTINEL(); 2402 } 2403 retValue = args[0].asRawBits(); 2404 } else { 2405 TRACE_PRINTF("pushing callee: %p\n", callee); 2406 PUSHNATIVE( 2407 StackValNative(CalleeToToken(callee, flags.isConstructing()))); 2408 2409 PUSHNATIVE(StackValNative( 2410 MakeFrameDescriptorForJitCall(FrameType::BaselineStub, argc))); 2411 2412 JSScript* script = callee->nonLazyScript(); 2413 jsbytecode* pc = script->code(); 2414 ImmutableScriptData* isd = script->immutableScriptData(); 2415 PBIResult result; 2416 Value ret; 2417 result = PortableBaselineInterpret<false, kHybridICsInterp>( 2418 cx, ctx.state, ctx.stack, sp, 2419 /* envChain = */ nullptr, &ret, pc, isd, nullptr, nullptr, 2420 nullptr, PBIResult::Ok); 2421 if (result != PBIResult::Ok) { 2422 ctx.error = result; 2423 return IC_ERROR_SENTINEL(); 2424 } 2425 if (flags.isConstructing() && !ret.isObject()) { 2426 ret = args[0]; 2427 } 2428 retValue = ret.asRawBits(); 2429 } 2430 } 2431 2432 PREDICT_RETURN(); 2433 DISPATCH_CACHEOP(); 2434 } 2435 2436 CACHEOP_CASE(CallScriptedGetterResult) 2437 CACHEOP_CASE_FALLTHROUGH(CallScriptedSetter) { 2438 bool isSetter = cacheop == CacheOp::CallScriptedSetter; 2439 ObjOperandId receiverId = cacheIRReader.objOperandId(); 2440 ObjOperandId calleeId = cacheIRReader.objOperandId(); 2441 ValOperandId rhsId = 2442 isSetter ? cacheIRReader.valOperandId() : ValOperandId(); 2443 bool sameRealm = cacheIRReader.readBool(); 2444 uint32_t nargsAndFlagsOffset = cacheIRReader.stubOffset(); 2445 (void)nargsAndFlagsOffset; 2446 2447 Value receiver = isSetter ? ObjectValue(*reinterpret_cast<JSObject*>( 2448 READ_REG(receiverId.id()))) 2449 : READ_VALUE_REG(receiverId.id()); 2450 JSFunction* callee = 2451 reinterpret_cast<JSFunction*>(READ_REG(calleeId.id())); 2452 Value rhs = isSetter ? READ_VALUE_REG(rhsId.id()) : UndefinedValue(); 2453 2454 if (!sameRealm) { 2455 FAIL_IC(); 2456 } 2457 2458 if (!callee->hasBaseScript() || !callee->baseScript()->hasBytecode() || 2459 !callee->baseScript()->hasJitScript()) { 2460 FAIL_IC(); 2461 } 2462 2463 // For now, fail any arg-underflow case. 2464 if (callee->nargs() != isSetter ? 1 : 0) { 2465 TRACE_PRINTF( 2466 "failing: getter/setter does not have exactly 0/1 arg (has %d " 2467 "instead)\n", 2468 int(callee->nargs())); 2469 FAIL_IC(); 2470 } 2471 2472 { 2473 PUSH_IC_FRAME(); 2474 2475 if (!ctx.stack.check(sp, sizeof(StackVal) * 8)) { 2476 ReportOverRecursed(ctx.frameMgr.cxForLocalUseOnly()); 2477 ctx.error = PBIResult::Error; 2478 return IC_ERROR_SENTINEL(); 2479 } 2480 2481 // This will not be an Exit frame but a BaselineStub frame, so 2482 // replace the ExitFrameType with the ICStub pointer. 2483 POPNNATIVE(1); 2484 PUSHNATIVE(StackValNative(cstub)); 2485 2486 if (isSetter) { 2487 // Push arg: value. 2488 PUSH(StackVal(rhs)); 2489 } 2490 TRACE_PRINTF("pushing receiver: %" PRIx64 "\n", receiver.asRawBits()); 2491 // Push thisv: receiver. 2492 PUSH(StackVal(receiver)); 2493 2494 TRACE_PRINTF("pushing callee: %p\n", callee); 2495 PUSHNATIVE(StackValNative( 2496 CalleeToToken(callee, /* isConstructing = */ false))); 2497 2498 PUSHNATIVE(StackValNative(MakeFrameDescriptorForJitCall( 2499 FrameType::BaselineStub, /* argc = */ isSetter ? 1 : 0))); 2500 2501 JSScript* script = callee->nonLazyScript(); 2502 jsbytecode* pc = script->code(); 2503 ImmutableScriptData* isd = script->immutableScriptData(); 2504 PBIResult result; 2505 Value ret; 2506 result = PortableBaselineInterpret<false, kHybridICsInterp>( 2507 cx, ctx.state, ctx.stack, sp, /* envChain = */ nullptr, &ret, pc, 2508 isd, nullptr, nullptr, nullptr, PBIResult::Ok); 2509 if (result != PBIResult::Ok) { 2510 ctx.error = result; 2511 return IC_ERROR_SENTINEL(); 2512 } 2513 retValue = ret.asRawBits(); 2514 } 2515 2516 PREDICT_RETURN(); 2517 DISPATCH_CACHEOP(); 2518 } 2519 2520 CACHEOP_CASE(CallBoundScriptedFunction) { 2521 ObjOperandId calleeId = cacheIRReader.objOperandId(); 2522 ObjOperandId targetId = cacheIRReader.objOperandId(); 2523 Int32OperandId argcId = cacheIRReader.int32OperandId(); 2524 CallFlags flags = cacheIRReader.callFlags(); 2525 uint32_t numBoundArgs = cacheIRReader.uint32Immediate(); 2526 2527 BoundFunctionObject* boundFunc = 2528 reinterpret_cast<BoundFunctionObject*>(READ_REG(calleeId.id())); 2529 JSFunction* callee = &boundFunc->getTarget()->as<JSFunction>(); 2530 uint32_t argc = uint32_t(READ_REG(argcId.id())); 2531 (void)targetId; 2532 2533 if (!callee->hasBaseScript() || !callee->baseScript()->hasBytecode() || 2534 !callee->baseScript()->hasJitScript()) { 2535 FAIL_IC(); 2536 } 2537 2538 // For now, fail any constructing or different-realm cases. 2539 if (flags.isConstructing()) { 2540 TRACE_PRINTF("failing: constructing\n"); 2541 FAIL_IC(); 2542 } 2543 if (!flags.isSameRealm()) { 2544 TRACE_PRINTF("failing: not same realm\n"); 2545 FAIL_IC(); 2546 } 2547 // And support only "standard" arg formats. 2548 if (flags.getArgFormat() != CallFlags::Standard) { 2549 TRACE_PRINTF("failing: not standard arg format\n"); 2550 FAIL_IC(); 2551 } 2552 2553 uint32_t totalArgs = numBoundArgs + argc; 2554 2555 // For now, fail any arg-underflow case. 2556 if (totalArgs < callee->nargs()) { 2557 TRACE_PRINTF("failing: too few args\n"); 2558 FAIL_IC(); 2559 } 2560 2561 StackVal* origArgs = ctx.sp(); 2562 2563 { 2564 PUSH_IC_FRAME(); 2565 2566 if (!ctx.stack.check(sp, sizeof(StackVal) * (totalArgs + 6))) { 2567 ReportOverRecursed(ctx.frameMgr.cxForLocalUseOnly()); 2568 ctx.error = PBIResult::Error; 2569 return IC_ERROR_SENTINEL(); 2570 } 2571 2572 // This will not be an Exit frame but a BaselineStub frame, so 2573 // replace the ExitFrameType with the ICStub pointer. 2574 POPNNATIVE(1); 2575 PUSHNATIVE(StackValNative(cstub)); 2576 2577 // Push args. 2578 for (uint32_t i = 0; i < argc; i++) { 2579 PUSH(origArgs[i]); 2580 } 2581 // Push bound args. 2582 for (uint32_t i = 0; i < numBoundArgs; i++) { 2583 PUSH(StackVal(boundFunc->getBoundArg(numBoundArgs - 1 - i))); 2584 } 2585 // Push bound `this`. 2586 PUSH(StackVal(boundFunc->getBoundThis())); 2587 2588 TRACE_PRINTF("pushing callee: %p\n", callee); 2589 PUSHNATIVE(StackValNative( 2590 CalleeToToken(callee, /* isConstructing = */ false))); 2591 2592 PUSHNATIVE(StackValNative(MakeFrameDescriptorForJitCall( 2593 FrameType::BaselineStub, totalArgs))); 2594 2595 JSScript* script = callee->nonLazyScript(); 2596 jsbytecode* pc = script->code(); 2597 ImmutableScriptData* isd = script->immutableScriptData(); 2598 PBIResult result; 2599 Value ret; 2600 result = PortableBaselineInterpret<false, kHybridICsInterp>( 2601 cx, ctx.state, ctx.stack, sp, /* envChain = */ nullptr, &ret, pc, 2602 isd, nullptr, nullptr, nullptr, PBIResult::Ok); 2603 if (result != PBIResult::Ok) { 2604 ctx.error = result; 2605 return IC_ERROR_SENTINEL(); 2606 } 2607 retValue = ret.asRawBits(); 2608 } 2609 2610 PREDICT_RETURN(); 2611 DISPATCH_CACHEOP(); 2612 } 2613 2614 CACHEOP_CASE(MetaScriptedThisShape) { 2615 // This op is only metadata for the Warp Transpiler and should be 2616 // ignored. 2617 cacheIRReader.argsForMetaScriptedThisShape(); 2618 PREDICT_NEXT(CallScriptedFunction); 2619 DISPATCH_CACHEOP(); 2620 } 2621 2622 CACHEOP_CASE(LoadFixedSlotResult) 2623 CACHEOP_CASE_FALLTHROUGH(LoadFixedSlotTypedResult) { 2624 ObjOperandId objId = cacheIRReader.objOperandId(); 2625 uint32_t offsetOffset = cacheIRReader.stubOffset(); 2626 if (cacheop == CacheOp::LoadFixedSlotTypedResult) { 2627 // Type is unused here. 2628 (void)cacheIRReader.valueType(); 2629 } 2630 uintptr_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 2631 NativeObject* nobj = 2632 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2633 Value* slot = reinterpret_cast<Value*>( 2634 reinterpret_cast<uintptr_t>(nobj) + offset); 2635 TRACE_PRINTF( 2636 "LoadFixedSlotResult: obj %p offsetOffset %d offset %d slotPtr %p " 2637 "slot %" PRIx64 "\n", 2638 nobj, int(offsetOffset), int(offset), slot, slot->asRawBits()); 2639 retValue = slot->asRawBits(); 2640 PREDICT_RETURN(); 2641 DISPATCH_CACHEOP(); 2642 } 2643 2644 CACHEOP_CASE(LoadDynamicSlotResult) { 2645 ObjOperandId objId = cacheIRReader.objOperandId(); 2646 uint32_t offsetOffset = cacheIRReader.stubOffset(); 2647 uintptr_t offset = stubInfo->getStubRawInt32(cstub, offsetOffset); 2648 NativeObject* nobj = 2649 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2650 HeapSlot* slots = nobj->getSlotsUnchecked(); 2651 retValue = slots[offset / sizeof(Value)].get().asRawBits(); 2652 PREDICT_RETURN(); 2653 DISPATCH_CACHEOP(); 2654 } 2655 2656 CACHEOP_CASE(LoadDenseElementResult) { 2657 ObjOperandId objId = cacheIRReader.objOperandId(); 2658 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2659 bool expectPackedElements = cacheIRReader.readBool(); 2660 NativeObject* nobj = 2661 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2662 ObjectElements* elems = nobj->getElementsHeader(); 2663 int32_t index = int32_t(READ_REG(indexId.id())); 2664 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) { 2665 FAIL_IC(); 2666 } 2667 if (expectPackedElements && !elems->isPacked()) { 2668 FAIL_IC(); 2669 } 2670 HeapSlot* slot = &elems->elements()[index]; 2671 Value val = slot->get(); 2672 if (!expectPackedElements && val.isMagic()) { 2673 FAIL_IC(); 2674 } 2675 retValue = val.asRawBits(); 2676 PREDICT_RETURN(); 2677 DISPATCH_CACHEOP(); 2678 } 2679 2680 CACHEOP_CASE(LoadDenseElementHoleResult) { 2681 ObjOperandId objId = cacheIRReader.objOperandId(); 2682 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2683 NativeObject* nobj = 2684 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2685 ObjectElements* elems = nobj->getElementsHeader(); 2686 int32_t index = int32_t(READ_REG(indexId.id())); 2687 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) { 2688 FAIL_IC(); 2689 } 2690 HeapSlot* slot = &elems->elements()[index]; 2691 Value val = slot->get(); 2692 if (val.isMagic()) { 2693 val.setUndefined(); 2694 } 2695 retValue = val.asRawBits(); 2696 PREDICT_RETURN(); 2697 DISPATCH_CACHEOP(); 2698 } 2699 2700 CACHEOP_CASE(LoadDenseElementExistsResult) { 2701 ObjOperandId objId = cacheIRReader.objOperandId(); 2702 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2703 NativeObject* nobj = 2704 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2705 ObjectElements* elems = nobj->getElementsHeader(); 2706 int32_t index = int32_t(READ_REG(indexId.id())); 2707 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) { 2708 FAIL_IC(); 2709 } 2710 HeapSlot* slot = &elems->elements()[index]; 2711 Value val = slot->get(); 2712 if (val.isMagic()) { 2713 FAIL_IC(); 2714 } 2715 retValue = BooleanValue(true).asRawBits(); 2716 PREDICT_RETURN(); 2717 DISPATCH_CACHEOP(); 2718 } 2719 2720 CACHEOP_CASE(LoadDenseElementHoleExistsResult) { 2721 ObjOperandId objId = cacheIRReader.objOperandId(); 2722 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2723 NativeObject* nobj = 2724 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2725 ObjectElements* elems = nobj->getElementsHeader(); 2726 int32_t index = int32_t(READ_REG(indexId.id())); 2727 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) { 2728 retValue = BooleanValue(false).asRawBits(); 2729 } else { 2730 HeapSlot* slot = &elems->elements()[index]; 2731 Value val = slot->get(); 2732 retValue = BooleanValue(!val.isMagic()).asRawBits(); 2733 } 2734 PREDICT_RETURN(); 2735 DISPATCH_CACHEOP(); 2736 } 2737 2738 CACHEOP_CASE(GuardIndexIsNotDenseElement) { 2739 ObjOperandId objId = cacheIRReader.objOperandId(); 2740 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2741 NativeObject* nobj = 2742 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 2743 ObjectElements* elems = nobj->getElementsHeader(); 2744 int32_t index = int32_t(READ_REG(indexId.id())); 2745 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) { 2746 // OK -- not in the dense index range. 2747 } else { 2748 HeapSlot* slot = &elems->elements()[index]; 2749 Value val = slot->get(); 2750 if (!val.isMagic()) { 2751 // Not a magic value -- not the hole, so guard fails. 2752 FAIL_IC(); 2753 } 2754 } 2755 DISPATCH_CACHEOP(); 2756 } 2757 2758 CACHEOP_CASE(LoadInt32ArrayLengthResult) { 2759 ObjOperandId objId = cacheIRReader.objOperandId(); 2760 ArrayObject* aobj = 2761 reinterpret_cast<ArrayObject*>(READ_REG(objId.id())); 2762 uint32_t length = aobj->length(); 2763 if (length > uint32_t(INT32_MAX)) { 2764 FAIL_IC(); 2765 } 2766 retValue = Int32Value(length).asRawBits(); 2767 PREDICT_RETURN(); 2768 DISPATCH_CACHEOP(); 2769 } 2770 2771 CACHEOP_CASE(LoadInt32ArrayLength) { 2772 ObjOperandId objId = cacheIRReader.objOperandId(); 2773 Int32OperandId resultId = cacheIRReader.int32OperandId(); 2774 BOUNDSCHECK(resultId); 2775 ArrayObject* aobj = 2776 reinterpret_cast<ArrayObject*>(READ_REG(objId.id())); 2777 uint32_t length = aobj->length(); 2778 if (length > uint32_t(INT32_MAX)) { 2779 FAIL_IC(); 2780 } 2781 WRITE_REG(resultId.id(), length, INT32); 2782 DISPATCH_CACHEOP(); 2783 } 2784 2785 CACHEOP_CASE(LoadArrayBufferByteLengthInt32Result) { 2786 ObjOperandId objId = cacheIRReader.objOperandId(); 2787 ArrayBufferObject* abo = 2788 reinterpret_cast<ArrayBufferObject*>(READ_REG(objId.id())); 2789 size_t len = abo->byteLength(); 2790 if (len > size_t(INT32_MAX)) { 2791 FAIL_IC(); 2792 } 2793 retValue = Int32Value(int32_t(len)).asRawBits(); 2794 PREDICT_RETURN(); 2795 DISPATCH_CACHEOP(); 2796 } 2797 2798 CACHEOP_CASE(LoadArrayBufferByteLengthDoubleResult) { 2799 ObjOperandId objId = cacheIRReader.objOperandId(); 2800 ArrayBufferObject* abo = 2801 reinterpret_cast<ArrayBufferObject*>(READ_REG(objId.id())); 2802 size_t len = abo->byteLength(); 2803 retValue = DoubleValue(double(len)).asRawBits(); 2804 PREDICT_RETURN(); 2805 DISPATCH_CACHEOP(); 2806 } 2807 2808 CACHEOP_CASE(LoadArrayBufferViewLengthInt32Result) { 2809 ObjOperandId objId = cacheIRReader.objOperandId(); 2810 ArrayBufferViewObject* abvo = 2811 reinterpret_cast<ArrayBufferViewObject*>(READ_REG(objId.id())); 2812 size_t len = size_t( 2813 abvo->getFixedSlot(ArrayBufferViewObject::LENGTH_SLOT).toPrivate()); 2814 if (len > size_t(INT32_MAX)) { 2815 FAIL_IC(); 2816 } 2817 retValue = Int32Value(int32_t(len)).asRawBits(); 2818 PREDICT_RETURN(); 2819 DISPATCH_CACHEOP(); 2820 } 2821 2822 CACHEOP_CASE(LoadArrayBufferViewLengthDoubleResult) { 2823 ObjOperandId objId = cacheIRReader.objOperandId(); 2824 ArrayBufferViewObject* abvo = 2825 reinterpret_cast<ArrayBufferViewObject*>(READ_REG(objId.id())); 2826 size_t len = size_t( 2827 abvo->getFixedSlot(ArrayBufferViewObject::LENGTH_SLOT).toPrivate()); 2828 retValue = DoubleValue(double(len)).asRawBits(); 2829 PREDICT_RETURN(); 2830 DISPATCH_CACHEOP(); 2831 } 2832 2833 CACHEOP_CASE(LoadArgumentsObjectArgResult) { 2834 ObjOperandId objId = cacheIRReader.objOperandId(); 2835 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2836 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 2837 uint32_t index = uint32_t(READ_REG(indexId.id())); 2838 ArgumentsObject* args = &obj->as<ArgumentsObject>(); 2839 if (index >= args->initialLength() || args->hasOverriddenElement()) { 2840 FAIL_IC(); 2841 } 2842 if (args->argIsForwarded(index)) { 2843 FAIL_IC(); 2844 } 2845 retValue = args->arg(index).asRawBits(); 2846 DISPATCH_CACHEOP(); 2847 } 2848 2849 CACHEOP_CASE(LinearizeForCharAccess) { 2850 StringOperandId strId = cacheIRReader.stringOperandId(); 2851 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2852 StringOperandId resultId = cacheIRReader.stringOperandId(); 2853 BOUNDSCHECK(resultId); 2854 JSString* str = reinterpret_cast<JSLinearString*>(READ_REG(strId.id())); 2855 (void)indexId; 2856 2857 WRITE_REG(resultId.id(), reinterpret_cast<uintptr_t>(str), STRING); 2858 if (str->isRope()) { 2859 PUSH_IC_FRAME(); 2860 JSLinearString* result = LinearizeForCharAccess(cx, str); 2861 if (!result) { 2862 ctx.error = PBIResult::Error; 2863 return IC_ERROR_SENTINEL(); 2864 } 2865 WRITE_REG(resultId.id(), reinterpret_cast<uintptr_t>(result), STRING); 2866 } 2867 PREDICT_NEXT(LoadStringCharResult); 2868 DISPATCH_CACHEOP(); 2869 } 2870 2871 CACHEOP_CASE(LinearizeForCodePointAccess) { 2872 StringOperandId strId = cacheIRReader.stringOperandId(); 2873 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2874 StringOperandId resultId = cacheIRReader.stringOperandId(); 2875 BOUNDSCHECK(resultId); 2876 JSString* str = reinterpret_cast<JSLinearString*>(READ_REG(strId.id())); 2877 (void)indexId; 2878 2879 WRITE_REG(resultId.id(), reinterpret_cast<uintptr_t>(str), STRING); 2880 if (str->isRope()) { 2881 PUSH_IC_FRAME(); 2882 JSLinearString* result = LinearizeForCharAccess(cx, str); 2883 if (!result) { 2884 ctx.error = PBIResult::Error; 2885 return IC_ERROR_SENTINEL(); 2886 } 2887 WRITE_REG(resultId.id(), reinterpret_cast<uintptr_t>(result), STRING); 2888 } 2889 PREDICT_NEXT(LoadStringCodePointResult); 2890 DISPATCH_CACHEOP(); 2891 } 2892 2893 CACHEOP_CASE(LoadStringCharResult) 2894 CACHEOP_CASE_FALLTHROUGH(LoadStringAtResult) { 2895 StringOperandId strId = cacheIRReader.stringOperandId(); 2896 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2897 bool handleOOB = cacheIRReader.readBool(); 2898 2899 JSString* str = reinterpret_cast<JSLinearString*>(READ_REG(strId.id())); 2900 int32_t index = int32_t(READ_REG(indexId.id())); 2901 JSString* result = nullptr; 2902 if (index < 0 || size_t(index) >= str->length()) { 2903 if (handleOOB) { 2904 if (cacheop == CacheOp::LoadStringCharResult) { 2905 // Return an empty string. 2906 retValue = 2907 StringValue(ctx.frameMgr.cxForLocalUseOnly()->names().empty_) 2908 .asRawBits(); 2909 } else { 2910 // Return `undefined`. 2911 retValue = UndefinedValue().asRawBits(); 2912 } 2913 } else { 2914 FAIL_IC(); 2915 } 2916 } else { 2917 char16_t c; 2918 // Guaranteed to always work because this CacheIR op is 2919 // always preceded by LinearizeForCharAccess. 2920 MOZ_ALWAYS_TRUE(str->getChar(/* cx = */ nullptr, index, &c)); 2921 StaticStrings& sstr = 2922 ctx.frameMgr.cxForLocalUseOnly()->staticStrings(); 2923 if (sstr.hasUnit(c)) { 2924 result = sstr.getUnit(c); 2925 } else { 2926 PUSH_IC_FRAME(); 2927 result = StringFromCharCode(cx, c); 2928 if (!result) { 2929 ctx.error = PBIResult::Error; 2930 return IC_ERROR_SENTINEL(); 2931 } 2932 } 2933 retValue = StringValue(result).asRawBits(); 2934 } 2935 PREDICT_RETURN(); 2936 DISPATCH_CACHEOP(); 2937 } 2938 2939 CACHEOP_CASE(LoadStringCharCodeResult) { 2940 StringOperandId strId = cacheIRReader.stringOperandId(); 2941 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2942 bool handleOOB = cacheIRReader.readBool(); 2943 2944 JSString* str = reinterpret_cast<JSLinearString*>(READ_REG(strId.id())); 2945 int32_t index = int32_t(READ_REG(indexId.id())); 2946 Value result; 2947 if (index < 0 || size_t(index) >= str->length()) { 2948 if (handleOOB) { 2949 // Return NaN. 2950 result = JS::NaNValue(); 2951 } else { 2952 FAIL_IC(); 2953 } 2954 } else { 2955 char16_t c; 2956 // Guaranteed to always work because this CacheIR op is 2957 // always preceded by LinearizeForCharAccess. 2958 MOZ_ALWAYS_TRUE(str->getChar(/* cx = */ nullptr, index, &c)); 2959 result = Int32Value(c); 2960 } 2961 retValue = result.asRawBits(); 2962 PREDICT_RETURN(); 2963 DISPATCH_CACHEOP(); 2964 } 2965 2966 CACHEOP_CASE(LoadStringCodePointResult) { 2967 StringOperandId strId = cacheIRReader.stringOperandId(); 2968 Int32OperandId indexId = cacheIRReader.int32OperandId(); 2969 bool handleOOB = cacheIRReader.readBool(); 2970 2971 JSString* str = reinterpret_cast<JSLinearString*>(READ_REG(strId.id())); 2972 int32_t index = int32_t(READ_REG(indexId.id())); 2973 Value result; 2974 if (index < 0 || size_t(index) >= str->length()) { 2975 if (handleOOB) { 2976 // Return undefined. 2977 result = UndefinedValue(); 2978 } else { 2979 FAIL_IC(); 2980 } 2981 } else { 2982 char32_t c; 2983 // Guaranteed to be always work because this CacheIR op is 2984 // always preceded by LinearizeForCharAccess. 2985 MOZ_ALWAYS_TRUE(str->getCodePoint(/* cx = */ nullptr, index, &c)); 2986 result = Int32Value(c); 2987 } 2988 retValue = result.asRawBits(); 2989 PREDICT_RETURN(); 2990 DISPATCH_CACHEOP(); 2991 } 2992 2993 CACHEOP_CASE(LoadStringLengthResult) { 2994 StringOperandId strId = cacheIRReader.stringOperandId(); 2995 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 2996 size_t length = str->length(); 2997 if (length > size_t(INT32_MAX)) { 2998 FAIL_IC(); 2999 } 3000 retValue = Int32Value(length).asRawBits(); 3001 PREDICT_RETURN(); 3002 DISPATCH_CACHEOP(); 3003 } 3004 3005 CACHEOP_CASE(LoadObjectResult) { 3006 ObjOperandId objId = cacheIRReader.objOperandId(); 3007 retValue = 3008 ObjectValue(*reinterpret_cast<JSObject*>(READ_REG(objId.id()))) 3009 .asRawBits(); 3010 PREDICT_RETURN(); 3011 DISPATCH_CACHEOP(); 3012 } 3013 3014 CACHEOP_CASE(LoadStringResult) { 3015 StringOperandId strId = cacheIRReader.stringOperandId(); 3016 retValue = 3017 StringValue(reinterpret_cast<JSString*>(READ_REG(strId.id()))) 3018 .asRawBits(); 3019 PREDICT_RETURN(); 3020 DISPATCH_CACHEOP(); 3021 } 3022 3023 CACHEOP_CASE(LoadSymbolResult) { 3024 SymbolOperandId symId = cacheIRReader.symbolOperandId(); 3025 retValue = 3026 SymbolValue(reinterpret_cast<JS::Symbol*>(READ_REG(symId.id()))) 3027 .asRawBits(); 3028 PREDICT_RETURN(); 3029 DISPATCH_CACHEOP(); 3030 } 3031 3032 CACHEOP_CASE(LoadInt32Result) { 3033 Int32OperandId valId = cacheIRReader.int32OperandId(); 3034 retValue = Int32Value(READ_REG(valId.id())).asRawBits(); 3035 PREDICT_RETURN(); 3036 DISPATCH_CACHEOP(); 3037 } 3038 3039 CACHEOP_CASE(LoadDoubleResult) { 3040 NumberOperandId valId = cacheIRReader.numberOperandId(); 3041 Value val = READ_VALUE_REG(valId.id()); 3042 if (val.isInt32()) { 3043 val = DoubleValue(val.toInt32()); 3044 } 3045 retValue = val.asRawBits(); 3046 PREDICT_RETURN(); 3047 DISPATCH_CACHEOP(); 3048 } 3049 3050 CACHEOP_CASE(LoadBigIntResult) { 3051 BigIntOperandId valId = cacheIRReader.bigIntOperandId(); 3052 retValue = 3053 BigIntValue(reinterpret_cast<JS::BigInt*>(READ_REG(valId.id()))) 3054 .asRawBits(); 3055 PREDICT_RETURN(); 3056 DISPATCH_CACHEOP(); 3057 } 3058 3059 CACHEOP_CASE(LoadBooleanResult) { 3060 bool val = cacheIRReader.readBool(); 3061 retValue = BooleanValue(val).asRawBits(); 3062 PREDICT_RETURN(); 3063 DISPATCH_CACHEOP(); 3064 } 3065 3066 CACHEOP_CASE(LoadInt32Constant) { 3067 uint32_t valOffset = cacheIRReader.stubOffset(); 3068 Int32OperandId resultId = cacheIRReader.int32OperandId(); 3069 BOUNDSCHECK(resultId); 3070 uint32_t value = stubInfo->getStubRawInt32(cstub, valOffset); 3071 WRITE_REG(resultId.id(), value, INT32); 3072 DISPATCH_CACHEOP(); 3073 } 3074 3075 CACHEOP_CASE(LoadConstantStringResult) { 3076 uint32_t strOffset = cacheIRReader.stubOffset(); 3077 JSString* str = reinterpret_cast<JSString*>( 3078 stubInfo->getStubRawWord(cstub, strOffset)); 3079 retValue = StringValue(str).asRawBits(); 3080 PREDICT_RETURN(); 3081 DISPATCH_CACHEOP(); 3082 } 3083 3084 CACHEOP_CASE(DoubleAddResult) { 3085 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3086 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3087 Value lhs = READ_VALUE_REG(lhsId.id()); 3088 Value rhs = READ_VALUE_REG(rhsId.id()); 3089 retValue = DoubleValue(lhs.toNumber() + rhs.toNumber()).asRawBits(); 3090 PREDICT_RETURN(); 3091 DISPATCH_CACHEOP(); 3092 } 3093 3094 CACHEOP_CASE(DoubleSubResult) { 3095 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3096 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3097 Value lhs = READ_VALUE_REG(lhsId.id()); 3098 Value rhs = READ_VALUE_REG(rhsId.id()); 3099 retValue = DoubleValue(lhs.toNumber() - rhs.toNumber()).asRawBits(); 3100 PREDICT_RETURN(); 3101 DISPATCH_CACHEOP(); 3102 } 3103 3104 CACHEOP_CASE(DoubleMulResult) { 3105 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3106 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3107 Value lhs = READ_VALUE_REG(lhsId.id()); 3108 Value rhs = READ_VALUE_REG(rhsId.id()); 3109 retValue = DoubleValue(lhs.toNumber() * rhs.toNumber()).asRawBits(); 3110 PREDICT_RETURN(); 3111 DISPATCH_CACHEOP(); 3112 } 3113 3114 CACHEOP_CASE(DoubleDivResult) { 3115 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3116 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3117 Value lhs = READ_VALUE_REG(lhsId.id()); 3118 Value rhs = READ_VALUE_REG(rhsId.id()); 3119 retValue = 3120 DoubleValue(NumberDiv(lhs.toNumber(), rhs.toNumber())).asRawBits(); 3121 PREDICT_RETURN(); 3122 DISPATCH_CACHEOP(); 3123 } 3124 3125 CACHEOP_CASE(DoubleModResult) { 3126 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3127 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3128 Value lhs = READ_VALUE_REG(lhsId.id()); 3129 Value rhs = READ_VALUE_REG(rhsId.id()); 3130 retValue = 3131 DoubleValue(NumberMod(lhs.toNumber(), rhs.toNumber())).asRawBits(); 3132 PREDICT_RETURN(); 3133 DISPATCH_CACHEOP(); 3134 } 3135 3136 CACHEOP_CASE(DoublePowResult) { 3137 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3138 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3139 Value lhs = READ_VALUE_REG(lhsId.id()); 3140 Value rhs = READ_VALUE_REG(rhsId.id()); 3141 retValue = 3142 DoubleValue(ecmaPow(lhs.toNumber(), rhs.toNumber())).asRawBits(); 3143 PREDICT_RETURN(); 3144 DISPATCH_CACHEOP(); 3145 } 3146 3147 #define INT32_OP(name, op, extra_check) \ 3148 CACHEOP_CASE(Int32##name##Result) { \ 3149 Int32OperandId lhsId = cacheIRReader.int32OperandId(); \ 3150 Int32OperandId rhsId = cacheIRReader.int32OperandId(); \ 3151 int64_t lhs = int64_t(int32_t(READ_REG(lhsId.id()))); \ 3152 int64_t rhs = int64_t(int32_t(READ_REG(rhsId.id()))); \ 3153 extra_check; \ 3154 int64_t result = lhs op rhs; \ 3155 if (result < INT32_MIN || result > INT32_MAX) { \ 3156 FAIL_IC(); \ 3157 } \ 3158 retValue = Int32Value(int32_t(result)).asRawBits(); \ 3159 PREDICT_RETURN(); \ 3160 DISPATCH_CACHEOP(); \ 3161 } 3162 3163 // clang-format off 3164 INT32_OP(Add, +, {}); 3165 INT32_OP(Sub, -, {}); 3166 // clang-format on 3167 INT32_OP(Mul, *, { 3168 if (rhs * lhs == 0 && ((rhs < 0) ^ (lhs < 0))) { 3169 FAIL_IC(); 3170 } 3171 }); 3172 INT32_OP(Div, /, { 3173 if (rhs == 0 || (lhs == INT32_MIN && rhs == -1)) { 3174 FAIL_IC(); 3175 } 3176 if (lhs == 0 && rhs < 0) { 3177 FAIL_IC(); 3178 } 3179 if (lhs % rhs != 0) { 3180 FAIL_IC(); 3181 } 3182 }); 3183 INT32_OP(Mod, %, { 3184 if (rhs == 0 || (lhs == INT32_MIN && rhs == -1)) { 3185 FAIL_IC(); 3186 } 3187 if (lhs % rhs == 0 && lhs < 0) { 3188 FAIL_IC(); 3189 } 3190 }); 3191 // clang-format off 3192 INT32_OP(BitOr, |, {}); 3193 INT32_OP(BitXor, ^, {}); 3194 INT32_OP(BitAnd, &, {}); 3195 // clang-format on 3196 3197 CACHEOP_CASE(Int32PowResult) { 3198 Int32OperandId lhsId = cacheIRReader.int32OperandId(); 3199 Int32OperandId rhsId = cacheIRReader.int32OperandId(); 3200 int64_t lhs = int64_t(int32_t(READ_REG(lhsId.id()))); 3201 uint64_t rhs = uint64_t(int32_t(READ_REG(rhsId.id()))); 3202 int64_t result; 3203 3204 if (lhs == 1) { 3205 result = 1; 3206 } else if (rhs >= uint64_t(INT64_MIN)) { 3207 FAIL_IC(); 3208 } else { 3209 result = 1; 3210 int64_t runningSquare = lhs; 3211 while (rhs) { 3212 if (rhs & 1) { 3213 result *= runningSquare; 3214 if (result > int64_t(INT32_MAX)) { 3215 FAIL_IC(); 3216 } 3217 } 3218 rhs >>= 1; 3219 if (rhs == 0) { 3220 break; 3221 } 3222 runningSquare *= runningSquare; 3223 if (runningSquare > int64_t(INT32_MAX)) { 3224 FAIL_IC(); 3225 } 3226 } 3227 } 3228 3229 retValue = Int32Value(int32_t(result)).asRawBits(); 3230 PREDICT_RETURN(); 3231 DISPATCH_CACHEOP(); 3232 } 3233 3234 CACHEOP_CASE(Int32IncResult) { 3235 Int32OperandId inputId = cacheIRReader.int32OperandId(); 3236 int64_t value = int64_t(int32_t(READ_REG(inputId.id()))); 3237 value++; 3238 if (value > INT32_MAX) { 3239 FAIL_IC(); 3240 } 3241 retValue = Int32Value(int32_t(value)).asRawBits(); 3242 PREDICT_RETURN(); 3243 DISPATCH_CACHEOP(); 3244 } 3245 3246 CACHEOP_CASE(Int32LeftShiftResult) { 3247 Int32OperandId lhsId = cacheIRReader.int32OperandId(); 3248 Int32OperandId rhsId = cacheIRReader.int32OperandId(); 3249 int32_t lhs = int32_t(READ_REG(lhsId.id())); 3250 int32_t rhs = int32_t(READ_REG(rhsId.id())); 3251 int32_t result = lhs << (rhs & 0x1F); 3252 retValue = Int32Value(result).asRawBits(); 3253 PREDICT_RETURN(); 3254 DISPATCH_CACHEOP(); 3255 } 3256 3257 CACHEOP_CASE(Int32RightShiftResult) { 3258 Int32OperandId lhsId = cacheIRReader.int32OperandId(); 3259 Int32OperandId rhsId = cacheIRReader.int32OperandId(); 3260 int32_t lhs = int32_t(READ_REG(lhsId.id())); 3261 int32_t rhs = int32_t(READ_REG(rhsId.id())); 3262 int32_t result = lhs >> (rhs & 0x1F); 3263 retValue = Int32Value(result).asRawBits(); 3264 PREDICT_RETURN(); 3265 DISPATCH_CACHEOP(); 3266 } 3267 3268 CACHEOP_CASE(Int32URightShiftResult) { 3269 Int32OperandId lhsId = cacheIRReader.int32OperandId(); 3270 Int32OperandId rhsId = cacheIRReader.int32OperandId(); 3271 bool forceDouble = cacheIRReader.readBool(); 3272 (void)forceDouble; 3273 uint32_t lhs = uint32_t(READ_REG(lhsId.id())); 3274 int32_t rhs = int32_t(READ_REG(rhsId.id())); 3275 uint32_t result = lhs >> (rhs & 0x1F); 3276 retValue = (result >= 0x80000000) 3277 ? DoubleValue(double(result)).asRawBits() 3278 : Int32Value(int32_t(result)).asRawBits(); 3279 PREDICT_RETURN(); 3280 DISPATCH_CACHEOP(); 3281 } 3282 3283 CACHEOP_CASE(Int32NotResult) { 3284 Int32OperandId inputId = cacheIRReader.int32OperandId(); 3285 int32_t input = int32_t(READ_REG(inputId.id())); 3286 retValue = Int32Value(~input).asRawBits(); 3287 PREDICT_RETURN(); 3288 DISPATCH_CACHEOP(); 3289 } 3290 3291 CACHEOP_CASE(LoadInt32TruthyResult) { 3292 ValOperandId inputId = cacheIRReader.valOperandId(); 3293 int32_t val = int32_t(READ_REG(inputId.id())); 3294 retValue = BooleanValue(val != 0).asRawBits(); 3295 PREDICT_RETURN(); 3296 DISPATCH_CACHEOP(); 3297 } 3298 3299 CACHEOP_CASE(LoadDoubleTruthyResult) { 3300 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3301 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3302 // NaN is falsy, not truthy. 3303 retValue = BooleanValue(input != 0.0 && !std::isnan(input)).asRawBits(); 3304 PREDICT_RETURN(); 3305 DISPATCH_CACHEOP(); 3306 } 3307 3308 CACHEOP_CASE(LoadStringTruthyResult) { 3309 StringOperandId strId = cacheIRReader.stringOperandId(); 3310 JSString* str = reinterpret_cast<JSLinearString*>(READ_REG(strId.id())); 3311 retValue = BooleanValue(str->length() > 0).asRawBits(); 3312 PREDICT_RETURN(); 3313 DISPATCH_CACHEOP(); 3314 } 3315 3316 CACHEOP_CASE(LoadObjectTruthyResult) { 3317 ObjOperandId objId = cacheIRReader.objOperandId(); 3318 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 3319 const JSClass* cls = obj->getClass(); 3320 if (cls->isProxyObject()) { 3321 FAIL_IC(); 3322 } 3323 retValue = BooleanValue(!cls->emulatesUndefined()).asRawBits(); 3324 PREDICT_RETURN(); 3325 DISPATCH_CACHEOP(); 3326 } 3327 3328 CACHEOP_CASE(LoadValueResult) { 3329 uint32_t valOffset = cacheIRReader.stubOffset(); 3330 retValue = stubInfo->getStubRawInt64(cstub, valOffset); 3331 PREDICT_RETURN(); 3332 DISPATCH_CACHEOP(); 3333 } 3334 3335 CACHEOP_CASE(LoadOperandResult) { 3336 ValOperandId inputId = cacheIRReader.valOperandId(); 3337 retValue = READ_REG(inputId.id()); 3338 PREDICT_RETURN(); 3339 DISPATCH_CACHEOP(); 3340 } 3341 3342 CACHEOP_CASE(ConcatStringsResult) { 3343 StringOperandId lhsId = cacheIRReader.stringOperandId(); 3344 StringOperandId rhsId = cacheIRReader.stringOperandId(); 3345 { 3346 PUSH_IC_FRAME(); 3347 ReservedRooted<JSString*> lhs( 3348 &ctx.state.str0, 3349 reinterpret_cast<JSString*>(READ_REG(lhsId.id()))); 3350 ReservedRooted<JSString*> rhs( 3351 &ctx.state.str1, 3352 reinterpret_cast<JSString*>(READ_REG(rhsId.id()))); 3353 JSString* result = 3354 ConcatStrings<CanGC>(ctx.frameMgr.cxForLocalUseOnly(), lhs, rhs); 3355 if (result) { 3356 retValue = StringValue(result).asRawBits(); 3357 } else { 3358 ctx.error = PBIResult::Error; 3359 return IC_ERROR_SENTINEL(); 3360 } 3361 } 3362 PREDICT_RETURN(); 3363 DISPATCH_CACHEOP(); 3364 } 3365 3366 CACHEOP_CASE(CompareStringResult) { 3367 JSOp op = cacheIRReader.jsop(); 3368 StringOperandId lhsId = cacheIRReader.stringOperandId(); 3369 StringOperandId rhsId = cacheIRReader.stringOperandId(); 3370 { 3371 PUSH_IC_FRAME(); 3372 ReservedRooted<JSString*> lhs( 3373 &ctx.state.str0, 3374 reinterpret_cast<JSString*>(READ_REG(lhsId.id()))); 3375 ReservedRooted<JSString*> rhs( 3376 &ctx.state.str1, 3377 reinterpret_cast<JSString*>(READ_REG(rhsId.id()))); 3378 bool result; 3379 if (lhs == rhs) { 3380 // If operands point to the same instance, the strings are trivially 3381 // equal. 3382 result = op == JSOp::Eq || op == JSOp::StrictEq || op == JSOp::Le || 3383 op == JSOp::Ge; 3384 } else { 3385 switch (op) { 3386 case JSOp::Eq: 3387 case JSOp::StrictEq: 3388 if (lhs->isAtom() && rhs->isAtom()) { 3389 result = false; 3390 break; 3391 } 3392 if (lhs->length() != rhs->length()) { 3393 result = false; 3394 break; 3395 } 3396 if (!StringsEqual<EqualityKind::Equal>(cx, lhs, rhs, &result)) { 3397 ctx.error = PBIResult::Error; 3398 return IC_ERROR_SENTINEL(); 3399 } 3400 break; 3401 case JSOp::Ne: 3402 case JSOp::StrictNe: 3403 if (lhs->isAtom() && rhs->isAtom()) { 3404 result = true; 3405 break; 3406 } 3407 if (lhs->length() != rhs->length()) { 3408 result = true; 3409 break; 3410 } 3411 if (!StringsEqual<EqualityKind::NotEqual>(cx, lhs, rhs, 3412 &result)) { 3413 ctx.error = PBIResult::Error; 3414 return IC_ERROR_SENTINEL(); 3415 } 3416 break; 3417 case JSOp::Lt: 3418 if (!StringsCompare<ComparisonKind::LessThan>(cx, lhs, rhs, 3419 &result)) { 3420 ctx.error = PBIResult::Error; 3421 return IC_ERROR_SENTINEL(); 3422 } 3423 break; 3424 case JSOp::Ge: 3425 if (!StringsCompare<ComparisonKind::GreaterThanOrEqual>( 3426 cx, lhs, rhs, &result)) { 3427 ctx.error = PBIResult::Error; 3428 return IC_ERROR_SENTINEL(); 3429 } 3430 break; 3431 case JSOp::Le: 3432 if (!StringsCompare<ComparisonKind::GreaterThanOrEqual>( 3433 cx, /* N.B. swapped order */ rhs, lhs, &result)) { 3434 ctx.error = PBIResult::Error; 3435 return IC_ERROR_SENTINEL(); 3436 } 3437 break; 3438 case JSOp::Gt: 3439 if (!StringsCompare<ComparisonKind::LessThan>( 3440 cx, /* N.B. swapped order */ rhs, lhs, &result)) { 3441 ctx.error = PBIResult::Error; 3442 return IC_ERROR_SENTINEL(); 3443 } 3444 break; 3445 default: 3446 MOZ_CRASH("bad opcode"); 3447 } 3448 } 3449 retValue = BooleanValue(result).asRawBits(); 3450 } 3451 PREDICT_RETURN(); 3452 DISPATCH_CACHEOP(); 3453 } 3454 3455 CACHEOP_CASE(CompareInt32Result) { 3456 JSOp op = cacheIRReader.jsop(); 3457 Int32OperandId lhsId = cacheIRReader.int32OperandId(); 3458 Int32OperandId rhsId = cacheIRReader.int32OperandId(); 3459 int64_t lhs = int64_t(int32_t(READ_REG(lhsId.id()))); 3460 int64_t rhs = int64_t(int32_t(READ_REG(rhsId.id()))); 3461 TRACE_PRINTF("lhs (%d) = %" PRIi64 " rhs (%d) = %" PRIi64 "\n", 3462 lhsId.id(), lhs, rhsId.id(), rhs); 3463 bool result; 3464 switch (op) { 3465 case JSOp::Eq: 3466 case JSOp::StrictEq: 3467 result = lhs == rhs; 3468 break; 3469 case JSOp::Ne: 3470 case JSOp::StrictNe: 3471 result = lhs != rhs; 3472 break; 3473 case JSOp::Lt: 3474 result = lhs < rhs; 3475 break; 3476 case JSOp::Le: 3477 result = lhs <= rhs; 3478 break; 3479 case JSOp::Gt: 3480 result = lhs > rhs; 3481 break; 3482 case JSOp::Ge: 3483 result = lhs >= rhs; 3484 break; 3485 default: 3486 MOZ_CRASH("Unexpected opcode"); 3487 } 3488 retValue = BooleanValue(result).asRawBits(); 3489 PREDICT_RETURN(); 3490 DISPATCH_CACHEOP(); 3491 } 3492 3493 CACHEOP_CASE(CompareDoubleResult) { 3494 JSOp op = cacheIRReader.jsop(); 3495 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3496 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3497 double lhs = READ_VALUE_REG(lhsId.id()).toNumber(); 3498 double rhs = READ_VALUE_REG(rhsId.id()).toNumber(); 3499 bool result; 3500 switch (op) { 3501 case JSOp::Eq: 3502 case JSOp::StrictEq: 3503 result = lhs == rhs; 3504 break; 3505 case JSOp::Ne: 3506 case JSOp::StrictNe: 3507 result = lhs != rhs; 3508 break; 3509 case JSOp::Lt: 3510 result = lhs < rhs; 3511 break; 3512 case JSOp::Le: 3513 result = lhs <= rhs; 3514 break; 3515 case JSOp::Gt: 3516 result = lhs > rhs; 3517 break; 3518 case JSOp::Ge: 3519 result = lhs >= rhs; 3520 break; 3521 default: 3522 MOZ_CRASH("Unexpected opcode"); 3523 } 3524 retValue = BooleanValue(result).asRawBits(); 3525 PREDICT_RETURN(); 3526 DISPATCH_CACHEOP(); 3527 } 3528 3529 CACHEOP_CASE(CompareNullUndefinedResult) { 3530 JSOp op = cacheIRReader.jsop(); 3531 bool isUndefined = cacheIRReader.readBool(); 3532 ValOperandId inputId = cacheIRReader.valOperandId(); 3533 Value val = READ_VALUE_REG(inputId.id()); 3534 if (val.isObject() && val.toObject().getClass()->isProxyObject()) { 3535 FAIL_IC(); 3536 } 3537 3538 bool result; 3539 switch (op) { 3540 case JSOp::Eq: 3541 result = val.isUndefined() || val.isNull() || 3542 (val.isObject() && 3543 val.toObject().getClass()->emulatesUndefined()); 3544 break; 3545 case JSOp::Ne: 3546 result = !(val.isUndefined() || val.isNull() || 3547 (val.isObject() && 3548 val.toObject().getClass()->emulatesUndefined())); 3549 break; 3550 case JSOp::StrictEq: 3551 result = isUndefined ? val.isUndefined() : val.isNull(); 3552 break; 3553 case JSOp::StrictNe: 3554 result = !(isUndefined ? val.isUndefined() : val.isNull()); 3555 break; 3556 default: 3557 MOZ_CRASH("bad opcode"); 3558 } 3559 retValue = BooleanValue(result).asRawBits(); 3560 PREDICT_RETURN(); 3561 DISPATCH_CACHEOP(); 3562 } 3563 3564 CACHEOP_CASE(CompareObjectResult) { 3565 auto args = cacheIRReader.argsForCompareObjectResult(); 3566 auto* lhs = reinterpret_cast<JSObject*>(READ_REG(args.lhsId.id())); 3567 auto* rhs = reinterpret_cast<JSObject*>(READ_REG(args.rhsId.id())); 3568 switch (args.op) { 3569 case JSOp::Eq: 3570 case JSOp::StrictEq: 3571 retValue = BooleanValue(lhs == rhs).asRawBits(); 3572 break; 3573 case JSOp::Ne: 3574 case JSOp::StrictNe: 3575 retValue = BooleanValue(lhs != rhs).asRawBits(); 3576 break; 3577 default: 3578 FAIL_IC(); 3579 } 3580 PREDICT_RETURN(); 3581 DISPATCH_CACHEOP(); 3582 } 3583 3584 CACHEOP_CASE(CompareSymbolResult) { 3585 auto args = cacheIRReader.argsForCompareSymbolResult(); 3586 auto* lhs = reinterpret_cast<JS::Symbol*>(READ_REG(args.lhsId.id())); 3587 auto* rhs = reinterpret_cast<JS::Symbol*>(READ_REG(args.rhsId.id())); 3588 switch (args.op) { 3589 case JSOp::Eq: 3590 case JSOp::StrictEq: 3591 retValue = BooleanValue(lhs == rhs).asRawBits(); 3592 break; 3593 case JSOp::Ne: 3594 case JSOp::StrictNe: 3595 retValue = BooleanValue(lhs != rhs).asRawBits(); 3596 break; 3597 default: 3598 FAIL_IC(); 3599 } 3600 PREDICT_RETURN(); 3601 DISPATCH_CACHEOP(); 3602 } 3603 3604 CACHEOP_CASE(AssertPropertyLookup) { 3605 // Debug-only assertion; we can ignore. 3606 cacheIRReader.argsForAssertPropertyLookup(); 3607 DISPATCH_CACHEOP(); 3608 } 3609 3610 CACHEOP_CASE(MathSqrtNumberResult) { 3611 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3612 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3613 retValue = NumberValue(sqrt(input)).asRawBits(); 3614 PREDICT_RETURN(); 3615 DISPATCH_CACHEOP(); 3616 } 3617 3618 CACHEOP_CASE(MathAbsInt32Result) { 3619 Int32OperandId inputId = cacheIRReader.int32OperandId(); 3620 int32_t input = int32_t(READ_REG(inputId.id())); 3621 if (input == INT32_MIN) { 3622 FAIL_IC(); 3623 } 3624 if (input < 0) { 3625 input = -input; 3626 } 3627 retValue = Int32Value(input).asRawBits(); 3628 PREDICT_RETURN(); 3629 DISPATCH_CACHEOP(); 3630 } 3631 3632 CACHEOP_CASE(MathAbsNumberResult) { 3633 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3634 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3635 retValue = DoubleValue(fabs(input)).asRawBits(); 3636 PREDICT_RETURN(); 3637 DISPATCH_CACHEOP(); 3638 } 3639 3640 CACHEOP_CASE(MathClz32Result) { 3641 Int32OperandId inputId = cacheIRReader.int32OperandId(); 3642 int32_t input = int32_t(READ_REG(inputId.id())); 3643 int32_t result = 3644 (input == 0) ? 32 : mozilla::CountLeadingZeroes32(input); 3645 retValue = Int32Value(result).asRawBits(); 3646 PREDICT_RETURN(); 3647 DISPATCH_CACHEOP(); 3648 } 3649 3650 CACHEOP_CASE(MathSignInt32Result) { 3651 Int32OperandId inputId = cacheIRReader.int32OperandId(); 3652 int32_t input = int32_t(READ_REG(inputId.id())); 3653 int32_t result = (input == 0) ? 0 : ((input > 0) ? 1 : -1); 3654 retValue = Int32Value(result).asRawBits(); 3655 PREDICT_RETURN(); 3656 DISPATCH_CACHEOP(); 3657 } 3658 3659 CACHEOP_CASE(MathSignNumberResult) { 3660 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3661 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3662 double result = 0; 3663 if (std::isnan(input)) { 3664 result = JS::GenericNaN(); 3665 } else if (input == 0 && std::signbit(input)) { 3666 result = -0.0; 3667 } else if (input == 0) { 3668 result = 0; 3669 } else if (input > 0) { 3670 result = 1; 3671 } else { 3672 result = -1; 3673 } 3674 retValue = DoubleValue(result).asRawBits(); 3675 PREDICT_RETURN(); 3676 DISPATCH_CACHEOP(); 3677 } 3678 3679 CACHEOP_CASE(MathSignNumberToInt32Result) { 3680 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3681 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3682 int32_t result = 0; 3683 if (std::isnan(input) || (input == 0.0 && std::signbit(input))) { 3684 FAIL_IC(); 3685 } else if (input == 0) { 3686 result = 0; 3687 } else if (input > 0) { 3688 result = 1; 3689 } else { 3690 result = -1; 3691 } 3692 retValue = Int32Value(result).asRawBits(); 3693 PREDICT_RETURN(); 3694 DISPATCH_CACHEOP(); 3695 } 3696 3697 CACHEOP_CASE(MathImulResult) { 3698 Int32OperandId lhsId = cacheIRReader.int32OperandId(); 3699 Int32OperandId rhsId = cacheIRReader.int32OperandId(); 3700 int32_t lhs = int32_t(READ_REG(lhsId.id())); 3701 int32_t rhs = int32_t(READ_REG(rhsId.id())); 3702 int32_t result = lhs * rhs; 3703 retValue = Int32Value(result).asRawBits(); 3704 PREDICT_RETURN(); 3705 DISPATCH_CACHEOP(); 3706 } 3707 3708 CACHEOP_CASE(MathFRoundNumberResult) { 3709 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3710 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3711 retValue = DoubleValue(double(float(input))).asRawBits(); 3712 PREDICT_RETURN(); 3713 DISPATCH_CACHEOP(); 3714 } 3715 3716 CACHEOP_CASE(MathRandomResult) { 3717 uint32_t rngOffset = cacheIRReader.stubOffset(); 3718 auto* rng = reinterpret_cast<mozilla::non_crypto::XorShift128PlusRNG*>( 3719 stubInfo->getStubRawWord(cstub, rngOffset)); 3720 retValue = DoubleValue(rng->nextDouble()).asRawBits(); 3721 PREDICT_RETURN(); 3722 DISPATCH_CACHEOP(); 3723 } 3724 3725 CACHEOP_CASE(MathHypot2NumberResult) { 3726 NumberOperandId firstId = cacheIRReader.numberOperandId(); 3727 double first = READ_VALUE_REG(firstId.id()).toNumber(); 3728 NumberOperandId secondId = cacheIRReader.numberOperandId(); 3729 double second = READ_VALUE_REG(secondId.id()).toNumber(); 3730 retValue = DoubleValue(ecmaHypot(first, second)).asRawBits(); 3731 PREDICT_RETURN(); 3732 DISPATCH_CACHEOP(); 3733 } 3734 3735 CACHEOP_CASE(MathHypot3NumberResult) { 3736 NumberOperandId firstId = cacheIRReader.numberOperandId(); 3737 double first = READ_VALUE_REG(firstId.id()).toNumber(); 3738 NumberOperandId secondId = cacheIRReader.numberOperandId(); 3739 double second = READ_VALUE_REG(secondId.id()).toNumber(); 3740 NumberOperandId thirdId = cacheIRReader.numberOperandId(); 3741 double third = READ_VALUE_REG(thirdId.id()).toNumber(); 3742 retValue = DoubleValue(hypot3(first, second, third)).asRawBits(); 3743 PREDICT_RETURN(); 3744 DISPATCH_CACHEOP(); 3745 } 3746 3747 CACHEOP_CASE(MathHypot4NumberResult) { 3748 NumberOperandId firstId = cacheIRReader.numberOperandId(); 3749 double first = READ_VALUE_REG(firstId.id()).toNumber(); 3750 NumberOperandId secondId = cacheIRReader.numberOperandId(); 3751 double second = READ_VALUE_REG(secondId.id()).toNumber(); 3752 NumberOperandId thirdId = cacheIRReader.numberOperandId(); 3753 double third = READ_VALUE_REG(thirdId.id()).toNumber(); 3754 NumberOperandId fourthId = cacheIRReader.numberOperandId(); 3755 double fourth = READ_VALUE_REG(fourthId.id()).toNumber(); 3756 retValue = 3757 DoubleValue(hypot4(first, second, third, fourth)).asRawBits(); 3758 PREDICT_RETURN(); 3759 DISPATCH_CACHEOP(); 3760 } 3761 3762 CACHEOP_CASE(MathAtan2NumberResult) { 3763 NumberOperandId lhsId = cacheIRReader.numberOperandId(); 3764 double lhs = READ_VALUE_REG(lhsId.id()).toNumber(); 3765 NumberOperandId rhsId = cacheIRReader.numberOperandId(); 3766 double rhs = READ_VALUE_REG(rhsId.id()).toNumber(); 3767 retValue = DoubleValue(ecmaAtan2(lhs, rhs)).asRawBits(); 3768 PREDICT_RETURN(); 3769 DISPATCH_CACHEOP(); 3770 } 3771 3772 CACHEOP_CASE(MathFloorNumberResult) { 3773 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3774 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3775 double result = std::floor(input); 3776 retValue = DoubleValue(result).asRawBits(); 3777 PREDICT_RETURN(); 3778 DISPATCH_CACHEOP(); 3779 } 3780 3781 CACHEOP_CASE(MathCeilNumberResult) { 3782 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3783 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3784 double result = std::ceil(input); 3785 retValue = DoubleValue(result).asRawBits(); 3786 PREDICT_RETURN(); 3787 DISPATCH_CACHEOP(); 3788 } 3789 3790 CACHEOP_CASE(MathTruncNumberResult) { 3791 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3792 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3793 double result = std::trunc(input); 3794 retValue = DoubleValue(result).asRawBits(); 3795 PREDICT_RETURN(); 3796 DISPATCH_CACHEOP(); 3797 } 3798 3799 CACHEOP_CASE(MathFloorToInt32Result) { 3800 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3801 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3802 if (input == 0.0 && std::signbit(input)) { 3803 FAIL_IC(); 3804 } 3805 double result = std::floor(input); 3806 int32_t intResult = int32_t(result); 3807 if (double(intResult) != result) { 3808 FAIL_IC(); 3809 } 3810 retValue = Int32Value(intResult).asRawBits(); 3811 PREDICT_RETURN(); 3812 DISPATCH_CACHEOP(); 3813 } 3814 3815 CACHEOP_CASE(MathCeilToInt32Result) { 3816 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3817 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3818 if (input > -1.0 && std::signbit(input)) { 3819 FAIL_IC(); 3820 } 3821 double result = std::ceil(input); 3822 int32_t intResult = int32_t(result); 3823 if (double(intResult) != result) { 3824 FAIL_IC(); 3825 } 3826 retValue = Int32Value(intResult).asRawBits(); 3827 PREDICT_RETURN(); 3828 DISPATCH_CACHEOP(); 3829 } 3830 3831 CACHEOP_CASE(MathTruncToInt32Result) { 3832 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3833 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3834 if (input == 0.0 && std::signbit(input)) { 3835 FAIL_IC(); 3836 } 3837 double result = std::trunc(input); 3838 int32_t intResult = int32_t(result); 3839 if (double(intResult) != result) { 3840 FAIL_IC(); 3841 } 3842 retValue = Int32Value(intResult).asRawBits(); 3843 PREDICT_RETURN(); 3844 DISPATCH_CACHEOP(); 3845 } 3846 3847 CACHEOP_CASE(MathRoundToInt32Result) { 3848 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3849 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3850 if (input == 0.0 && std::signbit(input)) { 3851 FAIL_IC(); 3852 } 3853 int32_t intResult = int32_t(input); 3854 if (double(intResult) != input) { 3855 FAIL_IC(); 3856 } 3857 retValue = Int32Value(intResult).asRawBits(); 3858 PREDICT_RETURN(); 3859 DISPATCH_CACHEOP(); 3860 } 3861 3862 CACHEOP_CASE(NumberMinMax) { 3863 auto args = cacheIRReader.argsForNumberMinMax(); 3864 BOUNDSCHECK(args.resultId); 3865 double first = READ_VALUE_REG(args.firstId.id()).toNumber(); 3866 double second = READ_VALUE_REG(args.secondId.id()).toNumber(); 3867 double result = DoubleMinMax(args.isMax, first, second); 3868 WRITE_VALUE_REG(args.resultId.id(), DoubleValue(result)); 3869 DISPATCH_CACHEOP(); 3870 } 3871 3872 CACHEOP_CASE(Int32MinMaxArrayResult) { 3873 ObjOperandId arrayId = cacheIRReader.objOperandId(); 3874 bool isMax = cacheIRReader.readBool(); 3875 // ICs that use this opcode depend on implicit unboxing due to 3876 // type-overload on ObjOperandId when a value is loaded 3877 // directly from an argument slot. We explicitly unbox here. 3878 NativeObject* nobj = reinterpret_cast<NativeObject*>( 3879 &READ_VALUE_REG(arrayId.id()).toObject()); 3880 uint32_t len = nobj->getDenseInitializedLength(); 3881 if (len == 0) { 3882 FAIL_IC(); 3883 } 3884 ObjectElements* elems = nobj->getElementsHeader(); 3885 int32_t accum = 0; 3886 for (uint32_t i = 0; i < len; i++) { 3887 HeapSlot* slot = &elems->elements()[i]; 3888 Value val = slot->get(); 3889 if (!val.isInt32()) { 3890 FAIL_IC(); 3891 } 3892 int32_t valInt = val.toInt32(); 3893 if (i > 0) { 3894 accum = isMax ? ((valInt > accum) ? valInt : accum) 3895 : ((valInt < accum) ? valInt : accum); 3896 } else { 3897 accum = valInt; 3898 } 3899 } 3900 retValue = Int32Value(accum).asRawBits(); 3901 PREDICT_RETURN(); 3902 DISPATCH_CACHEOP(); 3903 } 3904 3905 CACHEOP_CASE(NumberMinMaxArrayResult) { 3906 ObjOperandId arrayId = cacheIRReader.objOperandId(); 3907 bool isMax = cacheIRReader.readBool(); 3908 // ICs that use this opcode depend on implicit unboxing due to 3909 // type-overload on ObjOperandId when a value is loaded 3910 // directly from an argument slot. We explicitly unbox here. 3911 NativeObject* nobj = reinterpret_cast<NativeObject*>( 3912 &READ_VALUE_REG(arrayId.id()).toObject()); 3913 uint32_t len = nobj->getDenseInitializedLength(); 3914 if (len == 0) { 3915 FAIL_IC(); 3916 } 3917 ObjectElements* elems = nobj->getElementsHeader(); 3918 double accum = 0; 3919 for (uint32_t i = 0; i < len; i++) { 3920 HeapSlot* slot = &elems->elements()[i]; 3921 Value val = slot->get(); 3922 if (!val.isNumber()) { 3923 FAIL_IC(); 3924 } 3925 double valDouble = val.toNumber(); 3926 if (i > 0) { 3927 accum = DoubleMinMax(isMax, accum, valDouble); 3928 } else { 3929 accum = valDouble; 3930 } 3931 } 3932 retValue = DoubleValue(accum).asRawBits(); 3933 PREDICT_RETURN(); 3934 DISPATCH_CACHEOP(); 3935 } 3936 3937 CACHEOP_CASE(MathFunctionNumberResult) { 3938 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3939 UnaryMathFunction fun = cacheIRReader.unaryMathFunction(); 3940 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3941 auto funPtr = GetUnaryMathFunctionPtr(fun); 3942 retValue = DoubleValue(funPtr(input)).asRawBits(); 3943 PREDICT_RETURN(); 3944 DISPATCH_CACHEOP(); 3945 } 3946 3947 CACHEOP_CASE(NumberParseIntResult) { 3948 StringOperandId strId = cacheIRReader.stringOperandId(); 3949 Int32OperandId radixId = cacheIRReader.int32OperandId(); 3950 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 3951 int32_t radix = int32_t(READ_REG(radixId.id())); 3952 { 3953 PUSH_IC_FRAME(); 3954 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 3955 ReservedRooted<Value> result(&ctx.state.value0); 3956 if (!NumberParseInt(cx, str0, radix, &result)) { 3957 ctx.error = PBIResult::Error; 3958 return IC_ERROR_SENTINEL(); 3959 } 3960 retValue = result.asRawBits(); 3961 } 3962 PREDICT_RETURN(); 3963 DISPATCH_CACHEOP(); 3964 } 3965 3966 CACHEOP_CASE(DoubleParseIntResult) { 3967 NumberOperandId inputId = cacheIRReader.numberOperandId(); 3968 double input = READ_VALUE_REG(inputId.id()).toNumber(); 3969 if (std::isnan(input)) { 3970 FAIL_IC(); 3971 } 3972 int32_t result = int32_t(input); 3973 if (double(result) != input) { 3974 FAIL_IC(); 3975 } 3976 retValue = Int32Value(result).asRawBits(); 3977 PREDICT_RETURN(); 3978 DISPATCH_CACHEOP(); 3979 } 3980 3981 CACHEOP_CASE(GuardTagNotEqual) { 3982 ValueTagOperandId lhsId = cacheIRReader.valueTagOperandId(); 3983 ValueTagOperandId rhsId = cacheIRReader.valueTagOperandId(); 3984 int32_t lhs = int32_t(READ_REG(lhsId.id())); 3985 int32_t rhs = int32_t(READ_REG(rhsId.id())); 3986 if (lhs == rhs) { 3987 FAIL_IC(); 3988 } 3989 if (JSValueTag(lhs) <= JSVAL_TAG_INT32 || 3990 JSValueTag(rhs) <= JSVAL_TAG_INT32) { 3991 FAIL_IC(); 3992 } 3993 DISPATCH_CACHEOP(); 3994 } 3995 3996 CACHEOP_CASE(GuardNumberToIntPtrIndex) { 3997 auto args = cacheIRReader.argsForGuardNumberToIntPtrIndex(); 3998 BOUNDSCHECK(args.resultId); 3999 double input = READ_VALUE_REG(args.inputId.id()).toNumber(); 4000 // For simplicity, support only uint32 range for now. This 4001 // covers 32-bit and 64-bit systems. 4002 if (input < 0.0 || input >= (uint64_t(1) << 32)) { 4003 FAIL_IC(); 4004 } 4005 uintptr_t result = static_cast<uintptr_t>(input); 4006 // Convert back and compare to detect rounded fractional 4007 // parts. 4008 if (static_cast<double>(result) != input) { 4009 FAIL_IC(); 4010 } 4011 WRITE_REG(args.resultId.id(), uint64_t(result), OBJECT); 4012 DISPATCH_CACHEOP(); 4013 } 4014 4015 CACHEOP_CASE(LoadTypeOfObjectResult) { 4016 ObjOperandId objId = cacheIRReader.objOperandId(); 4017 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4018 const JSClass* cls = obj->getClass(); 4019 if (cls->isProxyObject()) { 4020 FAIL_IC(); 4021 } 4022 if (obj->is<JSFunction>()) { 4023 retValue = 4024 StringValue(ctx.frameMgr.cxForLocalUseOnly()->names().function) 4025 .asRawBits(); 4026 } else if (cls->emulatesUndefined()) { 4027 retValue = 4028 StringValue(ctx.frameMgr.cxForLocalUseOnly()->names().undefined) 4029 .asRawBits(); 4030 } else { 4031 retValue = 4032 StringValue(ctx.frameMgr.cxForLocalUseOnly()->names().object) 4033 .asRawBits(); 4034 } 4035 PREDICT_RETURN(); 4036 DISPATCH_CACHEOP(); 4037 } 4038 4039 CACHEOP_CASE(PackedArrayPopResult) { 4040 ObjOperandId objId = cacheIRReader.objOperandId(); 4041 ArrayObject* aobj = 4042 reinterpret_cast<ArrayObject*>(READ_REG(objId.id())); 4043 ObjectElements* elements = aobj->getElementsHeader(); 4044 if (!elements->isPacked() || elements->hasNonwritableArrayLength() || 4045 elements->isNotExtensible() || elements->maybeInIteration()) { 4046 FAIL_IC(); 4047 } 4048 size_t len = aobj->length(); 4049 if (len != aobj->getDenseInitializedLength()) { 4050 FAIL_IC(); 4051 } 4052 if (len == 0) { 4053 retValue = UndefinedValue().asRawBits(); 4054 } else { 4055 HeapSlot* slot = &elements->elements()[len - 1]; 4056 retValue = slot->get().asRawBits(); 4057 len--; 4058 aobj->setDenseInitializedLength(len); 4059 aobj->setLengthToInitializedLength(); 4060 } 4061 PREDICT_RETURN(); 4062 DISPATCH_CACHEOP(); 4063 } 4064 4065 CACHEOP_CASE(PackedArrayShiftResult) { 4066 ObjOperandId objId = cacheIRReader.objOperandId(); 4067 ArrayObject* aobj = 4068 reinterpret_cast<ArrayObject*>(READ_REG(objId.id())); 4069 ObjectElements* elements = aobj->getElementsHeader(); 4070 if (!elements->isPacked() || elements->hasNonwritableArrayLength() || 4071 elements->isNotExtensible() || elements->maybeInIteration()) { 4072 FAIL_IC(); 4073 } 4074 size_t len = aobj->length(); 4075 if (len != aobj->getDenseInitializedLength()) { 4076 FAIL_IC(); 4077 } 4078 if (len == 0) { 4079 retValue = UndefinedValue().asRawBits(); 4080 } else { 4081 HeapSlot* slot = &elements->elements()[0]; 4082 retValue = slot->get().asRawBits(); 4083 ArrayShiftMoveElements(aobj); 4084 } 4085 PREDICT_RETURN(); 4086 DISPATCH_CACHEOP(); 4087 } 4088 4089 CACHEOP_CASE(PackedArraySliceResult) { 4090 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 4091 ObjOperandId arrayId = cacheIRReader.objOperandId(); 4092 Int32OperandId beginId = cacheIRReader.int32OperandId(); 4093 Int32OperandId endId = cacheIRReader.int32OperandId(); 4094 (void)templateObjectOffset; 4095 ArrayObject* aobj = 4096 reinterpret_cast<ArrayObject*>(READ_REG(arrayId.id())); 4097 int32_t begin = int32_t(READ_REG(beginId.id())); 4098 int32_t end = int32_t(READ_REG(endId.id())); 4099 if (!aobj->getElementsHeader()->isPacked()) { 4100 FAIL_IC(); 4101 } 4102 { 4103 PUSH_IC_FRAME(); 4104 ReservedRooted<JSObject*> arr(&ctx.state.obj0, aobj); 4105 JSObject* ret = ArraySliceDense(cx, arr, begin, end, nullptr); 4106 if (!ret) { 4107 FAIL_IC(); 4108 } 4109 retValue = ObjectValue(*ret).asRawBits(); 4110 } 4111 PREDICT_RETURN(); 4112 DISPATCH_CACHEOP(); 4113 } 4114 4115 CACHEOP_CASE(IsPackedArrayResult) { 4116 ObjOperandId objId = cacheIRReader.objOperandId(); 4117 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4118 if (!obj->is<ArrayObject>()) { 4119 retValue = BooleanValue(false).asRawBits(); 4120 PREDICT_RETURN(); 4121 DISPATCH_CACHEOP(); 4122 } 4123 ArrayObject* aobj = 4124 reinterpret_cast<ArrayObject*>(READ_REG(objId.id())); 4125 if (aobj->length() != aobj->getDenseInitializedLength()) { 4126 retValue = BooleanValue(false).asRawBits(); 4127 PREDICT_RETURN(); 4128 DISPATCH_CACHEOP(); 4129 } 4130 retValue = BooleanValue(aobj->denseElementsArePacked()).asRawBits(); 4131 PREDICT_RETURN(); 4132 DISPATCH_CACHEOP(); 4133 } 4134 4135 CACHEOP_CASE(LoadArgumentsObjectLengthResult) { 4136 ObjOperandId objId = cacheIRReader.objOperandId(); 4137 ArgumentsObject* obj = 4138 reinterpret_cast<ArgumentsObject*>(READ_REG(objId.id())); 4139 if (obj->hasOverriddenLength()) { 4140 FAIL_IC(); 4141 } 4142 retValue = Int32Value(obj->initialLength()).asRawBits(); 4143 PREDICT_RETURN(); 4144 DISPATCH_CACHEOP(); 4145 } 4146 4147 CACHEOP_CASE(LoadArgumentsObjectLength) { 4148 ObjOperandId objId = cacheIRReader.objOperandId(); 4149 Int32OperandId resultId = cacheIRReader.int32OperandId(); 4150 BOUNDSCHECK(resultId); 4151 ArgumentsObject* obj = 4152 reinterpret_cast<ArgumentsObject*>(READ_REG(objId.id())); 4153 if (obj->hasOverriddenLength()) { 4154 FAIL_IC(); 4155 } 4156 WRITE_REG(resultId.id(), obj->initialLength(), INT32); 4157 DISPATCH_CACHEOP(); 4158 } 4159 4160 CACHEOP_CASE(ObjectToIteratorResult) { 4161 ObjOperandId objId = cacheIRReader.objOperandId(); 4162 uint32_t enumeratorsAddr = cacheIRReader.stubOffset(); 4163 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4164 (void)enumeratorsAddr; 4165 { 4166 PUSH_IC_FRAME(); 4167 ReservedRooted<JSObject*> rootedObj(&ctx.state.obj0, obj); 4168 auto* iter = GetIterator(cx, rootedObj); 4169 if (!iter) { 4170 ctx.error = PBIResult::Error; 4171 return IC_ERROR_SENTINEL(); 4172 } 4173 retValue = ObjectValue(*iter).asRawBits(); 4174 } 4175 PREDICT_RETURN(); 4176 DISPATCH_CACHEOP(); 4177 } 4178 4179 CACHEOP_CASE(LoadUndefinedResult) { 4180 retValue = UndefinedValue().asRawBits(); 4181 PREDICT_RETURN(); 4182 DISPATCH_CACHEOP(); 4183 } 4184 4185 CACHEOP_CASE(LoadDoubleConstant) { 4186 uint32_t valOffset = cacheIRReader.stubOffset(); 4187 NumberOperandId resultId = cacheIRReader.numberOperandId(); 4188 BOUNDSCHECK(resultId); 4189 WRITE_VALUE_REG( 4190 resultId.id(), 4191 Value::fromRawBits(stubInfo->getStubRawInt64(cstub, valOffset))); 4192 DISPATCH_CACHEOP(); 4193 } 4194 4195 CACHEOP_CASE(LoadBooleanConstant) { 4196 bool val = cacheIRReader.readBool(); 4197 BooleanOperandId resultId = cacheIRReader.booleanOperandId(); 4198 BOUNDSCHECK(resultId); 4199 WRITE_REG(resultId.id(), val ? 1 : 0, BOOLEAN); 4200 DISPATCH_CACHEOP(); 4201 } 4202 4203 CACHEOP_CASE(LoadUndefined) { 4204 ValOperandId resultId = cacheIRReader.numberOperandId(); 4205 BOUNDSCHECK(resultId); 4206 WRITE_VALUE_REG(resultId.id(), UndefinedValue()); 4207 DISPATCH_CACHEOP(); 4208 } 4209 4210 CACHEOP_CASE(LoadConstantString) { 4211 uint32_t valOffset = cacheIRReader.stubOffset(); 4212 StringOperandId resultId = cacheIRReader.stringOperandId(); 4213 BOUNDSCHECK(resultId); 4214 JSString* str = reinterpret_cast<JSString*>( 4215 stubInfo->getStubRawWord(cstub, valOffset)); 4216 WRITE_REG(resultId.id(), reinterpret_cast<uint64_t>(str), STRING); 4217 DISPATCH_CACHEOP(); 4218 } 4219 4220 CACHEOP_CASE(NewPlainObjectResult) { 4221 auto args = cacheIRReader.argsForNewPlainObjectResult(); 4222 SharedShape* shape = reinterpret_cast<SharedShape*>( 4223 stubInfo->getStubRawWord(cstub, args.shapeOffset)); 4224 gc::AllocSite* site = reinterpret_cast<gc::AllocSite*>( 4225 stubInfo->getStubRawWord(cstub, args.siteOffset)); 4226 { 4227 PUSH_IC_FRAME(); 4228 Rooted<SharedShape*> rootedShape(cx, shape); 4229 auto* result = NewPlainObjectBaselineFallback(cx, rootedShape, 4230 args.allocKind, site); 4231 if (!result) { 4232 ctx.error = PBIResult::Error; 4233 return IC_ERROR_SENTINEL(); 4234 } 4235 retValue = ObjectValue(*result).asRawBits(); 4236 } 4237 PREDICT_RETURN(); 4238 DISPATCH_CACHEOP(); 4239 } 4240 4241 CACHEOP_CASE(NewArrayObjectResult) { 4242 uint32_t arrayLength = cacheIRReader.uint32Immediate(); 4243 uint32_t shapeOffset = cacheIRReader.stubOffset(); 4244 uint32_t siteOffset = cacheIRReader.stubOffset(); 4245 (void)shapeOffset; 4246 gc::AllocSite* site = reinterpret_cast<gc::AllocSite*>( 4247 stubInfo->getStubRawWord(cstub, siteOffset)); 4248 gc::AllocKind allocKind = GuessArrayGCKind(arrayLength); 4249 MOZ_ASSERT(gc::GetObjectFinalizeKind(&ArrayObject::class_) == 4250 gc::FinalizeKind::None); 4251 MOZ_ASSERT(!IsFinalizedKind(allocKind)); 4252 { 4253 PUSH_IC_FRAME(); 4254 auto* result = 4255 NewArrayObjectBaselineFallback(cx, arrayLength, allocKind, site); 4256 if (!result) { 4257 ctx.error = PBIResult::Error; 4258 return IC_ERROR_SENTINEL(); 4259 } 4260 retValue = ObjectValue(*result).asRawBits(); 4261 } 4262 PREDICT_RETURN(); 4263 DISPATCH_CACHEOP(); 4264 } 4265 4266 CACHEOP_CASE(NewArrayFromLengthResult) { 4267 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 4268 Int32OperandId lengthId = cacheIRReader.int32OperandId(); 4269 uint32_t siteOffset = cacheIRReader.stubOffset(); 4270 ArrayObject* templateObject = reinterpret_cast<ArrayObject*>( 4271 stubInfo->getStubRawWord(cstub, templateObjectOffset)); 4272 gc::AllocSite* site = reinterpret_cast<gc::AllocSite*>( 4273 stubInfo->getStubRawWord(cstub, siteOffset)); 4274 int32_t length = int32_t(READ_REG(lengthId.id())); 4275 { 4276 PUSH_IC_FRAME(); 4277 Rooted<ArrayObject*> templateObjectRooted(cx, templateObject); 4278 auto* result = 4279 ArrayConstructorOneArg(cx, templateObjectRooted, length, site); 4280 if (!result) { 4281 ctx.error = PBIResult::Error; 4282 return IC_ERROR_SENTINEL(); 4283 } 4284 retValue = ObjectValue(*result).asRawBits(); 4285 } 4286 PREDICT_RETURN(); 4287 DISPATCH_CACHEOP(); 4288 } 4289 4290 CACHEOP_CASE(NewTypedArrayFromLengthResult) { 4291 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 4292 Int32OperandId lengthId = cacheIRReader.int32OperandId(); 4293 TypedArrayObject* templateObject = reinterpret_cast<TypedArrayObject*>( 4294 stubInfo->getStubRawWord(cstub, templateObjectOffset)); 4295 int32_t length = int32_t(READ_REG(lengthId.id())); 4296 { 4297 PUSH_IC_FRAME(); 4298 ReservedRooted<JSObject*> templateObjectRooted(&ctx.state.obj0, 4299 templateObject); 4300 auto* result = NewTypedArrayWithTemplateAndLength( 4301 cx, templateObjectRooted, length); 4302 if (!result) { 4303 ctx.error = PBIResult::Error; 4304 return IC_ERROR_SENTINEL(); 4305 } 4306 retValue = ObjectValue(*result).asRawBits(); 4307 } 4308 PREDICT_RETURN(); 4309 DISPATCH_CACHEOP(); 4310 } 4311 4312 CACHEOP_CASE(NewTypedArrayFromArrayBufferResult) { 4313 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 4314 ObjOperandId bufferId = cacheIRReader.objOperandId(); 4315 ValOperandId byteOffsetId = cacheIRReader.valOperandId(); 4316 ValOperandId lengthId = cacheIRReader.valOperandId(); 4317 TypedArrayObject* templateObject = reinterpret_cast<TypedArrayObject*>( 4318 stubInfo->getStubRawWord(cstub, templateObjectOffset)); 4319 JSObject* buffer = reinterpret_cast<JSObject*>(READ_REG(bufferId.id())); 4320 Value byteOffset = READ_VALUE_REG(byteOffsetId.id()); 4321 Value length = READ_VALUE_REG(lengthId.id()); 4322 { 4323 PUSH_IC_FRAME(); 4324 ReservedRooted<JSObject*> templateObjectRooted(&ctx.state.obj0, 4325 templateObject); 4326 ReservedRooted<JSObject*> bufferRooted(&ctx.state.obj1, buffer); 4327 ReservedRooted<Value> byteOffsetRooted(&ctx.state.value0, byteOffset); 4328 ReservedRooted<Value> lengthRooted(&ctx.state.value1, length); 4329 auto* result = NewTypedArrayWithTemplateAndBuffer( 4330 cx, templateObjectRooted, bufferRooted, byteOffsetRooted, 4331 lengthRooted); 4332 if (!result) { 4333 ctx.error = PBIResult::Error; 4334 return IC_ERROR_SENTINEL(); 4335 } 4336 retValue = ObjectValue(*result).asRawBits(); 4337 } 4338 PREDICT_RETURN(); 4339 DISPATCH_CACHEOP(); 4340 } 4341 4342 CACHEOP_CASE(NewTypedArrayFromArrayResult) { 4343 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 4344 ObjOperandId arrayId = cacheIRReader.objOperandId(); 4345 TypedArrayObject* templateObject = reinterpret_cast<TypedArrayObject*>( 4346 stubInfo->getStubRawWord(cstub, templateObjectOffset)); 4347 JSObject* array = reinterpret_cast<JSObject*>(READ_REG(arrayId.id())); 4348 { 4349 PUSH_IC_FRAME(); 4350 ReservedRooted<JSObject*> templateObjectRooted(&ctx.state.obj0, 4351 templateObject); 4352 ReservedRooted<JSObject*> arrayRooted(&ctx.state.obj1, array); 4353 auto* result = NewTypedArrayWithTemplateAndArray( 4354 cx, templateObjectRooted, arrayRooted); 4355 if (!result) { 4356 ctx.error = PBIResult::Error; 4357 return IC_ERROR_SENTINEL(); 4358 } 4359 retValue = ObjectValue(*result).asRawBits(); 4360 } 4361 PREDICT_RETURN(); 4362 DISPATCH_CACHEOP(); 4363 } 4364 4365 CACHEOP_CASE(ObjectToStringResult) { 4366 ObjOperandId objId = cacheIRReader.objOperandId(); 4367 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4368 { 4369 PUSH_IC_FRAME(); 4370 auto* result = ObjectClassToString(cx, obj); 4371 if (!result) { 4372 FAIL_IC(); 4373 } 4374 retValue = StringValue(result).asRawBits(); 4375 } 4376 PREDICT_RETURN(); 4377 DISPATCH_CACHEOP(); 4378 } 4379 4380 CACHEOP_CASE(CallNativeGetterResult) { 4381 ValOperandId receiverId = cacheIRReader.valOperandId(); 4382 uint32_t getterOffset = cacheIRReader.stubOffset(); 4383 bool sameRealm = cacheIRReader.readBool(); 4384 uint32_t nargsAndFlagsOffset = cacheIRReader.stubOffset(); 4385 (void)sameRealm; 4386 (void)nargsAndFlagsOffset; 4387 Value receiver = READ_VALUE_REG(receiverId.id()); 4388 JSFunction* getter = reinterpret_cast<JSFunction*>( 4389 stubInfo->getStubRawWord(cstub, getterOffset)); 4390 { 4391 PUSH_IC_FRAME(); 4392 ReservedRooted<JSFunction*> getterRooted(&ctx.state.fun0, getter); 4393 ReservedRooted<Value> receiverRooted(&ctx.state.value0, receiver); 4394 ReservedRooted<Value> resultRooted(&ctx.state.value1); 4395 if (!CallNativeGetter(cx, getterRooted, receiverRooted, 4396 &resultRooted)) { 4397 ctx.error = PBIResult::Error; 4398 return IC_ERROR_SENTINEL(); 4399 } 4400 retValue = resultRooted.asRawBits(); 4401 } 4402 PREDICT_RETURN(); 4403 DISPATCH_CACHEOP(); 4404 } 4405 4406 CACHEOP_CASE(CallNativeSetter) { 4407 ValOperandId receiverId = cacheIRReader.valOperandId(); 4408 uint32_t setterOffset = cacheIRReader.stubOffset(); 4409 ObjOperandId rhsId = cacheIRReader.objOperandId(); 4410 bool sameRealm = cacheIRReader.readBool(); 4411 uint32_t nargsAndFlagsOffset = cacheIRReader.stubOffset(); 4412 (void)sameRealm; 4413 (void)nargsAndFlagsOffset; 4414 JSObject* receiver = 4415 reinterpret_cast<JSObject*>(READ_REG(receiverId.id())); 4416 Value rhs = READ_VALUE_REG(rhsId.id()); 4417 JSFunction* setter = reinterpret_cast<JSFunction*>( 4418 stubInfo->getStubRawWord(cstub, setterOffset)); 4419 { 4420 PUSH_IC_FRAME(); 4421 ReservedRooted<JSFunction*> setterRooted(&ctx.state.fun0, setter); 4422 ReservedRooted<JSObject*> receiverRooted(&ctx.state.obj0, receiver); 4423 ReservedRooted<Value> rhsRooted(&ctx.state.value1, rhs); 4424 if (!CallNativeSetter(cx, setterRooted, receiverRooted, rhsRooted)) { 4425 ctx.error = PBIResult::Error; 4426 return IC_ERROR_SENTINEL(); 4427 } 4428 } 4429 PREDICT_RETURN(); 4430 DISPATCH_CACHEOP(); 4431 } 4432 4433 CACHEOP_CASE(LoadInstanceOfObjectResult) { 4434 ValOperandId lhsId = cacheIRReader.valOperandId(); 4435 ObjOperandId protoId = cacheIRReader.objOperandId(); 4436 Value lhs = READ_VALUE_REG(lhsId.id()); 4437 JSObject* rhsProto = 4438 reinterpret_cast<JSObject*>(READ_REG(protoId.id())); 4439 if (!lhs.isObject()) { 4440 retValue = BooleanValue(false).asRawBits(); 4441 PREDICT_RETURN(); 4442 DISPATCH_CACHEOP(); 4443 } 4444 4445 JSObject* lhsObj = &lhs.toObject(); 4446 bool result = false; 4447 while (true) { 4448 TaggedProto proto = lhsObj->taggedProto(); 4449 if (proto.isDynamic()) { 4450 FAIL_IC(); 4451 } 4452 JSObject* protoObj = proto.toObjectOrNull(); 4453 if (!protoObj) { 4454 result = false; 4455 break; 4456 } 4457 if (protoObj == rhsProto) { 4458 result = true; 4459 break; 4460 } 4461 lhsObj = protoObj; 4462 } 4463 retValue = BooleanValue(result).asRawBits(); 4464 PREDICT_RETURN(); 4465 DISPATCH_CACHEOP(); 4466 } 4467 4468 CACHEOP_CASE(StringFromCharCodeResult) { 4469 Int32OperandId codeId = cacheIRReader.int32OperandId(); 4470 uint32_t code = uint32_t(READ_REG(codeId.id())); 4471 StaticStrings& sstr = ctx.frameMgr.cxForLocalUseOnly()->staticStrings(); 4472 if (sstr.hasUnit(code)) { 4473 retValue = StringValue(sstr.getUnit(code)).asRawBits(); 4474 } else { 4475 PUSH_IC_FRAME(); 4476 auto* result = StringFromCharCode(cx, code); 4477 if (!result) { 4478 FAIL_IC(); 4479 } 4480 retValue = StringValue(result).asRawBits(); 4481 } 4482 PREDICT_RETURN(); 4483 DISPATCH_CACHEOP(); 4484 } 4485 4486 CACHEOP_CASE(StringFromCodePointResult) { 4487 Int32OperandId codeId = cacheIRReader.int32OperandId(); 4488 uint32_t code = uint32_t(READ_REG(codeId.id())); 4489 if (code > unicode::NonBMPMax) { 4490 FAIL_IC(); 4491 } 4492 StaticStrings& sstr = ctx.frameMgr.cxForLocalUseOnly()->staticStrings(); 4493 if (sstr.hasUnit(code)) { 4494 retValue = StringValue(sstr.getUnit(code)).asRawBits(); 4495 } else { 4496 PUSH_IC_FRAME(); 4497 auto* result = StringFromCodePoint(cx, code); 4498 if (!result) { 4499 FAIL_IC(); 4500 } 4501 retValue = StringValue(result).asRawBits(); 4502 } 4503 PREDICT_RETURN(); 4504 DISPATCH_CACHEOP(); 4505 } 4506 4507 CACHEOP_CASE(StringIncludesResult) { 4508 StringOperandId strId = cacheIRReader.stringOperandId(); 4509 StringOperandId searchStrId = cacheIRReader.stringOperandId(); 4510 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4511 JSString* searchStr = 4512 reinterpret_cast<JSString*>(READ_REG(searchStrId.id())); 4513 { 4514 PUSH_IC_FRAME(); 4515 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4516 ReservedRooted<JSString*> str1(&ctx.state.str1, searchStr); 4517 bool result = false; 4518 if (!StringIncludes(cx, str0, str1, &result)) { 4519 ctx.error = PBIResult::Error; 4520 return IC_ERROR_SENTINEL(); 4521 } 4522 retValue = BooleanValue(result).asRawBits(); 4523 } 4524 PREDICT_RETURN(); 4525 DISPATCH_CACHEOP(); 4526 } 4527 4528 CACHEOP_CASE(StringIndexOfResult) { 4529 StringOperandId strId = cacheIRReader.stringOperandId(); 4530 StringOperandId searchStrId = cacheIRReader.stringOperandId(); 4531 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4532 JSString* searchStr = 4533 reinterpret_cast<JSString*>(READ_REG(searchStrId.id())); 4534 { 4535 PUSH_IC_FRAME(); 4536 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4537 ReservedRooted<JSString*> str1(&ctx.state.str1, searchStr); 4538 int32_t result = 0; 4539 if (!StringIndexOf(cx, str0, str1, &result)) { 4540 ctx.error = PBIResult::Error; 4541 return IC_ERROR_SENTINEL(); 4542 } 4543 retValue = Int32Value(result).asRawBits(); 4544 } 4545 PREDICT_RETURN(); 4546 DISPATCH_CACHEOP(); 4547 } 4548 4549 CACHEOP_CASE(StringLastIndexOfResult) { 4550 StringOperandId strId = cacheIRReader.stringOperandId(); 4551 StringOperandId searchStrId = cacheIRReader.stringOperandId(); 4552 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4553 JSString* searchStr = 4554 reinterpret_cast<JSString*>(READ_REG(searchStrId.id())); 4555 { 4556 PUSH_IC_FRAME(); 4557 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4558 ReservedRooted<JSString*> str1(&ctx.state.str1, searchStr); 4559 int32_t result = 0; 4560 if (!StringLastIndexOf(cx, str0, str1, &result)) { 4561 ctx.error = PBIResult::Error; 4562 return IC_ERROR_SENTINEL(); 4563 } 4564 retValue = Int32Value(result).asRawBits(); 4565 } 4566 PREDICT_RETURN(); 4567 DISPATCH_CACHEOP(); 4568 } 4569 4570 CACHEOP_CASE(StringStartsWithResult) { 4571 StringOperandId strId = cacheIRReader.stringOperandId(); 4572 StringOperandId searchStrId = cacheIRReader.stringOperandId(); 4573 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4574 JSString* searchStr = 4575 reinterpret_cast<JSString*>(READ_REG(searchStrId.id())); 4576 { 4577 PUSH_IC_FRAME(); 4578 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4579 ReservedRooted<JSString*> str1(&ctx.state.str1, searchStr); 4580 bool result = false; 4581 if (!StringStartsWith(cx, str0, str1, &result)) { 4582 ctx.error = PBIResult::Error; 4583 return IC_ERROR_SENTINEL(); 4584 } 4585 retValue = BooleanValue(result).asRawBits(); 4586 } 4587 PREDICT_RETURN(); 4588 DISPATCH_CACHEOP(); 4589 } 4590 4591 CACHEOP_CASE(StringEndsWithResult) { 4592 StringOperandId strId = cacheIRReader.stringOperandId(); 4593 StringOperandId searchStrId = cacheIRReader.stringOperandId(); 4594 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4595 JSString* searchStr = 4596 reinterpret_cast<JSString*>(READ_REG(searchStrId.id())); 4597 { 4598 PUSH_IC_FRAME(); 4599 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4600 ReservedRooted<JSString*> str1(&ctx.state.str1, searchStr); 4601 bool result = false; 4602 if (!StringEndsWith(cx, str0, str1, &result)) { 4603 ctx.error = PBIResult::Error; 4604 return IC_ERROR_SENTINEL(); 4605 } 4606 retValue = BooleanValue(result).asRawBits(); 4607 } 4608 PREDICT_RETURN(); 4609 DISPATCH_CACHEOP(); 4610 } 4611 4612 CACHEOP_CASE(StringToLowerCaseResult) { 4613 StringOperandId strId = cacheIRReader.stringOperandId(); 4614 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4615 { 4616 PUSH_IC_FRAME(); 4617 auto* result = StringToLowerCase(cx, str); 4618 if (!result) { 4619 ctx.error = PBIResult::Error; 4620 return IC_ERROR_SENTINEL(); 4621 } 4622 retValue = StringValue(result).asRawBits(); 4623 } 4624 PREDICT_RETURN(); 4625 DISPATCH_CACHEOP(); 4626 } 4627 4628 CACHEOP_CASE(StringToUpperCaseResult) { 4629 StringOperandId strId = cacheIRReader.stringOperandId(); 4630 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4631 { 4632 PUSH_IC_FRAME(); 4633 auto* result = StringToUpperCase(cx, str); 4634 if (!result) { 4635 ctx.error = PBIResult::Error; 4636 return IC_ERROR_SENTINEL(); 4637 } 4638 retValue = StringValue(result).asRawBits(); 4639 } 4640 PREDICT_RETURN(); 4641 DISPATCH_CACHEOP(); 4642 } 4643 4644 CACHEOP_CASE(StringTrimResult) { 4645 StringOperandId strId = cacheIRReader.stringOperandId(); 4646 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4647 { 4648 PUSH_IC_FRAME(); 4649 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4650 auto* result = StringTrim(cx, str0); 4651 if (!result) { 4652 ctx.error = PBIResult::Error; 4653 return IC_ERROR_SENTINEL(); 4654 } 4655 retValue = StringValue(result).asRawBits(); 4656 } 4657 PREDICT_RETURN(); 4658 DISPATCH_CACHEOP(); 4659 } 4660 4661 CACHEOP_CASE(StringTrimStartResult) { 4662 StringOperandId strId = cacheIRReader.stringOperandId(); 4663 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4664 { 4665 PUSH_IC_FRAME(); 4666 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4667 auto* result = StringTrimStart(cx, str0); 4668 if (!result) { 4669 ctx.error = PBIResult::Error; 4670 return IC_ERROR_SENTINEL(); 4671 } 4672 retValue = StringValue(result).asRawBits(); 4673 } 4674 PREDICT_RETURN(); 4675 DISPATCH_CACHEOP(); 4676 } 4677 4678 CACHEOP_CASE(StringTrimEndResult) { 4679 StringOperandId strId = cacheIRReader.stringOperandId(); 4680 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4681 { 4682 PUSH_IC_FRAME(); 4683 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4684 auto* result = StringTrimEnd(cx, str0); 4685 if (!result) { 4686 ctx.error = PBIResult::Error; 4687 return IC_ERROR_SENTINEL(); 4688 } 4689 retValue = StringValue(result).asRawBits(); 4690 } 4691 PREDICT_RETURN(); 4692 DISPATCH_CACHEOP(); 4693 } 4694 4695 CACHEOP_CASE(CallSubstringKernelResult) { 4696 StringOperandId strId = cacheIRReader.stringOperandId(); 4697 Int32OperandId beginId = cacheIRReader.int32OperandId(); 4698 Int32OperandId lengthId = cacheIRReader.int32OperandId(); 4699 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4700 int32_t begin = int32_t(READ_REG(beginId.id())); 4701 int32_t length = int32_t(READ_REG(lengthId.id())); 4702 { 4703 PUSH_IC_FRAME(); 4704 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4705 auto* result = SubstringKernel(cx, str0, begin, length); 4706 if (!result) { 4707 ctx.error = PBIResult::Error; 4708 return IC_ERROR_SENTINEL(); 4709 } 4710 retValue = StringValue(result).asRawBits(); 4711 } 4712 PREDICT_RETURN(); 4713 DISPATCH_CACHEOP(); 4714 } 4715 4716 CACHEOP_CASE(StringReplaceStringResult) { 4717 StringOperandId strId = cacheIRReader.stringOperandId(); 4718 StringOperandId patternId = cacheIRReader.stringOperandId(); 4719 StringOperandId replacementId = cacheIRReader.stringOperandId(); 4720 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4721 JSString* pattern = 4722 reinterpret_cast<JSString*>(READ_REG(patternId.id())); 4723 JSString* replacement = 4724 reinterpret_cast<JSString*>(READ_REG(replacementId.id())); 4725 { 4726 PUSH_IC_FRAME(); 4727 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4728 ReservedRooted<JSString*> str1(&ctx.state.str1, pattern); 4729 ReservedRooted<JSString*> str2(&ctx.state.str2, replacement); 4730 auto* result = StringReplace(cx, str0, str1, str2); 4731 if (!result) { 4732 ctx.error = PBIResult::Error; 4733 return IC_ERROR_SENTINEL(); 4734 } 4735 retValue = StringValue(result).asRawBits(); 4736 } 4737 PREDICT_RETURN(); 4738 DISPATCH_CACHEOP(); 4739 } 4740 4741 CACHEOP_CASE(StringSplitStringResult) { 4742 StringOperandId strId = cacheIRReader.stringOperandId(); 4743 StringOperandId separatorId = cacheIRReader.stringOperandId(); 4744 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4745 JSString* separator = 4746 reinterpret_cast<JSString*>(READ_REG(separatorId.id())); 4747 { 4748 PUSH_IC_FRAME(); 4749 ReservedRooted<JSString*> str0(&ctx.state.str0, str); 4750 ReservedRooted<JSString*> str1(&ctx.state.str1, separator); 4751 auto* result = StringSplitString(cx, str0, str1, INT32_MAX); 4752 if (!result) { 4753 ctx.error = PBIResult::Error; 4754 return IC_ERROR_SENTINEL(); 4755 } 4756 retValue = ObjectValue(*result).asRawBits(); 4757 } 4758 PREDICT_RETURN(); 4759 DISPATCH_CACHEOP(); 4760 } 4761 4762 CACHEOP_CASE(StringToAtom) { 4763 StringOperandId strId = cacheIRReader.stringOperandId(); 4764 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 4765 JSAtom* result = 4766 AtomizeStringNoGC(ctx.frameMgr.cxForLocalUseOnly(), str); 4767 if (!result) { 4768 FAIL_IC(); 4769 } 4770 WRITE_REG(strId.id(), reinterpret_cast<uint64_t>(result), STRING); 4771 DISPATCH_CACHEOP(); 4772 } 4773 4774 CACHEOP_CASE(IdToStringOrSymbol) { 4775 ValOperandId resultId = cacheIRReader.valOperandId(); 4776 ValOperandId idId = cacheIRReader.valOperandId(); 4777 BOUNDSCHECK(resultId); 4778 Value id = READ_VALUE_REG(idId.id()); 4779 if (id.isString() || id.isSymbol()) { 4780 WRITE_VALUE_REG(resultId.id(), id); 4781 } else if (id.isInt32()) { 4782 int32_t idInt = id.toInt32(); 4783 StaticStrings& sstr = 4784 ctx.frameMgr.cxForLocalUseOnly()->staticStrings(); 4785 if (sstr.hasInt(idInt)) { 4786 WRITE_VALUE_REG(resultId.id(), StringValue(sstr.getInt(idInt))); 4787 } else { 4788 PUSH_IC_FRAME(); 4789 auto* result = Int32ToStringPure(cx, idInt); 4790 if (!result) { 4791 ctx.error = PBIResult::Error; 4792 return IC_ERROR_SENTINEL(); 4793 } 4794 WRITE_VALUE_REG(resultId.id(), StringValue(result)); 4795 } 4796 } else { 4797 FAIL_IC(); 4798 } 4799 DISPATCH_CACHEOP(); 4800 } 4801 4802 CACHEOP_CASE(NewStringIteratorResult) { 4803 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 4804 (void)templateObjectOffset; 4805 { 4806 PUSH_IC_FRAME(); 4807 auto* result = NewStringIterator(cx); 4808 if (!result) { 4809 ctx.error = PBIResult::Error; 4810 return IC_ERROR_SENTINEL(); 4811 } 4812 retValue = ObjectValue(*result).asRawBits(); 4813 } 4814 PREDICT_RETURN(); 4815 DISPATCH_CACHEOP(); 4816 } 4817 4818 CACHEOP_CASE(IsArrayResult) { 4819 ValOperandId valId = cacheIRReader.valOperandId(); 4820 Value val = READ_VALUE_REG(valId.id()); 4821 if (!val.isObject()) { 4822 retValue = BooleanValue(false).asRawBits(); 4823 } else { 4824 JSObject* obj = &val.toObject(); 4825 if (obj->getClass()->isProxyObject()) { 4826 FAIL_IC(); 4827 } 4828 retValue = BooleanValue(obj->is<ArrayObject>()).asRawBits(); 4829 } 4830 PREDICT_RETURN(); 4831 DISPATCH_CACHEOP(); 4832 } 4833 4834 CACHEOP_CASE(IsCallableResult) { 4835 ValOperandId valId = cacheIRReader.valOperandId(); 4836 Value val = READ_VALUE_REG(valId.id()); 4837 if (!val.isObject()) { 4838 retValue = BooleanValue(false).asRawBits(); 4839 } else { 4840 JSObject* obj = &val.toObject(); 4841 if (obj->getClass()->isProxyObject()) { 4842 FAIL_IC(); 4843 } 4844 bool callable = 4845 obj->is<JSFunction>() || obj->getClass()->getCall() != nullptr; 4846 retValue = BooleanValue(callable).asRawBits(); 4847 } 4848 PREDICT_RETURN(); 4849 DISPATCH_CACHEOP(); 4850 } 4851 4852 CACHEOP_CASE(IsConstructorResult) { 4853 ObjOperandId objId = cacheIRReader.objOperandId(); 4854 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4855 bool ctor = obj->isConstructor(); 4856 retValue = BooleanValue(ctor).asRawBits(); 4857 PREDICT_RETURN(); 4858 DISPATCH_CACHEOP(); 4859 } 4860 4861 CACHEOP_CASE(IsCrossRealmArrayConstructorResult) { 4862 ObjOperandId objId = cacheIRReader.objOperandId(); 4863 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4864 bool result = 4865 obj->shape()->realm() != 4866 ctx.frameMgr.cxForLocalUseOnly()->realm() && 4867 obj->is<JSFunction>() && obj->as<JSFunction>().isNativeFun() && 4868 obj->as<JSFunction>().nativeUnchecked() == &js::ArrayConstructor; 4869 retValue = BooleanValue(result).asRawBits(); 4870 PREDICT_RETURN(); 4871 DISPATCH_CACHEOP(); 4872 } 4873 4874 CACHEOP_CASE(IsTypedArrayResult) { 4875 ObjOperandId objId = cacheIRReader.objOperandId(); 4876 bool isPossiblyWrapped = cacheIRReader.readBool(); 4877 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4878 if (IsTypedArrayClass(obj->getClass())) { 4879 retValue = BooleanValue(true).asRawBits(); 4880 } else if (isPossiblyWrapped && obj->is<WrapperObject>()) { 4881 PUSH_IC_FRAME(); 4882 bool result; 4883 if (!IsPossiblyWrappedTypedArray(cx, obj, &result)) { 4884 ctx.error = PBIResult::Error; 4885 return IC_ERROR_SENTINEL(); 4886 } 4887 retValue = BooleanValue(result).asRawBits(); 4888 } else { 4889 retValue = BooleanValue(false).asRawBits(); 4890 } 4891 PREDICT_RETURN(); 4892 DISPATCH_CACHEOP(); 4893 } 4894 4895 CACHEOP_CASE(IsTypedArrayConstructorResult) { 4896 ObjOperandId objId = cacheIRReader.objOperandId(); 4897 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4898 retValue = BooleanValue(IsTypedArrayConstructor(obj)).asRawBits(); 4899 PREDICT_RETURN(); 4900 DISPATCH_CACHEOP(); 4901 } 4902 4903 CACHEOP_CASE(ArrayBufferViewByteOffsetInt32Result) { 4904 ObjOperandId objId = cacheIRReader.objOperandId(); 4905 ArrayBufferViewObject* abvo = 4906 reinterpret_cast<ArrayBufferViewObject*>(READ_REG(objId.id())); 4907 size_t byteOffset = 4908 size_t(abvo->getFixedSlot(ArrayBufferViewObject::BYTEOFFSET_SLOT) 4909 .toPrivate()); 4910 if (byteOffset > size_t(INT32_MAX)) { 4911 FAIL_IC(); 4912 } 4913 retValue = Int32Value(int32_t(byteOffset)).asRawBits(); 4914 PREDICT_RETURN(); 4915 DISPATCH_CACHEOP(); 4916 } 4917 4918 CACHEOP_CASE(ArrayBufferViewByteOffsetDoubleResult) { 4919 ObjOperandId objId = cacheIRReader.objOperandId(); 4920 ArrayBufferViewObject* abvo = 4921 reinterpret_cast<ArrayBufferViewObject*>(READ_REG(objId.id())); 4922 size_t byteOffset = 4923 size_t(abvo->getFixedSlot(ArrayBufferViewObject::BYTEOFFSET_SLOT) 4924 .toPrivate()); 4925 retValue = DoubleValue(double(byteOffset)).asRawBits(); 4926 PREDICT_RETURN(); 4927 DISPATCH_CACHEOP(); 4928 } 4929 4930 CACHEOP_CASE(TypedArrayByteLengthInt32Result) { 4931 ObjOperandId objId = cacheIRReader.objOperandId(); 4932 TypedArrayObject* tao = 4933 reinterpret_cast<TypedArrayObject*>(READ_REG(objId.id())); 4934 if (!tao->length()) { 4935 FAIL_IC(); 4936 } 4937 size_t length = *tao->length() * tao->bytesPerElement(); 4938 if (length > size_t(INT32_MAX)) { 4939 FAIL_IC(); 4940 } 4941 retValue = Int32Value(int32_t(length)).asRawBits(); 4942 PREDICT_RETURN(); 4943 DISPATCH_CACHEOP(); 4944 } 4945 4946 CACHEOP_CASE(TypedArrayByteLengthDoubleResult) { 4947 ObjOperandId objId = cacheIRReader.objOperandId(); 4948 TypedArrayObject* tao = 4949 reinterpret_cast<TypedArrayObject*>(READ_REG(objId.id())); 4950 if (!tao->length()) { 4951 FAIL_IC(); 4952 } 4953 size_t length = *tao->length() * tao->bytesPerElement(); 4954 retValue = DoubleValue(double(length)).asRawBits(); 4955 PREDICT_RETURN(); 4956 DISPATCH_CACHEOP(); 4957 } 4958 4959 CACHEOP_CASE(MegamorphicStoreSlot) { 4960 ObjOperandId objId = cacheIRReader.objOperandId(); 4961 uint32_t nameOffset = cacheIRReader.stubOffset(); 4962 ValOperandId valId = cacheIRReader.valOperandId(); 4963 bool strict = cacheIRReader.readBool(); 4964 4965 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4966 jsid id = 4967 jsid::fromRawBits(stubInfo->getStubRawWord(cstub, nameOffset)); 4968 Value val = READ_VALUE_REG(valId.id()); 4969 4970 { 4971 PUSH_IC_FRAME(); 4972 ReservedRooted<JSObject*> objRooted(&ctx.state.obj0, obj); 4973 ReservedRooted<jsid> idRooted(&ctx.state.id0, id); 4974 ReservedRooted<Value> valRooted(&ctx.state.value0, val); 4975 if (!SetPropertyMegamorphic<false>(cx, objRooted, idRooted, valRooted, 4976 strict)) { 4977 ctx.error = PBIResult::Error; 4978 return IC_ERROR_SENTINEL(); 4979 } 4980 } 4981 4982 PREDICT_RETURN(); 4983 DISPATCH_CACHEOP(); 4984 } 4985 4986 CACHEOP_CASE(MegamorphicHasPropResult) { 4987 ObjOperandId objId = cacheIRReader.objOperandId(); 4988 ValOperandId valId = cacheIRReader.valOperandId(); 4989 bool hasOwn = cacheIRReader.readBool(); 4990 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 4991 if (!obj->is<NativeObject>()) { 4992 FAIL_IC(); 4993 } 4994 Value val[2] = {READ_VALUE_REG(valId.id()), UndefinedValue()}; 4995 { 4996 PUSH_IC_FRAME(); 4997 bool ok = 4998 hasOwn 4999 ? HasNativeDataPropertyPure<true>(cx, obj, nullptr, &val[0]) 5000 : HasNativeDataPropertyPure<false>(cx, obj, nullptr, &val[0]); 5001 if (!ok) { 5002 FAIL_IC(); 5003 } 5004 retValue = val[1].asRawBits(); 5005 } 5006 PREDICT_RETURN(); 5007 DISPATCH_CACHEOP(); 5008 } 5009 5010 CACHEOP_CASE(ArrayJoinResult) { 5011 ObjOperandId objId = cacheIRReader.objOperandId(); 5012 StringOperandId sepId = cacheIRReader.stringOperandId(); 5013 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 5014 JSString* sep = reinterpret_cast<JSString*>(READ_REG(sepId.id())); 5015 { 5016 PUSH_IC_FRAME(); 5017 ReservedRooted<JSObject*> obj0(&ctx.state.obj0, obj); 5018 ReservedRooted<JSString*> str0(&ctx.state.str0, sep); 5019 auto* result = ArrayJoin(cx, obj0, str0); 5020 if (!result) { 5021 ctx.error = PBIResult::Error; 5022 return IC_ERROR_SENTINEL(); 5023 } 5024 retValue = StringValue(result).asRawBits(); 5025 } 5026 PREDICT_RETURN(); 5027 DISPATCH_CACHEOP(); 5028 } 5029 5030 CACHEOP_CASE(CallSetArrayLength) { 5031 ObjOperandId objId = cacheIRReader.objOperandId(); 5032 bool strict = cacheIRReader.readBool(); 5033 ValOperandId rhsId = cacheIRReader.valOperandId(); 5034 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 5035 Value rhs = READ_VALUE_REG(rhsId.id()); 5036 { 5037 PUSH_IC_FRAME(); 5038 ReservedRooted<JSObject*> obj0(&ctx.state.obj0, obj); 5039 ReservedRooted<Value> value0(&ctx.state.value0, rhs); 5040 if (!SetArrayLength(cx, obj0, value0, strict)) { 5041 ctx.error = PBIResult::Error; 5042 return IC_ERROR_SENTINEL(); 5043 } 5044 } 5045 PREDICT_RETURN(); 5046 DISPATCH_CACHEOP(); 5047 } 5048 5049 CACHEOP_CASE(ObjectKeysResult) { 5050 ObjOperandId objId = cacheIRReader.objOperandId(); 5051 JSObject* obj = reinterpret_cast<JSObject*>(READ_REG(objId.id())); 5052 { 5053 PUSH_IC_FRAME(); 5054 ReservedRooted<JSObject*> obj0(&ctx.state.obj0, obj); 5055 auto* result = ObjectKeys(cx, obj0); 5056 if (!result) { 5057 ctx.error = PBIResult::Error; 5058 return IC_ERROR_SENTINEL(); 5059 } 5060 retValue = ObjectValue(*result).asRawBits(); 5061 } 5062 PREDICT_RETURN(); 5063 DISPATCH_CACHEOP(); 5064 } 5065 5066 CACHEOP_CASE(ObjectCreateResult) { 5067 uint32_t templateOffset = cacheIRReader.stubOffset(); 5068 PlainObject* templateObj = reinterpret_cast<PlainObject*>( 5069 stubInfo->getStubRawWord(cstub, templateOffset)); 5070 { 5071 PUSH_IC_FRAME(); 5072 Rooted<PlainObject*> templateRooted(cx, templateObj); 5073 auto* result = ObjectCreateWithTemplate(cx, templateRooted); 5074 if (!result) { 5075 ctx.error = PBIResult::Error; 5076 return IC_ERROR_SENTINEL(); 5077 } 5078 retValue = ObjectValue(*result).asRawBits(); 5079 } 5080 PREDICT_RETURN(); 5081 DISPATCH_CACHEOP(); 5082 } 5083 5084 CACHEOP_CASE(CallNumberToString) { 5085 NumberOperandId inputId = cacheIRReader.numberOperandId(); 5086 StringOperandId resultId = cacheIRReader.stringOperandId(); 5087 BOUNDSCHECK(resultId); 5088 double input = READ_VALUE_REG(inputId.id()).toNumber(); 5089 { 5090 PUSH_IC_FRAME(); 5091 auto* result = NumberToStringPure(cx, input); 5092 if (!result) { 5093 FAIL_IC(); 5094 } 5095 WRITE_REG(resultId.id(), reinterpret_cast<uint64_t>(result), STRING); 5096 } 5097 PREDICT_RETURN(); 5098 DISPATCH_CACHEOP(); 5099 } 5100 5101 CACHEOP_CASE(Int32ToStringWithBaseResult) { 5102 Int32OperandId inputId = cacheIRReader.int32OperandId(); 5103 Int32OperandId baseId = cacheIRReader.int32OperandId(); 5104 int32_t input = int32_t(READ_REG(inputId.id())); 5105 int32_t base = int32_t(READ_REG(baseId.id())); 5106 if (base < 2 || base > 36) { 5107 FAIL_IC(); 5108 } 5109 { 5110 PUSH_IC_FRAME(); 5111 auto* result = Int32ToStringWithBase<CanGC>(cx, input, base, true); 5112 if (!result) { 5113 ctx.error = PBIResult::Error; 5114 return IC_ERROR_SENTINEL(); 5115 } 5116 retValue = StringValue(result).asRawBits(); 5117 } 5118 PREDICT_RETURN(); 5119 DISPATCH_CACHEOP(); 5120 } 5121 5122 CACHEOP_CASE(BooleanToString) { 5123 BooleanOperandId inputId = cacheIRReader.booleanOperandId(); 5124 StringOperandId resultId = cacheIRReader.stringOperandId(); 5125 BOUNDSCHECK(resultId); 5126 bool input = READ_REG(inputId.id()) != 0; 5127 auto& names = ctx.frameMgr.cxForLocalUseOnly()->names(); 5128 JSString* result = input ? names.true_ : names.false_; 5129 WRITE_REG(resultId.id(), reinterpret_cast<uint64_t>(result), STRING); 5130 DISPATCH_CACHEOP(); 5131 } 5132 5133 CACHEOP_CASE(IndirectTruncateInt32Result) { 5134 Int32OperandId valId = cacheIRReader.int32OperandId(); 5135 int32_t value = int32_t(READ_REG(valId.id())); 5136 retValue = Int32Value(value).asRawBits(); 5137 PREDICT_RETURN(); 5138 DISPATCH_CACHEOP(); 5139 } 5140 5141 CACHEOP_CASE(GetFirstDollarIndexResult) { 5142 StringOperandId strId = cacheIRReader.stringOperandId(); 5143 JSString* str = reinterpret_cast<JSString*>(READ_REG(strId.id())); 5144 int32_t result = 0; 5145 { 5146 PUSH_IC_FRAME(); 5147 if (!GetFirstDollarIndexRaw(cx, str, &result)) { 5148 ctx.error = PBIResult::Error; 5149 return IC_ERROR_SENTINEL(); 5150 } 5151 retValue = Int32Value(result).asRawBits(); 5152 } 5153 PREDICT_RETURN(); 5154 DISPATCH_CACHEOP(); 5155 } 5156 5157 CACHEOP_CASE(LoadBoundFunctionNumArgs) { 5158 ObjOperandId objId = cacheIRReader.objOperandId(); 5159 Int32OperandId resultId = cacheIRReader.int32OperandId(); 5160 BOUNDSCHECK(resultId); 5161 BoundFunctionObject* obj = 5162 reinterpret_cast<BoundFunctionObject*>(READ_REG(objId.id())); 5163 WRITE_REG(resultId.id(), obj->numBoundArgs(), INT32); 5164 DISPATCH_CACHEOP(); 5165 } 5166 5167 CACHEOP_CASE(LoadBoundFunctionTarget) { 5168 ObjOperandId objId = cacheIRReader.objOperandId(); 5169 ObjOperandId resultId = cacheIRReader.objOperandId(); 5170 BOUNDSCHECK(resultId); 5171 BoundFunctionObject* obj = 5172 reinterpret_cast<BoundFunctionObject*>(READ_REG(objId.id())); 5173 WRITE_REG(resultId.id(), reinterpret_cast<uint64_t>(obj->getTarget()), 5174 OBJECT); 5175 DISPATCH_CACHEOP(); 5176 } 5177 5178 CACHEOP_CASE(BindFunctionResult) 5179 CACHEOP_CASE_FALLTHROUGH(SpecializedBindFunctionResult) { 5180 ObjOperandId targetId = cacheIRReader.objOperandId(); 5181 uint32_t argc = cacheIRReader.uint32Immediate(); 5182 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 5183 5184 JSObject* target = reinterpret_cast<JSObject*>(READ_REG(targetId.id())); 5185 BoundFunctionObject* templateObject = 5186 (cacheop == CacheOp::SpecializedBindFunctionResult) 5187 ? reinterpret_cast<BoundFunctionObject*>( 5188 stubInfo->getStubRawWord(cstub, templateObjectOffset)) 5189 : nullptr; 5190 5191 StackVal* origArgs = ctx.sp(); 5192 { 5193 PUSH_IC_FRAME(); 5194 5195 for (uint32_t i = 0; i < argc; i++) { 5196 PUSH(origArgs[i]); 5197 } 5198 Value* args = reinterpret_cast<Value*>(sp); 5199 5200 ReservedRooted<JSObject*> targetRooted(&ctx.state.obj0, target); 5201 BoundFunctionObject* result; 5202 if (cacheop == CacheOp::BindFunctionResult) { 5203 result = BoundFunctionObject::functionBindImpl(cx, targetRooted, 5204 args, argc, nullptr); 5205 } else { 5206 Rooted<BoundFunctionObject*> templateObjectRooted(cx, 5207 templateObject); 5208 result = BoundFunctionObject::functionBindSpecializedBaseline( 5209 cx, targetRooted, args, argc, templateObjectRooted); 5210 } 5211 if (!result) { 5212 ctx.error = PBIResult::Error; 5213 return IC_ERROR_SENTINEL(); 5214 } 5215 5216 retValue = ObjectValue(*result).asRawBits(); 5217 } 5218 PREDICT_RETURN(); 5219 DISPATCH_CACHEOP(); 5220 } 5221 5222 CACHEOP_CASE(CallRegExpMatcherResult) 5223 CACHEOP_CASE_FALLTHROUGH(CallRegExpSearcherResult) { 5224 ObjOperandId regexpId = cacheIRReader.objOperandId(); 5225 StringOperandId inputId = cacheIRReader.stringOperandId(); 5226 Int32OperandId lastIndexId = cacheIRReader.int32OperandId(); 5227 uint32_t stubOffset = cacheIRReader.stubOffset(); 5228 5229 JSObject* regexp = reinterpret_cast<JSObject*>(READ_REG(regexpId.id())); 5230 JSString* input = reinterpret_cast<JSString*>(READ_REG(inputId.id())); 5231 int32_t lastIndex = int32_t(READ_REG(lastIndexId.id())); 5232 (void)stubOffset; 5233 5234 { 5235 PUSH_IC_FRAME(); 5236 ReservedRooted<JSObject*> regexpRooted(&ctx.state.obj0, regexp); 5237 ReservedRooted<JSString*> inputRooted(&ctx.state.str0, input); 5238 5239 if (cacheop == CacheOp::CallRegExpMatcherResult) { 5240 ReservedRooted<Value> result(&ctx.state.value0, UndefinedValue()); 5241 if (!RegExpMatcherRaw(cx, regexpRooted, inputRooted, lastIndex, 5242 nullptr, &result)) { 5243 ctx.error = PBIResult::Error; 5244 return IC_ERROR_SENTINEL(); 5245 } 5246 retValue = result.asRawBits(); 5247 } else { 5248 int32_t result = 0; 5249 if (!RegExpSearcherRaw(cx, regexpRooted, inputRooted, lastIndex, 5250 nullptr, &result)) { 5251 ctx.error = PBIResult::Error; 5252 return IC_ERROR_SENTINEL(); 5253 } 5254 retValue = Int32Value(result).asRawBits(); 5255 } 5256 } 5257 PREDICT_RETURN(); 5258 DISPATCH_CACHEOP(); 5259 } 5260 5261 CACHEOP_CASE(RegExpSearcherLastLimitResult) { 5262 uint32_t lastLimit = 5263 ctx.frameMgr.cxForLocalUseOnly()->regExpSearcherLastLimit; 5264 retValue = Int32Value(lastLimit).asRawBits(); 5265 PREDICT_RETURN(); 5266 DISPATCH_CACHEOP(); 5267 } 5268 5269 CACHEOP_CASE(RegExpHasCaptureGroupsResult) { 5270 ObjOperandId regexpId = cacheIRReader.objOperandId(); 5271 StringOperandId inputId = cacheIRReader.stringOperandId(); 5272 RegExpObject* regexp = 5273 reinterpret_cast<RegExpObject*>(READ_REG(regexpId.id())); 5274 JSString* input = reinterpret_cast<JSString*>(READ_REG(inputId.id())); 5275 { 5276 PUSH_IC_FRAME(); 5277 Rooted<RegExpObject*> regexpRooted(cx, regexp); 5278 ReservedRooted<JSString*> inputRooted(&ctx.state.str0, input); 5279 bool result = false; 5280 if (!RegExpHasCaptureGroups(cx, regexpRooted, inputRooted, &result)) { 5281 ctx.error = PBIResult::Error; 5282 return IC_ERROR_SENTINEL(); 5283 } 5284 retValue = BooleanValue(result).asRawBits(); 5285 } 5286 PREDICT_RETURN(); 5287 DISPATCH_CACHEOP(); 5288 } 5289 5290 CACHEOP_CASE(RegExpBuiltinExecMatchResult) { 5291 ObjOperandId regexpId = cacheIRReader.objOperandId(); 5292 StringOperandId inputId = cacheIRReader.stringOperandId(); 5293 uint32_t stubOffset = cacheIRReader.stubOffset(); 5294 5295 RegExpObject* regexp = 5296 reinterpret_cast<RegExpObject*>(READ_REG(regexpId.id())); 5297 JSString* input = reinterpret_cast<JSString*>(READ_REG(inputId.id())); 5298 (void)stubOffset; 5299 5300 { 5301 PUSH_IC_FRAME(); 5302 Rooted<RegExpObject*> regexpRooted(cx, regexp); 5303 ReservedRooted<JSString*> inputRooted(&ctx.state.str0, input); 5304 ReservedRooted<Value> output(&ctx.state.value0, UndefinedValue()); 5305 if (!RegExpBuiltinExecMatchFromJit(cx, regexpRooted, inputRooted, 5306 nullptr, &output)) { 5307 ctx.error = PBIResult::Error; 5308 return IC_ERROR_SENTINEL(); 5309 } 5310 retValue = output.asRawBits(); 5311 } 5312 PREDICT_RETURN(); 5313 DISPATCH_CACHEOP(); 5314 } 5315 5316 CACHEOP_CASE(RegExpBuiltinExecTestResult) { 5317 ObjOperandId regexpId = cacheIRReader.objOperandId(); 5318 StringOperandId inputId = cacheIRReader.stringOperandId(); 5319 uint32_t stubOffset = cacheIRReader.stubOffset(); 5320 5321 RegExpObject* regexp = 5322 reinterpret_cast<RegExpObject*>(READ_REG(regexpId.id())); 5323 JSString* input = reinterpret_cast<JSString*>(READ_REG(inputId.id())); 5324 (void)stubOffset; 5325 5326 { 5327 PUSH_IC_FRAME(); 5328 Rooted<RegExpObject*> regexpRooted(cx, regexp); 5329 ReservedRooted<JSString*> inputRooted(&ctx.state.str0, input); 5330 bool result = false; 5331 if (!RegExpBuiltinExecTestFromJit(cx, regexpRooted, inputRooted, 5332 &result)) { 5333 ctx.error = PBIResult::Error; 5334 return IC_ERROR_SENTINEL(); 5335 } 5336 retValue = BooleanValue(result).asRawBits(); 5337 } 5338 PREDICT_RETURN(); 5339 DISPATCH_CACHEOP(); 5340 } 5341 5342 CACHEOP_CASE(RegExpFlagResult) { 5343 ObjOperandId regexpId = cacheIRReader.objOperandId(); 5344 uint32_t flagsMask = cacheIRReader.uint32Immediate(); 5345 RegExpObject* regexp = 5346 reinterpret_cast<RegExpObject*>(READ_REG(regexpId.id())); 5347 JS::RegExpFlags flags = regexp->getFlags(); 5348 retValue = BooleanValue((uint32_t(flags.value()) & flagsMask) != 0) 5349 .asRawBits(); 5350 PREDICT_RETURN(); 5351 DISPATCH_CACHEOP(); 5352 } 5353 5354 CACHEOP_CASE(NewRegExpStringIteratorResult) { 5355 uint32_t templateObjectOffset = cacheIRReader.stubOffset(); 5356 (void)templateObjectOffset; 5357 { 5358 PUSH_IC_FRAME(); 5359 auto* result = NewRegExpStringIterator(cx); 5360 if (!result) { 5361 ctx.error = PBIResult::Error; 5362 return IC_ERROR_SENTINEL(); 5363 } 5364 retValue = ObjectValue(*result).asRawBits(); 5365 } 5366 PREDICT_RETURN(); 5367 DISPATCH_CACHEOP(); 5368 } 5369 5370 CACHEOP_CASE(CallGetSparseElementResult) { 5371 ObjOperandId objId = cacheIRReader.objOperandId(); 5372 Int32OperandId indexId = cacheIRReader.int32OperandId(); 5373 NativeObject* nobj = 5374 reinterpret_cast<NativeObject*>(READ_REG(objId.id())); 5375 int32_t index = int32_t(READ_REG(indexId.id())); 5376 { 5377 PUSH_IC_FRAME(); 5378 Rooted<NativeObject*> nobjRooted(cx, nobj); 5379 ReservedRooted<Value> result(&ctx.state.value0, UndefinedValue()); 5380 if (!GetSparseElementHelper(cx, nobjRooted, index, &result)) { 5381 ctx.error = PBIResult::Error; 5382 return IC_ERROR_SENTINEL(); 5383 } 5384 retValue = result.asRawBits(); 5385 } 5386 PREDICT_RETURN(); 5387 DISPATCH_CACHEOP(); 5388 } 5389 5390 #undef PREDICT_NEXT 5391 5392 #ifndef ENABLE_COMPUTED_GOTO_DISPATCH 5393 default: 5394 TRACE_PRINTF("unknown CacheOp\n"); 5395 FAIL_IC(); 5396 #endif 5397 } 5398 } 5399 5400 #define CACHEOP_UNIMPL(name, ...) \ 5401 cacheop_##name : __attribute__((unused)); \ 5402 TRACE_PRINTF("unknown CacheOp: " #name "\n"); \ 5403 FAIL_IC(); 5404 CACHE_IR_OPS(CACHEOP_UNIMPL) 5405 #undef CACHEOP_UNIMPL 5406 5407 next_ic: 5408 TRACE_PRINTF("IC failed; next IC\n"); 5409 return CallNextIC(arg0, arg1, stub, ctx); 5410 } 5411 5412 static MOZ_NEVER_INLINE uint64_t CallNextIC(uint64_t arg0, uint64_t arg1, 5413 ICStub* stub, ICCtx& ctx) { 5414 stub = stub->maybeNext(); 5415 MOZ_ASSERT(stub); 5416 uint64_t result; 5417 PBL_CALL_IC(stub->rawJitCode(), ctx, stub, result, arg0, arg1, ctx.arg2, 5418 true); 5419 return result; 5420 } 5421 5422 /* 5423 * ----------------------------------------------- 5424 * IC callsite logic, and fallback stubs 5425 * ----------------------------------------------- 5426 */ 5427 5428 #define DEFINE_IC(kind, arity, fallback_body) \ 5429 static uint64_t MOZ_NEVER_INLINE IC##kind##Fallback( \ 5430 uint64_t arg0, uint64_t arg1, ICStub* stub, ICCtx& ctx) { \ 5431 uint64_t retValue = 0; \ 5432 uint64_t arg2 = ctx.arg2; \ 5433 (void)arg2; \ 5434 ICFallbackStub* fallback = stub->toFallbackStub(); \ 5435 StackVal* sp = ctx.sp(); \ 5436 fallback_body; \ 5437 retValue = ctx.state.res.asRawBits(); \ 5438 ctx.state.res = UndefinedValue(); \ 5439 return retValue; \ 5440 error: \ 5441 ctx.error = PBIResult::Error; \ 5442 return IC_ERROR_SENTINEL(); \ 5443 } 5444 5445 #define DEFINE_IC_ALIAS(kind, target) \ 5446 static uint64_t MOZ_NEVER_INLINE IC##kind##Fallback( \ 5447 uint64_t arg0, uint64_t arg1, ICStub* stub, ICCtx& ctx) { \ 5448 return IC##target##Fallback(arg0, arg1, stub, ctx); \ 5449 } 5450 5451 #define IC_LOAD_VAL(state_elem, index) \ 5452 ReservedRooted<Value> state_elem(&ctx.state.state_elem, \ 5453 Value::fromRawBits(arg##index)) 5454 #define IC_LOAD_OBJ(state_elem, index) \ 5455 ReservedRooted<JSObject*> state_elem( \ 5456 &ctx.state.state_elem, reinterpret_cast<JSObject*>(arg##index)) 5457 5458 DEFINE_IC(TypeOf, 1, { 5459 IC_LOAD_VAL(value0, 0); 5460 PUSH_FALLBACK_IC_FRAME(); 5461 if (!DoTypeOfFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { 5462 goto error; 5463 } 5464 }); 5465 5466 DEFINE_IC(TypeOfEq, 1, { 5467 IC_LOAD_VAL(value0, 0); 5468 PUSH_FALLBACK_IC_FRAME(); 5469 if (!DoTypeOfEqFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { 5470 goto error; 5471 } 5472 }); 5473 5474 DEFINE_IC(GetName, 1, { 5475 IC_LOAD_OBJ(obj0, 0); 5476 PUSH_FALLBACK_IC_FRAME(); 5477 if (!DoGetNameFallback(cx, ctx.frame, fallback, obj0, &ctx.state.res)) { 5478 goto error; 5479 } 5480 }); 5481 5482 DEFINE_IC(Call, 1, { 5483 uint32_t argc = uint32_t(arg0); 5484 uint32_t totalArgs = 5485 argc + ctx.icregs.extraArgs; // this, callee, (constructing?), func args 5486 Value* args = reinterpret_cast<Value*>(&sp[0]); 5487 TRACE_PRINTF("Call fallback: argc %d totalArgs %d args %p\n", argc, totalArgs, 5488 args); 5489 // Reverse values on the stack. 5490 std::reverse(args, args + totalArgs); 5491 { 5492 PUSH_FALLBACK_IC_FRAME(); 5493 if (!DoCallFallback(cx, ctx.frame, fallback, argc, args, &ctx.state.res)) { 5494 std::reverse(args, args + totalArgs); 5495 goto error; 5496 } 5497 } 5498 }); 5499 5500 DEFINE_IC_ALIAS(CallConstructing, Call); 5501 5502 DEFINE_IC(SpreadCall, 1, { 5503 uint32_t argc = uint32_t(arg0); 5504 uint32_t totalArgs = 5505 argc + ctx.icregs.extraArgs; // this, callee, (constructing?), func args 5506 Value* args = reinterpret_cast<Value*>(&sp[0]); 5507 TRACE_PRINTF("Call fallback: argc %d totalArgs %d args %p\n", argc, totalArgs, 5508 args); 5509 // Reverse values on the stack. 5510 std::reverse(args, args + totalArgs); 5511 { 5512 PUSH_FALLBACK_IC_FRAME(); 5513 if (!DoSpreadCallFallback(cx, ctx.frame, fallback, args, &ctx.state.res)) { 5514 std::reverse(args, args + totalArgs); 5515 goto error; 5516 } 5517 } 5518 }); 5519 5520 DEFINE_IC_ALIAS(SpreadCallConstructing, SpreadCall); 5521 5522 DEFINE_IC(UnaryArith, 1, { 5523 IC_LOAD_VAL(value0, 0); 5524 PUSH_FALLBACK_IC_FRAME(); 5525 if (!DoUnaryArithFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { 5526 goto error; 5527 } 5528 }); 5529 5530 DEFINE_IC(BinaryArith, 2, { 5531 IC_LOAD_VAL(value0, 0); 5532 IC_LOAD_VAL(value1, 1); 5533 PUSH_FALLBACK_IC_FRAME(); 5534 if (!DoBinaryArithFallback(cx, ctx.frame, fallback, value0, value1, 5535 &ctx.state.res)) { 5536 goto error; 5537 } 5538 }); 5539 5540 DEFINE_IC(ToBool, 1, { 5541 IC_LOAD_VAL(value0, 0); 5542 PUSH_FALLBACK_IC_FRAME(); 5543 if (!DoToBoolFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { 5544 goto error; 5545 } 5546 }); 5547 5548 DEFINE_IC(Compare, 2, { 5549 IC_LOAD_VAL(value0, 0); 5550 IC_LOAD_VAL(value1, 1); 5551 PUSH_FALLBACK_IC_FRAME(); 5552 if (!DoCompareFallback(cx, ctx.frame, fallback, value0, value1, 5553 &ctx.state.res)) { 5554 goto error; 5555 } 5556 }); 5557 5558 DEFINE_IC(InstanceOf, 2, { 5559 IC_LOAD_VAL(value0, 0); 5560 IC_LOAD_VAL(value1, 1); 5561 PUSH_FALLBACK_IC_FRAME(); 5562 if (!DoInstanceOfFallback(cx, ctx.frame, fallback, value0, value1, 5563 &ctx.state.res)) { 5564 goto error; 5565 } 5566 }); 5567 5568 DEFINE_IC(In, 2, { 5569 IC_LOAD_VAL(value0, 0); 5570 IC_LOAD_VAL(value1, 1); 5571 PUSH_FALLBACK_IC_FRAME(); 5572 if (!DoInFallback(cx, ctx.frame, fallback, value0, value1, &ctx.state.res)) { 5573 goto error; 5574 } 5575 }); 5576 5577 DEFINE_IC(BindName, 1, { 5578 IC_LOAD_OBJ(obj0, 0); 5579 PUSH_FALLBACK_IC_FRAME(); 5580 if (!DoBindNameFallback(cx, ctx.frame, fallback, obj0, &ctx.state.res)) { 5581 goto error; 5582 } 5583 }); 5584 5585 DEFINE_IC(SetProp, 2, { 5586 IC_LOAD_VAL(value0, 0); 5587 IC_LOAD_VAL(value1, 1); 5588 PUSH_FALLBACK_IC_FRAME(); 5589 if (!DoSetPropFallback(cx, ctx.frame, fallback, nullptr, value0, value1)) { 5590 goto error; 5591 } 5592 }); 5593 5594 DEFINE_IC(NewObject, 0, { 5595 PUSH_FALLBACK_IC_FRAME(); 5596 if (!DoNewObjectFallback(cx, ctx.frame, fallback, &ctx.state.res)) { 5597 goto error; 5598 } 5599 }); 5600 5601 DEFINE_IC(GetProp, 1, { 5602 IC_LOAD_VAL(value0, 0); 5603 PUSH_FALLBACK_IC_FRAME(); 5604 if (!DoGetPropFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { 5605 goto error; 5606 } 5607 }); 5608 5609 DEFINE_IC(GetPropSuper, 2, { 5610 IC_LOAD_VAL(value0, 1); 5611 IC_LOAD_VAL(value1, 0); 5612 PUSH_FALLBACK_IC_FRAME(); 5613 if (!DoGetPropSuperFallback(cx, ctx.frame, fallback, value0, value1, 5614 &ctx.state.res)) { 5615 goto error; 5616 } 5617 }); 5618 5619 DEFINE_IC(GetElem, 2, { 5620 IC_LOAD_VAL(value0, 0); 5621 IC_LOAD_VAL(value1, 1); 5622 PUSH_FALLBACK_IC_FRAME(); 5623 if (!DoGetElemFallback(cx, ctx.frame, fallback, value0, value1, 5624 &ctx.state.res)) { 5625 goto error; 5626 } 5627 }); 5628 5629 DEFINE_IC(GetElemSuper, 3, { 5630 IC_LOAD_VAL(value0, 0); // receiver 5631 IC_LOAD_VAL(value1, 1); // obj (lhs) 5632 IC_LOAD_VAL(value2, 2); // key (rhs) 5633 PUSH_FALLBACK_IC_FRAME(); 5634 if (!DoGetElemSuperFallback(cx, ctx.frame, fallback, value1, value2, value0, 5635 &ctx.state.res)) { 5636 goto error; 5637 } 5638 }); 5639 5640 DEFINE_IC(GetImport, 0, { 5641 PUSH_FALLBACK_IC_FRAME(); 5642 if (!DoGetImportFallback(cx, ctx.frame, fallback, &ctx.state.res)) { 5643 goto error; 5644 } 5645 }); 5646 5647 DEFINE_IC(NewArray, 0, { 5648 PUSH_FALLBACK_IC_FRAME(); 5649 if (!DoNewArrayFallback(cx, ctx.frame, fallback, &ctx.state.res)) { 5650 goto error; 5651 } 5652 }); 5653 5654 DEFINE_IC(Lambda, 0, { 5655 PUSH_FALLBACK_IC_FRAME(); 5656 if (!DoLambdaFallback(cx, ctx.frame, fallback, &ctx.state.res)) { 5657 goto error; 5658 } 5659 }); 5660 5661 DEFINE_IC(LazyConstant, 0, { 5662 PUSH_FALLBACK_IC_FRAME(); 5663 if (!DoLazyConstantFallback(cx, ctx.frame, fallback, &ctx.state.res)) { 5664 goto error; 5665 } 5666 }); 5667 5668 DEFINE_IC(SetElem, 3, { 5669 IC_LOAD_VAL(value0, 0); 5670 IC_LOAD_VAL(value1, 1); 5671 IC_LOAD_VAL(value2, 2); 5672 PUSH_FALLBACK_IC_FRAME(); 5673 if (!DoSetElemFallback(cx, ctx.frame, fallback, nullptr, value0, value1, 5674 value2)) { 5675 goto error; 5676 } 5677 }); 5678 5679 DEFINE_IC(HasOwn, 2, { 5680 IC_LOAD_VAL(value0, 0); 5681 IC_LOAD_VAL(value1, 1); 5682 PUSH_FALLBACK_IC_FRAME(); 5683 if (!DoHasOwnFallback(cx, ctx.frame, fallback, value0, value1, 5684 &ctx.state.res)) { 5685 goto error; 5686 } 5687 }); 5688 5689 DEFINE_IC(CheckPrivateField, 2, { 5690 IC_LOAD_VAL(value0, 0); 5691 IC_LOAD_VAL(value1, 1); 5692 PUSH_FALLBACK_IC_FRAME(); 5693 if (!DoCheckPrivateFieldFallback(cx, ctx.frame, fallback, value0, value1, 5694 &ctx.state.res)) { 5695 goto error; 5696 } 5697 }); 5698 5699 DEFINE_IC(GetIterator, 1, { 5700 IC_LOAD_VAL(value0, 0); 5701 PUSH_FALLBACK_IC_FRAME(); 5702 if (!DoGetIteratorFallback(cx, ctx.frame, fallback, value0, &ctx.state.res)) { 5703 goto error; 5704 } 5705 }); 5706 5707 DEFINE_IC(ToPropertyKey, 1, { 5708 IC_LOAD_VAL(value0, 0); 5709 PUSH_FALLBACK_IC_FRAME(); 5710 if (!DoToPropertyKeyFallback(cx, ctx.frame, fallback, value0, 5711 &ctx.state.res)) { 5712 goto error; 5713 } 5714 }); 5715 5716 DEFINE_IC(OptimizeSpreadCall, 1, { 5717 IC_LOAD_VAL(value0, 0); 5718 PUSH_FALLBACK_IC_FRAME(); 5719 if (!DoOptimizeSpreadCallFallback(cx, ctx.frame, fallback, value0, 5720 &ctx.state.res)) { 5721 goto error; 5722 } 5723 }); 5724 5725 DEFINE_IC(OptimizeGetIterator, 1, { 5726 IC_LOAD_VAL(value0, 0); 5727 PUSH_FALLBACK_IC_FRAME(); 5728 if (!DoOptimizeGetIteratorFallback(cx, ctx.frame, fallback, value0, 5729 &ctx.state.res)) { 5730 goto error; 5731 } 5732 }); 5733 5734 DEFINE_IC(Rest, 0, { 5735 PUSH_FALLBACK_IC_FRAME(); 5736 if (!DoRestFallback(cx, ctx.frame, fallback, &ctx.state.res)) { 5737 goto error; 5738 } 5739 }); 5740 5741 DEFINE_IC(CloseIter, 1, { 5742 IC_LOAD_OBJ(obj0, 0); 5743 PUSH_FALLBACK_IC_FRAME(); 5744 if (!DoCloseIterFallback(cx, ctx.frame, fallback, obj0)) { 5745 goto error; 5746 } 5747 }); 5748 5749 uint8_t* GetPortableFallbackStub(BaselineICFallbackKind kind) { 5750 switch (kind) { 5751 #define _(ty) \ 5752 case BaselineICFallbackKind::ty: \ 5753 return reinterpret_cast<uint8_t*>(&IC##ty##Fallback); 5754 IC_BASELINE_FALLBACK_CODE_KIND_LIST(_) 5755 #undef _ 5756 case BaselineICFallbackKind::Count: 5757 MOZ_CRASH("Invalid kind"); 5758 } 5759 } 5760 5761 uint8_t* GetICInterpreter() { 5762 return reinterpret_cast<uint8_t*>(&ICInterpretOps); 5763 } 5764 5765 /* 5766 * ----------------------------------------------- 5767 * Main JSOp interpreter 5768 * ----------------------------------------------- 5769 */ 5770 5771 static EnvironmentObject& getEnvironmentFromCoordinate( 5772 BaselineFrame* frame, EnvironmentCoordinate ec) { 5773 JSObject* env = frame->environmentChain(); 5774 for (unsigned i = ec.hops(); i; i--) { 5775 if (env->is<EnvironmentObject>()) { 5776 env = &env->as<EnvironmentObject>().enclosingEnvironment(); 5777 } else { 5778 MOZ_ASSERT(env->is<DebugEnvironmentProxy>()); 5779 env = &env->as<DebugEnvironmentProxy>().enclosingEnvironment(); 5780 } 5781 } 5782 return env->is<EnvironmentObject>() 5783 ? env->as<EnvironmentObject>() 5784 : env->as<DebugEnvironmentProxy>().environment(); 5785 } 5786 5787 #ifndef __wasi__ 5788 # define DEBUG_CHECK() \ 5789 if (frame->isDebuggee()) { \ 5790 TRACE_PRINTF( \ 5791 "Debug check: frame is debuggee, checking for debug script\n"); \ 5792 if (frame->script()->hasDebugScript()) { \ 5793 goto debug; \ 5794 } \ 5795 } 5796 #else 5797 # define DEBUG_CHECK() 5798 #endif 5799 5800 #define LABEL(op) (&&label_##op) 5801 #ifdef ENABLE_COMPUTED_GOTO_DISPATCH 5802 # define CASE(op) label_##op: 5803 # define DISPATCH() \ 5804 DEBUG_CHECK(); \ 5805 goto* addresses[*pc] 5806 #else 5807 # define CASE(op) label_##op : case JSOp::op: 5808 # define DISPATCH() \ 5809 DEBUG_CHECK(); \ 5810 goto dispatch 5811 #endif 5812 5813 #define ADVANCE(delta) pc += (delta); 5814 #define ADVANCE_AND_DISPATCH(delta) \ 5815 ADVANCE(delta); \ 5816 DISPATCH(); 5817 5818 #define END_OP(op) ADVANCE_AND_DISPATCH(JSOpLength_##op); 5819 5820 #define VIRTPUSH(value) PUSH(value) 5821 #define VIRTPOP() POP() 5822 #define VIRTSP(index) sp[(index)] 5823 #define VIRTSPWRITE(index, value) sp[(index)] = (value) 5824 #define SYNCSP() 5825 #define SETLOCAL(i, value) frame->unaliasedLocal(i) = value 5826 #define GETLOCAL(i) frame->unaliasedLocal(i) 5827 5828 #define IC_SET_ARG_FROM_STACK(index, stack_index) \ 5829 ic_arg##index = sp[(stack_index)].asUInt64(); 5830 #define IC_POP_ARG(index) ic_arg##index = (*sp++).asUInt64(); 5831 #define IC_SET_VAL_ARG(index, expr) ic_arg##index = (expr).asRawBits(); 5832 #define IC_SET_OBJ_ARG(index, expr) \ 5833 ic_arg##index = reinterpret_cast<uint64_t>(expr); 5834 #define IC_ZERO_ARG(index) ic_arg##index = 0; 5835 #define IC_PUSH_RESULT() VIRTPUSH(StackVal(ic_ret)); 5836 5837 #if !defined(TRACE_INTERP) 5838 # define PREDICT_NEXT(op) \ 5839 if (JSOp(*pc) == JSOp::op) { \ 5840 DEBUG_CHECK(); \ 5841 goto label_##op; \ 5842 } 5843 #else 5844 # define PREDICT_NEXT(op) 5845 #endif 5846 5847 #ifdef ENABLE_COVERAGE 5848 # define COUNT_COVERAGE_PC(PC) \ 5849 if (frame->script()->hasScriptCounts()) { \ 5850 PCCounts* counts = frame->script()->maybeGetPCCounts(PC); \ 5851 MOZ_ASSERT(counts); \ 5852 counts->numExec()++; \ 5853 } 5854 # define COUNT_COVERAGE_MAIN() \ 5855 { \ 5856 jsbytecode* main = frame->script()->main(); \ 5857 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \ 5858 } 5859 #else 5860 # define COUNT_COVERAGE_PC(PC) ; 5861 # define COUNT_COVERAGE_MAIN() ; 5862 #endif 5863 5864 #define NEXT_IC() icEntry++ 5865 5866 #define INVOKE_IC(kind, hasarg2) \ 5867 ctx.sp_ = sp; \ 5868 frame->interpreterPC() = pc; \ 5869 frame->interpreterICEntry() = icEntry; \ 5870 SYNCSP(); \ 5871 PBL_CALL_IC(icEntry->firstStub()->rawJitCode(), ctx, icEntry->firstStub(), \ 5872 ic_ret, ic_arg0, ic_arg1, ic_arg2, hasarg2); \ 5873 if (ic_ret == IC_ERROR_SENTINEL()) { \ 5874 ic_result = ctx.error; \ 5875 goto ic_fail; \ 5876 } \ 5877 NEXT_IC(); 5878 5879 #define INVOKE_IC_AND_PUSH(kind, hasarg2) \ 5880 INVOKE_IC(kind, hasarg2); \ 5881 VIRTPUSH(StackVal(ic_ret)); 5882 5883 #define VIRTPOPN(n) \ 5884 SYNCSP(); \ 5885 POPN(n); 5886 5887 #define SPHANDLE(index) \ 5888 ({ \ 5889 SYNCSP(); \ 5890 Stack::handle(&sp[(index)]); \ 5891 }) 5892 #define SPHANDLEMUT(index) \ 5893 ({ \ 5894 SYNCSP(); \ 5895 Stack::handleMut(&sp[(index)]); \ 5896 }) 5897 5898 template <bool IsRestart, bool HybridICs> 5899 PBIResult PortableBaselineInterpret( 5900 JSContext* cx_, State& state, Stack& stack, StackVal* sp, 5901 JSObject* envChain, Value* ret, jsbytecode* pc, ImmutableScriptData* isd, 5902 jsbytecode* restartEntryPC, BaselineFrame* restartFrame, 5903 StackVal* restartEntryFrame, PBIResult restartCode) { 5904 #define RESTART(code) \ 5905 if (!IsRestart) { \ 5906 TRACE_PRINTF("Restarting (code %d sp %p fp %p)\n", int(code), sp, \ 5907 ctx.stack.fp); \ 5908 SYNCSP(); \ 5909 restartCode = code; \ 5910 goto restart; \ 5911 } 5912 5913 #define GOTO_ERROR() \ 5914 do { \ 5915 SYNCSP(); \ 5916 RESTART(PBIResult::Error); \ 5917 goto error; \ 5918 } while (0) 5919 5920 // Update local state when we switch to a new script with a new PC. 5921 #define RESET_PC(new_pc, new_script) \ 5922 pc = new_pc; \ 5923 entryPC = new_script->code(); \ 5924 isd = new_script->immutableScriptData(); \ 5925 icEntries = frame->icScript()->icEntries(); \ 5926 icEntry = frame->interpreterICEntry(); \ 5927 argsObjAliasesFormals = frame->script()->argsObjAliasesFormals(); \ 5928 resumeOffsets = isd->resumeOffsets().data(); 5929 5930 #define OPCODE_LABEL(op, ...) LABEL(op), 5931 #define TRAILING_LABEL(v) LABEL(default), 5932 5933 static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = { 5934 FOR_EACH_OPCODE(OPCODE_LABEL) 5935 FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)}; 5936 5937 #undef OPCODE_LABEL 5938 #undef TRAILING_LABEL 5939 5940 BaselineFrame* frame = restartFrame; 5941 StackVal* entryFrame = restartEntryFrame; 5942 jsbytecode* entryPC = restartEntryPC; 5943 5944 if (!IsRestart) { 5945 PUSHNATIVE(StackValNative(nullptr)); // Fake return address. 5946 frame = stack.pushFrame(sp, cx_, envChain); 5947 MOZ_ASSERT(frame); // safety: stack margin. 5948 sp = reinterpret_cast<StackVal*>(frame); 5949 // Save the entry frame so that when unwinding, we know when to 5950 // return from this C++ frame. 5951 entryFrame = sp; 5952 // Save the entry PC so that we can compute offsets locally. 5953 entryPC = pc; 5954 } 5955 5956 bool from_unwind = false; 5957 uint32_t nfixed = frame->script()->nfixed(); 5958 bool argsObjAliasesFormals = frame->script()->argsObjAliasesFormals(); 5959 5960 PBIResult ic_result = PBIResult::Ok; 5961 uint64_t ic_arg0 = 0, ic_arg1 = 0, ic_arg2 = 0, ic_ret = 0; 5962 5963 ICCtx ctx(cx_, frame, state, stack); 5964 auto* icEntries = frame->icScript()->icEntries(); 5965 auto* icEntry = icEntries; 5966 const uint32_t* resumeOffsets = isd->resumeOffsets().data(); 5967 5968 if (IsRestart) { 5969 ic_result = restartCode; 5970 TRACE_PRINTF( 5971 "Enter from restart: sp = %p ctx.stack.fp = %p ctx.frame = %p\n", sp, 5972 ctx.stack.fp, ctx.frame); 5973 goto ic_fail; 5974 } else { 5975 AutoCheckRecursionLimit recursion(ctx.frameMgr.cxForLocalUseOnly()); 5976 if (!recursion.checkDontReport(ctx.frameMgr.cxForLocalUseOnly())) { 5977 PUSH_EXIT_FRAME(); 5978 ReportOverRecursed(ctx.frameMgr.cxForLocalUseOnly()); 5979 return PBIResult::Error; 5980 } 5981 } 5982 5983 // Check max stack depth once, so we don't need to check it 5984 // otherwise below for ordinary stack-manipulation opcodes (just for 5985 // exit frames). 5986 if (!ctx.stack.check(sp, sizeof(StackVal) * frame->script()->nslots())) { 5987 PUSH_EXIT_FRAME(); 5988 ReportOverRecursed(ctx.frameMgr.cxForLocalUseOnly()); 5989 return PBIResult::Error; 5990 } 5991 5992 SYNCSP(); 5993 sp -= nfixed; 5994 for (uint32_t i = 0; i < nfixed; i++) { 5995 sp[i] = StackVal(UndefinedValue()); 5996 } 5997 ret->setUndefined(); 5998 5999 // Check if we are being debugged, and set a flag in the frame if so. This 6000 // flag must be set before calling InitFunctionEnvironmentObjects. 6001 if (frame->script()->isDebuggee()) { 6002 TRACE_PRINTF("Script is debuggee\n"); 6003 frame->setIsDebuggee(); 6004 } 6005 6006 if (CalleeTokenIsFunction(frame->calleeToken())) { 6007 JSFunction* func = CalleeTokenToFunction(frame->calleeToken()); 6008 frame->setEnvironmentChain(func->environment()); 6009 if (func->needsFunctionEnvironmentObjects()) { 6010 PUSH_EXIT_FRAME(); 6011 if (!js::InitFunctionEnvironmentObjects(cx, frame)) { 6012 GOTO_ERROR(); 6013 } 6014 TRACE_PRINTF("callee is func %p; created environment object: %p\n", func, 6015 frame->environmentChain()); 6016 } 6017 } 6018 6019 // The debug prologue can't run until the function environment is set up. 6020 if (frame->script()->isDebuggee()) { 6021 PUSH_EXIT_FRAME(); 6022 if (!DebugPrologue(cx, frame)) { 6023 GOTO_ERROR(); 6024 } 6025 } 6026 6027 if (!frame->script()->hasScriptCounts()) { 6028 if (ctx.frameMgr.cxForLocalUseOnly()->realm()->collectCoverageForDebug()) { 6029 PUSH_EXIT_FRAME(); 6030 if (!frame->script()->initScriptCounts(cx)) { 6031 GOTO_ERROR(); 6032 } 6033 } 6034 } 6035 COUNT_COVERAGE_MAIN(); 6036 6037 #ifdef ENABLE_INTERRUPT_CHECKS 6038 if (ctx.frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) { 6039 PUSH_EXIT_FRAME(); 6040 if (!InterruptCheck(cx)) { 6041 GOTO_ERROR(); 6042 } 6043 } 6044 #endif 6045 6046 TRACE_PRINTF("Entering: sp = %p fp = %p frame = %p, script = %p, pc = %p\n", 6047 sp, ctx.stack.fp, frame, frame->script(), pc); 6048 TRACE_PRINTF("nslots = %d nfixed = %d\n", int(frame->script()->nslots()), 6049 int(frame->script()->nfixed())); 6050 6051 while (true) { 6052 DEBUG_CHECK(); 6053 6054 #if !defined(ENABLE_COMPUTED_GOTO_DISPATCH) || !defined(__wasi__) 6055 dispatch: 6056 #endif 6057 6058 #ifdef TRACE_INTERP 6059 { 6060 JSOp op = JSOp(*pc); 6061 printf("sp[0] = %" PRIx64 " sp[1] = %" PRIx64 " sp[2] = %" PRIx64 "\n", 6062 sp[0].asUInt64(), sp[1].asUInt64(), sp[2].asUInt64()); 6063 printf("script = %p pc = %p: %s (ic %d entry %p) pending = %d\n", 6064 frame->script(), pc, CodeName(op), (int)(icEntry - icEntries), 6065 icEntry, ctx.frameMgr.cxForLocalUseOnly()->isExceptionPending()); 6066 printf("sp = %p fp = %p\n", sp, ctx.stack.fp); 6067 printf("TOS tag: %d\n", int(sp[0].asValue().asRawBits() >> 47)); 6068 fflush(stdout); 6069 } 6070 #endif 6071 6072 #ifdef ENABLE_COMPUTED_GOTO_DISPATCH 6073 goto* addresses[*pc]; 6074 #else 6075 (void)addresses; // Avoid unused-local error. We keep the table 6076 // itself to avoid warnings (see note in IC 6077 // interpreter above). 6078 switch (JSOp(*pc)) 6079 #endif 6080 { 6081 CASE(Nop) { END_OP(Nop); } 6082 CASE(NopIsAssignOp) { END_OP(NopIsAssignOp); } 6083 CASE(Undefined) { 6084 VIRTPUSH(StackVal(UndefinedValue())); 6085 END_OP(Undefined); 6086 } 6087 CASE(Null) { 6088 VIRTPUSH(StackVal(NullValue())); 6089 END_OP(Null); 6090 } 6091 CASE(False) { 6092 VIRTPUSH(StackVal(BooleanValue(false))); 6093 END_OP(False); 6094 } 6095 CASE(True) { 6096 VIRTPUSH(StackVal(BooleanValue(true))); 6097 END_OP(True); 6098 } 6099 CASE(Int32) { 6100 VIRTPUSH(StackVal(Int32Value(GET_INT32(pc)))); 6101 END_OP(Int32); 6102 } 6103 CASE(Zero) { 6104 VIRTPUSH(StackVal(Int32Value(0))); 6105 END_OP(Zero); 6106 } 6107 CASE(One) { 6108 VIRTPUSH(StackVal(Int32Value(1))); 6109 END_OP(One); 6110 } 6111 CASE(Int8) { 6112 VIRTPUSH(StackVal(Int32Value(GET_INT8(pc)))); 6113 END_OP(Int8); 6114 } 6115 CASE(Uint16) { 6116 VIRTPUSH(StackVal(Int32Value(GET_UINT16(pc)))); 6117 END_OP(Uint16); 6118 } 6119 CASE(Uint24) { 6120 VIRTPUSH(StackVal(Int32Value(GET_UINT24(pc)))); 6121 END_OP(Uint24); 6122 } 6123 CASE(Double) { 6124 VIRTPUSH(StackVal(GET_INLINE_VALUE(pc))); 6125 END_OP(Double); 6126 } 6127 CASE(BigInt) { 6128 VIRTPUSH(StackVal(JS::BigIntValue(frame->script()->getBigInt(pc)))); 6129 END_OP(BigInt); 6130 } 6131 CASE(String) { 6132 VIRTPUSH(StackVal(StringValue(frame->script()->getString(pc)))); 6133 END_OP(String); 6134 } 6135 CASE(Symbol) { 6136 VIRTPUSH(StackVal(SymbolValue( 6137 ctx.frameMgr.cxForLocalUseOnly()->wellKnownSymbols().get( 6138 GET_UINT8(pc))))); 6139 END_OP(Symbol); 6140 } 6141 CASE(Void) { 6142 VIRTSPWRITE(0, StackVal(JS::UndefinedValue())); 6143 END_OP(Void); 6144 } 6145 6146 CASE(Typeof) 6147 CASE(TypeofExpr) { 6148 static_assert(JSOpLength_Typeof == JSOpLength_TypeofExpr); 6149 if (HybridICs) { 6150 SYNCSP(); 6151 VIRTSPWRITE( 6152 0, 6153 StackVal(StringValue(TypeOfOperation( 6154 SPHANDLE(0), ctx.frameMgr.cxForLocalUseOnly()->runtime())))); 6155 NEXT_IC(); 6156 } else { 6157 IC_POP_ARG(0); 6158 IC_ZERO_ARG(1); 6159 IC_ZERO_ARG(2); 6160 INVOKE_IC_AND_PUSH(TypeOf, false); 6161 } 6162 END_OP(Typeof); 6163 } 6164 6165 CASE(TypeofEq) { 6166 if (HybridICs) { 6167 TypeofEqOperand operand = 6168 TypeofEqOperand::fromRawValue(GET_UINT8(pc)); 6169 bool result = js::TypeOfValue(SPHANDLE(0)) == operand.type(); 6170 if (operand.compareOp() == JSOp::Ne) { 6171 result = !result; 6172 } 6173 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6174 NEXT_IC(); 6175 } else { 6176 IC_POP_ARG(0); 6177 IC_ZERO_ARG(1); 6178 IC_ZERO_ARG(2); 6179 INVOKE_IC_AND_PUSH(TypeOfEq, false); 6180 } 6181 END_OP(TypeofEq); 6182 } 6183 6184 CASE(Pos) { 6185 if (VIRTSP(0).asValue().isNumber()) { 6186 // Nothing! 6187 NEXT_IC(); 6188 END_OP(Pos); 6189 } else { 6190 goto generic_unary; 6191 } 6192 } 6193 CASE(Neg) { 6194 Value v = VIRTSP(0).asValue(); 6195 if (v.isInt32()) { 6196 int32_t i = v.toInt32(); 6197 if (i != 0 && i != INT32_MIN) { 6198 VIRTSPWRITE(0, StackVal(Int32Value(-i))); 6199 NEXT_IC(); 6200 END_OP(Neg); 6201 } 6202 } 6203 if (v.isNumber()) { 6204 VIRTSPWRITE(0, StackVal(NumberValue(-v.toNumber()))); 6205 NEXT_IC(); 6206 END_OP(Neg); 6207 } 6208 goto generic_unary; 6209 } 6210 6211 CASE(Inc) { 6212 Value v = VIRTSP(0).asValue(); 6213 if (v.isInt32()) { 6214 int32_t i = v.toInt32(); 6215 if (i != INT32_MAX) { 6216 VIRTSPWRITE(0, StackVal(Int32Value(i + 1))); 6217 NEXT_IC(); 6218 END_OP(Inc); 6219 } 6220 } 6221 if (v.isNumber()) { 6222 VIRTSPWRITE(0, StackVal(NumberValue(v.toNumber() + 1))); 6223 NEXT_IC(); 6224 END_OP(Inc); 6225 } 6226 goto generic_unary; 6227 } 6228 CASE(Dec) { 6229 Value v = VIRTSP(0).asValue(); 6230 if (v.isInt32()) { 6231 int32_t i = v.toInt32(); 6232 if (i != INT32_MIN) { 6233 VIRTSPWRITE(0, StackVal(Int32Value(i - 1))); 6234 NEXT_IC(); 6235 END_OP(Dec); 6236 } 6237 } 6238 if (v.isNumber()) { 6239 VIRTSPWRITE(0, StackVal(NumberValue(v.toNumber() - 1))); 6240 NEXT_IC(); 6241 END_OP(Dec); 6242 } 6243 goto generic_unary; 6244 } 6245 6246 CASE(BitNot) { 6247 Value v = VIRTSP(0).asValue(); 6248 if (v.isInt32()) { 6249 int32_t i = v.toInt32(); 6250 VIRTSPWRITE(0, StackVal(Int32Value(~i))); 6251 NEXT_IC(); 6252 END_OP(Inc); 6253 } 6254 goto generic_unary; 6255 } 6256 6257 CASE(ToNumeric) { 6258 if (VIRTSP(0).asValue().isNumeric()) { 6259 NEXT_IC(); 6260 } else if (HybridICs) { 6261 SYNCSP(); 6262 MutableHandleValue val = SPHANDLEMUT(0); 6263 PUSH_EXIT_FRAME(); 6264 if (!ToNumeric(cx, val)) { 6265 GOTO_ERROR(); 6266 } 6267 NEXT_IC(); 6268 } else { 6269 goto generic_unary; 6270 } 6271 END_OP(ToNumeric); 6272 } 6273 6274 generic_unary:; 6275 { 6276 static_assert(JSOpLength_Pos == JSOpLength_Neg); 6277 static_assert(JSOpLength_Pos == JSOpLength_BitNot); 6278 static_assert(JSOpLength_Pos == JSOpLength_Inc); 6279 static_assert(JSOpLength_Pos == JSOpLength_Dec); 6280 static_assert(JSOpLength_Pos == JSOpLength_ToNumeric); 6281 IC_POP_ARG(0); 6282 IC_ZERO_ARG(1); 6283 IC_ZERO_ARG(2); 6284 INVOKE_IC_AND_PUSH(UnaryArith, false); 6285 END_OP(Pos); 6286 } 6287 6288 CASE(Not) { 6289 Value v = VIRTSP(0).asValue(); 6290 if (v.isBoolean()) { 6291 VIRTSPWRITE(0, StackVal(BooleanValue(!v.toBoolean()))); 6292 NEXT_IC(); 6293 } else if (HybridICs) { 6294 SYNCSP(); 6295 VIRTSPWRITE(0, StackVal(BooleanValue(!ToBoolean(SPHANDLE(0))))); 6296 NEXT_IC(); 6297 } else { 6298 IC_POP_ARG(0); 6299 IC_ZERO_ARG(1); 6300 IC_ZERO_ARG(2); 6301 INVOKE_IC(ToBool, false); 6302 VIRTPUSH( 6303 StackVal(BooleanValue(!Value::fromRawBits(ic_ret).toBoolean()))); 6304 } 6305 END_OP(Not); 6306 } 6307 6308 CASE(And) { 6309 bool result; 6310 Value v = VIRTSP(0).asValue(); 6311 if (v.isBoolean()) { 6312 result = v.toBoolean(); 6313 NEXT_IC(); 6314 } else if (HybridICs) { 6315 result = ToBoolean(SPHANDLE(0)); 6316 NEXT_IC(); 6317 } else { 6318 IC_SET_ARG_FROM_STACK(0, 0); 6319 IC_ZERO_ARG(1); 6320 IC_ZERO_ARG(2); 6321 INVOKE_IC(ToBool, false); 6322 result = Value::fromRawBits(ic_ret).toBoolean(); 6323 } 6324 int32_t jumpOffset = GET_JUMP_OFFSET(pc); 6325 if (!result) { 6326 ADVANCE(jumpOffset); 6327 PREDICT_NEXT(JumpTarget); 6328 PREDICT_NEXT(LoopHead); 6329 } else { 6330 ADVANCE(JSOpLength_And); 6331 } 6332 DISPATCH(); 6333 } 6334 CASE(Or) { 6335 bool result; 6336 Value v = VIRTSP(0).asValue(); 6337 if (v.isBoolean()) { 6338 result = v.toBoolean(); 6339 NEXT_IC(); 6340 } else if (HybridICs) { 6341 result = ToBoolean(SPHANDLE(0)); 6342 NEXT_IC(); 6343 } else { 6344 IC_SET_ARG_FROM_STACK(0, 0); 6345 IC_ZERO_ARG(1); 6346 IC_ZERO_ARG(2); 6347 INVOKE_IC(ToBool, false); 6348 result = Value::fromRawBits(ic_ret).toBoolean(); 6349 } 6350 int32_t jumpOffset = GET_JUMP_OFFSET(pc); 6351 if (result) { 6352 ADVANCE(jumpOffset); 6353 PREDICT_NEXT(JumpTarget); 6354 PREDICT_NEXT(LoopHead); 6355 } else { 6356 ADVANCE(JSOpLength_Or); 6357 } 6358 DISPATCH(); 6359 } 6360 CASE(JumpIfTrue) { 6361 bool result; 6362 Value v = VIRTSP(0).asValue(); 6363 if (v.isBoolean()) { 6364 result = v.toBoolean(); 6365 VIRTPOP(); 6366 NEXT_IC(); 6367 } else if (HybridICs) { 6368 result = ToBoolean(SPHANDLE(0)); 6369 VIRTPOP(); 6370 NEXT_IC(); 6371 } else { 6372 IC_POP_ARG(0); 6373 IC_ZERO_ARG(1); 6374 IC_ZERO_ARG(2); 6375 INVOKE_IC(ToBool, false); 6376 result = Value::fromRawBits(ic_ret).toBoolean(); 6377 } 6378 int32_t jumpOffset = GET_JUMP_OFFSET(pc); 6379 if (result) { 6380 ADVANCE(jumpOffset); 6381 PREDICT_NEXT(JumpTarget); 6382 PREDICT_NEXT(LoopHead); 6383 } else { 6384 ADVANCE(JSOpLength_JumpIfTrue); 6385 } 6386 DISPATCH(); 6387 } 6388 CASE(JumpIfFalse) { 6389 bool result; 6390 Value v = VIRTSP(0).asValue(); 6391 if (v.isBoolean()) { 6392 result = v.toBoolean(); 6393 VIRTPOP(); 6394 NEXT_IC(); 6395 } else if (HybridICs) { 6396 result = ToBoolean(SPHANDLE(0)); 6397 VIRTPOP(); 6398 NEXT_IC(); 6399 } else { 6400 IC_POP_ARG(0); 6401 IC_ZERO_ARG(1); 6402 IC_ZERO_ARG(2); 6403 INVOKE_IC(ToBool, false); 6404 result = Value::fromRawBits(ic_ret).toBoolean(); 6405 } 6406 int32_t jumpOffset = GET_JUMP_OFFSET(pc); 6407 if (!result) { 6408 ADVANCE(jumpOffset); 6409 PREDICT_NEXT(JumpTarget); 6410 PREDICT_NEXT(LoopHead); 6411 } else { 6412 ADVANCE(JSOpLength_JumpIfFalse); 6413 } 6414 DISPATCH(); 6415 } 6416 6417 CASE(Add) { 6418 if (HybridICs) { 6419 Value v0 = VIRTSP(0).asValue(); 6420 Value v1 = VIRTSP(1).asValue(); 6421 if (v0.isInt32() && v1.isInt32()) { 6422 int64_t lhs = v1.toInt32(); 6423 int64_t rhs = v0.toInt32(); 6424 int64_t result = lhs + rhs; 6425 if (result >= int64_t(INT32_MIN) && result <= int64_t(INT32_MAX)) { 6426 VIRTPOP(); 6427 VIRTSPWRITE(0, StackVal(Int32Value(int32_t(result)))); 6428 NEXT_IC(); 6429 END_OP(Add); 6430 } 6431 } 6432 if (v0.isNumber() && v1.isNumber()) { 6433 double lhs = v1.toNumber(); 6434 double rhs = v0.toNumber(); 6435 VIRTPOP(); 6436 VIRTSPWRITE(0, StackVal(NumberValue(lhs + rhs))); 6437 NEXT_IC(); 6438 END_OP(Add); 6439 } 6440 6441 MutableHandleValue lhs = SPHANDLEMUT(1); 6442 MutableHandleValue rhs = SPHANDLEMUT(0); 6443 MutableHandleValue result = SPHANDLEMUT(1); 6444 { 6445 PUSH_EXIT_FRAME(); 6446 if (!AddOperation(cx, lhs, rhs, result)) { 6447 GOTO_ERROR(); 6448 } 6449 } 6450 VIRTPOP(); 6451 NEXT_IC(); 6452 END_OP(Add); 6453 } 6454 goto generic_binary; 6455 } 6456 6457 CASE(Sub) { 6458 if (HybridICs) { 6459 Value v0 = VIRTSP(0).asValue(); 6460 Value v1 = VIRTSP(1).asValue(); 6461 if (v0.isInt32() && v1.isInt32()) { 6462 int64_t lhs = v1.toInt32(); 6463 int64_t rhs = v0.toInt32(); 6464 int64_t result = lhs - rhs; 6465 if (result >= int64_t(INT32_MIN) && result <= int64_t(INT32_MAX)) { 6466 VIRTPOP(); 6467 VIRTSPWRITE(0, StackVal(Int32Value(int32_t(result)))); 6468 NEXT_IC(); 6469 END_OP(Sub); 6470 } 6471 } 6472 if (v0.isNumber() && v1.isNumber()) { 6473 double lhs = v1.toNumber(); 6474 double rhs = v0.toNumber(); 6475 VIRTPOP(); 6476 VIRTSPWRITE(0, StackVal(NumberValue(lhs - rhs))); 6477 NEXT_IC(); 6478 END_OP(Add); 6479 } 6480 6481 MutableHandleValue lhs = SPHANDLEMUT(1); 6482 MutableHandleValue rhs = SPHANDLEMUT(0); 6483 MutableHandleValue result = SPHANDLEMUT(1); 6484 { 6485 PUSH_EXIT_FRAME(); 6486 if (!SubOperation(cx, lhs, rhs, result)) { 6487 GOTO_ERROR(); 6488 } 6489 } 6490 VIRTPOP(); 6491 NEXT_IC(); 6492 END_OP(Sub); 6493 } 6494 goto generic_binary; 6495 } 6496 6497 CASE(Mul) { 6498 if (HybridICs) { 6499 Value v0 = VIRTSP(0).asValue(); 6500 Value v1 = VIRTSP(1).asValue(); 6501 if (v0.isInt32() && v1.isInt32()) { 6502 int64_t lhs = v1.toInt32(); 6503 int64_t rhs = v0.toInt32(); 6504 int64_t product = lhs * rhs; 6505 if (product >= int64_t(INT32_MIN) && 6506 product <= int64_t(INT32_MAX) && 6507 (product != 0 || !((lhs < 0) ^ (rhs < 0)))) { 6508 VIRTPOP(); 6509 VIRTSPWRITE(0, StackVal(Int32Value(int32_t(product)))); 6510 NEXT_IC(); 6511 END_OP(Mul); 6512 } 6513 } 6514 if (v0.isNumber() && v1.isNumber()) { 6515 double lhs = v1.toNumber(); 6516 double rhs = v0.toNumber(); 6517 VIRTPOP(); 6518 VIRTSPWRITE(0, StackVal(NumberValue(lhs * rhs))); 6519 NEXT_IC(); 6520 END_OP(Mul); 6521 } 6522 6523 MutableHandleValue lhs = SPHANDLEMUT(1); 6524 MutableHandleValue rhs = SPHANDLEMUT(0); 6525 MutableHandleValue result = SPHANDLEMUT(1); 6526 { 6527 PUSH_EXIT_FRAME(); 6528 if (!MulOperation(cx, lhs, rhs, result)) { 6529 GOTO_ERROR(); 6530 } 6531 } 6532 VIRTPOP(); 6533 NEXT_IC(); 6534 END_OP(Mul); 6535 } 6536 goto generic_binary; 6537 } 6538 CASE(Div) { 6539 if (HybridICs) { 6540 Value v0 = VIRTSP(0).asValue(); 6541 Value v1 = VIRTSP(1).asValue(); 6542 if (v0.isNumber() && v1.isNumber()) { 6543 double lhs = v1.toNumber(); 6544 double rhs = v0.toNumber(); 6545 VIRTPOP(); 6546 VIRTSPWRITE(0, StackVal(NumberValue(NumberDiv(lhs, rhs)))); 6547 NEXT_IC(); 6548 END_OP(Div); 6549 } 6550 6551 MutableHandleValue lhs = SPHANDLEMUT(1); 6552 MutableHandleValue rhs = SPHANDLEMUT(0); 6553 MutableHandleValue result = SPHANDLEMUT(1); 6554 { 6555 PUSH_EXIT_FRAME(); 6556 if (!DivOperation(cx, lhs, rhs, result)) { 6557 GOTO_ERROR(); 6558 } 6559 } 6560 VIRTPOP(); 6561 NEXT_IC(); 6562 END_OP(Div); 6563 } 6564 goto generic_binary; 6565 } 6566 CASE(Mod) { 6567 if (HybridICs) { 6568 Value v0 = VIRTSP(0).asValue(); 6569 Value v1 = VIRTSP(1).asValue(); 6570 if (v0.isInt32() && v1.isInt32()) { 6571 int64_t lhs = v1.toInt32(); 6572 int64_t rhs = v0.toInt32(); 6573 if (lhs > 0 && rhs > 0) { 6574 int64_t mod = lhs % rhs; 6575 VIRTPOP(); 6576 VIRTSPWRITE(0, StackVal(Int32Value(int32_t(mod)))); 6577 NEXT_IC(); 6578 END_OP(Mod); 6579 } 6580 } 6581 if (v0.isNumber() && v1.isNumber()) { 6582 double lhs = v1.toNumber(); 6583 double rhs = v0.toNumber(); 6584 VIRTPOP(); 6585 VIRTSPWRITE(0, StackVal(DoubleValue(NumberMod(lhs, rhs)))); 6586 NEXT_IC(); 6587 END_OP(Mod); 6588 } 6589 6590 MutableHandleValue lhs = SPHANDLEMUT(1); 6591 MutableHandleValue rhs = SPHANDLEMUT(0); 6592 MutableHandleValue result = SPHANDLEMUT(1); 6593 { 6594 PUSH_EXIT_FRAME(); 6595 if (!ModOperation(cx, lhs, rhs, result)) { 6596 GOTO_ERROR(); 6597 } 6598 } 6599 VIRTPOP(); 6600 NEXT_IC(); 6601 END_OP(Mod); 6602 } 6603 goto generic_binary; 6604 } 6605 CASE(Pow) { 6606 if (HybridICs) { 6607 Value v0 = VIRTSP(0).asValue(); 6608 Value v1 = VIRTSP(1).asValue(); 6609 if (v0.isNumber() && v1.isNumber()) { 6610 double lhs = v1.toNumber(); 6611 double rhs = v0.toNumber(); 6612 VIRTPOP(); 6613 VIRTSPWRITE(0, StackVal(NumberValue(ecmaPow(lhs, rhs)))); 6614 NEXT_IC(); 6615 END_OP(Pow); 6616 } 6617 6618 MutableHandleValue lhs = SPHANDLEMUT(1); 6619 MutableHandleValue rhs = SPHANDLEMUT(0); 6620 MutableHandleValue result = SPHANDLEMUT(1); 6621 { 6622 PUSH_EXIT_FRAME(); 6623 if (!PowOperation(cx, lhs, rhs, result)) { 6624 GOTO_ERROR(); 6625 } 6626 } 6627 VIRTPOP(); 6628 NEXT_IC(); 6629 END_OP(Pow); 6630 } 6631 goto generic_binary; 6632 } 6633 CASE(BitOr) { 6634 if (HybridICs) { 6635 Value v0 = VIRTSP(0).asValue(); 6636 Value v1 = VIRTSP(1).asValue(); 6637 if (v0.isInt32() && v1.isInt32()) { 6638 int32_t lhs = v1.toInt32(); 6639 int32_t rhs = v0.toInt32(); 6640 VIRTPOP(); 6641 VIRTSPWRITE(0, StackVal(Int32Value(lhs | rhs))); 6642 NEXT_IC(); 6643 END_OP(BitOr); 6644 } 6645 } 6646 goto generic_binary; 6647 } 6648 CASE(BitAnd) { 6649 if (HybridICs) { 6650 Value v0 = VIRTSP(0).asValue(); 6651 Value v1 = VIRTSP(1).asValue(); 6652 if (v0.isInt32() && v1.isInt32()) { 6653 int32_t lhs = v1.toInt32(); 6654 int32_t rhs = v0.toInt32(); 6655 VIRTPOP(); 6656 VIRTSPWRITE(0, StackVal(Int32Value(lhs & rhs))); 6657 NEXT_IC(); 6658 END_OP(BitAnd); 6659 } 6660 } 6661 goto generic_binary; 6662 } 6663 CASE(BitXor) { 6664 if (HybridICs) { 6665 Value v0 = VIRTSP(0).asValue(); 6666 Value v1 = VIRTSP(1).asValue(); 6667 if (v0.isInt32() && v1.isInt32()) { 6668 int32_t lhs = v1.toInt32(); 6669 int32_t rhs = v0.toInt32(); 6670 VIRTPOP(); 6671 VIRTSPWRITE(0, StackVal(Int32Value(lhs ^ rhs))); 6672 NEXT_IC(); 6673 END_OP(BitXor); 6674 } 6675 } 6676 goto generic_binary; 6677 } 6678 CASE(Lsh) { 6679 if (HybridICs) { 6680 Value v0 = VIRTSP(0).asValue(); 6681 Value v1 = VIRTSP(1).asValue(); 6682 if (v0.isInt32() && v1.isInt32()) { 6683 // Unsigned to avoid undefined behavior on left-shift overflow 6684 // (see comment in BitLshOperation in Interpreter.cpp). 6685 uint32_t lhs = uint32_t(v1.toInt32()); 6686 uint32_t rhs = uint32_t(v0.toInt32()); 6687 VIRTPOP(); 6688 rhs &= 31; 6689 VIRTSPWRITE(0, StackVal(Int32Value(int32_t(lhs << rhs)))); 6690 NEXT_IC(); 6691 END_OP(Lsh); 6692 } 6693 } 6694 goto generic_binary; 6695 } 6696 CASE(Rsh) { 6697 if (HybridICs) { 6698 Value v0 = VIRTSP(0).asValue(); 6699 Value v1 = VIRTSP(1).asValue(); 6700 if (v0.isInt32() && v1.isInt32()) { 6701 int32_t lhs = v1.toInt32(); 6702 int32_t rhs = v0.toInt32(); 6703 VIRTPOP(); 6704 rhs &= 31; 6705 VIRTSPWRITE(0, StackVal(Int32Value(lhs >> rhs))); 6706 NEXT_IC(); 6707 END_OP(Rsh); 6708 } 6709 } 6710 goto generic_binary; 6711 } 6712 CASE(Ursh) { 6713 if (HybridICs) { 6714 Value v0 = VIRTSP(0).asValue(); 6715 Value v1 = VIRTSP(1).asValue(); 6716 if (v0.isInt32() && v1.isInt32()) { 6717 uint32_t lhs = uint32_t(v1.toInt32()); 6718 int32_t rhs = v0.toInt32(); 6719 VIRTPOP(); 6720 rhs &= 31; 6721 uint32_t result = lhs >> rhs; 6722 StackVal stackResult(0); 6723 if (result <= uint32_t(INT32_MAX)) { 6724 stackResult = StackVal(Int32Value(int32_t(result))); 6725 } else { 6726 stackResult = StackVal(NumberValue(double(result))); 6727 } 6728 VIRTSPWRITE(0, stackResult); 6729 NEXT_IC(); 6730 END_OP(Ursh); 6731 } 6732 } 6733 goto generic_binary; 6734 } 6735 6736 generic_binary:; 6737 { 6738 static_assert(JSOpLength_BitOr == JSOpLength_BitXor); 6739 static_assert(JSOpLength_BitOr == JSOpLength_BitAnd); 6740 static_assert(JSOpLength_BitOr == JSOpLength_Lsh); 6741 static_assert(JSOpLength_BitOr == JSOpLength_Rsh); 6742 static_assert(JSOpLength_BitOr == JSOpLength_Ursh); 6743 static_assert(JSOpLength_BitOr == JSOpLength_Add); 6744 static_assert(JSOpLength_BitOr == JSOpLength_Sub); 6745 static_assert(JSOpLength_BitOr == JSOpLength_Mul); 6746 static_assert(JSOpLength_BitOr == JSOpLength_Div); 6747 static_assert(JSOpLength_BitOr == JSOpLength_Mod); 6748 static_assert(JSOpLength_BitOr == JSOpLength_Pow); 6749 IC_POP_ARG(1); 6750 IC_POP_ARG(0); 6751 IC_ZERO_ARG(2); 6752 INVOKE_IC_AND_PUSH(BinaryArith, false); 6753 END_OP(Div); 6754 } 6755 6756 CASE(Eq) { 6757 if (HybridICs) { 6758 Value v0 = VIRTSP(0).asValue(); 6759 Value v1 = VIRTSP(1).asValue(); 6760 if (v0.isInt32() && v1.isInt32()) { 6761 bool result = v0.toInt32() == v1.toInt32(); 6762 VIRTPOP(); 6763 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6764 NEXT_IC(); 6765 END_OP(Eq); 6766 } 6767 if (v0.isNumber() && v1.isNumber()) { 6768 double lhs = v1.toNumber(); 6769 double rhs = v0.toNumber(); 6770 bool result = lhs == rhs; 6771 VIRTPOP(); 6772 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6773 NEXT_IC(); 6774 END_OP(Eq); 6775 } 6776 if (v0.isNumber() && v1.isNumber()) { 6777 bool result = v0.toNumber() == v1.toNumber(); 6778 VIRTPOP(); 6779 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6780 NEXT_IC(); 6781 END_OP(Eq); 6782 } 6783 } 6784 goto generic_cmp; 6785 } 6786 6787 CASE(Ne) { 6788 if (HybridICs) { 6789 Value v0 = VIRTSP(0).asValue(); 6790 Value v1 = VIRTSP(1).asValue(); 6791 if (v0.isInt32() && v1.isInt32()) { 6792 bool result = v0.toInt32() != v1.toInt32(); 6793 VIRTPOP(); 6794 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6795 NEXT_IC(); 6796 END_OP(Ne); 6797 } 6798 if (v0.isNumber() && v1.isNumber()) { 6799 double lhs = v1.toNumber(); 6800 double rhs = v0.toNumber(); 6801 bool result = lhs != rhs; 6802 VIRTPOP(); 6803 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6804 NEXT_IC(); 6805 END_OP(Ne); 6806 } 6807 if (v0.isNumber() && v1.isNumber()) { 6808 bool result = v0.toNumber() != v1.toNumber(); 6809 VIRTPOP(); 6810 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6811 NEXT_IC(); 6812 END_OP(Eq); 6813 } 6814 } 6815 goto generic_cmp; 6816 } 6817 6818 CASE(Lt) { 6819 if (HybridICs) { 6820 Value v0 = VIRTSP(0).asValue(); 6821 Value v1 = VIRTSP(1).asValue(); 6822 if (v0.isInt32() && v1.isInt32()) { 6823 bool result = v1.toInt32() < v0.toInt32(); 6824 VIRTPOP(); 6825 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6826 NEXT_IC(); 6827 END_OP(Lt); 6828 } 6829 if (v0.isNumber() && v1.isNumber()) { 6830 double lhs = v1.toNumber(); 6831 double rhs = v0.toNumber(); 6832 bool result = lhs < rhs; 6833 if (std::isnan(lhs) || std::isnan(rhs)) { 6834 result = false; 6835 } 6836 VIRTPOP(); 6837 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6838 NEXT_IC(); 6839 END_OP(Lt); 6840 } 6841 } 6842 goto generic_cmp; 6843 } 6844 CASE(Le) { 6845 if (HybridICs) { 6846 Value v0 = VIRTSP(0).asValue(); 6847 Value v1 = VIRTSP(1).asValue(); 6848 if (v0.isInt32() && v1.isInt32()) { 6849 bool result = v1.toInt32() <= v0.toInt32(); 6850 VIRTPOP(); 6851 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6852 NEXT_IC(); 6853 END_OP(Le); 6854 } 6855 if (v0.isNumber() && v1.isNumber()) { 6856 double lhs = v1.toNumber(); 6857 double rhs = v0.toNumber(); 6858 bool result = lhs <= rhs; 6859 if (std::isnan(lhs) || std::isnan(rhs)) { 6860 result = false; 6861 } 6862 VIRTPOP(); 6863 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6864 NEXT_IC(); 6865 END_OP(Le); 6866 } 6867 } 6868 goto generic_cmp; 6869 } 6870 CASE(Gt) { 6871 if (HybridICs) { 6872 Value v0 = VIRTSP(0).asValue(); 6873 Value v1 = VIRTSP(1).asValue(); 6874 if (v0.isInt32() && v1.isInt32()) { 6875 bool result = v1.toInt32() > v0.toInt32(); 6876 VIRTPOP(); 6877 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6878 NEXT_IC(); 6879 END_OP(Gt); 6880 } 6881 if (v0.isNumber() && v1.isNumber()) { 6882 double lhs = v1.toNumber(); 6883 double rhs = v0.toNumber(); 6884 bool result = lhs > rhs; 6885 if (std::isnan(lhs) || std::isnan(rhs)) { 6886 result = false; 6887 } 6888 VIRTPOP(); 6889 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6890 NEXT_IC(); 6891 END_OP(Gt); 6892 } 6893 } 6894 goto generic_cmp; 6895 } 6896 CASE(Ge) { 6897 if (HybridICs) { 6898 Value v0 = VIRTSP(0).asValue(); 6899 Value v1 = VIRTSP(1).asValue(); 6900 if (v0.isInt32() && v1.isInt32()) { 6901 bool result = v1.toInt32() >= v0.toInt32(); 6902 VIRTPOP(); 6903 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6904 NEXT_IC(); 6905 END_OP(Ge); 6906 } 6907 if (v0.isNumber() && v1.isNumber()) { 6908 double lhs = v1.toNumber(); 6909 double rhs = v0.toNumber(); 6910 bool result = lhs >= rhs; 6911 if (std::isnan(lhs) || std::isnan(rhs)) { 6912 result = false; 6913 } 6914 VIRTPOP(); 6915 VIRTSPWRITE(0, StackVal(BooleanValue(result))); 6916 NEXT_IC(); 6917 END_OP(Ge); 6918 } 6919 } 6920 goto generic_cmp; 6921 } 6922 6923 CASE(StrictEq) 6924 CASE(StrictNe) { 6925 if (HybridICs) { 6926 Value v0 = VIRTSP(0).asValue(); 6927 Value v1 = VIRTSP(1).asValue(); 6928 bool result; 6929 HandleValue lval = SPHANDLE(1); 6930 HandleValue rval = SPHANDLE(0); 6931 if (v0.isString() && v1.isString()) { 6932 PUSH_EXIT_FRAME(); 6933 if (!js::StrictlyEqual(cx, lval, rval, &result)) { 6934 GOTO_ERROR(); 6935 } 6936 } else { 6937 if (!js::StrictlyEqual(nullptr, lval, rval, &result)) { 6938 GOTO_ERROR(); 6939 } 6940 } 6941 VIRTPOP(); 6942 VIRTSPWRITE(0, 6943 StackVal(BooleanValue( 6944 (JSOp(*pc) == JSOp::StrictEq) ? result : !result))); 6945 NEXT_IC(); 6946 END_OP(StrictEq); 6947 } else { 6948 goto generic_cmp; 6949 } 6950 } 6951 6952 generic_cmp:; 6953 { 6954 static_assert(JSOpLength_Eq == JSOpLength_Ne); 6955 static_assert(JSOpLength_Eq == JSOpLength_StrictEq); 6956 static_assert(JSOpLength_Eq == JSOpLength_StrictNe); 6957 static_assert(JSOpLength_Eq == JSOpLength_Lt); 6958 static_assert(JSOpLength_Eq == JSOpLength_Gt); 6959 static_assert(JSOpLength_Eq == JSOpLength_Le); 6960 static_assert(JSOpLength_Eq == JSOpLength_Ge); 6961 IC_POP_ARG(1); 6962 IC_POP_ARG(0); 6963 IC_ZERO_ARG(2); 6964 INVOKE_IC_AND_PUSH(Compare, false); 6965 END_OP(Eq); 6966 } 6967 6968 CASE(StrictConstantNe) 6969 CASE(StrictConstantEq) { 6970 JSOp op = JSOp(*pc); 6971 uint16_t operand = GET_UINT16(pc); 6972 { 6973 bool result = js::ConstantStrictEqual(VIRTPOP().asValue(), operand); 6974 VIRTPUSH(StackVal( 6975 BooleanValue(op == JSOp::StrictConstantEq ? result : !result))); 6976 } 6977 END_OP(StrictConstantEq); 6978 } 6979 6980 CASE(Instanceof) { 6981 IC_POP_ARG(1); 6982 IC_POP_ARG(0); 6983 IC_ZERO_ARG(2); 6984 INVOKE_IC_AND_PUSH(InstanceOf, false); 6985 END_OP(Instanceof); 6986 } 6987 6988 CASE(In) { 6989 IC_POP_ARG(1); 6990 IC_POP_ARG(0); 6991 IC_ZERO_ARG(2); 6992 INVOKE_IC_AND_PUSH(In, false); 6993 END_OP(In); 6994 } 6995 6996 CASE(ToPropertyKey) { 6997 IC_POP_ARG(0); 6998 IC_ZERO_ARG(1); 6999 IC_ZERO_ARG(2); 7000 INVOKE_IC_AND_PUSH(ToPropertyKey, false); 7001 END_OP(ToPropertyKey); 7002 } 7003 7004 CASE(ToString) { 7005 if (VIRTSP(0).asValue().isString()) { 7006 END_OP(ToString); 7007 } 7008 { 7009 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7010 if (JSString* result = ToStringSlow<NoGC>( 7011 ctx.frameMgr.cxForLocalUseOnly(), value0)) { 7012 VIRTPUSH(StackVal(StringValue(result))); 7013 } else { 7014 { 7015 PUSH_EXIT_FRAME(); 7016 result = ToString<CanGC>(cx, value0); 7017 if (!result) { 7018 GOTO_ERROR(); 7019 } 7020 } 7021 VIRTPUSH(StackVal(StringValue(result))); 7022 } 7023 } 7024 END_OP(ToString); 7025 } 7026 7027 CASE(IsNullOrUndefined) { 7028 Value v = VIRTSP(0).asValue(); 7029 bool result = v.isNull() || v.isUndefined(); 7030 VIRTPUSH(StackVal(BooleanValue(result))); 7031 END_OP(IsNullOrUndefined); 7032 } 7033 7034 CASE(GlobalThis) { 7035 VIRTPUSH(StackVal(ObjectValue(*ctx.frameMgr.cxForLocalUseOnly() 7036 ->global() 7037 ->lexicalEnvironment() 7038 .thisObject()))); 7039 END_OP(GlobalThis); 7040 } 7041 7042 CASE(NonSyntacticGlobalThis) { 7043 { 7044 ReservedRooted<JSObject*> obj0(&state.obj0, 7045 frame->environmentChain()); 7046 ReservedRooted<Value> value0(&state.value0); 7047 { 7048 PUSH_EXIT_FRAME(); 7049 js::GetNonSyntacticGlobalThis(cx, obj0, &value0); 7050 } 7051 VIRTPUSH(StackVal(value0)); 7052 } 7053 END_OP(NonSyntacticGlobalThis); 7054 } 7055 7056 CASE(NewTarget) { 7057 VIRTPUSH(StackVal(frame->newTarget())); 7058 END_OP(NewTarget); 7059 } 7060 7061 CASE(DynamicImport) { 7062 { 7063 ReservedRooted<Value> value0(&state.value0, 7064 VIRTPOP().asValue()); // options 7065 ReservedRooted<Value> value1(&state.value1, 7066 VIRTPOP().asValue()); // specifier 7067 JSObject* promise; 7068 { 7069 PUSH_EXIT_FRAME(); 7070 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 7071 promise = StartDynamicModuleImport(cx, script0, value1, value0); 7072 if (!promise) { 7073 GOTO_ERROR(); 7074 } 7075 } 7076 VIRTPUSH(StackVal(ObjectValue(*promise))); 7077 } 7078 END_OP(DynamicImport); 7079 } 7080 7081 CASE(ImportMeta) { 7082 IC_ZERO_ARG(0); 7083 IC_ZERO_ARG(1); 7084 IC_ZERO_ARG(2); 7085 INVOKE_IC_AND_PUSH(LazyConstant, false); 7086 END_OP(ImportMeta); 7087 } 7088 7089 CASE(NewInit) { 7090 if (HybridICs) { 7091 JSObject* obj; 7092 { 7093 PUSH_EXIT_FRAME(); 7094 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 7095 obj = NewObjectOperation(cx, script0, pc); 7096 if (!obj) { 7097 GOTO_ERROR(); 7098 } 7099 } 7100 VIRTPUSH(StackVal(ObjectValue(*obj))); 7101 NEXT_IC(); 7102 END_OP(NewInit); 7103 } else { 7104 IC_ZERO_ARG(0); 7105 IC_ZERO_ARG(1); 7106 IC_ZERO_ARG(2); 7107 INVOKE_IC_AND_PUSH(NewObject, false); 7108 END_OP(NewInit); 7109 } 7110 } 7111 CASE(NewObject) { 7112 if (HybridICs) { 7113 JSObject* obj; 7114 { 7115 PUSH_EXIT_FRAME(); 7116 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 7117 obj = NewObjectOperation(cx, script0, pc); 7118 if (!obj) { 7119 GOTO_ERROR(); 7120 } 7121 } 7122 VIRTPUSH(StackVal(ObjectValue(*obj))); 7123 NEXT_IC(); 7124 END_OP(NewObject); 7125 } else { 7126 IC_ZERO_ARG(0); 7127 IC_ZERO_ARG(1); 7128 IC_ZERO_ARG(2); 7129 INVOKE_IC_AND_PUSH(NewObject, false); 7130 END_OP(NewObject); 7131 } 7132 } 7133 CASE(Object) { 7134 VIRTPUSH(StackVal(ObjectValue(*frame->script()->getObject(pc)))); 7135 END_OP(Object); 7136 } 7137 CASE(ObjWithProto) { 7138 { 7139 ReservedRooted<Value> value0(&state.value0, VIRTSP(0).asValue()); 7140 JSObject* obj; 7141 { 7142 PUSH_EXIT_FRAME(); 7143 obj = ObjectWithProtoOperation(cx, value0); 7144 if (!obj) { 7145 GOTO_ERROR(); 7146 } 7147 } 7148 VIRTSPWRITE(0, StackVal(ObjectValue(*obj))); 7149 } 7150 END_OP(ObjWithProto); 7151 } 7152 7153 CASE(InitElem) 7154 CASE(InitHiddenElem) 7155 CASE(InitLockedElem) 7156 CASE(InitElemInc) 7157 CASE(SetElem) 7158 CASE(StrictSetElem) { 7159 static_assert(JSOpLength_InitElem == JSOpLength_InitHiddenElem); 7160 static_assert(JSOpLength_InitElem == JSOpLength_InitLockedElem); 7161 static_assert(JSOpLength_InitElem == JSOpLength_InitElemInc); 7162 static_assert(JSOpLength_InitElem == JSOpLength_SetElem); 7163 static_assert(JSOpLength_InitElem == JSOpLength_StrictSetElem); 7164 StackVal val = VIRTSP(0); 7165 IC_POP_ARG(2); 7166 IC_POP_ARG(1); 7167 IC_SET_ARG_FROM_STACK(0, 0); 7168 if (JSOp(*pc) == JSOp::SetElem || JSOp(*pc) == JSOp::StrictSetElem) { 7169 VIRTSPWRITE(0, val); 7170 } 7171 INVOKE_IC(SetElem, true); 7172 if (JSOp(*pc) == JSOp::InitElemInc) { 7173 VIRTPUSH( 7174 StackVal(Int32Value(Value::fromRawBits(ic_arg1).toInt32() + 1))); 7175 } 7176 END_OP(InitElem); 7177 } 7178 7179 CASE(InitPropGetter) 7180 CASE(InitHiddenPropGetter) 7181 CASE(InitPropSetter) 7182 CASE(InitHiddenPropSetter) { 7183 static_assert(JSOpLength_InitPropGetter == 7184 JSOpLength_InitHiddenPropGetter); 7185 static_assert(JSOpLength_InitPropGetter == JSOpLength_InitPropSetter); 7186 static_assert(JSOpLength_InitPropGetter == 7187 JSOpLength_InitHiddenPropSetter); 7188 { 7189 ReservedRooted<JSObject*> obj1( 7190 &state.obj1, 7191 &VIRTPOP().asValue().toObject()); // val 7192 ReservedRooted<JSObject*> obj0( 7193 &state.obj0, 7194 &VIRTSP(0).asValue().toObject()); // obj; leave on stack 7195 ReservedRooted<PropertyName*> name0(&state.name0, 7196 frame->script()->getName(pc)); 7197 { 7198 PUSH_EXIT_FRAME(); 7199 if (!InitPropGetterSetterOperation(cx, pc, obj0, name0, obj1)) { 7200 GOTO_ERROR(); 7201 } 7202 } 7203 } 7204 END_OP(InitPropGetter); 7205 } 7206 7207 CASE(InitElemGetter) 7208 CASE(InitHiddenElemGetter) 7209 CASE(InitElemSetter) 7210 CASE(InitHiddenElemSetter) { 7211 static_assert(JSOpLength_InitElemGetter == 7212 JSOpLength_InitHiddenElemGetter); 7213 static_assert(JSOpLength_InitElemGetter == JSOpLength_InitElemSetter); 7214 static_assert(JSOpLength_InitElemGetter == 7215 JSOpLength_InitHiddenElemSetter); 7216 { 7217 ReservedRooted<JSObject*> obj1( 7218 &state.obj1, 7219 &VIRTPOP().asValue().toObject()); // val 7220 ReservedRooted<Value> value0(&state.value0, 7221 VIRTPOP().asValue()); // idval 7222 ReservedRooted<JSObject*> obj0( 7223 &state.obj0, 7224 &VIRTSP(0).asValue().toObject()); // obj; leave on stack 7225 { 7226 PUSH_EXIT_FRAME(); 7227 if (!InitElemGetterSetterOperation(cx, pc, obj0, value0, obj1)) { 7228 GOTO_ERROR(); 7229 } 7230 } 7231 } 7232 END_OP(InitElemGetter); 7233 } 7234 7235 CASE(GetProp) 7236 CASE(GetBoundName) { 7237 static_assert(JSOpLength_GetProp == JSOpLength_GetBoundName); 7238 IC_POP_ARG(0); 7239 IC_ZERO_ARG(1); 7240 IC_ZERO_ARG(2); 7241 INVOKE_IC_AND_PUSH(GetProp, false); 7242 END_OP(GetProp); 7243 } 7244 CASE(GetPropSuper) { 7245 IC_POP_ARG(0); 7246 IC_POP_ARG(1); 7247 IC_ZERO_ARG(2); 7248 INVOKE_IC_AND_PUSH(GetPropSuper, false); 7249 END_OP(GetPropSuper); 7250 } 7251 7252 CASE(GetElem) { 7253 if (HybridICs && VIRTSP(1).asValue().isString()) { 7254 HandleValue lhs = SPHANDLE(1); 7255 HandleValue rhs = SPHANDLE(0); 7256 uint32_t index; 7257 if (IsDefinitelyIndex(rhs, &index)) { 7258 JSString* str = lhs.toString(); 7259 if (index < str->length() && str->isLinear()) { 7260 JSLinearString* linear = &str->asLinear(); 7261 char16_t c = linear->latin1OrTwoByteChar(index); 7262 StaticStrings& sstr = 7263 ctx.frameMgr.cxForLocalUseOnly()->staticStrings(); 7264 if (sstr.hasUnit(c)) { 7265 VIRTPOP(); 7266 VIRTSPWRITE(0, StackVal(StringValue(sstr.getUnit(c)))); 7267 NEXT_IC(); 7268 END_OP(GetElem); 7269 } 7270 } 7271 } 7272 } 7273 7274 IC_POP_ARG(1); 7275 IC_POP_ARG(0); 7276 IC_ZERO_ARG(2); 7277 INVOKE_IC_AND_PUSH(GetElem, false); 7278 END_OP(GetElem); 7279 } 7280 7281 CASE(GetElemSuper) { 7282 // N.B.: second and third args are out of order! See the saga at 7283 // https://bugzilla.mozilla.org/show_bug.cgi?id=1709328; this is 7284 // an echo of that issue. 7285 IC_POP_ARG(1); 7286 IC_POP_ARG(2); 7287 IC_POP_ARG(0); 7288 INVOKE_IC_AND_PUSH(GetElemSuper, true); 7289 END_OP(GetElemSuper); 7290 } 7291 7292 CASE(DelProp) { 7293 { 7294 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7295 ReservedRooted<PropertyName*> name0(&state.name0, 7296 frame->script()->getName(pc)); 7297 bool res = false; 7298 { 7299 PUSH_EXIT_FRAME(); 7300 if (!DelPropOperation<false>(cx, value0, name0, &res)) { 7301 GOTO_ERROR(); 7302 } 7303 } 7304 VIRTPUSH(StackVal(BooleanValue(res))); 7305 } 7306 END_OP(DelProp); 7307 } 7308 CASE(StrictDelProp) { 7309 { 7310 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7311 ReservedRooted<PropertyName*> name0(&state.name0, 7312 frame->script()->getName(pc)); 7313 bool res = false; 7314 { 7315 PUSH_EXIT_FRAME(); 7316 if (!DelPropOperation<true>(cx, value0, name0, &res)) { 7317 GOTO_ERROR(); 7318 } 7319 } 7320 VIRTPUSH(StackVal(BooleanValue(res))); 7321 } 7322 END_OP(StrictDelProp); 7323 } 7324 CASE(DelElem) { 7325 { 7326 ReservedRooted<Value> value1(&state.value1, VIRTPOP().asValue()); 7327 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7328 bool res = false; 7329 { 7330 PUSH_EXIT_FRAME(); 7331 if (!DelElemOperation<false>(cx, value0, value1, &res)) { 7332 GOTO_ERROR(); 7333 } 7334 } 7335 VIRTPUSH(StackVal(BooleanValue(res))); 7336 } 7337 END_OP(DelElem); 7338 } 7339 CASE(StrictDelElem) { 7340 { 7341 ReservedRooted<Value> value1(&state.value1, VIRTPOP().asValue()); 7342 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7343 bool res = false; 7344 { 7345 PUSH_EXIT_FRAME(); 7346 if (!DelElemOperation<true>(cx, value0, value1, &res)) { 7347 GOTO_ERROR(); 7348 } 7349 } 7350 VIRTPUSH(StackVal(BooleanValue(res))); 7351 } 7352 END_OP(StrictDelElem); 7353 } 7354 7355 CASE(HasOwn) { 7356 IC_POP_ARG(1); 7357 IC_POP_ARG(0); 7358 IC_ZERO_ARG(2); 7359 INVOKE_IC_AND_PUSH(HasOwn, false); 7360 END_OP(HasOwn); 7361 } 7362 7363 CASE(CheckPrivateField) { 7364 IC_SET_ARG_FROM_STACK(1, 0); 7365 IC_SET_ARG_FROM_STACK(0, 1); 7366 IC_ZERO_ARG(2); 7367 INVOKE_IC_AND_PUSH(CheckPrivateField, false); 7368 END_OP(CheckPrivateField); 7369 } 7370 7371 CASE(NewPrivateName) { 7372 { 7373 ReservedRooted<JSAtom*> atom0(&state.atom0, 7374 frame->script()->getAtom(pc)); 7375 JS::Symbol* symbol; 7376 { 7377 PUSH_EXIT_FRAME(); 7378 symbol = NewPrivateName(cx, atom0); 7379 if (!symbol) { 7380 GOTO_ERROR(); 7381 } 7382 } 7383 VIRTPUSH(StackVal(SymbolValue(symbol))); 7384 } 7385 END_OP(NewPrivateName); 7386 } 7387 7388 CASE(SuperBase) { 7389 JSFunction& superEnvFunc = 7390 VIRTPOP().asValue().toObject().as<JSFunction>(); 7391 MOZ_ASSERT(superEnvFunc.allowSuperProperty()); 7392 MOZ_ASSERT(superEnvFunc.baseScript()->needsHomeObject()); 7393 const Value& homeObjVal = superEnvFunc.getExtendedSlot( 7394 FunctionExtended::METHOD_HOMEOBJECT_SLOT); 7395 7396 JSObject* homeObj = &homeObjVal.toObject(); 7397 JSObject* superBase = HomeObjectSuperBase(homeObj); 7398 7399 VIRTPUSH(StackVal(ObjectOrNullValue(superBase))); 7400 END_OP(SuperBase); 7401 } 7402 7403 CASE(SetPropSuper) 7404 CASE(StrictSetPropSuper) { 7405 // stack signature: receiver, lval, rval => rval 7406 static_assert(JSOpLength_SetPropSuper == JSOpLength_StrictSetPropSuper); 7407 bool strict = JSOp(*pc) == JSOp::StrictSetPropSuper; 7408 { 7409 ReservedRooted<Value> value2(&state.value2, 7410 VIRTPOP().asValue()); // rval 7411 ReservedRooted<Value> value1(&state.value1, 7412 VIRTPOP().asValue()); // lval 7413 ReservedRooted<Value> value0(&state.value0, 7414 VIRTPOP().asValue()); // recevier 7415 ReservedRooted<PropertyName*> name0(&state.name0, 7416 frame->script()->getName(pc)); 7417 { 7418 PUSH_EXIT_FRAME(); 7419 // SetPropertySuper(cx, lval, receiver, name, rval, strict) 7420 // (N.B.: lval and receiver are transposed!) 7421 if (!SetPropertySuper(cx, value1, value0, name0, value2, strict)) { 7422 GOTO_ERROR(); 7423 } 7424 } 7425 VIRTPUSH(StackVal(value2)); 7426 } 7427 END_OP(SetPropSuper); 7428 } 7429 7430 CASE(SetElemSuper) 7431 CASE(StrictSetElemSuper) { 7432 // stack signature: receiver, key, lval, rval => rval 7433 static_assert(JSOpLength_SetElemSuper == JSOpLength_StrictSetElemSuper); 7434 bool strict = JSOp(*pc) == JSOp::StrictSetElemSuper; 7435 { 7436 ReservedRooted<Value> value3(&state.value3, 7437 VIRTPOP().asValue()); // rval 7438 ReservedRooted<Value> value2(&state.value2, 7439 VIRTPOP().asValue()); // lval 7440 ReservedRooted<Value> value1(&state.value1, 7441 VIRTPOP().asValue()); // index 7442 ReservedRooted<Value> value0(&state.value0, 7443 VIRTPOP().asValue()); // receiver 7444 { 7445 PUSH_EXIT_FRAME(); 7446 // SetElementSuper(cx, lval, receiver, index, rval, strict) 7447 // (N.B.: lval, receiver and index are rotated!) 7448 if (!SetElementSuper(cx, value2, value0, value1, value3, strict)) { 7449 GOTO_ERROR(); 7450 } 7451 } 7452 VIRTPUSH(StackVal(value3)); // value 7453 } 7454 END_OP(SetElemSuper); 7455 } 7456 7457 CASE(Iter) { 7458 IC_POP_ARG(0); 7459 IC_ZERO_ARG(1); 7460 IC_ZERO_ARG(2); 7461 INVOKE_IC_AND_PUSH(GetIterator, false); 7462 END_OP(Iter); 7463 } 7464 7465 CASE(MoreIter) { 7466 // iter => iter, name 7467 Value v = IteratorMore(&VIRTSP(0).asValue().toObject()); 7468 VIRTPUSH(StackVal(v)); 7469 END_OP(MoreIter); 7470 } 7471 7472 CASE(IsNoIter) { 7473 // iter => iter, bool 7474 bool result = VIRTSP(0).asValue().isMagic(JS_NO_ITER_VALUE); 7475 VIRTPUSH(StackVal(BooleanValue(result))); 7476 END_OP(IsNoIter); 7477 } 7478 7479 CASE(EndIter) { 7480 // iter, interval => 7481 VIRTPOP(); 7482 CloseIterator(&VIRTPOP().asValue().toObject()); 7483 END_OP(EndIter); 7484 } 7485 7486 CASE(CloseIter) { 7487 IC_SET_OBJ_ARG(0, &VIRTPOP().asValue().toObject()); 7488 IC_ZERO_ARG(1); 7489 IC_ZERO_ARG(2); 7490 INVOKE_IC(CloseIter, false); 7491 END_OP(CloseIter); 7492 } 7493 7494 CASE(CheckIsObj) { 7495 if (!VIRTSP(0).asValue().isObject()) { 7496 PUSH_EXIT_FRAME(); 7497 MOZ_ALWAYS_FALSE( 7498 js::ThrowCheckIsObject(cx, js::CheckIsObjectKind(GET_UINT8(pc)))); 7499 /* abandon frame; error handler will re-establish sp */ 7500 GOTO_ERROR(); 7501 } 7502 END_OP(CheckIsObj); 7503 } 7504 7505 CASE(CheckObjCoercible) { 7506 { 7507 ReservedRooted<Value> value0(&state.value0, VIRTSP(0).asValue()); 7508 if (value0.isNullOrUndefined()) { 7509 PUSH_EXIT_FRAME(); 7510 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, value0)); 7511 /* abandon frame; error handler will re-establish sp */ 7512 GOTO_ERROR(); 7513 } 7514 } 7515 END_OP(CheckObjCoercible); 7516 } 7517 7518 CASE(ToAsyncIter) { 7519 // iter, next => asynciter 7520 { 7521 ReservedRooted<Value> value0(&state.value0, 7522 VIRTPOP().asValue()); // next 7523 ReservedRooted<JSObject*> obj0( 7524 &state.obj0, 7525 &VIRTPOP().asValue().toObject()); // iter 7526 JSObject* result; 7527 { 7528 PUSH_EXIT_FRAME(); 7529 result = CreateAsyncFromSyncIterator(cx, obj0, value0); 7530 if (!result) { 7531 GOTO_ERROR(); 7532 } 7533 } 7534 VIRTPUSH(StackVal(ObjectValue(*result))); 7535 } 7536 END_OP(ToAsyncIter); 7537 } 7538 7539 CASE(MutateProto) { 7540 // obj, protoVal => obj 7541 { 7542 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7543 ReservedRooted<JSObject*> obj0(&state.obj0, 7544 &VIRTSP(0).asValue().toObject()); 7545 { 7546 PUSH_EXIT_FRAME(); 7547 if (!MutatePrototype(cx, obj0.as<PlainObject>(), value0)) { 7548 GOTO_ERROR(); 7549 } 7550 } 7551 } 7552 END_OP(MutateProto); 7553 } 7554 7555 CASE(NewArray) { 7556 if (HybridICs) { 7557 ArrayObject* obj; 7558 { 7559 PUSH_EXIT_FRAME(); 7560 uint32_t length = GET_UINT32(pc); 7561 obj = NewArrayOperation(cx, length); 7562 if (!obj) { 7563 GOTO_ERROR(); 7564 } 7565 } 7566 VIRTPUSH(StackVal(ObjectValue(*obj))); 7567 NEXT_IC(); 7568 END_OP(NewArray); 7569 } else { 7570 IC_ZERO_ARG(0); 7571 IC_ZERO_ARG(1); 7572 IC_ZERO_ARG(2); 7573 INVOKE_IC_AND_PUSH(NewArray, false); 7574 END_OP(NewArray); 7575 } 7576 } 7577 7578 CASE(InitElemArray) { 7579 // array, val => array 7580 { 7581 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 7582 ReservedRooted<JSObject*> obj0(&state.obj0, 7583 &VIRTSP(0).asValue().toObject()); 7584 { 7585 PUSH_EXIT_FRAME(); 7586 InitElemArrayOperation(cx, pc, obj0.as<ArrayObject>(), value0); 7587 } 7588 } 7589 END_OP(InitElemArray); 7590 } 7591 7592 CASE(Hole) { 7593 VIRTPUSH(StackVal(MagicValue(JS_ELEMENTS_HOLE))); 7594 END_OP(Hole); 7595 } 7596 7597 CASE(RegExp) { 7598 JSObject* obj; 7599 { 7600 PUSH_EXIT_FRAME(); 7601 ReservedRooted<JSObject*> obj0(&state.obj0, 7602 frame->script()->getRegExp(pc)); 7603 obj = CloneRegExpObject(cx, obj0.as<RegExpObject>()); 7604 if (!obj) { 7605 GOTO_ERROR(); 7606 } 7607 } 7608 VIRTPUSH(StackVal(ObjectValue(*obj))); 7609 END_OP(RegExp); 7610 } 7611 7612 CASE(Lambda) { 7613 if (HybridICs) { 7614 JSObject* clone; 7615 { 7616 PUSH_EXIT_FRAME(); 7617 ReservedRooted<JSFunction*> fun0(&state.fun0, 7618 frame->script()->getFunction(pc)); 7619 ReservedRooted<JSObject*> obj0(&state.obj0, 7620 frame->environmentChain()); 7621 clone = Lambda(cx, fun0, obj0); 7622 if (!clone) { 7623 GOTO_ERROR(); 7624 } 7625 } 7626 VIRTPUSH(StackVal(ObjectValue(*clone))); 7627 NEXT_IC(); 7628 END_OP(Lambda); 7629 } else { 7630 IC_ZERO_ARG(0); 7631 IC_ZERO_ARG(1); 7632 IC_ZERO_ARG(2); 7633 INVOKE_IC_AND_PUSH(Lambda, false); 7634 END_OP(Lambda); 7635 } 7636 } 7637 7638 CASE(SetFunName) { 7639 // fun, name => fun 7640 { 7641 ReservedRooted<Value> value0(&state.value0, 7642 VIRTPOP().asValue()); // name 7643 ReservedRooted<JSFunction*> fun0( 7644 &state.fun0, &VIRTSP(0).asValue().toObject().as<JSFunction>()); 7645 FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(pc)); 7646 { 7647 PUSH_EXIT_FRAME(); 7648 if (!SetFunctionName(cx, fun0, value0, prefixKind)) { 7649 GOTO_ERROR(); 7650 } 7651 } 7652 } 7653 END_OP(SetFunName); 7654 } 7655 7656 CASE(InitHomeObject) { 7657 // fun, homeObject => fun 7658 { 7659 ReservedRooted<JSObject*> obj0( 7660 &state.obj0, &VIRTPOP().asValue().toObject()); // homeObject 7661 ReservedRooted<JSFunction*> fun0( 7662 &state.fun0, &VIRTSP(0).asValue().toObject().as<JSFunction>()); 7663 MOZ_ASSERT(fun0->allowSuperProperty()); 7664 MOZ_ASSERT(obj0->is<PlainObject>() || obj0->is<JSFunction>()); 7665 fun0->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT, 7666 ObjectValue(*obj0)); 7667 } 7668 END_OP(InitHomeObject); 7669 } 7670 7671 CASE(CheckClassHeritage) { 7672 { 7673 ReservedRooted<Value> value0(&state.value0, VIRTSP(0).asValue()); 7674 { 7675 PUSH_EXIT_FRAME(); 7676 if (!CheckClassHeritageOperation(cx, value0)) { 7677 GOTO_ERROR(); 7678 } 7679 } 7680 } 7681 END_OP(CheckClassHeritage); 7682 } 7683 7684 CASE(FunWithProto) { 7685 // proto => obj 7686 { 7687 ReservedRooted<JSObject*> obj0( 7688 &state.obj0, 7689 &VIRTPOP().asValue().toObject()); // proto 7690 ReservedRooted<JSObject*> obj1(&state.obj1, 7691 frame->environmentChain()); 7692 ReservedRooted<JSFunction*> fun0(&state.fun0, 7693 frame->script()->getFunction(pc)); 7694 JSObject* obj; 7695 { 7696 PUSH_EXIT_FRAME(); 7697 obj = FunWithProtoOperation(cx, fun0, obj1, obj0); 7698 if (!obj) { 7699 GOTO_ERROR(); 7700 } 7701 } 7702 VIRTPUSH(StackVal(ObjectValue(*obj))); 7703 } 7704 END_OP(FunWithProto); 7705 } 7706 7707 CASE(BuiltinObject) { 7708 IC_ZERO_ARG(0); 7709 IC_ZERO_ARG(1); 7710 IC_ZERO_ARG(2); 7711 INVOKE_IC_AND_PUSH(LazyConstant, false); 7712 END_OP(BuiltinObject); 7713 } 7714 7715 CASE(Call) 7716 CASE(CallIgnoresRv) 7717 CASE(CallContent) 7718 CASE(CallIter) 7719 CASE(CallContentIter) 7720 CASE(Eval) 7721 CASE(StrictEval) 7722 CASE(SuperCall) 7723 CASE(New) 7724 CASE(NewContent) { 7725 static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv); 7726 static_assert(JSOpLength_Call == JSOpLength_CallContent); 7727 static_assert(JSOpLength_Call == JSOpLength_CallIter); 7728 static_assert(JSOpLength_Call == JSOpLength_CallContentIter); 7729 static_assert(JSOpLength_Call == JSOpLength_Eval); 7730 static_assert(JSOpLength_Call == JSOpLength_StrictEval); 7731 static_assert(JSOpLength_Call == JSOpLength_SuperCall); 7732 static_assert(JSOpLength_Call == JSOpLength_New); 7733 static_assert(JSOpLength_Call == JSOpLength_NewContent); 7734 JSOp op = JSOp(*pc); 7735 bool constructing = (op == JSOp::New || op == JSOp::NewContent || 7736 op == JSOp::SuperCall); 7737 uint32_t argc = GET_ARGC(pc); 7738 do { 7739 { 7740 // CallArgsFromSp would be called with 7741 // - numValues = argc + 2 + constructing 7742 // - stackSlots = argc + constructing 7743 // - sp = vp + numValues 7744 // CallArgs::create then gets 7745 // - argc_ = stackSlots - constructing = argc 7746 // - argv_ = sp - stackSlots = vp + 2 7747 // our arguments are in reverse order compared to what CallArgs 7748 // expects so we should subtract any array subscripts from (sp + 7749 // stackSlots - 1) 7750 StackVal* firstArg = sp + argc + constructing - 1; 7751 7752 // callee is argv_[-2] -> sp + argc + constructing + 1 7753 // this is argv_[-1] -> sp + argc + constructing 7754 // newTarget is argv_[argc_] -> sp + constructing - 1 7755 // but this/newTarget are only used when constructing is 1 so we can 7756 // simplify this is argv_[-1] -> sp + argc + 1 newTarget is 7757 // argv_[argc_] -> sp 7758 7759 HandleValue callee = Stack::handle(firstArg + 2); 7760 if (!callee.isObject() || !callee.toObject().is<JSFunction>()) { 7761 TRACE_PRINTF("missed fastpath: not a function\n"); 7762 break; 7763 } 7764 ReservedRooted<JSFunction*> func( 7765 &state.fun0, &callee.toObject().as<JSFunction>()); 7766 if (!func->hasBaseScript() || !func->isInterpreted()) { 7767 TRACE_PRINTF("missed fastpath: not an interpreted script\n"); 7768 break; 7769 } 7770 if (!constructing && func->isClassConstructor()) { 7771 TRACE_PRINTF( 7772 "missed fastpath: constructor called without `new`\n"); 7773 break; 7774 } 7775 if (constructing && !func->isConstructor()) { 7776 TRACE_PRINTF( 7777 "missed fastpath: constructing with a non-constructor\n"); 7778 break; 7779 } 7780 if (!func->baseScript()->hasBytecode()) { 7781 TRACE_PRINTF("missed fastpath: no bytecode\n"); 7782 break; 7783 } 7784 ReservedRooted<JSScript*> calleeScript( 7785 &state.script0, func->baseScript()->asJSScript()); 7786 if (!calleeScript->hasJitScript()) { 7787 TRACE_PRINTF("missed fastpath: no jit-script\n"); 7788 break; 7789 } 7790 if (ctx.frameMgr.cxForLocalUseOnly()->realm() != 7791 calleeScript->realm()) { 7792 TRACE_PRINTF("missed fastpath: mismatched realm\n"); 7793 break; 7794 } 7795 if (argc < func->nargs()) { 7796 TRACE_PRINTF("missed fastpath: not enough arguments\n"); 7797 break; 7798 } 7799 7800 // Fast-path: function, interpreted, has JitScript, same realm, no 7801 // argument underflow. 7802 7803 // Include newTarget in the args if it exists; exclude callee 7804 uint32_t totalArgs = argc + 1 + constructing; 7805 StackVal* origArgs = sp; 7806 7807 TRACE_PRINTF( 7808 "Call fastpath: argc = %d origArgs = %p callee = %" PRIx64 "\n", 7809 argc, origArgs, callee.get().asRawBits()); 7810 7811 if (!ctx.stack.check(sp, sizeof(StackVal) * (totalArgs + 3))) { 7812 TRACE_PRINTF("missed fastpath: would cause stack overrun\n"); 7813 break; 7814 } 7815 7816 if (constructing) { 7817 MutableHandleValue thisv = Stack::handleMut(firstArg + 1); 7818 if (!thisv.isObject()) { 7819 HandleValue newTarget = Stack::handle(firstArg - argc); 7820 ReservedRooted<JSObject*> obj0(&state.obj0, 7821 &newTarget.toObject()); 7822 7823 PUSH_EXIT_FRAME(); 7824 // CreateThis might discard the JitScript but we're counting on 7825 // it continuing to exist while we evaluate the fastpath. 7826 AutoKeepJitScripts keepJitScript(cx); 7827 if (!CreateThis(cx, func, obj0, GenericObject, thisv)) { 7828 GOTO_ERROR(); 7829 } 7830 7831 TRACE_PRINTF("created %" PRIx64 "\n", thisv.get().asRawBits()); 7832 } 7833 } 7834 7835 // 0. Save current PC and interpreter IC pointer in 7836 // current frame, so we can retrieve them later. 7837 frame->interpreterPC() = pc; 7838 frame->interpreterICEntry() = icEntry; 7839 7840 // 1. Push a baseline stub frame. Don't use the frame manager 7841 // -- we don't want the frame to be auto-freed when we leave 7842 // this scope, and we don't want to shadow `sp`. 7843 StackVal* exitFP = ctx.stack.pushExitFrame(sp, frame); 7844 MOZ_ASSERT(exitFP); // safety: stack margin. 7845 sp = exitFP; 7846 TRACE_PRINTF("exit frame at %p\n", exitFP); 7847 7848 // 2. Modify exit code to nullptr (this is where ICStubReg is 7849 // normally saved; the tracing code can skip if null). 7850 PUSHNATIVE(StackValNative(nullptr)); 7851 7852 // 3. Push args in proper order (they are reversed in our 7853 // downward-growth stack compared to what the calling 7854 // convention expects). 7855 for (uint32_t i = 0; i < totalArgs; i++) { 7856 VIRTPUSH(origArgs[i]); 7857 } 7858 7859 // 4. Push inter-frame content: callee token, descriptor for 7860 // above. 7861 PUSHNATIVE(StackValNative(CalleeToToken(func, constructing))); 7862 PUSHNATIVE(StackValNative( 7863 MakeFrameDescriptorForJitCall(FrameType::BaselineStub, argc))); 7864 7865 // 5. Push fake return address, set script, push baseline frame. 7866 PUSHNATIVE(StackValNative(nullptr)); 7867 BaselineFrame* newFrame = 7868 ctx.stack.pushFrame(sp, ctx.frameMgr.cxForLocalUseOnly(), 7869 /* envChain = */ func->environment()); 7870 MOZ_ASSERT(newFrame); // safety: stack margin. 7871 TRACE_PRINTF("callee frame at %p\n", newFrame); 7872 frame = newFrame; 7873 ctx.frameMgr.switchToFrame(frame); 7874 ctx.frame = frame; 7875 // 6. Set up PC and SP for callee. 7876 sp = reinterpret_cast<StackVal*>(frame); 7877 RESET_PC(calleeScript->code(), calleeScript); 7878 // 7. Check callee stack space for max stack depth. 7879 if (!stack.check(sp, sizeof(StackVal) * calleeScript->nslots())) { 7880 PUSH_EXIT_FRAME(); 7881 ReportOverRecursed(ctx.frameMgr.cxForLocalUseOnly()); 7882 GOTO_ERROR(); 7883 } 7884 // 8. Push local slots, and set return value to `undefined` by 7885 // default. 7886 uint32_t nfixed = calleeScript->nfixed(); 7887 for (uint32_t i = 0; i < nfixed; i++) { 7888 VIRTPUSH(StackVal(UndefinedValue())); 7889 } 7890 ret->setUndefined(); 7891 // 9. Initialize environment objects. 7892 if (func->needsFunctionEnvironmentObjects()) { 7893 PUSH_EXIT_FRAME(); 7894 if (!js::InitFunctionEnvironmentObjects(cx, frame)) { 7895 GOTO_ERROR(); 7896 } 7897 } 7898 // 10. Set debug flag, if appropriate. 7899 if (frame->script()->isDebuggee()) { 7900 TRACE_PRINTF("Script is debuggee\n"); 7901 frame->setIsDebuggee(); 7902 7903 PUSH_EXIT_FRAME(); 7904 if (!DebugPrologue(cx, frame)) { 7905 GOTO_ERROR(); 7906 } 7907 } 7908 // 11. Check for interrupts. 7909 #ifdef ENABLE_INTERRUPT_CHECKS 7910 if (ctx.frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) { 7911 PUSH_EXIT_FRAME(); 7912 if (!InterruptCheck(cx)) { 7913 GOTO_ERROR(); 7914 } 7915 } 7916 #endif 7917 // 12. Initialize coverage tables, if needed. 7918 if (!frame->script()->hasScriptCounts()) { 7919 if (ctx.frameMgr.cxForLocalUseOnly() 7920 ->realm() 7921 ->collectCoverageForDebug()) { 7922 PUSH_EXIT_FRAME(); 7923 if (!frame->script()->initScriptCounts(cx)) { 7924 GOTO_ERROR(); 7925 } 7926 } 7927 } 7928 COUNT_COVERAGE_MAIN(); 7929 } 7930 7931 // Everything is switched to callee context now -- dispatch! 7932 DISPATCH(); 7933 } while (0); 7934 7935 // Slow path: use the IC! 7936 ic_arg0 = argc; 7937 ctx.icregs.extraArgs = 2 + constructing; 7938 INVOKE_IC(Call, false); 7939 VIRTPOPN(argc + 2 + constructing); 7940 VIRTPUSH(StackVal(Value::fromRawBits(ic_ret))); 7941 END_OP(Call); 7942 } 7943 7944 CASE(SpreadCall) 7945 CASE(SpreadEval) 7946 CASE(StrictSpreadEval) { 7947 static_assert(JSOpLength_SpreadCall == JSOpLength_SpreadEval); 7948 static_assert(JSOpLength_SpreadCall == JSOpLength_StrictSpreadEval); 7949 ic_arg0 = 1; 7950 IC_ZERO_ARG(1); 7951 IC_ZERO_ARG(2); 7952 ctx.icregs.extraArgs = 2; 7953 INVOKE_IC(SpreadCall, false); 7954 VIRTPOPN(3); 7955 VIRTPUSH(StackVal(Value::fromRawBits(ic_ret))); 7956 END_OP(SpreadCall); 7957 } 7958 7959 CASE(SpreadSuperCall) 7960 CASE(SpreadNew) { 7961 static_assert(JSOpLength_SpreadSuperCall == JSOpLength_SpreadNew); 7962 ic_arg0 = 1; 7963 ctx.icregs.extraArgs = 3; 7964 INVOKE_IC(SpreadCall, false); 7965 VIRTPOPN(4); 7966 VIRTPUSH(StackVal(Value::fromRawBits(ic_ret))); 7967 END_OP(SpreadSuperCall); 7968 } 7969 7970 CASE(OptimizeSpreadCall) { 7971 IC_POP_ARG(0); 7972 IC_ZERO_ARG(1); 7973 IC_ZERO_ARG(2); 7974 INVOKE_IC_AND_PUSH(OptimizeSpreadCall, false); 7975 END_OP(OptimizeSpreadCall); 7976 } 7977 7978 CASE(OptimizeGetIterator) { 7979 IC_POP_ARG(0); 7980 IC_ZERO_ARG(1); 7981 IC_ZERO_ARG(2); 7982 INVOKE_IC_AND_PUSH(OptimizeGetIterator, false); 7983 END_OP(OptimizeGetIterator); 7984 } 7985 7986 CASE(ImplicitThis) { 7987 { 7988 ReservedRooted<JSObject*> env(&state.obj0, 7989 &VIRTSP(0).asValue().toObject()); 7990 VIRTPOP(); 7991 PUSH_EXIT_FRAME(); 7992 ImplicitThisOperation(cx, env, &state.res); 7993 } 7994 VIRTPUSH(StackVal(state.res)); 7995 state.res.setUndefined(); 7996 END_OP(ImplicitThis); 7997 } 7998 7999 CASE(CallSiteObj) { 8000 JSObject* cso = frame->script()->getObject(pc); 8001 MOZ_ASSERT(!cso->as<ArrayObject>().isExtensible()); 8002 MOZ_ASSERT(cso->as<ArrayObject>().containsPure( 8003 ctx.frameMgr.cxForLocalUseOnly()->names().raw)); 8004 VIRTPUSH(StackVal(ObjectValue(*cso))); 8005 END_OP(CallSiteObj); 8006 } 8007 8008 CASE(IsConstructing) { 8009 VIRTPUSH(StackVal(MagicValue(JS_IS_CONSTRUCTING))); 8010 END_OP(IsConstructing); 8011 } 8012 8013 CASE(SuperFun) { 8014 JSObject* superEnvFunc = &VIRTPOP().asValue().toObject(); 8015 JSObject* superFun = SuperFunOperation(superEnvFunc); 8016 VIRTPUSH(StackVal(ObjectOrNullValue(superFun))); 8017 END_OP(SuperFun); 8018 } 8019 8020 CASE(CheckThis) { 8021 if (VIRTSP(0).asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) { 8022 PUSH_EXIT_FRAME(); 8023 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx)); 8024 GOTO_ERROR(); 8025 } 8026 END_OP(CheckThis); 8027 } 8028 8029 CASE(CheckThisReinit) { 8030 if (!VIRTSP(0).asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) { 8031 PUSH_EXIT_FRAME(); 8032 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx)); 8033 GOTO_ERROR(); 8034 } 8035 END_OP(CheckThisReinit); 8036 } 8037 8038 CASE(Generator) { 8039 JSObject* generator; 8040 { 8041 PUSH_EXIT_FRAME(); 8042 generator = CreateGeneratorFromFrame(cx, frame); 8043 if (!generator) { 8044 GOTO_ERROR(); 8045 } 8046 } 8047 VIRTPUSH(StackVal(ObjectValue(*generator))); 8048 END_OP(Generator); 8049 } 8050 8051 CASE(InitialYield) { 8052 // gen => rval, gen, resumeKind 8053 ReservedRooted<JSObject*> obj0(&state.obj0, 8054 &VIRTSP(0).asValue().toObject()); 8055 uint32_t frameSize = ctx.stack.frameSize(sp, frame); 8056 { 8057 PUSH_EXIT_FRAME(); 8058 if (!NormalSuspend(cx, obj0, frame, frameSize, pc)) { 8059 GOTO_ERROR(); 8060 } 8061 } 8062 frame->setReturnValue(VIRTSP(0).asValue()); 8063 goto do_return; 8064 } 8065 8066 CASE(Await) 8067 CASE(Yield) { 8068 // rval1, gen => rval2, gen, resumeKind 8069 ReservedRooted<JSObject*> obj0(&state.obj0, 8070 &VIRTPOP().asValue().toObject()); 8071 uint32_t frameSize = ctx.stack.frameSize(sp, frame); 8072 { 8073 PUSH_EXIT_FRAME(); 8074 if (!NormalSuspend(cx, obj0, frame, frameSize, pc)) { 8075 GOTO_ERROR(); 8076 } 8077 } 8078 frame->setReturnValue(VIRTSP(0).asValue()); 8079 goto do_return; 8080 } 8081 8082 CASE(FinalYieldRval) { 8083 // gen => 8084 ReservedRooted<JSObject*> obj0(&state.obj0, 8085 &VIRTPOP().asValue().toObject()); 8086 { 8087 PUSH_EXIT_FRAME(); 8088 if (!FinalSuspend(cx, obj0, pc)) { 8089 GOTO_ERROR(); 8090 } 8091 } 8092 goto do_return; 8093 } 8094 8095 CASE(IsGenClosing) { 8096 bool result = VIRTSP(0).asValue() == MagicValue(JS_GENERATOR_CLOSING); 8097 VIRTPUSH(StackVal(BooleanValue(result))); 8098 END_OP(IsGenClosing); 8099 } 8100 8101 CASE(AsyncAwait) { 8102 // value, gen => promise 8103 JSObject* promise; 8104 { 8105 ReservedRooted<JSObject*> obj0( 8106 &state.obj0, 8107 &VIRTPOP().asValue().toObject()); // gen 8108 ReservedRooted<Value> value0(&state.value0, 8109 VIRTPOP().asValue()); // value 8110 PUSH_EXIT_FRAME(); 8111 promise = AsyncFunctionAwait( 8112 cx, obj0.as<AsyncFunctionGeneratorObject>(), value0); 8113 if (!promise) { 8114 GOTO_ERROR(); 8115 } 8116 } 8117 VIRTPUSH(StackVal(ObjectValue(*promise))); 8118 END_OP(AsyncAwait); 8119 } 8120 8121 CASE(AsyncResolve) { 8122 // value, gen => promise 8123 JSObject* promise; 8124 { 8125 ReservedRooted<JSObject*> obj0( 8126 &state.obj0, 8127 &VIRTPOP().asValue().toObject()); // gen 8128 ReservedRooted<Value> value0(&state.value0, 8129 VIRTPOP().asValue()); // value 8130 PUSH_EXIT_FRAME(); 8131 promise = AsyncFunctionResolve( 8132 cx, obj0.as<AsyncFunctionGeneratorObject>(), value0); 8133 if (!promise) { 8134 GOTO_ERROR(); 8135 } 8136 } 8137 VIRTPUSH(StackVal(ObjectValue(*promise))); 8138 END_OP(AsyncResolve); 8139 } 8140 8141 CASE(AsyncReject) { 8142 // reason, gen => promise 8143 JSObject* promise; 8144 { 8145 ReservedRooted<JSObject*> obj0( 8146 &state.obj0, 8147 &VIRTPOP().asValue().toObject()); // gen 8148 ReservedRooted<Value> value0(&state.value0, 8149 VIRTPOP().asValue()); // stack 8150 ReservedRooted<Value> value1(&state.value1, 8151 VIRTPOP().asValue()); // reason 8152 PUSH_EXIT_FRAME(); 8153 promise = AsyncFunctionReject( 8154 cx, obj0.as<AsyncFunctionGeneratorObject>(), value1, value0); 8155 if (!promise) { 8156 GOTO_ERROR(); 8157 } 8158 } 8159 VIRTPUSH(StackVal(ObjectValue(*promise))); 8160 END_OP(AsyncReject); 8161 } 8162 8163 CASE(CanSkipAwait) { 8164 // value => value, can_skip 8165 bool result = false; 8166 { 8167 ReservedRooted<Value> value0(&state.value0, VIRTSP(0).asValue()); 8168 PUSH_EXIT_FRAME(); 8169 if (!CanSkipAwait(cx, value0, &result)) { 8170 GOTO_ERROR(); 8171 } 8172 } 8173 VIRTPUSH(StackVal(BooleanValue(result))); 8174 END_OP(CanSkipAwait); 8175 } 8176 8177 CASE(MaybeExtractAwaitValue) { 8178 // value, can_skip => value_or_resolved, can_skip 8179 { 8180 Value can_skip = VIRTPOP().asValue(); 8181 ReservedRooted<Value> value0(&state.value0, 8182 VIRTPOP().asValue()); // value 8183 if (can_skip.toBoolean()) { 8184 PUSH_EXIT_FRAME(); 8185 if (!ExtractAwaitValue(cx, value0, &value0)) { 8186 GOTO_ERROR(); 8187 } 8188 } 8189 VIRTPUSH(StackVal(value0)); 8190 VIRTPUSH(StackVal(can_skip)); 8191 } 8192 END_OP(MaybeExtractAwaitValue); 8193 } 8194 8195 CASE(ResumeKind) { 8196 GeneratorResumeKind resumeKind = ResumeKindFromPC(pc); 8197 VIRTPUSH(StackVal(Int32Value(int32_t(resumeKind)))); 8198 END_OP(ResumeKind); 8199 } 8200 8201 CASE(CheckResumeKind) { 8202 // rval, gen, resumeKind => rval 8203 { 8204 GeneratorResumeKind resumeKind = 8205 IntToResumeKind(VIRTPOP().asValue().toInt32()); 8206 ReservedRooted<JSObject*> obj0( 8207 &state.obj0, 8208 &VIRTPOP().asValue().toObject()); // gen 8209 ReservedRooted<Value> value0(&state.value0, 8210 VIRTSP(0).asValue()); // rval 8211 if (resumeKind != GeneratorResumeKind::Next) { 8212 PUSH_EXIT_FRAME(); 8213 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn( 8214 cx, frame, obj0.as<AbstractGeneratorObject>(), value0, 8215 resumeKind)); 8216 GOTO_ERROR(); 8217 } 8218 } 8219 END_OP(CheckResumeKind); 8220 } 8221 8222 CASE(Resume) { 8223 SYNCSP(); 8224 Value gen = VIRTSP(2).asValue(); 8225 Value* callerSP = reinterpret_cast<Value*>(sp); 8226 { 8227 ReservedRooted<Value> value0(&state.value0); 8228 ReservedRooted<JSObject*> obj0(&state.obj0, &gen.toObject()); 8229 { 8230 PUSH_EXIT_FRAME(); 8231 TRACE_PRINTF("Going to C++ interp for Resume\n"); 8232 if (!InterpretResume(cx, obj0, callerSP, &value0)) { 8233 GOTO_ERROR(); 8234 } 8235 } 8236 VIRTPOPN(2); 8237 VIRTSPWRITE(0, StackVal(value0)); 8238 } 8239 END_OP(Resume); 8240 } 8241 8242 CASE(JumpTarget) { 8243 int32_t icIndex = GET_INT32(pc); 8244 icEntry = icEntries + icIndex; 8245 COUNT_COVERAGE_PC(pc); 8246 END_OP(JumpTarget); 8247 } 8248 CASE(LoopHead) { 8249 int32_t icIndex = GET_INT32(pc); 8250 icEntry = icEntries + icIndex; 8251 #ifdef ENABLE_INTERRUPT_CHECKS 8252 if (ctx.frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) { 8253 PUSH_EXIT_FRAME(); 8254 if (!InterruptCheck(cx)) { 8255 GOTO_ERROR(); 8256 } 8257 } 8258 #endif 8259 COUNT_COVERAGE_PC(pc); 8260 END_OP(LoopHead); 8261 } 8262 CASE(AfterYield) { 8263 int32_t icIndex = GET_INT32(pc); 8264 icEntry = icEntries + icIndex; 8265 if (frame->script()->isDebuggee()) { 8266 TRACE_PRINTF("doing DebugAfterYield\n"); 8267 PUSH_EXIT_FRAME(); 8268 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 8269 if (DebugAPI::hasAnyBreakpointsOrStepMode(script0) && 8270 !HandleDebugTrap(cx, frame, pc)) { 8271 TRACE_PRINTF("HandleDebugTrap returned error\n"); 8272 GOTO_ERROR(); 8273 } 8274 if (!DebugAfterYield(cx, frame)) { 8275 TRACE_PRINTF("DebugAfterYield returned error\n"); 8276 GOTO_ERROR(); 8277 } 8278 } 8279 COUNT_COVERAGE_PC(pc); 8280 END_OP(AfterYield); 8281 } 8282 8283 CASE(Goto) { 8284 ADVANCE(GET_JUMP_OFFSET(pc)); 8285 PREDICT_NEXT(JumpTarget); 8286 PREDICT_NEXT(LoopHead); 8287 DISPATCH(); 8288 } 8289 8290 CASE(Coalesce) { 8291 if (!VIRTSP(0).asValue().isNullOrUndefined()) { 8292 ADVANCE(GET_JUMP_OFFSET(pc)); 8293 DISPATCH(); 8294 } else { 8295 END_OP(Coalesce); 8296 } 8297 } 8298 8299 CASE(Case) { 8300 bool cond = VIRTPOP().asValue().toBoolean(); 8301 if (cond) { 8302 VIRTPOP(); 8303 ADVANCE(GET_JUMP_OFFSET(pc)); 8304 DISPATCH(); 8305 } else { 8306 END_OP(Case); 8307 } 8308 } 8309 8310 CASE(Default) { 8311 VIRTPOP(); 8312 ADVANCE(GET_JUMP_OFFSET(pc)); 8313 DISPATCH(); 8314 } 8315 8316 CASE(TableSwitch) { 8317 int32_t len = GET_JUMP_OFFSET(pc); 8318 int32_t low = GET_JUMP_OFFSET(pc + 1 * JUMP_OFFSET_LEN); 8319 int32_t high = GET_JUMP_OFFSET(pc + 2 * JUMP_OFFSET_LEN); 8320 Value v = VIRTPOP().asValue(); 8321 int32_t i = 0; 8322 if (v.isInt32()) { 8323 i = v.toInt32(); 8324 } else if (!v.isDouble() || 8325 !mozilla::NumberEqualsInt32(v.toDouble(), &i)) { 8326 ADVANCE(len); 8327 DISPATCH(); 8328 } 8329 8330 if (i >= low && i <= high) { 8331 uint32_t idx = uint32_t(i) - uint32_t(low); 8332 uint32_t firstResumeIndex = GET_RESUMEINDEX(pc + 3 * JUMP_OFFSET_LEN); 8333 pc = entryPC + resumeOffsets[firstResumeIndex + idx]; 8334 DISPATCH(); 8335 } 8336 ADVANCE(len); 8337 DISPATCH(); 8338 } 8339 8340 CASE(Return) { 8341 frame->setReturnValue(VIRTPOP().asValue()); 8342 goto do_return; 8343 } 8344 8345 CASE(GetRval) { 8346 VIRTPUSH(StackVal(frame->returnValue())); 8347 END_OP(GetRval); 8348 } 8349 8350 CASE(SetRval) { 8351 frame->setReturnValue(VIRTPOP().asValue()); 8352 END_OP(SetRval); 8353 } 8354 8355 do_return: 8356 CASE(RetRval) { 8357 SYNCSP(); 8358 bool ok = true; 8359 if (frame->isDebuggee() && !from_unwind) { 8360 TRACE_PRINTF("doing DebugEpilogueOnBaselineReturn\n"); 8361 PUSH_EXIT_FRAME(); 8362 ok = DebugEpilogueOnBaselineReturn(cx, frame, pc); 8363 } 8364 from_unwind = false; 8365 8366 uint32_t argc = frame->numActualArgs(); 8367 sp = ctx.stack.popFrame(); 8368 8369 // If FP is higher than the entry frame now, return; otherwise, 8370 // do an inline state update. 8371 if (stack.fp > entryFrame) { 8372 *ret = frame->returnValue(); 8373 TRACE_PRINTF("ret = %" PRIx64 "\n", ret->asRawBits()); 8374 return ok ? PBIResult::Ok : PBIResult::Error; 8375 } else { 8376 TRACE_PRINTF("Return fastpath\n"); 8377 Value ret = frame->returnValue(); 8378 TRACE_PRINTF("ret = %" PRIx64 "\n", ret.asRawBits()); 8379 8380 // Pop exit frame as well. 8381 sp = ctx.stack.popFrame(); 8382 // Pop fake return address and descriptor. 8383 POPNNATIVE(2); 8384 8385 // Set PC, frame, and current script. 8386 frame = reinterpret_cast<BaselineFrame*>( 8387 reinterpret_cast<uintptr_t>(stack.fp) - BaselineFrame::Size()); 8388 TRACE_PRINTF(" sp -> %p, fp -> %p, frame -> %p\n", sp, ctx.stack.fp, 8389 frame); 8390 ctx.frameMgr.switchToFrame(frame); 8391 ctx.frame = frame; 8392 RESET_PC(frame->interpreterPC(), frame->script()); 8393 8394 // Adjust caller's stack to complete the call op that PC still points 8395 // to in that frame (pop args, push return value). 8396 JSOp op = JSOp(*pc); 8397 bool constructing = (op == JSOp::New || op == JSOp::NewContent || 8398 op == JSOp::SuperCall); 8399 // Fix-up return value; EnterJit would do this if we hadn't bypassed 8400 // it. 8401 if (constructing && ret.isPrimitive()) { 8402 ret = sp[argc + constructing].asValue(); 8403 TRACE_PRINTF("updated ret = %" PRIx64 "\n", ret.asRawBits()); 8404 } 8405 // Pop args -- this is 1 more than how many are pushed in the 8406 // `totalArgs` count during the call fastpath because it includes 8407 // the callee. 8408 VIRTPOPN(argc + 2 + constructing); 8409 // Push return value. 8410 VIRTPUSH(StackVal(ret)); 8411 8412 if (!ok) { 8413 GOTO_ERROR(); 8414 } 8415 8416 // Advance past call instruction, and advance past IC. 8417 NEXT_IC(); 8418 ADVANCE(JSOpLength_Call); 8419 8420 DISPATCH(); 8421 } 8422 } 8423 8424 CASE(CheckReturn) { 8425 Value thisval = VIRTPOP().asValue(); 8426 // inlined version of frame->checkReturn(thisval, result) 8427 // (js/src/vm/Stack.cpp). 8428 HandleValue retVal = frame->returnValue(); 8429 if (retVal.isObject()) { 8430 VIRTPUSH(StackVal(retVal)); 8431 } else if (!retVal.isUndefined()) { 8432 PUSH_EXIT_FRAME(); 8433 MOZ_ALWAYS_FALSE(ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, 8434 JSDVG_IGNORE_STACK, retVal, 8435 nullptr)); 8436 GOTO_ERROR(); 8437 } else if (thisval.isMagic(JS_UNINITIALIZED_LEXICAL)) { 8438 PUSH_EXIT_FRAME(); 8439 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx)); 8440 GOTO_ERROR(); 8441 } else { 8442 VIRTPUSH(StackVal(thisval)); 8443 } 8444 END_OP(CheckReturn); 8445 } 8446 8447 CASE(Throw) { 8448 { 8449 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 8450 PUSH_EXIT_FRAME(); 8451 MOZ_ALWAYS_FALSE(ThrowOperation(cx, value0)); 8452 GOTO_ERROR(); 8453 } 8454 END_OP(Throw); 8455 } 8456 8457 CASE(ThrowWithStack) { 8458 { 8459 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 8460 ReservedRooted<Value> value1(&state.value1, VIRTPOP().asValue()); 8461 PUSH_EXIT_FRAME(); 8462 MOZ_ALWAYS_FALSE(ThrowWithStackOperation(cx, value1, value0)); 8463 GOTO_ERROR(); 8464 } 8465 END_OP(ThrowWithStack); 8466 } 8467 8468 CASE(ThrowMsg) { 8469 { 8470 PUSH_EXIT_FRAME(); 8471 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(pc))); 8472 GOTO_ERROR(); 8473 } 8474 END_OP(ThrowMsg); 8475 } 8476 8477 CASE(ThrowSetConst) { 8478 { 8479 PUSH_EXIT_FRAME(); 8480 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 8481 ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script0, pc); 8482 GOTO_ERROR(); 8483 } 8484 END_OP(ThrowSetConst); 8485 } 8486 8487 CASE(Try) 8488 CASE(TryDestructuring) { 8489 static_assert(JSOpLength_Try == JSOpLength_TryDestructuring); 8490 END_OP(Try); 8491 } 8492 8493 CASE(Exception) { 8494 { 8495 PUSH_EXIT_FRAME(); 8496 if (!GetAndClearException(cx, &state.res)) { 8497 GOTO_ERROR(); 8498 } 8499 } 8500 VIRTPUSH(StackVal(state.res)); 8501 state.res.setUndefined(); 8502 END_OP(Exception); 8503 } 8504 8505 CASE(ExceptionAndStack) { 8506 { 8507 ReservedRooted<Value> value0(&state.value0); 8508 { 8509 PUSH_EXIT_FRAME(); 8510 if (!cx.getCx()->getPendingExceptionStack(&value0)) { 8511 GOTO_ERROR(); 8512 } 8513 if (!GetAndClearException(cx, &state.res)) { 8514 GOTO_ERROR(); 8515 } 8516 } 8517 VIRTPUSH(StackVal(state.res)); 8518 VIRTPUSH(StackVal(value0)); 8519 state.res.setUndefined(); 8520 } 8521 END_OP(ExceptionAndStack); 8522 } 8523 8524 CASE(Finally) { 8525 #ifdef ENABLE_INTERRUPT_CHECKS 8526 if (ctx.frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) { 8527 PUSH_EXIT_FRAME(); 8528 if (!InterruptCheck(cx)) { 8529 GOTO_ERROR(); 8530 } 8531 } 8532 #endif 8533 END_OP(Finally); 8534 } 8535 8536 CASE(Uninitialized) { 8537 VIRTPUSH(StackVal(MagicValue(JS_UNINITIALIZED_LEXICAL))); 8538 END_OP(Uninitialized); 8539 } 8540 CASE(InitLexical) { 8541 uint32_t i = GET_LOCALNO(pc); 8542 frame->unaliasedLocal(i) = VIRTSP(0).asValue(); 8543 END_OP(InitLexical); 8544 } 8545 8546 CASE(InitAliasedLexical) { 8547 EnvironmentCoordinate ec = EnvironmentCoordinate(pc); 8548 EnvironmentObject& obj = getEnvironmentFromCoordinate(frame, ec); 8549 obj.setAliasedBinding(ec, VIRTSP(0).asValue()); 8550 END_OP(InitAliasedLexical); 8551 } 8552 CASE(CheckLexical) { 8553 if (VIRTSP(0).asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) { 8554 PUSH_EXIT_FRAME(); 8555 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 8556 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script0, 8557 pc); 8558 GOTO_ERROR(); 8559 } 8560 END_OP(CheckLexical); 8561 } 8562 CASE(CheckAliasedLexical) { 8563 if (VIRTSP(0).asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) { 8564 PUSH_EXIT_FRAME(); 8565 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 8566 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script0, 8567 pc); 8568 GOTO_ERROR(); 8569 } 8570 END_OP(CheckAliasedLexical); 8571 } 8572 8573 CASE(BindUnqualifiedGName) { 8574 IC_SET_OBJ_ARG( 8575 0, 8576 &ctx.frameMgr.cxForLocalUseOnly()->global()->lexicalEnvironment()); 8577 IC_ZERO_ARG(1); 8578 IC_ZERO_ARG(2); 8579 INVOKE_IC_AND_PUSH(BindName, false); 8580 END_OP(BindUnqualifiedGName); 8581 } 8582 CASE(BindName) { 8583 IC_SET_OBJ_ARG(0, frame->environmentChain()); 8584 IC_ZERO_ARG(1); 8585 IC_ZERO_ARG(2); 8586 INVOKE_IC_AND_PUSH(BindName, false); 8587 END_OP(BindName); 8588 } 8589 CASE(BindUnqualifiedName) { 8590 IC_SET_OBJ_ARG(0, frame->environmentChain()); 8591 IC_ZERO_ARG(1); 8592 IC_ZERO_ARG(2); 8593 INVOKE_IC_AND_PUSH(BindName, false); 8594 END_OP(BindUnqualifiedName); 8595 } 8596 CASE(GetGName) { 8597 IC_SET_OBJ_ARG( 8598 0, 8599 &ctx.frameMgr.cxForLocalUseOnly()->global()->lexicalEnvironment()); 8600 IC_ZERO_ARG(1); 8601 IC_ZERO_ARG(2); 8602 INVOKE_IC_AND_PUSH(GetName, false); 8603 END_OP(GetGName); 8604 } 8605 CASE(GetName) { 8606 IC_SET_OBJ_ARG(0, frame->environmentChain()); 8607 IC_ZERO_ARG(1); 8608 IC_ZERO_ARG(2); 8609 INVOKE_IC_AND_PUSH(GetName, false); 8610 END_OP(GetName); 8611 } 8612 8613 CASE(GetArg) { 8614 unsigned i = GET_ARGNO(pc); 8615 if (argsObjAliasesFormals) { 8616 VIRTPUSH(StackVal(frame->argsObj().arg(i))); 8617 } else { 8618 VIRTPUSH(StackVal(frame->argv()[i])); 8619 } 8620 END_OP(GetArg); 8621 } 8622 8623 CASE(GetFrameArg) { 8624 uint32_t i = GET_ARGNO(pc); 8625 VIRTPUSH(StackVal(frame->argv()[i])); 8626 END_OP(GetFrameArg); 8627 } 8628 8629 CASE(GetLocal) { 8630 uint32_t i = GET_LOCALNO(pc); 8631 TRACE_PRINTF(" -> local: %d\n", int(i)); 8632 VIRTPUSH(StackVal(GETLOCAL(i))); 8633 END_OP(GetLocal); 8634 } 8635 8636 CASE(ArgumentsLength) { 8637 VIRTPUSH(StackVal(Int32Value(frame->numActualArgs()))); 8638 END_OP(ArgumentsLength); 8639 } 8640 8641 CASE(GetActualArg) { 8642 MOZ_ASSERT(!frame->script()->needsArgsObj()); 8643 uint32_t index = VIRTSP(0).asValue().toInt32(); 8644 VIRTSPWRITE(0, StackVal(frame->unaliasedActual(index))); 8645 END_OP(GetActualArg); 8646 } 8647 8648 CASE(GetAliasedVar) 8649 CASE(GetAliasedDebugVar) { 8650 static_assert(JSOpLength_GetAliasedVar == 8651 JSOpLength_GetAliasedDebugVar); 8652 EnvironmentCoordinate ec = EnvironmentCoordinate(pc); 8653 EnvironmentObject& obj = getEnvironmentFromCoordinate(frame, ec); 8654 VIRTPUSH(StackVal(obj.aliasedBinding(ec))); 8655 END_OP(GetAliasedVar); 8656 } 8657 8658 CASE(GetImport) { 8659 IC_ZERO_ARG(0); 8660 IC_ZERO_ARG(1); 8661 IC_ZERO_ARG(2); 8662 INVOKE_IC_AND_PUSH(GetImport, false); 8663 END_OP(GetImport); 8664 } 8665 8666 CASE(GetIntrinsic) { 8667 IC_ZERO_ARG(0); 8668 IC_ZERO_ARG(1); 8669 IC_ZERO_ARG(2); 8670 INVOKE_IC_AND_PUSH(LazyConstant, false); 8671 END_OP(GetIntrinsic); 8672 } 8673 8674 CASE(Callee) { 8675 VIRTPUSH(StackVal(frame->calleev())); 8676 END_OP(Callee); 8677 } 8678 8679 CASE(EnvCallee) { 8680 uint16_t numHops = GET_ENVCOORD_HOPS(pc); 8681 JSObject* env = &frame->environmentChain()->as<EnvironmentObject>(); 8682 for (unsigned i = 0; i < numHops; i++) { 8683 env = &env->as<EnvironmentObject>().enclosingEnvironment(); 8684 } 8685 VIRTPUSH(StackVal(ObjectValue(env->as<CallObject>().callee()))); 8686 END_OP(EnvCallee); 8687 } 8688 8689 CASE(SetProp) 8690 CASE(StrictSetProp) 8691 CASE(SetName) 8692 CASE(StrictSetName) 8693 CASE(SetGName) 8694 CASE(StrictSetGName) { 8695 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp); 8696 static_assert(JSOpLength_SetProp == JSOpLength_SetName); 8697 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetName); 8698 static_assert(JSOpLength_SetProp == JSOpLength_SetGName); 8699 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetGName); 8700 IC_POP_ARG(1); 8701 IC_POP_ARG(0); 8702 IC_ZERO_ARG(2); 8703 VIRTPUSH(StackVal(ic_arg1)); 8704 INVOKE_IC(SetProp, false); 8705 END_OP(SetProp); 8706 } 8707 8708 CASE(InitProp) 8709 CASE(InitHiddenProp) 8710 CASE(InitLockedProp) { 8711 static_assert(JSOpLength_InitProp == JSOpLength_InitHiddenProp); 8712 static_assert(JSOpLength_InitProp == JSOpLength_InitLockedProp); 8713 IC_POP_ARG(1); 8714 IC_SET_ARG_FROM_STACK(0, 0); 8715 IC_ZERO_ARG(2); 8716 INVOKE_IC(SetProp, false); 8717 END_OP(InitProp); 8718 } 8719 CASE(InitGLexical) { 8720 IC_SET_ARG_FROM_STACK(1, 0); 8721 IC_SET_OBJ_ARG( 8722 0, 8723 &ctx.frameMgr.cxForLocalUseOnly()->global()->lexicalEnvironment()); 8724 IC_ZERO_ARG(2); 8725 INVOKE_IC(SetProp, false); 8726 END_OP(InitGLexical); 8727 } 8728 8729 CASE(SetArg) { 8730 unsigned i = GET_ARGNO(pc); 8731 if (argsObjAliasesFormals) { 8732 frame->argsObj().setArg(i, VIRTSP(0).asValue()); 8733 } else { 8734 frame->argv()[i] = VIRTSP(0).asValue(); 8735 } 8736 END_OP(SetArg); 8737 } 8738 8739 CASE(SetLocal) { 8740 uint32_t i = GET_LOCALNO(pc); 8741 TRACE_PRINTF(" -> local: %d\n", int(i)); 8742 SETLOCAL(i, VIRTSP(0).asValue()); 8743 END_OP(SetLocal); 8744 } 8745 8746 CASE(SetAliasedVar) { 8747 EnvironmentCoordinate ec = EnvironmentCoordinate(pc); 8748 EnvironmentObject& obj = getEnvironmentFromCoordinate(frame, ec); 8749 MOZ_ASSERT(!IsUninitializedLexical(obj.aliasedBinding(ec))); 8750 obj.setAliasedBinding(ec, VIRTSP(0).asValue()); 8751 END_OP(SetAliasedVar); 8752 } 8753 8754 CASE(SetIntrinsic) { 8755 { 8756 ReservedRooted<Value> value0(&state.value0, VIRTSP(0).asValue()); 8757 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 8758 { 8759 PUSH_EXIT_FRAME(); 8760 if (!SetIntrinsicOperation(cx, script0, pc, value0)) { 8761 GOTO_ERROR(); 8762 } 8763 } 8764 } 8765 END_OP(SetIntrinsic); 8766 } 8767 8768 CASE(PushLexicalEnv) { 8769 { 8770 ReservedRooted<Scope*> scope0(&state.scope0, 8771 frame->script()->getScope(pc)); 8772 { 8773 PUSH_EXIT_FRAME(); 8774 if (!frame->pushLexicalEnvironment(cx, scope0.as<LexicalScope>())) { 8775 GOTO_ERROR(); 8776 } 8777 } 8778 } 8779 END_OP(PushLexicalEnv); 8780 } 8781 CASE(PopLexicalEnv) { 8782 if (frame->isDebuggee()) { 8783 TRACE_PRINTF("doing DebugLeaveThenPopLexicalEnv\n"); 8784 PUSH_EXIT_FRAME(); 8785 if (!DebugLeaveThenPopLexicalEnv(cx, frame, pc)) { 8786 GOTO_ERROR(); 8787 } 8788 } else { 8789 frame->popOffEnvironmentChain<LexicalEnvironmentObject>(); 8790 } 8791 END_OP(PopLexicalEnv); 8792 } 8793 CASE(DebugLeaveLexicalEnv) { 8794 if (frame->isDebuggee()) { 8795 TRACE_PRINTF("doing DebugLeaveLexicalEnv\n"); 8796 PUSH_EXIT_FRAME(); 8797 if (!DebugLeaveLexicalEnv(cx, frame, pc)) { 8798 GOTO_ERROR(); 8799 } 8800 } 8801 END_OP(DebugLeaveLexicalEnv); 8802 } 8803 8804 CASE(RecreateLexicalEnv) { 8805 { 8806 PUSH_EXIT_FRAME(); 8807 if (frame->isDebuggee()) { 8808 TRACE_PRINTF("doing DebuggeeRecreateLexicalEnv\n"); 8809 if (!DebuggeeRecreateLexicalEnv(cx, frame, pc)) { 8810 GOTO_ERROR(); 8811 } 8812 } else { 8813 if (!frame->recreateLexicalEnvironment<false>(cx)) { 8814 GOTO_ERROR(); 8815 } 8816 } 8817 } 8818 END_OP(RecreateLexicalEnv); 8819 } 8820 8821 CASE(FreshenLexicalEnv) { 8822 { 8823 PUSH_EXIT_FRAME(); 8824 if (frame->isDebuggee()) { 8825 TRACE_PRINTF("doing DebuggeeFreshenLexicalEnv\n"); 8826 if (!DebuggeeFreshenLexicalEnv(cx, frame, pc)) { 8827 GOTO_ERROR(); 8828 } 8829 } else { 8830 if (!frame->freshenLexicalEnvironment<false>(cx)) { 8831 GOTO_ERROR(); 8832 } 8833 } 8834 } 8835 END_OP(FreshenLexicalEnv); 8836 } 8837 CASE(PushClassBodyEnv) { 8838 { 8839 ReservedRooted<Scope*> scope0(&state.scope0, 8840 frame->script()->getScope(pc)); 8841 PUSH_EXIT_FRAME(); 8842 if (!frame->pushClassBodyEnvironment(cx, 8843 scope0.as<ClassBodyScope>())) { 8844 GOTO_ERROR(); 8845 } 8846 } 8847 END_OP(PushClassBodyEnv); 8848 } 8849 CASE(PushVarEnv) { 8850 { 8851 ReservedRooted<Scope*> scope0(&state.scope0, 8852 frame->script()->getScope(pc)); 8853 PUSH_EXIT_FRAME(); 8854 if (!frame->pushVarEnvironment(cx, scope0)) { 8855 GOTO_ERROR(); 8856 } 8857 } 8858 END_OP(PushVarEnv); 8859 } 8860 CASE(EnterWith) { 8861 { 8862 ReservedRooted<Scope*> scope0(&state.scope0, 8863 frame->script()->getScope(pc)); 8864 ReservedRooted<Value> value0(&state.value0, VIRTPOP().asValue()); 8865 PUSH_EXIT_FRAME(); 8866 if (!EnterWithOperation(cx, frame, value0, scope0.as<WithScope>())) { 8867 GOTO_ERROR(); 8868 } 8869 } 8870 END_OP(EnterWith); 8871 } 8872 CASE(LeaveWith) { 8873 frame->popOffEnvironmentChain<WithEnvironmentObject>(); 8874 END_OP(LeaveWith); 8875 } 8876 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 8877 CASE(AddDisposable) { 8878 { 8879 ReservedRooted<JSObject*> env(&state.obj0, frame->environmentChain()); 8880 8881 ReservedRooted<JS::Value> needsClosure(&state.value0, 8882 VIRTPOP().asValue()); 8883 ReservedRooted<JS::Value> method(&state.value1, VIRTPOP().asValue()); 8884 ReservedRooted<JS::Value> val(&state.value2, VIRTPOP().asValue()); 8885 UsingHint hint = UsingHint(GET_UINT8(pc)); 8886 PUSH_EXIT_FRAME(); 8887 if (!AddDisposableResourceToCapability( 8888 cx, env, val, method, needsClosure.toBoolean(), hint)) { 8889 GOTO_ERROR(); 8890 } 8891 } 8892 END_OP(AddDisposable); 8893 } 8894 8895 CASE(TakeDisposeCapability) { 8896 { 8897 ReservedRooted<JSObject*> env(&state.obj0, frame->environmentChain()); 8898 JS::Value maybeDisposables = 8899 env->as<DisposableEnvironmentObject>().getDisposables(); 8900 8901 MOZ_ASSERT(maybeDisposables.isObject() || 8902 maybeDisposables.isUndefined()); 8903 8904 if (maybeDisposables.isUndefined()) { 8905 VIRTPUSH(StackVal(UndefinedValue())); 8906 } else { 8907 VIRTPUSH(StackVal(maybeDisposables)); 8908 env->as<DisposableEnvironmentObject>().clearDisposables(); 8909 } 8910 } 8911 END_OP(TakeDisposeCapability); 8912 } 8913 8914 CASE(CreateSuppressedError) { 8915 ErrorObject* errorObj; 8916 { 8917 ReservedRooted<JS::Value> error(&state.value0, VIRTPOP().asValue()); 8918 ReservedRooted<JS::Value> suppressed(&state.value1, 8919 VIRTPOP().asValue()); 8920 PUSH_EXIT_FRAME(); 8921 errorObj = CreateSuppressedError(cx, error, suppressed); 8922 if (!errorObj) { 8923 GOTO_ERROR(); 8924 } 8925 } 8926 VIRTPUSH(StackVal(ObjectValue(*errorObj))); 8927 END_OP(CreateSuppressedError); 8928 } 8929 #endif 8930 CASE(BindVar) { 8931 JSObject* varObj; 8932 { 8933 ReservedRooted<JSObject*> obj0(&state.obj0, 8934 frame->environmentChain()); 8935 PUSH_EXIT_FRAME(); 8936 varObj = BindVarOperation(cx, obj0); 8937 } 8938 VIRTPUSH(StackVal(ObjectValue(*varObj))); 8939 END_OP(BindVar); 8940 } 8941 8942 CASE(GlobalOrEvalDeclInstantiation) { 8943 GCThingIndex lastFun = GET_GCTHING_INDEX(pc); 8944 { 8945 ReservedRooted<JSObject*> obj0(&state.obj0, 8946 frame->environmentChain()); 8947 ReservedRooted<JSScript*> script0(&state.script0, frame->script()); 8948 PUSH_EXIT_FRAME(); 8949 if (!GlobalOrEvalDeclInstantiation(cx, obj0, script0, lastFun)) { 8950 GOTO_ERROR(); 8951 } 8952 } 8953 END_OP(GlobalOrEvalDeclInstantiation); 8954 } 8955 8956 CASE(DelName) { 8957 { 8958 ReservedRooted<PropertyName*> name0(&state.name0, 8959 frame->script()->getName(pc)); 8960 ReservedRooted<JSObject*> obj0(&state.obj0, 8961 frame->environmentChain()); 8962 PUSH_EXIT_FRAME(); 8963 if (!DeleteNameOperation(cx, name0, obj0, &state.res)) { 8964 GOTO_ERROR(); 8965 } 8966 } 8967 VIRTPUSH(StackVal(state.res)); 8968 state.res.setUndefined(); 8969 END_OP(DelName); 8970 } 8971 8972 CASE(Arguments) { 8973 { 8974 PUSH_EXIT_FRAME(); 8975 if (!NewArgumentsObject(cx, frame, &state.res)) { 8976 GOTO_ERROR(); 8977 } 8978 } 8979 VIRTPUSH(StackVal(state.res)); 8980 state.res.setUndefined(); 8981 END_OP(Arguments); 8982 } 8983 8984 CASE(Rest) { 8985 IC_ZERO_ARG(0); 8986 IC_ZERO_ARG(1); 8987 IC_ZERO_ARG(2); 8988 INVOKE_IC_AND_PUSH(Rest, false); 8989 END_OP(Rest); 8990 } 8991 8992 CASE(FunctionThis) { 8993 { 8994 PUSH_EXIT_FRAME(); 8995 if (!js::GetFunctionThis(cx, frame, &state.res)) { 8996 GOTO_ERROR(); 8997 } 8998 } 8999 VIRTPUSH(StackVal(state.res)); 9000 state.res.setUndefined(); 9001 END_OP(FunctionThis); 9002 } 9003 9004 CASE(Pop) { 9005 VIRTPOP(); 9006 END_OP(Pop); 9007 } 9008 CASE(PopN) { 9009 SYNCSP(); 9010 uint32_t n = GET_UINT16(pc); 9011 VIRTPOPN(n); 9012 END_OP(PopN); 9013 } 9014 CASE(Dup) { 9015 StackVal value = VIRTSP(0); 9016 VIRTPUSH(value); 9017 END_OP(Dup); 9018 } 9019 CASE(Dup2) { 9020 StackVal value1 = VIRTSP(0); 9021 StackVal value2 = VIRTSP(1); 9022 VIRTPUSH(value2); 9023 VIRTPUSH(value1); 9024 END_OP(Dup2); 9025 } 9026 CASE(DupAt) { 9027 unsigned i = GET_UINT24(pc); 9028 StackVal value = VIRTSP(i); 9029 VIRTPUSH(value); 9030 END_OP(DupAt); 9031 } 9032 CASE(Swap) { 9033 StackVal v0 = VIRTSP(0); 9034 StackVal v1 = VIRTSP(1); 9035 VIRTSPWRITE(0, v1); 9036 VIRTSPWRITE(1, v0); 9037 END_OP(Swap); 9038 } 9039 CASE(Pick) { 9040 unsigned i = GET_UINT8(pc); 9041 SYNCSP(); 9042 StackVal tmp = sp[i]; 9043 memmove(&sp[1], &sp[0], sizeof(StackVal) * i); 9044 VIRTSPWRITE(0, tmp); 9045 END_OP(Pick); 9046 } 9047 CASE(Unpick) { 9048 unsigned i = GET_UINT8(pc); 9049 StackVal tmp = VIRTSP(0); 9050 SYNCSP(); 9051 memmove(&sp[0], &sp[1], sizeof(StackVal) * i); 9052 sp[i] = tmp; 9053 END_OP(Unpick); 9054 } 9055 CASE(DebugCheckSelfHosted) { 9056 HandleValue val = SPHANDLE(0); 9057 { 9058 PUSH_EXIT_FRAME(); 9059 if (!Debug_CheckSelfHosted(cx, val)) { 9060 GOTO_ERROR(); 9061 } 9062 } 9063 END_OP(DebugCheckSelfHosted); 9064 } 9065 CASE(Lineno) { END_OP(Lineno); } 9066 CASE(NopDestructuring) { END_OP(NopDestructuring); } 9067 CASE(ForceInterpreter) { END_OP(ForceInterpreter); } 9068 CASE(Debugger) { 9069 { 9070 PUSH_EXIT_FRAME(); 9071 if (!OnDebuggerStatement(cx, frame)) { 9072 GOTO_ERROR(); 9073 } 9074 } 9075 END_OP(Debugger); 9076 } 9077 9078 label_default: 9079 #ifndef ENABLE_COMPUTED_GOTO_DISPATCH 9080 default: 9081 #endif 9082 MOZ_CRASH("Bad opcode"); 9083 } 9084 } 9085 9086 restart: 9087 // This is a `goto` target so that we exit any on-stack exit frames 9088 // before restarting, to match previous behavior. 9089 return PortableBaselineInterpret<true, HybridICs>( 9090 ctx.frameMgr.cxForLocalUseOnly(), ctx.state, ctx.stack, sp, envChain, ret, 9091 pc, isd, entryPC, frame, entryFrame, restartCode); 9092 9093 error: 9094 TRACE_PRINTF("HandleException: frame %p\n", frame); 9095 { 9096 ResumeFromException rfe; 9097 { 9098 PUSH_EXIT_FRAME(); 9099 HandleException(&rfe); 9100 } 9101 9102 switch (rfe.kind) { 9103 case ExceptionResumeKind::EntryFrame: 9104 TRACE_PRINTF(" -> Return from entry frame\n"); 9105 frame->setReturnValue(MagicValue(JS_ION_ERROR)); 9106 ctx.stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer); 9107 ctx.stack.unwindingSP = reinterpret_cast<StackVal*>(rfe.stackPointer); 9108 ctx.stack.unwindingFP = reinterpret_cast<StackVal*>(rfe.framePointer); 9109 goto unwind_error; 9110 case ExceptionResumeKind::Catch: 9111 RESET_PC(frame->interpreterPC(), frame->script()); 9112 ctx.stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer); 9113 ctx.stack.unwindingSP = reinterpret_cast<StackVal*>(rfe.stackPointer); 9114 ctx.stack.unwindingFP = reinterpret_cast<StackVal*>(rfe.framePointer); 9115 TRACE_PRINTF(" -> catch to pc %p\n", pc); 9116 goto unwind; 9117 case ExceptionResumeKind::Finally: 9118 RESET_PC(frame->interpreterPC(), frame->script()); 9119 ctx.stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer); 9120 sp = reinterpret_cast<StackVal*>(rfe.stackPointer); 9121 TRACE_PRINTF(" -> finally to pc %p\n", pc); 9122 VIRTPUSH(StackVal(rfe.exception)); 9123 VIRTPUSH(StackVal(rfe.exceptionStack)); 9124 VIRTPUSH(StackVal(BooleanValue(true))); 9125 ctx.stack.unwindingSP = sp; 9126 ctx.stack.unwindingFP = ctx.stack.fp; 9127 goto unwind; 9128 case ExceptionResumeKind::ForcedReturnBaseline: 9129 RESET_PC(frame->interpreterPC(), frame->script()); 9130 ctx.stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer); 9131 ctx.stack.unwindingSP = reinterpret_cast<StackVal*>(rfe.stackPointer); 9132 ctx.stack.unwindingFP = reinterpret_cast<StackVal*>(rfe.framePointer); 9133 TRACE_PRINTF(" -> forced return\n"); 9134 goto unwind_ret; 9135 case ExceptionResumeKind::ForcedReturnIon: 9136 MOZ_CRASH( 9137 "Unexpected ForcedReturnIon exception-resume kind in Portable " 9138 "Baseline"); 9139 case ExceptionResumeKind::Bailout: 9140 MOZ_CRASH( 9141 "Unexpected Bailout exception-resume kind in Portable Baseline"); 9142 case ExceptionResumeKind::WasmInterpEntry: 9143 MOZ_CRASH( 9144 "Unexpected WasmInterpEntry exception-resume kind in Portable " 9145 "Baseline"); 9146 case ExceptionResumeKind::WasmCatch: 9147 MOZ_CRASH( 9148 "Unexpected WasmCatch exception-resume kind in Portable " 9149 "Baseline"); 9150 } 9151 } 9152 9153 DISPATCH(); 9154 9155 ic_fail: 9156 RESTART(ic_result); 9157 switch (ic_result) { 9158 case PBIResult::Ok: 9159 MOZ_CRASH("Unreachable: ic_result must be an error if we reach ic_fail"); 9160 case PBIResult::Error: 9161 goto error; 9162 case PBIResult::Unwind: 9163 goto unwind; 9164 case PBIResult::UnwindError: 9165 goto unwind_error; 9166 case PBIResult::UnwindRet: 9167 goto unwind_ret; 9168 } 9169 9170 unwind: 9171 TRACE_PRINTF("unwind: fp = %p entryFrame = %p\n", ctx.stack.fp, entryFrame); 9172 if (reinterpret_cast<uintptr_t>(ctx.stack.unwindingFP) > 9173 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) { 9174 TRACE_PRINTF(" -> returning\n"); 9175 return PBIResult::Unwind; 9176 } 9177 sp = ctx.stack.unwindingSP; 9178 ctx.stack.fp = ctx.stack.unwindingFP; 9179 frame = reinterpret_cast<BaselineFrame*>( 9180 reinterpret_cast<uintptr_t>(ctx.stack.fp) - BaselineFrame::Size()); 9181 TRACE_PRINTF(" -> setting sp to %p, frame to %p\n", sp, frame); 9182 ctx.frameMgr.switchToFrame(frame); 9183 ctx.frame = frame; 9184 RESET_PC(frame->interpreterPC(), frame->script()); 9185 DISPATCH(); 9186 unwind_error: 9187 TRACE_PRINTF("unwind_error: fp = %p entryFrame = %p\n", ctx.stack.fp, 9188 entryFrame); 9189 if (reinterpret_cast<uintptr_t>(ctx.stack.unwindingFP) > 9190 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) { 9191 return PBIResult::UnwindError; 9192 } 9193 if (reinterpret_cast<uintptr_t>(ctx.stack.unwindingFP) == 9194 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) { 9195 return PBIResult::Error; 9196 } 9197 sp = ctx.stack.unwindingSP; 9198 ctx.stack.fp = ctx.stack.unwindingFP; 9199 frame = reinterpret_cast<BaselineFrame*>( 9200 reinterpret_cast<uintptr_t>(ctx.stack.fp) - BaselineFrame::Size()); 9201 TRACE_PRINTF(" -> setting sp to %p, frame to %p\n", sp, frame); 9202 ctx.frameMgr.switchToFrame(frame); 9203 ctx.frame = frame; 9204 RESET_PC(frame->interpreterPC(), frame->script()); 9205 goto error; 9206 unwind_ret: 9207 TRACE_PRINTF("unwind_ret: fp = %p entryFrame = %p\n", ctx.stack.fp, 9208 entryFrame); 9209 if (reinterpret_cast<uintptr_t>(ctx.stack.unwindingFP) > 9210 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) { 9211 return PBIResult::UnwindRet; 9212 } 9213 if (reinterpret_cast<uintptr_t>(ctx.stack.unwindingFP) == 9214 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) { 9215 *ret = frame->returnValue(); 9216 return PBIResult::Ok; 9217 } 9218 sp = ctx.stack.unwindingSP; 9219 ctx.stack.fp = ctx.stack.unwindingFP; 9220 frame = reinterpret_cast<BaselineFrame*>( 9221 reinterpret_cast<uintptr_t>(ctx.stack.fp) - BaselineFrame::Size()); 9222 TRACE_PRINTF(" -> setting sp to %p, frame to %p\n", sp, frame); 9223 ctx.frameMgr.switchToFrame(frame); 9224 ctx.frame = frame; 9225 RESET_PC(frame->interpreterPC(), frame->script()); 9226 from_unwind = true; 9227 goto do_return; 9228 9229 #ifndef __wasi__ 9230 debug:; 9231 { 9232 TRACE_PRINTF("hit debug point\n"); 9233 PUSH_EXIT_FRAME(); 9234 if (!HandleDebugTrap(cx, frame, pc)) { 9235 TRACE_PRINTF("HandleDebugTrap returned error\n"); 9236 goto error; 9237 } 9238 RESET_PC(frame->interpreterPC(), frame->script()); 9239 TRACE_PRINTF("HandleDebugTrap done\n"); 9240 } 9241 goto dispatch; 9242 #endif 9243 } 9244 9245 /* 9246 * ----------------------------------------------- 9247 * Entry point 9248 * ----------------------------------------------- 9249 */ 9250 9251 bool PortableBaselineTrampoline(JSContext* cx, size_t argc, Value* argv, 9252 size_t numFormals, CalleeToken calleeToken, 9253 JSObject* envChain, Value* result) { 9254 State state(cx); 9255 Stack stack(cx->portableBaselineStack()); 9256 StackVal* sp = stack.top; 9257 9258 TRACE_PRINTF("Trampoline: calleeToken %p env %p\n", calleeToken, envChain); 9259 9260 // Expected stack frame: 9261 // - argN 9262 // - ... 9263 // - arg1 9264 // - this 9265 // - calleeToken 9266 // - descriptor 9267 // - "return address" (nullptr for top frame) 9268 9269 // `argc` is the number of args *excluding* `this` (`N` above). 9270 // `numFormals` is the minimum `N`; if less, we need to push 9271 // `UndefinedValue`s above. The argc in the frame descriptor does 9272 // not include `this` or any undefs. 9273 // 9274 // If constructing, there is an additional `newTarget` at the end. 9275 // 9276 // Note that `callee`, which is in the stack signature for a `Call` 9277 // JSOp, does *not* appear in this count: it is separately passed in 9278 // the `calleeToken`. 9279 9280 if (CalleeTokenIsFunction(calleeToken)) { 9281 bool constructing = CalleeTokenIsConstructing(calleeToken); 9282 size_t numCalleeActuals = std::max(argc, numFormals); 9283 size_t numUndefs = numCalleeActuals - argc; 9284 9285 // N.B.: we already checked the stack in 9286 // PortableBaselineInterpreterStackCheck; we don't do it here 9287 // because we can't push an exit frame if we don't have an entry 9288 // frame, and we need a full activation to produce the backtrace 9289 // from ReportOverRecursed. 9290 9291 if (constructing) { 9292 PUSH(StackVal(argv[argc])); 9293 } 9294 for (size_t i = 0; i < numUndefs; i++) { 9295 PUSH(StackVal(UndefinedValue())); 9296 } 9297 for (size_t i = 0; i < argc + 1; i++) { 9298 PUSH(StackVal(argv[argc - 1 - i])); 9299 } 9300 } 9301 PUSHNATIVE(StackValNative(calleeToken)); 9302 PUSHNATIVE(StackValNative( 9303 MakeFrameDescriptorForJitCall(FrameType::CppToJSJit, argc))); 9304 9305 JSScript* script = ScriptFromCalleeToken(calleeToken); 9306 jsbytecode* pc = script->code(); 9307 ImmutableScriptData* isd = script->immutableScriptData(); 9308 PBIResult ret; 9309 ret = PortableBaselineInterpret<false, kHybridICsInterp>( 9310 cx, state, stack, sp, envChain, result, pc, isd, nullptr, nullptr, 9311 nullptr, PBIResult::Ok); 9312 switch (ret) { 9313 case PBIResult::Ok: 9314 case PBIResult::UnwindRet: 9315 TRACE_PRINTF("PBI returned Ok/UnwindRet with result %" PRIx64 "\n", 9316 result->asRawBits()); 9317 break; 9318 case PBIResult::Error: 9319 case PBIResult::UnwindError: 9320 TRACE_PRINTF("PBI returned Error/UnwindError\n"); 9321 return false; 9322 case PBIResult::Unwind: 9323 MOZ_CRASH("Should not unwind out of top / entry frame"); 9324 } 9325 9326 return true; 9327 } 9328 9329 MethodStatus CanEnterPortableBaselineInterpreter(JSContext* cx, 9330 RunState& state) { 9331 if (!JitOptions.portableBaselineInterpreter) { 9332 return MethodStatus::Method_CantCompile; 9333 } 9334 if (state.script()->hasJitScript()) { 9335 return MethodStatus::Method_Compiled; 9336 } 9337 if (state.script()->hasForceInterpreterOp()) { 9338 return MethodStatus::Method_CantCompile; 9339 } 9340 if (state.script()->isAsync() || state.script()->isGenerator()) { 9341 return MethodStatus::Method_CantCompile; 9342 } 9343 if (cx->runtime()->geckoProfiler().enabled()) { 9344 return MethodStatus::Method_CantCompile; 9345 } 9346 9347 if (state.isInvoke()) { 9348 InvokeState& invoke = *state.asInvoke(); 9349 if (TooManyActualArguments(invoke.args().length())) { 9350 return MethodStatus::Method_CantCompile; 9351 } 9352 } else { 9353 if (state.asExecute()->isDebuggerEval()) { 9354 return MethodStatus::Method_CantCompile; 9355 } 9356 } 9357 if (state.script()->getWarmUpCount() <= 9358 JitOptions.portableBaselineInterpreterWarmUpThreshold) { 9359 return MethodStatus::Method_Skipped; 9360 } 9361 if (!cx->zone()->ensureJitZoneExists(cx)) { 9362 return MethodStatus::Method_Error; 9363 } 9364 9365 AutoKeepJitScripts keepJitScript(cx); 9366 if (!state.script()->ensureHasJitScript(cx, keepJitScript)) { 9367 return MethodStatus::Method_Error; 9368 } 9369 state.script()->updateJitCodeRaw(cx->runtime()); 9370 return MethodStatus::Method_Compiled; 9371 } 9372 9373 bool PortablebaselineInterpreterStackCheck(JSContext* cx, RunState& state, 9374 size_t numActualArgs) { 9375 auto& pbs = cx->portableBaselineStack(); 9376 StackVal* base = reinterpret_cast<StackVal*>(pbs.base); 9377 StackVal* top = reinterpret_cast<StackVal*>(pbs.top); 9378 ssize_t margin = kStackMargin / sizeof(StackVal); 9379 ssize_t needed = numActualArgs + state.script()->nslots() + margin; 9380 return (top - base) >= needed; 9381 } 9382 9383 } // namespace pbl 9384 } // namespace js