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/. */
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
15 #include "vm/PortableBaselineInterpret.h"
17 #include "mozilla/Maybe.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"
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"
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
70 # define TRACE_PRINTF(...) \
72 printf(__VA_ARGS__); \
76 # define TRACE_PRINTF(...) \
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 * -----------------------------------------------
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).
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.");
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) \
142 StackValNative* nativeSP = reinterpret_cast<StackValNative*>(sp); \
143 *--nativeSP = (val); \
144 sp = reinterpret_cast<StackVal*>(nativeSP); \
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.
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
,
172 if (!check(sp
, size
, false)) {
175 sp
= reinterpret_cast<StackVal
*>(reinterpret_cast<uintptr_t>(sp
) - size
);
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
,
185 JSObject
* envChain
) {
186 TRACE_PRINTF("pushFrame: sp = %p fp = %p\n", sp
, fp
);
190 PUSHNATIVE(StackValNative(fp
));
192 TRACE_PRINTF("pushFrame: new fp = %p\n", fp
);
194 BaselineFrame
* frame
=
195 reinterpret_cast<BaselineFrame
*>(allocate(sp
, BaselineFrame::Size()));
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());
206 frame
->setDebugFrameSize(0);
211 StackVal
* popFrame() {
213 reinterpret_cast<StackVal
*>(reinterpret_cast<StackValNative
*>(fp
) + 1);
214 fp
= reinterpret_cast<StackVal
*>(
215 reinterpret_cast<StackValNative
*>(fp
)->asVoidPtr());
217 TRACE_PRINTF("popFrame: fp = %p\n", fp
);
221 void setFrameSize(StackVal
* sp
, BaselineFrame
* prevFrame
) {
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
,
230 MOZ_ASSERT(frameSize
>= BaselineFrame::Size());
231 prevFrame
->setDebugFrameSize(frameSize
);
235 [[nodiscard
]] MOZ_ALWAYS_INLINE StackVal
* pushExitFrame(
236 StackVal
* sp
, BaselineFrame
* prevFrame
) {
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)) {
246 PUSHNATIVE(StackValNative(
247 MakeFrameDescriptorForJitCall(FrameType::BaselineJS
, 0)));
248 PUSHNATIVE(StackValNative(nullptr)); // fake return address.
249 PUSHNATIVE(StackValNative(prevFP
));
250 StackVal
* exitFP
= sp
;
252 TRACE_PRINTF(" -> fp = %p\n", fp
);
253 PUSHNATIVE(StackValNative(uint32_t(ExitFrameType::Bare
)));
257 void popExitFrame(StackVal
* fp
) {
258 StackVal
* prevFP
= reinterpret_cast<StackVal
*>(
259 reinterpret_cast<StackValNative
*>(fp
)->asVoidPtr());
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 * -----------------------------------------------
281 * -----------------------------------------------
285 CacheIRReader cacheIRReader
;
286 static const int kMaxICVals
= 16;
287 uint64_t icVals
[kMaxICVals
];
292 ICRegs() : cacheIRReader(nullptr, nullptr) {}
306 RootedScript script0
;
307 Rooted
<PropertyName
*> name0
;
309 Rooted
<JSAtom
*> atom0
;
311 Rooted
<Scope
*> scope0
;
313 explicit State(JSContext
* cx
)
333 * -----------------------------------------------
334 * RAII helpers for pushing exit frames.
336 * (See [SMDOC] in PortableBaselineInterpret.h for more.)
337 * -----------------------------------------------
340 class VMFrameManager
{
342 BaselineFrame
* frame
;
343 friend class VMFrame
;
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).
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
; }
366 void* prevSavedStack
;
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
);
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
));
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()) { \
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 * -----------------------------------------------
412 * -----------------------------------------------
415 ICInterpretOpResult MOZ_ALWAYS_INLINE
416 ICInterpretOps(BaselineFrame
* frame
, VMFrameManager
& frameMgr
, State
& state
,
417 ICRegs
& icregs
, Stack
& stack
, StackVal
* sp
, ICCacheIRStub
* cstub
,
419 #define CACHEOP_CASE(name) \
421 : TRACE_PRINTF("cacheop (frame %p pc %p stub %p): " #name "\n", frame, \
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,
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
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; \
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()]);
466 return ICInterpretOpResult::NextIC
;
468 icregs
.icVals
[inputId
.id()] = reinterpret_cast<uint64_t>(&v
.toObject());
469 PREDICT_NEXT(GuardShape
);
470 PREDICT_NEXT(GuardSpecificFunction
);
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
;
483 CACHEOP_CASE(GuardIsNull
) {
484 ValOperandId inputId
= icregs
.cacheIRReader
.valOperandId();
485 Value v
= Value::fromRawBits(icregs
.icVals
[inputId
.id()]);
487 return ICInterpretOpResult::NextIC
;
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
;
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;
511 CACHEOP_CASE(GuardToString
) {
512 ValOperandId inputId
= icregs
.cacheIRReader
.valOperandId();
513 Value v
= Value::fromRawBits(icregs
.icVals
[inputId
.id()]);
515 return ICInterpretOpResult::NextIC
;
517 icregs
.icVals
[inputId
.id()] = reinterpret_cast<uint64_t>(v
.toString());
518 PREDICT_NEXT(GuardToString
);
522 CACHEOP_CASE(GuardToSymbol
) {
523 ValOperandId inputId
= icregs
.cacheIRReader
.valOperandId();
524 Value v
= Value::fromRawBits(icregs
.icVals
[inputId
.id()]);
526 return ICInterpretOpResult::NextIC
;
528 icregs
.icVals
[inputId
.id()] = reinterpret_cast<uint64_t>(v
.toSymbol());
529 PREDICT_NEXT(GuardSpecificSymbol
);
533 CACHEOP_CASE(GuardToBigInt
) {
534 ValOperandId inputId
= icregs
.cacheIRReader
.valOperandId();
535 Value v
= Value::fromRawBits(icregs
.icVals
[inputId
.id()]);
537 return ICInterpretOpResult::NextIC
;
539 icregs
.icVals
[inputId
.id()] = reinterpret_cast<uint64_t>(v
.toBigInt());
543 CACHEOP_CASE(GuardIsNumber
) {
544 ValOperandId inputId
= icregs
.cacheIRReader
.valOperandId();
545 Value v
= Value::fromRawBits(icregs
.icVals
[inputId
.id()]);
547 return ICInterpretOpResult::NextIC
;
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()]);
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
);
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;
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()]);
586 icregs
.icVals
[resultId
.id()] = val
.toInt32();
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
);
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()]);
603 case ValueType::String
:
604 if (!val
.isString()) {
605 return ICInterpretOpResult::NextIC
;
608 case ValueType::Symbol
:
609 if (!val
.isSymbol()) {
610 return ICInterpretOpResult::NextIC
;
613 case ValueType::BigInt
:
614 if (!val
.isBigInt()) {
615 return ICInterpretOpResult::NextIC
;
618 case ValueType::Int32
:
619 if (!val
.isInt32()) {
620 return ICInterpretOpResult::NextIC
;
623 case ValueType::Boolean
:
624 if (!val
.isBoolean()) {
625 return ICInterpretOpResult::NextIC
;
628 case ValueType::Undefined
:
629 if (!val
.isUndefined()) {
630 return ICInterpretOpResult::NextIC
;
633 case ValueType::Null
:
635 return ICInterpretOpResult::NextIC
;
639 MOZ_CRASH("Unexpected type");
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
;
656 CACHEOP_CASE(GuardFuse
) {
657 RealmFuses::FuseIndex fuseIndex
= icregs
.cacheIRReader
.realmFuseIndex();
658 if (!frameMgr
.cxForLocalUseOnly()
660 ->realmFuses
.getFuseByIndex(fuseIndex
)
662 return ICInterpretOpResult::NextIC
;
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
);
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()]);
685 case GuardClassKind::Array
:
686 if (object
->getClass() != &ArrayObject::class_
) {
687 return ICInterpretOpResult::NextIC
;
690 case GuardClassKind::PlainObject
:
691 if (object
->getClass() != &PlainObject::class_
) {
692 return ICInterpretOpResult::NextIC
;
695 case GuardClassKind::FixedLengthArrayBuffer
:
696 if (object
->getClass() != &FixedLengthArrayBufferObject::class_
) {
697 return ICInterpretOpResult::NextIC
;
700 case GuardClassKind::FixedLengthSharedArrayBuffer
:
701 if (object
->getClass() != &FixedLengthSharedArrayBufferObject::class_
) {
702 return ICInterpretOpResult::NextIC
;
705 case GuardClassKind::FixedLengthDataView
:
706 if (object
->getClass() != &FixedLengthDataViewObject::class_
) {
707 return ICInterpretOpResult::NextIC
;
710 case GuardClassKind::MappedArguments
:
711 if (object
->getClass() != &MappedArgumentsObject::class_
) {
712 return ICInterpretOpResult::NextIC
;
715 case GuardClassKind::UnmappedArguments
:
716 if (object
->getClass() != &UnmappedArgumentsObject::class_
) {
717 return ICInterpretOpResult::NextIC
;
720 case GuardClassKind::WindowProxy
:
721 if (object
->getClass() !=
722 frameMgr
.cxForLocalUseOnly()->runtime()->maybeWindowProxyClass()) {
723 return ICInterpretOpResult::NextIC
;
726 case GuardClassKind::JSFunction
:
727 if (!object
->is
<JSFunction
>()) {
728 return ICInterpretOpResult::NextIC
;
731 case GuardClassKind::Set
:
732 if (object
->getClass() != &SetObject::class_
) {
733 return ICInterpretOpResult::NextIC
;
736 case GuardClassKind::Map
:
737 if (object
->getClass() != &MapObject::class_
) {
738 return ICInterpretOpResult::NextIC
;
741 case GuardClassKind::BoundFunction
:
742 if (object
->getClass() != &BoundFunctionObject::class_
) {
743 return ICInterpretOpResult::NextIC
;
750 CACHEOP_CASE(GuardGlobalGeneration
) {
751 uint32_t expectedOffset
= icregs
.cacheIRReader
.stubOffset();
752 uint32_t generationAddrOffset
= icregs
.cacheIRReader
.stubOffset();
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
;
763 CACHEOP_CASE(GuardSpecificObject
) {
764 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
765 uint32_t expectedOffset
= icregs
.cacheIRReader
.stubOffset();
767 cstub
->stubInfo()->getStubRawWord(cstub
, expectedOffset
);
768 if (expected
!= icregs
.icVals
[objId
.id()]) {
769 return ICInterpretOpResult::NextIC
;
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.
780 cstub
->stubInfo()->getStubRawWord(cstub
, expectedOffset
);
781 if (expected
!= icregs
.icVals
[funId
.id()]) {
782 return ICInterpretOpResult::NextIC
;
784 PREDICT_NEXT(LoadArgumentFixedSlot
);
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
);
805 CACHEOP_CASE(GuardSpecificAtom
) {
806 StringOperandId strId
= icregs
.cacheIRReader
.stringOperandId();
807 uint32_t expectedOffset
= icregs
.cacheIRReader
.stubOffset();
809 cstub
->stubInfo()->getStubRawWord(cstub
, expectedOffset
);
810 if (expected
!= icregs
.icVals
[strId
.id()]) {
811 return ICInterpretOpResult::NextIC
;
816 CACHEOP_CASE(GuardSpecificSymbol
) {
817 SymbolOperandId symId
= icregs
.cacheIRReader
.symbolOperandId();
818 uint32_t expectedOffset
= icregs
.cacheIRReader
.stubOffset();
820 cstub
->stubInfo()->getStubRawWord(cstub
, expectedOffset
);
821 if (expected
!= icregs
.icVals
[symId
.id()]) {
822 return ICInterpretOpResult::NextIC
;
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
;
836 CACHEOP_CASE(GuardDynamicSlotIsSpecificObject
) {
837 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
838 ObjOperandId expectedId
= icregs
.cacheIRReader
.objOperandId();
839 uint32_t slotOffset
= icregs
.cacheIRReader
.stubOffset();
841 reinterpret_cast<JSObject
*>(icregs
.icVals
[expectedId
.id()]);
842 uintptr_t offset
= cstub
->stubInfo()->getStubRawInt32(cstub
, slotOffset
);
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
;
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
;
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
);
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();
879 intptr_t obj
= cstub
->stubInfo()->getStubRawWord(cstub
, protoObjOffset
);
880 icregs
.icVals
[resultId
.id()] = obj
;
881 PREDICT_NEXT(GuardShape
);
885 CACHEOP_CASE(LoadProto
) {
886 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
887 ObjOperandId resultId
= icregs
.cacheIRReader
.objOperandId();
888 BOUNDSCHECK(resultId
);
890 reinterpret_cast<NativeObject
*>(icregs
.icVals
[objId
.id()]);
891 icregs
.icVals
[resultId
.id()] =
892 reinterpret_cast<uintptr_t>(nobj
->staticPrototype());
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
),
903 icregs
.icVals
[resultId
.id()] = val
.asRawBits();
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();
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
);
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()]);
929 PREDICT_NEXT(ReturnFromIC
);
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
);
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
);
949 CACHEOP_CASE(StoreDenseElement
) {
950 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
951 Int32OperandId indexId
= icregs
.cacheIRReader
.int32OperandId();
952 ValOperandId rhsId
= icregs
.cacheIRReader
.valOperandId();
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(),
967 PREDICT_NEXT(ReturnFromIC
);
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
);
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
;
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
);
1000 icregs
.icVals
[resultId
.id()] = reinterpret_cast<uintptr_t>(str
);
1002 return ICInterpretOpResult::NextIC
;
1007 CACHEOP_CASE(CallScriptedFunction
)
1008 CACHEOP_CASE_FALLTHROUGH(CallNativeFunction
) {
1009 bool isNative
= cacheop
== CacheOp::CallNativeFunction
;
1010 TRACE_PRINTF("CallScriptedFunction / CallNativeFunction (native: %d)\n",
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;
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()]);
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
;
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.
1065 PUSHNATIVE(StackValNative(cstub
));
1068 for (uint32_t i
= 0; i
< totalArgs
; i
++) {
1071 Value
* args
= reinterpret_cast<Value
*>(sp
);
1073 TRACE_PRINTF("pushing callee: %p\n", callee
);
1075 StackValNative(CalleeToToken(callee
, /* isConstructing = */ false)));
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
));
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
1096 bool success
= native(cx
, argc
, args
);
1098 stack
.fp
= trampolinePrevFP
;
1102 return ICInterpretOpResult::Error
;
1104 icregs
.icResult
= args
[0].asRawBits();
1106 PUSHNATIVE(StackValNative(
1107 MakeFrameDescriptorForJitCall(FrameType::BaselineStub
, argc
)));
1109 switch (PortableBaselineInterpret(
1110 cx
, state
, stack
, sp
, /* envChain = */ nullptr,
1111 reinterpret_cast<Value
*>(&icregs
.icResult
))) {
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
;
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()]);
1136 reinterpret_cast<Value
*>(reinterpret_cast<uintptr_t>(nobj
) + offset
);
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
);
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
);
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
);
1178 CACHEOP_CASE(LoadInt32ArrayLengthResult
) {
1179 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
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
);
1191 CACHEOP_CASE(LoadInt32ArrayLength
) {
1192 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
1193 Int32OperandId resultId
= icregs
.cacheIRReader
.int32OperandId();
1194 BOUNDSCHECK(resultId
);
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
;
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
);
1211 reinterpret_cast<JSLinearString
*>(icregs
.icVals
[strId
.id()]);
1214 if (!str
->isRope()) {
1215 icregs
.icVals
[resultId
.id()] = reinterpret_cast<uintptr_t>(str
);
1218 JSLinearString
* result
= LinearizeForCharAccess(cx
, str
);
1220 return ICInterpretOpResult::Error
;
1222 icregs
.icVals
[resultId
.id()] = reinterpret_cast<uintptr_t>(result
);
1224 PREDICT_NEXT(LoadStringCharResult
);
1228 CACHEOP_CASE(LoadStringCharResult
) {
1229 StringOperandId strId
= icregs
.cacheIRReader
.stringOperandId();
1230 Int32OperandId indexId
= icregs
.cacheIRReader
.int32OperandId();
1231 bool handleOOB
= icregs
.cacheIRReader
.readBool();
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()) {
1239 // Return an empty string.
1240 result
= frameMgr
.cxForLocalUseOnly()->names().empty_
;
1242 return ICInterpretOpResult::NextIC
;
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
);
1254 result
= StringFromCharCode(cx
, c
);
1256 return ICInterpretOpResult::Error
;
1260 icregs
.icResult
= StringValue(result
).asRawBits();
1261 PREDICT_NEXT(ReturnFromIC
);
1265 CACHEOP_CASE(LoadStringCharCodeResult
) {
1266 StringOperandId strId
= icregs
.cacheIRReader
.stringOperandId();
1267 Int32OperandId indexId
= icregs
.cacheIRReader
.int32OperandId();
1268 bool handleOOB
= icregs
.cacheIRReader
.readBool();
1271 reinterpret_cast<JSLinearString
*>(icregs
.icVals
[strId
.id()]);
1272 int32_t index
= int32_t(icregs
.icVals
[indexId
.id()]);
1274 if (index
< 0 || size_t(index
) >= str
->length()) {
1277 result
= JS::NaNValue();
1279 return ICInterpretOpResult::NextIC
;
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
);
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
);
1305 CACHEOP_CASE(LoadObjectResult
) {
1306 ObjOperandId objId
= icregs
.cacheIRReader
.objOperandId();
1308 ObjectValue(*reinterpret_cast<JSObject
*>(icregs
.icVals
[objId
.id()]))
1310 PREDICT_NEXT(ReturnFromIC
);
1314 CACHEOP_CASE(LoadStringResult
) {
1315 StringOperandId strId
= icregs
.cacheIRReader
.stringOperandId();
1317 StringValue(reinterpret_cast<JSString
*>(icregs
.icVals
[strId
.id()]))
1322 CACHEOP_CASE(LoadSymbolResult
) {
1323 SymbolOperandId symId
= icregs
.cacheIRReader
.symbolOperandId();
1325 SymbolValue(reinterpret_cast<JS::Symbol
*>(icregs
.icVals
[symId
.id()]))
1327 PREDICT_NEXT(ReturnFromIC
);
1331 CACHEOP_CASE(LoadInt32Result
) {
1332 Int32OperandId valId
= icregs
.cacheIRReader
.int32OperandId();
1333 icregs
.icResult
= Int32Value(icregs
.icVals
[valId
.id()]).asRawBits();
1334 PREDICT_NEXT(ReturnFromIC
);
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
);
1349 CACHEOP_CASE(LoadBigIntResult
) {
1350 BigIntOperandId valId
= icregs
.cacheIRReader
.bigIntOperandId();
1352 BigIntValue(reinterpret_cast<JS::BigInt
*>(icregs
.icVals
[valId
.id()]))
1354 PREDICT_NEXT(ReturnFromIC
);
1358 CACHEOP_CASE(LoadBooleanResult
) {
1359 bool val
= icregs
.cacheIRReader
.readBool();
1360 icregs
.icResult
= BooleanValue(val
).asRawBits();
1361 PREDICT_NEXT(ReturnFromIC
);
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
;
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
);
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()])); \
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
, -, {});
1402 if (rhs
* lhs
== 0 && ((rhs
< 0) ^ (lhs
< 0))) {
1403 return ICInterpretOpResult::NextIC
;
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
;
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()]));
1437 } else if (rhs
< 0) {
1438 return ICInterpretOpResult::NextIC
;
1441 int64_t runningSquare
= lhs
;
1444 result
*= runningSquare
;
1445 if (result
> int64_t(INT32_MAX
)) {
1446 return ICInterpretOpResult::NextIC
;
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
);
1465 CACHEOP_CASE(Int32IncResult
) {
1466 Int32OperandId inputId
= icregs
.cacheIRReader
.int32OperandId();
1467 int64_t value
= int64_t(int32_t(icregs
.icVals
[inputId
.id()]));
1469 if (value
> INT32_MAX
) {
1470 return ICInterpretOpResult::NextIC
;
1472 icregs
.icResult
= Int32Value(int32_t(value
)).asRawBits();
1473 PREDICT_NEXT(ReturnFromIC
);
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
);
1485 CACHEOP_CASE(LoadStringTruthyResult
) {
1486 StringOperandId strId
= icregs
.cacheIRReader
.stringOperandId();
1488 reinterpret_cast<JSLinearString
*>(icregs
.icVals
[strId
.id()]);
1489 icregs
.icResult
= BooleanValue(str
->length() > 0).asRawBits();
1490 PREDICT_NEXT(ReturnFromIC
);
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
);
1506 CACHEOP_CASE(LoadValueResult
) {
1507 uint32_t valOffset
= icregs
.cacheIRReader
.stubOffset();
1508 icregs
.icResult
= cstub
->stubInfo()->getStubRawInt64(cstub
, valOffset
);
1509 PREDICT_NEXT(ReturnFromIC
);
1513 CACHEOP_CASE(LoadOperandResult
) {
1514 ValOperandId inputId
= icregs
.cacheIRReader
.valOperandId();
1515 icregs
.icResult
= icregs
.icVals
[inputId
.id()];
1516 PREDICT_NEXT(ReturnFromIC
);
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()]));
1530 ConcatStrings
<NoGC
>(frameMgr
.cxForLocalUseOnly(), lhs
, rhs
);
1532 icregs
.icResult
= StringValue(result
).asRawBits();
1534 return ICInterpretOpResult::NextIC
;
1536 PREDICT_NEXT(ReturnFromIC
);
1540 CACHEOP_CASE(CompareStringResult
) {
1541 JSOp op
= icregs
.cacheIRReader
.jsop();
1542 StringOperandId lhsId
= icregs
.cacheIRReader
.stringOperandId();
1543 StringOperandId rhsId
= icregs
.cacheIRReader
.stringOperandId();
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()]));
1553 case JSOp::StrictEq
:
1554 if (lhs
->length() != rhs
->length()) {
1558 if (!StringsEqual
<EqualityKind::Equal
>(cx
, lhs
, rhs
, &result
)) {
1559 return ICInterpretOpResult::Error
;
1563 case JSOp::StrictNe
:
1564 if (lhs
->length() != rhs
->length()) {
1568 if (!StringsEqual
<EqualityKind::NotEqual
>(cx
, lhs
, rhs
, &result
)) {
1569 return ICInterpretOpResult::Error
;
1573 if (!StringsCompare
<ComparisonKind::LessThan
>(cx
, lhs
, rhs
,
1575 return ICInterpretOpResult::Error
;
1579 if (!StringsCompare
<ComparisonKind::GreaterThanOrEqual
>(cx
, lhs
, rhs
,
1581 return ICInterpretOpResult::Error
;
1585 if (!StringsCompare
<ComparisonKind::GreaterThanOrEqual
>(
1586 cx
, /* N.B. swapped order */ rhs
, lhs
, &result
)) {
1587 return ICInterpretOpResult::Error
;
1591 if (!StringsCompare
<ComparisonKind::LessThan
>(
1592 cx
, /* N.B. swapped order */ rhs
, lhs
, &result
)) {
1593 return ICInterpretOpResult::Error
;
1597 MOZ_CRASH("bad opcode");
1599 icregs
.icResult
= BooleanValue(result
).asRawBits();
1601 PREDICT_NEXT(ReturnFromIC
);
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
);
1616 case JSOp::StrictEq
:
1617 result
= lhs
== rhs
;
1620 case JSOp::StrictNe
:
1621 result
= lhs
!= rhs
;
1627 result
= lhs
<= rhs
;
1633 result
= lhs
>= rhs
;
1636 MOZ_CRASH("Unexpected opcode");
1638 icregs
.icResult
= BooleanValue(result
).asRawBits();
1639 PREDICT_NEXT(ReturnFromIC
);
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
;
1656 val
.isUndefined() || val
.isNull() ||
1657 (val
.isObject() && val
.toObject().getClass()->emulatesUndefined());
1661 val
.isUndefined() || val
.isNull() ||
1662 (val
.isObject() && val
.toObject().getClass()->emulatesUndefined()));
1664 case JSOp::StrictEq
:
1665 result
= isUndefined
? val
.isUndefined() : val
.isNull();
1667 case JSOp::StrictNe
:
1668 result
= !(isUndefined
? val
.isUndefined() : val
.isNull());
1671 MOZ_CRASH("bad opcode");
1673 icregs
.icResult
= BooleanValue(result
).asRawBits();
1674 PREDICT_NEXT(ReturnFromIC
);
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.
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
)
1873 CACHEOP_CASE_UNIMPL(CallScriptedProxyGetResult
)
1874 CACHEOP_CASE_UNIMPL(CallScriptedProxyGetByValueResult
)
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
;
2007 * -----------------------------------------------
2008 * IC callsite logic, and fallback stubs
2009 * -----------------------------------------------
2012 #define SAVE_INPUTS(arity) \
2018 inputs[0] = icregs.icVals[0]; \
2021 inputs[0] = icregs.icVals[0]; \
2022 inputs[1] = icregs.icVals[1]; \
2025 inputs[0] = icregs.icVals[0]; \
2026 inputs[1] = icregs.icVals[1]; \
2027 inputs[2] = icregs.icVals[2]; \
2032 #define RESTORE_INPUTS(arity) \
2038 icregs.icVals[0] = inputs[0]; \
2041 icregs.icVals[0] = inputs[0]; \
2042 icregs.icVals[1] = inputs[1]; \
2045 icregs.icVals[0] = inputs[0]; \
2046 icregs.icVals[1] = inputs[1]; \
2047 icregs.icVals[2] = inputs[2]; \
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); \
2061 if (stub->isFallback()) { \
2062 ICFallbackStub* fallback = stub->toFallbackStub(); \
2064 icregs.icResult = state.res.asRawBits(); \
2065 state.res = UndefinedValue(); \
2066 return PBIResult::Ok; \
2068 return PBIResult::Error; \
2070 ICCacheIRStub* cstub = stub->toCacheIRStub(); \
2071 cstub->incrementEnteredCount(); \
2072 new (&icregs.cacheIRReader) CacheIRReader(cstub->stubInfo()); \
2073 switch (ICInterpretOps(frame, frameMgr, state, icregs, stack, sp, \
2075 case ICInterpretOpResult::NextIC: \
2076 stub = stub->maybeNext(); \
2077 RESTORE_INPUTS(arity); \
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
)) {
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
)) {
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
,
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
);
2134 if (!DoCallFallback(cx
, frame
, fallback
, argc
, args
, &state
.res
)) {
2135 std::reverse(args
, args
+ totalArgs
);
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
)) {
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
)) {
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
)) {
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
)) {
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
)) {
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
)) {
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
)) {
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
)) {
2211 DEFINE_IC(NewObject
, 0, {
2212 PUSH_FALLBACK_IC_FRAME();
2213 if (!DoNewObjectFallback(cx
, frame
, fallback
, &state
.res
)) {
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
)) {
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
,
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
)) {
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
,
2256 DEFINE_IC(NewArray
, 0, {
2257 PUSH_FALLBACK_IC_FRAME();
2258 if (!DoNewArrayFallback(cx
, frame
, fallback
, &state
.res
)) {
2263 DEFINE_IC(GetIntrinsic
, 0, {
2264 PUSH_FALLBACK_IC_FRAME();
2265 if (!DoGetIntrinsicFallback(cx
, frame
, fallback
, &state
.res
)) {
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
,
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
)) {
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
,
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
)) {
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
)) {
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
)) {
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
)) {
2332 DEFINE_IC(Rest
, 0, {
2333 PUSH_FALLBACK_IC_FRAME();
2334 if (!DoRestFallback(cx
, frame
, fallback
, &state
.res
)) {
2339 DEFINE_IC(CloseIter
, 1, {
2340 IC_LOAD_OBJ(obj0
, 0);
2341 PUSH_FALLBACK_IC_FRAME();
2342 if (!DoCloseIterFallback(cx
, frame
, fallback
, obj0
)) {
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();
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();
2370 # define DEBUG_CHECK() \
2371 if (frame->isDebuggee()) { \
2373 "Debug check: frame is debuggee, checking for debug script\n"); \
2374 if (script->hasDebugScript()) { \
2379 # define DEBUG_CHECK()
2382 #define LABEL(op) (&&label_##op)
2383 #define CASE(op) label_##op:
2384 #if !defined(TRACE_INTERP)
2385 # define DISPATCH() \
2387 goto* addresses[*pc]
2389 # define DISPATCH() \
2394 #define ADVANCE(delta) pc += (delta);
2395 #define ADVANCE_AND_DISPATCH(delta) \
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) { \
2416 # define PREDICT_NEXT(op)
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: \
2437 case PBIResult::Error: \
2439 case PBIResult::Unwind: \
2441 case PBIResult::UnwindError: \
2442 goto unwind_error; \
2443 case PBIResult::UnwindRet: \
2448 PBIResult
PortableBaselineInterpret(JSContext
* cx_
, State
& state
, Stack
& stack
,
2449 StackVal
* sp
, JSObject
* envChain
,
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
)};
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
;
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())) {
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
2487 if (!stack
.check(sp
, sizeof(StackVal
) * script
->nslots())) {
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()) {
2504 if (!js::InitFunctionEnvironmentObjects(cx
, frame
)) {
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
2514 if (script
->isDebuggee()) {
2515 TRACE_PRINTF("Script is debuggee\n");
2516 frame
->setIsDebuggee();
2519 if (!DebugPrologue(cx
, frame
)) {
2524 if (!script
->hasScriptCounts()) {
2525 if (frameMgr
.cxForLocalUseOnly()->realm()->collectCoverageForDebug()) {
2527 if (!script
->initScriptCounts(cx
)) {
2532 COUNT_COVERAGE_MAIN();
2535 if (frameMgr
.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
2537 if (!InterruptCheck(cx
)) {
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()));
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
,
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));
2571 goto* addresses
[*pc
];
2573 CASE(Nop
) { END_OP(Nop
); }
2574 CASE(NopIsAssignOp
) { END_OP(NopIsAssignOp
); }
2576 PUSH(StackVal(UndefinedValue()));
2580 PUSH(StackVal(NullValue()));
2584 PUSH(StackVal(BooleanValue(false)));
2588 PUSH(StackVal(BooleanValue(true)));
2592 PUSH(StackVal(Int32Value(GET_INT32(pc
))));
2596 PUSH(StackVal(Int32Value(0)));
2600 PUSH(StackVal(Int32Value(1)));
2604 PUSH(StackVal(Int32Value(GET_INT8(pc
))));
2608 PUSH(StackVal(Int32Value(GET_UINT16(pc
))));
2612 PUSH(StackVal(Int32Value(GET_UINT24(pc
))));
2616 PUSH(StackVal(GET_INLINE_VALUE(pc
)));
2620 PUSH(StackVal(JS::BigIntValue(script
->getBigInt(pc
))));
2624 PUSH(StackVal(StringValue(script
->getString(pc
))));
2629 SymbolValue(frameMgr
.cxForLocalUseOnly()->wellKnownSymbols().get(
2634 sp
[0] = StackVal(JS::UndefinedValue());
2640 static_assert(JSOpLength_Typeof
== JSOpLength_TypeofExpr
);
2642 sp
[0] = StackVal(StringValue(TypeOfOperation(
2643 Stack::handle(sp
), frameMgr
.cxForLocalUseOnly()->runtime())));
2654 if (sp
[0].asValue().isNumber()) {
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
));
2671 if (sp
[0].asValue().isNumber()) {
2672 sp
[0] = StackVal(NumberValue(-sp
[0].asValue().toNumber()));
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));
2688 if (sp
[0].asValue().isNumber()) {
2689 sp
[0] = StackVal(NumberValue(sp
[0].asValue().toNumber() + 1));
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));
2704 if (sp
[0].asValue().isNumber()) {
2705 sp
[0] = StackVal(NumberValue(sp
[0].asValue().toNumber() - 1));
2713 if (sp
[0].asValue().isInt32()) {
2714 int32_t i
= sp
[0].asValue().toInt32();
2715 sp
[0] = StackVal(Int32Value(~i
));
2723 if (sp
[0].asValue().isNumeric()) {
2725 } else if (kHybridICs
) {
2726 MutableHandleValue val
= Stack::handleMut(&sp
[0]);
2728 if (!ToNumeric(cx
, val
)) {
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
);
2745 INVOKE_IC(UnaryArith
);
2752 sp
[0] = StackVal(BooleanValue(!ToBoolean(Stack::handle(sp
))));
2758 BooleanValue(!Value::fromRawBits(icregs
.icResult
).toBoolean())));
2766 result
= ToBoolean(Stack::handle(sp
));
2769 IC_SET_ARG_FROM_STACK(0, 0);
2771 result
= Value::fromRawBits(icregs
.icResult
).toBoolean();
2773 int32_t jumpOffset
= GET_JUMP_OFFSET(pc
);
2775 ADVANCE(jumpOffset
);
2776 PREDICT_NEXT(JumpTarget
);
2777 PREDICT_NEXT(LoopHead
);
2779 ADVANCE(JSOpLength_And
);
2786 result
= ToBoolean(Stack::handle(sp
));
2789 IC_SET_ARG_FROM_STACK(0, 0);
2791 result
= Value::fromRawBits(icregs
.icResult
).toBoolean();
2793 int32_t jumpOffset
= GET_JUMP_OFFSET(pc
);
2795 ADVANCE(jumpOffset
);
2796 PREDICT_NEXT(JumpTarget
);
2797 PREDICT_NEXT(LoopHead
);
2799 ADVANCE(JSOpLength_Or
);
2806 result
= ToBoolean(Stack::handle(sp
));
2812 result
= Value::fromRawBits(icregs
.icResult
).toBoolean();
2814 int32_t jumpOffset
= GET_JUMP_OFFSET(pc
);
2816 ADVANCE(jumpOffset
);
2817 PREDICT_NEXT(JumpTarget
);
2818 PREDICT_NEXT(LoopHead
);
2820 ADVANCE(JSOpLength_JumpIfTrue
);
2827 result
= ToBoolean(Stack::handle(sp
));
2833 result
= Value::fromRawBits(icregs
.icResult
).toBoolean();
2835 int32_t jumpOffset
= GET_JUMP_OFFSET(pc
);
2837 ADVANCE(jumpOffset
);
2838 PREDICT_NEXT(JumpTarget
);
2839 PREDICT_NEXT(LoopHead
);
2841 ADVANCE(JSOpLength_JumpIfFalse
);
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
)) {
2853 sp
[0] = StackVal(Int32Value(int32_t(lhs
+ rhs
)));
2858 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
2859 double lhs
= sp
[1].asValue().toNumber();
2860 double rhs
= sp
[0].asValue().toNumber();
2862 sp
[0] = StackVal(NumberValue(lhs
+ rhs
));
2867 MutableHandleValue lhs
= Stack::handleMut(sp
+ 1);
2868 MutableHandleValue rhs
= Stack::handleMut(sp
);
2869 MutableHandleValue result
= Stack::handleMut(sp
+ 1);
2872 if (!AddOperation(cx
, lhs
, rhs
, result
)) {
2880 goto generic_binary
;
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
)) {
2890 sp
[0] = StackVal(Int32Value(int32_t(lhs
- rhs
)));
2895 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
2896 double lhs
= sp
[1].asValue().toNumber();
2897 double rhs
= sp
[0].asValue().toNumber();
2899 sp
[0] = StackVal(NumberValue(lhs
- rhs
));
2904 MutableHandleValue lhs
= Stack::handleMut(sp
+ 1);
2905 MutableHandleValue rhs
= Stack::handleMut(sp
);
2906 MutableHandleValue result
= Stack::handleMut(sp
+ 1);
2909 if (!SubOperation(cx
, lhs
, rhs
, result
)) {
2917 goto generic_binary
;
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)))) {
2928 sp
[0] = StackVal(Int32Value(int32_t(product
)));
2933 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
2934 double lhs
= sp
[1].asValue().toNumber();
2935 double rhs
= sp
[0].asValue().toNumber();
2937 sp
[0] = StackVal(NumberValue(lhs
* rhs
));
2942 MutableHandleValue lhs
= Stack::handleMut(sp
+ 1);
2943 MutableHandleValue rhs
= Stack::handleMut(sp
);
2944 MutableHandleValue result
= Stack::handleMut(sp
+ 1);
2947 if (!MulOperation(cx
, lhs
, rhs
, result
)) {
2955 goto generic_binary
;
2958 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
2959 double lhs
= sp
[1].asValue().toNumber();
2960 double rhs
= sp
[0].asValue().toNumber();
2962 sp
[0] = StackVal(NumberValue(NumberDiv(lhs
, rhs
)));
2967 MutableHandleValue lhs
= Stack::handleMut(sp
+ 1);
2968 MutableHandleValue rhs
= Stack::handleMut(sp
);
2969 MutableHandleValue result
= Stack::handleMut(sp
+ 1);
2972 if (!DivOperation(cx
, lhs
, rhs
, result
)) {
2980 goto generic_binary
;
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
;
2989 sp
[0] = StackVal(Int32Value(int32_t(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();
2998 sp
[0] = StackVal(DoubleValue(NumberMod(lhs
, rhs
)));
3003 MutableHandleValue lhs
= Stack::handleMut(sp
+ 1);
3004 MutableHandleValue rhs
= Stack::handleMut(sp
);
3005 MutableHandleValue result
= Stack::handleMut(sp
+ 1);
3008 if (!ModOperation(cx
, lhs
, rhs
, result
)) {
3016 goto generic_binary
;
3019 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
3020 double lhs
= sp
[1].asValue().toNumber();
3021 double rhs
= sp
[0].asValue().toNumber();
3023 sp
[0] = StackVal(NumberValue(ecmaPow(lhs
, rhs
)));
3028 MutableHandleValue lhs
= Stack::handleMut(sp
+ 1);
3029 MutableHandleValue rhs
= Stack::handleMut(sp
);
3030 MutableHandleValue result
= Stack::handleMut(sp
+ 1);
3033 if (!PowOperation(cx
, lhs
, rhs
, result
)) {
3041 goto generic_binary
;
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();
3048 sp
[0] = StackVal(Int32Value(lhs
| rhs
));
3052 goto generic_binary
;
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();
3059 sp
[0] = StackVal(Int32Value(lhs
& rhs
));
3063 goto generic_binary
;
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();
3070 sp
[0] = StackVal(Int32Value(lhs
^ rhs
));
3074 goto generic_binary
;
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());
3084 sp
[0] = StackVal(Int32Value(int32_t(lhs
<< rhs
)));
3088 goto generic_binary
;
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();
3096 sp
[0] = StackVal(Int32Value(lhs
>> rhs
));
3100 goto generic_binary
;
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();
3108 uint32_t result
= lhs
>> rhs
;
3109 if (result
<= uint32_t(INT32_MAX
)) {
3110 sp
[0] = StackVal(Int32Value(int32_t(result
)));
3112 sp
[0] = StackVal(NumberValue(double(result
)));
3117 goto 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
);
3134 INVOKE_IC(BinaryArith
);
3140 if (sp
[0].asValue().isInt32() && sp
[1].asValue().isInt32()) {
3141 bool result
= sp
[0].asValue().toInt32() == sp
[1].asValue().toInt32();
3143 sp
[0] = StackVal(BooleanValue(result
));
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
;
3152 sp
[0] = StackVal(BooleanValue(result
));
3156 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
3157 bool result
= sp
[0].asValue().toNumber() == sp
[1].asValue().toNumber();
3159 sp
[0] = StackVal(BooleanValue(result
));
3167 if (sp
[0].asValue().isInt32() && sp
[1].asValue().isInt32()) {
3168 bool result
= sp
[0].asValue().toInt32() != sp
[1].asValue().toInt32();
3170 sp
[0] = StackVal(BooleanValue(result
));
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
;
3179 sp
[0] = StackVal(BooleanValue(result
));
3183 if (sp
[0].asValue().isNumber() && sp
[1].asValue().isNumber()) {
3184 bool result
= sp
[0].asValue().toNumber() != sp
[1].asValue().toNumber();
3186 sp
[0] = StackVal(BooleanValue(result
));
3194 if (sp
[0].asValue().isInt32() && sp
[1].asValue().isInt32()) {
3195 bool result
= sp
[1].asValue().toInt32() < sp
[0].asValue().toInt32();
3197 sp
[0] = StackVal(BooleanValue(result
));
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
)) {
3209 sp
[0] = StackVal(BooleanValue(result
));
3216 if (sp
[0].asValue().isInt32() && sp
[1].asValue().isInt32()) {
3217 bool result
= sp
[1].asValue().toInt32() <= sp
[0].asValue().toInt32();
3219 sp
[0] = StackVal(BooleanValue(result
));
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
)) {
3231 sp
[0] = StackVal(BooleanValue(result
));
3238 if (sp
[0].asValue().isInt32() && sp
[1].asValue().isInt32()) {
3239 bool result
= sp
[1].asValue().toInt32() > sp
[0].asValue().toInt32();
3241 sp
[0] = StackVal(BooleanValue(result
));
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
)) {
3253 sp
[0] = StackVal(BooleanValue(result
));
3260 if (sp
[0].asValue().isInt32() && sp
[1].asValue().isInt32()) {
3261 bool result
= sp
[1].asValue().toInt32() >= sp
[0].asValue().toInt32();
3263 sp
[0] = StackVal(BooleanValue(result
));
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
)) {
3275 sp
[0] = StackVal(BooleanValue(result
));
3286 HandleValue lval
= Stack::handle(sp
+ 1);
3287 HandleValue rval
= Stack::handle(sp
);
3288 if (sp
[0].asValue().isString() && sp
[1].asValue().isString()) {
3290 if (!js::StrictlyEqual(cx
, lval
, rval
, &result
)) {
3294 if (!js::StrictlyEqual(nullptr, lval
, rval
, &result
)) {
3300 BooleanValue((JSOp(*pc
) == JSOp::StrictEq
) ? result
: !result
));
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
);
3326 INVOKE_IC(InstanceOf
);
3339 CASE(ToPropertyKey
) {
3341 INVOKE_IC(ToPropertyKey
);
3343 END_OP(ToPropertyKey
);
3347 if (sp
[0].asValue().isString()) {
3351 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
3352 if (JSString
* result
=
3353 ToStringSlow
<NoGC
>(frameMgr
.cxForLocalUseOnly(), value0
)) {
3354 PUSH(StackVal(StringValue(result
)));
3358 result
= ToString
<CanGC
>(cx
, value0
);
3363 PUSH(StackVal(StringValue(result
)));
3369 CASE(IsNullOrUndefined
) {
3370 bool result
= sp
[0].asValue().isNull() || sp
[0].asValue().isUndefined();
3371 PUSH(StackVal(BooleanValue(result
)));
3372 END_OP(IsNullOrUndefined
);
3376 PUSH(StackVal(ObjectValue(*frameMgr
.cxForLocalUseOnly()
3378 ->lexicalEnvironment()
3383 CASE(NonSyntacticGlobalThis
) {
3385 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
3386 ReservedRooted
<Value
> value0(&state
.value0
);
3389 js::GetNonSyntacticGlobalThis(cx
, obj0
, &value0
);
3391 PUSH(StackVal(value0
));
3393 END_OP(NonSyntacticGlobalThis
);
3397 PUSH(StackVal(frame
->newTarget()));
3401 CASE(DynamicImport
) {
3403 ReservedRooted
<Value
> value0(&state
.value0
,
3404 POP().asValue()); // options
3405 ReservedRooted
<Value
> value1(&state
.value1
,
3406 POP().asValue()); // specifier
3410 promise
= StartDynamicModuleImport(cx
, script
, value1
, value0
);
3415 PUSH(StackVal(ObjectValue(*promise
)));
3417 END_OP(DynamicImport
);
3421 JSObject
* metaObject
;
3424 metaObject
= ImportMetaOperation(cx
, script
);
3429 PUSH(StackVal(ObjectValue(*metaObject
)));
3438 obj
= NewObjectOperation(cx
, script
, pc
);
3443 PUSH(StackVal(ObjectValue(*obj
)));
3447 INVOKE_IC(NewObject
);
3457 obj
= NewObjectOperation(cx
, script
, pc
);
3462 PUSH(StackVal(ObjectValue(*obj
)));
3466 INVOKE_IC(NewObject
);
3472 PUSH(StackVal(ObjectValue(*script
->getObject(pc
))));
3475 CASE(ObjWithProto
) {
3477 ReservedRooted
<Value
> value0(&state
.value0
, sp
[0].asValue());
3481 obj
= ObjectWithProtoOperation(cx
, value0
);
3486 sp
[0] = StackVal(ObjectValue(*obj
));
3488 END_OP(ObjWithProto
);
3492 CASE(InitHiddenElem
)
3493 CASE(InitLockedElem
)
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];
3505 IC_SET_ARG_FROM_STACK(0, 0);
3506 if (JSOp(*pc
) == JSOp::SetElem
|| JSOp(*pc
) == JSOp::StrictSetElem
) {
3510 if (JSOp(*pc
) == JSOp::InitElemInc
) {
3512 Int32Value(Value::fromRawBits(icregs
.icVals
[1]).toInt32() + 1)));
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
));
3534 if (!InitPropGetterSetterOperation(cx
, pc
, obj0
, name0
, obj1
)) {
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
3559 if (!InitElemGetterSetterOperation(cx
, pc
, obj0
, value0
, obj1
)) {
3564 END_OP(InitElemGetter
);
3568 CASE(GetBoundName
) {
3569 static_assert(JSOpLength_GetProp
== JSOpLength_GetBoundName
);
3575 CASE(GetPropSuper
) {
3578 INVOKE_IC(GetPropSuper
);
3580 END_OP(GetPropSuper
);
3584 HandleValue lhs
= Stack::handle(&sp
[1]);
3585 HandleValue rhs
= Stack::handle(&sp
[0]);
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
)));
3602 if (lhs
.isObject()) {
3603 JSObject
* obj
= &lhs
.toObject();
3605 if (GetElementNoGC(frameMgr
.cxForLocalUseOnly(), obj
, lhs
, index
,
3607 sp
[1] = StackVal(ret
);
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.
3629 INVOKE_IC(GetElemSuper
);
3631 END_OP(GetElemSuper
);
3636 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
3637 ReservedRooted
<PropertyName
*> name0(&state
.name0
, script
->getName(pc
));
3641 if (!DelPropOperation
<false>(cx
, value0
, name0
, &res
)) {
3645 PUSH(StackVal(BooleanValue(res
)));
3649 CASE(StrictDelProp
) {
3651 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
3652 ReservedRooted
<PropertyName
*> name0(&state
.name0
, script
->getName(pc
));
3656 if (!DelPropOperation
<true>(cx
, value0
, name0
, &res
)) {
3660 PUSH(StackVal(BooleanValue(res
)));
3662 END_OP(StrictDelProp
);
3666 ReservedRooted
<Value
> value1(&state
.value1
, POP().asValue());
3667 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
3671 if (!DelElemOperation
<false>(cx
, value0
, value1
, &res
)) {
3675 PUSH(StackVal(BooleanValue(res
)));
3679 CASE(StrictDelElem
) {
3681 ReservedRooted
<Value
> value1(&state
.value1
, POP().asValue());
3682 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
3686 if (!DelElemOperation
<true>(cx
, value0
, value1
, &res
)) {
3690 PUSH(StackVal(BooleanValue(res
)));
3692 END_OP(StrictDelElem
);
3703 CASE(CheckPrivateField
) {
3704 IC_SET_ARG_FROM_STACK(1, 0);
3705 IC_SET_ARG_FROM_STACK(0, 1);
3706 INVOKE_IC(CheckPrivateField
);
3708 END_OP(CheckPrivateField
);
3711 CASE(NewPrivateName
) {
3713 ReservedRooted
<JSAtom
*> atom0(&state
.atom0
, script
->getAtom(pc
));
3717 symbol
= NewPrivateName(cx
, atom0
);
3722 PUSH(StackVal(SymbolValue(symbol
)));
3724 END_OP(NewPrivateName
);
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
)));
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
));
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
)) {
3760 PUSH(StackVal(value2
));
3762 END_OP(SetPropSuper
);
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
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
)) {
3784 PUSH(StackVal(value3
)); // value
3786 END_OP(SetElemSuper
);
3791 INVOKE_IC(GetIterator
);
3797 // iter => iter, name
3798 Value v
= IteratorMore(&sp
[0].asValue().toObject());
3804 // iter => iter, bool
3805 bool result
= sp
[0].asValue().isMagic(JS_NO_ITER_VALUE
);
3806 PUSH(StackVal(BooleanValue(result
)));
3811 // iter, interval =>
3813 CloseIterator(&POP().asValue().toObject());
3818 IC_SET_OBJ_ARG(0, &POP().asValue().toObject());
3819 INVOKE_IC(CloseIter
);
3824 if (!sp
[0].asValue().isObject()) {
3827 js::ThrowCheckIsObject(cx
, js::CheckIsObjectKind(GET_UINT8(pc
))));
3828 /* abandon frame; error handler will re-establish sp */
3834 CASE(CheckObjCoercible
) {
3836 ReservedRooted
<Value
> value0(&state
.value0
, sp
[0].asValue());
3837 if (value0
.isNullOrUndefined()) {
3839 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx
, value0
));
3840 /* abandon frame; error handler will re-establish sp */
3844 END_OP(CheckObjCoercible
);
3848 // iter, next => asynciter
3850 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue()); // next
3851 ReservedRooted
<JSObject
*> obj0(&state
.obj0
,
3852 &POP().asValue().toObject()); // iter
3856 result
= CreateAsyncFromSyncIterator(cx
, obj0
, value0
);
3861 PUSH(StackVal(ObjectValue(*result
)));
3863 END_OP(ToAsyncIter
);
3867 // obj, protoVal => obj
3869 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
3870 ReservedRooted
<JSObject
*> obj0(&state
.obj0
,
3871 &sp
[0].asValue().toObject());
3874 if (!MutatePrototype(cx
, obj0
.as
<PlainObject
>(), value0
)) {
3879 END_OP(MutateProto
);
3887 uint32_t length
= GET_UINT32(pc
);
3888 obj
= NewArrayOperation(cx
, length
);
3893 PUSH(StackVal(ObjectValue(*obj
)));
3897 INVOKE_IC(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());
3911 InitElemArrayOperation(cx
, pc
, obj0
.as
<ArrayObject
>(), value0
);
3914 END_OP(InitElemArray
);
3918 PUSH(StackVal(MagicValue(JS_ELEMENTS_HOLE
)));
3926 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, script
->getRegExp(pc
));
3927 obj
= CloneRegExpObject(cx
, obj0
.as
<RegExpObject
>());
3932 PUSH(StackVal(ObjectValue(*obj
)));
3938 ReservedRooted
<JSFunction
*> fun0(&state
.fun0
, script
->getFunction(pc
));
3939 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
3943 res
= js::Lambda(cx
, fun0
, obj0
);
3948 PUSH(StackVal(ObjectValue(*res
)));
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
));
3962 if (!SetFunctionName(cx
, fun0
, value0
, prefixKind
)) {
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());
3990 if (!CheckClassHeritageOperation(cx
, value0
)) {
3995 END_OP(CheckClassHeritage
);
3998 CASE(FunWithProto
) {
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
));
4008 obj
= FunWithProtoOperation(cx
, fun0
, obj1
, obj0
);
4013 PUSH(StackVal(ObjectValue(*obj
)));
4015 END_OP(FunWithProto
);
4018 CASE(BuiltinObject
) {
4019 auto kind
= BuiltinObjectKind(GET_UINT8(pc
));
4023 builtin
= BuiltinObjectOperation(cx
, kind
);
4028 PUSH(StackVal(ObjectValue(*builtin
)));
4029 END_OP(BuiltinObject
);
4036 CASE(CallContentIter
)
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
);
4053 (op
== JSOp::New
|| op
== JSOp::NewContent
|| op
== JSOp::SuperCall
);
4054 uint32_t argc
= GET_ARGC(pc
);
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 +
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");
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");
4087 if (!constructing
&& func
->isClassConstructor()) {
4088 TRACE_PRINTF("missed fastpath: constructor called without `new`\n");
4091 if (!func
->baseScript()->hasBytecode()) {
4092 TRACE_PRINTF("missed fastpath: no bytecode\n");
4095 ReservedRooted
<JSScript
*> calleeScript(
4096 &state
.script0
, func
->baseScript()->asJSScript());
4097 if (!calleeScript
->hasJitScript()) {
4098 TRACE_PRINTF("missed fastpath: no jit-script\n");
4101 if (frameMgr
.cxForLocalUseOnly()->realm() != calleeScript
->realm()) {
4102 TRACE_PRINTF("missed fastpath: mismatched realm\n");
4105 if (argc
< func
->nargs()) {
4106 TRACE_PRINTF("missed fastpath: not enough arguments\n");
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
;
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");
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());
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
)) {
4141 TRACE_PRINTF("created %" PRIx64
"\n", thisv
.get().asRawBits());
4145 // 0. Save current PC in current frame, so we can retrieve
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.
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
++) {
4168 // 4. Push inter-frame content: callee token, descriptor for
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
);
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())) {
4190 ReportOverRecursed(frameMgr
.cxForLocalUseOnly());
4193 // 8. Push local slots, and set return value to `undefined` by
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()) {
4203 if (!js::InitFunctionEnvironmentObjects(cx
, frame
)) {
4207 // 10. Set debug flag, if appropriate.
4208 if (script
->isDebuggee()) {
4209 TRACE_PRINTF("Script is debuggee\n");
4210 frame
->setIsDebuggee();
4213 if (!DebugPrologue(cx
, frame
)) {
4217 // 11. Check for interrupts.
4219 if (frameMgr
.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
4221 if (!InterruptCheck(cx
)) {
4226 // 12. Initialize coverage tables, if needed.
4227 if (!script
->hasScriptCounts()) {
4228 if (frameMgr
.cxForLocalUseOnly()
4230 ->collectCoverageForDebug()) {
4232 if (!script
->initScriptCounts(cx
)) {
4237 COUNT_COVERAGE_MAIN();
4240 // Everything is switched to callee context now -- dispatch!
4244 // Slow path: use the IC!
4245 icregs
.icVals
[0] = argc
;
4246 icregs
.extraArgs
= 2 + constructing
;
4247 icregs
.spreadCall
= false;
4249 POPN(argc
+ 2 + constructing
);
4250 PUSH(StackVal(Value::fromRawBits(icregs
.icResult
)));
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;
4264 PUSH(StackVal(Value::fromRawBits(icregs
.icResult
)));
4268 CASE(SpreadSuperCall
)
4270 static_assert(JSOpLength_SpreadSuperCall
== JSOpLength_SpreadNew
);
4271 icregs
.icVals
[0] = 1;
4272 icregs
.extraArgs
= 3;
4273 icregs
.spreadCall
= true;
4276 PUSH(StackVal(Value::fromRawBits(icregs
.icResult
)));
4277 END_OP(SpreadSuperCall
);
4280 CASE(OptimizeSpreadCall
) {
4282 INVOKE_IC(OptimizeSpreadCall
);
4284 END_OP(OptimizeSpreadCall
);
4287 CASE(OptimizeGetIterator
) {
4289 INVOKE_IC(OptimizeGetIterator
);
4291 END_OP(OptimizeGetIterator
);
4294 CASE(ImplicitThis
) {
4296 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
4297 ReservedRooted
<PropertyName
*> name0(&state
.name0
, script
->getName(pc
));
4299 if (!ImplicitThisOperation(cx
, obj0
, name0
, &state
.res
)) {
4303 PUSH(StackVal(state
.res
));
4304 state
.res
.setUndefined();
4305 END_OP(ImplicitThis
);
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
);
4323 JSObject
* superEnvFunc
= &POP().asValue().toObject();
4324 JSObject
* superFun
= SuperFunOperation(superEnvFunc
);
4325 PUSH(StackVal(ObjectOrNullValue(superFun
)));
4330 if (sp
[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL
)) {
4332 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx
));
4338 CASE(CheckThisReinit
) {
4339 if (!sp
[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL
)) {
4341 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx
));
4344 END_OP(CheckThisReinit
);
4348 JSObject
* generator
;
4351 generator
= CreateGeneratorFromFrame(cx
, frame
);
4356 PUSH(StackVal(ObjectValue(*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
);
4366 if (!NormalSuspend(cx
, obj0
, frame
, frameSize
, pc
)) {
4370 frame
->setReturnValue(sp
[0].asValue());
4376 // rval1, gen => rval2, gen, resumeKind
4377 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, &POP().asValue().toObject());
4378 uint32_t frameSize
= stack
.frameSize(sp
, frame
);
4381 if (!NormalSuspend(cx
, obj0
, frame
, frameSize
, pc
)) {
4385 frame
->setReturnValue(sp
[0].asValue());
4389 CASE(FinalYieldRval
) {
4391 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, &POP().asValue().toObject());
4394 if (!FinalSuspend(cx
, obj0
, pc
)) {
4401 CASE(IsGenClosing
) {
4402 bool result
= sp
[0].asValue() == MagicValue(JS_GENERATOR_CLOSING
);
4403 PUSH(StackVal(BooleanValue(result
)));
4404 END_OP(IsGenClosing
);
4408 // value, gen => promise
4411 ReservedRooted
<JSObject
*> obj0(&state
.obj0
,
4412 &POP().asValue().toObject()); // gen
4413 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue()); // value
4415 promise
= AsyncFunctionAwait(
4416 cx
, obj0
.as
<AsyncFunctionGeneratorObject
>(), value0
);
4421 PUSH(StackVal(ObjectValue(*promise
)));
4425 CASE(AsyncResolve
) {
4426 // value, gen => promise
4429 ReservedRooted
<JSObject
*> obj0(&state
.obj0
,
4430 &POP().asValue().toObject()); // gen
4431 ReservedRooted
<Value
> value0(&state
.value0
,
4432 POP().asValue()); // value
4434 promise
= AsyncFunctionResolve(
4435 cx
, obj0
.as
<AsyncFunctionGeneratorObject
>(), value0
);
4440 PUSH(StackVal(ObjectValue(*promise
)));
4441 END_OP(AsyncResolve
);
4445 // reason, gen => 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
4455 promise
= AsyncFunctionReject(
4456 cx
, obj0
.as
<AsyncFunctionGeneratorObject
>(), value1
, value0
);
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());
4471 if (!CanSkipAwait(cx
, value0
, &result
)) {
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()) {
4486 if (!ExtractAwaitValue(cx
, value0
, &value0
)) {
4490 PUSH(StackVal(value0
));
4491 PUSH(StackVal(can_skip
));
4493 END_OP(MaybeExtractAwaitValue
);
4497 GeneratorResumeKind resumeKind
= ResumeKindFromPC(pc
);
4498 PUSH(StackVal(Int32Value(int32_t(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
) {
4512 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(
4513 cx
, frame
, obj0
.as
<AbstractGeneratorObject
>(), value0
,
4518 END_OP(CheckResumeKind
);
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());
4529 TRACE_PRINTF("Going to C++ interp for Resume\n");
4530 if (!InterpretResume(cx
, obj0
, callerSP
, &value0
)) {
4535 sp
[0] = StackVal(value0
);
4541 int32_t icIndex
= GET_INT32(pc
);
4542 frame
->interpreterICEntry() = frame
->icScript()->icEntries() + icIndex
;
4543 COUNT_COVERAGE_PC(pc
);
4547 int32_t icIndex
= GET_INT32(pc
);
4548 frame
->interpreterICEntry() = frame
->icScript()->icEntries() + icIndex
;
4550 if (frameMgr
.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
4552 if (!InterruptCheck(cx
)) {
4557 COUNT_COVERAGE_PC(pc
);
4561 int32_t icIndex
= GET_INT32(pc
);
4562 frame
->interpreterICEntry() = frame
->icScript()->icEntries() + icIndex
;
4563 if (script
->isDebuggee()) {
4564 TRACE_PRINTF("doing DebugAfterYield\n");
4566 if (DebugAPI::hasAnyBreakpointsOrStepMode(script
) &&
4567 !HandleDebugTrap(cx
, frame
, pc
)) {
4568 TRACE_PRINTF("HandleDebugTrap returned error\n");
4571 if (!DebugAfterYield(cx
, frame
)) {
4572 TRACE_PRINTF("DebugAfterYield returned error\n");
4576 COUNT_COVERAGE_PC(pc
);
4581 ADVANCE(GET_JUMP_OFFSET(pc
));
4582 PREDICT_NEXT(JumpTarget
);
4583 PREDICT_NEXT(LoopHead
);
4588 if (!sp
[0].asValue().isNullOrUndefined()) {
4589 ADVANCE(GET_JUMP_OFFSET(pc
));
4597 bool cond
= POP().asValue().toBoolean();
4600 ADVANCE(GET_JUMP_OFFSET(pc
));
4609 ADVANCE(GET_JUMP_OFFSET(pc
));
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();
4621 } else if (!v
.isDouble() ||
4622 !mozilla::NumberEqualsInt32(v
.toDouble(), &i
)) {
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
);
4637 frame
->setReturnValue(POP().asValue());
4642 PUSH(StackVal(frame
->returnValue()));
4647 frame
->setReturnValue(POP().asValue());
4654 if (frame
->isDebuggee() && !from_unwind
) {
4655 TRACE_PRINTF("doing DebugEpilogueOnBaselineReturn\n");
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
;
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.
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
4701 POPN(argc
+ 2 + constructing
);
4702 // Push return value.
4703 PUSH(StackVal(ret
));
4709 // Advance past call instruction, and advance past IC.
4711 ADVANCE(JSOpLength_Call
);
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()) {
4726 MOZ_ALWAYS_FALSE(ReportValueError(cx
, JSMSG_BAD_DERIVED_RETURN
,
4727 JSDVG_IGNORE_STACK
, retVal
, nullptr));
4729 } else if (thisval
.isMagic(JS_UNINITIALIZED_LEXICAL
)) {
4731 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx
));
4734 PUSH(StackVal(thisval
));
4736 END_OP(CheckReturn
);
4741 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
4743 MOZ_ALWAYS_FALSE(ThrowOperation(cx
, value0
));
4749 CASE(ThrowWithStack
) {
4751 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
4752 ReservedRooted
<Value
> value1(&state
.value1
, POP().asValue());
4754 MOZ_ALWAYS_FALSE(ThrowWithStackOperation(cx
, value1
, value0
));
4757 END_OP(ThrowWithStack
);
4763 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx
, GET_UINT8(pc
)));
4769 CASE(ThrowSetConst
) {
4772 ReportRuntimeLexicalError(cx
, JSMSG_BAD_CONST_ASSIGN
, script
, pc
);
4775 END_OP(ThrowSetConst
);
4779 CASE(TryDestructuring
) {
4780 static_assert(JSOpLength_Try
== JSOpLength_TryDestructuring
);
4787 if (!GetAndClearException(cx
, &state
.res
)) {
4791 PUSH(StackVal(state
.res
));
4792 state
.res
.setUndefined();
4796 CASE(ExceptionAndStack
) {
4798 ReservedRooted
<Value
> value0(&state
.value0
);
4801 if (!cx
.getCx()->getPendingExceptionStack(&value0
)) {
4804 if (!GetAndClearException(cx
, &state
.res
)) {
4808 PUSH(StackVal(state
.res
));
4809 PUSH(StackVal(value0
));
4810 state
.res
.setUndefined();
4812 END_OP(ExceptionAndStack
);
4817 if (frameMgr
.cxForLocalUseOnly()->hasAnyPendingInterrupt()) {
4819 if (!InterruptCheck(cx
)) {
4827 CASE(Uninitialized
) {
4828 PUSH(StackVal(MagicValue(JS_UNINITIALIZED_LEXICAL
)));
4829 END_OP(Uninitialized
);
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
)) {
4846 ReportRuntimeLexicalError(cx
, JSMSG_UNINITIALIZED_LEXICAL
, script
, pc
);
4849 END_OP(CheckLexical
);
4851 CASE(CheckAliasedLexical
) {
4852 if (sp
[0].asValue().isMagic(JS_UNINITIALIZED_LEXICAL
)) {
4854 ReportRuntimeLexicalError(cx
, JSMSG_UNINITIALIZED_LEXICAL
, script
, pc
);
4857 END_OP(CheckAliasedLexical
);
4862 0, &frameMgr
.cxForLocalUseOnly()->global()->lexicalEnvironment());
4863 INVOKE_IC(BindName
);
4868 IC_SET_OBJ_ARG(0, frame
->environmentChain());
4869 INVOKE_IC(BindName
);
4875 0, &frameMgr
.cxForLocalUseOnly()->global()->lexicalEnvironment());
4881 IC_SET_OBJ_ARG(0, frame
->environmentChain());
4888 unsigned i
= GET_ARGNO(pc
);
4889 if (script
->argsObjAliasesFormals()) {
4890 PUSH(StackVal(frame
->argsObj().arg(i
)));
4892 PUSH(StackVal(frame
->unaliasedFormal(i
)));
4898 uint32_t i
= GET_ARGNO(pc
);
4899 PUSH(StackVal(frame
->unaliasedFormal(i
, DONT_CHECK_ALIASING
)));
4900 END_OP(GetFrameArg
);
4904 uint32_t i
= GET_LOCALNO(pc
);
4905 TRACE_PRINTF(" -> local: %d\n", int(i
));
4906 PUSH(StackVal(frame
->unaliasedLocal(i
)));
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
);
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
);
4933 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
4934 ReservedRooted
<Value
> value0(&state
.value0
);
4937 if (!GetImportOperation(cx
, obj0
, script
, pc
, &value0
)) {
4941 PUSH(StackVal(value0
));
4946 CASE(GetIntrinsic
) {
4947 INVOKE_IC(GetIntrinsic
);
4949 END_OP(GetIntrinsic
);
4953 PUSH(StackVal(frame
->calleev()));
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())));
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
);
4980 PUSH(StackVal(icregs
.icVals
[1]));
4986 CASE(InitHiddenProp
)
4987 CASE(InitLockedProp
) {
4988 static_assert(JSOpLength_InitProp
== JSOpLength_InitHiddenProp
);
4989 static_assert(JSOpLength_InitProp
== JSOpLength_InitLockedProp
);
4991 IC_SET_ARG_FROM_STACK(0, 0);
4995 CASE(InitGLexical
) {
4996 IC_SET_ARG_FROM_STACK(1, 0);
4998 0, &frameMgr
.cxForLocalUseOnly()->global()->lexicalEnvironment());
5000 END_OP(InitGLexical
);
5004 unsigned i
= GET_ARGNO(pc
);
5005 if (script
->argsObjAliasesFormals()) {
5006 frame
->argsObj().setArg(i
, sp
[0].asValue());
5008 frame
->unaliasedFormal(i
) = sp
[0].asValue();
5014 uint32_t i
= GET_LOCALNO(pc
);
5015 TRACE_PRINTF(" -> local: %d\n", int(i
));
5016 frame
->unaliasedLocal(i
) = sp
[0].asValue();
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());
5033 if (!SetIntrinsicOperation(cx
, script
, pc
, value0
)) {
5038 END_OP(SetIntrinsic
);
5041 CASE(PushLexicalEnv
) {
5043 ReservedRooted
<Scope
*> scope0(&state
.scope0
, script
->getScope(pc
));
5046 if (!frame
->pushLexicalEnvironment(cx
, scope0
.as
<LexicalScope
>())) {
5051 END_OP(PushLexicalEnv
);
5053 CASE(PopLexicalEnv
) {
5054 if (frame
->isDebuggee()) {
5055 TRACE_PRINTF("doing DebugLeaveThenPopLexicalEnv\n");
5057 if (!DebugLeaveThenPopLexicalEnv(cx
, frame
, pc
)) {
5061 frame
->popOffEnvironmentChain
<LexicalEnvironmentObject
>();
5063 END_OP(PopLexicalEnv
);
5065 CASE(DebugLeaveLexicalEnv
) {
5066 if (frame
->isDebuggee()) {
5067 TRACE_PRINTF("doing DebugLeaveLexicalEnv\n");
5069 if (!DebugLeaveLexicalEnv(cx
, frame
, pc
)) {
5073 END_OP(DebugLeaveLexicalEnv
);
5076 CASE(RecreateLexicalEnv
) {
5079 if (frame
->isDebuggee()) {
5080 TRACE_PRINTF("doing DebugLeaveThenRecreateLexicalEnv\n");
5081 if (!DebugLeaveThenRecreateLexicalEnv(cx
, frame
, pc
)) {
5085 if (!frame
->recreateLexicalEnvironment(cx
)) {
5090 END_OP(RecreateLexicalEnv
);
5093 CASE(FreshenLexicalEnv
) {
5096 if (frame
->isDebuggee()) {
5097 TRACE_PRINTF("doing DebugLeaveThenFreshenLexicalEnv\n");
5098 if (!DebugLeaveThenFreshenLexicalEnv(cx
, frame
, pc
)) {
5102 if (!frame
->freshenLexicalEnvironment(cx
)) {
5107 END_OP(FreshenLexicalEnv
);
5109 CASE(PushClassBodyEnv
) {
5111 ReservedRooted
<Scope
*> scope0(&state
.scope0
, script
->getScope(pc
));
5113 if (!frame
->pushClassBodyEnvironment(cx
, scope0
.as
<ClassBodyScope
>())) {
5117 END_OP(PushClassBodyEnv
);
5121 ReservedRooted
<Scope
*> scope0(&state
.scope0
, script
->getScope(pc
));
5123 if (!frame
->pushVarEnvironment(cx
, scope0
)) {
5131 ReservedRooted
<Scope
*> scope0(&state
.scope0
, script
->getScope(pc
));
5132 ReservedRooted
<Value
> value0(&state
.value0
, POP().asValue());
5134 if (!EnterWithOperation(cx
, frame
, value0
, scope0
.as
<WithScope
>())) {
5141 frame
->popOffEnvironmentChain
<WithEnvironmentObject
>();
5147 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
5149 varObj
= BindVarOperation(cx
, obj0
);
5151 PUSH(StackVal(ObjectValue(*varObj
)));
5155 CASE(GlobalOrEvalDeclInstantiation
) {
5156 GCThingIndex lastFun
= GET_GCTHING_INDEX(pc
);
5158 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
5160 if (!GlobalOrEvalDeclInstantiation(cx
, obj0
, script
, lastFun
)) {
5164 END_OP(GlobalOrEvalDeclInstantiation
);
5169 ReservedRooted
<PropertyName
*> name0(&state
.name0
, script
->getName(pc
));
5170 ReservedRooted
<JSObject
*> obj0(&state
.obj0
, frame
->environmentChain());
5172 if (!DeleteNameOperation(cx
, name0
, obj0
, &state
.res
)) {
5176 PUSH(StackVal(state
.res
));
5177 state
.res
.setUndefined();
5184 if (!NewArgumentsObject(cx
, frame
, &state
.res
)) {
5188 PUSH(StackVal(state
.res
));
5189 state
.res
.setUndefined();
5199 CASE(FunctionThis
) {
5202 if (!js::GetFunctionThis(cx
, frame
, &state
.res
)) {
5206 PUSH(StackVal(state
.res
));
5207 state
.res
.setUndefined();
5208 END_OP(FunctionThis
);
5216 uint32_t n
= GET_UINT16(pc
);
5221 StackVal value
= sp
[0];
5226 StackVal value1
= sp
[0];
5227 StackVal value2
= sp
[1];
5233 unsigned i
= GET_UINT24(pc
);
5234 StackVal value
= sp
[i
];
5239 std::swap(sp
[0], sp
[1]);
5243 unsigned i
= GET_UINT8(pc
);
5244 StackVal tmp
= sp
[i
];
5245 memmove(&sp
[1], &sp
[0], sizeof(StackVal
) * i
);
5250 unsigned i
= GET_UINT8(pc
);
5251 StackVal tmp
= sp
[0];
5252 memmove(&sp
[0], &sp
[1], sizeof(StackVal
) * i
);
5256 CASE(DebugCheckSelfHosted
) {
5257 HandleValue val
= Stack::handle(&sp
[0]);
5260 if (!Debug_CheckSelfHosted(cx
, val
)) {
5264 END_OP(DebugCheckSelfHosted
);
5266 CASE(Lineno
) { END_OP(Lineno
); }
5267 CASE(NopDestructuring
) { END_OP(NopDestructuring
); }
5268 CASE(ForceInterpreter
) { END_OP(ForceInterpreter
); }
5272 if (!OnDebuggerStatement(cx
, frame
)) {
5280 MOZ_CRASH("Bad opcode");
5284 TRACE_PRINTF("HandleException: frame %p\n", frame
);
5286 ResumeFromException rfe
;
5289 HandleException(&rfe
);
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
);
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
);
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
;
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");
5321 case ExceptionResumeKind::ForcedReturnIon
:
5323 "Unexpected ForcedReturnIon exception-resume kind in Portable "
5325 case ExceptionResumeKind::Bailout
:
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
:
5332 "Unexpected WasmCatch exception-resume kind in Portable "
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());
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());
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());
5395 TRACE_PRINTF("hit debug point\n");
5397 if (!HandleDebugTrap(cx
, frame
, pc
)) {
5398 TRACE_PRINTF("HandleDebugTrap returned error\n");
5401 pc
= frame
->interpreterPC();
5402 TRACE_PRINTF("HandleDebugTrap done\n");
5409 * -----------------------------------------------
5411 * -----------------------------------------------
5414 bool PortableBaselineTrampoline(JSContext
* cx
, size_t argc
, Value
* argv
,
5415 size_t numFormals
, size_t numActuals
,
5416 CalleeToken calleeToken
, JSObject
* envChain
,
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:
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.
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
)) {
5469 case PBIResult::UnwindRet
:
5470 TRACE_PRINTF("PBI returned Ok/UnwindRet with result %" PRIx64
"\n",
5471 result
->asRawBits());
5473 case PBIResult::Error
:
5474 case PBIResult::UnwindError
:
5475 TRACE_PRINTF("PBI returned Error/UnwindError\n");
5477 case PBIResult::Unwind
:
5478 MOZ_CRASH("Should not unwind out of top / entry frame");
5484 MethodStatus
CanEnterPortableBaselineInterpreter(JSContext
* cx
,
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
;
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
;