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 bytecode interpreter.
11 #include "vm/Interpreter-inl.h"
13 #include "mozilla/DebugOnly.h"
14 #include "mozilla/FloatingPoint.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/ScopeExit.h"
17 #include "mozilla/Sprintf.h"
18 #include "mozilla/TimeStamp.h"
19 #include "mozilla/WrappingOperations.h"
24 #include "jslibmath.h"
28 #include "builtin/Array.h"
29 #include "builtin/Eval.h"
30 #include "builtin/ModuleObject.h"
31 #include "builtin/Object.h"
32 #include "builtin/Promise.h"
34 #include "jit/AtomicOperations.h"
35 #include "jit/BaselineJIT.h"
37 #include "jit/JitRuntime.h"
38 #include "js/experimental/JitInfo.h" // JSJitInfo
39 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
40 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
41 #include "js/friend/WindowProxy.h" // js::IsWindowProxy
42 #include "js/Printer.h"
43 #include "util/CheckedArithmetic.h"
44 #include "util/StringBuffer.h"
45 #include "vm/AsyncFunction.h"
46 #include "vm/AsyncIteration.h"
47 #include "vm/BigIntType.h"
48 #include "vm/BytecodeUtil.h" // JSDVG_SEARCH_STACK
49 #include "vm/EqualityOperations.h" // js::StrictlyEqual
50 #include "vm/GeneratorObject.h"
51 #include "vm/Iteration.h"
52 #include "vm/JSAtomUtils.h" // AtomToPrintableString
53 #include "vm/JSContext.h"
54 #include "vm/JSFunction.h"
55 #include "vm/JSObject.h"
56 #include "vm/JSScript.h"
57 #include "vm/Opcodes.h"
59 #include "vm/PlainObject.h" // js::PlainObject
62 #include "vm/SharedStencil.h" // GCThingIndex
63 #include "vm/StringType.h"
64 #include "vm/ThrowMsgKind.h" // ThrowMsgKind
66 #ifdef ENABLE_RECORD_TUPLE
67 # include "vm/RecordType.h"
68 # include "vm/TupleType.h"
71 #include "builtin/Boolean-inl.h"
72 #include "debugger/DebugAPI-inl.h"
73 #include "vm/ArgumentsObject-inl.h"
74 #include "vm/EnvironmentObject-inl.h"
75 #include "vm/GeckoProfiler-inl.h"
76 #include "vm/JSScript-inl.h"
77 #include "vm/NativeObject-inl.h"
78 #include "vm/ObjectOperations-inl.h"
79 #include "vm/PlainObject-inl.h" // js::CopyInitializerObject, js::CreateThis
80 #include "vm/Probes-inl.h"
81 #include "vm/Stack-inl.h"
85 using mozilla::DebugOnly
;
86 using mozilla::NumberEqualsInt32
;
88 using js::jit::JitScript
;
91 static MOZ_ALWAYS_INLINE
bool LooseEqualityOp(JSContext
* cx
,
92 InterpreterRegs
& regs
) {
93 HandleValue rval
= regs
.stackHandleAt(-1);
94 HandleValue lval
= regs
.stackHandleAt(-2);
96 if (!LooselyEqual(cx
, lval
, rval
, &cond
)) {
101 regs
.sp
[-1].setBoolean(cond
);
105 JSObject
* js::BoxNonStrictThis(JSContext
* cx
, HandleValue thisv
) {
106 MOZ_ASSERT(!thisv
.isMagic());
108 if (thisv
.isNullOrUndefined()) {
109 return cx
->global()->lexicalEnvironment().thisObject();
112 if (thisv
.isObject()) {
113 return &thisv
.toObject();
116 return PrimitiveToObject(cx
, thisv
);
119 bool js::GetFunctionThis(JSContext
* cx
, AbstractFramePtr frame
,
120 MutableHandleValue res
) {
121 MOZ_ASSERT(frame
.isFunctionFrame());
122 MOZ_ASSERT(!frame
.callee()->isArrow());
124 if (frame
.thisArgument().isObject() || frame
.callee()->strict()) {
125 res
.set(frame
.thisArgument());
129 MOZ_ASSERT(!frame
.callee()->isSelfHostedBuiltin(),
130 "Self-hosted builtins must be strict");
132 RootedValue
thisv(cx
, frame
.thisArgument());
134 // If there is a NSVO on environment chain, use it as basis for fallback
135 // global |this|. This gives a consistent definition of global lexical
136 // |this| between function and global contexts.
138 // NOTE: If only non-syntactic WithEnvironments are on the chain, we use the
139 // global lexical |this| value. This is for compatibility with the Subscript
141 if (frame
.script()->hasNonSyntacticScope() && thisv
.isNullOrUndefined()) {
142 RootedObject
env(cx
, frame
.environmentChain());
144 if (IsNSVOLexicalEnvironment(env
) || IsGlobalLexicalEnvironment(env
)) {
145 res
.setObject(*GetThisObjectOfLexical(env
));
148 if (!env
->enclosingEnvironment()) {
149 // This can only happen in Debugger eval frames: in that case we
150 // don't always have a global lexical env, see EvaluateInEnv.
151 MOZ_ASSERT(env
->is
<GlobalObject
>());
152 res
.setObject(*GetThisObject(env
));
155 env
= env
->enclosingEnvironment();
159 JSObject
* obj
= BoxNonStrictThis(cx
, thisv
);
168 void js::GetNonSyntacticGlobalThis(JSContext
* cx
, HandleObject envChain
,
169 MutableHandleValue res
) {
170 RootedObject
env(cx
, envChain
);
172 if (IsExtensibleLexicalEnvironment(env
)) {
173 res
.setObject(*GetThisObjectOfLexical(env
));
176 if (!env
->enclosingEnvironment()) {
177 // This can only happen in Debugger eval frames: in that case we
178 // don't always have a global lexical env, see EvaluateInEnv.
179 MOZ_ASSERT(env
->is
<GlobalObject
>());
180 res
.setObject(*GetThisObject(env
));
183 env
= env
->enclosingEnvironment();
188 static bool IsSelfHostedOrKnownBuiltinCtor(JSFunction
* fun
, JSContext
* cx
) {
189 if (fun
->isSelfHostedOrIntrinsic()) {
193 // GetBuiltinConstructor in MapGroupBy
194 if (fun
== cx
->global()->maybeGetConstructor(JSProto_Map
)) {
198 // GetBuiltinConstructor in intlFallbackSymbol
199 if (fun
== cx
->global()->maybeGetConstructor(JSProto_Symbol
)) {
203 // ConstructorForTypedArray in MergeSortTypedArray
204 if (fun
== cx
->global()->maybeGetConstructor(JSProto_Int8Array
) ||
205 fun
== cx
->global()->maybeGetConstructor(JSProto_Uint8Array
) ||
206 fun
== cx
->global()->maybeGetConstructor(JSProto_Int16Array
) ||
207 fun
== cx
->global()->maybeGetConstructor(JSProto_Uint16Array
) ||
208 fun
== cx
->global()->maybeGetConstructor(JSProto_Int32Array
) ||
209 fun
== cx
->global()->maybeGetConstructor(JSProto_Uint32Array
) ||
210 fun
== cx
->global()->maybeGetConstructor(JSProto_Float32Array
) ||
211 fun
== cx
->global()->maybeGetConstructor(JSProto_Float64Array
) ||
212 fun
== cx
->global()->maybeGetConstructor(JSProto_Uint8ClampedArray
) ||
213 fun
== cx
->global()->maybeGetConstructor(JSProto_BigInt64Array
) ||
214 fun
== cx
->global()->maybeGetConstructor(JSProto_BigUint64Array
)) {
222 bool js::Debug_CheckSelfHosted(JSContext
* cx
, HandleValue funVal
) {
224 JSFunction
* fun
= &UncheckedUnwrap(&funVal
.toObject())->as
<JSFunction
>();
225 MOZ_ASSERT(IsSelfHostedOrKnownBuiltinCtor(fun
, cx
),
226 "functions directly called inside self-hosted JS must be one of "
227 "selfhosted function, self-hosted intrinsic, or known built-in "
230 MOZ_CRASH("self-hosted checks should only be done in Debug builds");
233 // This is purely to police self-hosted code. There is no actual operation.
237 static inline bool GetPropertyOperation(JSContext
* cx
,
238 Handle
<PropertyName
*> name
,
240 MutableHandleValue vp
) {
241 if (name
== cx
->names().length
&& GetLengthProperty(lval
, vp
)) {
245 return GetProperty(cx
, lval
, name
, vp
);
248 static inline bool GetNameOperation(JSContext
* cx
, HandleObject envChain
,
249 Handle
<PropertyName
*> name
, JSOp nextOp
,
250 MutableHandleValue vp
) {
251 /* Kludge to allow (typeof foo == "undefined") tests. */
252 if (nextOp
== JSOp::Typeof
) {
253 return GetEnvironmentName
<GetNameMode::TypeOf
>(cx
, envChain
, name
, vp
);
255 return GetEnvironmentName
<GetNameMode::Normal
>(cx
, envChain
, name
, vp
);
258 bool js::GetImportOperation(JSContext
* cx
, HandleObject envChain
,
259 HandleScript script
, jsbytecode
* pc
,
260 MutableHandleValue vp
) {
261 RootedObject
env(cx
), pobj(cx
);
262 Rooted
<PropertyName
*> name(cx
, script
->getName(pc
));
265 MOZ_ALWAYS_TRUE(LookupName(cx
, name
, envChain
, &env
, &pobj
, &prop
));
266 MOZ_ASSERT(env
&& env
->is
<ModuleEnvironmentObject
>());
267 MOZ_ASSERT(env
->as
<ModuleEnvironmentObject
>().hasImportBinding(name
));
268 return FetchName
<GetNameMode::Normal
>(cx
, env
, pobj
, name
, prop
, vp
);
271 static JSObject
* SuperFunOperation(JSObject
* callee
) {
272 MOZ_ASSERT(callee
->as
<JSFunction
>().isClassConstructor());
274 callee
->as
<JSFunction
>().baseScript()->isDerivedClassConstructor());
276 return callee
->as
<JSFunction
>().staticPrototype();
279 static JSObject
* HomeObjectSuperBase(JSObject
* homeObj
) {
280 MOZ_ASSERT(homeObj
->is
<PlainObject
>() || homeObj
->is
<JSFunction
>());
282 return homeObj
->staticPrototype();
285 bool js::ReportIsNotFunction(JSContext
* cx
, HandleValue v
, int numToSkip
,
286 MaybeConstruct construct
) {
287 unsigned error
= construct
? JSMSG_NOT_CONSTRUCTOR
: JSMSG_NOT_FUNCTION
;
288 int spIndex
= numToSkip
>= 0 ? -(numToSkip
+ 1) : JSDVG_SEARCH_STACK
;
290 ReportValueError(cx
, error
, spIndex
, v
, nullptr);
294 JSObject
* js::ValueToCallable(JSContext
* cx
, HandleValue v
, int numToSkip
,
295 MaybeConstruct construct
) {
296 if (v
.isObject() && v
.toObject().isCallable()) {
297 return &v
.toObject();
300 ReportIsNotFunction(cx
, v
, numToSkip
, construct
);
304 static bool MaybeCreateThisForConstructor(JSContext
* cx
, const CallArgs
& args
) {
305 if (args
.thisv().isObject()) {
309 RootedFunction
callee(cx
, &args
.callee().as
<JSFunction
>());
310 RootedObject
newTarget(cx
, &args
.newTarget().toObject());
312 MOZ_ASSERT(callee
->hasBytecode());
314 if (!CreateThis(cx
, callee
, newTarget
, GenericObject
, args
.mutableThisv())) {
318 // Ensure the callee still has a non-lazy script. We normally don't relazify
319 // in active compartments, but the .prototype lookup might have called the
320 // relazifyFunctions testing function that doesn't have this restriction.
321 return JSFunction::getOrCreateScript(cx
, callee
);
324 #ifdef ENABLE_RECORD_TUPLE
325 static bool AddRecordSpreadOperation(JSContext
* cx
, HandleValue recHandle
,
326 HandleValue spreadeeHandle
) {
327 MOZ_ASSERT(recHandle
.toExtendedPrimitive().is
<RecordType
>());
328 RecordType
* rec
= &recHandle
.toExtendedPrimitive().as
<RecordType
>();
330 RootedObject
obj(cx
, ToObjectOrGetObjectPayload(cx
, spreadeeHandle
));
332 RootedIdVector
keys(cx
);
333 if (!GetPropertyKeys(cx
, obj
, JSITER_OWNONLY
| JSITER_SYMBOLS
, &keys
)) {
337 size_t len
= keys
.length();
338 RootedId
propKey(cx
);
339 RootedValue
propValue(cx
);
340 for (size_t i
= 0; i
< len
; i
++) {
341 propKey
.set(keys
[i
]);
344 if (MOZ_UNLIKELY(!GetProperty(cx
, obj
, obj
, propKey
, &propValue
))) {
348 if (MOZ_UNLIKELY(!rec
->initializeNextProperty(cx
, propKey
, propValue
))) {
357 InterpreterFrame
* InvokeState::pushInterpreterFrame(JSContext
* cx
) {
358 return cx
->interpreterStack().pushInvokeFrame(cx
, args_
, construct_
);
361 InterpreterFrame
* ExecuteState::pushInterpreterFrame(JSContext
* cx
) {
362 return cx
->interpreterStack().pushExecuteFrame(cx
, script_
, envChain_
,
366 InterpreterFrame
* RunState::pushInterpreterFrame(JSContext
* cx
) {
368 return asInvoke()->pushInterpreterFrame(cx
);
370 return asExecute()->pushInterpreterFrame(cx
);
373 static MOZ_ALWAYS_INLINE
bool MaybeEnterInterpreterTrampoline(JSContext
* cx
,
376 if (jit::JitOptions
.emitInterpreterEntryTrampoline
&&
377 cx
->runtime()->hasJitRuntime()) {
378 js::jit::JitRuntime
* jitRuntime
= cx
->runtime()->jitRuntime();
379 JSScript
* script
= state
.script();
381 uint8_t* codeRaw
= nullptr;
382 auto p
= jitRuntime
->getInterpreterEntryMap()->lookup(script
);
384 codeRaw
= p
->value().raw();
385 } else if (js::jit::JitCode
* code
=
386 jitRuntime
->generateEntryTrampolineForScript(cx
, script
)) {
387 js::jit::EntryTrampoline
entry(cx
, code
);
388 if (!jitRuntime
->getInterpreterEntryMap()->put(script
, entry
)) {
391 codeRaw
= code
->raw();
394 MOZ_ASSERT(codeRaw
, "Should have a valid trampoline here.");
395 // The C++ entry thunk is located at the vmInterpreterEntryOffset offset.
396 codeRaw
+= jitRuntime
->vmInterpreterEntryOffset();
397 return js::jit::EnterInterpreterEntryTrampoline(codeRaw
, cx
, &state
);
400 return Interpret(cx
, state
);
403 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
404 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
407 # pragma optimize("g", off)
409 bool js::RunScript(JSContext
* cx
, RunState
& state
) {
410 AutoCheckRecursionLimit
recursion(cx
);
411 if (!recursion
.check(cx
)) {
415 MOZ_ASSERT_IF(cx
->runtime()->hasJitRuntime(),
416 !cx
->runtime()->jitRuntime()->disallowArbitraryCode());
418 // Since any script can conceivably GC, make sure it's safe to do so.
419 cx
->verifyIsSafeToGC();
421 MOZ_ASSERT(cx
->realm() == state
.script()->realm());
423 MOZ_DIAGNOSTIC_ASSERT(cx
->realm()->isSystem() ||
424 cx
->runtime()->allowContentJS());
426 if (!DebugAPI::checkNoExecute(cx
, state
.script())) {
430 GeckoProfilerEntryMarker
marker(cx
, state
.script());
432 bool measuringTime
= !cx
->isMeasuringExecutionTime();
433 mozilla::TimeStamp startTime
;
435 cx
->setIsMeasuringExecutionTime(true);
436 cx
->setIsExecuting(true);
437 startTime
= mozilla::TimeStamp::Now();
439 auto timerEnd
= mozilla::MakeScopeExit([&]() {
441 mozilla::TimeDuration delta
= mozilla::TimeStamp::Now() - startTime
;
442 cx
->realm()->timers
.executionTime
+= delta
;
443 cx
->setIsMeasuringExecutionTime(false);
444 cx
->setIsExecuting(false);
448 jit::EnterJitStatus status
= jit::MaybeEnterJit(cx
, state
);
450 case jit::EnterJitStatus::Error
:
452 case jit::EnterJitStatus::Ok
:
454 case jit::EnterJitStatus::NotEntered
:
458 bool ok
= MaybeEnterInterpreterTrampoline(cx
, state
);
463 # pragma optimize("", on)
466 STATIC_PRECONDITION_ASSUME(ubound(args
.argv_
) >= argc
)
467 MOZ_ALWAYS_INLINE
bool CallJSNative(JSContext
* cx
, Native native
,
468 CallReason reason
, const CallArgs
& args
) {
469 AutoCheckRecursionLimit
recursion(cx
);
470 if (!recursion
.check(cx
)) {
474 NativeResumeMode resumeMode
= DebugAPI::onNativeCall(cx
, args
, reason
);
475 if (resumeMode
!= NativeResumeMode::Continue
) {
476 return resumeMode
== NativeResumeMode::Override
;
480 bool alreadyThrowing
= cx
->isExceptionPending();
483 MOZ_ASSERT(!args
.callee().is
<ProxyObject
>());
485 AutoRealm
ar(cx
, &args
.callee());
486 bool ok
= native(cx
, args
.length(), args
.base());
488 cx
->check(args
.rval());
489 MOZ_ASSERT_IF(!alreadyThrowing
, !cx
->isExceptionPending());
494 STATIC_PRECONDITION(ubound(args
.argv_
) >= argc
)
495 MOZ_ALWAYS_INLINE
bool CallJSNativeConstructor(JSContext
* cx
, Native native
,
496 const CallArgs
& args
) {
498 RootedObject
callee(cx
, &args
.callee());
501 MOZ_ASSERT(args
.thisv().isMagic());
502 if (!CallJSNative(cx
, native
, CallReason::Call
, args
)) {
507 * Native constructors must return non-primitive values on success.
508 * Although it is legal, if a constructor returns the callee, there is a
509 * 99.9999% chance it is a bug. If any valid code actually wants the
510 * constructor to return the callee, the assertion can be removed or
511 * (another) conjunct can be added to the antecedent.
514 * - (new Object(Object)) returns the callee.
515 * - The bound function construct hook can return an arbitrary object,
516 * including the callee.
518 * Also allow if this may be due to a debugger hook since fuzzing may let this
521 MOZ_ASSERT(args
.rval().isObject());
522 MOZ_ASSERT_IF(!JS_IsNativeFunction(callee
, obj_construct
) &&
523 !callee
->is
<BoundFunctionObject
>() &&
524 !cx
->insideDebuggerEvaluationWithOnNativeCallHook
,
525 args
.rval() != ObjectValue(*callee
));
531 * Find a function reference and its 'this' value implicit first parameter
532 * under argc arguments on cx's stack, and call the function. Push missing
533 * required arguments, allocate declared local variables, and pop everything
534 * when done. Then push the return value.
536 * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
537 * necessary. The caller (usually the interpreter) must have performed
540 bool js::InternalCallOrConstruct(JSContext
* cx
, const CallArgs
& args
,
541 MaybeConstruct construct
,
542 CallReason reason
/* = CallReason::Call */) {
543 MOZ_ASSERT(args
.length() <= ARGS_LENGTH_MAX
);
545 unsigned skipForCallee
= args
.length() + 1 + (construct
== CONSTRUCT
);
546 if (args
.calleev().isPrimitive()) {
547 return ReportIsNotFunction(cx
, args
.calleev(), skipForCallee
, construct
);
550 /* Invoke non-functions. */
551 if (MOZ_UNLIKELY(!args
.callee().is
<JSFunction
>())) {
552 MOZ_ASSERT_IF(construct
, !args
.callee().isConstructor());
554 if (!args
.callee().isCallable()) {
555 return ReportIsNotFunction(cx
, args
.calleev(), skipForCallee
, construct
);
558 if (args
.callee().is
<ProxyObject
>()) {
559 RootedObject
proxy(cx
, &args
.callee());
560 return Proxy::call(cx
, proxy
, args
);
563 JSNative call
= args
.callee().callHook();
564 MOZ_ASSERT(call
, "isCallable without a callHook?");
566 return CallJSNative(cx
, call
, reason
, args
);
569 /* Invoke native functions. */
570 RootedFunction
fun(cx
, &args
.callee().as
<JSFunction
>());
571 if (fun
->isNativeFun()) {
572 MOZ_ASSERT_IF(construct
, !fun
->isConstructor());
573 JSNative native
= fun
->native();
574 if (!construct
&& args
.ignoresReturnValue() && fun
->hasJitInfo()) {
575 const JSJitInfo
* jitInfo
= fun
->jitInfo();
576 if (jitInfo
->type() == JSJitInfo::IgnoresReturnValueNative
) {
577 native
= jitInfo
->ignoresReturnValueMethod
;
580 return CallJSNative(cx
, native
, reason
, args
);
583 // Self-hosted builtins are considered native by the onNativeCall hook.
584 if (fun
->isSelfHostedBuiltin()) {
585 NativeResumeMode resumeMode
= DebugAPI::onNativeCall(cx
, args
, reason
);
586 if (resumeMode
!= NativeResumeMode::Continue
) {
587 return resumeMode
== NativeResumeMode::Override
;
591 if (!JSFunction::getOrCreateScript(cx
, fun
)) {
595 /* Run function until JSOp::RetRval, JSOp::Return or error. */
596 InvokeState
state(cx
, args
, construct
);
598 // Create |this| if we're constructing. Switch to the callee's realm to
599 // ensure this object has the correct realm.
600 AutoRealm
ar(cx
, state
.script());
601 if (construct
&& !MaybeCreateThisForConstructor(cx
, args
)) {
605 // Calling class constructors throws an error from the callee's realm.
606 if (construct
!= CONSTRUCT
&& fun
->isClassConstructor()) {
607 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
608 JSMSG_CANT_CALL_CLASS_CONSTRUCTOR
);
612 bool ok
= RunScript(cx
, state
);
614 MOZ_ASSERT_IF(ok
&& construct
, args
.rval().isObject());
618 // Returns true if the callee needs an outerized |this| object. Outerization
619 // means passing the WindowProxy instead of the Window (a GlobalObject) because
620 // we must never expose the Window to script. This returns false only for DOM
621 // getters or setters.
622 static bool CalleeNeedsOuterizedThisObject(const Value
& callee
) {
623 if (!callee
.isObject() || !callee
.toObject().is
<JSFunction
>()) {
626 JSFunction
& fun
= callee
.toObject().as
<JSFunction
>();
627 if (!fun
.isNativeFun() || !fun
.hasJitInfo()) {
630 return fun
.jitInfo()->needsOuterizedThisObject();
633 static bool InternalCall(JSContext
* cx
, const AnyInvokeArgs
& args
,
635 MOZ_ASSERT(args
.array() + args
.length() == args
.end(),
636 "must pass calling arguments to a calling attempt");
639 // The caller is responsible for calling GetThisObject if needed.
640 if (args
.thisv().isObject()) {
641 JSObject
* thisObj
= &args
.thisv().toObject();
642 MOZ_ASSERT_IF(CalleeNeedsOuterizedThisObject(args
.calleev()),
643 GetThisObject(thisObj
) == thisObj
);
647 return InternalCallOrConstruct(cx
, args
, NO_CONSTRUCT
, reason
);
650 bool js::CallFromStack(JSContext
* cx
, const CallArgs
& args
,
651 CallReason reason
/* = CallReason::Call */) {
652 return InternalCall(cx
, static_cast<const AnyInvokeArgs
&>(args
), reason
);
655 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
657 bool js::Call(JSContext
* cx
, HandleValue fval
, HandleValue thisv
,
658 const AnyInvokeArgs
& args
, MutableHandleValue rval
,
660 // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
662 args
.CallArgs::setCallee(fval
);
663 args
.CallArgs::setThis(thisv
);
665 if (thisv
.isObject()) {
666 // If |this| is a global object, it might be a Window and in that case we
667 // usually have to pass the WindowProxy instead.
668 JSObject
* thisObj
= &thisv
.toObject();
669 if (thisObj
->is
<GlobalObject
>()) {
670 if (CalleeNeedsOuterizedThisObject(fval
)) {
671 args
.mutableThisv().setObject(*GetThisObject(thisObj
));
674 // Fast path: we don't have to do anything if the object isn't a global.
675 MOZ_ASSERT(GetThisObject(thisObj
) == thisObj
);
679 if (!InternalCall(cx
, args
, reason
)) {
683 rval
.set(args
.rval());
687 static bool InternalConstruct(JSContext
* cx
, const AnyConstructArgs
& args
,
688 CallReason reason
= CallReason::Call
) {
689 MOZ_ASSERT(args
.array() + args
.length() + 1 == args
.end(),
690 "must pass constructing arguments to a construction attempt");
691 MOZ_ASSERT(!FunctionClass
.getConstruct());
692 MOZ_ASSERT(!ExtendedFunctionClass
.getConstruct());
694 // Callers are responsible for enforcing these preconditions.
695 MOZ_ASSERT(IsConstructor(args
.calleev()),
696 "trying to construct a value that isn't a constructor");
697 MOZ_ASSERT(IsConstructor(args
.CallArgs::newTarget()),
698 "provided new.target value must be a constructor");
700 MOZ_ASSERT(args
.thisv().isMagic(JS_IS_CONSTRUCTING
) ||
701 args
.thisv().isObject());
703 JSObject
& callee
= args
.callee();
704 if (callee
.is
<JSFunction
>()) {
705 RootedFunction
fun(cx
, &callee
.as
<JSFunction
>());
707 if (fun
->isNativeFun()) {
708 return CallJSNativeConstructor(cx
, fun
->native(), args
);
711 if (!InternalCallOrConstruct(cx
, args
, CONSTRUCT
, reason
)) {
715 MOZ_ASSERT(args
.CallArgs::rval().isObject());
719 if (callee
.is
<ProxyObject
>()) {
720 RootedObject
proxy(cx
, &callee
);
721 return Proxy::construct(cx
, proxy
, args
);
724 JSNative construct
= callee
.constructHook();
725 MOZ_ASSERT(construct
!= nullptr, "IsConstructor without a construct hook?");
727 return CallJSNativeConstructor(cx
, construct
, args
);
730 // Check that |callee|, the callee in a |new| expression, is a constructor.
731 static bool StackCheckIsConstructorCalleeNewTarget(JSContext
* cx
,
733 HandleValue newTarget
) {
734 // Calls from the stack could have any old non-constructor callee.
735 if (!IsConstructor(callee
)) {
736 ReportValueError(cx
, JSMSG_NOT_CONSTRUCTOR
, JSDVG_SEARCH_STACK
, callee
,
741 // The new.target has already been vetted by previous calls, or is the callee.
742 // We can just assert that it's a constructor.
743 MOZ_ASSERT(IsConstructor(newTarget
));
748 bool js::ConstructFromStack(JSContext
* cx
, const CallArgs
& args
,
749 CallReason reason
/* CallReason::Call */) {
750 if (!StackCheckIsConstructorCalleeNewTarget(cx
, args
.calleev(),
755 return InternalConstruct(cx
, static_cast<const AnyConstructArgs
&>(args
),
759 bool js::Construct(JSContext
* cx
, HandleValue fval
,
760 const AnyConstructArgs
& args
, HandleValue newTarget
,
761 MutableHandleObject objp
) {
762 MOZ_ASSERT(args
.thisv().isMagic(JS_IS_CONSTRUCTING
));
764 // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
765 args
.CallArgs::setCallee(fval
);
766 args
.CallArgs::newTarget().set(newTarget
);
768 if (!InternalConstruct(cx
, args
)) {
772 MOZ_ASSERT(args
.CallArgs::rval().isObject());
773 objp
.set(&args
.CallArgs::rval().toObject());
777 bool js::InternalConstructWithProvidedThis(JSContext
* cx
, HandleValue fval
,
779 const AnyConstructArgs
& args
,
780 HandleValue newTarget
,
781 MutableHandleValue rval
) {
782 args
.CallArgs::setCallee(fval
);
784 MOZ_ASSERT(thisv
.isObject());
785 args
.CallArgs::setThis(thisv
);
787 args
.CallArgs::newTarget().set(newTarget
);
789 if (!InternalConstruct(cx
, args
)) {
793 rval
.set(args
.CallArgs::rval());
797 bool js::CallGetter(JSContext
* cx
, HandleValue thisv
, HandleValue getter
,
798 MutableHandleValue rval
) {
799 FixedInvokeArgs
<0> args(cx
);
801 return Call(cx
, getter
, thisv
, args
, rval
, CallReason::Getter
);
804 bool js::CallSetter(JSContext
* cx
, HandleValue thisv
, HandleValue setter
,
806 FixedInvokeArgs
<1> args(cx
);
809 RootedValue
ignored(cx
);
810 return Call(cx
, setter
, thisv
, args
, &ignored
, CallReason::Setter
);
813 bool js::ExecuteKernel(JSContext
* cx
, HandleScript script
,
814 HandleObject envChainArg
, AbstractFramePtr evalInFrame
,
815 MutableHandleValue result
) {
816 MOZ_ASSERT_IF(script
->isGlobalCode(),
817 IsGlobalLexicalEnvironment(envChainArg
) ||
818 !IsSyntacticEnvironment(envChainArg
));
820 RootedObject
terminatingEnv(cx
, envChainArg
);
821 while (IsSyntacticEnvironment(terminatingEnv
)) {
822 terminatingEnv
= terminatingEnv
->enclosingEnvironment();
824 MOZ_ASSERT(terminatingEnv
->is
<GlobalObject
>() ||
825 script
->hasNonSyntacticScope());
828 if (script
->treatAsRunOnce()) {
829 if (script
->hasRunOnce()) {
830 JS_ReportErrorASCII(cx
,
831 "Trying to execute a run-once script multiple times");
835 script
->setHasRunOnce();
838 if (script
->isEmpty()) {
839 result
.setUndefined();
843 probes::StartExecution(script
);
844 ExecuteState
state(cx
, script
, envChainArg
, evalInFrame
, result
);
845 bool ok
= RunScript(cx
, state
);
846 probes::StopExecution(script
);
851 bool js::Execute(JSContext
* cx
, HandleScript script
, HandleObject envChain
,
852 MutableHandleValue rval
) {
853 /* The env chain is something we control, so we know it can't
854 have any outer objects on it. */
855 MOZ_ASSERT(!IsWindowProxy(envChain
));
857 if (script
->isModule()) {
859 envChain
== script
->module()->environment(),
860 "Module scripts can only be executed in the module's environment");
863 IsGlobalLexicalEnvironment(envChain
) || script
->hasNonSyntacticScope(),
864 "Only global scripts with non-syntactic envs can be executed with "
865 "interesting envchains");
868 /* Ensure the env chain is all same-compartment and terminates in a global. */
870 JSObject
* s
= envChain
;
873 MOZ_ASSERT_IF(!s
->enclosingEnvironment(), s
->is
<GlobalObject
>());
874 } while ((s
= s
->enclosingEnvironment()));
877 return ExecuteKernel(cx
, script
, envChain
, NullFramePtr() /* evalInFrame */,
882 * ES6 (4-25-16) 12.10.4 InstanceofOperator
884 bool js::InstanceofOperator(JSContext
* cx
, HandleObject obj
, HandleValue v
,
886 /* Step 1. is handled by caller. */
889 RootedValue
hasInstance(cx
);
890 RootedId
id(cx
, PropertyKey::Symbol(cx
->wellKnownSymbols().hasInstance
));
891 if (!GetProperty(cx
, obj
, obj
, id
, &hasInstance
)) {
895 if (!hasInstance
.isNullOrUndefined()) {
896 if (!IsCallable(hasInstance
)) {
897 return ReportIsNotFunction(cx
, hasInstance
);
901 RootedValue
rval(cx
);
902 if (!Call(cx
, hasInstance
, obj
, v
, &rval
)) {
905 *bp
= ToBoolean(rval
);
910 if (!obj
->isCallable()) {
911 RootedValue
val(cx
, ObjectValue(*obj
));
912 return ReportIsNotFunction(cx
, val
);
916 return OrdinaryHasInstance(cx
, obj
, v
, bp
);
919 JSType
js::TypeOfObject(JSObject
* obj
) {
920 #ifdef ENABLE_RECORD_TUPLE
921 MOZ_ASSERT(!js::IsExtendedPrimitive(*obj
));
924 AutoUnsafeCallWithABI unsafe
;
925 if (EmulatesUndefined(obj
)) {
926 return JSTYPE_UNDEFINED
;
928 if (obj
->isCallable()) {
929 return JSTYPE_FUNCTION
;
931 return JSTYPE_OBJECT
;
934 #ifdef ENABLE_RECORD_TUPLE
935 JSType
TypeOfExtendedPrimitive(JSObject
* obj
) {
936 MOZ_ASSERT(js::IsExtendedPrimitive(*obj
));
938 if (obj
->is
<RecordType
>()) {
939 return JSTYPE_RECORD
;
941 if (obj
->is
<TupleType
>()) {
944 MOZ_CRASH("Unknown ExtendedPrimitive");
948 JSType
js::TypeOfValue(const Value
& v
) {
950 case ValueType::Double
:
951 case ValueType::Int32
:
952 return JSTYPE_NUMBER
;
953 case ValueType::String
:
954 return JSTYPE_STRING
;
955 case ValueType::Null
:
956 return JSTYPE_OBJECT
;
957 case ValueType::Undefined
:
958 return JSTYPE_UNDEFINED
;
959 case ValueType::Object
:
960 return TypeOfObject(&v
.toObject());
961 #ifdef ENABLE_RECORD_TUPLE
962 case ValueType::ExtendedPrimitive
:
963 return TypeOfExtendedPrimitive(&v
.toExtendedPrimitive());
965 case ValueType::Boolean
:
966 return JSTYPE_BOOLEAN
;
967 case ValueType::BigInt
:
968 return JSTYPE_BIGINT
;
969 case ValueType::Symbol
:
970 return JSTYPE_SYMBOL
;
971 case ValueType::Magic
:
972 case ValueType::PrivateGCThing
:
976 ReportBadValueTypeAndCrash(v
);
979 bool js::CheckClassHeritageOperation(JSContext
* cx
, HandleValue heritage
) {
980 if (IsConstructor(heritage
)) {
984 if (heritage
.isNull()) {
988 if (heritage
.isObject()) {
989 ReportIsNotFunction(cx
, heritage
, 0, CONSTRUCT
);
993 ReportValueError(cx
, JSMSG_BAD_HERITAGE
, -1, heritage
, nullptr,
994 "not an object or null");
998 PlainObject
* js::ObjectWithProtoOperation(JSContext
* cx
, HandleValue val
) {
999 if (!val
.isObjectOrNull()) {
1000 ReportValueError(cx
, JSMSG_NOT_OBJORNULL
, -1, val
, nullptr);
1004 RootedObject
proto(cx
, val
.toObjectOrNull());
1005 return NewPlainObjectWithProto(cx
, proto
);
1008 JSObject
* js::FunWithProtoOperation(JSContext
* cx
, HandleFunction fun
,
1009 HandleObject parent
, HandleObject proto
) {
1010 return CloneFunctionReuseScript(cx
, fun
, parent
, proto
);
1014 * Enter the new with environment using an object at sp[-1] and associate the
1015 * depth of the with block with sp + stackIndex.
1017 bool js::EnterWithOperation(JSContext
* cx
, AbstractFramePtr frame
,
1018 HandleValue val
, Handle
<WithScope
*> scope
) {
1019 RootedObject
obj(cx
);
1020 if (val
.isObject()) {
1021 obj
= &val
.toObject();
1023 obj
= ToObject(cx
, val
);
1029 RootedObject
envChain(cx
, frame
.environmentChain());
1030 WithEnvironmentObject
* withobj
=
1031 WithEnvironmentObject::create(cx
, obj
, envChain
, scope
);
1036 frame
.pushOnEnvironmentChain(*withobj
);
1040 static void PopEnvironment(JSContext
* cx
, EnvironmentIter
& ei
) {
1041 switch (ei
.scope().kind()) {
1042 case ScopeKind::Lexical
:
1043 case ScopeKind::SimpleCatch
:
1044 case ScopeKind::Catch
:
1045 case ScopeKind::NamedLambda
:
1046 case ScopeKind::StrictNamedLambda
:
1047 case ScopeKind::FunctionLexical
:
1048 case ScopeKind::ClassBody
:
1049 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1050 DebugEnvironments::onPopLexical(cx
, ei
);
1052 if (ei
.scope().hasEnvironment()) {
1054 .popOffEnvironmentChain
<ScopedLexicalEnvironmentObject
>();
1057 case ScopeKind::With
:
1058 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1059 DebugEnvironments::onPopWith(ei
.initialFrame());
1061 ei
.initialFrame().popOffEnvironmentChain
<WithEnvironmentObject
>();
1063 case ScopeKind::Function
:
1064 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1065 DebugEnvironments::onPopCall(cx
, ei
.initialFrame());
1067 if (ei
.scope().hasEnvironment()) {
1068 ei
.initialFrame().popOffEnvironmentChain
<CallObject
>();
1071 case ScopeKind::FunctionBodyVar
:
1072 case ScopeKind::StrictEval
:
1073 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1074 DebugEnvironments::onPopVar(cx
, ei
);
1076 if (ei
.scope().hasEnvironment()) {
1077 ei
.initialFrame().popOffEnvironmentChain
<VarEnvironmentObject
>();
1080 case ScopeKind::Module
:
1081 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1082 DebugEnvironments::onPopModule(cx
, ei
);
1085 case ScopeKind::Eval
:
1086 case ScopeKind::Global
:
1087 case ScopeKind::NonSyntactic
:
1089 case ScopeKind::WasmInstance
:
1090 case ScopeKind::WasmFunction
:
1091 MOZ_CRASH("wasm is not interpreted");
1096 // Unwind environment chain and iterator to match the env corresponding to
1097 // the given bytecode position.
1098 void js::UnwindEnvironment(JSContext
* cx
, EnvironmentIter
& ei
, jsbytecode
* pc
) {
1099 if (!ei
.withinInitialFrame()) {
1103 Rooted
<Scope
*> scope(cx
, ei
.initialFrame().script()->innermostScope(pc
));
1106 // A frame's environment chain cannot be unwound to anything enclosing the
1107 // body scope of a script. This includes the parameter defaults
1108 // environment and the decl env object. These environments, once pushed
1109 // onto the environment chain, are expected to be there for the duration
1112 // Attempting to unwind to the parameter defaults code in a script is a
1113 // bug; that section of code has no try-catch blocks.
1114 JSScript
* script
= ei
.initialFrame().script();
1115 for (uint32_t i
= 0; i
< script
->bodyScopeIndex(); i
++) {
1116 MOZ_ASSERT(scope
!= script
->getScope(GCThingIndex(i
)));
1120 for (; ei
.maybeScope() != scope
; ei
++) {
1121 PopEnvironment(cx
, ei
);
1125 // Unwind all environments. This is needed because block scopes may cover the
1126 // first bytecode at a script's main(). e.g.,
1128 // function f() { { let i = 0; } }
1130 // will have no pc location distinguishing the first block scope from the
1131 // outermost function scope.
1132 void js::UnwindAllEnvironmentsInFrame(JSContext
* cx
, EnvironmentIter
& ei
) {
1133 for (; ei
.withinInitialFrame(); ei
++) {
1134 PopEnvironment(cx
, ei
);
1138 // Compute the pc needed to unwind the environment to the beginning of a try
1139 // block. We cannot unwind to *after* the JSOp::Try, because that might be the
1140 // first opcode of an inner scope, with the same problem as above. e.g.,
1142 // try { { let x; } }
1144 // will have no pc location distinguishing the try block scope from the inner
1146 jsbytecode
* js::UnwindEnvironmentToTryPc(JSScript
* script
, const TryNote
* tn
) {
1147 jsbytecode
* pc
= script
->offsetToPC(tn
->start
);
1148 if (tn
->kind() == TryNoteKind::Catch
|| tn
->kind() == TryNoteKind::Finally
) {
1149 pc
-= JSOpLength_Try
;
1150 MOZ_ASSERT(JSOp(*pc
) == JSOp::Try
);
1151 } else if (tn
->kind() == TryNoteKind::Destructuring
) {
1152 pc
-= JSOpLength_TryDestructuring
;
1153 MOZ_ASSERT(JSOp(*pc
) == JSOp::TryDestructuring
);
1158 static void SettleOnTryNote(JSContext
* cx
, const TryNote
* tn
,
1159 EnvironmentIter
& ei
, InterpreterRegs
& regs
) {
1160 // Unwind the environment to the beginning of the JSOp::Try.
1161 UnwindEnvironment(cx
, ei
, UnwindEnvironmentToTryPc(regs
.fp()->script(), tn
));
1163 // Set pc to the first bytecode after the the try note to point
1164 // to the beginning of catch or finally.
1165 regs
.pc
= regs
.fp()->script()->offsetToPC(tn
->start
+ tn
->length
);
1166 regs
.sp
= regs
.spForStackDepth(tn
->stackDepth
);
1169 class InterpreterTryNoteFilter
{
1170 const InterpreterRegs
& regs_
;
1173 explicit InterpreterTryNoteFilter(const InterpreterRegs
& regs
)
1175 bool operator()(const TryNote
* note
) {
1176 return note
->stackDepth
<= regs_
.stackDepth();
1180 class TryNoteIterInterpreter
: public TryNoteIter
<InterpreterTryNoteFilter
> {
1182 TryNoteIterInterpreter(JSContext
* cx
, const InterpreterRegs
& regs
)
1183 : TryNoteIter(cx
, regs
.fp()->script(), regs
.pc
,
1184 InterpreterTryNoteFilter(regs
)) {}
1187 static void UnwindIteratorsForUncatchableException(
1188 JSContext
* cx
, const InterpreterRegs
& regs
) {
1189 // c.f. the regular (catchable) TryNoteIterInterpreter loop in
1191 for (TryNoteIterInterpreter
tni(cx
, regs
); !tni
.done(); ++tni
) {
1192 const TryNote
* tn
= *tni
;
1193 switch (tn
->kind()) {
1194 case TryNoteKind::ForIn
: {
1195 Value
* sp
= regs
.spForStackDepth(tn
->stackDepth
);
1196 UnwindIteratorForUncatchableException(&sp
[-1].toObject());
1205 enum HandleErrorContinuation
{
1206 SuccessfulReturnContinuation
,
1207 ErrorReturnContinuation
,
1212 static HandleErrorContinuation
ProcessTryNotes(JSContext
* cx
,
1213 EnvironmentIter
& ei
,
1214 InterpreterRegs
& regs
) {
1215 for (TryNoteIterInterpreter
tni(cx
, regs
); !tni
.done(); ++tni
) {
1216 const TryNote
* tn
= *tni
;
1218 switch (tn
->kind()) {
1219 case TryNoteKind::Catch
:
1220 /* Catch cannot intercept the closing of a generator. */
1221 if (cx
->isClosingGenerator()) {
1225 SettleOnTryNote(cx
, tn
, ei
, regs
);
1226 return CatchContinuation
;
1228 case TryNoteKind::Finally
:
1229 SettleOnTryNote(cx
, tn
, ei
, regs
);
1230 return FinallyContinuation
;
1232 case TryNoteKind::ForIn
: {
1233 /* This is similar to JSOp::EndIter in the interpreter loop. */
1234 MOZ_ASSERT(tn
->stackDepth
<= regs
.stackDepth());
1235 Value
* sp
= regs
.spForStackDepth(tn
->stackDepth
);
1236 JSObject
* obj
= &sp
[-1].toObject();
1241 case TryNoteKind::Destructuring
: {
1242 // Whether the destructuring iterator is done is at the top of the
1243 // stack. The iterator object is second from the top.
1244 MOZ_ASSERT(tn
->stackDepth
> 1);
1245 Value
* sp
= regs
.spForStackDepth(tn
->stackDepth
);
1246 RootedValue
doneValue(cx
, sp
[-1]);
1247 MOZ_RELEASE_ASSERT(!doneValue
.isMagic());
1248 bool done
= ToBoolean(doneValue
);
1250 RootedObject
iterObject(cx
, &sp
[-2].toObject());
1251 if (!IteratorCloseForException(cx
, iterObject
)) {
1252 SettleOnTryNote(cx
, tn
, ei
, regs
);
1253 return ErrorReturnContinuation
;
1259 case TryNoteKind::ForOf
:
1260 case TryNoteKind::Loop
:
1263 // TryNoteKind::ForOfIterClose is handled internally by the try note
1266 MOZ_CRASH("Invalid try note");
1270 return SuccessfulReturnContinuation
;
1273 bool js::HandleClosingGeneratorReturn(JSContext
* cx
, AbstractFramePtr frame
,
1276 * Propagate the exception or error to the caller unless the exception
1277 * is an asynchronous return from a generator.
1279 if (cx
->isClosingGenerator()) {
1280 cx
->clearPendingException();
1282 auto* genObj
= GetGeneratorObjectForFrame(cx
, frame
);
1283 genObj
->setClosed();
1288 static HandleErrorContinuation
HandleError(JSContext
* cx
,
1289 InterpreterRegs
& regs
) {
1290 MOZ_ASSERT(regs
.fp()->script()->containsPC(regs
.pc
));
1291 MOZ_ASSERT(cx
->realm() == regs
.fp()->script()->realm());
1293 if (regs
.fp()->script()->hasScriptCounts()) {
1294 PCCounts
* counts
= regs
.fp()->script()->getThrowCounts(regs
.pc
);
1295 // If we failed to allocate, then skip the increment and continue to
1296 // handle the exception.
1298 counts
->numExec()++;
1302 EnvironmentIter
ei(cx
, regs
.fp(), regs
.pc
);
1306 if (cx
->isExceptionPending()) {
1307 /* Call debugger throw hooks. */
1308 if (!cx
->isClosingGenerator()) {
1309 if (!DebugAPI::onExceptionUnwind(cx
, regs
.fp())) {
1310 if (!cx
->isExceptionPending()) {
1314 // Ensure that the debugger hasn't returned 'true' while clearing the
1316 MOZ_ASSERT(cx
->isExceptionPending());
1319 HandleErrorContinuation res
= ProcessTryNotes(cx
, ei
, regs
);
1321 case SuccessfulReturnContinuation
:
1323 case ErrorReturnContinuation
:
1325 case CatchContinuation
:
1326 case FinallyContinuation
:
1327 // No need to increment the PCCounts number of execution here, as
1328 // the interpreter increments any PCCounts if present.
1329 MOZ_ASSERT_IF(regs
.fp()->script()->hasScriptCounts(),
1330 regs
.fp()->script()->maybeGetPCCounts(regs
.pc
));
1334 ok
= HandleClosingGeneratorReturn(cx
, regs
.fp(), ok
);
1336 UnwindIteratorsForUncatchableException(cx
, regs
);
1338 // We may be propagating a forced return from a debugger hook function.
1339 if (MOZ_UNLIKELY(cx
->isPropagatingForcedReturn())) {
1340 cx
->clearPropagatingForcedReturn();
1345 ok
= DebugAPI::onLeaveFrame(cx
, regs
.fp(), regs
.pc
, ok
);
1347 // After this point, we will pop the frame regardless. Settle the frame on
1348 // the end of the script.
1349 regs
.setToEndOfScript();
1351 return ok
? SuccessfulReturnContinuation
: ErrorReturnContinuation
;
1354 #define REGS (activation.regs())
1355 #define PUSH_COPY(v) \
1358 cx->debugOnlyCheck(REGS.sp[-1]); \
1360 #define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
1361 #define PUSH_NULL() REGS.sp++->setNull()
1362 #define PUSH_UNDEFINED() REGS.sp++->setUndefined()
1363 #define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
1364 #define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
1365 #define PUSH_INT32(i) REGS.sp++->setInt32(i)
1366 #define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
1367 #define PUSH_BIGINT(b) REGS.sp++->setBigInt(b)
1368 #define PUSH_STRING(s) \
1370 REGS.sp++->setString(s); \
1371 cx->debugOnlyCheck(REGS.sp[-1]); \
1373 #define PUSH_OBJECT(obj) \
1375 REGS.sp++->setObject(obj); \
1376 cx->debugOnlyCheck(REGS.sp[-1]); \
1378 #define PUSH_OBJECT_OR_NULL(obj) \
1380 REGS.sp++->setObjectOrNull(obj); \
1381 cx->debugOnlyCheck(REGS.sp[-1]); \
1383 #ifdef ENABLE_RECORD_TUPLE
1384 # define PUSH_EXTENDED_PRIMITIVE(obj) \
1386 REGS.sp++->setExtendedPrimitive(obj); \
1387 cx->debugOnlyCheck(REGS.sp[-1]); \
1390 #define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
1391 #define POP_COPY_TO(v) (v) = *--REGS.sp
1392 #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
1395 * Same for JSOp::SetName and JSOp::SetProp, which differ only slightly but
1396 * remain distinct for the decompiler.
1398 static_assert(JSOpLength_SetName
== JSOpLength_SetProp
);
1400 /* See TRY_BRANCH_AFTER_COND. */
1401 static_assert(JSOpLength_JumpIfTrue
== JSOpLength_JumpIfFalse
);
1402 static_assert(uint8_t(JSOp::JumpIfTrue
) == uint8_t(JSOp::JumpIfFalse
) + 1);
1405 * Compute the implicit |this| value used by a call expression with an
1406 * unqualified name reference. The environment the binding was found on is
1407 * passed as argument, env.
1409 * The implicit |this| is |undefined| for all environment types except
1410 * WithEnvironmentObject. This is the case for |with(...) {...}| expressions or
1411 * if the embedding uses a non-syntactic WithEnvironmentObject.
1413 * NOTE: A non-syntactic WithEnvironmentObject may have a corresponding
1414 * extensible LexicalEnviornmentObject, but it will not be considered as an
1415 * implicit |this|. This is for compatibility with the Gecko subscript loader.
1417 static inline Value
ComputeImplicitThis(JSObject
* env
) {
1418 // Fast-path for GlobalObject
1419 if (env
->is
<GlobalObject
>()) {
1420 return UndefinedValue();
1423 // WithEnvironmentObjects have an actual implicit |this|
1424 if (env
->is
<WithEnvironmentObject
>()) {
1425 return ObjectValue(*GetThisObjectOfWith(env
));
1428 // Debugger environments need special casing, as despite being
1429 // non-syntactic, they wrap syntactic environments and should not be
1430 // treated like other embedding-specific non-syntactic environments.
1431 if (env
->is
<DebugEnvironmentProxy
>()) {
1432 return ComputeImplicitThis(&env
->as
<DebugEnvironmentProxy
>().environment());
1435 MOZ_ASSERT(env
->is
<EnvironmentObject
>());
1436 return UndefinedValue();
1439 static MOZ_ALWAYS_INLINE
bool AddOperation(JSContext
* cx
,
1440 MutableHandleValue lhs
,
1441 MutableHandleValue rhs
,
1442 MutableHandleValue res
) {
1443 if (lhs
.isInt32() && rhs
.isInt32()) {
1444 int32_t l
= lhs
.toInt32(), r
= rhs
.toInt32();
1446 if (MOZ_LIKELY(SafeAdd(l
, r
, &t
))) {
1452 if (!ToPrimitive(cx
, lhs
)) {
1455 if (!ToPrimitive(cx
, rhs
)) {
1459 bool lIsString
= lhs
.isString();
1460 bool rIsString
= rhs
.isString();
1461 if (lIsString
|| rIsString
) {
1464 lstr
= lhs
.toString();
1466 lstr
= ToString
<CanGC
>(cx
, lhs
);
1474 rstr
= rhs
.toString();
1476 // Save/restore lstr in case of GC activity under ToString.
1477 lhs
.setString(lstr
);
1478 rstr
= ToString
<CanGC
>(cx
, rhs
);
1482 lstr
= lhs
.toString();
1484 JSString
* str
= ConcatStrings
<NoGC
>(cx
, lstr
, rstr
);
1486 RootedString
nlstr(cx
, lstr
), nrstr(cx
, rstr
);
1487 str
= ConcatStrings
<CanGC
>(cx
, nlstr
, nrstr
);
1496 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1500 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1501 return BigInt::addValue(cx
, lhs
, rhs
, res
);
1504 res
.setNumber(lhs
.toNumber() + rhs
.toNumber());
1508 static MOZ_ALWAYS_INLINE
bool SubOperation(JSContext
* cx
,
1509 MutableHandleValue lhs
,
1510 MutableHandleValue rhs
,
1511 MutableHandleValue res
) {
1512 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1516 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1517 return BigInt::subValue(cx
, lhs
, rhs
, res
);
1520 res
.setNumber(lhs
.toNumber() - rhs
.toNumber());
1524 static MOZ_ALWAYS_INLINE
bool MulOperation(JSContext
* cx
,
1525 MutableHandleValue lhs
,
1526 MutableHandleValue rhs
,
1527 MutableHandleValue res
) {
1528 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1532 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1533 return BigInt::mulValue(cx
, lhs
, rhs
, res
);
1536 res
.setNumber(lhs
.toNumber() * rhs
.toNumber());
1540 static MOZ_ALWAYS_INLINE
bool DivOperation(JSContext
* cx
,
1541 MutableHandleValue lhs
,
1542 MutableHandleValue rhs
,
1543 MutableHandleValue res
) {
1544 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1548 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1549 return BigInt::divValue(cx
, lhs
, rhs
, res
);
1552 res
.setNumber(NumberDiv(lhs
.toNumber(), rhs
.toNumber()));
1556 static MOZ_ALWAYS_INLINE
bool ModOperation(JSContext
* cx
,
1557 MutableHandleValue lhs
,
1558 MutableHandleValue rhs
,
1559 MutableHandleValue res
) {
1561 if (lhs
.isInt32() && rhs
.isInt32() && (l
= lhs
.toInt32()) >= 0 &&
1562 (r
= rhs
.toInt32()) > 0) {
1563 int32_t mod
= l
% r
;
1568 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1572 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1573 return BigInt::modValue(cx
, lhs
, rhs
, res
);
1576 res
.setNumber(NumberMod(lhs
.toNumber(), rhs
.toNumber()));
1580 static MOZ_ALWAYS_INLINE
bool PowOperation(JSContext
* cx
,
1581 MutableHandleValue lhs
,
1582 MutableHandleValue rhs
,
1583 MutableHandleValue res
) {
1584 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1588 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1589 return BigInt::powValue(cx
, lhs
, rhs
, res
);
1592 res
.setNumber(ecmaPow(lhs
.toNumber(), rhs
.toNumber()));
1596 static MOZ_ALWAYS_INLINE
bool BitNotOperation(JSContext
* cx
,
1597 MutableHandleValue in
,
1598 MutableHandleValue out
) {
1599 if (!ToInt32OrBigInt(cx
, in
)) {
1603 if (in
.isBigInt()) {
1604 return BigInt::bitNotValue(cx
, in
, out
);
1607 out
.setInt32(~in
.toInt32());
1611 static MOZ_ALWAYS_INLINE
bool BitXorOperation(JSContext
* cx
,
1612 MutableHandleValue lhs
,
1613 MutableHandleValue rhs
,
1614 MutableHandleValue out
) {
1615 if (!ToInt32OrBigInt(cx
, lhs
) || !ToInt32OrBigInt(cx
, rhs
)) {
1619 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1620 return BigInt::bitXorValue(cx
, lhs
, rhs
, out
);
1623 out
.setInt32(lhs
.toInt32() ^ rhs
.toInt32());
1627 static MOZ_ALWAYS_INLINE
bool BitOrOperation(JSContext
* cx
,
1628 MutableHandleValue lhs
,
1629 MutableHandleValue rhs
,
1630 MutableHandleValue out
) {
1631 if (!ToInt32OrBigInt(cx
, lhs
) || !ToInt32OrBigInt(cx
, rhs
)) {
1635 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1636 return BigInt::bitOrValue(cx
, lhs
, rhs
, out
);
1639 out
.setInt32(lhs
.toInt32() | rhs
.toInt32());
1643 static MOZ_ALWAYS_INLINE
bool BitAndOperation(JSContext
* cx
,
1644 MutableHandleValue lhs
,
1645 MutableHandleValue rhs
,
1646 MutableHandleValue out
) {
1647 if (!ToInt32OrBigInt(cx
, lhs
) || !ToInt32OrBigInt(cx
, rhs
)) {
1651 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1652 return BigInt::bitAndValue(cx
, lhs
, rhs
, out
);
1655 out
.setInt32(lhs
.toInt32() & rhs
.toInt32());
1659 static MOZ_ALWAYS_INLINE
bool BitLshOperation(JSContext
* cx
,
1660 MutableHandleValue lhs
,
1661 MutableHandleValue rhs
,
1662 MutableHandleValue out
) {
1663 if (!ToInt32OrBigInt(cx
, lhs
) || !ToInt32OrBigInt(cx
, rhs
)) {
1667 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1668 return BigInt::lshValue(cx
, lhs
, rhs
, out
);
1671 // Signed left-shift is undefined on overflow, so |lhs << (rhs & 31)| won't
1672 // work. Instead, convert to unsigned space (where overflow is treated
1673 // modularly), perform the operation there, then convert back.
1674 uint32_t left
= static_cast<uint32_t>(lhs
.toInt32());
1675 uint8_t right
= rhs
.toInt32() & 31;
1676 out
.setInt32(mozilla::WrapToSigned(left
<< right
));
1680 static MOZ_ALWAYS_INLINE
bool BitRshOperation(JSContext
* cx
,
1681 MutableHandleValue lhs
,
1682 MutableHandleValue rhs
,
1683 MutableHandleValue out
) {
1684 if (!ToInt32OrBigInt(cx
, lhs
) || !ToInt32OrBigInt(cx
, rhs
)) {
1688 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1689 return BigInt::rshValue(cx
, lhs
, rhs
, out
);
1692 out
.setInt32(lhs
.toInt32() >> (rhs
.toInt32() & 31));
1696 static MOZ_ALWAYS_INLINE
bool UrshOperation(JSContext
* cx
,
1697 MutableHandleValue lhs
,
1698 MutableHandleValue rhs
,
1699 MutableHandleValue out
) {
1700 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1704 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1705 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
1706 JSMSG_BIGINT_TO_NUMBER
);
1712 if (!ToUint32(cx
, lhs
, &left
) || !ToInt32(cx
, rhs
, &right
)) {
1715 left
>>= right
& 31;
1716 out
.setNumber(uint32_t(left
));
1720 // BigInt proposal 3.2.4 Abstract Relational Comparison
1721 // Returns Nothing when at least one operand is a NaN, or when
1722 // ToNumeric or StringToBigInt can't interpret a string as a numeric
1723 // value. (These cases correspond to a NaN result in the spec.)
1724 // Otherwise, return a boolean to indicate whether lhs is less than
1725 // rhs. The operands must be primitives; the caller is responsible for
1726 // evaluating them in the correct order.
1727 static MOZ_ALWAYS_INLINE
bool LessThanImpl(JSContext
* cx
,
1728 MutableHandleValue lhs
,
1729 MutableHandleValue rhs
,
1730 mozilla::Maybe
<bool>& res
) {
1731 // Steps 1 and 2 are performed by the caller.
1734 if (lhs
.isString() && rhs
.isString()) {
1735 JSString
* l
= lhs
.toString();
1736 JSString
* r
= rhs
.toString();
1738 if (!CompareStrings(cx
, l
, r
, &result
)) {
1741 res
= mozilla::Some(result
< 0);
1746 if (lhs
.isBigInt() && rhs
.isString()) {
1747 return BigInt::lessThan(cx
, lhs
, rhs
, res
);
1751 if (lhs
.isString() && rhs
.isBigInt()) {
1752 return BigInt::lessThan(cx
, lhs
, rhs
, res
);
1756 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1761 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1762 return BigInt::lessThan(cx
, lhs
, rhs
, res
);
1765 // Step 4e for Number operands.
1766 MOZ_ASSERT(lhs
.isNumber() && rhs
.isNumber());
1767 double lhsNum
= lhs
.toNumber();
1768 double rhsNum
= rhs
.toNumber();
1770 if (std::isnan(lhsNum
) || std::isnan(rhsNum
)) {
1771 res
= mozilla::Maybe
<bool>(mozilla::Nothing());
1775 res
= mozilla::Some(lhsNum
< rhsNum
);
1779 static MOZ_ALWAYS_INLINE
bool LessThanOperation(JSContext
* cx
,
1780 MutableHandleValue lhs
,
1781 MutableHandleValue rhs
,
1783 if (lhs
.isInt32() && rhs
.isInt32()) {
1784 *res
= lhs
.toInt32() < rhs
.toInt32();
1788 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1792 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1796 mozilla::Maybe
<bool> tmpResult
;
1797 if (!LessThanImpl(cx
, lhs
, rhs
, tmpResult
)) {
1800 *res
= tmpResult
.valueOr(false);
1804 static MOZ_ALWAYS_INLINE
bool LessThanOrEqualOperation(JSContext
* cx
,
1805 MutableHandleValue lhs
,
1806 MutableHandleValue rhs
,
1808 if (lhs
.isInt32() && rhs
.isInt32()) {
1809 *res
= lhs
.toInt32() <= rhs
.toInt32();
1813 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1817 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1821 mozilla::Maybe
<bool> tmpResult
;
1822 if (!LessThanImpl(cx
, rhs
, lhs
, tmpResult
)) {
1825 *res
= !tmpResult
.valueOr(true);
1829 static MOZ_ALWAYS_INLINE
bool GreaterThanOperation(JSContext
* cx
,
1830 MutableHandleValue lhs
,
1831 MutableHandleValue rhs
,
1833 if (lhs
.isInt32() && rhs
.isInt32()) {
1834 *res
= lhs
.toInt32() > rhs
.toInt32();
1838 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1842 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1846 mozilla::Maybe
<bool> tmpResult
;
1847 if (!LessThanImpl(cx
, rhs
, lhs
, tmpResult
)) {
1850 *res
= tmpResult
.valueOr(false);
1854 static MOZ_ALWAYS_INLINE
bool GreaterThanOrEqualOperation(
1855 JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
, bool* res
) {
1856 if (lhs
.isInt32() && rhs
.isInt32()) {
1857 *res
= lhs
.toInt32() >= rhs
.toInt32();
1861 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1865 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1869 mozilla::Maybe
<bool> tmpResult
;
1870 if (!LessThanImpl(cx
, lhs
, rhs
, tmpResult
)) {
1873 *res
= !tmpResult
.valueOr(true);
1877 static MOZ_ALWAYS_INLINE
bool SetObjectElementOperation(
1878 JSContext
* cx
, HandleObject obj
, HandleId id
, HandleValue value
,
1879 HandleValue receiver
, bool strict
) {
1880 ObjectOpResult result
;
1881 return SetProperty(cx
, obj
, id
, value
, receiver
, result
) &&
1882 result
.checkStrictModeError(cx
, obj
, id
, strict
);
1885 static MOZ_ALWAYS_INLINE
void InitElemArrayOperation(JSContext
* cx
,
1887 Handle
<ArrayObject
*> arr
,
1889 MOZ_ASSERT(JSOp(*pc
) == JSOp::InitElemArray
);
1891 // The dense elements must have been initialized up to this index. The JIT
1892 // implementation also depends on this.
1893 uint32_t index
= GET_UINT32(pc
);
1894 MOZ_ASSERT(index
< arr
->getDenseCapacity());
1895 MOZ_ASSERT(index
== arr
->getDenseInitializedLength());
1897 // Bump the initialized length even for hole values to ensure the
1898 // index == initLength invariant holds for later InitElemArray ops.
1899 arr
->setDenseInitializedLength(index
+ 1);
1901 if (val
.isMagic(JS_ELEMENTS_HOLE
)) {
1902 arr
->initDenseElementHole(index
);
1904 arr
->initDenseElement(index
, val
);
1909 * As an optimization, the interpreter creates a handful of reserved Rooted<T>
1910 * variables at the beginning, thus inserting them into the Rooted list once
1911 * upon entry. ReservedRooted "borrows" a reserved Rooted variable and uses it
1912 * within a local scope, resetting the value to nullptr (or the appropriate
1913 * equivalent for T) at scope end. This avoids inserting/removing the Rooted
1914 * from the rooter list, while preventing stale values from being kept alive
1918 template <typename T
>
1919 class ReservedRooted
: public RootedOperations
<T
, ReservedRooted
<T
>> {
1920 Rooted
<T
>* savedRoot
;
1923 ReservedRooted(Rooted
<T
>* root
, const T
& ptr
) : savedRoot(root
) {
1927 explicit ReservedRooted(Rooted
<T
>* root
) : savedRoot(root
) {
1928 *root
= JS::SafelyInitialized
<T
>::create();
1931 ~ReservedRooted() { *savedRoot
= JS::SafelyInitialized
<T
>::create(); }
1933 void set(const T
& p
) const { *savedRoot
= p
; }
1934 operator Handle
<T
>() { return *savedRoot
; }
1935 operator Rooted
<T
>&() { return *savedRoot
; }
1936 MutableHandle
<T
> operator&() { return &*savedRoot
; }
1938 DECLARE_NONPOINTER_ACCESSOR_METHODS(savedRoot
->get())
1939 DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(savedRoot
->get())
1940 DECLARE_POINTER_CONSTREF_OPS(T
)
1941 DECLARE_POINTER_ASSIGN_OPS(ReservedRooted
, T
)
1944 void js::ReportInNotObjectError(JSContext
* cx
, HandleValue lref
,
1946 auto uniqueCharsFromString
= [](JSContext
* cx
,
1947 HandleValue ref
) -> UniqueChars
{
1948 static const size_t MaxStringLength
= 16;
1949 RootedString
str(cx
, ref
.toString());
1950 if (str
->length() > MaxStringLength
) {
1951 JSStringBuilder
buf(cx
);
1952 if (!buf
.appendSubstring(str
, 0, MaxStringLength
)) {
1955 if (!buf
.append("...")) {
1958 str
= buf
.finishString();
1963 return QuoteString(cx
, str
, '"');
1966 if (lref
.isString() && rref
.isString()) {
1967 UniqueChars lbytes
= uniqueCharsFromString(cx
, lref
);
1971 UniqueChars rbytes
= uniqueCharsFromString(cx
, rref
);
1975 JS_ReportErrorNumberUTF8(cx
, GetErrorMessage
, nullptr, JSMSG_IN_STRING
,
1976 lbytes
.get(), rbytes
.get());
1980 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_IN_NOT_OBJECT
,
1981 InformalValueTypeName(rref
));
1984 bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER
js::Interpret(JSContext
* cx
,
1987 * Define macros for an interpreter loop. Opcode dispatch is done by
1988 * indirect goto (aka a threaded interpreter), which is technically
1989 * non-standard but is supported by all of our supported compilers.
1991 #define INTERPRETER_LOOP()
1992 #define CASE(OP) label_##OP:
1995 #define DISPATCH_TO(OP) goto* addresses[(OP)]
1997 #define LABEL(X) (&&label_##X)
1999 // Use addresses instead of offsets to optimize for runtime speed over
2000 // load-time relocation overhead.
2001 static const void* const addresses
[EnableInterruptsPseudoOpcode
+ 1] = {
2002 #define OPCODE_LABEL(op, ...) LABEL(op),
2003 FOR_EACH_OPCODE(OPCODE_LABEL
)
2005 #define TRAILING_LABEL(v) \
2006 ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
2008 FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL
)
2009 #undef TRAILING_LABEL
2013 * Increment REGS.pc by N, load the opcode at that position,
2014 * and jump to the code to execute it.
2016 * When Debugger puts a script in single-step mode, all js::Interpret
2017 * invocations that might be presently running that script must have
2018 * interrupts enabled. It's not practical to simply check
2019 * script->stepModeEnabled() at each point some callee could have changed
2020 * it, because there are so many places js::Interpret could possibly cause
2021 * JavaScript to run: each place an object might be coerced to a primitive
2022 * or a number, for example. So instead, we expose a simple mechanism to
2023 * let Debugger tweak the affected js::Interpret frames when an onStep
2024 * handler is added: calling activation.enableInterruptsUnconditionally()
2025 * will enable interrupts, and activation.opMask() is or'd with the opcode
2026 * to implement a simple alternate dispatch.
2028 #define ADVANCE_AND_DISPATCH(N) \
2032 DISPATCH_TO(*REGS.pc | activation.opMask()); \
2036 * Shorthand for the common sequence at the end of a fixed-size opcode.
2038 #define END_CASE(OP) ADVANCE_AND_DISPATCH(JSOpLength_##OP);
2041 * Prepare to call a user-supplied branch handler, and abort the script
2042 * if it returns false.
2044 #define CHECK_BRANCH() \
2046 if (!CheckForInterrupt(cx)) goto error; \
2050 * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
2051 * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
2052 * is the backedge of a loop.
2056 int32_t nlen = (n); \
2057 if (nlen <= 0) CHECK_BRANCH(); \
2058 ADVANCE_AND_DISPATCH(nlen); \
2062 * Initialize code coverage vectors.
2064 #define INIT_COVERAGE() \
2066 if (!script->hasScriptCounts()) { \
2067 if (cx->realm()->collectCoverageForDebug()) { \
2068 if (!script->initScriptCounts(cx)) goto error; \
2074 * Increment the code coverage counter associated with the given pc.
2076 #define COUNT_COVERAGE_PC(PC) \
2078 if (script->hasScriptCounts()) { \
2079 PCCounts* counts = script->maybeGetPCCounts(PC); \
2080 MOZ_ASSERT(counts); \
2081 counts->numExec()++; \
2085 #define COUNT_COVERAGE_MAIN() \
2087 jsbytecode* main = script->main(); \
2088 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
2091 #define COUNT_COVERAGE() \
2093 MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
2094 COUNT_COVERAGE_PC(REGS.pc); \
2097 #define SET_SCRIPT(s) \
2100 MOZ_ASSERT(cx->realm() == script->realm()); \
2101 if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
2102 script->hasScriptCounts()) \
2103 activation.enableInterruptsUnconditionally(); \
2106 #define SANITY_CHECKS() \
2108 js::gc::MaybeVerifyBarriers(cx); \
2111 // Verify that an uninitialized lexical is followed by a correct check op.
2113 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2115 if (IsUninitializedLexical(val)) { \
2116 JSOp next = JSOp(*GetNextPc(REGS.pc)); \
2117 MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn || \
2118 next == JSOp::CheckThisReinit || \
2119 next == JSOp::CheckAliasedLexical); \
2123 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2129 gc::MaybeVerifyBarriers(cx
, true);
2131 InterpreterFrame
* entryFrame
= state
.pushInterpreterFrame(cx
);
2136 ActivationEntryMonitor
entryMonitor(cx
, entryFrame
);
2137 InterpreterActivation
activation(state
, cx
, entryFrame
);
2139 /* The script is used frequently, so keep a local copy. */
2140 RootedScript
script(cx
);
2141 SET_SCRIPT(REGS
.fp()->script());
2144 * Pool of rooters for use in this interpreter frame. References to these
2145 * are used for local variables within interpreter cases. This avoids
2146 * creating new rooters each time an interpreter case is entered, and also
2147 * correctness pitfalls due to incorrect compilation of destructor calls
2148 * around computed gotos.
2150 RootedValue
rootValue0(cx
), rootValue1(cx
);
2151 RootedObject
rootObject0(cx
), rootObject1(cx
);
2152 RootedFunction
rootFunction0(cx
);
2153 Rooted
<JSAtom
*> rootAtom0(cx
);
2154 Rooted
<PropertyName
*> rootName0(cx
);
2155 RootedId
rootId0(cx
);
2156 RootedScript
rootScript0(cx
);
2157 Rooted
<Scope
*> rootScope0(cx
);
2158 DebugOnly
<uint32_t> blockDepth
;
2160 /* State communicated between non-local jumps: */
2161 bool interpReturnOK
;
2162 bool frameHalfInitialized
;
2164 if (!activation
.entryFrame()->prologue(cx
)) {
2165 goto prologue_error
;
2168 if (!DebugAPI::onEnterFrame(cx
, activation
.entryFrame())) {
2172 // Increment the coverage for the main entry point.
2174 COUNT_COVERAGE_MAIN();
2176 // Enter the interpreter loop starting at the current pc.
2177 ADVANCE_AND_DISPATCH(0);
2179 INTERPRETER_LOOP() {
2180 CASE(EnableInterruptsPseudoOpcode
) {
2181 bool moreInterrupts
= false;
2182 jsbytecode op
= *REGS
.pc
;
2184 if (!script
->hasScriptCounts() &&
2185 cx
->realm()->collectCoverageForDebug()) {
2186 if (!script
->initScriptCounts(cx
)) {
2191 if (script
->isDebuggee()) {
2192 if (DebugAPI::stepModeEnabled(script
)) {
2193 if (!DebugAPI::onSingleStep(cx
)) {
2196 moreInterrupts
= true;
2199 if (DebugAPI::hasAnyBreakpointsOrStepMode(script
)) {
2200 moreInterrupts
= true;
2203 if (DebugAPI::hasBreakpointsAt(script
, REGS
.pc
)) {
2204 if (!DebugAPI::onTrap(cx
)) {
2210 MOZ_ASSERT(activation
.opMask() == EnableInterruptsPseudoOpcode
);
2211 if (!moreInterrupts
) {
2212 activation
.clearInterruptsMask();
2215 /* Commence executing the actual opcode. */
2220 /* Various 1-byte no-ops. */
2223 CASE(NopDestructuring
)
2224 CASE(TryDestructuring
) {
2225 MOZ_ASSERT(GetBytecodeLength(REGS
.pc
) == 1);
2226 ADVANCE_AND_DISPATCH(1);
2231 END_CASE(JumpTarget
)
2236 // Attempt on-stack replacement into the Baseline Interpreter.
2237 if (jit::IsBaselineInterpreterEnabled()) {
2238 script
->incWarmUpCounter();
2240 jit::MethodStatus status
=
2241 jit::CanEnterBaselineInterpreterAtBranch(cx
, REGS
.fp());
2242 if (status
== jit::Method_Error
) {
2245 if (status
== jit::Method_Compiled
) {
2246 bool wasProfiler
= REGS
.fp()->hasPushedGeckoProfilerFrame();
2248 jit::JitExecStatus maybeOsr
;
2250 GeckoProfilerBaselineOSRMarker
osr(cx
, wasProfiler
);
2252 jit::EnterBaselineInterpreterAtBranch(cx
, REGS
.fp(), REGS
.pc
);
2255 // We failed to call into baseline at all, so treat as an error.
2256 if (maybeOsr
== jit::JitExec_Aborted
) {
2260 interpReturnOK
= (maybeOsr
== jit::JitExec_Ok
);
2262 // Pop the profiler frame pushed by the interpreter. (The compiled
2263 // version of the function popped a copy of the frame pushed by the
2266 cx
->geckoProfiler().exit(cx
, script
);
2269 if (activation
.entryFrame() != REGS
.fp()) {
2270 goto jit_return_pop_frame
;
2272 goto leave_on_safe_point
;
2281 CASE(ForceInterpreter
) {
2282 // Ensure pattern matching still works.
2283 MOZ_ASSERT(script
->hasForceInterpreterOp());
2285 END_CASE(ForceInterpreter
)
2287 CASE(Undefined
) { PUSH_UNDEFINED(); }
2290 CASE(Pop
) { REGS
.sp
--; }
2294 MOZ_ASSERT(GET_UINT16(REGS
.pc
) <= REGS
.stackDepth());
2295 REGS
.sp
-= GET_UINT16(REGS
.pc
);
2300 MOZ_ASSERT(GET_UINT24(REGS
.pc
) < REGS
.stackDepth());
2301 unsigned i
= GET_UINT24(REGS
.pc
);
2302 const Value
& rref
= REGS
.sp
[-int(i
+ 1)];
2307 CASE(SetRval
) { POP_RETURN_VALUE(); }
2310 CASE(GetRval
) { PUSH_COPY(REGS
.fp()->returnValue()); }
2314 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
2316 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
2318 if (!EnterWithOperation(cx
, REGS
.fp(), val
, scope
.as
<WithScope
>())) {
2325 REGS
.fp()->popOffEnvironmentChain
<WithEnvironmentObject
>();
2335 * When the inlined frame exits with an exception or an error, ok will be
2336 * false after the inline_return label.
2340 successful_return_continuation
:
2341 interpReturnOK
= true;
2343 return_continuation
:
2344 frameHalfInitialized
= false;
2346 prologue_return_continuation
:
2348 if (activation
.entryFrame() != REGS
.fp()) {
2349 // Stop the engine. (No details about which engine exactly, could be
2350 // interpreter, Baseline or IonMonkey.)
2351 if (MOZ_LIKELY(!frameHalfInitialized
)) {
2353 DebugAPI::onLeaveFrame(cx
, REGS
.fp(), REGS
.pc
, interpReturnOK
);
2355 REGS
.fp()->epilogue(cx
, REGS
.pc
);
2358 jit_return_pop_frame
:
2360 activation
.popInlineFrame(REGS
.fp());
2362 JSScript
* callerScript
= REGS
.fp()->script();
2363 if (cx
->realm() != callerScript
->realm()) {
2364 cx
->leaveRealm(callerScript
->realm());
2366 SET_SCRIPT(callerScript
);
2371 MOZ_ASSERT(IsInvokePC(REGS
.pc
));
2372 MOZ_ASSERT(cx
->realm() == script
->realm());
2374 /* Resume execution in the calling frame. */
2375 if (MOZ_LIKELY(interpReturnOK
)) {
2376 if (JSOp(*REGS
.pc
) == JSOp::Resume
) {
2377 ADVANCE_AND_DISPATCH(JSOpLength_Resume
);
2380 MOZ_ASSERT(GetBytecodeLength(REGS
.pc
) == JSOpLength_Call
);
2381 ADVANCE_AND_DISPATCH(JSOpLength_Call
);
2386 // Stack should be empty for the outer frame, unless we executed the
2387 // first |await| expression in an async function.
2388 MOZ_ASSERT(REGS
.stackDepth() == 0 ||
2389 (JSOp(*REGS
.pc
) == JSOp::Await
&&
2390 !REGS
.fp()->isResumedGenerator()));
2399 CASE(Goto
) { BRANCH(GET_JUMP_OFFSET(REGS
.pc
)); }
2402 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2405 BRANCH(GET_JUMP_OFFSET(REGS
.pc
));
2408 END_CASE(JumpIfFalse
)
2411 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2414 BRANCH(GET_JUMP_OFFSET(REGS
.pc
));
2417 END_CASE(JumpIfTrue
)
2420 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2422 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS
.pc
));
2428 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2429 bool cond
= !res
.isNullOrUndefined();
2431 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS
.pc
));
2437 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2439 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS
.pc
));
2444 #define FETCH_ELEMENT_ID(n, id) \
2446 if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
2449 #define TRY_BRANCH_AFTER_COND(cond, spdec) \
2451 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1); \
2453 (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
2455 REGS.sp -= (spdec); \
2456 if ((cond) == (diff_ != 0)) { \
2458 BRANCH(GET_JUMP_OFFSET(REGS.pc)); \
2460 ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse); \
2465 HandleValue rref
= REGS
.stackHandleAt(-1);
2466 if (!rref
.isObject()) {
2467 HandleValue lref
= REGS
.stackHandleAt(-2);
2468 ReportInNotObjectError(cx
, lref
, rref
);
2473 ReservedRooted
<JSObject
*> obj(&rootObject0
, &rref
.toObject());
2474 ReservedRooted
<jsid
> id(&rootId0
);
2475 FETCH_ELEMENT_ID(-2, id
);
2476 if (!HasProperty(cx
, obj
, id
, &found
)) {
2480 TRY_BRANCH_AFTER_COND(found
, 2);
2482 REGS
.sp
[-1].setBoolean(found
);
2487 HandleValue val
= REGS
.stackHandleAt(-1);
2488 HandleValue idval
= REGS
.stackHandleAt(-2);
2491 if (!HasOwnProperty(cx
, val
, idval
, &found
)) {
2496 REGS
.sp
[-1].setBoolean(found
);
2500 CASE(CheckPrivateField
) {
2501 /* Load the object being initialized into lval/val. */
2502 HandleValue val
= REGS
.stackHandleAt(-2);
2503 HandleValue idval
= REGS
.stackHandleAt(-1);
2505 bool result
= false;
2506 if (!CheckPrivateFieldOperation(cx
, REGS
.pc
, val
, idval
, &result
)) {
2510 PUSH_BOOLEAN(result
);
2512 END_CASE(CheckPrivateField
)
2514 CASE(NewPrivateName
) {
2515 ReservedRooted
<JSAtom
*> name(&rootAtom0
, script
->getAtom(REGS
.pc
));
2517 auto* symbol
= NewPrivateName(cx
, name
);
2522 PUSH_SYMBOL(symbol
);
2524 END_CASE(NewPrivateName
)
2526 CASE(IsNullOrUndefined
) {
2527 bool b
= REGS
.sp
[-1].isNullOrUndefined();
2530 END_CASE(IsNullOrUndefined
)
2533 MOZ_ASSERT(REGS
.stackDepth() >= 1);
2534 HandleValue val
= REGS
.stackHandleAt(-1);
2535 JSObject
* iter
= ValueToIterator(cx
, val
);
2539 REGS
.sp
[-1].setObject(*iter
);
2544 MOZ_ASSERT(REGS
.stackDepth() >= 1);
2545 MOZ_ASSERT(REGS
.sp
[-1].isObject());
2546 Value v
= IteratorMore(®S
.sp
[-1].toObject());
2552 bool b
= REGS
.sp
[-1].isMagic(JS_NO_ITER_VALUE
);
2558 MOZ_ASSERT(REGS
.stackDepth() >= 2);
2559 CloseIterator(®S
.sp
[-2].toObject());
2565 ReservedRooted
<JSObject
*> iter(&rootObject0
, ®S
.sp
[-1].toObject());
2566 CompletionKind kind
= CompletionKind(GET_UINT8(REGS
.pc
));
2567 if (!CloseIterOperation(cx
, iter
, kind
)) {
2574 CASE(IsGenClosing
) {
2575 bool b
= REGS
.sp
[-1].isMagic(JS_GENERATOR_CLOSING
);
2578 END_CASE(IsGenClosing
)
2581 MOZ_ASSERT(REGS
.stackDepth() >= 1);
2582 const Value
& rref
= REGS
.sp
[-1];
2588 MOZ_ASSERT(REGS
.stackDepth() >= 2);
2589 const Value
& lref
= REGS
.sp
[-2];
2590 const Value
& rref
= REGS
.sp
[-1];
2597 MOZ_ASSERT(REGS
.stackDepth() >= 2);
2598 Value
& lref
= REGS
.sp
[-2];
2599 Value
& rref
= REGS
.sp
[-1];
2605 unsigned i
= GET_UINT8(REGS
.pc
);
2606 MOZ_ASSERT(REGS
.stackDepth() >= i
+ 1);
2607 Value lval
= REGS
.sp
[-int(i
+ 1)];
2608 memmove(REGS
.sp
- (i
+ 1), REGS
.sp
- i
, sizeof(Value
) * i
);
2614 int i
= GET_UINT8(REGS
.pc
);
2615 MOZ_ASSERT(REGS
.stackDepth() >= unsigned(i
) + 1);
2616 Value lval
= REGS
.sp
[-1];
2617 memmove(REGS
.sp
- i
, REGS
.sp
- (i
+ 1), sizeof(Value
) * i
);
2618 REGS
.sp
[-(i
+ 1)] = lval
;
2624 JSOp op
= JSOp(*REGS
.pc
);
2625 ReservedRooted
<JSObject
*> envChain(&rootObject0
);
2626 if (op
== JSOp::BindName
) {
2627 envChain
.set(REGS
.fp()->environmentChain());
2629 MOZ_ASSERT(!script
->hasNonSyntacticScope());
2630 envChain
.set(®S
.fp()->global().lexicalEnvironment());
2632 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2634 // Assigning to an undeclared name adds a property to the global object.
2635 ReservedRooted
<JSObject
*> env(&rootObject1
);
2636 if (!LookupNameUnqualified(cx
, name
, envChain
, &env
)) {
2642 static_assert(JSOpLength_BindName
== JSOpLength_BindGName
,
2643 "We're sharing the END_CASE so the lengths better match");
2648 JSObject
* varObj
= BindVarOperation(cx
, REGS
.fp()->environmentChain());
2649 PUSH_OBJECT(*varObj
);
2654 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2655 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2656 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2657 if (!BitOrOperation(cx
, lhs
, rhs
, res
)) {
2665 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2666 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2667 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2668 if (!BitXorOperation(cx
, lhs
, rhs
, res
)) {
2676 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2677 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2678 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2679 if (!BitAndOperation(cx
, lhs
, rhs
, res
)) {
2687 if (!LooseEqualityOp
<true>(cx
, REGS
)) {
2694 if (!LooseEqualityOp
<false>(cx
, REGS
)) {
2700 #define STRICT_EQUALITY_OP(OP, COND) \
2702 HandleValue lval = REGS.stackHandleAt(-2); \
2703 HandleValue rval = REGS.stackHandleAt(-1); \
2705 if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
2708 (COND) = equal OP true; \
2714 STRICT_EQUALITY_OP(==, cond
);
2715 REGS
.sp
[-1].setBoolean(cond
);
2721 STRICT_EQUALITY_OP(!=, cond
);
2722 REGS
.sp
[-1].setBoolean(cond
);
2726 #undef STRICT_EQUALITY_OP
2729 bool cond
= REGS
.sp
[-1].toBoolean();
2733 BRANCH(GET_JUMP_OFFSET(REGS
.pc
));
2740 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2741 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2742 if (!LessThanOperation(cx
, lval
, rval
, &cond
)) {
2745 TRY_BRANCH_AFTER_COND(cond
, 2);
2746 REGS
.sp
[-2].setBoolean(cond
);
2753 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2754 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2755 if (!LessThanOrEqualOperation(cx
, lval
, rval
, &cond
)) {
2758 TRY_BRANCH_AFTER_COND(cond
, 2);
2759 REGS
.sp
[-2].setBoolean(cond
);
2766 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2767 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2768 if (!GreaterThanOperation(cx
, lval
, rval
, &cond
)) {
2771 TRY_BRANCH_AFTER_COND(cond
, 2);
2772 REGS
.sp
[-2].setBoolean(cond
);
2779 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2780 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2781 if (!GreaterThanOrEqualOperation(cx
, lval
, rval
, &cond
)) {
2784 TRY_BRANCH_AFTER_COND(cond
, 2);
2785 REGS
.sp
[-2].setBoolean(cond
);
2791 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2792 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2793 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2794 if (!BitLshOperation(cx
, lhs
, rhs
, res
)) {
2802 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2803 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2804 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2805 if (!BitRshOperation(cx
, lhs
, rhs
, res
)) {
2813 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2814 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2815 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2816 if (!UrshOperation(cx
, lhs
, rhs
, res
)) {
2824 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2825 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2826 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2827 if (!AddOperation(cx
, lval
, rval
, res
)) {
2835 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2836 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2837 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2838 if (!SubOperation(cx
, &lval
, &rval
, res
)) {
2846 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2847 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2848 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2849 if (!MulOperation(cx
, &lval
, &rval
, res
)) {
2857 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2858 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2859 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2860 if (!DivOperation(cx
, &lval
, &rval
, res
)) {
2868 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2869 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2870 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2871 if (!ModOperation(cx
, &lval
, &rval
, res
)) {
2879 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2880 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2881 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2882 if (!PowOperation(cx
, &lval
, &rval
, res
)) {
2890 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2892 PUSH_BOOLEAN(!cond
);
2897 MutableHandleValue val
= REGS
.stackHandleAt(-1);
2898 if (!BitNotOperation(cx
, val
, val
)) {
2905 MutableHandleValue val
= REGS
.stackHandleAt(-1);
2906 if (!NegOperation(cx
, val
, val
)) {
2913 if (!ToNumber(cx
, REGS
.stackHandleAt(-1))) {
2920 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2921 ReservedRooted
<JSObject
*> envObj(&rootObject0
,
2922 REGS
.fp()->environmentChain());
2925 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2926 if (!DeleteNameOperation(cx
, name
, envObj
, res
)) {
2933 CASE(StrictDelProp
) {
2934 static_assert(JSOpLength_DelProp
== JSOpLength_StrictDelProp
,
2935 "delprop and strictdelprop must be the same size");
2936 HandleValue val
= REGS
.stackHandleAt(-1);
2937 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2939 if (JSOp(*REGS
.pc
) == JSOp::StrictDelProp
) {
2940 if (!DelPropOperation
<true>(cx
, val
, name
, &res
)) {
2944 if (!DelPropOperation
<false>(cx
, val
, name
, &res
)) {
2948 REGS
.sp
[-1].setBoolean(res
);
2953 CASE(StrictDelElem
) {
2954 static_assert(JSOpLength_DelElem
== JSOpLength_StrictDelElem
,
2955 "delelem and strictdelelem must be the same size");
2956 HandleValue val
= REGS
.stackHandleAt(-2);
2957 HandleValue propval
= REGS
.stackHandleAt(-1);
2959 if (JSOp(*REGS
.pc
) == JSOp::StrictDelElem
) {
2960 if (!DelElemOperation
<true>(cx
, val
, propval
, &res
)) {
2964 if (!DelElemOperation
<false>(cx
, val
, propval
, &res
)) {
2968 REGS
.sp
[-2].setBoolean(res
);
2973 CASE(ToPropertyKey
) {
2974 ReservedRooted
<Value
> idval(&rootValue1
, REGS
.sp
[-1]);
2975 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2976 if (!ToPropertyKeyOperation(cx
, idval
, res
)) {
2980 END_CASE(ToPropertyKey
)
2984 REGS
.sp
[-1].setString(TypeOfOperation(REGS
.sp
[-1], cx
->runtime()));
2988 CASE(Void
) { REGS
.sp
[-1].setUndefined(); }
2991 CASE(FunctionThis
) {
2993 if (!GetFunctionThis(cx
, REGS
.fp(), REGS
.stackHandleAt(-1))) {
2997 END_CASE(FunctionThis
)
3000 MOZ_ASSERT(!script
->hasNonSyntacticScope());
3001 PUSH_OBJECT(*cx
->global()->lexicalEnvironment().thisObject());
3003 END_CASE(GlobalThis
)
3005 CASE(NonSyntacticGlobalThis
) {
3007 GetNonSyntacticGlobalThis(cx
, REGS
.fp()->environmentChain(),
3008 REGS
.stackHandleAt(-1));
3010 END_CASE(NonSyntacticGlobalThis
)
3013 if (!REGS
.sp
[-1].isObject()) {
3015 ThrowCheckIsObject(cx
, CheckIsObjectKind(GET_UINT8(REGS
.pc
))));
3019 END_CASE(CheckIsObj
)
3022 if (REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
3023 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx
));
3029 CASE(CheckThisReinit
) {
3030 if (!REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
3031 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx
));
3035 END_CASE(CheckThisReinit
)
3038 ReservedRooted
<Value
> thisv(&rootValue0
, REGS
.sp
[-1]);
3039 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
3040 if (!REGS
.fp()->checkReturn(cx
, thisv
, rval
)) {
3044 END_CASE(CheckReturn
)
3047 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-1]);
3048 MutableHandleValue res
= REGS
.stackHandleAt(-1);
3049 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3050 if (!GetPropertyOperation(cx
, name
, lval
, res
)) {
3053 cx
->debugOnlyCheck(res
);
3057 CASE(GetPropSuper
) {
3058 ReservedRooted
<Value
> receiver(&rootValue0
, REGS
.sp
[-2]);
3059 HandleValue lval
= REGS
.stackHandleAt(-1);
3060 MOZ_ASSERT(lval
.isObjectOrNull());
3061 MutableHandleValue rref
= REGS
.stackHandleAt(-2);
3062 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3064 ReservedRooted
<JSObject
*> obj(&rootObject0
);
3065 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -1, name
);
3070 if (!GetProperty(cx
, obj
, receiver
, name
, rref
)) {
3074 cx
->debugOnlyCheck(rref
);
3078 END_CASE(GetPropSuper
)
3080 CASE(GetBoundName
) {
3081 ReservedRooted
<JSObject
*> env(&rootObject0
, ®S
.sp
[-1].toObject());
3082 ReservedRooted
<jsid
> id(&rootId0
, NameToId(script
->getName(REGS
.pc
)));
3083 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
3084 if (!GetNameBoundInEnvironment(cx
, env
, id
, rval
)) {
3087 cx
->debugOnlyCheck(rval
);
3089 END_CASE(GetBoundName
)
3091 CASE(SetIntrinsic
) {
3092 HandleValue value
= REGS
.stackHandleAt(-1);
3094 if (!SetIntrinsicOperation(cx
, script
, REGS
.pc
, value
)) {
3098 END_CASE(SetIntrinsic
)
3101 CASE(StrictSetGName
)
3103 CASE(StrictSetName
) {
3104 static_assert(JSOpLength_SetName
== JSOpLength_StrictSetName
,
3105 "setname and strictsetname must be the same size");
3106 static_assert(JSOpLength_SetGName
== JSOpLength_StrictSetGName
,
3107 "setgname and strictsetgname must be the same size");
3108 static_assert(JSOpLength_SetName
== JSOpLength_SetGName
,
3109 "We're sharing the END_CASE so the lengths better match");
3111 ReservedRooted
<JSObject
*> env(&rootObject0
, ®S
.sp
[-2].toObject());
3112 HandleValue value
= REGS
.stackHandleAt(-1);
3114 if (!SetNameOperation(cx
, script
, REGS
.pc
, env
, value
)) {
3118 REGS
.sp
[-2] = REGS
.sp
[-1];
3124 CASE(StrictSetProp
) {
3125 static_assert(JSOpLength_SetProp
== JSOpLength_StrictSetProp
,
3126 "setprop and strictsetprop must be the same size");
3128 HandleValue lval
= REGS
.stackHandleAt(lvalIndex
);
3129 HandleValue rval
= REGS
.stackHandleAt(-1);
3131 ReservedRooted
<jsid
> id(&rootId0
, NameToId(script
->getName(REGS
.pc
)));
3133 bool strict
= JSOp(*REGS
.pc
) == JSOp::StrictSetProp
;
3135 ReservedRooted
<JSObject
*> obj(&rootObject0
);
3136 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, lvalIndex
, id
);
3141 if (!SetObjectElementOperation(cx
, obj
, id
, rval
, lval
, strict
)) {
3145 REGS
.sp
[-2] = REGS
.sp
[-1];
3151 CASE(StrictSetPropSuper
) {
3153 JSOpLength_SetPropSuper
== JSOpLength_StrictSetPropSuper
,
3154 "setprop-super and strictsetprop-super must be the same size");
3156 HandleValue receiver
= REGS
.stackHandleAt(-3);
3157 HandleValue lval
= REGS
.stackHandleAt(-2);
3158 MOZ_ASSERT(lval
.isObjectOrNull());
3159 HandleValue rval
= REGS
.stackHandleAt(-1);
3160 ReservedRooted
<jsid
> id(&rootId0
, NameToId(script
->getName(REGS
.pc
)));
3162 bool strict
= JSOp(*REGS
.pc
) == JSOp::StrictSetPropSuper
;
3164 ReservedRooted
<JSObject
*> obj(&rootObject0
);
3165 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -2, id
);
3170 if (!SetObjectElementOperation(cx
, obj
, id
, rval
, receiver
, strict
)) {
3174 REGS
.sp
[-3] = REGS
.sp
[-1];
3177 END_CASE(SetPropSuper
)
3181 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[lvalIndex
]);
3182 HandleValue rval
= REGS
.stackHandleAt(-1);
3183 MutableHandleValue res
= REGS
.stackHandleAt(-2);
3185 if (!GetElementOperationWithStackIndex(cx
, lval
, lvalIndex
, rval
, res
)) {
3193 CASE(GetElemSuper
) {
3194 ReservedRooted
<Value
> receiver(&rootValue0
, REGS
.sp
[-3]);
3195 HandleValue index
= REGS
.stackHandleAt(-2);
3196 HandleValue lval
= REGS
.stackHandleAt(-1);
3197 MOZ_ASSERT(lval
.isObjectOrNull());
3199 MutableHandleValue res
= REGS
.stackHandleAt(-3);
3201 ReservedRooted
<JSObject
*> obj(&rootObject0
);
3202 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -1, index
);
3207 if (!GetObjectElementOperation(cx
, JSOp(*REGS
.pc
), obj
, receiver
, index
,
3214 END_CASE(GetElemSuper
)
3217 CASE(StrictSetElem
) {
3218 static_assert(JSOpLength_SetElem
== JSOpLength_StrictSetElem
,
3219 "setelem and strictsetelem must be the same size");
3220 int receiverIndex
= -3;
3221 HandleValue receiver
= REGS
.stackHandleAt(receiverIndex
);
3222 HandleValue value
= REGS
.stackHandleAt(-1);
3224 ReservedRooted
<JSObject
*> obj(&rootObject0
);
3225 obj
= ToObjectFromStackForPropertyAccess(cx
, receiver
, receiverIndex
,
3226 REGS
.stackHandleAt(-2));
3231 ReservedRooted
<jsid
> id(&rootId0
);
3232 FETCH_ELEMENT_ID(-2, id
);
3234 if (!SetObjectElementOperation(cx
, obj
, id
, value
, receiver
,
3235 JSOp(*REGS
.pc
) == JSOp::StrictSetElem
)) {
3238 REGS
.sp
[-3] = value
;
3244 CASE(StrictSetElemSuper
) {
3246 JSOpLength_SetElemSuper
== JSOpLength_StrictSetElemSuper
,
3247 "setelem-super and strictsetelem-super must be the same size");
3249 HandleValue receiver
= REGS
.stackHandleAt(-4);
3250 HandleValue lval
= REGS
.stackHandleAt(-2);
3251 MOZ_ASSERT(lval
.isObjectOrNull());
3252 HandleValue value
= REGS
.stackHandleAt(-1);
3254 ReservedRooted
<JSObject
*> obj(&rootObject0
);
3255 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -2,
3256 REGS
.stackHandleAt(-3));
3261 ReservedRooted
<jsid
> id(&rootId0
);
3262 FETCH_ELEMENT_ID(-3, id
);
3264 bool strict
= JSOp(*REGS
.pc
) == JSOp::StrictSetElemSuper
;
3265 if (!SetObjectElementOperation(cx
, obj
, id
, value
, receiver
, strict
)) {
3268 REGS
.sp
[-4] = value
;
3271 END_CASE(SetElemSuper
)
3275 static_assert(JSOpLength_Eval
== JSOpLength_StrictEval
,
3276 "eval and stricteval must be the same size");
3278 CallArgs args
= CallArgsFromSp(GET_ARGC(REGS
.pc
), REGS
.sp
);
3279 if (cx
->global()->valueIsEval(args
.calleev())) {
3280 if (!DirectEval(cx
, args
.get(0), args
.rval())) {
3284 if (!CallFromStack(cx
, args
, CallReason::Call
)) {
3289 REGS
.sp
= args
.spAfterCall();
3295 CASE(SpreadSuperCall
) {
3296 if (REGS
.fp()->hasPushedGeckoProfilerFrame()) {
3297 cx
->geckoProfiler().updatePC(cx
, script
, REGS
.pc
);
3303 CASE(StrictSpreadEval
) {
3304 static_assert(JSOpLength_SpreadEval
== JSOpLength_StrictSpreadEval
,
3305 "spreadeval and strictspreadeval must be the same size");
3306 bool construct
= JSOp(*REGS
.pc
) == JSOp::SpreadNew
||
3307 JSOp(*REGS
.pc
) == JSOp::SpreadSuperCall
;
3309 MOZ_ASSERT(REGS
.stackDepth() >= 3u + construct
);
3311 HandleValue callee
= REGS
.stackHandleAt(-3 - construct
);
3312 HandleValue thisv
= REGS
.stackHandleAt(-2 - construct
);
3313 HandleValue arr
= REGS
.stackHandleAt(-1 - construct
);
3314 MutableHandleValue ret
= REGS
.stackHandleAt(-3 - construct
);
3316 RootedValue
& newTarget
= rootValue0
;
3318 newTarget
= REGS
.sp
[-1];
3320 newTarget
= NullValue();
3323 if (!SpreadCallOperation(cx
, script
, REGS
.pc
, thisv
, callee
, arr
,
3328 REGS
.sp
-= 2 + construct
;
3330 END_CASE(SpreadCall
)
3338 CASE(CallContentIter
)
3340 static_assert(JSOpLength_Call
== JSOpLength_New
,
3341 "call and new must be the same size");
3342 static_assert(JSOpLength_Call
== JSOpLength_CallContent
,
3343 "call and call-content must be the same size");
3344 static_assert(JSOpLength_Call
== JSOpLength_CallIgnoresRv
,
3345 "call and call-ignores-rv must be the same size");
3346 static_assert(JSOpLength_Call
== JSOpLength_CallIter
,
3347 "call and calliter must be the same size");
3348 static_assert(JSOpLength_Call
== JSOpLength_CallContentIter
,
3349 "call and call-content-iter must be the same size");
3350 static_assert(JSOpLength_Call
== JSOpLength_SuperCall
,
3351 "call and supercall must be the same size");
3353 if (REGS
.fp()->hasPushedGeckoProfilerFrame()) {
3354 cx
->geckoProfiler().updatePC(cx
, script
, REGS
.pc
);
3357 JSOp op
= JSOp(*REGS
.pc
);
3358 MaybeConstruct construct
= MaybeConstruct(
3359 op
== JSOp::New
|| op
== JSOp::NewContent
|| op
== JSOp::SuperCall
);
3360 bool ignoresReturnValue
= op
== JSOp::CallIgnoresRv
;
3361 unsigned argStackSlots
= GET_ARGC(REGS
.pc
) + construct
;
3363 MOZ_ASSERT(REGS
.stackDepth() >= 2u + GET_ARGC(REGS
.pc
));
3365 CallArgsFromSp(argStackSlots
, REGS
.sp
, construct
, ignoresReturnValue
);
3367 JSFunction
* maybeFun
;
3368 bool isFunction
= IsFunctionObject(args
.calleev(), &maybeFun
);
3370 // Use the slow path if the callee is not an interpreted function, if we
3371 // have to throw an exception, or if we might have to invoke the
3372 // OnNativeCall hook for a self-hosted builtin.
3373 if (!isFunction
|| !maybeFun
->isInterpreted() ||
3374 (construct
&& !maybeFun
->isConstructor()) ||
3375 (!construct
&& maybeFun
->isClassConstructor()) ||
3376 cx
->insideDebuggerEvaluationWithOnNativeCallHook
) {
3378 CallReason reason
= op
== JSOp::NewContent
? CallReason::CallContent
3380 if (!ConstructFromStack(cx
, args
, reason
)) {
3384 if ((op
== JSOp::CallIter
|| op
== JSOp::CallContentIter
) &&
3385 args
.calleev().isPrimitive()) {
3386 MOZ_ASSERT(args
.length() == 0, "thisv must be on top of the stack");
3387 ReportValueError(cx
, JSMSG_NOT_ITERABLE
, -1, args
.thisv(), nullptr);
3392 (op
== JSOp::CallContent
|| op
== JSOp::CallContentIter
)
3393 ? CallReason::CallContent
3395 if (!CallFromStack(cx
, args
, reason
)) {
3399 Value
* newsp
= args
.spAfterCall();
3401 ADVANCE_AND_DISPATCH(JSOpLength_Call
);
3405 MOZ_ASSERT(maybeFun
);
3406 ReservedRooted
<JSFunction
*> fun(&rootFunction0
, maybeFun
);
3407 ReservedRooted
<JSScript
*> funScript(
3408 &rootScript0
, JSFunction::getOrCreateScript(cx
, fun
));
3413 // Enter the callee's realm if this is a cross-realm call. Use
3414 // MakeScopeExit to leave this realm on all error/JIT-return paths
3416 const bool isCrossRealm
= cx
->realm() != funScript
->realm();
3418 cx
->enterRealmOf(funScript
);
3420 auto leaveRealmGuard
=
3421 mozilla::MakeScopeExit([isCrossRealm
, cx
, &script
] {
3423 cx
->leaveRealm(script
->realm());
3427 if (construct
&& !MaybeCreateThisForConstructor(cx
, args
)) {
3432 InvokeState
state(cx
, args
, construct
);
3434 jit::EnterJitStatus status
= jit::MaybeEnterJit(cx
, state
);
3436 case jit::EnterJitStatus::Error
:
3438 case jit::EnterJitStatus::Ok
:
3439 interpReturnOK
= true;
3441 REGS
.sp
= args
.spAfterCall();
3443 case jit::EnterJitStatus::NotEntered
:
3447 #ifdef NIGHTLY_BUILD
3448 // If entry trampolines are enabled, call back into
3449 // MaybeEnterInterpreterTrampoline so we can generate an
3450 // entry trampoline for the new frame.
3451 if (jit::JitOptions
.emitInterpreterEntryTrampoline
) {
3452 if (MaybeEnterInterpreterTrampoline(cx
, state
)) {
3453 interpReturnOK
= true;
3455 REGS
.sp
= args
.spAfterCall();
3463 funScript
= fun
->nonLazyScript();
3465 if (!activation
.pushInlineFrame(args
, funScript
, construct
)) {
3468 leaveRealmGuard
.release(); // We leave the callee's realm when we
3469 // call popInlineFrame.
3472 SET_SCRIPT(REGS
.fp()->script());
3474 if (!REGS
.fp()->prologue(cx
)) {
3475 goto prologue_error
;
3478 if (!DebugAPI::onEnterFrame(cx
, REGS
.fp())) {
3482 // Increment the coverage for the main entry point.
3484 COUNT_COVERAGE_MAIN();
3486 /* Load first op and dispatch it (safe since JSOp::RetRval). */
3487 ADVANCE_AND_DISPATCH(0);
3490 CASE(OptimizeSpreadCall
) {
3491 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
3492 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
3494 if (!OptimizeSpreadCall(cx
, val
, rval
)) {
3498 END_CASE(OptimizeSpreadCall
)
3501 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx
, GET_UINT8(REGS
.pc
)));
3506 CASE(ImplicitThis
) {
3507 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3508 ReservedRooted
<JSObject
*> envObj(&rootObject0
,
3509 REGS
.fp()->environmentChain());
3510 ReservedRooted
<JSObject
*> env(&rootObject1
);
3511 if (!LookupNameWithGlobalDefault(cx
, name
, envObj
, &env
)) {
3515 Value v
= ComputeImplicitThis(env
);
3518 END_CASE(ImplicitThis
)
3521 ReservedRooted
<Value
> rval(&rootValue0
);
3522 ReservedRooted
<JSObject
*> env(&rootObject0
,
3523 &cx
->global()->lexicalEnvironment());
3524 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3525 MOZ_ASSERT(!script
->hasNonSyntacticScope());
3526 if (!GetNameOperation(cx
, env
, name
, JSOp(REGS
.pc
[JSOpLength_GetGName
]),
3536 ReservedRooted
<Value
> rval(&rootValue0
);
3537 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3538 if (!GetNameOperation(cx
, REGS
.fp()->environmentChain(), name
,
3539 JSOp(REGS
.pc
[JSOpLength_GetName
]), &rval
)) {
3549 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
3550 HandleObject envChain
= REGS
.fp()->environmentChain();
3551 if (!GetImportOperation(cx
, envChain
, script
, REGS
.pc
, rval
)) {
3557 CASE(GetIntrinsic
) {
3558 ReservedRooted
<Value
> rval(&rootValue0
);
3559 if (!GetIntrinsicOperation(cx
, script
, REGS
.pc
, &rval
)) {
3565 END_CASE(GetIntrinsic
)
3567 CASE(Uint16
) { PUSH_INT32((int32_t)GET_UINT16(REGS
.pc
)); }
3570 CASE(Uint24
) { PUSH_INT32((int32_t)GET_UINT24(REGS
.pc
)); }
3573 CASE(Int8
) { PUSH_INT32(GET_INT8(REGS
.pc
)); }
3576 CASE(Int32
) { PUSH_INT32(GET_INT32(REGS
.pc
)); }
3579 CASE(Double
) { PUSH_COPY(GET_INLINE_VALUE(REGS
.pc
)); }
3582 CASE(String
) { PUSH_STRING(script
->getString(REGS
.pc
)); }
3586 MutableHandleValue oper
= REGS
.stackHandleAt(-1);
3588 if (!oper
.isString()) {
3589 JSString
* operString
= ToString
<CanGC
>(cx
, oper
);
3593 oper
.setString(operString
);
3599 PUSH_SYMBOL(cx
->wellKnownSymbols().get(GET_UINT8(REGS
.pc
)));
3604 MOZ_ASSERT(script
->treatAsRunOnce());
3605 PUSH_OBJECT(*script
->getObject(REGS
.pc
));
3610 JSObject
* cso
= script
->getObject(REGS
.pc
);
3611 MOZ_ASSERT(!cso
->as
<ArrayObject
>().isExtensible());
3612 MOZ_ASSERT(cso
->as
<ArrayObject
>().containsPure(cx
->names().raw
));
3615 END_CASE(CallSiteObj
)
3619 * Push a regexp object cloned from the regexp literal object mapped by
3620 * the bytecode at pc.
3622 ReservedRooted
<JSObject
*> re(&rootObject0
, script
->getRegExp(REGS
.pc
));
3623 JSObject
* obj
= CloneRegExpObject(cx
, re
.as
<RegExpObject
>());
3631 CASE(Zero
) { PUSH_INT32(0); }
3634 CASE(One
) { PUSH_INT32(1); }
3637 CASE(Null
) { PUSH_NULL(); }
3640 CASE(False
) { PUSH_BOOLEAN(false); }
3643 CASE(True
) { PUSH_BOOLEAN(true); }
3647 jsbytecode
* pc2
= REGS
.pc
;
3648 int32_t len
= GET_JUMP_OFFSET(pc2
);
3651 * ECMAv2+ forbids conversion of discriminant, so we will skip to the
3652 * default case if the discriminant isn't already an int jsval. (This
3653 * opcode is emitted only for dense int-domain switches.)
3655 const Value
& rref
= *--REGS
.sp
;
3657 if (rref
.isInt32()) {
3660 /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
3661 if (!rref
.isDouble() || !NumberEqualsInt32(rref
.toDouble(), &i
)) {
3662 ADVANCE_AND_DISPATCH(len
);
3666 pc2
+= JUMP_OFFSET_LEN
;
3667 int32_t low
= GET_JUMP_OFFSET(pc2
);
3668 pc2
+= JUMP_OFFSET_LEN
;
3669 int32_t high
= GET_JUMP_OFFSET(pc2
);
3671 i
= uint32_t(i
) - uint32_t(low
);
3672 if (uint32_t(i
) < uint32_t(high
- low
+ 1)) {
3673 len
= script
->tableSwitchCaseOffset(REGS
.pc
, uint32_t(i
)) -
3674 script
->pcToOffset(REGS
.pc
);
3676 ADVANCE_AND_DISPATCH(len
);
3680 MOZ_ASSERT(script
->needsArgsObj());
3681 ArgumentsObject
* obj
= ArgumentsObject::createExpected(cx
, REGS
.fp());
3685 PUSH_COPY(ObjectValue(*obj
));
3690 ReservedRooted
<JSObject
*> rest(&rootObject0
,
3691 REGS
.fp()->createRestParameter(cx
));
3695 PUSH_COPY(ObjectValue(*rest
));
3699 CASE(GetAliasedVar
) {
3700 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3701 ReservedRooted
<Value
> val(
3702 &rootValue0
, REGS
.fp()->aliasedEnvironment(ec
).aliasedBinding(ec
));
3704 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val
);
3708 END_CASE(GetAliasedVar
)
3710 CASE(GetAliasedDebugVar
) {
3711 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3712 ReservedRooted
<Value
> val(
3714 REGS
.fp()->aliasedEnvironmentMaybeDebug(ec
).aliasedBinding(ec
));
3716 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val
);
3720 END_CASE(GetAliasedVar
)
3722 CASE(SetAliasedVar
) {
3723 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3724 EnvironmentObject
& obj
= REGS
.fp()->aliasedEnvironment(ec
);
3725 MOZ_ASSERT(!IsUninitializedLexical(obj
.aliasedBinding(ec
)));
3726 obj
.setAliasedBinding(ec
, REGS
.sp
[-1]);
3728 END_CASE(SetAliasedVar
)
3730 CASE(ThrowSetConst
) {
3731 ReportRuntimeLexicalError(cx
, JSMSG_BAD_CONST_ASSIGN
, script
, REGS
.pc
);
3734 END_CASE(ThrowSetConst
)
3736 CASE(CheckLexical
) {
3737 if (REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
3738 ReportRuntimeLexicalError(cx
, JSMSG_UNINITIALIZED_LEXICAL
, script
,
3743 END_CASE(CheckLexical
)
3745 CASE(CheckAliasedLexical
) {
3746 if (REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
3747 ReportRuntimeLexicalError(cx
, JSMSG_UNINITIALIZED_LEXICAL
, script
,
3752 END_CASE(CheckAliasedLexical
)
3755 uint32_t i
= GET_LOCALNO(REGS
.pc
);
3756 REGS
.fp()->unaliasedLocal(i
) = REGS
.sp
[-1];
3758 END_CASE(InitLexical
)
3760 CASE(InitAliasedLexical
) {
3761 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3762 EnvironmentObject
& obj
= REGS
.fp()->aliasedEnvironment(ec
);
3763 obj
.setAliasedBinding(ec
, REGS
.sp
[-1]);
3765 END_CASE(InitAliasedLexical
)
3767 CASE(InitGLexical
) {
3768 ExtensibleLexicalEnvironmentObject
* lexicalEnv
;
3769 if (script
->hasNonSyntacticScope()) {
3770 lexicalEnv
= ®S
.fp()->extensibleLexicalEnvironment();
3772 lexicalEnv
= &cx
->global()->lexicalEnvironment();
3774 HandleValue value
= REGS
.stackHandleAt(-1);
3775 InitGlobalLexicalOperation(cx
, lexicalEnv
, script
, REGS
.pc
, value
);
3777 END_CASE(InitGLexical
)
3779 CASE(Uninitialized
) { PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL
); }
3780 END_CASE(Uninitialized
)
3783 unsigned i
= GET_ARGNO(REGS
.pc
);
3784 if (script
->argsObjAliasesFormals()) {
3785 PUSH_COPY(REGS
.fp()->argsObj().arg(i
));
3787 PUSH_COPY(REGS
.fp()->unaliasedFormal(i
));
3793 uint32_t i
= GET_ARGNO(REGS
.pc
);
3794 PUSH_COPY(REGS
.fp()->unaliasedFormal(i
, DONT_CHECK_ALIASING
));
3796 END_CASE(GetFrameArg
)
3799 unsigned i
= GET_ARGNO(REGS
.pc
);
3800 if (script
->argsObjAliasesFormals()) {
3801 REGS
.fp()->argsObj().setArg(i
, REGS
.sp
[-1]);
3803 REGS
.fp()->unaliasedFormal(i
) = REGS
.sp
[-1];
3809 uint32_t i
= GET_LOCALNO(REGS
.pc
);
3810 PUSH_COPY_SKIP_CHECK(REGS
.fp()->unaliasedLocal(i
));
3813 if (IsUninitializedLexical(REGS
.sp
[-1])) {
3814 JSOp next
= JSOp(*GetNextPc(REGS
.pc
));
3815 MOZ_ASSERT(next
== JSOp::CheckThis
|| next
== JSOp::CheckReturn
||
3816 next
== JSOp::CheckThisReinit
|| next
== JSOp::CheckLexical
);
3820 * Skip the same-compartment assertion if the local will be immediately
3821 * popped. We do not guarantee sync for dead locals when coming in from
3822 * the method JIT, and a GetLocal followed by Pop is not considered to
3823 * be a use of the variable.
3825 if (JSOp(REGS
.pc
[JSOpLength_GetLocal
]) != JSOp::Pop
) {
3826 cx
->debugOnlyCheck(REGS
.sp
[-1]);
3833 uint32_t i
= GET_LOCALNO(REGS
.pc
);
3835 MOZ_ASSERT(!IsUninitializedLexical(REGS
.fp()->unaliasedLocal(i
)));
3837 REGS
.fp()->unaliasedLocal(i
) = REGS
.sp
[-1];
3841 CASE(ArgumentsLength
) {
3842 MOZ_ASSERT(!script
->needsArgsObj());
3843 PUSH_INT32(REGS
.fp()->numActualArgs());
3845 END_CASE(ArgumentsLength
)
3847 CASE(GetActualArg
) {
3848 MOZ_ASSERT(!script
->needsArgsObj());
3849 uint32_t index
= REGS
.sp
[-1].toInt32();
3850 REGS
.sp
[-1] = REGS
.fp()->unaliasedActual(index
);
3852 END_CASE(GetActualArg
)
3854 CASE(GlobalOrEvalDeclInstantiation
) {
3855 GCThingIndex lastFun
= GET_GCTHING_INDEX(REGS
.pc
);
3856 HandleObject env
= REGS
.fp()->environmentChain();
3857 if (!GlobalOrEvalDeclInstantiation(cx
, env
, script
, lastFun
)) {
3861 END_CASE(GlobalOrEvalDeclInstantiation
)
3864 /* Load the specified function object literal. */
3865 ReservedRooted
<JSFunction
*> fun(&rootFunction0
,
3866 script
->getFunction(REGS
.pc
));
3867 JSObject
* obj
= Lambda(cx
, fun
, REGS
.fp()->environmentChain());
3872 MOZ_ASSERT(obj
->staticPrototype());
3878 ReservedRooted
<Value
> nextMethod(&rootValue0
, REGS
.sp
[-1]);
3879 ReservedRooted
<JSObject
*> iter(&rootObject1
, ®S
.sp
[-2].toObject());
3880 JSObject
* asyncIter
= CreateAsyncFromSyncIterator(cx
, iter
, nextMethod
);
3886 REGS
.sp
[-1].setObject(*asyncIter
);
3888 END_CASE(ToAsyncIter
)
3890 CASE(CanSkipAwait
) {
3891 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
3893 if (!CanSkipAwait(cx
, val
, &canSkip
)) {
3897 PUSH_BOOLEAN(canSkip
);
3899 END_CASE(CanSkipAwait
)
3901 CASE(MaybeExtractAwaitValue
) {
3902 MutableHandleValue val
= REGS
.stackHandleAt(-2);
3903 ReservedRooted
<Value
> canSkip(&rootValue0
, REGS
.sp
[-1]);
3905 if (canSkip
.toBoolean()) {
3906 if (!ExtractAwaitValue(cx
, val
, val
)) {
3911 END_CASE(MaybeExtractAwaitValue
)
3914 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3915 ReservedRooted
<JSObject
*> gen(&rootObject1
, ®S
.sp
[-1].toObject());
3916 ReservedRooted
<Value
> value(&rootValue0
, REGS
.sp
[-2]);
3918 AsyncFunctionAwait(cx
, gen
.as
<AsyncFunctionGeneratorObject
>(), value
);
3924 REGS
.sp
[-1].setObject(*promise
);
3926 END_CASE(AsyncAwait
)
3928 CASE(AsyncResolve
) {
3929 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3930 auto resolveKind
= AsyncFunctionResolveKind(GET_UINT8(REGS
.pc
));
3931 ReservedRooted
<JSObject
*> gen(&rootObject1
, ®S
.sp
[-1].toObject());
3932 ReservedRooted
<Value
> valueOrReason(&rootValue0
, REGS
.sp
[-2]);
3934 AsyncFunctionResolve(cx
, gen
.as
<AsyncFunctionGeneratorObject
>(),
3935 valueOrReason
, resolveKind
);
3941 REGS
.sp
[-1].setObject(*promise
);
3943 END_CASE(AsyncResolve
)
3946 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3947 FunctionPrefixKind prefixKind
= FunctionPrefixKind(GET_UINT8(REGS
.pc
));
3948 ReservedRooted
<Value
> name(&rootValue0
, REGS
.sp
[-1]);
3949 ReservedRooted
<JSFunction
*> fun(&rootFunction0
,
3950 ®S
.sp
[-2].toObject().as
<JSFunction
>());
3951 if (!SetFunctionName(cx
, fun
, name
, prefixKind
)) {
3957 END_CASE(SetFunName
)
3960 MOZ_ASSERT(REGS
.fp()->isFunctionFrame());
3961 PUSH_COPY(REGS
.fp()->calleev());
3965 CASE(InitPropGetter
)
3966 CASE(InitHiddenPropGetter
)
3967 CASE(InitPropSetter
)
3968 CASE(InitHiddenPropSetter
) {
3969 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3971 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
3972 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3973 ReservedRooted
<JSObject
*> val(&rootObject1
, ®S
.sp
[-1].toObject());
3975 if (!InitPropGetterSetterOperation(cx
, REGS
.pc
, obj
, name
, val
)) {
3981 END_CASE(InitPropGetter
)
3983 CASE(InitElemGetter
)
3984 CASE(InitHiddenElemGetter
)
3985 CASE(InitElemSetter
)
3986 CASE(InitHiddenElemSetter
) {
3987 MOZ_ASSERT(REGS
.stackDepth() >= 3);
3989 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-3].toObject());
3990 ReservedRooted
<Value
> idval(&rootValue0
, REGS
.sp
[-2]);
3991 ReservedRooted
<JSObject
*> val(&rootObject1
, ®S
.sp
[-1].toObject());
3993 if (!InitElemGetterSetterOperation(cx
, REGS
.pc
, obj
, idval
, val
)) {
3999 END_CASE(InitElemGetter
)
4001 CASE(Hole
) { PUSH_MAGIC(JS_ELEMENTS_HOLE
); }
4005 JSObject
* obj
= NewObjectOperation(cx
, script
, REGS
.pc
);
4015 uint32_t length
= GET_UINT32(REGS
.pc
);
4016 ArrayObject
* obj
= NewArrayOperation(cx
, length
);
4025 JSObject
* obj
= NewObjectOperation(cx
, script
, REGS
.pc
);
4034 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4036 if (REGS
.sp
[-1].isObjectOrNull()) {
4037 ReservedRooted
<JSObject
*> newProto(&rootObject1
,
4038 REGS
.sp
[-1].toObjectOrNull());
4039 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
4040 MOZ_ASSERT(obj
->is
<PlainObject
>());
4042 if (!SetPrototype(cx
, obj
, newProto
)) {
4049 END_CASE(MutateProto
)
4052 CASE(InitLockedProp
)
4053 CASE(InitHiddenProp
) {
4054 static_assert(JSOpLength_InitProp
== JSOpLength_InitLockedProp
,
4055 "initprop and initlockedprop must be the same size");
4056 static_assert(JSOpLength_InitProp
== JSOpLength_InitHiddenProp
,
4057 "initprop and inithiddenprop must be the same size");
4058 /* Load the property's initial value into rval. */
4059 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4060 ReservedRooted
<Value
> rval(&rootValue0
, REGS
.sp
[-1]);
4062 /* Load the object being initialized into lval/obj. */
4063 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
4065 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
4067 if (!InitPropertyOperation(cx
, REGS
.pc
, obj
, name
, rval
)) {
4076 CASE(InitHiddenElem
)
4077 CASE(InitLockedElem
) {
4078 MOZ_ASSERT(REGS
.stackDepth() >= 3);
4079 HandleValue val
= REGS
.stackHandleAt(-1);
4080 HandleValue id
= REGS
.stackHandleAt(-2);
4082 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-3].toObject());
4084 if (!InitElemOperation(cx
, REGS
.pc
, obj
, id
, val
)) {
4092 CASE(InitElemArray
) {
4093 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4094 HandleValue val
= REGS
.stackHandleAt(-1);
4095 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
4097 InitElemArrayOperation(cx
, REGS
.pc
, obj
.as
<ArrayObject
>(), val
);
4100 END_CASE(InitElemArray
)
4103 MOZ_ASSERT(REGS
.stackDepth() >= 3);
4104 HandleValue val
= REGS
.stackHandleAt(-1);
4106 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-3].toObject());
4108 uint32_t index
= REGS
.sp
[-2].toInt32();
4109 if (!InitElemIncOperation(cx
, obj
.as
<ArrayObject
>(), index
, val
)) {
4113 REGS
.sp
[-2].setInt32(index
+ 1);
4116 END_CASE(InitElemInc
)
4118 #ifdef ENABLE_RECORD_TUPLE
4120 uint32_t length
= GET_UINT32(REGS
.pc
);
4121 RecordType
* rec
= RecordType::createUninitialized(cx
, length
);
4125 PUSH_EXTENDED_PRIMITIVE(*rec
);
4127 END_CASE(InitRecord
)
4129 CASE(AddRecordProperty
) {
4130 MOZ_ASSERT(REGS
.stackDepth() >= 3);
4132 ReservedRooted
<JSObject
*> rec(&rootObject0
,
4133 ®S
.sp
[-3].toExtendedPrimitive());
4134 MOZ_ASSERT(rec
->is
<RecordType
>());
4136 ReservedRooted
<Value
> key(&rootValue0
, REGS
.sp
[-2]);
4137 ReservedRooted
<jsid
> id(&rootId0
);
4138 if (!JS_ValueToId(cx
, key
, &id
)) {
4141 if (!rec
->as
<RecordType
>().initializeNextProperty(
4142 cx
, id
, REGS
.stackHandleAt(-1))) {
4148 END_CASE(AddRecordProperty
)
4150 CASE(AddRecordSpread
) {
4151 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4153 if (!AddRecordSpreadOperation(cx
, REGS
.stackHandleAt(-2),
4154 REGS
.stackHandleAt(-1))) {
4159 END_CASE(AddRecordSpread
)
4161 CASE(FinishRecord
) {
4162 MOZ_ASSERT(REGS
.stackDepth() >= 1);
4163 RecordType
* rec
= ®S
.sp
[-1].toExtendedPrimitive().as
<RecordType
>();
4164 if (!rec
->finishInitialization(cx
)) {
4168 END_CASE(FinishRecord
)
4171 uint32_t length
= GET_UINT32(REGS
.pc
);
4172 TupleType
* tup
= TupleType::createUninitialized(cx
, length
);
4176 PUSH_EXTENDED_PRIMITIVE(*tup
);
4180 CASE(AddTupleElement
) {
4181 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4183 ReservedRooted
<JSObject
*> tup(&rootObject0
,
4184 ®S
.sp
[-2].toExtendedPrimitive());
4185 HandleValue val
= REGS
.stackHandleAt(-1);
4187 if (!tup
->as
<TupleType
>().initializeNextElement(cx
, val
)) {
4193 END_CASE(AddTupleElement
)
4196 MOZ_ASSERT(REGS
.stackDepth() >= 1);
4197 TupleType
& tup
= REGS
.sp
[-1].toExtendedPrimitive().as
<TupleType
>();
4198 tup
.finishInitialization(cx
);
4200 END_CASE(FinishTuple
)
4205 MutableHandleValue res
= REGS
.stackHandleAt(-1);
4206 if (!GetAndClearException(cx
, res
)) {
4212 CASE(Finally
) { CHECK_BRANCH(); }
4217 ReservedRooted
<Value
> v(&rootValue0
);
4219 MOZ_ALWAYS_FALSE(ThrowOperation(cx
, v
));
4220 /* let the code at error try to catch the exception. */
4225 ReservedRooted
<Value
> rref(&rootValue0
, REGS
.sp
[-1]);
4226 if (HandleValue(rref
).isPrimitive()) {
4227 ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
, -1, rref
, nullptr);
4230 ReservedRooted
<JSObject
*> obj(&rootObject0
, &rref
.toObject());
4232 if (!InstanceofOperator(cx
, obj
, REGS
.stackHandleAt(-2), &cond
)) {
4236 REGS
.sp
[-1].setBoolean(cond
);
4238 END_CASE(Instanceof
)
4241 if (!DebugAPI::onDebuggerStatement(cx
, REGS
.fp())) {
4247 CASE(PushLexicalEnv
) {
4248 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
4250 // Create block environment and push on scope chain.
4251 if (!REGS
.fp()->pushLexicalEnvironment(cx
, scope
.as
<LexicalScope
>())) {
4255 END_CASE(PushLexicalEnv
)
4257 CASE(PopLexicalEnv
) {
4259 Scope
* scope
= script
->lookupScope(REGS
.pc
);
4261 MOZ_ASSERT(scope
->is
<LexicalScope
>() || scope
->is
<ClassBodyScope
>());
4262 MOZ_ASSERT_IF(scope
->is
<LexicalScope
>(),
4263 scope
->as
<LexicalScope
>().hasEnvironment());
4264 MOZ_ASSERT_IF(scope
->is
<ClassBodyScope
>(),
4265 scope
->as
<ClassBodyScope
>().hasEnvironment());
4268 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
4269 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
4272 // Pop block from scope chain.
4273 REGS
.fp()->popOffEnvironmentChain
<LexicalEnvironmentObject
>();
4275 END_CASE(PopLexicalEnv
)
4277 CASE(DebugLeaveLexicalEnv
) {
4279 Scope
* scope
= script
->lookupScope(REGS
.pc
);
4281 MOZ_ASSERT(scope
->is
<LexicalScope
>() || scope
->is
<ClassBodyScope
>());
4282 MOZ_ASSERT_IF(scope
->is
<LexicalScope
>(),
4283 !scope
->as
<LexicalScope
>().hasEnvironment());
4284 MOZ_ASSERT_IF(scope
->is
<ClassBodyScope
>(),
4285 !scope
->as
<ClassBodyScope
>().hasEnvironment());
4287 // FIXME: This opcode should not be necessary. The debugger shouldn't
4288 // need help from bytecode to do its job. See bug 927782.
4290 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
4291 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
4294 END_CASE(DebugLeaveLexicalEnv
)
4296 CASE(FreshenLexicalEnv
) {
4298 Scope
* scope
= script
->getScope(REGS
.pc
);
4299 auto envChain
= REGS
.fp()->environmentChain();
4300 auto* envScope
= &envChain
->as
<BlockLexicalEnvironmentObject
>().scope();
4301 MOZ_ASSERT(scope
== envScope
);
4304 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
4305 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
4308 if (!REGS
.fp()->freshenLexicalEnvironment(cx
)) {
4312 END_CASE(FreshenLexicalEnv
)
4314 CASE(RecreateLexicalEnv
) {
4316 Scope
* scope
= script
->getScope(REGS
.pc
);
4317 auto envChain
= REGS
.fp()->environmentChain();
4318 auto* envScope
= &envChain
->as
<BlockLexicalEnvironmentObject
>().scope();
4319 MOZ_ASSERT(scope
== envScope
);
4322 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
4323 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
4326 if (!REGS
.fp()->recreateLexicalEnvironment(cx
)) {
4330 END_CASE(RecreateLexicalEnv
)
4332 CASE(PushClassBodyEnv
) {
4333 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
4335 if (!REGS
.fp()->pushClassBodyEnvironment(cx
,
4336 scope
.as
<ClassBodyScope
>())) {
4340 END_CASE(PushClassBodyEnv
)
4343 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
4345 if (!REGS
.fp()->pushVarEnvironment(cx
, scope
)) {
4349 END_CASE(PushVarEnv
)
4352 MOZ_ASSERT(!cx
->isExceptionPending());
4353 MOZ_ASSERT(REGS
.stackDepth() == 0);
4354 JSObject
* obj
= AbstractGeneratorObject::createFromFrame(cx
, REGS
.fp());
4362 CASE(InitialYield
) {
4363 MOZ_ASSERT(!cx
->isExceptionPending());
4364 MOZ_ASSERT_IF(script
->isModule() && script
->isAsync(),
4365 REGS
.fp()->isModuleFrame());
4366 MOZ_ASSERT_IF(!script
->isModule() && script
->isAsync(),
4367 REGS
.fp()->isFunctionFrame());
4368 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-1].toObject());
4370 MOZ_ASSERT(REGS
.stackDepth() == 0);
4371 if (!AbstractGeneratorObject::suspend(cx
, obj
, REGS
.fp(), REGS
.pc
,
4372 script
->nfixed())) {
4375 goto successful_return_continuation
;
4380 MOZ_ASSERT(!cx
->isExceptionPending());
4381 MOZ_ASSERT_IF(script
->isModule() && script
->isAsync(),
4382 REGS
.fp()->isModuleFrame());
4383 MOZ_ASSERT_IF(!script
->isModule() && script
->isAsync(),
4384 REGS
.fp()->isFunctionFrame());
4385 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-1].toObject());
4386 if (!AbstractGeneratorObject::suspend(
4387 cx
, obj
, REGS
.fp(), REGS
.pc
,
4388 script
->nfixed() + REGS
.stackDepth() - 2)) {
4395 goto successful_return_continuation
;
4399 GeneratorResumeKind resumeKind
= ResumeKindFromPC(REGS
.pc
);
4400 PUSH_INT32(int32_t(resumeKind
));
4402 END_CASE(ResumeKind
)
4404 CASE(CheckResumeKind
) {
4405 int32_t kindInt
= REGS
.sp
[-1].toInt32();
4406 GeneratorResumeKind resumeKind
= IntToResumeKind(kindInt
);
4407 if (MOZ_UNLIKELY(resumeKind
!= GeneratorResumeKind::Next
)) {
4408 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-3]);
4409 Rooted
<AbstractGeneratorObject
*> gen(
4410 cx
, ®S
.sp
[-2].toObject().as
<AbstractGeneratorObject
>());
4411 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx
, activation
.regs().fp(), gen
,
4417 END_CASE(CheckResumeKind
)
4421 Rooted
<AbstractGeneratorObject
*> gen(
4422 cx
, ®S
.sp
[-3].toObject().as
<AbstractGeneratorObject
>());
4423 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-2]);
4424 ReservedRooted
<Value
> resumeKindVal(&rootValue1
, REGS
.sp
[-1]);
4426 // popInlineFrame expects there to be an additional value on the stack
4427 // to pop off, so leave "gen" on the stack.
4430 if (!AbstractGeneratorObject::resume(cx
, activation
, gen
, val
,
4435 JSScript
* generatorScript
= REGS
.fp()->script();
4436 if (cx
->realm() != generatorScript
->realm()) {
4437 cx
->enterRealmOf(generatorScript
);
4439 SET_SCRIPT(generatorScript
);
4441 if (!probes::EnterScript(cx
, generatorScript
,
4442 generatorScript
->function(), REGS
.fp())) {
4446 if (!DebugAPI::onResumeFrame(cx
, REGS
.fp())) {
4447 if (cx
->isPropagatingForcedReturn()) {
4451 .isGenerator(), // as opposed to an async function
4457 ADVANCE_AND_DISPATCH(0);
4461 // AbstractGeneratorObject::resume takes care of setting the frame's
4463 MOZ_ASSERT_IF(REGS
.fp()->script()->isDebuggee(), REGS
.fp()->isDebuggee());
4466 END_CASE(AfterYield
)
4468 CASE(FinalYieldRval
) {
4469 ReservedRooted
<JSObject
*> gen(&rootObject0
, ®S
.sp
[-1].toObject());
4471 AbstractGeneratorObject::finalSuspend(gen
);
4472 goto successful_return_continuation
;
4475 CASE(CheckClassHeritage
) {
4476 HandleValue heritage
= REGS
.stackHandleAt(-1);
4478 if (!CheckClassHeritageOperation(cx
, heritage
)) {
4482 END_CASE(CheckClassHeritage
)
4484 CASE(BuiltinObject
) {
4485 auto kind
= BuiltinObjectKind(GET_UINT8(REGS
.pc
));
4486 JSObject
* builtin
= BuiltinObjectOperation(cx
, kind
);
4490 PUSH_OBJECT(*builtin
);
4492 END_CASE(BuiltinObject
)
4494 CASE(FunWithProto
) {
4495 ReservedRooted
<JSObject
*> proto(&rootObject1
, ®S
.sp
[-1].toObject());
4497 /* Load the specified function object literal. */
4498 ReservedRooted
<JSFunction
*> fun(&rootFunction0
,
4499 script
->getFunction(REGS
.pc
));
4502 FunWithProtoOperation(cx
, fun
, REGS
.fp()->environmentChain(), proto
);
4507 REGS
.sp
[-1].setObject(*obj
);
4509 END_CASE(FunWithProto
)
4511 CASE(ObjWithProto
) {
4512 JSObject
* obj
= ObjectWithProtoOperation(cx
, REGS
.stackHandleAt(-1));
4517 REGS
.sp
[-1].setObject(*obj
);
4519 END_CASE(ObjWithProto
)
4521 CASE(InitHomeObject
) {
4522 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4524 /* Load the function to be initialized */
4525 JSFunction
* func
= ®S
.sp
[-2].toObject().as
<JSFunction
>();
4526 MOZ_ASSERT(func
->allowSuperProperty());
4528 /* Load the home object */
4529 JSObject
* obj
= ®S
.sp
[-1].toObject();
4530 MOZ_ASSERT(obj
->is
<PlainObject
>() || obj
->is
<JSFunction
>());
4532 func
->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT
,
4536 END_CASE(InitHomeObject
)
4539 JSFunction
& superEnvFunc
= REGS
.sp
[-1].toObject().as
<JSFunction
>();
4540 MOZ_ASSERT(superEnvFunc
.allowSuperProperty());
4541 MOZ_ASSERT(superEnvFunc
.baseScript()->needsHomeObject());
4542 const Value
& homeObjVal
= superEnvFunc
.getExtendedSlot(
4543 FunctionExtended::METHOD_HOMEOBJECT_SLOT
);
4545 JSObject
* homeObj
= &homeObjVal
.toObject();
4546 JSObject
* superBase
= HomeObjectSuperBase(homeObj
);
4548 REGS
.sp
[-1].setObjectOrNull(superBase
);
4553 PUSH_COPY(REGS
.fp()->newTarget());
4554 MOZ_ASSERT(REGS
.sp
[-1].isObject() || REGS
.sp
[-1].isUndefined());
4559 JSObject
* metaObject
= ImportMetaOperation(cx
, script
);
4564 PUSH_OBJECT(*metaObject
);
4566 END_CASE(ImportMeta
)
4568 CASE(DynamicImport
) {
4569 ReservedRooted
<Value
> options(&rootValue0
, REGS
.sp
[-1]);
4572 ReservedRooted
<Value
> specifier(&rootValue1
);
4573 POP_COPY_TO(specifier
);
4576 StartDynamicModuleImport(cx
, script
, specifier
, options
);
4577 if (!promise
) goto error
;
4579 PUSH_OBJECT(*promise
);
4581 END_CASE(DynamicImport
)
4584 uint8_t numHops
= GET_UINT8(REGS
.pc
);
4585 JSObject
* env
= ®S
.fp()->environmentChain()->as
<EnvironmentObject
>();
4586 for (unsigned i
= 0; i
< numHops
; i
++) {
4587 env
= &env
->as
<EnvironmentObject
>().enclosingEnvironment();
4589 PUSH_OBJECT(env
->as
<CallObject
>().callee());
4594 JSObject
* superEnvFunc
= ®S
.sp
[-1].toObject();
4595 JSObject
* superFun
= SuperFunOperation(superEnvFunc
);
4596 REGS
.sp
[-1].setObjectOrNull(superFun
);
4600 CASE(CheckObjCoercible
) {
4601 ReservedRooted
<Value
> checkVal(&rootValue0
, REGS
.sp
[-1]);
4602 if (checkVal
.isNullOrUndefined()) {
4603 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx
, checkVal
));
4607 END_CASE(CheckObjCoercible
)
4609 CASE(DebugCheckSelfHosted
) {
4611 ReservedRooted
<Value
> checkVal(&rootValue0
, REGS
.sp
[-1]);
4612 if (!Debug_CheckSelfHosted(cx
, checkVal
)) {
4617 END_CASE(DebugCheckSelfHosted
)
4619 CASE(IsConstructing
) { PUSH_MAGIC(JS_IS_CONSTRUCTING
); }
4620 END_CASE(IsConstructing
)
4623 MutableHandleValue val
= REGS
.stackHandleAt(-1);
4624 if (!IncOperation(cx
, val
, val
)) {
4631 MutableHandleValue val
= REGS
.stackHandleAt(-1);
4632 if (!DecOperation(cx
, val
, val
)) {
4639 if (!ToNumeric(cx
, REGS
.stackHandleAt(-1))) {
4645 CASE(BigInt
) { PUSH_BIGINT(script
->getBigInt(REGS
.pc
)); }
4650 SprintfLiteral(numBuf
, "%d", *REGS
.pc
);
4651 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
4652 JSMSG_BAD_BYTECODE
, numBuf
);
4656 } /* interpreter loop */
4658 MOZ_CRASH("Interpreter loop exited via fallthrough");
4661 switch (HandleError(cx
, REGS
)) {
4662 case SuccessfulReturnContinuation
:
4663 goto successful_return_continuation
;
4665 case ErrorReturnContinuation
:
4666 interpReturnOK
= false;
4667 goto return_continuation
;
4669 case CatchContinuation
:
4670 ADVANCE_AND_DISPATCH(0);
4672 case FinallyContinuation
: {
4674 * Push (exception, true) pair for finally to indicate that we
4675 * should rethrow the exception.
4677 ReservedRooted
<Value
> exception(&rootValue0
);
4678 if (!cx
->getPendingException(&exception
)) {
4679 interpReturnOK
= false;
4680 goto return_continuation
;
4682 PUSH_COPY(exception
);
4684 cx
->clearPendingException();
4686 ADVANCE_AND_DISPATCH(0);
4689 MOZ_CRASH("Invalid HandleError continuation");
4692 if (MOZ_LIKELY(!frameHalfInitialized
)) {
4694 DebugAPI::onLeaveFrame(cx
, REGS
.fp(), REGS
.pc
, interpReturnOK
);
4696 REGS
.fp()->epilogue(cx
, REGS
.pc
);
4699 gc::MaybeVerifyBarriers(cx
, true);
4702 * This path is used when it's guaranteed the method can be finished
4705 leave_on_safe_point
:
4707 if (interpReturnOK
) {
4708 state
.setReturnValue(activation
.entryFrame()->returnValue());
4711 return interpReturnOK
;
4714 interpReturnOK
= false;
4715 frameHalfInitialized
= true;
4716 goto prologue_return_continuation
;
4719 bool js::ThrowOperation(JSContext
* cx
, HandleValue v
) {
4720 MOZ_ASSERT(!cx
->isExceptionPending());
4721 cx
->setPendingException(v
, ShouldCaptureStack::Maybe
);
4725 bool js::GetProperty(JSContext
* cx
, HandleValue v
, Handle
<PropertyName
*> name
,
4726 MutableHandleValue vp
) {
4727 if (name
== cx
->names().length
) {
4728 // Fast path for strings, arrays and arguments.
4729 if (GetLengthProperty(v
, vp
)) {
4734 // Optimize common cases like (2).toString() or "foo".valueOf() to not
4735 // create a wrapper object.
4736 if (v
.isPrimitive() && !v
.isNullOrUndefined()) {
4740 case ValueType::Double
:
4741 case ValueType::Int32
:
4742 proto
= GlobalObject::getOrCreateNumberPrototype(cx
, cx
->global());
4744 case ValueType::Boolean
:
4745 proto
= GlobalObject::getOrCreateBooleanPrototype(cx
, cx
->global());
4747 case ValueType::String
:
4748 proto
= GlobalObject::getOrCreateStringPrototype(cx
, cx
->global());
4750 case ValueType::Symbol
:
4751 proto
= GlobalObject::getOrCreateSymbolPrototype(cx
, cx
->global());
4753 case ValueType::BigInt
:
4754 proto
= GlobalObject::getOrCreateBigIntPrototype(cx
, cx
->global());
4756 #ifdef ENABLE_RECORD_TUPLE
4757 case ValueType::ExtendedPrimitive
: {
4758 RootedObject
obj(cx
, &v
.toExtendedPrimitive());
4759 RootedId
id(cx
, NameToId(name
));
4760 return ExtendedPrimitiveGetProperty(cx
, obj
, v
, id
, vp
);
4763 case ValueType::Undefined
:
4764 case ValueType::Null
:
4765 case ValueType::Magic
:
4766 case ValueType::PrivateGCThing
:
4767 case ValueType::Object
:
4768 MOZ_CRASH("unexpected type");
4775 if (GetPropertyPure(cx
, proto
, NameToId(name
), vp
.address())) {
4780 RootedValue
receiver(cx
, v
);
4782 cx
, ToObjectFromStackForPropertyAccess(cx
, v
, JSDVG_SEARCH_STACK
, name
));
4787 return GetProperty(cx
, obj
, receiver
, name
, vp
);
4790 JSObject
* js::Lambda(JSContext
* cx
, HandleFunction fun
, HandleObject parent
) {
4792 if (fun
->isNativeFun()) {
4793 MOZ_ASSERT(IsAsmJSModule(fun
));
4794 clone
= CloneAsmJSModuleFunction(cx
, fun
);
4796 RootedObject
proto(cx
, fun
->staticPrototype());
4797 clone
= CloneFunctionReuseScript(cx
, fun
, parent
, proto
);
4803 MOZ_ASSERT(fun
->global() == clone
->global());
4807 JSObject
* js::BindVarOperation(JSContext
* cx
, JSObject
* envChain
) {
4808 // Note: BindVarOperation has an unused cx argument because the JIT callVM
4809 // machinery requires this.
4810 return &GetVariablesObject(envChain
);
4813 JSObject
* js::ImportMetaOperation(JSContext
* cx
, HandleScript script
) {
4814 RootedObject
module(cx
, GetModuleObjectForScript(script
));
4816 return GetOrCreateModuleMetaObject(cx
, module
);
4819 JSObject
* js::BuiltinObjectOperation(JSContext
* cx
, BuiltinObjectKind kind
) {
4820 return GetOrCreateBuiltinObject(cx
, kind
);
4823 bool js::ThrowMsgOperation(JSContext
* cx
, const unsigned throwMsgKind
) {
4824 auto errorNum
= ThrowMsgKindToErrNum(ThrowMsgKind(throwMsgKind
));
4825 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, errorNum
);
4829 bool js::GetAndClearExceptionAndStack(JSContext
* cx
, MutableHandleValue res
,
4830 MutableHandle
<SavedFrame
*> stack
) {
4831 if (!cx
->getPendingException(res
)) {
4834 stack
.set(cx
->getPendingExceptionStack());
4835 cx
->clearPendingException();
4837 // Allow interrupting deeply nested exception handling.
4838 return CheckForInterrupt(cx
);
4841 bool js::GetAndClearException(JSContext
* cx
, MutableHandleValue res
) {
4842 Rooted
<SavedFrame
*> stack(cx
);
4843 return GetAndClearExceptionAndStack(cx
, res
, &stack
);
4846 template <bool strict
>
4847 bool js::DelPropOperation(JSContext
* cx
, HandleValue val
,
4848 Handle
<PropertyName
*> name
, bool* res
) {
4849 const int valIndex
= -1;
4850 RootedObject
obj(cx
,
4851 ToObjectFromStackForPropertyAccess(cx
, val
, valIndex
, name
));
4856 RootedId
id(cx
, NameToId(name
));
4857 ObjectOpResult result
;
4858 if (!DeleteProperty(cx
, obj
, id
, result
)) {
4864 return result
.reportError(cx
, obj
, id
);
4873 template bool js::DelPropOperation
<true>(JSContext
* cx
, HandleValue val
,
4874 Handle
<PropertyName
*> name
, bool* res
);
4875 template bool js::DelPropOperation
<false>(JSContext
* cx
, HandleValue val
,
4876 Handle
<PropertyName
*> name
,
4879 template <bool strict
>
4880 bool js::DelElemOperation(JSContext
* cx
, HandleValue val
, HandleValue index
,
4882 const int valIndex
= -2;
4884 cx
, ToObjectFromStackForPropertyAccess(cx
, val
, valIndex
, index
));
4890 if (!ToPropertyKey(cx
, index
, &id
)) {
4893 ObjectOpResult result
;
4894 if (!DeleteProperty(cx
, obj
, id
, result
)) {
4900 return result
.reportError(cx
, obj
, id
);
4909 template bool js::DelElemOperation
<true>(JSContext
*, HandleValue
, HandleValue
,
4911 template bool js::DelElemOperation
<false>(JSContext
*, HandleValue
, HandleValue
,
4914 bool js::SetObjectElement(JSContext
* cx
, HandleObject obj
, HandleValue index
,
4915 HandleValue value
, bool strict
) {
4917 if (!ToPropertyKey(cx
, index
, &id
)) {
4920 RootedValue
receiver(cx
, ObjectValue(*obj
));
4921 return SetObjectElementOperation(cx
, obj
, id
, value
, receiver
, strict
);
4924 bool js::SetObjectElementWithReceiver(JSContext
* cx
, HandleObject obj
,
4925 HandleValue index
, HandleValue value
,
4926 HandleValue receiver
, bool strict
) {
4928 if (!ToPropertyKey(cx
, index
, &id
)) {
4931 return SetObjectElementOperation(cx
, obj
, id
, value
, receiver
, strict
);
4934 bool js::AddValues(JSContext
* cx
, MutableHandleValue lhs
,
4935 MutableHandleValue rhs
, MutableHandleValue res
) {
4936 return AddOperation(cx
, lhs
, rhs
, res
);
4939 bool js::SubValues(JSContext
* cx
, MutableHandleValue lhs
,
4940 MutableHandleValue rhs
, MutableHandleValue res
) {
4941 return SubOperation(cx
, lhs
, rhs
, res
);
4944 bool js::MulValues(JSContext
* cx
, MutableHandleValue lhs
,
4945 MutableHandleValue rhs
, MutableHandleValue res
) {
4946 return MulOperation(cx
, lhs
, rhs
, res
);
4949 bool js::DivValues(JSContext
* cx
, MutableHandleValue lhs
,
4950 MutableHandleValue rhs
, MutableHandleValue res
) {
4951 return DivOperation(cx
, lhs
, rhs
, res
);
4954 bool js::ModValues(JSContext
* cx
, MutableHandleValue lhs
,
4955 MutableHandleValue rhs
, MutableHandleValue res
) {
4956 return ModOperation(cx
, lhs
, rhs
, res
);
4959 bool js::PowValues(JSContext
* cx
, MutableHandleValue lhs
,
4960 MutableHandleValue rhs
, MutableHandleValue res
) {
4961 return PowOperation(cx
, lhs
, rhs
, res
);
4964 bool js::BitNot(JSContext
* cx
, MutableHandleValue in
, MutableHandleValue res
) {
4965 return BitNotOperation(cx
, in
, res
);
4968 bool js::BitXor(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4969 MutableHandleValue res
) {
4970 return BitXorOperation(cx
, lhs
, rhs
, res
);
4973 bool js::BitOr(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4974 MutableHandleValue res
) {
4975 return BitOrOperation(cx
, lhs
, rhs
, res
);
4978 bool js::BitAnd(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4979 MutableHandleValue res
) {
4980 return BitAndOperation(cx
, lhs
, rhs
, res
);
4983 bool js::BitLsh(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4984 MutableHandleValue res
) {
4985 return BitLshOperation(cx
, lhs
, rhs
, res
);
4988 bool js::BitRsh(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4989 MutableHandleValue res
) {
4990 return BitRshOperation(cx
, lhs
, rhs
, res
);
4993 bool js::UrshValues(JSContext
* cx
, MutableHandleValue lhs
,
4994 MutableHandleValue rhs
, MutableHandleValue res
) {
4995 return UrshOperation(cx
, lhs
, rhs
, res
);
4998 bool js::LessThan(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
5000 return LessThanOperation(cx
, lhs
, rhs
, res
);
5003 bool js::LessThanOrEqual(JSContext
* cx
, MutableHandleValue lhs
,
5004 MutableHandleValue rhs
, bool* res
) {
5005 return LessThanOrEqualOperation(cx
, lhs
, rhs
, res
);
5008 bool js::GreaterThan(JSContext
* cx
, MutableHandleValue lhs
,
5009 MutableHandleValue rhs
, bool* res
) {
5010 return GreaterThanOperation(cx
, lhs
, rhs
, res
);
5013 bool js::GreaterThanOrEqual(JSContext
* cx
, MutableHandleValue lhs
,
5014 MutableHandleValue rhs
, bool* res
) {
5015 return GreaterThanOrEqualOperation(cx
, lhs
, rhs
, res
);
5018 bool js::AtomicIsLockFree(JSContext
* cx
, HandleValue in
, int* out
) {
5020 if (!ToInt32(cx
, in
, &i
)) {
5023 *out
= js::jit::AtomicOperations::isLockfreeJS(i
);
5027 bool js::DeleteNameOperation(JSContext
* cx
, Handle
<PropertyName
*> name
,
5028 HandleObject scopeObj
, MutableHandleValue res
) {
5029 RootedObject
scope(cx
), pobj(cx
);
5030 PropertyResult prop
;
5031 if (!LookupName(cx
, name
, scopeObj
, &scope
, &pobj
, &prop
)) {
5036 // Return true for non-existent names.
5037 res
.setBoolean(true);
5041 ObjectOpResult result
;
5042 RootedId
id(cx
, NameToId(name
));
5043 if (!DeleteProperty(cx
, scope
, id
, result
)) {
5047 bool status
= result
.ok();
5048 res
.setBoolean(status
);
5051 // Deleting a name from the global object removes it from [[VarNames]].
5052 if (pobj
== scope
&& scope
->is
<GlobalObject
>()) {
5053 scope
->as
<GlobalObject
>().removeFromVarNames(name
);
5060 bool js::ImplicitThisOperation(JSContext
* cx
, HandleObject scopeObj
,
5061 Handle
<PropertyName
*> name
,
5062 MutableHandleValue res
) {
5063 RootedObject
obj(cx
);
5064 if (!LookupNameWithGlobalDefault(cx
, name
, scopeObj
, &obj
)) {
5068 res
.set(ComputeImplicitThis(obj
));
5072 unsigned js::GetInitDataPropAttrs(JSOp op
) {
5074 case JSOp::InitProp
:
5075 case JSOp::InitElem
:
5076 return JSPROP_ENUMERATE
;
5077 case JSOp::InitLockedProp
:
5078 case JSOp::InitLockedElem
:
5079 return JSPROP_PERMANENT
| JSPROP_READONLY
;
5080 case JSOp::InitHiddenProp
:
5081 case JSOp::InitHiddenElem
:
5082 // Non-enumerable, but writable and configurable
5086 MOZ_CRASH("Unknown data initprop");
5089 static bool InitGetterSetterOperation(JSContext
* cx
, jsbytecode
* pc
,
5090 HandleObject obj
, HandleId id
,
5092 MOZ_ASSERT(val
->isCallable());
5094 JSOp op
= JSOp(*pc
);
5097 if (!IsHiddenInitOp(op
)) {
5098 attrs
|= JSPROP_ENUMERATE
;
5101 if (op
== JSOp::InitPropGetter
|| op
== JSOp::InitElemGetter
||
5102 op
== JSOp::InitHiddenPropGetter
|| op
== JSOp::InitHiddenElemGetter
) {
5103 return DefineAccessorProperty(cx
, obj
, id
, val
, nullptr, attrs
);
5106 MOZ_ASSERT(op
== JSOp::InitPropSetter
|| op
== JSOp::InitElemSetter
||
5107 op
== JSOp::InitHiddenPropSetter
||
5108 op
== JSOp::InitHiddenElemSetter
);
5109 return DefineAccessorProperty(cx
, obj
, id
, nullptr, val
, attrs
);
5112 bool js::InitPropGetterSetterOperation(JSContext
* cx
, jsbytecode
* pc
,
5114 Handle
<PropertyName
*> name
,
5116 RootedId
id(cx
, NameToId(name
));
5117 return InitGetterSetterOperation(cx
, pc
, obj
, id
, val
);
5120 bool js::InitElemGetterSetterOperation(JSContext
* cx
, jsbytecode
* pc
,
5121 HandleObject obj
, HandleValue idval
,
5124 if (!ToPropertyKey(cx
, idval
, &id
)) {
5128 return InitGetterSetterOperation(cx
, pc
, obj
, id
, val
);
5131 bool js::SpreadCallOperation(JSContext
* cx
, HandleScript script
, jsbytecode
* pc
,
5132 HandleValue thisv
, HandleValue callee
,
5133 HandleValue arr
, HandleValue newTarget
,
5134 MutableHandleValue res
) {
5135 Rooted
<ArrayObject
*> aobj(cx
, &arr
.toObject().as
<ArrayObject
>());
5136 uint32_t length
= aobj
->length();
5137 JSOp op
= JSOp(*pc
);
5138 bool constructing
= op
== JSOp::SpreadNew
|| op
== JSOp::SpreadSuperCall
;
5140 // {Construct,Invoke}Args::init does this too, but this gives us a better
5142 if (length
> ARGS_LENGTH_MAX
) {
5143 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5144 constructing
? JSMSG_TOO_MANY_CON_SPREADARGS
5145 : JSMSG_TOO_MANY_FUN_SPREADARGS
);
5149 // Do our own checks for the callee being a function, as Invoke uses the
5150 // expression decompiler to decompile the callee stack operand based on
5151 // the number of arguments. Spread operations have the callee at sp - 3
5152 // when not constructing, and sp - 4 when constructing.
5153 if (callee
.isPrimitive()) {
5154 return ReportIsNotFunction(cx
, callee
, 2 + constructing
,
5155 constructing
? CONSTRUCT
: NO_CONSTRUCT
);
5158 if (!callee
.toObject().isCallable()) {
5159 return ReportIsNotFunction(cx
, callee
, 2 + constructing
,
5160 constructing
? CONSTRUCT
: NO_CONSTRUCT
);
5163 // The object must be an array with dense elements and no holes. Baseline's
5164 // optimized spread call stubs rely on this.
5165 MOZ_ASSERT(IsPackedArray(aobj
));
5168 if (!StackCheckIsConstructorCalleeNewTarget(cx
, callee
, newTarget
)) {
5172 ConstructArgs
cargs(cx
);
5173 if (!cargs
.init(cx
, length
)) {
5177 if (!GetElements(cx
, aobj
, length
, cargs
.array())) {
5181 RootedObject
obj(cx
);
5182 if (!Construct(cx
, callee
, cargs
, newTarget
, &obj
)) {
5185 res
.setObject(*obj
);
5187 InvokeArgs
args(cx
);
5188 if (!args
.init(cx
, length
)) {
5192 if (!GetElements(cx
, aobj
, length
, args
.array())) {
5196 if ((op
== JSOp::SpreadEval
|| op
== JSOp::StrictSpreadEval
) &&
5197 cx
->global()->valueIsEval(callee
)) {
5198 if (!DirectEval(cx
, args
.get(0), res
)) {
5202 MOZ_ASSERT(op
== JSOp::SpreadCall
|| op
== JSOp::SpreadEval
||
5203 op
== JSOp::StrictSpreadEval
,
5204 "bad spread opcode");
5206 if (!Call(cx
, callee
, thisv
, args
, res
)) {
5215 static bool OptimizeArraySpreadCall(JSContext
* cx
, HandleObject obj
,
5216 MutableHandleValue result
) {
5217 MOZ_ASSERT(result
.isUndefined());
5219 // Optimize spread call by skipping spread operation when following
5220 // conditions are met:
5221 // * the argument is an array
5222 // * the array has no hole
5223 // * array[@@iterator] is not modified
5224 // * the array's prototype is Array.prototype
5225 // * Array.prototype[@@iterator] is not modified
5226 // * %ArrayIteratorPrototype%.next is not modified
5227 if (!IsPackedArray(obj
)) {
5231 ForOfPIC::Chain
* stubChain
= ForOfPIC::getOrCreate(cx
);
5237 if (!stubChain
->tryOptimizeArray(cx
, obj
.as
<ArrayObject
>(), &optimized
)) {
5244 result
.setObject(*obj
);
5248 static bool OptimizeArgumentsSpreadCall(JSContext
* cx
, HandleObject obj
,
5249 MutableHandleValue result
) {
5250 MOZ_ASSERT(result
.isUndefined());
5252 // Optimize spread call by skipping the spread operation when the following
5253 // conditions are met:
5254 // * the argument is an arguments object
5255 // * the arguments object has no deleted elements
5256 // * arguments.length is not overridden
5257 // * arguments[@@iterator] is not overridden
5258 // * %ArrayIteratorPrototype%.next is not modified
5260 if (!obj
->is
<ArgumentsObject
>()) {
5264 Handle
<ArgumentsObject
*> args
= obj
.as
<ArgumentsObject
>();
5265 if (args
->hasOverriddenElement() || args
->hasOverriddenLength() ||
5266 args
->hasOverriddenIterator()) {
5270 ForOfPIC::Chain
* stubChain
= ForOfPIC::getOrCreate(cx
);
5276 if (!stubChain
->tryOptimizeArrayIteratorNext(cx
, &optimized
)) {
5283 auto* array
= ArrayFromArgumentsObject(cx
, args
);
5288 result
.setObject(*array
);
5292 bool js::OptimizeSpreadCall(JSContext
* cx
, HandleValue arg
,
5293 MutableHandleValue result
) {
5294 // This function returns |undefined| if the spread operation can't be
5296 result
.setUndefined();
5298 if (!arg
.isObject()) {
5302 RootedObject
obj(cx
, &arg
.toObject());
5303 if (!OptimizeArraySpreadCall(cx
, obj
, result
)) {
5306 if (result
.isObject()) {
5309 if (!OptimizeArgumentsSpreadCall(cx
, obj
, result
)) {
5312 if (result
.isObject()) {
5316 MOZ_ASSERT(result
.isUndefined());
5320 ArrayObject
* js::ArrayFromArgumentsObject(JSContext
* cx
,
5321 Handle
<ArgumentsObject
*> args
) {
5322 MOZ_ASSERT(!args
->hasOverriddenLength());
5323 MOZ_ASSERT(!args
->hasOverriddenElement());
5325 uint32_t length
= args
->initialLength();
5326 auto* array
= NewDenseFullyAllocatedArray(cx
, length
);
5330 array
->setDenseInitializedLength(length
);
5332 for (uint32_t index
= 0; index
< length
; index
++) {
5333 const Value
& v
= args
->element(index
);
5334 array
->initDenseElement(index
, v
);
5340 JSObject
* js::NewObjectOperation(JSContext
* cx
, HandleScript script
,
5341 const jsbytecode
* pc
) {
5342 if (JSOp(*pc
) == JSOp::NewObject
) {
5343 Rooted
<SharedShape
*> shape(cx
, script
->getShape(pc
));
5344 return PlainObject::createWithShape(cx
, shape
);
5347 MOZ_ASSERT(JSOp(*pc
) == JSOp::NewInit
);
5348 return NewPlainObject(cx
);
5351 JSObject
* js::NewPlainObjectBaselineFallback(JSContext
* cx
,
5352 Handle
<SharedShape
*> shape
,
5353 gc::AllocKind allocKind
,
5354 gc::AllocSite
* site
) {
5355 MOZ_ASSERT(shape
->getObjectClass() == &PlainObject::class_
);
5357 mozilla::Maybe
<AutoRealm
> ar
;
5358 if (cx
->realm() != shape
->realm()) {
5359 MOZ_ASSERT(cx
->compartment() == shape
->compartment());
5360 ar
.emplace(cx
, shape
);
5363 gc::Heap initialHeap
= site
->initialHeap();
5364 return NativeObject::create(cx
, allocKind
, initialHeap
, shape
, site
);
5367 JSObject
* js::NewPlainObjectOptimizedFallback(JSContext
* cx
,
5368 Handle
<SharedShape
*> shape
,
5369 gc::AllocKind allocKind
,
5370 gc::Heap initialHeap
) {
5371 MOZ_ASSERT(shape
->getObjectClass() == &PlainObject::class_
);
5373 mozilla::Maybe
<AutoRealm
> ar
;
5374 if (cx
->realm() != shape
->realm()) {
5375 MOZ_ASSERT(cx
->compartment() == shape
->compartment());
5376 ar
.emplace(cx
, shape
);
5379 gc::AllocSite
* site
= cx
->zone()->optimizedAllocSite();
5380 return NativeObject::create(cx
, allocKind
, initialHeap
, shape
, site
);
5383 ArrayObject
* js::NewArrayOperation(
5384 JSContext
* cx
, uint32_t length
,
5385 NewObjectKind newKind
/* = GenericObject */) {
5386 return NewDenseFullyAllocatedArray(cx
, length
, newKind
);
5389 ArrayObject
* js::NewArrayObjectBaselineFallback(JSContext
* cx
, uint32_t length
,
5390 gc::AllocKind allocKind
,
5391 gc::AllocSite
* site
) {
5392 NewObjectKind newKind
=
5393 site
->initialHeap() == gc::Heap::Tenured
? TenuredObject
: GenericObject
;
5394 ArrayObject
* array
= NewDenseFullyAllocatedArray(cx
, length
, newKind
, site
);
5395 // It's important that we allocate an object with the alloc kind we were
5396 // expecting so that a new arena gets allocated if the current arena for that
5398 MOZ_ASSERT_IF(array
&& array
->isTenured(),
5399 array
->asTenured().getAllocKind() == allocKind
);
5403 ArrayObject
* js::NewArrayObjectOptimizedFallback(JSContext
* cx
, uint32_t length
,
5404 gc::AllocKind allocKind
,
5405 NewObjectKind newKind
) {
5406 gc::AllocSite
* site
= cx
->zone()->optimizedAllocSite();
5407 ArrayObject
* array
= NewDenseFullyAllocatedArray(cx
, length
, newKind
, site
);
5408 // It's important that we allocate an object with the alloc kind we were
5409 // expecting so that a new arena gets allocated if the current arena for that
5411 MOZ_ASSERT_IF(array
&& array
->isTenured(),
5412 array
->asTenured().getAllocKind() == allocKind
);
5416 void js::ReportRuntimeLexicalError(JSContext
* cx
, unsigned errorNumber
,
5418 MOZ_ASSERT(errorNumber
== JSMSG_UNINITIALIZED_LEXICAL
||
5419 errorNumber
== JSMSG_BAD_CONST_ASSIGN
);
5420 if (UniqueChars printable
=
5421 IdToPrintableUTF8(cx
, id
, IdToPrintableBehavior::IdIsIdentifier
)) {
5422 JS_ReportErrorNumberUTF8(cx
, GetErrorMessage
, nullptr, errorNumber
,
5427 void js::ReportRuntimeLexicalError(JSContext
* cx
, unsigned errorNumber
,
5428 Handle
<PropertyName
*> name
) {
5429 RootedId
id(cx
, NameToId(name
));
5430 ReportRuntimeLexicalError(cx
, errorNumber
, id
);
5433 void js::ReportRuntimeLexicalError(JSContext
* cx
, unsigned errorNumber
,
5434 HandleScript script
, jsbytecode
* pc
) {
5435 JSOp op
= JSOp(*pc
);
5436 MOZ_ASSERT(op
== JSOp::CheckLexical
|| op
== JSOp::CheckAliasedLexical
||
5437 op
== JSOp::ThrowSetConst
|| op
== JSOp::GetImport
);
5439 Rooted
<PropertyName
*> name(cx
);
5440 if (IsLocalOp(op
)) {
5441 name
= FrameSlotName(script
, pc
)->asPropertyName();
5442 } else if (IsAliasedVarOp(op
)) {
5443 name
= EnvironmentCoordinateNameSlow(script
, pc
);
5445 MOZ_ASSERT(IsAtomOp(op
));
5446 name
= script
->getName(pc
);
5449 ReportRuntimeLexicalError(cx
, errorNumber
, name
);
5452 void js::ReportRuntimeRedeclaration(JSContext
* cx
, Handle
<PropertyName
*> name
,
5453 const char* redeclKind
) {
5454 if (UniqueChars printable
= AtomToPrintableString(cx
, name
)) {
5455 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5456 JSMSG_REDECLARED_VAR
, redeclKind
,
5461 bool js::ThrowCheckIsObject(JSContext
* cx
, CheckIsObjectKind kind
) {
5463 case CheckIsObjectKind::IteratorNext
:
5464 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5465 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE
, "next");
5467 case CheckIsObjectKind::IteratorReturn
:
5468 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5469 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE
, "return");
5471 case CheckIsObjectKind::IteratorThrow
:
5472 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5473 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE
, "throw");
5475 case CheckIsObjectKind::GetIterator
:
5476 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5477 JSMSG_GET_ITER_RETURNED_PRIMITIVE
);
5479 case CheckIsObjectKind::GetAsyncIterator
:
5480 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5481 JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE
);
5483 #ifdef ENABLE_DECORATORS
5484 case CheckIsObjectKind::DecoratorReturn
:
5485 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5486 JSMSG_DECORATOR_INVALID_RETURN_TYPE
);
5490 MOZ_CRASH("Unknown kind");
5495 bool js::ThrowUninitializedThis(JSContext
* cx
) {
5496 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5497 JSMSG_UNINITIALIZED_THIS
);
5501 bool js::ThrowInitializedThis(JSContext
* cx
) {
5502 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_REINIT_THIS
);
5506 bool js::ThrowObjectCoercible(JSContext
* cx
, HandleValue value
) {
5507 MOZ_ASSERT(value
.isNullOrUndefined());
5508 ReportIsNullOrUndefinedForPropertyAccess(cx
, value
, JSDVG_SEARCH_STACK
);
5512 bool js::SetPropertySuper(JSContext
* cx
, HandleValue lval
, HandleValue receiver
,
5513 Handle
<PropertyName
*> name
, HandleValue rval
,
5515 MOZ_ASSERT(lval
.isObjectOrNull());
5517 RootedObject
obj(cx
, ToObjectFromStackForPropertyAccess(
5518 cx
, lval
, JSDVG_SEARCH_STACK
, name
));
5523 RootedId
id(cx
, NameToId(name
));
5524 return SetObjectElementOperation(cx
, obj
, id
, rval
, receiver
, strict
);
5527 bool js::SetElementSuper(JSContext
* cx
, HandleValue lval
, HandleValue receiver
,
5528 HandleValue index
, HandleValue rval
, bool strict
) {
5529 MOZ_ASSERT(lval
.isObjectOrNull());
5531 RootedObject
obj(cx
, ToObjectFromStackForPropertyAccess(
5532 cx
, lval
, JSDVG_SEARCH_STACK
, index
));
5537 return SetObjectElementWithReceiver(cx
, obj
, index
, rval
, receiver
, strict
);
5540 bool js::LoadAliasedDebugVar(JSContext
* cx
, JSObject
* env
, jsbytecode
* pc
,
5541 MutableHandleValue result
) {
5542 EnvironmentCoordinate
ec(pc
);
5544 for (unsigned i
= ec
.hops(); i
; i
--) {
5545 if (env
->is
<EnvironmentObject
>()) {
5546 env
= &env
->as
<EnvironmentObject
>().enclosingEnvironment();
5548 MOZ_ASSERT(env
->is
<DebugEnvironmentProxy
>());
5549 env
= &env
->as
<DebugEnvironmentProxy
>().enclosingEnvironment();
5553 EnvironmentObject
& finalEnv
=
5554 env
->is
<EnvironmentObject
>()
5555 ? env
->as
<EnvironmentObject
>()
5556 : env
->as
<DebugEnvironmentProxy
>().environment();
5558 result
.set(finalEnv
.aliasedBinding(ec
));
5562 // https://tc39.es/ecma262/#sec-iteratorclose
5563 bool js::CloseIterOperation(JSContext
* cx
, HandleObject iter
,
5564 CompletionKind kind
) {
5565 // Steps 1-2 are implicit.
5568 RootedValue
returnMethod(cx
);
5570 GetProperty(cx
, iter
, iter
, cx
->names().return_
, &returnMethod
);
5573 RootedValue
result(cx
);
5576 if (returnMethod
.isNullOrUndefined()) {
5580 if (IsCallable(returnMethod
)) {
5581 RootedValue
thisVal(cx
, ObjectValue(*iter
));
5582 innerResult
= Call(cx
, returnMethod
, thisVal
, &result
);
5584 innerResult
= ReportIsNotFunction(cx
, returnMethod
);
5589 if (kind
== CompletionKind::Throw
) {
5590 // If we close an iterator while unwinding for an exception,
5591 // the initial exception takes priority over any exception thrown
5592 // while closing the iterator.
5593 if (cx
->isExceptionPending()) {
5594 cx
->clearPendingException();
5605 if (!result
.isObject()) {
5606 return ThrowCheckIsObject(cx
, CheckIsObjectKind::IteratorReturn
);