Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / vm / PortableBaselineInterpret.cpp
blob624aa9915a869fc6a5bf2cd5911e83b0de855331
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/. */
7 /*
8 * JavaScript "portable baseline interpreter": an interpreter that is
9 * capable of running ICs, but without any native code.
11 * See the [SMDOC] in vm/PortableBaselineInterpret.h for a high-level
12 * overview.
15 #include "vm/PortableBaselineInterpret.h"
17 #include "mozilla/Maybe.h"
18 #include <algorithm>
20 #include "jsapi.h"
22 #include "builtin/DataViewObject.h"
23 #include "builtin/MapObject.h"
24 #include "builtin/String.h"
25 #include "debugger/DebugAPI.h"
26 #include "jit/BaselineFrame.h"
27 #include "jit/BaselineIC.h"
28 #include "jit/BaselineJIT.h"
29 #include "jit/CacheIR.h"
30 #include "jit/CacheIRCompiler.h"
31 #include "jit/CacheIRReader.h"
32 #include "jit/JitFrames.h"
33 #include "jit/JitScript.h"
34 #include "jit/JSJitFrameIter.h"
35 #include "jit/VMFunctions.h"
36 #include "vm/AsyncFunction.h"
37 #include "vm/AsyncIteration.h"
38 #include "vm/EnvironmentObject.h"
39 #include "vm/EqualityOperations.h"
40 #include "vm/GeneratorObject.h"
41 #include "vm/Interpreter.h"
42 #include "vm/Iteration.h"
43 #include "vm/JitActivation.h"
44 #include "vm/JSScript.h"
45 #include "vm/Opcodes.h"
46 #include "vm/PlainObject.h"
47 #include "vm/Shape.h"
49 #include "debugger/DebugAPI-inl.h"
50 #include "jit/BaselineFrame-inl.h"
51 #include "jit/JitScript-inl.h"
52 #include "vm/EnvironmentObject-inl.h"
53 #include "vm/Interpreter-inl.h"
54 #include "vm/JSScript-inl.h"
55 #include "vm/PlainObject-inl.h"
57 namespace js {
58 namespace pbl {
60 using namespace js::jit;
63 * Debugging: enable `TRACE_INTERP` for an extremely detailed dump of
64 * what PBL is doing at every opcode step.
67 // #define TRACE_INTERP
69 #ifdef TRACE_INTERP
70 # define TRACE_PRINTF(...) \
71 do { \
72 printf(__VA_ARGS__); \
73 fflush(stdout); \
74 } while (0)
75 #else
76 # define TRACE_PRINTF(...) \
77 do { \
78 } while (0)
79 #endif
81 // Whether we are using the "hybrid" strategy for ICs (see the [SMDOC]
82 // in PortableBaselineInterpret.h for more). This is currently a
83 // constant, but may become configurable in the future.
84 static const bool kHybridICs = true;
87 * -----------------------------------------------
88 * Stack handling
89 * -----------------------------------------------
92 // Large enough for an exit frame.
93 static const size_t kStackMargin = 1024;
96 * A 64-bit value on the auxiliary stack. May either be a raw uint64_t
97 * or a `Value` (JS NaN-boxed value).
99 struct StackVal {
100 uint64_t value;
102 explicit StackVal(uint64_t v) : value(v) {}
103 explicit StackVal(const Value& v) : value(v.asRawBits()) {}
105 uint64_t asUInt64() const { return value; }
106 Value asValue() const { return Value::fromRawBits(value); }
110 * A native-pointer-sized value on the auxiliary stack. This is
111 * separate from the above because we support running on 32-bit
112 * systems as well! May either be a `void*` (or cast to a
113 * `CalleeToken`, which is a typedef for a `void*`), or a `uint32_t`,
114 * which always fits in a native pointer width on our supported
115 * platforms. (See static_assert below.)
117 struct StackValNative {
118 static_assert(sizeof(uintptr_t) >= sizeof(uint32_t),
119 "Must be at least a 32-bit system to use PBL.");
121 uintptr_t value;
123 explicit StackValNative(void* v) : value(reinterpret_cast<uintptr_t>(v)) {}
124 explicit StackValNative(uint32_t v) : value(v) {}
126 void* asVoidPtr() const { return reinterpret_cast<void*>(value); }
127 CalleeToken asCalleeToken() const {
128 return reinterpret_cast<CalleeToken>(value);
132 // Assert that the stack alignment is no more than the size of a
133 // StackValNative -- we rely on this when setting up call frames.
134 static_assert(JitStackAlignment <= sizeof(StackValNative));
136 #define PUSH(val) *--sp = (val)
137 #define POP() (*sp++)
138 #define POPN(n) sp += (n)
140 #define PUSHNATIVE(val) \
141 do { \
142 StackValNative* nativeSP = reinterpret_cast<StackValNative*>(sp); \
143 *--nativeSP = (val); \
144 sp = reinterpret_cast<StackVal*>(nativeSP); \
145 } while (0)
146 #define POPNNATIVE(n) \
147 sp = reinterpret_cast<StackVal*>(reinterpret_cast<StackValNative*>(sp) + (n))
150 * Helper class to manage the auxiliary stack and push/pop frames.
152 struct Stack {
153 StackVal* fp;
154 StackVal* base;
155 StackVal* top;
156 StackVal* unwindingSP;
158 explicit Stack(PortableBaselineStack& pbs)
159 : fp(reinterpret_cast<StackVal*>(pbs.top)),
160 base(reinterpret_cast<StackVal*>(pbs.base)),
161 top(reinterpret_cast<StackVal*>(pbs.top)),
162 unwindingSP(nullptr) {}
164 MOZ_ALWAYS_INLINE bool check(StackVal* sp, size_t size, bool margin = true) {
165 return reinterpret_cast<uintptr_t>(base) + size +
166 (margin ? kStackMargin : 0) <=
167 reinterpret_cast<uintptr_t>(sp);
170 [[nodiscard]] MOZ_ALWAYS_INLINE StackVal* allocate(StackVal* sp,
171 size_t size) {
172 if (!check(sp, size, false)) {
173 return nullptr;
175 sp = reinterpret_cast<StackVal*>(reinterpret_cast<uintptr_t>(sp) - size);
176 return sp;
179 uint32_t frameSize(StackVal* sp, BaselineFrame* curFrame) const {
180 return sizeof(StackVal) * (reinterpret_cast<StackVal*>(fp) - sp);
183 [[nodiscard]] MOZ_ALWAYS_INLINE BaselineFrame* pushFrame(StackVal* sp,
184 JSContext* cx,
185 JSObject* envChain) {
186 TRACE_PRINTF("pushFrame: sp = %p fp = %p\n", sp, fp);
187 if (sp == base) {
188 return nullptr;
190 PUSHNATIVE(StackValNative(fp));
191 fp = sp;
192 TRACE_PRINTF("pushFrame: new fp = %p\n", fp);
194 BaselineFrame* frame =
195 reinterpret_cast<BaselineFrame*>(allocate(sp, BaselineFrame::Size()));
196 if (!frame) {
197 return nullptr;
200 frame->setFlags(BaselineFrame::Flags::RUNNING_IN_INTERPRETER);
201 frame->setEnvironmentChain(envChain);
202 JSScript* script = frame->script();
203 frame->setICScript(script->jitScript()->icScript());
204 frame->setInterpreterFields(script->code());
205 #ifdef DEBUG
206 frame->setDebugFrameSize(0);
207 #endif
208 return frame;
211 StackVal* popFrame() {
212 StackVal* newTOS =
213 reinterpret_cast<StackVal*>(reinterpret_cast<StackValNative*>(fp) + 1);
214 fp = reinterpret_cast<StackVal*>(
215 reinterpret_cast<StackValNative*>(fp)->asVoidPtr());
216 MOZ_ASSERT(fp);
217 TRACE_PRINTF("popFrame: fp = %p\n", fp);
218 return newTOS;
221 void setFrameSize(StackVal* sp, BaselineFrame* prevFrame) {
222 #ifdef DEBUG
223 MOZ_ASSERT(fp != nullptr);
224 uintptr_t frameSize =
225 reinterpret_cast<uintptr_t>(fp) - reinterpret_cast<uintptr_t>(sp);
226 MOZ_ASSERT(reinterpret_cast<uintptr_t>(fp) >=
227 reinterpret_cast<uintptr_t>(sp));
228 TRACE_PRINTF("pushExitFrame: fp = %p cur() = %p -> frameSize = %d\n", fp,
229 sp, int(frameSize));
230 MOZ_ASSERT(frameSize >= BaselineFrame::Size());
231 prevFrame->setDebugFrameSize(frameSize);
232 #endif
235 [[nodiscard]] MOZ_ALWAYS_INLINE StackVal* pushExitFrame(
236 StackVal* sp, BaselineFrame* prevFrame) {
237 uint8_t* prevFP =
238 reinterpret_cast<uint8_t*>(prevFrame) + BaselineFrame::Size();
239 MOZ_ASSERT(reinterpret_cast<StackVal*>(prevFP) == fp);
240 setFrameSize(sp, prevFrame);
242 if (!check(sp, sizeof(StackVal) * 4, false)) {
243 return nullptr;
246 PUSHNATIVE(StackValNative(
247 MakeFrameDescriptorForJitCall(FrameType::BaselineJS, 0)));
248 PUSHNATIVE(StackValNative(nullptr)); // fake return address.
249 PUSHNATIVE(StackValNative(prevFP));
250 StackVal* exitFP = sp;
251 fp = exitFP;
252 TRACE_PRINTF(" -> fp = %p\n", fp);
253 PUSHNATIVE(StackValNative(uint32_t(ExitFrameType::Bare)));
254 return exitFP;
257 void popExitFrame(StackVal* fp) {
258 StackVal* prevFP = reinterpret_cast<StackVal*>(
259 reinterpret_cast<StackValNative*>(fp)->asVoidPtr());
260 MOZ_ASSERT(prevFP);
261 this->fp = prevFP;
262 TRACE_PRINTF("popExitFrame: fp -> %p\n", fp);
265 BaselineFrame* frameFromFP() {
266 return reinterpret_cast<BaselineFrame*>(reinterpret_cast<uintptr_t>(fp) -
267 BaselineFrame::Size());
270 static HandleValue handle(StackVal* sp) {
271 return HandleValue::fromMarkedLocation(reinterpret_cast<Value*>(sp));
273 static MutableHandleValue handleMut(StackVal* sp) {
274 return MutableHandleValue::fromMarkedLocation(reinterpret_cast<Value*>(sp));
279 * -----------------------------------------------
280 * Interpreter state
281 * -----------------------------------------------
284 struct ICRegs {
285 CacheIRReader cacheIRReader;
286 static const int kMaxICVals = 16;
287 uint64_t icVals[kMaxICVals];
288 uint64_t icResult;
289 int extraArgs;
290 bool spreadCall;
292 ICRegs() : cacheIRReader(nullptr, nullptr) {}
295 struct State {
296 RootedValue value0;
297 RootedValue value1;
298 RootedValue value2;
299 RootedValue value3;
300 RootedValue res;
301 RootedObject obj0;
302 RootedObject obj1;
303 RootedObject obj2;
304 RootedString str0;
305 RootedString str1;
306 RootedScript script0;
307 Rooted<PropertyName*> name0;
308 Rooted<jsid> id0;
309 Rooted<JSAtom*> atom0;
310 RootedFunction fun0;
311 Rooted<Scope*> scope0;
313 explicit State(JSContext* cx)
314 : value0(cx),
315 value1(cx),
316 value2(cx),
317 value3(cx),
318 res(cx),
319 obj0(cx),
320 obj1(cx),
321 obj2(cx),
322 str0(cx),
323 str1(cx),
324 script0(cx),
325 name0(cx),
326 id0(cx),
327 atom0(cx),
328 fun0(cx),
329 scope0(cx) {}
333 * -----------------------------------------------
334 * RAII helpers for pushing exit frames.
336 * (See [SMDOC] in PortableBaselineInterpret.h for more.)
337 * -----------------------------------------------
340 class VMFrameManager {
341 JSContext* cx;
342 BaselineFrame* frame;
343 friend class VMFrame;
345 public:
346 VMFrameManager(JSContext*& cx_, BaselineFrame* frame_)
347 : cx(cx_), frame(frame_) {
348 // Once the manager exists, we need to create an exit frame to
349 // have access to the cx (unless the caller promises it is not
350 // calling into the rest of the runtime).
351 cx_ = nullptr;
354 void switchToFrame(BaselineFrame* frame) { this->frame = frame; }
356 // Provides the JSContext, but *only* if no calls into the rest of
357 // the runtime (that may invoke a GC or stack walk) occur. Avoids
358 // the overhead of pushing an exit frame.
359 JSContext* cxForLocalUseOnly() const { return cx; }
362 class VMFrame {
363 JSContext* cx;
364 Stack& stack;
365 StackVal* exitFP;
366 void* prevSavedStack;
368 public:
369 VMFrame(VMFrameManager& mgr, Stack& stack_, StackVal* sp, jsbytecode* pc)
370 : cx(mgr.cx), stack(stack_) {
371 mgr.frame->interpreterPC() = pc;
372 exitFP = stack.pushExitFrame(sp, mgr.frame);
373 if (!exitFP) {
374 return;
376 cx->activation()->asJit()->setJSExitFP(reinterpret_cast<uint8_t*>(exitFP));
377 prevSavedStack = cx->portableBaselineStack().top;
378 cx->portableBaselineStack().top = reinterpret_cast<void*>(spBelowFrame());
381 StackVal* spBelowFrame() {
382 return reinterpret_cast<StackVal*>(reinterpret_cast<uintptr_t>(exitFP) -
383 sizeof(StackValNative));
386 ~VMFrame() {
387 stack.popExitFrame(exitFP);
388 cx->portableBaselineStack().top = prevSavedStack;
391 JSContext* getCx() const { return cx; }
392 operator JSContext*() const { return cx; }
394 bool success() const { return exitFP != nullptr; }
397 #define PUSH_EXIT_FRAME_OR_RET(value) \
398 VMFrame cx(frameMgr, stack, sp, pc); \
399 if (!cx.success()) { \
400 return value; \
402 StackVal* sp = cx.spBelowFrame(); /* shadow the definition */ \
403 (void)sp; /* avoid unused-variable warnings */
405 #define PUSH_IC_FRAME() PUSH_EXIT_FRAME_OR_RET(ICInterpretOpResult::Error)
406 #define PUSH_FALLBACK_IC_FRAME() PUSH_EXIT_FRAME_OR_RET(PBIResult::Error)
407 #define PUSH_EXIT_FRAME() PUSH_EXIT_FRAME_OR_RET(PBIResult::Error)
410 * -----------------------------------------------
411 * IC Interpreter
412 * -----------------------------------------------
415 ICInterpretOpResult MOZ_ALWAYS_INLINE
416 ICInterpretOps(BaselineFrame* frame, VMFrameManager& frameMgr, State& state,
417 ICRegs& icregs, Stack& stack, StackVal* sp, ICCacheIRStub* cstub,
418 jsbytecode* pc) {
419 #define CACHEOP_CASE(name) \
420 cacheop_##name \
421 : TRACE_PRINTF("cacheop (frame %p pc %p stub %p): " #name "\n", frame, \
422 pc, cstub);
423 #define CACHEOP_CASE_FALLTHROUGH(name) CACHEOP_CASE(name)
424 #define CACHEOP_CASE_UNIMPL(name) cacheop_##name:
426 static const void* const addresses[long(CacheOp::NumOpcodes)] = {
427 #define OP(name, ...) &&cacheop_##name,
428 CACHE_IR_OPS(OP)
429 #undef OP
432 #define DISPATCH_CACHEOP() \
433 cacheop = icregs.cacheIRReader.readOp(); \
434 goto* addresses[long(cacheop)];
436 // We set a fixed bound on the number of icVals which is smaller than what IC
437 // generators may use. As a result we can't evaluate an IC if it defines too
438 // many values. Note that we don't need to check this when reading from icVals
439 // because we should have bailed out before the earlier write which defined the
440 // same value. Similarly, we don't need to check writes to locations which we've
441 // just read from.
442 #define BOUNDSCHECK(resultId) \
443 if (resultId.id() >= ICRegs::kMaxICVals) return ICInterpretOpResult::NextIC;
445 #define PREDICT_NEXT(name) \
446 if (icregs.cacheIRReader.peekOp() == CacheOp::name) { \
447 icregs.cacheIRReader.readOp(); \
448 goto cacheop_##name; \
451 CacheOp cacheop;
453 DISPATCH_CACHEOP();
455 CACHEOP_CASE(ReturnFromIC) {
456 TRACE_PRINTF("stub successful!\n");
457 return ICInterpretOpResult::Return;
460 CACHEOP_CASE(GuardToObject) {
461 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
462 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
463 TRACE_PRINTF("GuardToObject: icVal %" PRIx64 "\n",
464 icregs.icVals[inputId.id()]);
465 if (!v.isObject()) {
466 return ICInterpretOpResult::NextIC;
468 icregs.icVals[inputId.id()] = reinterpret_cast<uint64_t>(&v.toObject());
469 PREDICT_NEXT(GuardShape);
470 PREDICT_NEXT(GuardSpecificFunction);
471 DISPATCH_CACHEOP();
474 CACHEOP_CASE(GuardIsNullOrUndefined) {
475 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
476 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
477 if (!v.isNullOrUndefined()) {
478 return ICInterpretOpResult::NextIC;
480 DISPATCH_CACHEOP();
483 CACHEOP_CASE(GuardIsNull) {
484 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
485 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
486 if (!v.isNull()) {
487 return ICInterpretOpResult::NextIC;
489 DISPATCH_CACHEOP();
492 CACHEOP_CASE(GuardIsUndefined) {
493 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
494 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
495 if (!v.isUndefined()) {
496 return ICInterpretOpResult::NextIC;
498 DISPATCH_CACHEOP();
501 CACHEOP_CASE(GuardToBoolean) {
502 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
503 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
504 if (!v.isBoolean()) {
505 return ICInterpretOpResult::NextIC;
507 icregs.icVals[inputId.id()] = v.toBoolean() ? 1 : 0;
508 DISPATCH_CACHEOP();
511 CACHEOP_CASE(GuardToString) {
512 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
513 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
514 if (!v.isString()) {
515 return ICInterpretOpResult::NextIC;
517 icregs.icVals[inputId.id()] = reinterpret_cast<uint64_t>(v.toString());
518 PREDICT_NEXT(GuardToString);
519 DISPATCH_CACHEOP();
522 CACHEOP_CASE(GuardToSymbol) {
523 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
524 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
525 if (!v.isSymbol()) {
526 return ICInterpretOpResult::NextIC;
528 icregs.icVals[inputId.id()] = reinterpret_cast<uint64_t>(v.toSymbol());
529 PREDICT_NEXT(GuardSpecificSymbol);
530 DISPATCH_CACHEOP();
533 CACHEOP_CASE(GuardToBigInt) {
534 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
535 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
536 if (!v.isBigInt()) {
537 return ICInterpretOpResult::NextIC;
539 icregs.icVals[inputId.id()] = reinterpret_cast<uint64_t>(v.toBigInt());
540 DISPATCH_CACHEOP();
543 CACHEOP_CASE(GuardIsNumber) {
544 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
545 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
546 if (!v.isNumber()) {
547 return ICInterpretOpResult::NextIC;
549 DISPATCH_CACHEOP();
552 CACHEOP_CASE(GuardToInt32) {
553 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
554 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
555 TRACE_PRINTF("GuardToInt32 (%d): icVal %" PRIx64 "\n", inputId.id(),
556 icregs.icVals[inputId.id()]);
557 if (!v.isInt32()) {
558 return ICInterpretOpResult::NextIC;
560 // N.B.: we don't need to unbox because the low 32 bits are
561 // already the int32 itself, and we are careful when using
562 // `Int32Operand`s to only use those bits.
564 PREDICT_NEXT(GuardToInt32);
565 DISPATCH_CACHEOP();
568 CACHEOP_CASE(GuardBooleanToInt32) {
569 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
570 Int32OperandId resultId = icregs.cacheIRReader.int32OperandId();
571 BOUNDSCHECK(resultId);
572 Value v = Value::fromRawBits(icregs.icVals[inputId.id()]);
573 if (!v.isBoolean()) {
574 return ICInterpretOpResult::NextIC;
576 icregs.icVals[resultId.id()] = v.toBoolean() ? 1 : 0;
577 DISPATCH_CACHEOP();
580 CACHEOP_CASE(GuardToInt32Index) {
581 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
582 Int32OperandId resultId = icregs.cacheIRReader.int32OperandId();
583 BOUNDSCHECK(resultId);
584 Value val = Value::fromRawBits(icregs.icVals[inputId.id()]);
585 if (val.isInt32()) {
586 icregs.icVals[resultId.id()] = val.toInt32();
587 DISPATCH_CACHEOP();
588 } else if (val.isDouble()) {
589 double doubleVal = val.toDouble();
590 if (doubleVal >= double(INT32_MIN) && doubleVal <= double(INT32_MAX)) {
591 icregs.icVals[resultId.id()] = int32_t(doubleVal);
592 DISPATCH_CACHEOP();
595 return ICInterpretOpResult::NextIC;
598 CACHEOP_CASE(GuardNonDoubleType) {
599 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
600 ValueType type = icregs.cacheIRReader.valueType();
601 Value val = Value::fromRawBits(icregs.icVals[inputId.id()]);
602 switch (type) {
603 case ValueType::String:
604 if (!val.isString()) {
605 return ICInterpretOpResult::NextIC;
607 break;
608 case ValueType::Symbol:
609 if (!val.isSymbol()) {
610 return ICInterpretOpResult::NextIC;
612 break;
613 case ValueType::BigInt:
614 if (!val.isBigInt()) {
615 return ICInterpretOpResult::NextIC;
617 break;
618 case ValueType::Int32:
619 if (!val.isInt32()) {
620 return ICInterpretOpResult::NextIC;
622 break;
623 case ValueType::Boolean:
624 if (!val.isBoolean()) {
625 return ICInterpretOpResult::NextIC;
627 break;
628 case ValueType::Undefined:
629 if (!val.isUndefined()) {
630 return ICInterpretOpResult::NextIC;
632 break;
633 case ValueType::Null:
634 if (!val.isNull()) {
635 return ICInterpretOpResult::NextIC;
637 break;
638 default:
639 MOZ_CRASH("Unexpected type");
641 DISPATCH_CACHEOP();
644 CACHEOP_CASE(GuardShape) {
645 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
646 uint32_t shapeOffset = icregs.cacheIRReader.stubOffset();
647 JSObject* obj = reinterpret_cast<JSObject*>(icregs.icVals[objId.id()]);
648 uintptr_t expectedShape =
649 cstub->stubInfo()->getStubRawWord(cstub, shapeOffset);
650 if (reinterpret_cast<uintptr_t>(obj->shape()) != expectedShape) {
651 return ICInterpretOpResult::NextIC;
653 DISPATCH_CACHEOP();
656 CACHEOP_CASE(GuardFuse) {
657 RealmFuses::FuseIndex fuseIndex = icregs.cacheIRReader.realmFuseIndex();
658 if (!frameMgr.cxForLocalUseOnly()
659 ->realm()
660 ->realmFuses.getFuseByIndex(fuseIndex)
661 ->intact()) {
662 return ICInterpretOpResult::NextIC;
664 DISPATCH_CACHEOP();
667 CACHEOP_CASE(GuardProto) {
668 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
669 uint32_t protoOffset = icregs.cacheIRReader.stubOffset();
670 JSObject* obj = reinterpret_cast<JSObject*>(icregs.icVals[objId.id()]);
671 uintptr_t expectedProto =
672 cstub->stubInfo()->getStubRawWord(cstub, protoOffset);
673 if (reinterpret_cast<uintptr_t>(obj->staticPrototype()) != expectedProto) {
674 return ICInterpretOpResult::NextIC;
676 PREDICT_NEXT(LoadProto);
677 DISPATCH_CACHEOP();
680 CACHEOP_CASE(GuardClass) {
681 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
682 GuardClassKind kind = icregs.cacheIRReader.guardClassKind();
683 JSObject* object = reinterpret_cast<JSObject*>(icregs.icVals[objId.id()]);
684 switch (kind) {
685 case GuardClassKind::Array:
686 if (object->getClass() != &ArrayObject::class_) {
687 return ICInterpretOpResult::NextIC;
689 break;
690 case GuardClassKind::PlainObject:
691 if (object->getClass() != &PlainObject::class_) {
692 return ICInterpretOpResult::NextIC;
694 break;
695 case GuardClassKind::FixedLengthArrayBuffer:
696 if (object->getClass() != &FixedLengthArrayBufferObject::class_) {
697 return ICInterpretOpResult::NextIC;
699 break;
700 case GuardClassKind::FixedLengthSharedArrayBuffer:
701 if (object->getClass() != &FixedLengthSharedArrayBufferObject::class_) {
702 return ICInterpretOpResult::NextIC;
704 break;
705 case GuardClassKind::FixedLengthDataView:
706 if (object->getClass() != &FixedLengthDataViewObject::class_) {
707 return ICInterpretOpResult::NextIC;
709 break;
710 case GuardClassKind::MappedArguments:
711 if (object->getClass() != &MappedArgumentsObject::class_) {
712 return ICInterpretOpResult::NextIC;
714 break;
715 case GuardClassKind::UnmappedArguments:
716 if (object->getClass() != &UnmappedArgumentsObject::class_) {
717 return ICInterpretOpResult::NextIC;
719 break;
720 case GuardClassKind::WindowProxy:
721 if (object->getClass() !=
722 frameMgr.cxForLocalUseOnly()->runtime()->maybeWindowProxyClass()) {
723 return ICInterpretOpResult::NextIC;
725 break;
726 case GuardClassKind::JSFunction:
727 if (!object->is<JSFunction>()) {
728 return ICInterpretOpResult::NextIC;
730 break;
731 case GuardClassKind::Set:
732 if (object->getClass() != &SetObject::class_) {
733 return ICInterpretOpResult::NextIC;
735 break;
736 case GuardClassKind::Map:
737 if (object->getClass() != &MapObject::class_) {
738 return ICInterpretOpResult::NextIC;
740 break;
741 case GuardClassKind::BoundFunction:
742 if (object->getClass() != &BoundFunctionObject::class_) {
743 return ICInterpretOpResult::NextIC;
745 break;
747 DISPATCH_CACHEOP();
750 CACHEOP_CASE(GuardGlobalGeneration) {
751 uint32_t expectedOffset = icregs.cacheIRReader.stubOffset();
752 uint32_t generationAddrOffset = icregs.cacheIRReader.stubOffset();
753 uint32_t expected =
754 cstub->stubInfo()->getStubRawInt32(cstub, expectedOffset);
755 uint32_t* generationAddr = reinterpret_cast<uint32_t*>(
756 cstub->stubInfo()->getStubRawWord(cstub, generationAddrOffset));
757 if (*generationAddr != expected) {
758 return ICInterpretOpResult::NextIC;
760 DISPATCH_CACHEOP();
763 CACHEOP_CASE(GuardSpecificObject) {
764 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
765 uint32_t expectedOffset = icregs.cacheIRReader.stubOffset();
766 uintptr_t expected =
767 cstub->stubInfo()->getStubRawWord(cstub, expectedOffset);
768 if (expected != icregs.icVals[objId.id()]) {
769 return ICInterpretOpResult::NextIC;
771 DISPATCH_CACHEOP();
774 CACHEOP_CASE(GuardSpecificFunction) {
775 ObjOperandId funId = icregs.cacheIRReader.objOperandId();
776 uint32_t expectedOffset = icregs.cacheIRReader.stubOffset();
777 uint32_t nargsAndFlagsOffset = icregs.cacheIRReader.stubOffset();
778 (void)nargsAndFlagsOffset; // Unused.
779 uintptr_t expected =
780 cstub->stubInfo()->getStubRawWord(cstub, expectedOffset);
781 if (expected != icregs.icVals[funId.id()]) {
782 return ICInterpretOpResult::NextIC;
784 PREDICT_NEXT(LoadArgumentFixedSlot);
785 DISPATCH_CACHEOP();
788 CACHEOP_CASE(GuardFunctionScript) {
789 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
790 uint32_t expectedOffset = icregs.cacheIRReader.stubOffset();
791 uint32_t nargsAndFlagsOffset = icregs.cacheIRReader.stubOffset();
792 JSFunction* fun = reinterpret_cast<JSFunction*>(icregs.icVals[objId.id()]);
793 BaseScript* expected = reinterpret_cast<BaseScript*>(
794 cstub->stubInfo()->getStubRawWord(cstub, expectedOffset));
795 (void)nargsAndFlagsOffset;
797 if (!fun->hasBaseScript() || fun->baseScript() != expected) {
798 return ICInterpretOpResult::NextIC;
801 PREDICT_NEXT(CallScriptedFunction);
802 DISPATCH_CACHEOP();
805 CACHEOP_CASE(GuardSpecificAtom) {
806 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
807 uint32_t expectedOffset = icregs.cacheIRReader.stubOffset();
808 uintptr_t expected =
809 cstub->stubInfo()->getStubRawWord(cstub, expectedOffset);
810 if (expected != icregs.icVals[strId.id()]) {
811 return ICInterpretOpResult::NextIC;
813 DISPATCH_CACHEOP();
816 CACHEOP_CASE(GuardSpecificSymbol) {
817 SymbolOperandId symId = icregs.cacheIRReader.symbolOperandId();
818 uint32_t expectedOffset = icregs.cacheIRReader.stubOffset();
819 uintptr_t expected =
820 cstub->stubInfo()->getStubRawWord(cstub, expectedOffset);
821 if (expected != icregs.icVals[symId.id()]) {
822 return ICInterpretOpResult::NextIC;
824 DISPATCH_CACHEOP();
827 CACHEOP_CASE(GuardSpecificInt32) {
828 Int32OperandId numId = icregs.cacheIRReader.int32OperandId();
829 int32_t expected = icregs.cacheIRReader.int32Immediate();
830 if (expected != int32_t(icregs.icVals[numId.id()])) {
831 return ICInterpretOpResult::NextIC;
833 DISPATCH_CACHEOP();
836 CACHEOP_CASE(GuardDynamicSlotIsSpecificObject) {
837 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
838 ObjOperandId expectedId = icregs.cacheIRReader.objOperandId();
839 uint32_t slotOffset = icregs.cacheIRReader.stubOffset();
840 JSObject* expected =
841 reinterpret_cast<JSObject*>(icregs.icVals[expectedId.id()]);
842 uintptr_t offset = cstub->stubInfo()->getStubRawInt32(cstub, slotOffset);
843 NativeObject* nobj =
844 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
845 HeapSlot* slots = nobj->getSlotsUnchecked();
846 Value actual = slots[offset / sizeof(Value)];
847 if (actual != ObjectValue(*expected)) {
848 return ICInterpretOpResult::NextIC;
850 DISPATCH_CACHEOP();
853 CACHEOP_CASE(GuardNoAllocationMetadataBuilder) {
854 uint32_t builderAddrOffset = icregs.cacheIRReader.stubOffset();
855 uintptr_t builderAddr =
856 cstub->stubInfo()->getStubRawWord(cstub, builderAddrOffset);
857 if (*reinterpret_cast<uintptr_t*>(builderAddr) != 0) {
858 return ICInterpretOpResult::NextIC;
860 DISPATCH_CACHEOP();
863 CACHEOP_CASE(LoadObject) {
864 ObjOperandId resultId = icregs.cacheIRReader.objOperandId();
865 BOUNDSCHECK(resultId);
866 uint32_t objOffset = icregs.cacheIRReader.stubOffset();
867 intptr_t obj = cstub->stubInfo()->getStubRawWord(cstub, objOffset);
868 icregs.icVals[resultId.id()] = obj;
869 PREDICT_NEXT(GuardShape);
870 DISPATCH_CACHEOP();
873 CACHEOP_CASE(LoadProtoObject) {
874 ObjOperandId resultId = icregs.cacheIRReader.objOperandId();
875 BOUNDSCHECK(resultId);
876 uint32_t protoObjOffset = icregs.cacheIRReader.stubOffset();
877 ObjOperandId receiverObjId = icregs.cacheIRReader.objOperandId();
878 (void)receiverObjId;
879 intptr_t obj = cstub->stubInfo()->getStubRawWord(cstub, protoObjOffset);
880 icregs.icVals[resultId.id()] = obj;
881 PREDICT_NEXT(GuardShape);
882 DISPATCH_CACHEOP();
885 CACHEOP_CASE(LoadProto) {
886 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
887 ObjOperandId resultId = icregs.cacheIRReader.objOperandId();
888 BOUNDSCHECK(resultId);
889 NativeObject* nobj =
890 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
891 icregs.icVals[resultId.id()] =
892 reinterpret_cast<uintptr_t>(nobj->staticPrototype());
893 DISPATCH_CACHEOP();
896 CACHEOP_CASE(LoadArgumentFixedSlot) {
897 ValOperandId resultId = icregs.cacheIRReader.valOperandId();
898 BOUNDSCHECK(resultId);
899 uint8_t slotIndex = icregs.cacheIRReader.readByte();
900 Value val = sp[slotIndex].asValue();
901 TRACE_PRINTF(" -> slot %d: val %" PRIx64 "\n", int(slotIndex),
902 val.asRawBits());
903 icregs.icVals[resultId.id()] = val.asRawBits();
904 DISPATCH_CACHEOP();
907 CACHEOP_CASE(LoadArgumentDynamicSlot) {
908 ValOperandId resultId = icregs.cacheIRReader.valOperandId();
909 BOUNDSCHECK(resultId);
910 Int32OperandId argcId = icregs.cacheIRReader.int32OperandId();
911 uint8_t slotIndex = icregs.cacheIRReader.readByte();
912 int32_t argc = int32_t(icregs.icVals[argcId.id()]);
913 Value val = sp[slotIndex + argc].asValue();
914 icregs.icVals[resultId.id()] = val.asRawBits();
915 DISPATCH_CACHEOP();
918 CACHEOP_CASE(StoreFixedSlot) {
919 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
920 uint32_t offsetOffset = icregs.cacheIRReader.stubOffset();
921 ValOperandId rhsId = icregs.cacheIRReader.valOperandId();
922 uintptr_t offset = cstub->stubInfo()->getStubRawInt32(cstub, offsetOffset);
923 NativeObject* nobj =
924 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
925 GCPtr<Value>* slot = reinterpret_cast<GCPtr<Value>*>(
926 reinterpret_cast<uintptr_t>(nobj) + offset);
927 Value val = Value::fromRawBits(icregs.icVals[rhsId.id()]);
928 slot->set(val);
929 PREDICT_NEXT(ReturnFromIC);
930 DISPATCH_CACHEOP();
933 CACHEOP_CASE(StoreDynamicSlot) {
934 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
935 uint32_t offsetOffset = icregs.cacheIRReader.stubOffset();
936 ValOperandId rhsId = icregs.cacheIRReader.valOperandId();
937 uint32_t offset = cstub->stubInfo()->getStubRawInt32(cstub, offsetOffset);
938 NativeObject* nobj =
939 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
940 HeapSlot* slots = nobj->getSlotsUnchecked();
941 Value val = Value::fromRawBits(icregs.icVals[rhsId.id()]);
942 size_t dynSlot = offset / sizeof(Value);
943 size_t slot = dynSlot + nobj->numFixedSlots();
944 slots[dynSlot].set(nobj, HeapSlot::Slot, slot, val);
945 PREDICT_NEXT(ReturnFromIC);
946 DISPATCH_CACHEOP();
949 CACHEOP_CASE(StoreDenseElement) {
950 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
951 Int32OperandId indexId = icregs.cacheIRReader.int32OperandId();
952 ValOperandId rhsId = icregs.cacheIRReader.valOperandId();
953 NativeObject* nobj =
954 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
955 ObjectElements* elems = nobj->getElementsHeader();
956 int32_t index = int32_t(icregs.icVals[indexId.id()]);
957 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) {
958 return ICInterpretOpResult::NextIC;
960 HeapSlot* slot = &elems->elements()[index];
961 if (slot->get().isMagic()) {
962 return ICInterpretOpResult::NextIC;
964 Value val = Value::fromRawBits(icregs.icVals[rhsId.id()]);
965 slot->set(nobj, HeapSlot::Element, index + elems->numShiftedElements(),
966 val);
967 PREDICT_NEXT(ReturnFromIC);
968 DISPATCH_CACHEOP();
971 CACHEOP_CASE(IsObjectResult) {
972 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
973 Value val = Value::fromRawBits(icregs.icVals[inputId.id()]);
974 icregs.icResult = BooleanValue(val.isObject()).asRawBits();
975 PREDICT_NEXT(ReturnFromIC);
976 DISPATCH_CACHEOP();
979 CACHEOP_CASE(Int32MinMax) {
980 bool isMax = icregs.cacheIRReader.readBool();
981 Int32OperandId firstId = icregs.cacheIRReader.int32OperandId();
982 Int32OperandId secondId = icregs.cacheIRReader.int32OperandId();
983 Int32OperandId resultId = icregs.cacheIRReader.int32OperandId();
984 BOUNDSCHECK(resultId);
985 int32_t lhs = int32_t(icregs.icVals[firstId.id()]);
986 int32_t rhs = int32_t(icregs.icVals[secondId.id()]);
987 int32_t result = ((lhs > rhs) ^ isMax) ? rhs : lhs;
988 icregs.icVals[resultId.id()] = result;
989 DISPATCH_CACHEOP();
992 CACHEOP_CASE(CallInt32ToString) {
993 Int32OperandId inputId = icregs.cacheIRReader.int32OperandId();
994 StringOperandId resultId = icregs.cacheIRReader.stringOperandId();
995 BOUNDSCHECK(resultId);
996 int32_t input = int32_t(icregs.icVals[inputId.id()]);
997 JSLinearString* str =
998 Int32ToStringPure(frameMgr.cxForLocalUseOnly(), input);
999 if (str) {
1000 icregs.icVals[resultId.id()] = reinterpret_cast<uintptr_t>(str);
1001 } else {
1002 return ICInterpretOpResult::NextIC;
1004 DISPATCH_CACHEOP();
1007 CACHEOP_CASE(CallScriptedFunction)
1008 CACHEOP_CASE_FALLTHROUGH(CallNativeFunction) {
1009 bool isNative = cacheop == CacheOp::CallNativeFunction;
1010 TRACE_PRINTF("CallScriptedFunction / CallNativeFunction (native: %d)\n",
1011 isNative);
1012 ObjOperandId calleeId = icregs.cacheIRReader.objOperandId();
1013 Int32OperandId argcId = icregs.cacheIRReader.int32OperandId();
1014 CallFlags flags = icregs.cacheIRReader.callFlags();
1015 uint32_t argcFixed = icregs.cacheIRReader.uint32Immediate();
1016 bool ignoresRv = false;
1017 if (isNative) {
1018 ignoresRv = icregs.cacheIRReader.readBool();
1021 JSFunction* callee =
1022 reinterpret_cast<JSFunction*>(icregs.icVals[calleeId.id()]);
1023 uint32_t argc = uint32_t(icregs.icVals[argcId.id()]);
1024 (void)argcFixed;
1026 if (!isNative) {
1027 if (!callee->hasBaseScript() || !callee->baseScript()->hasBytecode() ||
1028 !callee->baseScript()->hasJitScript()) {
1029 return ICInterpretOpResult::NextIC;
1033 // For now, fail any constructing or different-realm cases.
1034 if (flags.isConstructing() || !flags.isSameRealm()) {
1035 TRACE_PRINTF("failing: constructing or not same realm\n");
1036 return ICInterpretOpResult::NextIC;
1038 // And support only "standard" arg formats.
1039 if (flags.getArgFormat() != CallFlags::Standard) {
1040 TRACE_PRINTF("failing: not standard arg format\n");
1041 return ICInterpretOpResult::NextIC;
1044 // For now, fail any arg-underflow case.
1045 if (argc < callee->nargs()) {
1046 TRACE_PRINTF("failing: too few args\n");
1047 return ICInterpretOpResult::NextIC;
1050 uint32_t extra = 1 + flags.isConstructing() + isNative;
1051 uint32_t totalArgs = argc + extra;
1052 StackVal* origArgs = sp;
1055 PUSH_IC_FRAME();
1057 if (!stack.check(sp, sizeof(StackVal) * (totalArgs + 6))) {
1058 ReportOverRecursed(frameMgr.cxForLocalUseOnly());
1059 return ICInterpretOpResult::Error;
1062 // This will not be an Exit frame but a BaselineStub frame, so
1063 // replace the ExitFrameType with the ICStub pointer.
1064 POPNNATIVE(1);
1065 PUSHNATIVE(StackValNative(cstub));
1067 // Push args.
1068 for (uint32_t i = 0; i < totalArgs; i++) {
1069 PUSH(origArgs[i]);
1071 Value* args = reinterpret_cast<Value*>(sp);
1073 TRACE_PRINTF("pushing callee: %p\n", callee);
1074 PUSHNATIVE(
1075 StackValNative(CalleeToToken(callee, /* isConstructing = */ false)));
1077 if (isNative) {
1078 PUSHNATIVE(StackValNative(argc));
1079 PUSHNATIVE(StackValNative(
1080 MakeFrameDescriptorForJitCall(FrameType::BaselineStub, 0)));
1082 // We *also* need an exit frame (the native baseline
1083 // execution would invoke a trampoline here).
1084 StackVal* trampolinePrevFP = stack.fp;
1085 PUSHNATIVE(StackValNative(nullptr)); // fake return address.
1086 PUSHNATIVE(StackValNative(stack.fp));
1087 stack.fp = sp;
1088 PUSHNATIVE(StackValNative(uint32_t(ExitFrameType::CallNative)));
1089 cx.getCx()->activation()->asJit()->setJSExitFP(
1090 reinterpret_cast<uint8_t*>(stack.fp));
1091 cx.getCx()->portableBaselineStack().top = reinterpret_cast<void*>(sp);
1093 JSNative native = ignoresRv
1094 ? callee->jitInfo()->ignoresReturnValueMethod
1095 : callee->native();
1096 bool success = native(cx, argc, args);
1098 stack.fp = trampolinePrevFP;
1099 POPNNATIVE(4);
1101 if (!success) {
1102 return ICInterpretOpResult::Error;
1104 icregs.icResult = args[0].asRawBits();
1105 } else {
1106 PUSHNATIVE(StackValNative(
1107 MakeFrameDescriptorForJitCall(FrameType::BaselineStub, argc)));
1109 switch (PortableBaselineInterpret(
1110 cx, state, stack, sp, /* envChain = */ nullptr,
1111 reinterpret_cast<Value*>(&icregs.icResult))) {
1112 case PBIResult::Ok:
1113 break;
1114 case PBIResult::Error:
1115 return ICInterpretOpResult::Error;
1116 case PBIResult::Unwind:
1117 return ICInterpretOpResult::Unwind;
1118 case PBIResult::UnwindError:
1119 return ICInterpretOpResult::UnwindError;
1120 case PBIResult::UnwindRet:
1121 return ICInterpretOpResult::UnwindRet;
1126 DISPATCH_CACHEOP();
1129 CACHEOP_CASE(LoadFixedSlotResult) {
1130 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1131 uint32_t offsetOffset = icregs.cacheIRReader.stubOffset();
1132 uintptr_t offset = cstub->stubInfo()->getStubRawInt32(cstub, offsetOffset);
1133 NativeObject* nobj =
1134 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
1135 Value* slot =
1136 reinterpret_cast<Value*>(reinterpret_cast<uintptr_t>(nobj) + offset);
1137 TRACE_PRINTF(
1138 "LoadFixedSlotResult: obj %p offsetOffset %d offset %d slotPtr %p "
1139 "slot %" PRIx64 "\n",
1140 nobj, int(offsetOffset), int(offset), slot, slot->asRawBits());
1141 icregs.icResult = slot->asRawBits();
1142 PREDICT_NEXT(ReturnFromIC);
1143 DISPATCH_CACHEOP();
1146 CACHEOP_CASE(LoadDynamicSlotResult) {
1147 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1148 uint32_t offsetOffset = icregs.cacheIRReader.stubOffset();
1149 uintptr_t offset = cstub->stubInfo()->getStubRawInt32(cstub, offsetOffset);
1150 NativeObject* nobj =
1151 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
1152 HeapSlot* slots = nobj->getSlotsUnchecked();
1153 icregs.icResult = slots[offset / sizeof(Value)].get().asRawBits();
1154 PREDICT_NEXT(ReturnFromIC);
1155 DISPATCH_CACHEOP();
1158 CACHEOP_CASE(LoadDenseElementResult) {
1159 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1160 Int32OperandId indexId = icregs.cacheIRReader.int32OperandId();
1161 NativeObject* nobj =
1162 reinterpret_cast<NativeObject*>(icregs.icVals[objId.id()]);
1163 ObjectElements* elems = nobj->getElementsHeader();
1164 int32_t index = int32_t(icregs.icVals[indexId.id()]);
1165 if (index < 0 || uint32_t(index) >= nobj->getDenseInitializedLength()) {
1166 return ICInterpretOpResult::NextIC;
1168 HeapSlot* slot = &elems->elements()[index];
1169 Value val = slot->get();
1170 if (val.isMagic()) {
1171 return ICInterpretOpResult::NextIC;
1173 icregs.icResult = val.asRawBits();
1174 PREDICT_NEXT(ReturnFromIC);
1175 DISPATCH_CACHEOP();
1178 CACHEOP_CASE(LoadInt32ArrayLengthResult) {
1179 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1180 ArrayObject* aobj =
1181 reinterpret_cast<ArrayObject*>(icregs.icVals[objId.id()]);
1182 uint32_t length = aobj->length();
1183 if (length > uint32_t(INT32_MAX)) {
1184 return ICInterpretOpResult::NextIC;
1186 icregs.icResult = Int32Value(length).asRawBits();
1187 PREDICT_NEXT(ReturnFromIC);
1188 DISPATCH_CACHEOP();
1191 CACHEOP_CASE(LoadInt32ArrayLength) {
1192 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1193 Int32OperandId resultId = icregs.cacheIRReader.int32OperandId();
1194 BOUNDSCHECK(resultId);
1195 ArrayObject* aobj =
1196 reinterpret_cast<ArrayObject*>(icregs.icVals[objId.id()]);
1197 uint32_t length = aobj->length();
1198 if (length > uint32_t(INT32_MAX)) {
1199 return ICInterpretOpResult::NextIC;
1201 icregs.icVals[resultId.id()] = length;
1202 DISPATCH_CACHEOP();
1205 CACHEOP_CASE(LinearizeForCharAccess) {
1206 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
1207 Int32OperandId indexId = icregs.cacheIRReader.int32OperandId();
1208 StringOperandId resultId = icregs.cacheIRReader.stringOperandId();
1209 BOUNDSCHECK(resultId);
1210 JSString* str =
1211 reinterpret_cast<JSLinearString*>(icregs.icVals[strId.id()]);
1212 (void)indexId;
1214 if (!str->isRope()) {
1215 icregs.icVals[resultId.id()] = reinterpret_cast<uintptr_t>(str);
1216 } else {
1217 PUSH_IC_FRAME();
1218 JSLinearString* result = LinearizeForCharAccess(cx, str);
1219 if (!result) {
1220 return ICInterpretOpResult::Error;
1222 icregs.icVals[resultId.id()] = reinterpret_cast<uintptr_t>(result);
1224 PREDICT_NEXT(LoadStringCharResult);
1225 DISPATCH_CACHEOP();
1228 CACHEOP_CASE(LoadStringCharResult) {
1229 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
1230 Int32OperandId indexId = icregs.cacheIRReader.int32OperandId();
1231 bool handleOOB = icregs.cacheIRReader.readBool();
1233 JSString* str =
1234 reinterpret_cast<JSLinearString*>(icregs.icVals[strId.id()]);
1235 int32_t index = int32_t(icregs.icVals[indexId.id()]);
1236 JSString* result = nullptr;
1237 if (index < 0 || size_t(index) >= str->length()) {
1238 if (handleOOB) {
1239 // Return an empty string.
1240 result = frameMgr.cxForLocalUseOnly()->names().empty_;
1241 } else {
1242 return ICInterpretOpResult::NextIC;
1244 } else {
1245 char16_t c;
1246 // Guaranteed to be always work because this CacheIR op is
1247 // always preceded by LinearizeForCharAccess.
1248 MOZ_ALWAYS_TRUE(str->getChar(/* cx = */ nullptr, index, &c));
1249 StaticStrings& sstr = frameMgr.cxForLocalUseOnly()->staticStrings();
1250 if (sstr.hasUnit(c)) {
1251 result = sstr.getUnit(c);
1252 } else {
1253 PUSH_IC_FRAME();
1254 result = StringFromCharCode(cx, c);
1255 if (!result) {
1256 return ICInterpretOpResult::Error;
1260 icregs.icResult = StringValue(result).asRawBits();
1261 PREDICT_NEXT(ReturnFromIC);
1262 DISPATCH_CACHEOP();
1265 CACHEOP_CASE(LoadStringCharCodeResult) {
1266 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
1267 Int32OperandId indexId = icregs.cacheIRReader.int32OperandId();
1268 bool handleOOB = icregs.cacheIRReader.readBool();
1270 JSString* str =
1271 reinterpret_cast<JSLinearString*>(icregs.icVals[strId.id()]);
1272 int32_t index = int32_t(icregs.icVals[indexId.id()]);
1273 Value result;
1274 if (index < 0 || size_t(index) >= str->length()) {
1275 if (handleOOB) {
1276 // Return NaN.
1277 result = JS::NaNValue();
1278 } else {
1279 return ICInterpretOpResult::NextIC;
1281 } else {
1282 char16_t c;
1283 // Guaranteed to be always work because this CacheIR op is
1284 // always preceded by LinearizeForCharAccess.
1285 MOZ_ALWAYS_TRUE(str->getChar(/* cx = */ nullptr, index, &c));
1286 result = Int32Value(c);
1288 icregs.icResult = result.asRawBits();
1289 PREDICT_NEXT(ReturnFromIC);
1290 DISPATCH_CACHEOP();
1293 CACHEOP_CASE(LoadStringLengthResult) {
1294 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
1295 JSString* str = reinterpret_cast<JSString*>(icregs.icVals[strId.id()]);
1296 size_t length = str->length();
1297 if (length > size_t(INT32_MAX)) {
1298 return ICInterpretOpResult::NextIC;
1300 icregs.icResult = Int32Value(length).asRawBits();
1301 PREDICT_NEXT(ReturnFromIC);
1302 DISPATCH_CACHEOP();
1305 CACHEOP_CASE(LoadObjectResult) {
1306 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1307 icregs.icResult =
1308 ObjectValue(*reinterpret_cast<JSObject*>(icregs.icVals[objId.id()]))
1309 .asRawBits();
1310 PREDICT_NEXT(ReturnFromIC);
1311 DISPATCH_CACHEOP();
1314 CACHEOP_CASE(LoadStringResult) {
1315 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
1316 icregs.icResult =
1317 StringValue(reinterpret_cast<JSString*>(icregs.icVals[strId.id()]))
1318 .asRawBits();
1319 DISPATCH_CACHEOP();
1322 CACHEOP_CASE(LoadSymbolResult) {
1323 SymbolOperandId symId = icregs.cacheIRReader.symbolOperandId();
1324 icregs.icResult =
1325 SymbolValue(reinterpret_cast<JS::Symbol*>(icregs.icVals[symId.id()]))
1326 .asRawBits();
1327 PREDICT_NEXT(ReturnFromIC);
1328 DISPATCH_CACHEOP();
1331 CACHEOP_CASE(LoadInt32Result) {
1332 Int32OperandId valId = icregs.cacheIRReader.int32OperandId();
1333 icregs.icResult = Int32Value(icregs.icVals[valId.id()]).asRawBits();
1334 PREDICT_NEXT(ReturnFromIC);
1335 DISPATCH_CACHEOP();
1338 CACHEOP_CASE(LoadDoubleResult) {
1339 NumberOperandId valId = icregs.cacheIRReader.numberOperandId();
1340 Value val = Value::fromRawBits(icregs.icVals[valId.id()]);
1341 if (val.isInt32()) {
1342 val = DoubleValue(val.toInt32());
1344 icregs.icResult = val.asRawBits();
1345 PREDICT_NEXT(ReturnFromIC);
1346 DISPATCH_CACHEOP();
1349 CACHEOP_CASE(LoadBigIntResult) {
1350 BigIntOperandId valId = icregs.cacheIRReader.bigIntOperandId();
1351 icregs.icResult =
1352 BigIntValue(reinterpret_cast<JS::BigInt*>(icregs.icVals[valId.id()]))
1353 .asRawBits();
1354 PREDICT_NEXT(ReturnFromIC);
1355 DISPATCH_CACHEOP();
1358 CACHEOP_CASE(LoadBooleanResult) {
1359 bool val = icregs.cacheIRReader.readBool();
1360 icregs.icResult = BooleanValue(val).asRawBits();
1361 PREDICT_NEXT(ReturnFromIC);
1362 DISPATCH_CACHEOP();
1365 CACHEOP_CASE(LoadInt32Constant) {
1366 uint32_t valOffset = icregs.cacheIRReader.stubOffset();
1367 Int32OperandId resultId = icregs.cacheIRReader.int32OperandId();
1368 BOUNDSCHECK(resultId);
1369 uint32_t value = cstub->stubInfo()->getStubRawInt32(cstub, valOffset);
1370 icregs.icVals[resultId.id()] = value;
1371 DISPATCH_CACHEOP();
1374 CACHEOP_CASE(LoadConstantStringResult) {
1375 uint32_t strOffset = icregs.cacheIRReader.stubOffset();
1376 JSString* str = reinterpret_cast<JSString*>(
1377 cstub->stubInfo()->getStubRawWord(cstub, strOffset));
1378 icregs.icResult = StringValue(str).asRawBits();
1379 PREDICT_NEXT(ReturnFromIC);
1380 DISPATCH_CACHEOP();
1383 #define INT32_OP(name, op, extra_check) \
1384 CACHEOP_CASE(Int32##name##Result) { \
1385 Int32OperandId lhsId = icregs.cacheIRReader.int32OperandId(); \
1386 Int32OperandId rhsId = icregs.cacheIRReader.int32OperandId(); \
1387 int64_t lhs = int64_t(int32_t(icregs.icVals[lhsId.id()])); \
1388 int64_t rhs = int64_t(int32_t(icregs.icVals[rhsId.id()])); \
1389 extra_check; \
1390 int64_t result = lhs op rhs; \
1391 if (result < INT32_MIN || result > INT32_MAX) { \
1392 return ICInterpretOpResult::NextIC; \
1394 icregs.icResult = Int32Value(int32_t(result)).asRawBits(); \
1395 PREDICT_NEXT(ReturnFromIC); \
1396 DISPATCH_CACHEOP(); \
1399 INT32_OP(Add, +, {});
1400 INT32_OP(Sub, -, {});
1401 INT32_OP(Mul, *, {
1402 if (rhs * lhs == 0 && ((rhs < 0) ^ (lhs < 0))) {
1403 return ICInterpretOpResult::NextIC;
1406 INT32_OP(Div, /, {
1407 if (rhs == 0 || (lhs == INT32_MIN && rhs == -1)) {
1408 return ICInterpretOpResult::NextIC;
1410 if (lhs == 0 && rhs < 0) {
1411 return ICInterpretOpResult::NextIC;
1413 if (lhs % rhs != 0) {
1414 return ICInterpretOpResult::NextIC;
1417 INT32_OP(Mod, %, {
1418 if (rhs == 0 || (lhs == INT32_MIN && rhs == -1)) {
1419 return ICInterpretOpResult::NextIC;
1421 if (lhs % rhs == 0 && lhs < 0) {
1422 return ICInterpretOpResult::NextIC;
1425 INT32_OP(BitOr, |, {});
1426 INT32_OP(BitAnd, &, {});
1428 CACHEOP_CASE(Int32PowResult) {
1429 Int32OperandId lhsId = icregs.cacheIRReader.int32OperandId();
1430 Int32OperandId rhsId = icregs.cacheIRReader.int32OperandId();
1431 int64_t lhs = int64_t(int32_t(icregs.icVals[lhsId.id()]));
1432 int64_t rhs = int64_t(int32_t(icregs.icVals[rhsId.id()]));
1433 int64_t result;
1435 if (lhs == 1) {
1436 result = 1;
1437 } else if (rhs < 0) {
1438 return ICInterpretOpResult::NextIC;
1439 } else {
1440 result = 1;
1441 int64_t runningSquare = lhs;
1442 while (rhs) {
1443 if (rhs & 1) {
1444 result *= runningSquare;
1445 if (result > int64_t(INT32_MAX)) {
1446 return ICInterpretOpResult::NextIC;
1449 rhs >>= 1;
1450 if (rhs == 0) {
1451 break;
1453 runningSquare *= runningSquare;
1454 if (runningSquare > int64_t(INT32_MAX)) {
1455 return ICInterpretOpResult::NextIC;
1460 icregs.icResult = Int32Value(int32_t(result)).asRawBits();
1461 PREDICT_NEXT(ReturnFromIC);
1462 DISPATCH_CACHEOP();
1465 CACHEOP_CASE(Int32IncResult) {
1466 Int32OperandId inputId = icregs.cacheIRReader.int32OperandId();
1467 int64_t value = int64_t(int32_t(icregs.icVals[inputId.id()]));
1468 value++;
1469 if (value > INT32_MAX) {
1470 return ICInterpretOpResult::NextIC;
1472 icregs.icResult = Int32Value(int32_t(value)).asRawBits();
1473 PREDICT_NEXT(ReturnFromIC);
1474 DISPATCH_CACHEOP();
1477 CACHEOP_CASE(LoadInt32TruthyResult) {
1478 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
1479 int32_t val = int32_t(icregs.icVals[inputId.id()]);
1480 icregs.icResult = BooleanValue(val != 0).asRawBits();
1481 PREDICT_NEXT(ReturnFromIC);
1482 DISPATCH_CACHEOP();
1485 CACHEOP_CASE(LoadStringTruthyResult) {
1486 StringOperandId strId = icregs.cacheIRReader.stringOperandId();
1487 JSString* str =
1488 reinterpret_cast<JSLinearString*>(icregs.icVals[strId.id()]);
1489 icregs.icResult = BooleanValue(str->length() > 0).asRawBits();
1490 PREDICT_NEXT(ReturnFromIC);
1491 DISPATCH_CACHEOP();
1494 CACHEOP_CASE(LoadObjectTruthyResult) {
1495 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1496 JSObject* obj = reinterpret_cast<JSObject*>(icregs.icVals[objId.id()]);
1497 const JSClass* cls = obj->getClass();
1498 if (cls->isProxyObject()) {
1499 return ICInterpretOpResult::NextIC;
1501 icregs.icResult = BooleanValue(!cls->emulatesUndefined()).asRawBits();
1502 PREDICT_NEXT(ReturnFromIC);
1503 DISPATCH_CACHEOP();
1506 CACHEOP_CASE(LoadValueResult) {
1507 uint32_t valOffset = icregs.cacheIRReader.stubOffset();
1508 icregs.icResult = cstub->stubInfo()->getStubRawInt64(cstub, valOffset);
1509 PREDICT_NEXT(ReturnFromIC);
1510 DISPATCH_CACHEOP();
1513 CACHEOP_CASE(LoadOperandResult) {
1514 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
1515 icregs.icResult = icregs.icVals[inputId.id()];
1516 PREDICT_NEXT(ReturnFromIC);
1517 DISPATCH_CACHEOP();
1520 CACHEOP_CASE(CallStringConcatResult) {
1521 StringOperandId lhsId = icregs.cacheIRReader.stringOperandId();
1522 StringOperandId rhsId = icregs.cacheIRReader.stringOperandId();
1523 // We don't push a frame and do a CanGC invocation here; we do a
1524 // pure (NoGC) invocation only, because it's cheaper.
1525 FakeRooted<JSString*> lhs(
1526 nullptr, reinterpret_cast<JSString*>(icregs.icVals[lhsId.id()]));
1527 FakeRooted<JSString*> rhs(
1528 nullptr, reinterpret_cast<JSString*>(icregs.icVals[rhsId.id()]));
1529 JSString* result =
1530 ConcatStrings<NoGC>(frameMgr.cxForLocalUseOnly(), lhs, rhs);
1531 if (result) {
1532 icregs.icResult = StringValue(result).asRawBits();
1533 } else {
1534 return ICInterpretOpResult::NextIC;
1536 PREDICT_NEXT(ReturnFromIC);
1537 DISPATCH_CACHEOP();
1540 CACHEOP_CASE(CompareStringResult) {
1541 JSOp op = icregs.cacheIRReader.jsop();
1542 StringOperandId lhsId = icregs.cacheIRReader.stringOperandId();
1543 StringOperandId rhsId = icregs.cacheIRReader.stringOperandId();
1545 PUSH_IC_FRAME();
1546 ReservedRooted<JSString*> lhs(
1547 &state.str0, reinterpret_cast<JSString*>(icregs.icVals[lhsId.id()]));
1548 ReservedRooted<JSString*> rhs(
1549 &state.str1, reinterpret_cast<JSString*>(icregs.icVals[rhsId.id()]));
1550 bool result;
1551 switch (op) {
1552 case JSOp::Eq:
1553 case JSOp::StrictEq:
1554 if (lhs->length() != rhs->length()) {
1555 result = false;
1556 break;
1558 if (!StringsEqual<EqualityKind::Equal>(cx, lhs, rhs, &result)) {
1559 return ICInterpretOpResult::Error;
1561 break;
1562 case JSOp::Ne:
1563 case JSOp::StrictNe:
1564 if (lhs->length() != rhs->length()) {
1565 result = true;
1566 break;
1568 if (!StringsEqual<EqualityKind::NotEqual>(cx, lhs, rhs, &result)) {
1569 return ICInterpretOpResult::Error;
1571 break;
1572 case JSOp::Lt:
1573 if (!StringsCompare<ComparisonKind::LessThan>(cx, lhs, rhs,
1574 &result)) {
1575 return ICInterpretOpResult::Error;
1577 break;
1578 case JSOp::Ge:
1579 if (!StringsCompare<ComparisonKind::GreaterThanOrEqual>(cx, lhs, rhs,
1580 &result)) {
1581 return ICInterpretOpResult::Error;
1583 break;
1584 case JSOp::Le:
1585 if (!StringsCompare<ComparisonKind::GreaterThanOrEqual>(
1586 cx, /* N.B. swapped order */ rhs, lhs, &result)) {
1587 return ICInterpretOpResult::Error;
1589 break;
1590 case JSOp::Gt:
1591 if (!StringsCompare<ComparisonKind::LessThan>(
1592 cx, /* N.B. swapped order */ rhs, lhs, &result)) {
1593 return ICInterpretOpResult::Error;
1595 break;
1596 default:
1597 MOZ_CRASH("bad opcode");
1599 icregs.icResult = BooleanValue(result).asRawBits();
1601 PREDICT_NEXT(ReturnFromIC);
1602 DISPATCH_CACHEOP();
1605 CACHEOP_CASE(CompareInt32Result) {
1606 JSOp op = icregs.cacheIRReader.jsop();
1607 Int32OperandId lhsId = icregs.cacheIRReader.int32OperandId();
1608 Int32OperandId rhsId = icregs.cacheIRReader.int32OperandId();
1609 int64_t lhs = int64_t(int32_t(icregs.icVals[lhsId.id()]));
1610 int64_t rhs = int64_t(int32_t(icregs.icVals[rhsId.id()]));
1611 TRACE_PRINTF("lhs (%d) = %" PRIi64 " rhs (%d) = %" PRIi64 "\n", lhsId.id(),
1612 lhs, rhsId.id(), rhs);
1613 bool result;
1614 switch (op) {
1615 case JSOp::Eq:
1616 case JSOp::StrictEq:
1617 result = lhs == rhs;
1618 break;
1619 case JSOp::Ne:
1620 case JSOp::StrictNe:
1621 result = lhs != rhs;
1622 break;
1623 case JSOp::Lt:
1624 result = lhs < rhs;
1625 break;
1626 case JSOp::Le:
1627 result = lhs <= rhs;
1628 break;
1629 case JSOp::Gt:
1630 result = lhs > rhs;
1631 break;
1632 case JSOp::Ge:
1633 result = lhs >= rhs;
1634 break;
1635 default:
1636 MOZ_CRASH("Unexpected opcode");
1638 icregs.icResult = BooleanValue(result).asRawBits();
1639 PREDICT_NEXT(ReturnFromIC);
1640 DISPATCH_CACHEOP();
1643 CACHEOP_CASE(CompareNullUndefinedResult) {
1644 JSOp op = icregs.cacheIRReader.jsop();
1645 bool isUndefined = icregs.cacheIRReader.readBool();
1646 ValOperandId inputId = icregs.cacheIRReader.valOperandId();
1647 Value val = Value::fromRawBits(icregs.icVals[inputId.id()]);
1648 if (val.isObject() && val.toObject().getClass()->isProxyObject()) {
1649 return ICInterpretOpResult::NextIC;
1652 bool result;
1653 switch (op) {
1654 case JSOp::Eq:
1655 result =
1656 val.isUndefined() || val.isNull() ||
1657 (val.isObject() && val.toObject().getClass()->emulatesUndefined());
1658 break;
1659 case JSOp::Ne:
1660 result = !(
1661 val.isUndefined() || val.isNull() ||
1662 (val.isObject() && val.toObject().getClass()->emulatesUndefined()));
1663 break;
1664 case JSOp::StrictEq:
1665 result = isUndefined ? val.isUndefined() : val.isNull();
1666 break;
1667 case JSOp::StrictNe:
1668 result = !(isUndefined ? val.isUndefined() : val.isNull());
1669 break;
1670 default:
1671 MOZ_CRASH("bad opcode");
1673 icregs.icResult = BooleanValue(result).asRawBits();
1674 PREDICT_NEXT(ReturnFromIC);
1675 DISPATCH_CACHEOP();
1678 CACHEOP_CASE(AssertPropertyLookup) {
1679 ObjOperandId objId = icregs.cacheIRReader.objOperandId();
1680 uint32_t idOffset = icregs.cacheIRReader.stubOffset();
1681 uint32_t slotOffset = icregs.cacheIRReader.stubOffset();
1682 // Debug-only assertion; we can ignore.
1683 (void)objId;
1684 (void)idOffset;
1685 (void)slotOffset;
1686 DISPATCH_CACHEOP();
1689 CACHEOP_CASE_UNIMPL(GuardToNonGCThing)
1690 CACHEOP_CASE_UNIMPL(Int32ToIntPtr)
1691 CACHEOP_CASE_UNIMPL(GuardNumberToIntPtrIndex)
1692 CACHEOP_CASE_UNIMPL(GuardToInt32ModUint32)
1693 CACHEOP_CASE_UNIMPL(GuardToUint8Clamped)
1694 CACHEOP_CASE_UNIMPL(GuardMultipleShapes)
1695 CACHEOP_CASE_UNIMPL(GuardNullProto)
1696 CACHEOP_CASE_UNIMPL(GuardAnyClass)
1697 CACHEOP_CASE_UNIMPL(HasClassResult)
1698 CACHEOP_CASE_UNIMPL(CallRegExpMatcherResult)
1699 CACHEOP_CASE_UNIMPL(CallRegExpSearcherResult)
1700 CACHEOP_CASE_UNIMPL(RegExpSearcherLastLimitResult)
1701 CACHEOP_CASE_UNIMPL(RegExpHasCaptureGroupsResult)
1702 CACHEOP_CASE_UNIMPL(RegExpBuiltinExecMatchResult)
1703 CACHEOP_CASE_UNIMPL(RegExpBuiltinExecTestResult)
1704 CACHEOP_CASE_UNIMPL(RegExpFlagResult)
1705 CACHEOP_CASE_UNIMPL(CallSubstringKernelResult)
1706 CACHEOP_CASE_UNIMPL(StringReplaceStringResult)
1707 CACHEOP_CASE_UNIMPL(StringSplitStringResult)
1708 CACHEOP_CASE_UNIMPL(RegExpPrototypeOptimizableResult)
1709 CACHEOP_CASE_UNIMPL(RegExpInstanceOptimizableResult)
1710 CACHEOP_CASE_UNIMPL(GetFirstDollarIndexResult)
1711 CACHEOP_CASE_UNIMPL(GuardCompartment)
1712 CACHEOP_CASE_UNIMPL(GuardIsExtensible)
1713 CACHEOP_CASE_UNIMPL(GuardIsNativeObject)
1714 CACHEOP_CASE_UNIMPL(GuardIsProxy)
1715 CACHEOP_CASE_UNIMPL(GuardIsNotProxy)
1716 CACHEOP_CASE_UNIMPL(GuardIsNotArrayBufferMaybeShared)
1717 CACHEOP_CASE_UNIMPL(GuardIsTypedArray)
1718 CACHEOP_CASE_UNIMPL(GuardIsFixedLengthTypedArray)
1719 CACHEOP_CASE_UNIMPL(GuardHasProxyHandler)
1720 CACHEOP_CASE_UNIMPL(GuardIsNotDOMProxy)
1721 CACHEOP_CASE_UNIMPL(GuardObjectIdentity)
1722 CACHEOP_CASE_UNIMPL(GuardNoDenseElements)
1723 CACHEOP_CASE_UNIMPL(GuardStringToIndex)
1724 CACHEOP_CASE_UNIMPL(GuardStringToInt32)
1725 CACHEOP_CASE_UNIMPL(GuardStringToNumber)
1726 CACHEOP_CASE_UNIMPL(BooleanToNumber)
1727 CACHEOP_CASE_UNIMPL(GuardHasGetterSetter)
1728 CACHEOP_CASE_UNIMPL(GuardInt32IsNonNegative)
1729 CACHEOP_CASE_UNIMPL(GuardIndexIsValidUpdateOrAdd)
1730 CACHEOP_CASE_UNIMPL(GuardIndexIsNotDenseElement)
1731 CACHEOP_CASE_UNIMPL(GuardTagNotEqual)
1732 CACHEOP_CASE_UNIMPL(GuardXrayExpandoShapeAndDefaultProto)
1733 CACHEOP_CASE_UNIMPL(GuardXrayNoExpando)
1734 CACHEOP_CASE_UNIMPL(GuardDynamicSlotIsNotObject)
1735 CACHEOP_CASE_UNIMPL(GuardFixedSlotValue)
1736 CACHEOP_CASE_UNIMPL(GuardDynamicSlotValue)
1737 CACHEOP_CASE_UNIMPL(LoadScriptedProxyHandler)
1738 CACHEOP_CASE_UNIMPL(IdToStringOrSymbol)
1739 CACHEOP_CASE_UNIMPL(LoadFixedSlot)
1740 CACHEOP_CASE_UNIMPL(LoadDynamicSlot)
1741 CACHEOP_CASE_UNIMPL(GuardFunctionHasJitEntry)
1742 CACHEOP_CASE_UNIMPL(GuardFunctionHasNoJitEntry)
1743 CACHEOP_CASE_UNIMPL(GuardFunctionIsNonBuiltinCtor)
1744 CACHEOP_CASE_UNIMPL(GuardFunctionIsConstructor)
1745 CACHEOP_CASE_UNIMPL(GuardNotClassConstructor)
1746 CACHEOP_CASE_UNIMPL(GuardArrayIsPacked)
1747 CACHEOP_CASE_UNIMPL(GuardArgumentsObjectFlags)
1748 CACHEOP_CASE_UNIMPL(LoadEnclosingEnvironment)
1749 CACHEOP_CASE_UNIMPL(LoadWrapperTarget)
1750 CACHEOP_CASE_UNIMPL(LoadValueTag)
1751 CACHEOP_CASE_UNIMPL(TruncateDoubleToUInt32)
1752 CACHEOP_CASE_UNIMPL(DoubleToUint8Clamped)
1753 CACHEOP_CASE_UNIMPL(MegamorphicLoadSlotResult)
1754 CACHEOP_CASE_UNIMPL(MegamorphicLoadSlotByValueResult)
1755 CACHEOP_CASE_UNIMPL(MegamorphicStoreSlot)
1756 CACHEOP_CASE_UNIMPL(MegamorphicSetElement)
1757 CACHEOP_CASE_UNIMPL(MegamorphicHasPropResult)
1758 CACHEOP_CASE_UNIMPL(ObjectToIteratorResult)
1759 CACHEOP_CASE_UNIMPL(ValueToIteratorResult)
1760 CACHEOP_CASE_UNIMPL(LoadDOMExpandoValue)
1761 CACHEOP_CASE_UNIMPL(LoadDOMExpandoValueGuardGeneration)
1762 CACHEOP_CASE_UNIMPL(LoadDOMExpandoValueIgnoreGeneration)
1763 CACHEOP_CASE_UNIMPL(GuardDOMExpandoMissingOrGuardShape)
1764 CACHEOP_CASE_UNIMPL(AddAndStoreFixedSlot)
1765 CACHEOP_CASE_UNIMPL(AddAndStoreDynamicSlot)
1766 CACHEOP_CASE_UNIMPL(AllocateAndStoreDynamicSlot)
1767 CACHEOP_CASE_UNIMPL(AddSlotAndCallAddPropHook)
1768 CACHEOP_CASE_UNIMPL(StoreDenseElementHole)
1769 CACHEOP_CASE_UNIMPL(ArrayPush)
1770 CACHEOP_CASE_UNIMPL(ArrayJoinResult)
1771 CACHEOP_CASE_UNIMPL(ObjectKeysResult)
1772 CACHEOP_CASE_UNIMPL(PackedArrayPopResult)
1773 CACHEOP_CASE_UNIMPL(PackedArrayShiftResult)
1774 CACHEOP_CASE_UNIMPL(PackedArraySliceResult)
1775 CACHEOP_CASE_UNIMPL(ArgumentsSliceResult)
1776 CACHEOP_CASE_UNIMPL(IsArrayResult)
1777 CACHEOP_CASE_UNIMPL(StoreFixedSlotUndefinedResult)
1778 CACHEOP_CASE_UNIMPL(IsPackedArrayResult)
1779 CACHEOP_CASE_UNIMPL(IsCallableResult)
1780 CACHEOP_CASE_UNIMPL(IsConstructorResult)
1781 CACHEOP_CASE_UNIMPL(IsCrossRealmArrayConstructorResult)
1782 CACHEOP_CASE_UNIMPL(IsTypedArrayResult)
1783 CACHEOP_CASE_UNIMPL(IsTypedArrayConstructorResult)
1784 CACHEOP_CASE_UNIMPL(ArrayBufferViewByteOffsetInt32Result)
1785 CACHEOP_CASE_UNIMPL(ArrayBufferViewByteOffsetDoubleResult)
1786 CACHEOP_CASE_UNIMPL(TypedArrayByteLengthInt32Result)
1787 CACHEOP_CASE_UNIMPL(TypedArrayByteLengthDoubleResult)
1788 CACHEOP_CASE_UNIMPL(TypedArrayElementSizeResult)
1789 CACHEOP_CASE_UNIMPL(GuardHasAttachedArrayBuffer)
1790 CACHEOP_CASE_UNIMPL(NewArrayIteratorResult)
1791 CACHEOP_CASE_UNIMPL(NewStringIteratorResult)
1792 CACHEOP_CASE_UNIMPL(NewRegExpStringIteratorResult)
1793 CACHEOP_CASE_UNIMPL(ObjectCreateResult)
1794 CACHEOP_CASE_UNIMPL(NewArrayFromLengthResult)
1795 CACHEOP_CASE_UNIMPL(NewTypedArrayFromLengthResult)
1796 CACHEOP_CASE_UNIMPL(NewTypedArrayFromArrayBufferResult)
1797 CACHEOP_CASE_UNIMPL(NewTypedArrayFromArrayResult)
1798 CACHEOP_CASE_UNIMPL(NewStringObjectResult)
1799 CACHEOP_CASE_UNIMPL(StringFromCharCodeResult)
1800 CACHEOP_CASE_UNIMPL(StringFromCodePointResult)
1801 CACHEOP_CASE_UNIMPL(StringIncludesResult)
1802 CACHEOP_CASE_UNIMPL(StringIndexOfResult)
1803 CACHEOP_CASE_UNIMPL(StringLastIndexOfResult)
1804 CACHEOP_CASE_UNIMPL(StringStartsWithResult)
1805 CACHEOP_CASE_UNIMPL(StringEndsWithResult)
1806 CACHEOP_CASE_UNIMPL(StringToLowerCaseResult)
1807 CACHEOP_CASE_UNIMPL(StringToUpperCaseResult)
1808 CACHEOP_CASE_UNIMPL(StringTrimResult)
1809 CACHEOP_CASE_UNIMPL(StringTrimStartResult)
1810 CACHEOP_CASE_UNIMPL(StringTrimEndResult)
1811 CACHEOP_CASE_UNIMPL(LinearizeForCodePointAccess)
1812 CACHEOP_CASE_UNIMPL(LoadStringAtResult)
1813 CACHEOP_CASE_UNIMPL(LoadStringCodePointResult)
1814 CACHEOP_CASE_UNIMPL(ToRelativeStringIndex)
1815 CACHEOP_CASE_UNIMPL(MathAbsInt32Result)
1816 CACHEOP_CASE_UNIMPL(MathAbsNumberResult)
1817 CACHEOP_CASE_UNIMPL(MathClz32Result)
1818 CACHEOP_CASE_UNIMPL(MathSignInt32Result)
1819 CACHEOP_CASE_UNIMPL(MathSignNumberResult)
1820 CACHEOP_CASE_UNIMPL(MathSignNumberToInt32Result)
1821 CACHEOP_CASE_UNIMPL(MathImulResult)
1822 CACHEOP_CASE_UNIMPL(MathSqrtNumberResult)
1823 CACHEOP_CASE_UNIMPL(MathFRoundNumberResult)
1824 CACHEOP_CASE_UNIMPL(MathRandomResult)
1825 CACHEOP_CASE_UNIMPL(MathHypot2NumberResult)
1826 CACHEOP_CASE_UNIMPL(MathHypot3NumberResult)
1827 CACHEOP_CASE_UNIMPL(MathHypot4NumberResult)
1828 CACHEOP_CASE_UNIMPL(MathAtan2NumberResult)
1829 CACHEOP_CASE_UNIMPL(MathFloorNumberResult)
1830 CACHEOP_CASE_UNIMPL(MathCeilNumberResult)
1831 CACHEOP_CASE_UNIMPL(MathTruncNumberResult)
1832 CACHEOP_CASE_UNIMPL(MathFloorToInt32Result)
1833 CACHEOP_CASE_UNIMPL(MathCeilToInt32Result)
1834 CACHEOP_CASE_UNIMPL(MathTruncToInt32Result)
1835 CACHEOP_CASE_UNIMPL(MathRoundToInt32Result)
1836 CACHEOP_CASE_UNIMPL(NumberMinMax)
1837 CACHEOP_CASE_UNIMPL(Int32MinMaxArrayResult)
1838 CACHEOP_CASE_UNIMPL(NumberMinMaxArrayResult)
1839 CACHEOP_CASE_UNIMPL(MathFunctionNumberResult)
1840 CACHEOP_CASE_UNIMPL(NumberParseIntResult)
1841 CACHEOP_CASE_UNIMPL(DoubleParseIntResult)
1842 CACHEOP_CASE_UNIMPL(ObjectToStringResult)
1843 CACHEOP_CASE_UNIMPL(ReflectGetPrototypeOfResult)
1844 CACHEOP_CASE_UNIMPL(StoreTypedArrayElement)
1845 CACHEOP_CASE_UNIMPL(AtomicsCompareExchangeResult)
1846 CACHEOP_CASE_UNIMPL(AtomicsExchangeResult)
1847 CACHEOP_CASE_UNIMPL(AtomicsAddResult)
1848 CACHEOP_CASE_UNIMPL(AtomicsSubResult)
1849 CACHEOP_CASE_UNIMPL(AtomicsAndResult)
1850 CACHEOP_CASE_UNIMPL(AtomicsOrResult)
1851 CACHEOP_CASE_UNIMPL(AtomicsXorResult)
1852 CACHEOP_CASE_UNIMPL(AtomicsLoadResult)
1853 CACHEOP_CASE_UNIMPL(AtomicsStoreResult)
1854 CACHEOP_CASE_UNIMPL(AtomicsIsLockFreeResult)
1855 CACHEOP_CASE_UNIMPL(CallNativeSetter)
1856 CACHEOP_CASE_UNIMPL(CallScriptedSetter)
1857 CACHEOP_CASE_UNIMPL(CallInlinedSetter)
1858 CACHEOP_CASE_UNIMPL(CallDOMSetter)
1859 CACHEOP_CASE_UNIMPL(CallSetArrayLength)
1860 CACHEOP_CASE_UNIMPL(ProxySet)
1861 CACHEOP_CASE_UNIMPL(ProxySetByValue)
1862 CACHEOP_CASE_UNIMPL(CallAddOrUpdateSparseElementHelper)
1863 CACHEOP_CASE_UNIMPL(CallNumberToString)
1864 CACHEOP_CASE_UNIMPL(Int32ToStringWithBaseResult)
1865 CACHEOP_CASE_UNIMPL(BooleanToString)
1866 CACHEOP_CASE_UNIMPL(CallBoundScriptedFunction)
1867 CACHEOP_CASE_UNIMPL(CallWasmFunction)
1868 CACHEOP_CASE_UNIMPL(GuardWasmArg)
1869 CACHEOP_CASE_UNIMPL(CallDOMFunction)
1870 CACHEOP_CASE_UNIMPL(CallClassHook)
1871 CACHEOP_CASE_UNIMPL(CallInlinedFunction)
1872 #ifdef JS_PUNBOX64
1873 CACHEOP_CASE_UNIMPL(CallScriptedProxyGetResult)
1874 CACHEOP_CASE_UNIMPL(CallScriptedProxyGetByValueResult)
1875 #endif
1876 CACHEOP_CASE_UNIMPL(MetaScriptedThisShape)
1877 CACHEOP_CASE_UNIMPL(BindFunctionResult)
1878 CACHEOP_CASE_UNIMPL(SpecializedBindFunctionResult)
1879 CACHEOP_CASE_UNIMPL(LoadFixedSlotTypedResult)
1880 CACHEOP_CASE_UNIMPL(LoadDenseElementHoleResult)
1881 CACHEOP_CASE_UNIMPL(CallGetSparseElementResult)
1882 CACHEOP_CASE_UNIMPL(LoadDenseElementExistsResult)
1883 CACHEOP_CASE_UNIMPL(LoadTypedArrayElementExistsResult)
1884 CACHEOP_CASE_UNIMPL(LoadDenseElementHoleExistsResult)
1885 CACHEOP_CASE_UNIMPL(LoadTypedArrayElementResult)
1886 CACHEOP_CASE_UNIMPL(LoadDataViewValueResult)
1887 CACHEOP_CASE_UNIMPL(StoreDataViewValueResult)
1888 CACHEOP_CASE_UNIMPL(LoadArgumentsObjectArgResult)
1889 CACHEOP_CASE_UNIMPL(LoadArgumentsObjectArgHoleResult)
1890 CACHEOP_CASE_UNIMPL(LoadArgumentsObjectArgExistsResult)
1891 CACHEOP_CASE_UNIMPL(LoadArgumentsObjectLengthResult)
1892 CACHEOP_CASE_UNIMPL(LoadArgumentsObjectLength)
1893 CACHEOP_CASE_UNIMPL(LoadFunctionLengthResult)
1894 CACHEOP_CASE_UNIMPL(LoadFunctionNameResult)
1895 CACHEOP_CASE_UNIMPL(LoadBoundFunctionNumArgs)
1896 CACHEOP_CASE_UNIMPL(LoadBoundFunctionTarget)
1897 CACHEOP_CASE_UNIMPL(GuardBoundFunctionIsConstructor)
1898 CACHEOP_CASE_UNIMPL(LoadArrayBufferByteLengthInt32Result)
1899 CACHEOP_CASE_UNIMPL(LoadArrayBufferByteLengthDoubleResult)
1900 CACHEOP_CASE_UNIMPL(LoadArrayBufferViewLengthInt32Result)
1901 CACHEOP_CASE_UNIMPL(LoadArrayBufferViewLengthDoubleResult)
1902 CACHEOP_CASE_UNIMPL(FrameIsConstructingResult)
1903 CACHEOP_CASE_UNIMPL(CallScriptedGetterResult)
1904 CACHEOP_CASE_UNIMPL(CallInlinedGetterResult)
1905 CACHEOP_CASE_UNIMPL(CallNativeGetterResult)
1906 CACHEOP_CASE_UNIMPL(CallDOMGetterResult)
1907 CACHEOP_CASE_UNIMPL(ProxyGetResult)
1908 CACHEOP_CASE_UNIMPL(ProxyGetByValueResult)
1909 CACHEOP_CASE_UNIMPL(ProxyHasPropResult)
1910 CACHEOP_CASE_UNIMPL(CallObjectHasSparseElementResult)
1911 CACHEOP_CASE_UNIMPL(CallNativeGetElementResult)
1912 CACHEOP_CASE_UNIMPL(CallNativeGetElementSuperResult)
1913 CACHEOP_CASE_UNIMPL(GetNextMapSetEntryForIteratorResult)
1914 CACHEOP_CASE_UNIMPL(LoadUndefinedResult)
1915 CACHEOP_CASE_UNIMPL(LoadDoubleConstant)
1916 CACHEOP_CASE_UNIMPL(LoadBooleanConstant)
1917 CACHEOP_CASE_UNIMPL(LoadUndefined)
1918 CACHEOP_CASE_UNIMPL(LoadConstantString)
1919 CACHEOP_CASE_UNIMPL(LoadInstanceOfObjectResult)
1920 CACHEOP_CASE_UNIMPL(LoadTypeOfObjectResult)
1921 CACHEOP_CASE_UNIMPL(DoubleAddResult)
1922 CACHEOP_CASE_UNIMPL(DoubleSubResult)
1923 CACHEOP_CASE_UNIMPL(DoubleMulResult)
1924 CACHEOP_CASE_UNIMPL(DoubleDivResult)
1925 CACHEOP_CASE_UNIMPL(DoubleModResult)
1926 CACHEOP_CASE_UNIMPL(DoublePowResult)
1927 CACHEOP_CASE_UNIMPL(BigIntAddResult)
1928 CACHEOP_CASE_UNIMPL(BigIntSubResult)
1929 CACHEOP_CASE_UNIMPL(BigIntMulResult)
1930 CACHEOP_CASE_UNIMPL(BigIntDivResult)
1931 CACHEOP_CASE_UNIMPL(BigIntModResult)
1932 CACHEOP_CASE_UNIMPL(BigIntPowResult)
1933 CACHEOP_CASE_UNIMPL(Int32BitXorResult)
1934 CACHEOP_CASE_UNIMPL(Int32LeftShiftResult)
1935 CACHEOP_CASE_UNIMPL(Int32RightShiftResult)
1936 CACHEOP_CASE_UNIMPL(Int32URightShiftResult)
1937 CACHEOP_CASE_UNIMPL(Int32NotResult)
1938 CACHEOP_CASE_UNIMPL(BigIntBitOrResult)
1939 CACHEOP_CASE_UNIMPL(BigIntBitXorResult)
1940 CACHEOP_CASE_UNIMPL(BigIntBitAndResult)
1941 CACHEOP_CASE_UNIMPL(BigIntLeftShiftResult)
1942 CACHEOP_CASE_UNIMPL(BigIntRightShiftResult)
1943 CACHEOP_CASE_UNIMPL(BigIntNotResult)
1944 CACHEOP_CASE_UNIMPL(Int32NegationResult)
1945 CACHEOP_CASE_UNIMPL(DoubleNegationResult)
1946 CACHEOP_CASE_UNIMPL(BigIntNegationResult)
1947 CACHEOP_CASE_UNIMPL(Int32DecResult)
1948 CACHEOP_CASE_UNIMPL(DoubleIncResult)
1949 CACHEOP_CASE_UNIMPL(DoubleDecResult)
1950 CACHEOP_CASE_UNIMPL(BigIntIncResult)
1951 CACHEOP_CASE_UNIMPL(BigIntDecResult)
1952 CACHEOP_CASE_UNIMPL(LoadDoubleTruthyResult)
1953 CACHEOP_CASE_UNIMPL(LoadBigIntTruthyResult)
1954 CACHEOP_CASE_UNIMPL(LoadValueTruthyResult)
1955 CACHEOP_CASE_UNIMPL(NewPlainObjectResult)
1956 CACHEOP_CASE_UNIMPL(NewArrayObjectResult)
1957 CACHEOP_CASE_UNIMPL(CallStringObjectConcatResult)
1958 CACHEOP_CASE_UNIMPL(CallIsSuspendedGeneratorResult)
1959 CACHEOP_CASE_UNIMPL(CompareObjectResult)
1960 CACHEOP_CASE_UNIMPL(CompareSymbolResult)
1961 CACHEOP_CASE_UNIMPL(CompareDoubleResult)
1962 CACHEOP_CASE_UNIMPL(CompareBigIntResult)
1963 CACHEOP_CASE_UNIMPL(CompareBigIntInt32Result)
1964 CACHEOP_CASE_UNIMPL(CompareBigIntNumberResult)
1965 CACHEOP_CASE_UNIMPL(CompareBigIntStringResult)
1966 CACHEOP_CASE_UNIMPL(CompareDoubleSameValueResult)
1967 CACHEOP_CASE_UNIMPL(SameValueResult)
1968 CACHEOP_CASE_UNIMPL(IndirectTruncateInt32Result)
1969 CACHEOP_CASE_UNIMPL(BigIntAsIntNResult)
1970 CACHEOP_CASE_UNIMPL(BigIntAsUintNResult)
1971 CACHEOP_CASE_UNIMPL(SetHasResult)
1972 CACHEOP_CASE_UNIMPL(SetHasNonGCThingResult)
1973 CACHEOP_CASE_UNIMPL(SetHasStringResult)
1974 CACHEOP_CASE_UNIMPL(SetHasSymbolResult)
1975 CACHEOP_CASE_UNIMPL(SetHasBigIntResult)
1976 CACHEOP_CASE_UNIMPL(SetHasObjectResult)
1977 CACHEOP_CASE_UNIMPL(SetSizeResult)
1978 CACHEOP_CASE_UNIMPL(MapHasResult)
1979 CACHEOP_CASE_UNIMPL(MapHasNonGCThingResult)
1980 CACHEOP_CASE_UNIMPL(MapHasStringResult)
1981 CACHEOP_CASE_UNIMPL(MapHasSymbolResult)
1982 CACHEOP_CASE_UNIMPL(MapHasBigIntResult)
1983 CACHEOP_CASE_UNIMPL(MapHasObjectResult)
1984 CACHEOP_CASE_UNIMPL(MapGetResult)
1985 CACHEOP_CASE_UNIMPL(MapGetNonGCThingResult)
1986 CACHEOP_CASE_UNIMPL(MapGetStringResult)
1987 CACHEOP_CASE_UNIMPL(MapGetSymbolResult)
1988 CACHEOP_CASE_UNIMPL(MapGetBigIntResult)
1989 CACHEOP_CASE_UNIMPL(MapGetObjectResult)
1990 CACHEOP_CASE_UNIMPL(MapSizeResult)
1991 CACHEOP_CASE_UNIMPL(ArrayFromArgumentsObjectResult)
1992 CACHEOP_CASE_UNIMPL(CloseIterScriptedResult)
1993 CACHEOP_CASE_UNIMPL(CallPrintString)
1994 CACHEOP_CASE_UNIMPL(Breakpoint)
1995 CACHEOP_CASE_UNIMPL(WrapResult)
1996 CACHEOP_CASE_UNIMPL(Bailout)
1997 CACHEOP_CASE_UNIMPL(AssertRecoveredOnBailoutResult)
1998 CACHEOP_CASE_UNIMPL(GuardIsNotUninitializedLexical) {
1999 TRACE_PRINTF("unknown CacheOp: %s\n", CacheIROpNames[int(cacheop)]);
2000 return ICInterpretOpResult::NextIC;
2003 #undef PREDICT_NEXT
2007 * -----------------------------------------------
2008 * IC callsite logic, and fallback stubs
2009 * -----------------------------------------------
2012 #define SAVE_INPUTS(arity) \
2013 do { \
2014 switch (arity) { \
2015 case 0: \
2016 break; \
2017 case 1: \
2018 inputs[0] = icregs.icVals[0]; \
2019 break; \
2020 case 2: \
2021 inputs[0] = icregs.icVals[0]; \
2022 inputs[1] = icregs.icVals[1]; \
2023 break; \
2024 case 3: \
2025 inputs[0] = icregs.icVals[0]; \
2026 inputs[1] = icregs.icVals[1]; \
2027 inputs[2] = icregs.icVals[2]; \
2028 break; \
2030 } while (0)
2032 #define RESTORE_INPUTS(arity) \
2033 do { \
2034 switch (arity) { \
2035 case 0: \
2036 break; \
2037 case 1: \
2038 icregs.icVals[0] = inputs[0]; \
2039 break; \
2040 case 2: \
2041 icregs.icVals[0] = inputs[0]; \
2042 icregs.icVals[1] = inputs[1]; \
2043 break; \
2044 case 3: \
2045 icregs.icVals[0] = inputs[0]; \
2046 icregs.icVals[1] = inputs[1]; \
2047 icregs.icVals[2] = inputs[2]; \
2048 break; \
2050 } while (0)
2052 #define DEFINE_IC(kind, arity, fallback_body) \
2053 static PBIResult MOZ_ALWAYS_INLINE IC##kind( \
2054 BaselineFrame* frame, VMFrameManager& frameMgr, State& state, \
2055 ICRegs& icregs, Stack& stack, StackVal* sp, jsbytecode* pc) { \
2056 ICStub* stub = frame->interpreterICEntry()->firstStub(); \
2057 uint64_t inputs[3]; \
2058 SAVE_INPUTS(arity); \
2059 while (true) { \
2060 next_stub: \
2061 if (stub->isFallback()) { \
2062 ICFallbackStub* fallback = stub->toFallbackStub(); \
2063 fallback_body; \
2064 icregs.icResult = state.res.asRawBits(); \
2065 state.res = UndefinedValue(); \
2066 return PBIResult::Ok; \
2067 error: \
2068 return PBIResult::Error; \
2069 } else { \
2070 ICCacheIRStub* cstub = stub->toCacheIRStub(); \
2071 cstub->incrementEnteredCount(); \
2072 new (&icregs.cacheIRReader) CacheIRReader(cstub->stubInfo()); \
2073 switch (ICInterpretOps(frame, frameMgr, state, icregs, stack, sp, \
2074 cstub, pc)) { \
2075 case ICInterpretOpResult::NextIC: \
2076 stub = stub->maybeNext(); \
2077 RESTORE_INPUTS(arity); \
2078 goto next_stub; \
2079 case ICInterpretOpResult::Return: \
2080 return PBIResult::Ok; \
2081 case ICInterpretOpResult::Error: \
2082 return PBIResult::Error; \
2083 case ICInterpretOpResult::Unwind: \
2084 return PBIResult::Unwind; \
2085 case ICInterpretOpResult::UnwindError: \
2086 return PBIResult::UnwindError; \
2087 case ICInterpretOpResult::UnwindRet: \
2088 return PBIResult::UnwindRet; \
2094 #define IC_LOAD_VAL(state_elem, index) \
2095 ReservedRooted<Value> state_elem(&state.state_elem, \
2096 Value::fromRawBits(icregs.icVals[(index)]))
2097 #define IC_LOAD_OBJ(state_elem, index) \
2098 ReservedRooted<JSObject*> state_elem( \
2099 &state.state_elem, reinterpret_cast<JSObject*>(icregs.icVals[(index)]))
2101 DEFINE_IC(Typeof, 1, {
2102 IC_LOAD_VAL(value0, 0);
2103 PUSH_FALLBACK_IC_FRAME();
2104 if (!DoTypeOfFallback(cx, frame, fallback, value0, &state.res)) {
2105 goto error;
2109 DEFINE_IC(GetName, 1, {
2110 IC_LOAD_OBJ(obj0, 0);
2111 PUSH_FALLBACK_IC_FRAME();
2112 if (!DoGetNameFallback(cx, frame, fallback, obj0, &state.res)) {
2113 goto error;
2117 DEFINE_IC(Call, 1, {
2118 uint32_t argc = uint32_t(icregs.icVals[0]);
2119 uint32_t totalArgs =
2120 argc + icregs.extraArgs; // this, callee, (constructing?), func args
2121 Value* args = reinterpret_cast<Value*>(&sp[0]);
2122 TRACE_PRINTF("Call fallback: argc %d totalArgs %d args %p\n", argc, totalArgs,
2123 args);
2124 // Reverse values on the stack.
2125 std::reverse(args, args + totalArgs);
2127 PUSH_FALLBACK_IC_FRAME();
2128 if (icregs.spreadCall) {
2129 if (!DoSpreadCallFallback(cx, frame, fallback, args, &state.res)) {
2130 std::reverse(args, args + totalArgs);
2131 goto error;
2133 } else {
2134 if (!DoCallFallback(cx, frame, fallback, argc, args, &state.res)) {
2135 std::reverse(args, args + totalArgs);
2136 goto error;
2142 DEFINE_IC(UnaryArith, 1, {
2143 IC_LOAD_VAL(value0, 0);
2144 PUSH_FALLBACK_IC_FRAME();
2145 if (!DoUnaryArithFallback(cx, frame, fallback, value0, &state.res)) {
2146 goto error;
2150 DEFINE_IC(BinaryArith, 2, {
2151 IC_LOAD_VAL(value0, 0);
2152 IC_LOAD_VAL(value1, 1);
2153 PUSH_FALLBACK_IC_FRAME();
2154 if (!DoBinaryArithFallback(cx, frame, fallback, value0, value1, &state.res)) {
2155 goto error;
2159 DEFINE_IC(ToBool, 1, {
2160 IC_LOAD_VAL(value0, 0);
2161 PUSH_FALLBACK_IC_FRAME();
2162 if (!DoToBoolFallback(cx, frame, fallback, value0, &state.res)) {
2163 goto error;
2167 DEFINE_IC(Compare, 2, {
2168 IC_LOAD_VAL(value0, 0);
2169 IC_LOAD_VAL(value1, 1);
2170 PUSH_FALLBACK_IC_FRAME();
2171 if (!DoCompareFallback(cx, frame, fallback, value0, value1, &state.res)) {
2172 goto error;
2176 DEFINE_IC(InstanceOf, 2, {
2177 IC_LOAD_VAL(value0, 0);
2178 IC_LOAD_VAL(value1, 1);
2179 PUSH_FALLBACK_IC_FRAME();
2180 if (!DoInstanceOfFallback(cx, frame, fallback, value0, value1, &state.res)) {
2181 goto error;
2185 DEFINE_IC(In, 2, {
2186 IC_LOAD_VAL(value0, 0);
2187 IC_LOAD_VAL(value1, 1);
2188 PUSH_FALLBACK_IC_FRAME();
2189 if (!DoInFallback(cx, frame, fallback, value0, value1, &state.res)) {
2190 goto error;
2194 DEFINE_IC(BindName, 1, {
2195 IC_LOAD_OBJ(obj0, 0);
2196 PUSH_FALLBACK_IC_FRAME();
2197 if (!DoBindNameFallback(cx, frame, fallback, obj0, &state.res)) {
2198 goto error;
2202 DEFINE_IC(SetProp, 2, {
2203 IC_LOAD_VAL(value0, 0);
2204 IC_LOAD_VAL(value1, 1);
2205 PUSH_FALLBACK_IC_FRAME();
2206 if (!DoSetPropFallback(cx, frame, fallback, nullptr, value0, value1)) {
2207 goto error;
2211 DEFINE_IC(NewObject, 0, {
2212 PUSH_FALLBACK_IC_FRAME();
2213 if (!DoNewObjectFallback(cx, frame, fallback, &state.res)) {
2214 goto error;
2218 DEFINE_IC(GetProp, 1, {
2219 IC_LOAD_VAL(value0, 0);
2220 PUSH_FALLBACK_IC_FRAME();
2221 if (!DoGetPropFallback(cx, frame, fallback, &value0, &state.res)) {
2222 goto error;
2226 DEFINE_IC(GetPropSuper, 2, {
2227 IC_LOAD_VAL(value0, 1);
2228 IC_LOAD_VAL(value1, 0);
2229 PUSH_FALLBACK_IC_FRAME();
2230 if (!DoGetPropSuperFallback(cx, frame, fallback, value0, &value1,
2231 &state.res)) {
2232 goto error;
2236 DEFINE_IC(GetElem, 2, {
2237 IC_LOAD_VAL(value0, 0);
2238 IC_LOAD_VAL(value1, 1);
2239 PUSH_FALLBACK_IC_FRAME();
2240 if (!DoGetElemFallback(cx, frame, fallback, value0, value1, &state.res)) {
2241 goto error;
2245 DEFINE_IC(GetElemSuper, 3, {
2246 IC_LOAD_VAL(value0, 0); // receiver
2247 IC_LOAD_VAL(value1, 1); // obj (lhs)
2248 IC_LOAD_VAL(value2, 2); // key (rhs)
2249 PUSH_FALLBACK_IC_FRAME();
2250 if (!DoGetElemSuperFallback(cx, frame, fallback, value1, value2, value0,
2251 &state.res)) {
2252 goto error;
2256 DEFINE_IC(NewArray, 0, {
2257 PUSH_FALLBACK_IC_FRAME();
2258 if (!DoNewArrayFallback(cx, frame, fallback, &state.res)) {
2259 goto error;
2263 DEFINE_IC(GetIntrinsic, 0, {
2264 PUSH_FALLBACK_IC_FRAME();
2265 if (!DoGetIntrinsicFallback(cx, frame, fallback, &state.res)) {
2266 goto error;
2270 DEFINE_IC(SetElem, 3, {
2271 IC_LOAD_VAL(value0, 0);
2272 IC_LOAD_VAL(value1, 1);
2273 IC_LOAD_VAL(value2, 2);
2274 PUSH_FALLBACK_IC_FRAME();
2275 if (!DoSetElemFallback(cx, frame, fallback, nullptr, value0, value1,
2276 value2)) {
2277 goto error;
2281 DEFINE_IC(HasOwn, 2, {
2282 IC_LOAD_VAL(value0, 0);
2283 IC_LOAD_VAL(value1, 1);
2284 PUSH_FALLBACK_IC_FRAME();
2285 if (!DoHasOwnFallback(cx, frame, fallback, value0, value1, &state.res)) {
2286 goto error;
2290 DEFINE_IC(CheckPrivateField, 2, {
2291 IC_LOAD_VAL(value0, 0);
2292 IC_LOAD_VAL(value1, 1);
2293 PUSH_FALLBACK_IC_FRAME();
2294 if (!DoCheckPrivateFieldFallback(cx, frame, fallback, value0, value1,
2295 &state.res)) {
2296 goto error;
2300 DEFINE_IC(GetIterator, 1, {
2301 IC_LOAD_VAL(value0, 0);
2302 PUSH_FALLBACK_IC_FRAME();
2303 if (!DoGetIteratorFallback(cx, frame, fallback, value0, &state.res)) {
2304 goto error;
2308 DEFINE_IC(ToPropertyKey, 1, {
2309 IC_LOAD_VAL(value0, 0);
2310 PUSH_FALLBACK_IC_FRAME();
2311 if (!DoToPropertyKeyFallback(cx, frame, fallback, value0, &state.res)) {
2312 goto error;
2316 DEFINE_IC(OptimizeSpreadCall, 1, {
2317 IC_LOAD_VAL(value0, 0);
2318 PUSH_FALLBACK_IC_FRAME();
2319 if (!DoOptimizeSpreadCallFallback(cx, frame, fallback, value0, &state.res)) {
2320 goto error;
2324 DEFINE_IC(OptimizeGetIterator, 1, {
2325 IC_LOAD_VAL(value0, 0);
2326 PUSH_FALLBACK_IC_FRAME();
2327 if (!DoOptimizeGetIteratorFallback(cx, frame, fallback, value0, &state.res)) {
2328 goto error;
2332 DEFINE_IC(Rest, 0, {
2333 PUSH_FALLBACK_IC_FRAME();
2334 if (!DoRestFallback(cx, frame, fallback, &state.res)) {
2335 goto error;
2339 DEFINE_IC(CloseIter, 1, {
2340 IC_LOAD_OBJ(obj0, 0);
2341 PUSH_FALLBACK_IC_FRAME();
2342 if (!DoCloseIterFallback(cx, frame, fallback, obj0)) {
2343 goto error;
2348 * -----------------------------------------------
2349 * Main JSOp interpreter
2350 * -----------------------------------------------
2353 static EnvironmentObject& getEnvironmentFromCoordinate(
2354 BaselineFrame* frame, EnvironmentCoordinate ec) {
2355 JSObject* env = frame->environmentChain();
2356 for (unsigned i = ec.hops(); i; i--) {
2357 if (env->is<EnvironmentObject>()) {
2358 env = &env->as<EnvironmentObject>().enclosingEnvironment();
2359 } else {
2360 MOZ_ASSERT(env->is<DebugEnvironmentProxy>());
2361 env = &env->as<DebugEnvironmentProxy>().enclosingEnvironment();
2364 return env->is<EnvironmentObject>()
2365 ? env->as<EnvironmentObject>()
2366 : env->as<DebugEnvironmentProxy>().environment();
2369 #ifndef __wasi__
2370 # define DEBUG_CHECK() \
2371 if (frame->isDebuggee()) { \
2372 TRACE_PRINTF( \
2373 "Debug check: frame is debuggee, checking for debug script\n"); \
2374 if (script->hasDebugScript()) { \
2375 goto debug; \
2378 #else
2379 # define DEBUG_CHECK()
2380 #endif
2382 #define LABEL(op) (&&label_##op)
2383 #define CASE(op) label_##op:
2384 #if !defined(TRACE_INTERP)
2385 # define DISPATCH() \
2386 DEBUG_CHECK(); \
2387 goto* addresses[*pc]
2388 #else
2389 # define DISPATCH() \
2390 DEBUG_CHECK(); \
2391 goto dispatch
2392 #endif
2394 #define ADVANCE(delta) pc += (delta);
2395 #define ADVANCE_AND_DISPATCH(delta) \
2396 ADVANCE(delta); \
2397 DISPATCH();
2399 #define END_OP(op) ADVANCE_AND_DISPATCH(JSOpLength_##op);
2401 #define IC_SET_ARG_FROM_STACK(index, stack_index) \
2402 icregs.icVals[(index)] = sp[(stack_index)].asUInt64();
2403 #define IC_POP_ARG(index) icregs.icVals[(index)] = (*sp++).asUInt64();
2404 #define IC_SET_VAL_ARG(index, expr) icregs.icVals[(index)] = (expr).asRawBits();
2405 #define IC_SET_OBJ_ARG(index, expr) \
2406 icregs.icVals[(index)] = reinterpret_cast<uint64_t>(expr);
2407 #define IC_PUSH_RESULT() PUSH(StackVal(icregs.icResult));
2409 #if !defined(TRACE_INTERP)
2410 # define PREDICT_NEXT(op) \
2411 if (JSOp(*pc) == JSOp::op) { \
2412 DEBUG_CHECK(); \
2413 goto label_##op; \
2415 #else
2416 # define PREDICT_NEXT(op)
2417 #endif
2419 #define COUNT_COVERAGE_PC(PC) \
2420 if (script->hasScriptCounts()) { \
2421 PCCounts* counts = script->maybeGetPCCounts(PC); \
2422 MOZ_ASSERT(counts); \
2423 counts->numExec()++; \
2425 #define COUNT_COVERAGE_MAIN() \
2427 jsbytecode* main = script->main(); \
2428 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
2431 #define NEXT_IC() frame->interpreterICEntry()++;
2433 #define INVOKE_IC(kind) \
2434 switch (IC##kind(frame, frameMgr, state, icregs, stack, sp, pc)) { \
2435 case PBIResult::Ok: \
2436 break; \
2437 case PBIResult::Error: \
2438 goto error; \
2439 case PBIResult::Unwind: \
2440 goto unwind; \
2441 case PBIResult::UnwindError: \
2442 goto unwind_error; \
2443 case PBIResult::UnwindRet: \
2444 goto unwind_ret; \
2446 NEXT_IC();
2448 PBIResult PortableBaselineInterpret(JSContext* cx_, State& state, Stack& stack,
2449 StackVal* sp, JSObject* envChain,
2450 Value* ret) {
2451 #define OPCODE_LABEL(op, ...) LABEL(op),
2452 #define TRAILING_LABEL(v) LABEL(default),
2454 static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = {
2455 FOR_EACH_OPCODE(OPCODE_LABEL)
2456 FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)};
2458 #undef OPCODE_LABEL
2459 #undef TRAILING_LABEL
2461 PUSHNATIVE(StackValNative(nullptr)); // Fake return address.
2462 BaselineFrame* frame = stack.pushFrame(sp, cx_, envChain);
2463 MOZ_ASSERT(frame); // safety: stack margin.
2464 sp = reinterpret_cast<StackVal*>(frame);
2466 // Save the entry frame so that when unwinding, we know when to
2467 // return from this C++ frame.
2468 StackVal* entryFrame = sp;
2470 ICRegs icregs;
2471 RootedScript script(cx_, frame->script());
2472 jsbytecode* pc = frame->interpreterPC();
2473 bool from_unwind = false;
2475 VMFrameManager frameMgr(cx_, frame);
2477 AutoCheckRecursionLimit recursion(frameMgr.cxForLocalUseOnly());
2478 if (!recursion.checkDontReport(frameMgr.cxForLocalUseOnly())) {
2479 PUSH_EXIT_FRAME();
2480 ReportOverRecursed(frameMgr.cxForLocalUseOnly());
2481 return PBIResult::Error;
2484 // Check max stack depth once, so we don't need to check it
2485 // otherwise below for ordinary stack-manipulation opcodes (just for
2486 // exit frames).
2487 if (!stack.check(sp, sizeof(StackVal) * script->nslots())) {
2488 PUSH_EXIT_FRAME();
2489 ReportOverRecursed(frameMgr.cxForLocalUseOnly());
2490 return PBIResult::Error;
2493 uint32_t nfixed = script->nfixed();
2494 for (uint32_t i = 0; i < nfixed; i++) {
2495 PUSH(StackVal(UndefinedValue()));
2497 ret->setUndefined();
2499 if (CalleeTokenIsFunction(frame->calleeToken())) {
2500 JSFunction* func = CalleeTokenToFunction(frame->calleeToken());
2501 frame->setEnvironmentChain(func->environment());
2502 if (func->needsFunctionEnvironmentObjects()) {
2503 PUSH_EXIT_FRAME();
2504 if (!js::InitFunctionEnvironmentObjects(cx, frame)) {
2505 goto error;
2507 TRACE_PRINTF("callee is func %p; created environment object: %p\n", func,
2508 frame->environmentChain());
2512 // Check if we are being debugged, and set a flag in the frame if
2513 // so.
2514 if (script->isDebuggee()) {
2515 TRACE_PRINTF("Script is debuggee\n");
2516 frame->setIsDebuggee();
2518 PUSH_EXIT_FRAME();
2519 if (!DebugPrologue(cx, frame)) {
2520 goto error;
2524 if (!script->hasScriptCounts()) {
2525 if (frameMgr.cxForLocalUseOnly()->realm()->collectCoverageForDebug()) {
2526 PUSH_EXIT_FRAME();
2527 if (!script->initScriptCounts(cx)) {
2528 goto error;
2532 COUNT_COVERAGE_MAIN();
2534 #ifndef __wasi__
2535 if (frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
2536 PUSH_EXIT_FRAME();
2537 if (!InterruptCheck(cx)) {
2538 goto error;
2541 #endif
2543 TRACE_PRINTF("Entering: sp = %p fp = %p frame = %p, script = %p, pc = %p\n",
2544 sp, stack.fp, frame, script.get(), pc);
2545 TRACE_PRINTF("nslots = %d nfixed = %d\n", int(script->nslots()),
2546 int(script->nfixed()));
2548 while (true) {
2549 DEBUG_CHECK();
2551 #ifndef __wasi__
2552 dispatch:
2553 #endif
2555 #ifdef TRACE_INTERP
2557 JSOp op = JSOp(*pc);
2558 printf("sp[0] = %" PRIx64 " sp[1] = %" PRIx64 " sp[2] = %" PRIx64 "\n",
2559 sp[0].asUInt64(), sp[1].asUInt64(), sp[2].asUInt64());
2560 printf("script = %p pc = %p: %s (ic %d) pending = %d\n", script.get(), pc,
2561 CodeName(op),
2562 (int)(frame->interpreterICEntry() -
2563 script->jitScript()->icScript()->icEntries()),
2564 frameMgr.cxForLocalUseOnly()->isExceptionPending());
2565 printf("sp = %p fp = %p\n", sp, stack.fp);
2566 printf("TOS tag: %d\n", int(sp[0].asValue().asRawBits() >> 47));
2567 fflush(stdout);
2569 #endif
2571 goto* addresses[*pc];
2573 CASE(Nop) { END_OP(Nop); }
2574 CASE(NopIsAssignOp) { END_OP(NopIsAssignOp); }
2575 CASE(Undefined) {
2576 PUSH(StackVal(UndefinedValue()));
2577 END_OP(Undefined);
2579 CASE(Null) {
2580 PUSH(StackVal(NullValue()));
2581 END_OP(Null);
2583 CASE(False) {
2584 PUSH(StackVal(BooleanValue(false)));
2585 END_OP(False);
2587 CASE(True) {
2588 PUSH(StackVal(BooleanValue(true)));
2589 END_OP(True);
2591 CASE(Int32) {
2592 PUSH(StackVal(Int32Value(GET_INT32(pc))));
2593 END_OP(Int32);
2595 CASE(Zero) {
2596 PUSH(StackVal(Int32Value(0)));
2597 END_OP(Zero);
2599 CASE(One) {
2600 PUSH(StackVal(Int32Value(1)));
2601 END_OP(One);
2603 CASE(Int8) {
2604 PUSH(StackVal(Int32Value(GET_INT8(pc))));
2605 END_OP(Int8);
2607 CASE(Uint16) {
2608 PUSH(StackVal(Int32Value(GET_UINT16(pc))));
2609 END_OP(Uint16);
2611 CASE(Uint24) {
2612 PUSH(StackVal(Int32Value(GET_UINT24(pc))));
2613 END_OP(Uint24);
2615 CASE(Double) {
2616 PUSH(StackVal(GET_INLINE_VALUE(pc)));
2617 END_OP(Double);
2619 CASE(BigInt) {
2620 PUSH(StackVal(JS::BigIntValue(script->getBigInt(pc))));
2621 END_OP(BigInt);
2623 CASE(String) {
2624 PUSH(StackVal(StringValue(script->getString(pc))));
2625 END_OP(String);
2627 CASE(Symbol) {
2628 PUSH(StackVal(
2629 SymbolValue(frameMgr.cxForLocalUseOnly()->wellKnownSymbols().get(
2630 GET_UINT8(pc)))));
2631 END_OP(Symbol);
2633 CASE(Void) {
2634 sp[0] = StackVal(JS::UndefinedValue());
2635 END_OP(Void);
2638 CASE(Typeof)
2639 CASE(TypeofExpr) {
2640 static_assert(JSOpLength_Typeof == JSOpLength_TypeofExpr);
2641 if (kHybridICs) {
2642 sp[0] = StackVal(StringValue(TypeOfOperation(
2643 Stack::handle(sp), frameMgr.cxForLocalUseOnly()->runtime())));
2644 NEXT_IC();
2645 } else {
2646 IC_POP_ARG(0);
2647 INVOKE_IC(Typeof);
2648 IC_PUSH_RESULT();
2650 END_OP(Typeof);
2653 CASE(Pos) {
2654 if (sp[0].asValue().isNumber()) {
2655 // Nothing!
2656 NEXT_IC();
2657 END_OP(Pos);
2658 } else {
2659 goto generic_unary;
2662 CASE(Neg) {
2663 if (sp[0].asValue().isInt32()) {
2664 int32_t i = sp[0].asValue().toInt32();
2665 if (i != 0 && i != INT32_MIN) {
2666 sp[0] = StackVal(Int32Value(-i));
2667 NEXT_IC();
2668 END_OP(Neg);
2671 if (sp[0].asValue().isNumber()) {
2672 sp[0] = StackVal(NumberValue(-sp[0].asValue().toNumber()));
2673 NEXT_IC();
2674 END_OP(Neg);
2676 goto generic_unary;
2679 CASE(Inc) {
2680 if (sp[0].asValue().isInt32()) {
2681 int32_t i = sp[0].asValue().toInt32();
2682 if (i != INT32_MAX) {
2683 sp[0] = StackVal(Int32Value(i + 1));
2684 NEXT_IC();
2685 END_OP(Inc);
2688 if (sp[0].asValue().isNumber()) {
2689 sp[0] = StackVal(NumberValue(sp[0].asValue().toNumber() + 1));
2690 NEXT_IC();
2691 END_OP(Inc);
2693 goto generic_unary;
2695 CASE(Dec) {
2696 if (sp[0].asValue().isInt32()) {
2697 int32_t i = sp[0].asValue().toInt32();
2698 if (i != INT32_MIN) {
2699 sp[0] = StackVal(Int32Value(i - 1));
2700 NEXT_IC();
2701 END_OP(Dec);
2704 if (sp[0].asValue().isNumber()) {
2705 sp[0] = StackVal(NumberValue(sp[0].asValue().toNumber() - 1));
2706 NEXT_IC();
2707 END_OP(Dec);
2709 goto generic_unary;
2712 CASE(BitNot) {
2713 if (sp[0].asValue().isInt32()) {
2714 int32_t i = sp[0].asValue().toInt32();
2715 sp[0] = StackVal(Int32Value(~i));
2716 NEXT_IC();
2717 END_OP(Inc);
2719 goto generic_unary;
2722 CASE(ToNumeric) {
2723 if (sp[0].asValue().isNumeric()) {
2724 NEXT_IC();
2725 } else if (kHybridICs) {
2726 MutableHandleValue val = Stack::handleMut(&sp[0]);
2727 PUSH_EXIT_FRAME();
2728 if (!ToNumeric(cx, val)) {
2729 goto error;
2731 NEXT_IC();
2732 } else {
2733 goto generic_unary;
2735 END_OP(ToNumeric);
2738 generic_unary: {
2739 static_assert(JSOpLength_Pos == JSOpLength_Neg);
2740 static_assert(JSOpLength_Pos == JSOpLength_BitNot);
2741 static_assert(JSOpLength_Pos == JSOpLength_Inc);
2742 static_assert(JSOpLength_Pos == JSOpLength_Dec);
2743 static_assert(JSOpLength_Pos == JSOpLength_ToNumeric);
2744 IC_POP_ARG(0);
2745 INVOKE_IC(UnaryArith);
2746 IC_PUSH_RESULT();
2747 END_OP(Pos);
2750 CASE(Not) {
2751 if (kHybridICs) {
2752 sp[0] = StackVal(BooleanValue(!ToBoolean(Stack::handle(sp))));
2753 NEXT_IC();
2754 } else {
2755 IC_POP_ARG(0);
2756 INVOKE_IC(ToBool);
2757 PUSH(StackVal(
2758 BooleanValue(!Value::fromRawBits(icregs.icResult).toBoolean())));
2760 END_OP(Not);
2763 CASE(And) {
2764 bool result;
2765 if (kHybridICs) {
2766 result = ToBoolean(Stack::handle(sp));
2767 NEXT_IC();
2768 } else {
2769 IC_SET_ARG_FROM_STACK(0, 0);
2770 INVOKE_IC(ToBool);
2771 result = Value::fromRawBits(icregs.icResult).toBoolean();
2773 int32_t jumpOffset = GET_JUMP_OFFSET(pc);
2774 if (!result) {
2775 ADVANCE(jumpOffset);
2776 PREDICT_NEXT(JumpTarget);
2777 PREDICT_NEXT(LoopHead);
2778 } else {
2779 ADVANCE(JSOpLength_And);
2781 DISPATCH();
2783 CASE(Or) {
2784 bool result;
2785 if (kHybridICs) {
2786 result = ToBoolean(Stack::handle(sp));
2787 NEXT_IC();
2788 } else {
2789 IC_SET_ARG_FROM_STACK(0, 0);
2790 INVOKE_IC(ToBool);
2791 result = Value::fromRawBits(icregs.icResult).toBoolean();
2793 int32_t jumpOffset = GET_JUMP_OFFSET(pc);
2794 if (result) {
2795 ADVANCE(jumpOffset);
2796 PREDICT_NEXT(JumpTarget);
2797 PREDICT_NEXT(LoopHead);
2798 } else {
2799 ADVANCE(JSOpLength_Or);
2801 DISPATCH();
2803 CASE(JumpIfTrue) {
2804 bool result;
2805 if (kHybridICs) {
2806 result = ToBoolean(Stack::handle(sp));
2807 POP();
2808 NEXT_IC();
2809 } else {
2810 IC_POP_ARG(0);
2811 INVOKE_IC(ToBool);
2812 result = Value::fromRawBits(icregs.icResult).toBoolean();
2814 int32_t jumpOffset = GET_JUMP_OFFSET(pc);
2815 if (result) {
2816 ADVANCE(jumpOffset);
2817 PREDICT_NEXT(JumpTarget);
2818 PREDICT_NEXT(LoopHead);
2819 } else {
2820 ADVANCE(JSOpLength_JumpIfTrue);
2822 DISPATCH();
2824 CASE(JumpIfFalse) {
2825 bool result;
2826 if (kHybridICs) {
2827 result = ToBoolean(Stack::handle(sp));
2828 POP();
2829 NEXT_IC();
2830 } else {
2831 IC_POP_ARG(0);
2832 INVOKE_IC(ToBool);
2833 result = Value::fromRawBits(icregs.icResult).toBoolean();
2835 int32_t jumpOffset = GET_JUMP_OFFSET(pc);
2836 if (!result) {
2837 ADVANCE(jumpOffset);
2838 PREDICT_NEXT(JumpTarget);
2839 PREDICT_NEXT(LoopHead);
2840 } else {
2841 ADVANCE(JSOpLength_JumpIfFalse);
2843 DISPATCH();
2846 CASE(Add) {
2847 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
2848 int64_t lhs = sp[1].asValue().toInt32();
2849 int64_t rhs = sp[0].asValue().toInt32();
2850 if (lhs + rhs >= int64_t(INT32_MIN) &&
2851 lhs + rhs <= int64_t(INT32_MAX)) {
2852 POP();
2853 sp[0] = StackVal(Int32Value(int32_t(lhs + rhs)));
2854 NEXT_IC();
2855 END_OP(Add);
2858 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
2859 double lhs = sp[1].asValue().toNumber();
2860 double rhs = sp[0].asValue().toNumber();
2861 POP();
2862 sp[0] = StackVal(NumberValue(lhs + rhs));
2863 NEXT_IC();
2864 END_OP(Add);
2866 if (kHybridICs) {
2867 MutableHandleValue lhs = Stack::handleMut(sp + 1);
2868 MutableHandleValue rhs = Stack::handleMut(sp);
2869 MutableHandleValue result = Stack::handleMut(sp + 1);
2871 PUSH_EXIT_FRAME();
2872 if (!AddOperation(cx, lhs, rhs, result)) {
2873 goto error;
2876 POP();
2877 NEXT_IC();
2878 END_OP(Add);
2880 goto generic_binary;
2883 CASE(Sub) {
2884 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
2885 int64_t lhs = sp[1].asValue().toInt32();
2886 int64_t rhs = sp[0].asValue().toInt32();
2887 if (lhs - rhs >= int64_t(INT32_MIN) &&
2888 lhs - rhs <= int64_t(INT32_MAX)) {
2889 POP();
2890 sp[0] = StackVal(Int32Value(int32_t(lhs - rhs)));
2891 NEXT_IC();
2892 END_OP(Sub);
2895 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
2896 double lhs = sp[1].asValue().toNumber();
2897 double rhs = sp[0].asValue().toNumber();
2898 POP();
2899 sp[0] = StackVal(NumberValue(lhs - rhs));
2900 NEXT_IC();
2901 END_OP(Add);
2903 if (kHybridICs) {
2904 MutableHandleValue lhs = Stack::handleMut(sp + 1);
2905 MutableHandleValue rhs = Stack::handleMut(sp);
2906 MutableHandleValue result = Stack::handleMut(sp + 1);
2908 PUSH_EXIT_FRAME();
2909 if (!SubOperation(cx, lhs, rhs, result)) {
2910 goto error;
2913 POP();
2914 NEXT_IC();
2915 END_OP(Sub);
2917 goto generic_binary;
2920 CASE(Mul) {
2921 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
2922 int64_t lhs = sp[1].asValue().toInt32();
2923 int64_t rhs = sp[0].asValue().toInt32();
2924 int64_t product = lhs * rhs;
2925 if (product >= int64_t(INT32_MIN) && product <= int64_t(INT32_MAX) &&
2926 (product != 0 || !((lhs < 0) ^ (rhs < 0)))) {
2927 POP();
2928 sp[0] = StackVal(Int32Value(int32_t(product)));
2929 NEXT_IC();
2930 END_OP(Mul);
2933 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
2934 double lhs = sp[1].asValue().toNumber();
2935 double rhs = sp[0].asValue().toNumber();
2936 POP();
2937 sp[0] = StackVal(NumberValue(lhs * rhs));
2938 NEXT_IC();
2939 END_OP(Mul);
2941 if (kHybridICs) {
2942 MutableHandleValue lhs = Stack::handleMut(sp + 1);
2943 MutableHandleValue rhs = Stack::handleMut(sp);
2944 MutableHandleValue result = Stack::handleMut(sp + 1);
2946 PUSH_EXIT_FRAME();
2947 if (!MulOperation(cx, lhs, rhs, result)) {
2948 goto error;
2951 POP();
2952 NEXT_IC();
2953 END_OP(Mul);
2955 goto generic_binary;
2957 CASE(Div) {
2958 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
2959 double lhs = sp[1].asValue().toNumber();
2960 double rhs = sp[0].asValue().toNumber();
2961 POP();
2962 sp[0] = StackVal(NumberValue(NumberDiv(lhs, rhs)));
2963 NEXT_IC();
2964 END_OP(Div);
2966 if (kHybridICs) {
2967 MutableHandleValue lhs = Stack::handleMut(sp + 1);
2968 MutableHandleValue rhs = Stack::handleMut(sp);
2969 MutableHandleValue result = Stack::handleMut(sp + 1);
2971 PUSH_EXIT_FRAME();
2972 if (!DivOperation(cx, lhs, rhs, result)) {
2973 goto error;
2976 POP();
2977 NEXT_IC();
2978 END_OP(Div);
2980 goto generic_binary;
2982 CASE(Mod) {
2983 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
2984 int64_t lhs = sp[1].asValue().toInt32();
2985 int64_t rhs = sp[0].asValue().toInt32();
2986 if (lhs > 0 && rhs > 0) {
2987 int64_t mod = lhs % rhs;
2988 POP();
2989 sp[0] = StackVal(Int32Value(int32_t(mod)));
2990 NEXT_IC();
2991 END_OP(Mod);
2994 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
2995 double lhs = sp[1].asValue().toNumber();
2996 double rhs = sp[0].asValue().toNumber();
2997 POP();
2998 sp[0] = StackVal(DoubleValue(NumberMod(lhs, rhs)));
2999 NEXT_IC();
3000 END_OP(Mod);
3002 if (kHybridICs) {
3003 MutableHandleValue lhs = Stack::handleMut(sp + 1);
3004 MutableHandleValue rhs = Stack::handleMut(sp);
3005 MutableHandleValue result = Stack::handleMut(sp + 1);
3007 PUSH_EXIT_FRAME();
3008 if (!ModOperation(cx, lhs, rhs, result)) {
3009 goto error;
3012 POP();
3013 NEXT_IC();
3014 END_OP(Mod);
3016 goto generic_binary;
3018 CASE(Pow) {
3019 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3020 double lhs = sp[1].asValue().toNumber();
3021 double rhs = sp[0].asValue().toNumber();
3022 POP();
3023 sp[0] = StackVal(NumberValue(ecmaPow(lhs, rhs)));
3024 NEXT_IC();
3025 END_OP(Pow);
3027 if (kHybridICs) {
3028 MutableHandleValue lhs = Stack::handleMut(sp + 1);
3029 MutableHandleValue rhs = Stack::handleMut(sp);
3030 MutableHandleValue result = Stack::handleMut(sp + 1);
3032 PUSH_EXIT_FRAME();
3033 if (!PowOperation(cx, lhs, rhs, result)) {
3034 goto error;
3037 POP();
3038 NEXT_IC();
3039 END_OP(Pow);
3041 goto generic_binary;
3043 CASE(BitOr) {
3044 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3045 int32_t lhs = sp[1].asValue().toInt32();
3046 int32_t rhs = sp[0].asValue().toInt32();
3047 POP();
3048 sp[0] = StackVal(Int32Value(lhs | rhs));
3049 NEXT_IC();
3050 END_OP(BitOr);
3052 goto generic_binary;
3054 CASE(BitAnd) {
3055 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3056 int32_t lhs = sp[1].asValue().toInt32();
3057 int32_t rhs = sp[0].asValue().toInt32();
3058 POP();
3059 sp[0] = StackVal(Int32Value(lhs & rhs));
3060 NEXT_IC();
3061 END_OP(BitAnd);
3063 goto generic_binary;
3065 CASE(BitXor) {
3066 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3067 int32_t lhs = sp[1].asValue().toInt32();
3068 int32_t rhs = sp[0].asValue().toInt32();
3069 POP();
3070 sp[0] = StackVal(Int32Value(lhs ^ rhs));
3071 NEXT_IC();
3072 END_OP(BitXor);
3074 goto generic_binary;
3076 CASE(Lsh) {
3077 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3078 // Unsigned to avoid undefined behavior on left-shift overflow
3079 // (see comment in BitLshOperation in Interpreter.cpp).
3080 uint32_t lhs = uint32_t(sp[1].asValue().toInt32());
3081 uint32_t rhs = uint32_t(sp[0].asValue().toInt32());
3082 POP();
3083 rhs &= 31;
3084 sp[0] = StackVal(Int32Value(int32_t(lhs << rhs)));
3085 NEXT_IC();
3086 END_OP(Lsh);
3088 goto generic_binary;
3090 CASE(Rsh) {
3091 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3092 int32_t lhs = sp[1].asValue().toInt32();
3093 int32_t rhs = sp[0].asValue().toInt32();
3094 POP();
3095 rhs &= 31;
3096 sp[0] = StackVal(Int32Value(lhs >> rhs));
3097 NEXT_IC();
3098 END_OP(Rsh);
3100 goto generic_binary;
3102 CASE(Ursh) {
3103 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3104 uint32_t lhs = uint32_t(sp[1].asValue().toInt32());
3105 int32_t rhs = sp[0].asValue().toInt32();
3106 POP();
3107 rhs &= 31;
3108 uint32_t result = lhs >> rhs;
3109 if (result <= uint32_t(INT32_MAX)) {
3110 sp[0] = StackVal(Int32Value(int32_t(result)));
3111 } else {
3112 sp[0] = StackVal(NumberValue(double(result)));
3114 NEXT_IC();
3115 END_OP(Ursh);
3117 goto generic_binary;
3120 generic_binary: {
3121 static_assert(JSOpLength_BitOr == JSOpLength_BitXor);
3122 static_assert(JSOpLength_BitOr == JSOpLength_BitAnd);
3123 static_assert(JSOpLength_BitOr == JSOpLength_Lsh);
3124 static_assert(JSOpLength_BitOr == JSOpLength_Rsh);
3125 static_assert(JSOpLength_BitOr == JSOpLength_Ursh);
3126 static_assert(JSOpLength_BitOr == JSOpLength_Add);
3127 static_assert(JSOpLength_BitOr == JSOpLength_Sub);
3128 static_assert(JSOpLength_BitOr == JSOpLength_Mul);
3129 static_assert(JSOpLength_BitOr == JSOpLength_Div);
3130 static_assert(JSOpLength_BitOr == JSOpLength_Mod);
3131 static_assert(JSOpLength_BitOr == JSOpLength_Pow);
3132 IC_POP_ARG(1);
3133 IC_POP_ARG(0);
3134 INVOKE_IC(BinaryArith);
3135 IC_PUSH_RESULT();
3136 END_OP(Div);
3139 CASE(Eq) {
3140 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3141 bool result = sp[0].asValue().toInt32() == sp[1].asValue().toInt32();
3142 POP();
3143 sp[0] = StackVal(BooleanValue(result));
3144 NEXT_IC();
3145 END_OP(Eq);
3147 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3148 double lhs = sp[1].asValue().toNumber();
3149 double rhs = sp[0].asValue().toNumber();
3150 bool result = lhs == rhs;
3151 POP();
3152 sp[0] = StackVal(BooleanValue(result));
3153 NEXT_IC();
3154 END_OP(Eq);
3156 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3157 bool result = sp[0].asValue().toNumber() == sp[1].asValue().toNumber();
3158 POP();
3159 sp[0] = StackVal(BooleanValue(result));
3160 NEXT_IC();
3161 END_OP(Eq);
3163 goto generic_cmp;
3166 CASE(Ne) {
3167 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3168 bool result = sp[0].asValue().toInt32() != sp[1].asValue().toInt32();
3169 POP();
3170 sp[0] = StackVal(BooleanValue(result));
3171 NEXT_IC();
3172 END_OP(Ne);
3174 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3175 double lhs = sp[1].asValue().toNumber();
3176 double rhs = sp[0].asValue().toNumber();
3177 bool result = lhs != rhs;
3178 POP();
3179 sp[0] = StackVal(BooleanValue(result));
3180 NEXT_IC();
3181 END_OP(Ne);
3183 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3184 bool result = sp[0].asValue().toNumber() != sp[1].asValue().toNumber();
3185 POP();
3186 sp[0] = StackVal(BooleanValue(result));
3187 NEXT_IC();
3188 END_OP(Eq);
3190 goto generic_cmp;
3193 CASE(Lt) {
3194 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3195 bool result = sp[1].asValue().toInt32() < sp[0].asValue().toInt32();
3196 POP();
3197 sp[0] = StackVal(BooleanValue(result));
3198 NEXT_IC();
3199 END_OP(Lt);
3201 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3202 double lhs = sp[1].asValue().toNumber();
3203 double rhs = sp[0].asValue().toNumber();
3204 bool result = lhs < rhs;
3205 if (std::isnan(lhs) || std::isnan(rhs)) {
3206 result = false;
3208 POP();
3209 sp[0] = StackVal(BooleanValue(result));
3210 NEXT_IC();
3211 END_OP(Lt);
3213 goto generic_cmp;
3215 CASE(Le) {
3216 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3217 bool result = sp[1].asValue().toInt32() <= sp[0].asValue().toInt32();
3218 POP();
3219 sp[0] = StackVal(BooleanValue(result));
3220 NEXT_IC();
3221 END_OP(Le);
3223 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3224 double lhs = sp[1].asValue().toNumber();
3225 double rhs = sp[0].asValue().toNumber();
3226 bool result = lhs <= rhs;
3227 if (std::isnan(lhs) || std::isnan(rhs)) {
3228 result = false;
3230 POP();
3231 sp[0] = StackVal(BooleanValue(result));
3232 NEXT_IC();
3233 END_OP(Le);
3235 goto generic_cmp;
3237 CASE(Gt) {
3238 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3239 bool result = sp[1].asValue().toInt32() > sp[0].asValue().toInt32();
3240 POP();
3241 sp[0] = StackVal(BooleanValue(result));
3242 NEXT_IC();
3243 END_OP(Gt);
3245 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3246 double lhs = sp[1].asValue().toNumber();
3247 double rhs = sp[0].asValue().toNumber();
3248 bool result = lhs > rhs;
3249 if (std::isnan(lhs) || std::isnan(rhs)) {
3250 result = false;
3252 POP();
3253 sp[0] = StackVal(BooleanValue(result));
3254 NEXT_IC();
3255 END_OP(Gt);
3257 goto generic_cmp;
3259 CASE(Ge) {
3260 if (sp[0].asValue().isInt32() && sp[1].asValue().isInt32()) {
3261 bool result = sp[1].asValue().toInt32() >= sp[0].asValue().toInt32();
3262 POP();
3263 sp[0] = StackVal(BooleanValue(result));
3264 NEXT_IC();
3265 END_OP(Ge);
3267 if (sp[0].asValue().isNumber() && sp[1].asValue().isNumber()) {
3268 double lhs = sp[1].asValue().toNumber();
3269 double rhs = sp[0].asValue().toNumber();
3270 bool result = lhs >= rhs;
3271 if (std::isnan(lhs) || std::isnan(rhs)) {
3272 result = false;
3274 POP();
3275 sp[0] = StackVal(BooleanValue(result));
3276 NEXT_IC();
3277 END_OP(Ge);
3279 goto generic_cmp;
3282 CASE(StrictEq)
3283 CASE(StrictNe) {
3284 if (kHybridICs) {
3285 bool result;
3286 HandleValue lval = Stack::handle(sp + 1);
3287 HandleValue rval = Stack::handle(sp);
3288 if (sp[0].asValue().isString() && sp[1].asValue().isString()) {
3289 PUSH_EXIT_FRAME();
3290 if (!js::StrictlyEqual(cx, lval, rval, &result)) {
3291 goto error;
3293 } else {
3294 if (!js::StrictlyEqual(nullptr, lval, rval, &result)) {
3295 goto error;
3298 POP();
3299 sp[0] = StackVal(
3300 BooleanValue((JSOp(*pc) == JSOp::StrictEq) ? result : !result));
3301 NEXT_IC();
3302 END_OP(StrictEq);
3303 } else {
3304 goto generic_cmp;
3308 generic_cmp: {
3309 static_assert(JSOpLength_Eq == JSOpLength_Ne);
3310 static_assert(JSOpLength_Eq == JSOpLength_StrictEq);
3311 static_assert(JSOpLength_Eq == JSOpLength_StrictNe);
3312 static_assert(JSOpLength_Eq == JSOpLength_Lt);
3313 static_assert(JSOpLength_Eq == JSOpLength_Gt);
3314 static_assert(JSOpLength_Eq == JSOpLength_Le);
3315 static_assert(JSOpLength_Eq == JSOpLength_Ge);
3316 IC_POP_ARG(1);
3317 IC_POP_ARG(0);
3318 INVOKE_IC(Compare);
3319 IC_PUSH_RESULT();
3320 END_OP(Eq);
3323 CASE(Instanceof) {
3324 IC_POP_ARG(1);
3325 IC_POP_ARG(0);
3326 INVOKE_IC(InstanceOf);
3327 IC_PUSH_RESULT();
3328 END_OP(Instanceof);
3331 CASE(In) {
3332 IC_POP_ARG(1);
3333 IC_POP_ARG(0);
3334 INVOKE_IC(In);
3335 IC_PUSH_RESULT();
3336 END_OP(In);
3339 CASE(ToPropertyKey) {
3340 IC_POP_ARG(0);
3341 INVOKE_IC(ToPropertyKey);
3342 IC_PUSH_RESULT();
3343 END_OP(ToPropertyKey);
3346 CASE(ToString) {
3347 if (sp[0].asValue().isString()) {
3348 END_OP(ToString);
3351 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3352 if (JSString* result =
3353 ToStringSlow<NoGC>(frameMgr.cxForLocalUseOnly(), value0)) {
3354 PUSH(StackVal(StringValue(result)));
3355 } else {
3357 PUSH_EXIT_FRAME();
3358 result = ToString<CanGC>(cx, value0);
3359 if (!result) {
3360 goto error;
3363 PUSH(StackVal(StringValue(result)));
3366 END_OP(ToString);
3369 CASE(IsNullOrUndefined) {
3370 bool result = sp[0].asValue().isNull() || sp[0].asValue().isUndefined();
3371 PUSH(StackVal(BooleanValue(result)));
3372 END_OP(IsNullOrUndefined);
3375 CASE(GlobalThis) {
3376 PUSH(StackVal(ObjectValue(*frameMgr.cxForLocalUseOnly()
3377 ->global()
3378 ->lexicalEnvironment()
3379 .thisObject())));
3380 END_OP(GlobalThis);
3383 CASE(NonSyntacticGlobalThis) {
3385 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
3386 ReservedRooted<Value> value0(&state.value0);
3388 PUSH_EXIT_FRAME();
3389 js::GetNonSyntacticGlobalThis(cx, obj0, &value0);
3391 PUSH(StackVal(value0));
3393 END_OP(NonSyntacticGlobalThis);
3396 CASE(NewTarget) {
3397 PUSH(StackVal(frame->newTarget()));
3398 END_OP(NewTarget);
3401 CASE(DynamicImport) {
3403 ReservedRooted<Value> value0(&state.value0,
3404 POP().asValue()); // options
3405 ReservedRooted<Value> value1(&state.value1,
3406 POP().asValue()); // specifier
3407 JSObject* promise;
3409 PUSH_EXIT_FRAME();
3410 promise = StartDynamicModuleImport(cx, script, value1, value0);
3411 if (!promise) {
3412 goto error;
3415 PUSH(StackVal(ObjectValue(*promise)));
3417 END_OP(DynamicImport);
3420 CASE(ImportMeta) {
3421 JSObject* metaObject;
3423 PUSH_EXIT_FRAME();
3424 metaObject = ImportMetaOperation(cx, script);
3425 if (!metaObject) {
3426 goto error;
3429 PUSH(StackVal(ObjectValue(*metaObject)));
3430 END_OP(ImportMeta);
3433 CASE(NewInit) {
3434 if (kHybridICs) {
3435 JSObject* obj;
3437 PUSH_EXIT_FRAME();
3438 obj = NewObjectOperation(cx, script, pc);
3439 if (!obj) {
3440 goto error;
3443 PUSH(StackVal(ObjectValue(*obj)));
3444 NEXT_IC();
3445 END_OP(NewInit);
3446 } else {
3447 INVOKE_IC(NewObject);
3448 IC_PUSH_RESULT();
3449 END_OP(NewInit);
3452 CASE(NewObject) {
3453 if (kHybridICs) {
3454 JSObject* obj;
3456 PUSH_EXIT_FRAME();
3457 obj = NewObjectOperation(cx, script, pc);
3458 if (!obj) {
3459 goto error;
3462 PUSH(StackVal(ObjectValue(*obj)));
3463 NEXT_IC();
3464 END_OP(NewObject);
3465 } else {
3466 INVOKE_IC(NewObject);
3467 IC_PUSH_RESULT();
3468 END_OP(NewObject);
3471 CASE(Object) {
3472 PUSH(StackVal(ObjectValue(*script->getObject(pc))));
3473 END_OP(Object);
3475 CASE(ObjWithProto) {
3477 ReservedRooted<Value> value0(&state.value0, sp[0].asValue());
3478 JSObject* obj;
3480 PUSH_EXIT_FRAME();
3481 obj = ObjectWithProtoOperation(cx, value0);
3482 if (!obj) {
3483 goto error;
3486 sp[0] = StackVal(ObjectValue(*obj));
3488 END_OP(ObjWithProto);
3491 CASE(InitElem)
3492 CASE(InitHiddenElem)
3493 CASE(InitLockedElem)
3494 CASE(InitElemInc)
3495 CASE(SetElem)
3496 CASE(StrictSetElem) {
3497 static_assert(JSOpLength_InitElem == JSOpLength_InitHiddenElem);
3498 static_assert(JSOpLength_InitElem == JSOpLength_InitLockedElem);
3499 static_assert(JSOpLength_InitElem == JSOpLength_InitElemInc);
3500 static_assert(JSOpLength_InitElem == JSOpLength_SetElem);
3501 static_assert(JSOpLength_InitElem == JSOpLength_StrictSetElem);
3502 StackVal val = sp[0];
3503 IC_POP_ARG(2);
3504 IC_POP_ARG(1);
3505 IC_SET_ARG_FROM_STACK(0, 0);
3506 if (JSOp(*pc) == JSOp::SetElem || JSOp(*pc) == JSOp::StrictSetElem) {
3507 sp[0] = val;
3509 INVOKE_IC(SetElem);
3510 if (JSOp(*pc) == JSOp::InitElemInc) {
3511 PUSH(StackVal(
3512 Int32Value(Value::fromRawBits(icregs.icVals[1]).toInt32() + 1)));
3514 END_OP(InitElem);
3517 CASE(InitPropGetter)
3518 CASE(InitHiddenPropGetter)
3519 CASE(InitPropSetter)
3520 CASE(InitHiddenPropSetter) {
3521 static_assert(JSOpLength_InitPropGetter ==
3522 JSOpLength_InitHiddenPropGetter);
3523 static_assert(JSOpLength_InitPropGetter == JSOpLength_InitPropSetter);
3524 static_assert(JSOpLength_InitPropGetter ==
3525 JSOpLength_InitHiddenPropSetter);
3527 ReservedRooted<JSObject*> obj1(&state.obj1,
3528 &POP().asValue().toObject()); // val
3529 ReservedRooted<JSObject*> obj0(
3530 &state.obj0, &sp[0].asValue().toObject()); // obj; leave on stack
3531 ReservedRooted<PropertyName*> name0(&state.name0, script->getName(pc));
3533 PUSH_EXIT_FRAME();
3534 if (!InitPropGetterSetterOperation(cx, pc, obj0, name0, obj1)) {
3535 goto error;
3539 END_OP(InitPropGetter);
3542 CASE(InitElemGetter)
3543 CASE(InitHiddenElemGetter)
3544 CASE(InitElemSetter)
3545 CASE(InitHiddenElemSetter) {
3546 static_assert(JSOpLength_InitElemGetter ==
3547 JSOpLength_InitHiddenElemGetter);
3548 static_assert(JSOpLength_InitElemGetter == JSOpLength_InitElemSetter);
3549 static_assert(JSOpLength_InitElemGetter ==
3550 JSOpLength_InitHiddenElemSetter);
3552 ReservedRooted<JSObject*> obj1(&state.obj1,
3553 &POP().asValue().toObject()); // val
3554 ReservedRooted<Value> value0(&state.value0, POP().asValue()); // idval
3555 ReservedRooted<JSObject*> obj0(
3556 &state.obj0, &sp[0].asValue().toObject()); // obj; leave on stack
3558 PUSH_EXIT_FRAME();
3559 if (!InitElemGetterSetterOperation(cx, pc, obj0, value0, obj1)) {
3560 goto error;
3564 END_OP(InitElemGetter);
3567 CASE(GetProp)
3568 CASE(GetBoundName) {
3569 static_assert(JSOpLength_GetProp == JSOpLength_GetBoundName);
3570 IC_POP_ARG(0);
3571 INVOKE_IC(GetProp);
3572 IC_PUSH_RESULT();
3573 END_OP(GetProp);
3575 CASE(GetPropSuper) {
3576 IC_POP_ARG(0);
3577 IC_POP_ARG(1);
3578 INVOKE_IC(GetPropSuper);
3579 IC_PUSH_RESULT();
3580 END_OP(GetPropSuper);
3583 CASE(GetElem) {
3584 HandleValue lhs = Stack::handle(&sp[1]);
3585 HandleValue rhs = Stack::handle(&sp[0]);
3586 uint32_t index;
3587 if (IsDefinitelyIndex(rhs, &index)) {
3588 if (lhs.isString()) {
3589 JSString* str = lhs.toString();
3590 if (index < str->length() && str->isLinear()) {
3591 JSLinearString* linear = &str->asLinear();
3592 char16_t c = linear->latin1OrTwoByteChar(index);
3593 StaticStrings& sstr = frameMgr.cxForLocalUseOnly()->staticStrings();
3594 if (sstr.hasUnit(c)) {
3595 sp[1] = StackVal(StringValue(sstr.getUnit(c)));
3596 POP();
3597 NEXT_IC();
3598 END_OP(GetElem);
3602 if (lhs.isObject()) {
3603 JSObject* obj = &lhs.toObject();
3604 Value ret;
3605 if (GetElementNoGC(frameMgr.cxForLocalUseOnly(), obj, lhs, index,
3606 &ret)) {
3607 sp[1] = StackVal(ret);
3608 POP();
3609 NEXT_IC();
3610 END_OP(GetElem);
3615 IC_POP_ARG(1);
3616 IC_POP_ARG(0);
3617 INVOKE_IC(GetElem);
3618 IC_PUSH_RESULT();
3619 END_OP(GetElem);
3622 CASE(GetElemSuper) {
3623 // N.B.: second and third args are out of order! See the saga at
3624 // https://bugzilla.mozilla.org/show_bug.cgi?id=1709328; this is
3625 // an echo of that issue.
3626 IC_POP_ARG(1);
3627 IC_POP_ARG(2);
3628 IC_POP_ARG(0);
3629 INVOKE_IC(GetElemSuper);
3630 IC_PUSH_RESULT();
3631 END_OP(GetElemSuper);
3634 CASE(DelProp) {
3636 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3637 ReservedRooted<PropertyName*> name0(&state.name0, script->getName(pc));
3638 bool res = false;
3640 PUSH_EXIT_FRAME();
3641 if (!DelPropOperation<false>(cx, value0, name0, &res)) {
3642 goto error;
3645 PUSH(StackVal(BooleanValue(res)));
3647 END_OP(DelProp);
3649 CASE(StrictDelProp) {
3651 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3652 ReservedRooted<PropertyName*> name0(&state.name0, script->getName(pc));
3653 bool res = false;
3655 PUSH_EXIT_FRAME();
3656 if (!DelPropOperation<true>(cx, value0, name0, &res)) {
3657 goto error;
3660 PUSH(StackVal(BooleanValue(res)));
3662 END_OP(StrictDelProp);
3664 CASE(DelElem) {
3666 ReservedRooted<Value> value1(&state.value1, POP().asValue());
3667 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3668 bool res = false;
3670 PUSH_EXIT_FRAME();
3671 if (!DelElemOperation<false>(cx, value0, value1, &res)) {
3672 goto error;
3675 PUSH(StackVal(BooleanValue(res)));
3677 END_OP(DelElem);
3679 CASE(StrictDelElem) {
3681 ReservedRooted<Value> value1(&state.value1, POP().asValue());
3682 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3683 bool res = false;
3685 PUSH_EXIT_FRAME();
3686 if (!DelElemOperation<true>(cx, value0, value1, &res)) {
3687 goto error;
3690 PUSH(StackVal(BooleanValue(res)));
3692 END_OP(StrictDelElem);
3695 CASE(HasOwn) {
3696 IC_POP_ARG(1);
3697 IC_POP_ARG(0);
3698 INVOKE_IC(HasOwn);
3699 IC_PUSH_RESULT();
3700 END_OP(HasOwn);
3703 CASE(CheckPrivateField) {
3704 IC_SET_ARG_FROM_STACK(1, 0);
3705 IC_SET_ARG_FROM_STACK(0, 1);
3706 INVOKE_IC(CheckPrivateField);
3707 IC_PUSH_RESULT();
3708 END_OP(CheckPrivateField);
3711 CASE(NewPrivateName) {
3713 ReservedRooted<JSAtom*> atom0(&state.atom0, script->getAtom(pc));
3714 JS::Symbol* symbol;
3716 PUSH_EXIT_FRAME();
3717 symbol = NewPrivateName(cx, atom0);
3718 if (!symbol) {
3719 goto error;
3722 PUSH(StackVal(SymbolValue(symbol)));
3724 END_OP(NewPrivateName);
3727 CASE(SuperBase) {
3728 JSFunction& superEnvFunc = POP().asValue().toObject().as<JSFunction>();
3729 MOZ_ASSERT(superEnvFunc.allowSuperProperty());
3730 MOZ_ASSERT(superEnvFunc.baseScript()->needsHomeObject());
3731 const Value& homeObjVal = superEnvFunc.getExtendedSlot(
3732 FunctionExtended::METHOD_HOMEOBJECT_SLOT);
3734 JSObject* homeObj = &homeObjVal.toObject();
3735 JSObject* superBase = HomeObjectSuperBase(homeObj);
3737 PUSH(StackVal(ObjectOrNullValue(superBase)));
3738 END_OP(SuperBase);
3741 CASE(SetPropSuper)
3742 CASE(StrictSetPropSuper) {
3743 // stack signature: receiver, lval, rval => rval
3744 static_assert(JSOpLength_SetPropSuper == JSOpLength_StrictSetPropSuper);
3745 bool strict = JSOp(*pc) == JSOp::StrictSetPropSuper;
3747 ReservedRooted<Value> value2(&state.value2, POP().asValue()); // rval
3748 ReservedRooted<Value> value1(&state.value1, POP().asValue()); // lval
3749 ReservedRooted<Value> value0(&state.value0,
3750 POP().asValue()); // recevier
3751 ReservedRooted<PropertyName*> name0(&state.name0, script->getName(pc));
3753 PUSH_EXIT_FRAME();
3754 // SetPropertySuper(cx, lval, receiver, name, rval, strict)
3755 // (N.B.: lval and receiver are transposed!)
3756 if (!SetPropertySuper(cx, value1, value0, name0, value2, strict)) {
3757 goto error;
3760 PUSH(StackVal(value2));
3762 END_OP(SetPropSuper);
3765 CASE(SetElemSuper)
3766 CASE(StrictSetElemSuper) {
3767 // stack signature: receiver, key, lval, rval => rval
3768 static_assert(JSOpLength_SetElemSuper == JSOpLength_StrictSetElemSuper);
3769 bool strict = JSOp(*pc) == JSOp::StrictSetElemSuper;
3771 ReservedRooted<Value> value3(&state.value3, POP().asValue()); // rval
3772 ReservedRooted<Value> value2(&state.value2, POP().asValue()); // lval
3773 ReservedRooted<Value> value1(&state.value1, POP().asValue()); // index
3774 ReservedRooted<Value> value0(&state.value0,
3775 POP().asValue()); // receiver
3777 PUSH_EXIT_FRAME();
3778 // SetElementSuper(cx, lval, receiver, index, rval, strict)
3779 // (N.B.: lval, receiver and index are rotated!)
3780 if (!SetElementSuper(cx, value2, value0, value1, value3, strict)) {
3781 goto error;
3784 PUSH(StackVal(value3)); // value
3786 END_OP(SetElemSuper);
3789 CASE(Iter) {
3790 IC_POP_ARG(0);
3791 INVOKE_IC(GetIterator);
3792 IC_PUSH_RESULT();
3793 END_OP(Iter);
3796 CASE(MoreIter) {
3797 // iter => iter, name
3798 Value v = IteratorMore(&sp[0].asValue().toObject());
3799 PUSH(StackVal(v));
3800 END_OP(MoreIter);
3803 CASE(IsNoIter) {
3804 // iter => iter, bool
3805 bool result = sp[0].asValue().isMagic(JS_NO_ITER_VALUE);
3806 PUSH(StackVal(BooleanValue(result)));
3807 END_OP(IsNoIter);
3810 CASE(EndIter) {
3811 // iter, interval =>
3812 POP();
3813 CloseIterator(&POP().asValue().toObject());
3814 END_OP(EndIter);
3817 CASE(CloseIter) {
3818 IC_SET_OBJ_ARG(0, &POP().asValue().toObject());
3819 INVOKE_IC(CloseIter);
3820 END_OP(CloseIter);
3823 CASE(CheckIsObj) {
3824 if (!sp[0].asValue().isObject()) {
3825 PUSH_EXIT_FRAME();
3826 MOZ_ALWAYS_FALSE(
3827 js::ThrowCheckIsObject(cx, js::CheckIsObjectKind(GET_UINT8(pc))));
3828 /* abandon frame; error handler will re-establish sp */
3829 goto error;
3831 END_OP(CheckIsObj);
3834 CASE(CheckObjCoercible) {
3836 ReservedRooted<Value> value0(&state.value0, sp[0].asValue());
3837 if (value0.isNullOrUndefined()) {
3838 PUSH_EXIT_FRAME();
3839 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, value0));
3840 /* abandon frame; error handler will re-establish sp */
3841 goto error;
3844 END_OP(CheckObjCoercible);
3847 CASE(ToAsyncIter) {
3848 // iter, next => asynciter
3850 ReservedRooted<Value> value0(&state.value0, POP().asValue()); // next
3851 ReservedRooted<JSObject*> obj0(&state.obj0,
3852 &POP().asValue().toObject()); // iter
3853 JSObject* result;
3855 PUSH_EXIT_FRAME();
3856 result = CreateAsyncFromSyncIterator(cx, obj0, value0);
3857 if (!result) {
3858 goto error;
3861 PUSH(StackVal(ObjectValue(*result)));
3863 END_OP(ToAsyncIter);
3866 CASE(MutateProto) {
3867 // obj, protoVal => obj
3869 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3870 ReservedRooted<JSObject*> obj0(&state.obj0,
3871 &sp[0].asValue().toObject());
3873 PUSH_EXIT_FRAME();
3874 if (!MutatePrototype(cx, obj0.as<PlainObject>(), value0)) {
3875 goto error;
3879 END_OP(MutateProto);
3882 CASE(NewArray) {
3883 if (kHybridICs) {
3884 ArrayObject* obj;
3886 PUSH_EXIT_FRAME();
3887 uint32_t length = GET_UINT32(pc);
3888 obj = NewArrayOperation(cx, length);
3889 if (!obj) {
3890 goto error;
3893 PUSH(StackVal(ObjectValue(*obj)));
3894 NEXT_IC();
3895 END_OP(NewArray);
3896 } else {
3897 INVOKE_IC(NewArray);
3898 IC_PUSH_RESULT();
3899 END_OP(NewArray);
3903 CASE(InitElemArray) {
3904 // array, val => array
3906 ReservedRooted<Value> value0(&state.value0, POP().asValue());
3907 ReservedRooted<JSObject*> obj0(&state.obj0,
3908 &sp[0].asValue().toObject());
3910 PUSH_EXIT_FRAME();
3911 InitElemArrayOperation(cx, pc, obj0.as<ArrayObject>(), value0);
3914 END_OP(InitElemArray);
3917 CASE(Hole) {
3918 PUSH(StackVal(MagicValue(JS_ELEMENTS_HOLE)));
3919 END_OP(Hole);
3922 CASE(RegExp) {
3923 JSObject* obj;
3925 PUSH_EXIT_FRAME();
3926 ReservedRooted<JSObject*> obj0(&state.obj0, script->getRegExp(pc));
3927 obj = CloneRegExpObject(cx, obj0.as<RegExpObject>());
3928 if (!obj) {
3929 goto error;
3932 PUSH(StackVal(ObjectValue(*obj)));
3933 END_OP(RegExp);
3936 CASE(Lambda) {
3938 ReservedRooted<JSFunction*> fun0(&state.fun0, script->getFunction(pc));
3939 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
3940 JSObject* res;
3942 PUSH_EXIT_FRAME();
3943 res = js::Lambda(cx, fun0, obj0);
3944 if (!res) {
3945 goto error;
3948 PUSH(StackVal(ObjectValue(*res)));
3950 END_OP(Lambda);
3953 CASE(SetFunName) {
3954 // fun, name => fun
3956 ReservedRooted<Value> value0(&state.value0, POP().asValue()); // name
3957 ReservedRooted<JSFunction*> fun0(
3958 &state.fun0, &sp[0].asValue().toObject().as<JSFunction>());
3959 FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(pc));
3961 PUSH_EXIT_FRAME();
3962 if (!SetFunctionName(cx, fun0, value0, prefixKind)) {
3963 goto error;
3967 END_OP(SetFunName);
3970 CASE(InitHomeObject) {
3971 // fun, homeObject => fun
3973 ReservedRooted<JSObject*> obj0(
3974 &state.obj0, &POP().asValue().toObject()); // homeObject
3975 ReservedRooted<JSFunction*> fun0(
3976 &state.fun0, &sp[0].asValue().toObject().as<JSFunction>());
3977 MOZ_ASSERT(fun0->allowSuperProperty());
3978 MOZ_ASSERT(obj0->is<PlainObject>() || obj0->is<JSFunction>());
3979 fun0->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT,
3980 ObjectValue(*obj0));
3982 END_OP(InitHomeObject);
3985 CASE(CheckClassHeritage) {
3987 ReservedRooted<Value> value0(&state.value0, sp[0].asValue());
3989 PUSH_EXIT_FRAME();
3990 if (!CheckClassHeritageOperation(cx, value0)) {
3991 goto error;
3995 END_OP(CheckClassHeritage);
3998 CASE(FunWithProto) {
3999 // proto => obj
4001 ReservedRooted<JSObject*> obj0(&state.obj0,
4002 &POP().asValue().toObject()); // proto
4003 ReservedRooted<JSObject*> obj1(&state.obj1, frame->environmentChain());
4004 ReservedRooted<JSFunction*> fun0(&state.fun0, script->getFunction(pc));
4005 JSObject* obj;
4007 PUSH_EXIT_FRAME();
4008 obj = FunWithProtoOperation(cx, fun0, obj1, obj0);
4009 if (!obj) {
4010 goto error;
4013 PUSH(StackVal(ObjectValue(*obj)));
4015 END_OP(FunWithProto);
4018 CASE(BuiltinObject) {
4019 auto kind = BuiltinObjectKind(GET_UINT8(pc));
4020 JSObject* builtin;
4022 PUSH_EXIT_FRAME();
4023 builtin = BuiltinObjectOperation(cx, kind);
4024 if (!builtin) {
4025 goto error;
4028 PUSH(StackVal(ObjectValue(*builtin)));
4029 END_OP(BuiltinObject);
4032 CASE(Call)
4033 CASE(CallIgnoresRv)
4034 CASE(CallContent)
4035 CASE(CallIter)
4036 CASE(CallContentIter)
4037 CASE(Eval)
4038 CASE(StrictEval)
4039 CASE(SuperCall)
4040 CASE(New)
4041 CASE(NewContent) {
4042 static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv);
4043 static_assert(JSOpLength_Call == JSOpLength_CallContent);
4044 static_assert(JSOpLength_Call == JSOpLength_CallIter);
4045 static_assert(JSOpLength_Call == JSOpLength_CallContentIter);
4046 static_assert(JSOpLength_Call == JSOpLength_Eval);
4047 static_assert(JSOpLength_Call == JSOpLength_StrictEval);
4048 static_assert(JSOpLength_Call == JSOpLength_SuperCall);
4049 static_assert(JSOpLength_Call == JSOpLength_New);
4050 static_assert(JSOpLength_Call == JSOpLength_NewContent);
4051 JSOp op = JSOp(*pc);
4052 bool constructing =
4053 (op == JSOp::New || op == JSOp::NewContent || op == JSOp::SuperCall);
4054 uint32_t argc = GET_ARGC(pc);
4055 do {
4057 // CallArgsFromSp would be called with
4058 // - numValues = argc + 2 + constructing
4059 // - stackSlots = argc + constructing
4060 // - sp = vp + numValues
4061 // CallArgs::create then gets
4062 // - argc_ = stackSlots - constructing = argc
4063 // - argv_ = sp - stackSlots = vp + 2
4064 // our arguments are in reverse order compared to what CallArgs
4065 // expects so we should subtract any array subscripts from (sp +
4066 // stackSlots - 1)
4067 StackVal* firstArg = sp + argc + constructing - 1;
4069 // callee is argv_[-2] -> sp + argc + constructing + 1
4070 // this is argv_[-1] -> sp + argc + constructing
4071 // newTarget is argv_[argc_] -> sp + constructing - 1
4072 // but this/newTarget are only used when constructing is 1 so we can
4073 // simplify this is argv_[-1] -> sp + argc + 1 newTarget is
4074 // argv_[argc_] -> sp
4076 HandleValue callee = Stack::handle(firstArg + 2);
4077 if (!callee.isObject() || !callee.toObject().is<JSFunction>()) {
4078 TRACE_PRINTF("missed fastpath: not a function\n");
4079 break;
4081 ReservedRooted<JSFunction*> func(&state.fun0,
4082 &callee.toObject().as<JSFunction>());
4083 if (!func->hasBaseScript() || !func->isInterpreted()) {
4084 TRACE_PRINTF("missed fastpath: not an interpreted script\n");
4085 break;
4087 if (!constructing && func->isClassConstructor()) {
4088 TRACE_PRINTF("missed fastpath: constructor called without `new`\n");
4089 break;
4091 if (!func->baseScript()->hasBytecode()) {
4092 TRACE_PRINTF("missed fastpath: no bytecode\n");
4093 break;
4095 ReservedRooted<JSScript*> calleeScript(
4096 &state.script0, func->baseScript()->asJSScript());
4097 if (!calleeScript->hasJitScript()) {
4098 TRACE_PRINTF("missed fastpath: no jit-script\n");
4099 break;
4101 if (frameMgr.cxForLocalUseOnly()->realm() != calleeScript->realm()) {
4102 TRACE_PRINTF("missed fastpath: mismatched realm\n");
4103 break;
4105 if (argc < func->nargs()) {
4106 TRACE_PRINTF("missed fastpath: not enough arguments\n");
4107 break;
4110 // Fast-path: function, interpreted, has JitScript, same realm, no
4111 // argument underflow.
4113 // Include newTarget in the args if it exists; exclude callee
4114 uint32_t totalArgs = argc + 1 + constructing;
4115 StackVal* origArgs = sp;
4117 TRACE_PRINTF(
4118 "Call fastpath: argc = %d origArgs = %p callee = %" PRIx64 "\n",
4119 argc, origArgs, callee.get().asRawBits());
4121 if (!stack.check(sp, sizeof(StackVal) * (totalArgs + 3))) {
4122 TRACE_PRINTF("missed fastpath: would cause stack overrun\n");
4123 break;
4126 if (constructing) {
4127 MutableHandleValue thisv = Stack::handleMut(firstArg + 1);
4128 if (!thisv.isObject()) {
4129 HandleValue newTarget = Stack::handle(firstArg - argc);
4130 ReservedRooted<JSObject*> obj0(&state.obj0,
4131 &newTarget.toObject());
4133 PUSH_EXIT_FRAME();
4134 // CreateThis might discard the JitScript but we're counting on it
4135 // continuing to exist while we evaluate the fastpath.
4136 AutoKeepJitScripts keepJitScript(cx);
4137 if (!CreateThis(cx, func, obj0, GenericObject, thisv)) {
4138 goto error;
4141 TRACE_PRINTF("created %" PRIx64 "\n", thisv.get().asRawBits());
4145 // 0. Save current PC in current frame, so we can retrieve
4146 // it later.
4147 frame->interpreterPC() = pc;
4149 // 1. Push a baseline stub frame. Don't use the frame manager
4150 // -- we don't want the frame to be auto-freed when we leave
4151 // this scope, and we don't want to shadow `sp`.
4152 StackVal* exitFP = stack.pushExitFrame(sp, frame);
4153 MOZ_ASSERT(exitFP); // safety: stack margin.
4154 sp = exitFP;
4155 TRACE_PRINTF("exit frame at %p\n", exitFP);
4157 // 2. Modify exit code to nullptr (this is where ICStubReg is
4158 // normally saved; the tracing code can skip if null).
4159 PUSHNATIVE(StackValNative(nullptr));
4161 // 3. Push args in proper order (they are reversed in our
4162 // downward-growth stack compared to what the calling
4163 // convention expects).
4164 for (uint32_t i = 0; i < totalArgs; i++) {
4165 PUSH(origArgs[i]);
4168 // 4. Push inter-frame content: callee token, descriptor for
4169 // above.
4170 PUSHNATIVE(StackValNative(CalleeToToken(func, constructing)));
4171 PUSHNATIVE(StackValNative(
4172 MakeFrameDescriptorForJitCall(FrameType::BaselineStub, argc)));
4174 // 5. Push fake return address, set script, push baseline frame.
4175 PUSHNATIVE(StackValNative(nullptr));
4176 script.set(calleeScript);
4177 BaselineFrame* newFrame =
4178 stack.pushFrame(sp, frameMgr.cxForLocalUseOnly(),
4179 /* envChain = */ func->environment());
4180 MOZ_ASSERT(newFrame); // safety: stack margin.
4181 TRACE_PRINTF("callee frame at %p\n", newFrame);
4182 frame = newFrame;
4183 frameMgr.switchToFrame(frame);
4184 // 6. Set up PC and SP for callee.
4185 sp = reinterpret_cast<StackVal*>(frame);
4186 pc = calleeScript->code();
4187 // 7. Check callee stack space for max stack depth.
4188 if (!stack.check(sp, sizeof(StackVal) * calleeScript->nslots())) {
4189 PUSH_EXIT_FRAME();
4190 ReportOverRecursed(frameMgr.cxForLocalUseOnly());
4191 goto error;
4193 // 8. Push local slots, and set return value to `undefined` by
4194 // default.
4195 uint32_t nfixed = calleeScript->nfixed();
4196 for (uint32_t i = 0; i < nfixed; i++) {
4197 PUSH(StackVal(UndefinedValue()));
4199 ret->setUndefined();
4200 // 9. Initialize environment objects.
4201 if (func->needsFunctionEnvironmentObjects()) {
4202 PUSH_EXIT_FRAME();
4203 if (!js::InitFunctionEnvironmentObjects(cx, frame)) {
4204 goto error;
4207 // 10. Set debug flag, if appropriate.
4208 if (script->isDebuggee()) {
4209 TRACE_PRINTF("Script is debuggee\n");
4210 frame->setIsDebuggee();
4212 PUSH_EXIT_FRAME();
4213 if (!DebugPrologue(cx, frame)) {
4214 goto error;
4217 // 11. Check for interrupts.
4218 #ifndef __wasi__
4219 if (frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
4220 PUSH_EXIT_FRAME();
4221 if (!InterruptCheck(cx)) {
4222 goto error;
4225 #endif
4226 // 12. Initialize coverage tables, if needed.
4227 if (!script->hasScriptCounts()) {
4228 if (frameMgr.cxForLocalUseOnly()
4229 ->realm()
4230 ->collectCoverageForDebug()) {
4231 PUSH_EXIT_FRAME();
4232 if (!script->initScriptCounts(cx)) {
4233 goto error;
4237 COUNT_COVERAGE_MAIN();
4240 // Everything is switched to callee context now -- dispatch!
4241 DISPATCH();
4242 } while (0);
4244 // Slow path: use the IC!
4245 icregs.icVals[0] = argc;
4246 icregs.extraArgs = 2 + constructing;
4247 icregs.spreadCall = false;
4248 INVOKE_IC(Call);
4249 POPN(argc + 2 + constructing);
4250 PUSH(StackVal(Value::fromRawBits(icregs.icResult)));
4251 END_OP(Call);
4254 CASE(SpreadCall)
4255 CASE(SpreadEval)
4256 CASE(StrictSpreadEval) {
4257 static_assert(JSOpLength_SpreadCall == JSOpLength_SpreadEval);
4258 static_assert(JSOpLength_SpreadCall == JSOpLength_StrictSpreadEval);
4259 icregs.icVals[0] = 1;
4260 icregs.extraArgs = 2;
4261 icregs.spreadCall = true;
4262 INVOKE_IC(Call);
4263 POPN(3);
4264 PUSH(StackVal(Value::fromRawBits(icregs.icResult)));
4265 END_OP(SpreadCall);
4268 CASE(SpreadSuperCall)
4269 CASE(SpreadNew) {
4270 static_assert(JSOpLength_SpreadSuperCall == JSOpLength_SpreadNew);
4271 icregs.icVals[0] = 1;
4272 icregs.extraArgs = 3;
4273 icregs.spreadCall = true;
4274 INVOKE_IC(Call);
4275 POPN(4);
4276 PUSH(StackVal(Value::fromRawBits(icregs.icResult)));
4277 END_OP(SpreadSuperCall);
4280 CASE(OptimizeSpreadCall) {
4281 IC_POP_ARG(0);
4282 INVOKE_IC(OptimizeSpreadCall);
4283 IC_PUSH_RESULT();
4284 END_OP(OptimizeSpreadCall);
4287 CASE(OptimizeGetIterator) {
4288 IC_POP_ARG(0);
4289 INVOKE_IC(OptimizeGetIterator);
4290 IC_PUSH_RESULT();
4291 END_OP(OptimizeGetIterator);
4294 CASE(ImplicitThis) {
4296 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
4297 ReservedRooted<PropertyName*> name0(&state.name0, script->getName(pc));
4298 PUSH_EXIT_FRAME();
4299 if (!ImplicitThisOperation(cx, obj0, name0, &state.res)) {
4300 goto error;
4303 PUSH(StackVal(state.res));
4304 state.res.setUndefined();
4305 END_OP(ImplicitThis);
4308 CASE(CallSiteObj) {
4309 JSObject* cso = script->getObject(pc);
4310 MOZ_ASSERT(!cso->as<ArrayObject>().isExtensible());
4311 MOZ_ASSERT(cso->as<ArrayObject>().containsPure(
4312 frameMgr.cxForLocalUseOnly()->names().raw));
4313 PUSH(StackVal(ObjectValue(*cso)));
4314 END_OP(CallSiteObj);
4317 CASE(IsConstructing) {
4318 PUSH(StackVal(MagicValue(JS_IS_CONSTRUCTING)));
4319 END_OP(IsConstructing);
4322 CASE(SuperFun) {
4323 JSObject* superEnvFunc = &POP().asValue().toObject();
4324 JSObject* superFun = SuperFunOperation(superEnvFunc);
4325 PUSH(StackVal(ObjectOrNullValue(superFun)));
4326 END_OP(SuperFun);
4329 CASE(CheckThis) {
4330 if (sp[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) {
4331 PUSH_EXIT_FRAME();
4332 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
4333 goto error;
4335 END_OP(CheckThis);
4338 CASE(CheckThisReinit) {
4339 if (!sp[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) {
4340 PUSH_EXIT_FRAME();
4341 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx));
4342 goto error;
4344 END_OP(CheckThisReinit);
4347 CASE(Generator) {
4348 JSObject* generator;
4350 PUSH_EXIT_FRAME();
4351 generator = CreateGeneratorFromFrame(cx, frame);
4352 if (!generator) {
4353 goto error;
4356 PUSH(StackVal(ObjectValue(*generator)));
4357 END_OP(Generator);
4360 CASE(InitialYield) {
4361 // gen => rval, gen, resumeKind
4362 ReservedRooted<JSObject*> obj0(&state.obj0, &sp[0].asValue().toObject());
4363 uint32_t frameSize = stack.frameSize(sp, frame);
4365 PUSH_EXIT_FRAME();
4366 if (!NormalSuspend(cx, obj0, frame, frameSize, pc)) {
4367 goto error;
4370 frame->setReturnValue(sp[0].asValue());
4371 goto do_return;
4374 CASE(Await)
4375 CASE(Yield) {
4376 // rval1, gen => rval2, gen, resumeKind
4377 ReservedRooted<JSObject*> obj0(&state.obj0, &POP().asValue().toObject());
4378 uint32_t frameSize = stack.frameSize(sp, frame);
4380 PUSH_EXIT_FRAME();
4381 if (!NormalSuspend(cx, obj0, frame, frameSize, pc)) {
4382 goto error;
4385 frame->setReturnValue(sp[0].asValue());
4386 goto do_return;
4389 CASE(FinalYieldRval) {
4390 // gen =>
4391 ReservedRooted<JSObject*> obj0(&state.obj0, &POP().asValue().toObject());
4393 PUSH_EXIT_FRAME();
4394 if (!FinalSuspend(cx, obj0, pc)) {
4395 goto error;
4398 goto do_return;
4401 CASE(IsGenClosing) {
4402 bool result = sp[0].asValue() == MagicValue(JS_GENERATOR_CLOSING);
4403 PUSH(StackVal(BooleanValue(result)));
4404 END_OP(IsGenClosing);
4407 CASE(AsyncAwait) {
4408 // value, gen => promise
4409 JSObject* promise;
4411 ReservedRooted<JSObject*> obj0(&state.obj0,
4412 &POP().asValue().toObject()); // gen
4413 ReservedRooted<Value> value0(&state.value0, POP().asValue()); // value
4414 PUSH_EXIT_FRAME();
4415 promise = AsyncFunctionAwait(
4416 cx, obj0.as<AsyncFunctionGeneratorObject>(), value0);
4417 if (!promise) {
4418 goto error;
4421 PUSH(StackVal(ObjectValue(*promise)));
4422 END_OP(AsyncAwait);
4425 CASE(AsyncResolve) {
4426 // value, gen => promise
4427 JSObject* promise;
4429 ReservedRooted<JSObject*> obj0(&state.obj0,
4430 &POP().asValue().toObject()); // gen
4431 ReservedRooted<Value> value0(&state.value0,
4432 POP().asValue()); // value
4433 PUSH_EXIT_FRAME();
4434 promise = AsyncFunctionResolve(
4435 cx, obj0.as<AsyncFunctionGeneratorObject>(), value0);
4436 if (!promise) {
4437 goto error;
4440 PUSH(StackVal(ObjectValue(*promise)));
4441 END_OP(AsyncResolve);
4444 CASE(AsyncReject) {
4445 // reason, gen => promise
4446 JSObject* promise;
4448 ReservedRooted<JSObject*> obj0(&state.obj0,
4449 &POP().asValue().toObject()); // gen
4450 ReservedRooted<Value> value0(&state.value0,
4451 POP().asValue()); // stack
4452 ReservedRooted<Value> value1(&state.value1,
4453 POP().asValue()); // reason
4454 PUSH_EXIT_FRAME();
4455 promise = AsyncFunctionReject(
4456 cx, obj0.as<AsyncFunctionGeneratorObject>(), value1, value0);
4457 if (!promise) {
4458 goto error;
4461 PUSH(StackVal(ObjectValue(*promise)));
4462 END_OP(AsyncReject);
4465 CASE(CanSkipAwait) {
4466 // value => value, can_skip
4467 bool result = false;
4469 ReservedRooted<Value> value0(&state.value0, sp[0].asValue());
4470 PUSH_EXIT_FRAME();
4471 if (!CanSkipAwait(cx, value0, &result)) {
4472 goto error;
4475 PUSH(StackVal(BooleanValue(result)));
4476 END_OP(CanSkipAwait);
4479 CASE(MaybeExtractAwaitValue) {
4480 // value, can_skip => value_or_resolved, can_skip
4482 Value can_skip = POP().asValue();
4483 ReservedRooted<Value> value0(&state.value0, POP().asValue()); // value
4484 if (can_skip.toBoolean()) {
4485 PUSH_EXIT_FRAME();
4486 if (!ExtractAwaitValue(cx, value0, &value0)) {
4487 goto error;
4490 PUSH(StackVal(value0));
4491 PUSH(StackVal(can_skip));
4493 END_OP(MaybeExtractAwaitValue);
4496 CASE(ResumeKind) {
4497 GeneratorResumeKind resumeKind = ResumeKindFromPC(pc);
4498 PUSH(StackVal(Int32Value(int32_t(resumeKind))));
4499 END_OP(ResumeKind);
4502 CASE(CheckResumeKind) {
4503 // rval, gen, resumeKind => rval
4505 GeneratorResumeKind resumeKind =
4506 IntToResumeKind(POP().asValue().toInt32());
4507 ReservedRooted<JSObject*> obj0(&state.obj0,
4508 &POP().asValue().toObject()); // gen
4509 ReservedRooted<Value> value0(&state.value0, sp[0].asValue()); // rval
4510 if (resumeKind != GeneratorResumeKind::Next) {
4511 PUSH_EXIT_FRAME();
4512 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(
4513 cx, frame, obj0.as<AbstractGeneratorObject>(), value0,
4514 resumeKind));
4515 goto error;
4518 END_OP(CheckResumeKind);
4521 CASE(Resume) {
4522 Value gen = sp[2].asValue();
4523 Value* callerSP = reinterpret_cast<Value*>(sp);
4525 ReservedRooted<Value> value0(&state.value0);
4526 ReservedRooted<JSObject*> obj0(&state.obj0, &gen.toObject());
4528 PUSH_EXIT_FRAME();
4529 TRACE_PRINTF("Going to C++ interp for Resume\n");
4530 if (!InterpretResume(cx, obj0, callerSP, &value0)) {
4531 goto error;
4534 POPN(2);
4535 sp[0] = StackVal(value0);
4537 END_OP(Resume);
4540 CASE(JumpTarget) {
4541 int32_t icIndex = GET_INT32(pc);
4542 frame->interpreterICEntry() = frame->icScript()->icEntries() + icIndex;
4543 COUNT_COVERAGE_PC(pc);
4544 END_OP(JumpTarget);
4546 CASE(LoopHead) {
4547 int32_t icIndex = GET_INT32(pc);
4548 frame->interpreterICEntry() = frame->icScript()->icEntries() + icIndex;
4549 #ifndef __wasi__
4550 if (frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
4551 PUSH_EXIT_FRAME();
4552 if (!InterruptCheck(cx)) {
4553 goto error;
4556 #endif
4557 COUNT_COVERAGE_PC(pc);
4558 END_OP(LoopHead);
4560 CASE(AfterYield) {
4561 int32_t icIndex = GET_INT32(pc);
4562 frame->interpreterICEntry() = frame->icScript()->icEntries() + icIndex;
4563 if (script->isDebuggee()) {
4564 TRACE_PRINTF("doing DebugAfterYield\n");
4565 PUSH_EXIT_FRAME();
4566 if (DebugAPI::hasAnyBreakpointsOrStepMode(script) &&
4567 !HandleDebugTrap(cx, frame, pc)) {
4568 TRACE_PRINTF("HandleDebugTrap returned error\n");
4569 goto error;
4571 if (!DebugAfterYield(cx, frame)) {
4572 TRACE_PRINTF("DebugAfterYield returned error\n");
4573 goto error;
4576 COUNT_COVERAGE_PC(pc);
4577 END_OP(AfterYield);
4580 CASE(Goto) {
4581 ADVANCE(GET_JUMP_OFFSET(pc));
4582 PREDICT_NEXT(JumpTarget);
4583 PREDICT_NEXT(LoopHead);
4584 DISPATCH();
4587 CASE(Coalesce) {
4588 if (!sp[0].asValue().isNullOrUndefined()) {
4589 ADVANCE(GET_JUMP_OFFSET(pc));
4590 DISPATCH();
4591 } else {
4592 END_OP(Coalesce);
4596 CASE(Case) {
4597 bool cond = POP().asValue().toBoolean();
4598 if (cond) {
4599 POP();
4600 ADVANCE(GET_JUMP_OFFSET(pc));
4601 DISPATCH();
4602 } else {
4603 END_OP(Case);
4607 CASE(Default) {
4608 POP();
4609 ADVANCE(GET_JUMP_OFFSET(pc));
4610 DISPATCH();
4613 CASE(TableSwitch) {
4614 int32_t len = GET_JUMP_OFFSET(pc);
4615 int32_t low = GET_JUMP_OFFSET(pc + 1 * JUMP_OFFSET_LEN);
4616 int32_t high = GET_JUMP_OFFSET(pc + 2 * JUMP_OFFSET_LEN);
4617 Value v = POP().asValue();
4618 int32_t i = 0;
4619 if (v.isInt32()) {
4620 i = v.toInt32();
4621 } else if (!v.isDouble() ||
4622 !mozilla::NumberEqualsInt32(v.toDouble(), &i)) {
4623 ADVANCE(len);
4624 DISPATCH();
4627 i = uint32_t(i) - uint32_t(low);
4628 if ((uint32_t(i) < uint32_t(high - low + 1))) {
4629 len = script->tableSwitchCaseOffset(pc, uint32_t(i)) -
4630 script->pcToOffset(pc);
4632 ADVANCE(len);
4633 DISPATCH();
4636 CASE(Return) {
4637 frame->setReturnValue(POP().asValue());
4638 goto do_return;
4641 CASE(GetRval) {
4642 PUSH(StackVal(frame->returnValue()));
4643 END_OP(GetRval);
4646 CASE(SetRval) {
4647 frame->setReturnValue(POP().asValue());
4648 END_OP(SetRval);
4651 do_return:
4652 CASE(RetRval) {
4653 bool ok = true;
4654 if (frame->isDebuggee() && !from_unwind) {
4655 TRACE_PRINTF("doing DebugEpilogueOnBaselineReturn\n");
4656 PUSH_EXIT_FRAME();
4657 ok = DebugEpilogueOnBaselineReturn(cx, frame, pc);
4659 from_unwind = false;
4661 uint32_t argc = frame->numActualArgs();
4662 sp = stack.popFrame();
4664 // If FP is higher than the entry frame now, return; otherwise,
4665 // do an inline state update.
4666 if (stack.fp > entryFrame) {
4667 *ret = frame->returnValue();
4668 TRACE_PRINTF("ret = %" PRIx64 "\n", ret->asRawBits());
4669 return ok ? PBIResult::Ok : PBIResult::Error;
4670 } else {
4671 TRACE_PRINTF("Return fastpath\n");
4672 Value ret = frame->returnValue();
4673 TRACE_PRINTF("ret = %" PRIx64 "\n", ret.asRawBits());
4675 // Pop exit frame as well.
4676 sp = stack.popFrame();
4677 // Pop fake return address and descriptor.
4678 POPNNATIVE(2);
4680 // Set PC, frame, and current script.
4681 frame = reinterpret_cast<BaselineFrame*>(
4682 reinterpret_cast<uintptr_t>(stack.fp) - BaselineFrame::Size());
4683 TRACE_PRINTF(" sp -> %p, fp -> %p, frame -> %p\n", sp, stack.fp, frame);
4684 frameMgr.switchToFrame(frame);
4685 pc = frame->interpreterPC();
4686 script.set(frame->script());
4688 // Adjust caller's stack to complete the call op that PC still points to
4689 // in that frame (pop args, push return value).
4690 JSOp op = JSOp(*pc);
4691 bool constructing = (op == JSOp::New || op == JSOp::NewContent ||
4692 op == JSOp::SuperCall);
4693 // Fix-up return value; EnterJit would do this if we hadn't bypassed it.
4694 if (constructing && ret.isPrimitive()) {
4695 ret = sp[argc + constructing].asValue();
4696 TRACE_PRINTF("updated ret = %" PRIx64 "\n", ret.asRawBits());
4698 // Pop args -- this is 1 more than how many are pushed in the
4699 // `totalArgs` count during the call fastpath because it includes
4700 // the callee.
4701 POPN(argc + 2 + constructing);
4702 // Push return value.
4703 PUSH(StackVal(ret));
4705 if (!ok) {
4706 goto error;
4709 // Advance past call instruction, and advance past IC.
4710 NEXT_IC();
4711 ADVANCE(JSOpLength_Call);
4713 DISPATCH();
4717 CASE(CheckReturn) {
4718 Value thisval = POP().asValue();
4719 // inlined version of frame->checkReturn(thisval, result)
4720 // (js/src/vm/Stack.cpp).
4721 HandleValue retVal = frame->returnValue();
4722 if (retVal.isObject()) {
4723 PUSH(StackVal(retVal));
4724 } else if (!retVal.isUndefined()) {
4725 PUSH_EXIT_FRAME();
4726 MOZ_ALWAYS_FALSE(ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN,
4727 JSDVG_IGNORE_STACK, retVal, nullptr));
4728 goto error;
4729 } else if (thisval.isMagic(JS_UNINITIALIZED_LEXICAL)) {
4730 PUSH_EXIT_FRAME();
4731 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
4732 goto error;
4733 } else {
4734 PUSH(StackVal(thisval));
4736 END_OP(CheckReturn);
4739 CASE(Throw) {
4741 ReservedRooted<Value> value0(&state.value0, POP().asValue());
4742 PUSH_EXIT_FRAME();
4743 MOZ_ALWAYS_FALSE(ThrowOperation(cx, value0));
4744 goto error;
4746 END_OP(Throw);
4749 CASE(ThrowWithStack) {
4751 ReservedRooted<Value> value0(&state.value0, POP().asValue());
4752 ReservedRooted<Value> value1(&state.value1, POP().asValue());
4753 PUSH_EXIT_FRAME();
4754 MOZ_ALWAYS_FALSE(ThrowWithStackOperation(cx, value1, value0));
4755 goto error;
4757 END_OP(ThrowWithStack);
4760 CASE(ThrowMsg) {
4762 PUSH_EXIT_FRAME();
4763 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(pc)));
4764 goto error;
4766 END_OP(ThrowMsg);
4769 CASE(ThrowSetConst) {
4771 PUSH_EXIT_FRAME();
4772 ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script, pc);
4773 goto error;
4775 END_OP(ThrowSetConst);
4778 CASE(Try)
4779 CASE(TryDestructuring) {
4780 static_assert(JSOpLength_Try == JSOpLength_TryDestructuring);
4781 END_OP(Try);
4784 CASE(Exception) {
4786 PUSH_EXIT_FRAME();
4787 if (!GetAndClearException(cx, &state.res)) {
4788 goto error;
4791 PUSH(StackVal(state.res));
4792 state.res.setUndefined();
4793 END_OP(Exception);
4796 CASE(ExceptionAndStack) {
4798 ReservedRooted<Value> value0(&state.value0);
4800 PUSH_EXIT_FRAME();
4801 if (!cx.getCx()->getPendingExceptionStack(&value0)) {
4802 goto error;
4804 if (!GetAndClearException(cx, &state.res)) {
4805 goto error;
4808 PUSH(StackVal(state.res));
4809 PUSH(StackVal(value0));
4810 state.res.setUndefined();
4812 END_OP(ExceptionAndStack);
4815 CASE(Finally) {
4816 #ifndef __wasi__
4817 if (frameMgr.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
4818 PUSH_EXIT_FRAME();
4819 if (!InterruptCheck(cx)) {
4820 goto error;
4823 #endif
4824 END_OP(Finally);
4827 CASE(Uninitialized) {
4828 PUSH(StackVal(MagicValue(JS_UNINITIALIZED_LEXICAL)));
4829 END_OP(Uninitialized);
4831 CASE(InitLexical) {
4832 uint32_t i = GET_LOCALNO(pc);
4833 frame->unaliasedLocal(i) = sp[0].asValue();
4834 END_OP(InitLexical);
4837 CASE(InitAliasedLexical) {
4838 EnvironmentCoordinate ec = EnvironmentCoordinate(pc);
4839 EnvironmentObject& obj = getEnvironmentFromCoordinate(frame, ec);
4840 obj.setAliasedBinding(ec, sp[0].asValue());
4841 END_OP(InitAliasedLexical);
4843 CASE(CheckLexical) {
4844 if (sp[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) {
4845 PUSH_EXIT_FRAME();
4846 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script, pc);
4847 goto error;
4849 END_OP(CheckLexical);
4851 CASE(CheckAliasedLexical) {
4852 if (sp[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL)) {
4853 PUSH_EXIT_FRAME();
4854 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script, pc);
4855 goto error;
4857 END_OP(CheckAliasedLexical);
4860 CASE(BindGName) {
4861 IC_SET_OBJ_ARG(
4862 0, &frameMgr.cxForLocalUseOnly()->global()->lexicalEnvironment());
4863 INVOKE_IC(BindName);
4864 IC_PUSH_RESULT();
4865 END_OP(BindGName);
4867 CASE(BindName) {
4868 IC_SET_OBJ_ARG(0, frame->environmentChain());
4869 INVOKE_IC(BindName);
4870 IC_PUSH_RESULT();
4871 END_OP(BindName);
4873 CASE(GetGName) {
4874 IC_SET_OBJ_ARG(
4875 0, &frameMgr.cxForLocalUseOnly()->global()->lexicalEnvironment());
4876 INVOKE_IC(GetName);
4877 IC_PUSH_RESULT();
4878 END_OP(GetGName);
4880 CASE(GetName) {
4881 IC_SET_OBJ_ARG(0, frame->environmentChain());
4882 INVOKE_IC(GetName);
4883 IC_PUSH_RESULT();
4884 END_OP(GetName);
4887 CASE(GetArg) {
4888 unsigned i = GET_ARGNO(pc);
4889 if (script->argsObjAliasesFormals()) {
4890 PUSH(StackVal(frame->argsObj().arg(i)));
4891 } else {
4892 PUSH(StackVal(frame->unaliasedFormal(i)));
4894 END_OP(GetArg);
4897 CASE(GetFrameArg) {
4898 uint32_t i = GET_ARGNO(pc);
4899 PUSH(StackVal(frame->unaliasedFormal(i, DONT_CHECK_ALIASING)));
4900 END_OP(GetFrameArg);
4903 CASE(GetLocal) {
4904 uint32_t i = GET_LOCALNO(pc);
4905 TRACE_PRINTF(" -> local: %d\n", int(i));
4906 PUSH(StackVal(frame->unaliasedLocal(i)));
4907 END_OP(GetLocal);
4910 CASE(ArgumentsLength) {
4911 PUSH(StackVal(Int32Value(frame->numActualArgs())));
4912 END_OP(ArgumentsLength);
4915 CASE(GetActualArg) {
4916 MOZ_ASSERT(!script->needsArgsObj());
4917 uint32_t index = sp[0].asValue().toInt32();
4918 sp[0] = StackVal(frame->unaliasedActual(index));
4919 END_OP(GetActualArg);
4922 CASE(GetAliasedVar)
4923 CASE(GetAliasedDebugVar) {
4924 static_assert(JSOpLength_GetAliasedVar == JSOpLength_GetAliasedDebugVar);
4925 EnvironmentCoordinate ec = EnvironmentCoordinate(pc);
4926 EnvironmentObject& obj = getEnvironmentFromCoordinate(frame, ec);
4927 PUSH(StackVal(obj.aliasedBinding(ec)));
4928 END_OP(GetAliasedVar);
4931 CASE(GetImport) {
4933 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
4934 ReservedRooted<Value> value0(&state.value0);
4936 PUSH_EXIT_FRAME();
4937 if (!GetImportOperation(cx, obj0, script, pc, &value0)) {
4938 goto error;
4941 PUSH(StackVal(value0));
4943 END_OP(GetImport);
4946 CASE(GetIntrinsic) {
4947 INVOKE_IC(GetIntrinsic);
4948 IC_PUSH_RESULT();
4949 END_OP(GetIntrinsic);
4952 CASE(Callee) {
4953 PUSH(StackVal(frame->calleev()));
4954 END_OP(Callee);
4957 CASE(EnvCallee) {
4958 uint8_t numHops = GET_UINT8(pc);
4959 JSObject* env = &frame->environmentChain()->as<EnvironmentObject>();
4960 for (unsigned i = 0; i < numHops; i++) {
4961 env = &env->as<EnvironmentObject>().enclosingEnvironment();
4963 PUSH(StackVal(ObjectValue(env->as<CallObject>().callee())));
4964 END_OP(EnvCallee);
4967 CASE(SetProp)
4968 CASE(StrictSetProp)
4969 CASE(SetName)
4970 CASE(StrictSetName)
4971 CASE(SetGName)
4972 CASE(StrictSetGName) {
4973 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp);
4974 static_assert(JSOpLength_SetProp == JSOpLength_SetName);
4975 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetName);
4976 static_assert(JSOpLength_SetProp == JSOpLength_SetGName);
4977 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetGName);
4978 IC_POP_ARG(1);
4979 IC_POP_ARG(0);
4980 PUSH(StackVal(icregs.icVals[1]));
4981 INVOKE_IC(SetProp);
4982 END_OP(SetProp);
4985 CASE(InitProp)
4986 CASE(InitHiddenProp)
4987 CASE(InitLockedProp) {
4988 static_assert(JSOpLength_InitProp == JSOpLength_InitHiddenProp);
4989 static_assert(JSOpLength_InitProp == JSOpLength_InitLockedProp);
4990 IC_POP_ARG(1);
4991 IC_SET_ARG_FROM_STACK(0, 0);
4992 INVOKE_IC(SetProp);
4993 END_OP(InitProp);
4995 CASE(InitGLexical) {
4996 IC_SET_ARG_FROM_STACK(1, 0);
4997 IC_SET_OBJ_ARG(
4998 0, &frameMgr.cxForLocalUseOnly()->global()->lexicalEnvironment());
4999 INVOKE_IC(SetProp);
5000 END_OP(InitGLexical);
5003 CASE(SetArg) {
5004 unsigned i = GET_ARGNO(pc);
5005 if (script->argsObjAliasesFormals()) {
5006 frame->argsObj().setArg(i, sp[0].asValue());
5007 } else {
5008 frame->unaliasedFormal(i) = sp[0].asValue();
5010 END_OP(SetArg);
5013 CASE(SetLocal) {
5014 uint32_t i = GET_LOCALNO(pc);
5015 TRACE_PRINTF(" -> local: %d\n", int(i));
5016 frame->unaliasedLocal(i) = sp[0].asValue();
5017 END_OP(SetLocal);
5020 CASE(SetAliasedVar) {
5021 EnvironmentCoordinate ec = EnvironmentCoordinate(pc);
5022 EnvironmentObject& obj = getEnvironmentFromCoordinate(frame, ec);
5023 MOZ_ASSERT(!IsUninitializedLexical(obj.aliasedBinding(ec)));
5024 obj.setAliasedBinding(ec, sp[0].asValue());
5025 END_OP(SetAliasedVar);
5028 CASE(SetIntrinsic) {
5030 ReservedRooted<Value> value0(&state.value0, sp[0].asValue());
5032 PUSH_EXIT_FRAME();
5033 if (!SetIntrinsicOperation(cx, script, pc, value0)) {
5034 goto error;
5038 END_OP(SetIntrinsic);
5041 CASE(PushLexicalEnv) {
5043 ReservedRooted<Scope*> scope0(&state.scope0, script->getScope(pc));
5045 PUSH_EXIT_FRAME();
5046 if (!frame->pushLexicalEnvironment(cx, scope0.as<LexicalScope>())) {
5047 goto error;
5051 END_OP(PushLexicalEnv);
5053 CASE(PopLexicalEnv) {
5054 if (frame->isDebuggee()) {
5055 TRACE_PRINTF("doing DebugLeaveThenPopLexicalEnv\n");
5056 PUSH_EXIT_FRAME();
5057 if (!DebugLeaveThenPopLexicalEnv(cx, frame, pc)) {
5058 goto error;
5060 } else {
5061 frame->popOffEnvironmentChain<LexicalEnvironmentObject>();
5063 END_OP(PopLexicalEnv);
5065 CASE(DebugLeaveLexicalEnv) {
5066 if (frame->isDebuggee()) {
5067 TRACE_PRINTF("doing DebugLeaveLexicalEnv\n");
5068 PUSH_EXIT_FRAME();
5069 if (!DebugLeaveLexicalEnv(cx, frame, pc)) {
5070 goto error;
5073 END_OP(DebugLeaveLexicalEnv);
5076 CASE(RecreateLexicalEnv) {
5078 PUSH_EXIT_FRAME();
5079 if (frame->isDebuggee()) {
5080 TRACE_PRINTF("doing DebugLeaveThenRecreateLexicalEnv\n");
5081 if (!DebugLeaveThenRecreateLexicalEnv(cx, frame, pc)) {
5082 goto error;
5084 } else {
5085 if (!frame->recreateLexicalEnvironment(cx)) {
5086 goto error;
5090 END_OP(RecreateLexicalEnv);
5093 CASE(FreshenLexicalEnv) {
5095 PUSH_EXIT_FRAME();
5096 if (frame->isDebuggee()) {
5097 TRACE_PRINTF("doing DebugLeaveThenFreshenLexicalEnv\n");
5098 if (!DebugLeaveThenFreshenLexicalEnv(cx, frame, pc)) {
5099 goto error;
5101 } else {
5102 if (!frame->freshenLexicalEnvironment(cx)) {
5103 goto error;
5107 END_OP(FreshenLexicalEnv);
5109 CASE(PushClassBodyEnv) {
5111 ReservedRooted<Scope*> scope0(&state.scope0, script->getScope(pc));
5112 PUSH_EXIT_FRAME();
5113 if (!frame->pushClassBodyEnvironment(cx, scope0.as<ClassBodyScope>())) {
5114 goto error;
5117 END_OP(PushClassBodyEnv);
5119 CASE(PushVarEnv) {
5121 ReservedRooted<Scope*> scope0(&state.scope0, script->getScope(pc));
5122 PUSH_EXIT_FRAME();
5123 if (!frame->pushVarEnvironment(cx, scope0)) {
5124 goto error;
5127 END_OP(PushVarEnv);
5129 CASE(EnterWith) {
5131 ReservedRooted<Scope*> scope0(&state.scope0, script->getScope(pc));
5132 ReservedRooted<Value> value0(&state.value0, POP().asValue());
5133 PUSH_EXIT_FRAME();
5134 if (!EnterWithOperation(cx, frame, value0, scope0.as<WithScope>())) {
5135 goto error;
5138 END_OP(EnterWith);
5140 CASE(LeaveWith) {
5141 frame->popOffEnvironmentChain<WithEnvironmentObject>();
5142 END_OP(LeaveWith);
5144 CASE(BindVar) {
5145 JSObject* varObj;
5147 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
5148 PUSH_EXIT_FRAME();
5149 varObj = BindVarOperation(cx, obj0);
5151 PUSH(StackVal(ObjectValue(*varObj)));
5152 END_OP(BindVar);
5155 CASE(GlobalOrEvalDeclInstantiation) {
5156 GCThingIndex lastFun = GET_GCTHING_INDEX(pc);
5158 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
5159 PUSH_EXIT_FRAME();
5160 if (!GlobalOrEvalDeclInstantiation(cx, obj0, script, lastFun)) {
5161 goto error;
5164 END_OP(GlobalOrEvalDeclInstantiation);
5167 CASE(DelName) {
5169 ReservedRooted<PropertyName*> name0(&state.name0, script->getName(pc));
5170 ReservedRooted<JSObject*> obj0(&state.obj0, frame->environmentChain());
5171 PUSH_EXIT_FRAME();
5172 if (!DeleteNameOperation(cx, name0, obj0, &state.res)) {
5173 goto error;
5176 PUSH(StackVal(state.res));
5177 state.res.setUndefined();
5178 END_OP(DelName);
5181 CASE(Arguments) {
5183 PUSH_EXIT_FRAME();
5184 if (!NewArgumentsObject(cx, frame, &state.res)) {
5185 goto error;
5188 PUSH(StackVal(state.res));
5189 state.res.setUndefined();
5190 END_OP(Arguments);
5193 CASE(Rest) {
5194 INVOKE_IC(Rest);
5195 IC_PUSH_RESULT();
5196 END_OP(Rest);
5199 CASE(FunctionThis) {
5201 PUSH_EXIT_FRAME();
5202 if (!js::GetFunctionThis(cx, frame, &state.res)) {
5203 goto error;
5206 PUSH(StackVal(state.res));
5207 state.res.setUndefined();
5208 END_OP(FunctionThis);
5211 CASE(Pop) {
5212 POP();
5213 END_OP(Pop);
5215 CASE(PopN) {
5216 uint32_t n = GET_UINT16(pc);
5217 POPN(n);
5218 END_OP(PopN);
5220 CASE(Dup) {
5221 StackVal value = sp[0];
5222 PUSH(value);
5223 END_OP(Dup);
5225 CASE(Dup2) {
5226 StackVal value1 = sp[0];
5227 StackVal value2 = sp[1];
5228 PUSH(value2);
5229 PUSH(value1);
5230 END_OP(Dup2);
5232 CASE(DupAt) {
5233 unsigned i = GET_UINT24(pc);
5234 StackVal value = sp[i];
5235 PUSH(value);
5236 END_OP(DupAt);
5238 CASE(Swap) {
5239 std::swap(sp[0], sp[1]);
5240 END_OP(Swap);
5242 CASE(Pick) {
5243 unsigned i = GET_UINT8(pc);
5244 StackVal tmp = sp[i];
5245 memmove(&sp[1], &sp[0], sizeof(StackVal) * i);
5246 sp[0] = tmp;
5247 END_OP(Pick);
5249 CASE(Unpick) {
5250 unsigned i = GET_UINT8(pc);
5251 StackVal tmp = sp[0];
5252 memmove(&sp[0], &sp[1], sizeof(StackVal) * i);
5253 sp[i] = tmp;
5254 END_OP(Unpick);
5256 CASE(DebugCheckSelfHosted) {
5257 HandleValue val = Stack::handle(&sp[0]);
5259 PUSH_EXIT_FRAME();
5260 if (!Debug_CheckSelfHosted(cx, val)) {
5261 goto error;
5264 END_OP(DebugCheckSelfHosted);
5266 CASE(Lineno) { END_OP(Lineno); }
5267 CASE(NopDestructuring) { END_OP(NopDestructuring); }
5268 CASE(ForceInterpreter) { END_OP(ForceInterpreter); }
5269 CASE(Debugger) {
5271 PUSH_EXIT_FRAME();
5272 if (!OnDebuggerStatement(cx, frame)) {
5273 goto error;
5276 END_OP(Debugger);
5279 label_default:
5280 MOZ_CRASH("Bad opcode");
5283 error:
5284 TRACE_PRINTF("HandleException: frame %p\n", frame);
5286 ResumeFromException rfe;
5288 PUSH_EXIT_FRAME();
5289 HandleException(&rfe);
5292 switch (rfe.kind) {
5293 case ExceptionResumeKind::EntryFrame:
5294 TRACE_PRINTF(" -> Return from entry frame\n");
5295 frame->setReturnValue(MagicValue(JS_ION_ERROR));
5296 stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer);
5297 stack.unwindingSP = reinterpret_cast<StackVal*>(rfe.stackPointer);
5298 goto unwind_error;
5299 case ExceptionResumeKind::Catch:
5300 pc = frame->interpreterPC();
5301 stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer);
5302 stack.unwindingSP = reinterpret_cast<StackVal*>(rfe.stackPointer);
5303 TRACE_PRINTF(" -> catch to pc %p\n", pc);
5304 goto unwind;
5305 case ExceptionResumeKind::Finally:
5306 pc = frame->interpreterPC();
5307 stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer);
5308 sp = reinterpret_cast<StackVal*>(rfe.stackPointer);
5309 TRACE_PRINTF(" -> finally to pc %p\n", pc);
5310 PUSH(StackVal(rfe.exception));
5311 PUSH(StackVal(rfe.exceptionStack));
5312 PUSH(StackVal(BooleanValue(true)));
5313 stack.unwindingSP = sp;
5314 goto unwind;
5315 case ExceptionResumeKind::ForcedReturnBaseline:
5316 pc = frame->interpreterPC();
5317 stack.fp = reinterpret_cast<StackVal*>(rfe.framePointer);
5318 stack.unwindingSP = reinterpret_cast<StackVal*>(rfe.stackPointer);
5319 TRACE_PRINTF(" -> forced return\n");
5320 goto unwind_ret;
5321 case ExceptionResumeKind::ForcedReturnIon:
5322 MOZ_CRASH(
5323 "Unexpected ForcedReturnIon exception-resume kind in Portable "
5324 "Baseline");
5325 case ExceptionResumeKind::Bailout:
5326 MOZ_CRASH(
5327 "Unexpected Bailout exception-resume kind in Portable Baseline");
5328 case ExceptionResumeKind::Wasm:
5329 MOZ_CRASH("Unexpected Wasm exception-resume kind in Portable Baseline");
5330 case ExceptionResumeKind::WasmCatch:
5331 MOZ_CRASH(
5332 "Unexpected WasmCatch exception-resume kind in Portable "
5333 "Baseline");
5337 DISPATCH();
5339 unwind:
5340 TRACE_PRINTF("unwind: fp = %p entryFrame = %p\n", stack.fp, entryFrame);
5341 if (reinterpret_cast<uintptr_t>(stack.fp) >
5342 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) {
5343 TRACE_PRINTF(" -> returning\n");
5344 return PBIResult::Unwind;
5346 sp = stack.unwindingSP;
5347 frame = reinterpret_cast<BaselineFrame*>(
5348 reinterpret_cast<uintptr_t>(stack.fp) - BaselineFrame::Size());
5349 TRACE_PRINTF(" -> setting sp to %p, frame to %p\n", sp, frame);
5350 frameMgr.switchToFrame(frame);
5351 pc = frame->interpreterPC();
5352 script.set(frame->script());
5353 DISPATCH();
5354 unwind_error:
5355 TRACE_PRINTF("unwind_error: fp = %p entryFrame = %p\n", stack.fp, entryFrame);
5356 if (reinterpret_cast<uintptr_t>(stack.fp) >
5357 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) {
5358 return PBIResult::UnwindError;
5360 if (reinterpret_cast<uintptr_t>(stack.fp) ==
5361 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) {
5362 return PBIResult::Error;
5364 sp = stack.unwindingSP;
5365 frame = reinterpret_cast<BaselineFrame*>(
5366 reinterpret_cast<uintptr_t>(stack.fp) - BaselineFrame::Size());
5367 TRACE_PRINTF(" -> setting sp to %p, frame to %p\n", sp, frame);
5368 frameMgr.switchToFrame(frame);
5369 pc = frame->interpreterPC();
5370 script.set(frame->script());
5371 goto error;
5372 unwind_ret:
5373 TRACE_PRINTF("unwind_ret: fp = %p entryFrame = %p\n", stack.fp, entryFrame);
5374 if (reinterpret_cast<uintptr_t>(stack.fp) >
5375 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) {
5376 return PBIResult::UnwindRet;
5378 if (reinterpret_cast<uintptr_t>(stack.fp) ==
5379 reinterpret_cast<uintptr_t>(entryFrame) + BaselineFrame::Size()) {
5380 *ret = frame->returnValue();
5381 return PBIResult::Ok;
5383 sp = stack.unwindingSP;
5384 frame = reinterpret_cast<BaselineFrame*>(
5385 reinterpret_cast<uintptr_t>(stack.fp) - BaselineFrame::Size());
5386 TRACE_PRINTF(" -> setting sp to %p, frame to %p\n", sp, frame);
5387 frameMgr.switchToFrame(frame);
5388 pc = frame->interpreterPC();
5389 script.set(frame->script());
5390 from_unwind = true;
5391 goto do_return;
5393 #ifndef __wasi__
5394 debug: {
5395 TRACE_PRINTF("hit debug point\n");
5396 PUSH_EXIT_FRAME();
5397 if (!HandleDebugTrap(cx, frame, pc)) {
5398 TRACE_PRINTF("HandleDebugTrap returned error\n");
5399 goto error;
5401 pc = frame->interpreterPC();
5402 TRACE_PRINTF("HandleDebugTrap done\n");
5404 goto dispatch;
5405 #endif
5409 * -----------------------------------------------
5410 * Entry point
5411 * -----------------------------------------------
5414 bool PortableBaselineTrampoline(JSContext* cx, size_t argc, Value* argv,
5415 size_t numFormals, size_t numActuals,
5416 CalleeToken calleeToken, JSObject* envChain,
5417 Value* result) {
5418 State state(cx);
5419 Stack stack(cx->portableBaselineStack());
5420 StackVal* sp = stack.top;
5422 TRACE_PRINTF("Trampoline: calleeToken %p env %p\n", calleeToken, envChain);
5424 // Expected stack frame:
5425 // - argN
5426 // - ...
5427 // - arg1
5428 // - this
5429 // - calleeToken
5430 // - descriptor
5431 // - "return address" (nullptr for top frame)
5433 // `argc` is the number of args *including* `this` (`N + 1`
5434 // above). `numFormals` is the minimum `N`; if less, we need to push
5435 // `UndefinedValue`s above. We need to pass an argc (including
5436 // `this`) accoundint for the extra undefs in the descriptor's argc.
5438 // If constructing, there is an additional `newTarget` at the end.
5440 // Note that `callee`, which is in the stack signature for a `Call`
5441 // JSOp, does *not* appear in this count: it is separately passed in
5442 // the `calleeToken`.
5444 bool constructing = CalleeTokenIsConstructing(calleeToken);
5445 size_t numCalleeActuals = std::max(numActuals, numFormals);
5446 size_t numUndefs = numCalleeActuals - numActuals;
5448 // N.B.: we already checked the stack in
5449 // PortableBaselineInterpreterStackCheck; we don't do it here
5450 // because we can't push an exit frame if we don't have an entry
5451 // frame, and we need a full activation to produce the backtrace
5452 // from ReportOverRecursed.
5454 if (constructing) {
5455 PUSH(StackVal(argv[argc]));
5457 for (size_t i = 0; i < numUndefs; i++) {
5458 PUSH(StackVal(UndefinedValue()));
5460 for (size_t i = 0; i < argc; i++) {
5461 PUSH(StackVal(argv[argc - 1 - i]));
5463 PUSHNATIVE(StackValNative(calleeToken));
5464 PUSHNATIVE(StackValNative(
5465 MakeFrameDescriptorForJitCall(FrameType::CppToJSJit, numActuals)));
5467 switch (PortableBaselineInterpret(cx, state, stack, sp, envChain, result)) {
5468 case PBIResult::Ok:
5469 case PBIResult::UnwindRet:
5470 TRACE_PRINTF("PBI returned Ok/UnwindRet with result %" PRIx64 "\n",
5471 result->asRawBits());
5472 break;
5473 case PBIResult::Error:
5474 case PBIResult::UnwindError:
5475 TRACE_PRINTF("PBI returned Error/UnwindError\n");
5476 return false;
5477 case PBIResult::Unwind:
5478 MOZ_CRASH("Should not unwind out of top / entry frame");
5481 return true;
5484 MethodStatus CanEnterPortableBaselineInterpreter(JSContext* cx,
5485 RunState& state) {
5486 if (!JitOptions.portableBaselineInterpreter) {
5487 return MethodStatus::Method_CantCompile;
5489 if (state.script()->hasJitScript()) {
5490 return MethodStatus::Method_Compiled;
5492 if (state.script()->hasForceInterpreterOp()) {
5493 return MethodStatus::Method_CantCompile;
5495 if (cx->runtime()->geckoProfiler().enabled()) {
5496 return MethodStatus::Method_CantCompile;
5499 if (state.isInvoke()) {
5500 InvokeState& invoke = *state.asInvoke();
5501 if (TooManyActualArguments(invoke.args().length())) {
5502 return MethodStatus::Method_CantCompile;
5504 } else {
5505 if (state.asExecute()->isDebuggerEval()) {
5506 return MethodStatus::Method_CantCompile;
5509 if (state.script()->getWarmUpCount() <=
5510 JitOptions.portableBaselineInterpreterWarmUpThreshold) {
5511 return MethodStatus::Method_Skipped;
5513 if (!cx->zone()->ensureJitZoneExists(cx)) {
5514 return MethodStatus::Method_Error;
5517 AutoKeepJitScripts keepJitScript(cx);
5518 if (!state.script()->ensureHasJitScript(cx, keepJitScript)) {
5519 return MethodStatus::Method_Error;
5521 state.script()->updateJitCodeRaw(cx->runtime());
5522 return MethodStatus::Method_Compiled;
5525 bool PortablebaselineInterpreterStackCheck(JSContext* cx, RunState& state,
5526 size_t numActualArgs) {
5527 auto& pbs = cx->portableBaselineStack();
5528 StackVal* base = reinterpret_cast<StackVal*>(pbs.base);
5529 StackVal* top = reinterpret_cast<StackVal*>(pbs.top);
5530 ssize_t margin = kStackMargin / sizeof(StackVal);
5531 ssize_t needed = numActualArgs + state.script()->nslots() + margin;
5532 return (top - base) >= needed;
5535 } // namespace pbl
5536 } // namespace js