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 bool js::ReportIsNotFunction(JSContext
* cx
, HandleValue v
, int numToSkip
,
272 MaybeConstruct construct
) {
273 unsigned error
= construct
? JSMSG_NOT_CONSTRUCTOR
: JSMSG_NOT_FUNCTION
;
274 int spIndex
= numToSkip
>= 0 ? -(numToSkip
+ 1) : JSDVG_SEARCH_STACK
;
276 ReportValueError(cx
, error
, spIndex
, v
, nullptr);
280 JSObject
* js::ValueToCallable(JSContext
* cx
, HandleValue v
, int numToSkip
,
281 MaybeConstruct construct
) {
282 if (v
.isObject() && v
.toObject().isCallable()) {
283 return &v
.toObject();
286 ReportIsNotFunction(cx
, v
, numToSkip
, construct
);
290 static bool MaybeCreateThisForConstructor(JSContext
* cx
, const CallArgs
& args
) {
291 if (args
.thisv().isObject()) {
295 RootedFunction
callee(cx
, &args
.callee().as
<JSFunction
>());
296 RootedObject
newTarget(cx
, &args
.newTarget().toObject());
298 MOZ_ASSERT(callee
->hasBytecode());
300 if (!CreateThis(cx
, callee
, newTarget
, GenericObject
, args
.mutableThisv())) {
304 // Ensure the callee still has a non-lazy script. We normally don't relazify
305 // in active compartments, but the .prototype lookup might have called the
306 // relazifyFunctions testing function that doesn't have this restriction.
307 return JSFunction::getOrCreateScript(cx
, callee
);
310 #ifdef ENABLE_RECORD_TUPLE
311 static bool AddRecordSpreadOperation(JSContext
* cx
, HandleValue recHandle
,
312 HandleValue spreadeeHandle
) {
313 MOZ_ASSERT(recHandle
.toExtendedPrimitive().is
<RecordType
>());
314 RecordType
* rec
= &recHandle
.toExtendedPrimitive().as
<RecordType
>();
316 RootedObject
obj(cx
, ToObjectOrGetObjectPayload(cx
, spreadeeHandle
));
318 RootedIdVector
keys(cx
);
319 if (!GetPropertyKeys(cx
, obj
, JSITER_OWNONLY
| JSITER_SYMBOLS
, &keys
)) {
323 size_t len
= keys
.length();
324 RootedId
propKey(cx
);
325 RootedValue
propValue(cx
);
326 for (size_t i
= 0; i
< len
; i
++) {
327 propKey
.set(keys
[i
]);
330 if (MOZ_UNLIKELY(!GetProperty(cx
, obj
, obj
, propKey
, &propValue
))) {
334 if (MOZ_UNLIKELY(!rec
->initializeNextProperty(cx
, propKey
, propValue
))) {
343 InterpreterFrame
* InvokeState::pushInterpreterFrame(JSContext
* cx
) {
344 return cx
->interpreterStack().pushInvokeFrame(cx
, args_
, construct_
);
347 InterpreterFrame
* ExecuteState::pushInterpreterFrame(JSContext
* cx
) {
348 return cx
->interpreterStack().pushExecuteFrame(cx
, script_
, envChain_
,
352 InterpreterFrame
* RunState::pushInterpreterFrame(JSContext
* cx
) {
354 return asInvoke()->pushInterpreterFrame(cx
);
356 return asExecute()->pushInterpreterFrame(cx
);
359 static MOZ_ALWAYS_INLINE
bool MaybeEnterInterpreterTrampoline(JSContext
* cx
,
362 if (jit::JitOptions
.emitInterpreterEntryTrampoline
&&
363 cx
->runtime()->hasJitRuntime()) {
364 js::jit::JitRuntime
* jitRuntime
= cx
->runtime()->jitRuntime();
365 JSScript
* script
= state
.script();
367 uint8_t* codeRaw
= nullptr;
368 auto p
= jitRuntime
->getInterpreterEntryMap()->lookup(script
);
370 codeRaw
= p
->value().raw();
371 } else if (js::jit::JitCode
* code
=
372 jitRuntime
->generateEntryTrampolineForScript(cx
, script
)) {
373 js::jit::EntryTrampoline
entry(cx
, code
);
374 if (!jitRuntime
->getInterpreterEntryMap()->put(script
, entry
)) {
377 codeRaw
= code
->raw();
380 MOZ_ASSERT(codeRaw
, "Should have a valid trampoline here.");
381 // The C++ entry thunk is located at the vmInterpreterEntryOffset offset.
382 codeRaw
+= jitRuntime
->vmInterpreterEntryOffset();
383 return js::jit::EnterInterpreterEntryTrampoline(codeRaw
, cx
, &state
);
386 return Interpret(cx
, state
);
389 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
390 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
393 # pragma optimize("g", off)
395 bool js::RunScript(JSContext
* cx
, RunState
& state
) {
396 AutoCheckRecursionLimit
recursion(cx
);
397 if (!recursion
.check(cx
)) {
401 MOZ_ASSERT_IF(cx
->runtime()->hasJitRuntime(),
402 !cx
->runtime()->jitRuntime()->disallowArbitraryCode());
404 // Since any script can conceivably GC, make sure it's safe to do so.
405 cx
->verifyIsSafeToGC();
407 MOZ_ASSERT(cx
->realm() == state
.script()->realm());
409 MOZ_DIAGNOSTIC_ASSERT(cx
->realm()->isSystem() ||
410 cx
->runtime()->allowContentJS());
412 if (!DebugAPI::checkNoExecute(cx
, state
.script())) {
416 GeckoProfilerEntryMarker
marker(cx
, state
.script());
418 bool measuringTime
= !cx
->isMeasuringExecutionTime();
419 mozilla::TimeStamp startTime
;
421 cx
->setIsMeasuringExecutionTime(true);
422 cx
->setIsExecuting(true);
423 startTime
= mozilla::TimeStamp::Now();
425 auto timerEnd
= mozilla::MakeScopeExit([&]() {
427 mozilla::TimeDuration delta
= mozilla::TimeStamp::Now() - startTime
;
428 cx
->realm()->timers
.executionTime
+= delta
;
429 cx
->setIsMeasuringExecutionTime(false);
430 cx
->setIsExecuting(false);
434 jit::EnterJitStatus status
= jit::MaybeEnterJit(cx
, state
);
436 case jit::EnterJitStatus::Error
:
438 case jit::EnterJitStatus::Ok
:
440 case jit::EnterJitStatus::NotEntered
:
444 bool ok
= MaybeEnterInterpreterTrampoline(cx
, state
);
449 # pragma optimize("", on)
452 STATIC_PRECONDITION_ASSUME(ubound(args
.argv_
) >= argc
)
453 MOZ_ALWAYS_INLINE
bool CallJSNative(JSContext
* cx
, Native native
,
454 CallReason reason
, const CallArgs
& args
) {
455 AutoCheckRecursionLimit
recursion(cx
);
456 if (!recursion
.check(cx
)) {
460 NativeResumeMode resumeMode
= DebugAPI::onNativeCall(cx
, args
, reason
);
461 if (resumeMode
!= NativeResumeMode::Continue
) {
462 return resumeMode
== NativeResumeMode::Override
;
466 bool alreadyThrowing
= cx
->isExceptionPending();
469 MOZ_ASSERT(!args
.callee().is
<ProxyObject
>());
471 AutoRealm
ar(cx
, &args
.callee());
472 bool ok
= native(cx
, args
.length(), args
.base());
474 cx
->check(args
.rval());
475 MOZ_ASSERT_IF(!alreadyThrowing
, !cx
->isExceptionPending());
480 STATIC_PRECONDITION(ubound(args
.argv_
) >= argc
)
481 MOZ_ALWAYS_INLINE
bool CallJSNativeConstructor(JSContext
* cx
, Native native
,
482 const CallArgs
& args
) {
484 RootedObject
callee(cx
, &args
.callee());
487 MOZ_ASSERT(args
.thisv().isMagic());
488 if (!CallJSNative(cx
, native
, CallReason::Call
, args
)) {
493 * Native constructors must return non-primitive values on success.
494 * Although it is legal, if a constructor returns the callee, there is a
495 * 99.9999% chance it is a bug. If any valid code actually wants the
496 * constructor to return the callee, the assertion can be removed or
497 * (another) conjunct can be added to the antecedent.
500 * - (new Object(Object)) returns the callee.
501 * - The bound function construct hook can return an arbitrary object,
502 * including the callee.
504 * Also allow if this may be due to a debugger hook since fuzzing may let this
507 MOZ_ASSERT(args
.rval().isObject());
508 MOZ_ASSERT_IF(!JS_IsNativeFunction(callee
, obj_construct
) &&
509 !callee
->is
<BoundFunctionObject
>() &&
510 !cx
->insideDebuggerEvaluationWithOnNativeCallHook
,
511 args
.rval() != ObjectValue(*callee
));
517 * Find a function reference and its 'this' value implicit first parameter
518 * under argc arguments on cx's stack, and call the function. Push missing
519 * required arguments, allocate declared local variables, and pop everything
520 * when done. Then push the return value.
522 * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
523 * necessary. The caller (usually the interpreter) must have performed
526 bool js::InternalCallOrConstruct(JSContext
* cx
, const CallArgs
& args
,
527 MaybeConstruct construct
,
528 CallReason reason
/* = CallReason::Call */) {
529 MOZ_ASSERT(args
.length() <= ARGS_LENGTH_MAX
);
531 unsigned skipForCallee
= args
.length() + 1 + (construct
== CONSTRUCT
);
532 if (args
.calleev().isPrimitive()) {
533 return ReportIsNotFunction(cx
, args
.calleev(), skipForCallee
, construct
);
536 /* Invoke non-functions. */
537 if (MOZ_UNLIKELY(!args
.callee().is
<JSFunction
>())) {
538 MOZ_ASSERT_IF(construct
, !args
.callee().isConstructor());
540 if (!args
.callee().isCallable()) {
541 return ReportIsNotFunction(cx
, args
.calleev(), skipForCallee
, construct
);
544 if (args
.callee().is
<ProxyObject
>()) {
545 RootedObject
proxy(cx
, &args
.callee());
546 return Proxy::call(cx
, proxy
, args
);
549 JSNative call
= args
.callee().callHook();
550 MOZ_ASSERT(call
, "isCallable without a callHook?");
552 return CallJSNative(cx
, call
, reason
, args
);
555 /* Invoke native functions. */
556 RootedFunction
fun(cx
, &args
.callee().as
<JSFunction
>());
557 if (fun
->isNativeFun()) {
558 MOZ_ASSERT_IF(construct
, !fun
->isConstructor());
559 JSNative native
= fun
->native();
560 if (!construct
&& args
.ignoresReturnValue() && fun
->hasJitInfo()) {
561 const JSJitInfo
* jitInfo
= fun
->jitInfo();
562 if (jitInfo
->type() == JSJitInfo::IgnoresReturnValueNative
) {
563 native
= jitInfo
->ignoresReturnValueMethod
;
566 return CallJSNative(cx
, native
, reason
, args
);
569 // Self-hosted builtins are considered native by the onNativeCall hook.
570 if (fun
->isSelfHostedBuiltin()) {
571 NativeResumeMode resumeMode
= DebugAPI::onNativeCall(cx
, args
, reason
);
572 if (resumeMode
!= NativeResumeMode::Continue
) {
573 return resumeMode
== NativeResumeMode::Override
;
577 if (!JSFunction::getOrCreateScript(cx
, fun
)) {
581 /* Run function until JSOp::RetRval, JSOp::Return or error. */
582 InvokeState
state(cx
, args
, construct
);
584 // Create |this| if we're constructing. Switch to the callee's realm to
585 // ensure this object has the correct realm.
586 AutoRealm
ar(cx
, state
.script());
587 if (construct
&& !MaybeCreateThisForConstructor(cx
, args
)) {
591 // Calling class constructors throws an error from the callee's realm.
592 if (construct
!= CONSTRUCT
&& fun
->isClassConstructor()) {
593 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
594 JSMSG_CANT_CALL_CLASS_CONSTRUCTOR
);
598 bool ok
= RunScript(cx
, state
);
600 MOZ_ASSERT_IF(ok
&& construct
, args
.rval().isObject());
604 // Returns true if the callee needs an outerized |this| object. Outerization
605 // means passing the WindowProxy instead of the Window (a GlobalObject) because
606 // we must never expose the Window to script. This returns false only for DOM
607 // getters or setters.
608 static bool CalleeNeedsOuterizedThisObject(const Value
& callee
) {
609 if (!callee
.isObject() || !callee
.toObject().is
<JSFunction
>()) {
612 JSFunction
& fun
= callee
.toObject().as
<JSFunction
>();
613 if (!fun
.isNativeFun() || !fun
.hasJitInfo()) {
616 return fun
.jitInfo()->needsOuterizedThisObject();
619 static bool InternalCall(JSContext
* cx
, const AnyInvokeArgs
& args
,
621 MOZ_ASSERT(args
.array() + args
.length() == args
.end(),
622 "must pass calling arguments to a calling attempt");
625 // The caller is responsible for calling GetThisObject if needed.
626 if (args
.thisv().isObject()) {
627 JSObject
* thisObj
= &args
.thisv().toObject();
628 MOZ_ASSERT_IF(CalleeNeedsOuterizedThisObject(args
.calleev()),
629 GetThisObject(thisObj
) == thisObj
);
633 return InternalCallOrConstruct(cx
, args
, NO_CONSTRUCT
, reason
);
636 bool js::CallFromStack(JSContext
* cx
, const CallArgs
& args
,
637 CallReason reason
/* = CallReason::Call */) {
638 return InternalCall(cx
, static_cast<const AnyInvokeArgs
&>(args
), reason
);
641 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
643 bool js::Call(JSContext
* cx
, HandleValue fval
, HandleValue thisv
,
644 const AnyInvokeArgs
& args
, MutableHandleValue rval
,
646 // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
648 args
.CallArgs::setCallee(fval
);
649 args
.CallArgs::setThis(thisv
);
651 if (thisv
.isObject()) {
652 // If |this| is a global object, it might be a Window and in that case we
653 // usually have to pass the WindowProxy instead.
654 JSObject
* thisObj
= &thisv
.toObject();
655 if (thisObj
->is
<GlobalObject
>()) {
656 if (CalleeNeedsOuterizedThisObject(fval
)) {
657 args
.mutableThisv().setObject(*GetThisObject(thisObj
));
660 // Fast path: we don't have to do anything if the object isn't a global.
661 MOZ_ASSERT(GetThisObject(thisObj
) == thisObj
);
665 if (!InternalCall(cx
, args
, reason
)) {
669 rval
.set(args
.rval());
673 static bool InternalConstruct(JSContext
* cx
, const AnyConstructArgs
& args
,
674 CallReason reason
= CallReason::Call
) {
675 MOZ_ASSERT(args
.array() + args
.length() + 1 == args
.end(),
676 "must pass constructing arguments to a construction attempt");
677 MOZ_ASSERT(!FunctionClass
.getConstruct());
678 MOZ_ASSERT(!ExtendedFunctionClass
.getConstruct());
680 // Callers are responsible for enforcing these preconditions.
681 MOZ_ASSERT(IsConstructor(args
.calleev()),
682 "trying to construct a value that isn't a constructor");
683 MOZ_ASSERT(IsConstructor(args
.CallArgs::newTarget()),
684 "provided new.target value must be a constructor");
686 MOZ_ASSERT(args
.thisv().isMagic(JS_IS_CONSTRUCTING
) ||
687 args
.thisv().isObject());
689 JSObject
& callee
= args
.callee();
690 if (callee
.is
<JSFunction
>()) {
691 RootedFunction
fun(cx
, &callee
.as
<JSFunction
>());
693 if (fun
->isNativeFun()) {
694 return CallJSNativeConstructor(cx
, fun
->native(), args
);
697 if (!InternalCallOrConstruct(cx
, args
, CONSTRUCT
, reason
)) {
701 MOZ_ASSERT(args
.CallArgs::rval().isObject());
705 if (callee
.is
<ProxyObject
>()) {
706 RootedObject
proxy(cx
, &callee
);
707 return Proxy::construct(cx
, proxy
, args
);
710 JSNative construct
= callee
.constructHook();
711 MOZ_ASSERT(construct
!= nullptr, "IsConstructor without a construct hook?");
713 return CallJSNativeConstructor(cx
, construct
, args
);
716 // Check that |callee|, the callee in a |new| expression, is a constructor.
717 static bool StackCheckIsConstructorCalleeNewTarget(JSContext
* cx
,
719 HandleValue newTarget
) {
720 // Calls from the stack could have any old non-constructor callee.
721 if (!IsConstructor(callee
)) {
722 ReportValueError(cx
, JSMSG_NOT_CONSTRUCTOR
, JSDVG_SEARCH_STACK
, callee
,
727 // The new.target has already been vetted by previous calls, or is the callee.
728 // We can just assert that it's a constructor.
729 MOZ_ASSERT(IsConstructor(newTarget
));
734 bool js::ConstructFromStack(JSContext
* cx
, const CallArgs
& args
,
735 CallReason reason
/* CallReason::Call */) {
736 if (!StackCheckIsConstructorCalleeNewTarget(cx
, args
.calleev(),
741 return InternalConstruct(cx
, static_cast<const AnyConstructArgs
&>(args
),
745 bool js::Construct(JSContext
* cx
, HandleValue fval
,
746 const AnyConstructArgs
& args
, HandleValue newTarget
,
747 MutableHandleObject objp
) {
748 MOZ_ASSERT(args
.thisv().isMagic(JS_IS_CONSTRUCTING
));
750 // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
751 args
.CallArgs::setCallee(fval
);
752 args
.CallArgs::newTarget().set(newTarget
);
754 if (!InternalConstruct(cx
, args
)) {
758 MOZ_ASSERT(args
.CallArgs::rval().isObject());
759 objp
.set(&args
.CallArgs::rval().toObject());
763 bool js::InternalConstructWithProvidedThis(JSContext
* cx
, HandleValue fval
,
765 const AnyConstructArgs
& args
,
766 HandleValue newTarget
,
767 MutableHandleValue rval
) {
768 args
.CallArgs::setCallee(fval
);
770 MOZ_ASSERT(thisv
.isObject());
771 args
.CallArgs::setThis(thisv
);
773 args
.CallArgs::newTarget().set(newTarget
);
775 if (!InternalConstruct(cx
, args
)) {
779 rval
.set(args
.CallArgs::rval());
783 bool js::CallGetter(JSContext
* cx
, HandleValue thisv
, HandleValue getter
,
784 MutableHandleValue rval
) {
785 FixedInvokeArgs
<0> args(cx
);
787 return Call(cx
, getter
, thisv
, args
, rval
, CallReason::Getter
);
790 bool js::CallSetter(JSContext
* cx
, HandleValue thisv
, HandleValue setter
,
792 FixedInvokeArgs
<1> args(cx
);
795 RootedValue
ignored(cx
);
796 return Call(cx
, setter
, thisv
, args
, &ignored
, CallReason::Setter
);
799 bool js::ExecuteKernel(JSContext
* cx
, HandleScript script
,
800 HandleObject envChainArg
, AbstractFramePtr evalInFrame
,
801 MutableHandleValue result
) {
802 MOZ_ASSERT_IF(script
->isGlobalCode(),
803 IsGlobalLexicalEnvironment(envChainArg
) ||
804 !IsSyntacticEnvironment(envChainArg
));
806 RootedObject
terminatingEnv(cx
, envChainArg
);
807 while (IsSyntacticEnvironment(terminatingEnv
)) {
808 terminatingEnv
= terminatingEnv
->enclosingEnvironment();
810 MOZ_ASSERT(terminatingEnv
->is
<GlobalObject
>() ||
811 script
->hasNonSyntacticScope());
814 if (script
->treatAsRunOnce()) {
815 if (script
->hasRunOnce()) {
816 JS_ReportErrorASCII(cx
,
817 "Trying to execute a run-once script multiple times");
821 script
->setHasRunOnce();
824 if (script
->isEmpty()) {
825 result
.setUndefined();
829 probes::StartExecution(script
);
830 ExecuteState
state(cx
, script
, envChainArg
, evalInFrame
, result
);
831 bool ok
= RunScript(cx
, state
);
832 probes::StopExecution(script
);
837 bool js::Execute(JSContext
* cx
, HandleScript script
, HandleObject envChain
,
838 MutableHandleValue rval
) {
839 /* The env chain is something we control, so we know it can't
840 have any outer objects on it. */
841 MOZ_ASSERT(!IsWindowProxy(envChain
));
843 if (script
->isModule()) {
845 envChain
== script
->module()->environment(),
846 "Module scripts can only be executed in the module's environment");
849 IsGlobalLexicalEnvironment(envChain
) || script
->hasNonSyntacticScope(),
850 "Only global scripts with non-syntactic envs can be executed with "
851 "interesting envchains");
854 /* Ensure the env chain is all same-compartment and terminates in a global. */
856 JSObject
* s
= envChain
;
859 MOZ_ASSERT_IF(!s
->enclosingEnvironment(), s
->is
<GlobalObject
>());
860 } while ((s
= s
->enclosingEnvironment()));
863 return ExecuteKernel(cx
, script
, envChain
, NullFramePtr() /* evalInFrame */,
868 * ES6 (4-25-16) 12.10.4 InstanceofOperator
870 bool js::InstanceofOperator(JSContext
* cx
, HandleObject obj
, HandleValue v
,
872 /* Step 1. is handled by caller. */
875 RootedValue
hasInstance(cx
);
876 RootedId
id(cx
, PropertyKey::Symbol(cx
->wellKnownSymbols().hasInstance
));
877 if (!GetProperty(cx
, obj
, obj
, id
, &hasInstance
)) {
881 if (!hasInstance
.isNullOrUndefined()) {
882 if (!IsCallable(hasInstance
)) {
883 return ReportIsNotFunction(cx
, hasInstance
);
887 RootedValue
rval(cx
);
888 if (!Call(cx
, hasInstance
, obj
, v
, &rval
)) {
891 *bp
= ToBoolean(rval
);
896 if (!obj
->isCallable()) {
897 RootedValue
val(cx
, ObjectValue(*obj
));
898 return ReportIsNotFunction(cx
, val
);
902 return OrdinaryHasInstance(cx
, obj
, v
, bp
);
905 JSType
js::TypeOfObject(JSObject
* obj
) {
906 #ifdef ENABLE_RECORD_TUPLE
907 MOZ_ASSERT(!js::IsExtendedPrimitive(*obj
));
910 AutoUnsafeCallWithABI unsafe
;
911 if (EmulatesUndefined(obj
)) {
912 return JSTYPE_UNDEFINED
;
914 if (obj
->isCallable()) {
915 return JSTYPE_FUNCTION
;
917 return JSTYPE_OBJECT
;
920 #ifdef ENABLE_RECORD_TUPLE
921 JSType
TypeOfExtendedPrimitive(JSObject
* obj
) {
922 MOZ_ASSERT(js::IsExtendedPrimitive(*obj
));
924 if (obj
->is
<RecordType
>()) {
925 return JSTYPE_RECORD
;
927 if (obj
->is
<TupleType
>()) {
930 MOZ_CRASH("Unknown ExtendedPrimitive");
934 JSType
js::TypeOfValue(const Value
& v
) {
936 case ValueType::Double
:
937 case ValueType::Int32
:
938 return JSTYPE_NUMBER
;
939 case ValueType::String
:
940 return JSTYPE_STRING
;
941 case ValueType::Null
:
942 return JSTYPE_OBJECT
;
943 case ValueType::Undefined
:
944 return JSTYPE_UNDEFINED
;
945 case ValueType::Object
:
946 return TypeOfObject(&v
.toObject());
947 #ifdef ENABLE_RECORD_TUPLE
948 case ValueType::ExtendedPrimitive
:
949 return TypeOfExtendedPrimitive(&v
.toExtendedPrimitive());
951 case ValueType::Boolean
:
952 return JSTYPE_BOOLEAN
;
953 case ValueType::BigInt
:
954 return JSTYPE_BIGINT
;
955 case ValueType::Symbol
:
956 return JSTYPE_SYMBOL
;
957 case ValueType::Magic
:
958 case ValueType::PrivateGCThing
:
962 ReportBadValueTypeAndCrash(v
);
965 bool js::CheckClassHeritageOperation(JSContext
* cx
, HandleValue heritage
) {
966 if (IsConstructor(heritage
)) {
970 if (heritage
.isNull()) {
974 if (heritage
.isObject()) {
975 ReportIsNotFunction(cx
, heritage
, 0, CONSTRUCT
);
979 ReportValueError(cx
, JSMSG_BAD_HERITAGE
, -1, heritage
, nullptr,
980 "not an object or null");
984 PlainObject
* js::ObjectWithProtoOperation(JSContext
* cx
, HandleValue val
) {
985 if (!val
.isObjectOrNull()) {
986 ReportValueError(cx
, JSMSG_NOT_OBJORNULL
, -1, val
, nullptr);
990 RootedObject
proto(cx
, val
.toObjectOrNull());
991 return NewPlainObjectWithProto(cx
, proto
);
994 JSObject
* js::FunWithProtoOperation(JSContext
* cx
, HandleFunction fun
,
995 HandleObject parent
, HandleObject proto
) {
996 return CloneFunctionReuseScript(cx
, fun
, parent
, proto
);
1000 * Enter the new with environment using an object at sp[-1] and associate the
1001 * depth of the with block with sp + stackIndex.
1003 bool js::EnterWithOperation(JSContext
* cx
, AbstractFramePtr frame
,
1004 HandleValue val
, Handle
<WithScope
*> scope
) {
1005 RootedObject
obj(cx
);
1006 if (val
.isObject()) {
1007 obj
= &val
.toObject();
1009 obj
= ToObject(cx
, val
);
1015 RootedObject
envChain(cx
, frame
.environmentChain());
1016 WithEnvironmentObject
* withobj
=
1017 WithEnvironmentObject::create(cx
, obj
, envChain
, scope
);
1022 frame
.pushOnEnvironmentChain(*withobj
);
1026 static void PopEnvironment(JSContext
* cx
, EnvironmentIter
& ei
) {
1027 switch (ei
.scope().kind()) {
1028 case ScopeKind::Lexical
:
1029 case ScopeKind::SimpleCatch
:
1030 case ScopeKind::Catch
:
1031 case ScopeKind::NamedLambda
:
1032 case ScopeKind::StrictNamedLambda
:
1033 case ScopeKind::FunctionLexical
:
1034 case ScopeKind::ClassBody
:
1035 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1036 DebugEnvironments::onPopLexical(cx
, ei
);
1038 if (ei
.scope().hasEnvironment()) {
1040 .popOffEnvironmentChain
<ScopedLexicalEnvironmentObject
>();
1043 case ScopeKind::With
:
1044 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1045 DebugEnvironments::onPopWith(ei
.initialFrame());
1047 ei
.initialFrame().popOffEnvironmentChain
<WithEnvironmentObject
>();
1049 case ScopeKind::Function
:
1050 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1051 DebugEnvironments::onPopCall(cx
, ei
.initialFrame());
1053 if (ei
.scope().hasEnvironment()) {
1054 ei
.initialFrame().popOffEnvironmentChain
<CallObject
>();
1057 case ScopeKind::FunctionBodyVar
:
1058 case ScopeKind::StrictEval
:
1059 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1060 DebugEnvironments::onPopVar(cx
, ei
);
1062 if (ei
.scope().hasEnvironment()) {
1063 ei
.initialFrame().popOffEnvironmentChain
<VarEnvironmentObject
>();
1066 case ScopeKind::Module
:
1067 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
1068 DebugEnvironments::onPopModule(cx
, ei
);
1071 case ScopeKind::Eval
:
1072 case ScopeKind::Global
:
1073 case ScopeKind::NonSyntactic
:
1075 case ScopeKind::WasmInstance
:
1076 case ScopeKind::WasmFunction
:
1077 MOZ_CRASH("wasm is not interpreted");
1082 // Unwind environment chain and iterator to match the env corresponding to
1083 // the given bytecode position.
1084 void js::UnwindEnvironment(JSContext
* cx
, EnvironmentIter
& ei
, jsbytecode
* pc
) {
1085 if (!ei
.withinInitialFrame()) {
1089 Rooted
<Scope
*> scope(cx
, ei
.initialFrame().script()->innermostScope(pc
));
1092 // A frame's environment chain cannot be unwound to anything enclosing the
1093 // body scope of a script. This includes the parameter defaults
1094 // environment and the decl env object. These environments, once pushed
1095 // onto the environment chain, are expected to be there for the duration
1098 // Attempting to unwind to the parameter defaults code in a script is a
1099 // bug; that section of code has no try-catch blocks.
1100 JSScript
* script
= ei
.initialFrame().script();
1101 for (uint32_t i
= 0; i
< script
->bodyScopeIndex(); i
++) {
1102 MOZ_ASSERT(scope
!= script
->getScope(GCThingIndex(i
)));
1106 for (; ei
.maybeScope() != scope
; ei
++) {
1107 PopEnvironment(cx
, ei
);
1111 // Unwind all environments. This is needed because block scopes may cover the
1112 // first bytecode at a script's main(). e.g.,
1114 // function f() { { let i = 0; } }
1116 // will have no pc location distinguishing the first block scope from the
1117 // outermost function scope.
1118 void js::UnwindAllEnvironmentsInFrame(JSContext
* cx
, EnvironmentIter
& ei
) {
1119 for (; ei
.withinInitialFrame(); ei
++) {
1120 PopEnvironment(cx
, ei
);
1124 // Compute the pc needed to unwind the environment to the beginning of a try
1125 // block. We cannot unwind to *after* the JSOp::Try, because that might be the
1126 // first opcode of an inner scope, with the same problem as above. e.g.,
1128 // try { { let x; } }
1130 // will have no pc location distinguishing the try block scope from the inner
1132 jsbytecode
* js::UnwindEnvironmentToTryPc(JSScript
* script
, const TryNote
* tn
) {
1133 jsbytecode
* pc
= script
->offsetToPC(tn
->start
);
1134 if (tn
->kind() == TryNoteKind::Catch
|| tn
->kind() == TryNoteKind::Finally
) {
1135 pc
-= JSOpLength_Try
;
1136 MOZ_ASSERT(JSOp(*pc
) == JSOp::Try
);
1137 } else if (tn
->kind() == TryNoteKind::Destructuring
) {
1138 pc
-= JSOpLength_TryDestructuring
;
1139 MOZ_ASSERT(JSOp(*pc
) == JSOp::TryDestructuring
);
1144 static void SettleOnTryNote(JSContext
* cx
, const TryNote
* tn
,
1145 EnvironmentIter
& ei
, InterpreterRegs
& regs
) {
1146 // Unwind the environment to the beginning of the JSOp::Try.
1147 UnwindEnvironment(cx
, ei
, UnwindEnvironmentToTryPc(regs
.fp()->script(), tn
));
1149 // Set pc to the first bytecode after the the try note to point
1150 // to the beginning of catch or finally.
1151 regs
.pc
= regs
.fp()->script()->offsetToPC(tn
->start
+ tn
->length
);
1152 regs
.sp
= regs
.spForStackDepth(tn
->stackDepth
);
1155 class InterpreterTryNoteFilter
{
1156 const InterpreterRegs
& regs_
;
1159 explicit InterpreterTryNoteFilter(const InterpreterRegs
& regs
)
1161 bool operator()(const TryNote
* note
) {
1162 return note
->stackDepth
<= regs_
.stackDepth();
1166 class TryNoteIterInterpreter
: public TryNoteIter
<InterpreterTryNoteFilter
> {
1168 TryNoteIterInterpreter(JSContext
* cx
, const InterpreterRegs
& regs
)
1169 : TryNoteIter(cx
, regs
.fp()->script(), regs
.pc
,
1170 InterpreterTryNoteFilter(regs
)) {}
1173 static void UnwindIteratorsForUncatchableException(
1174 JSContext
* cx
, const InterpreterRegs
& regs
) {
1175 // c.f. the regular (catchable) TryNoteIterInterpreter loop in
1177 for (TryNoteIterInterpreter
tni(cx
, regs
); !tni
.done(); ++tni
) {
1178 const TryNote
* tn
= *tni
;
1179 switch (tn
->kind()) {
1180 case TryNoteKind::ForIn
: {
1181 Value
* sp
= regs
.spForStackDepth(tn
->stackDepth
);
1182 UnwindIteratorForUncatchableException(&sp
[-1].toObject());
1191 enum HandleErrorContinuation
{
1192 SuccessfulReturnContinuation
,
1193 ErrorReturnContinuation
,
1198 static HandleErrorContinuation
ProcessTryNotes(JSContext
* cx
,
1199 EnvironmentIter
& ei
,
1200 InterpreterRegs
& regs
) {
1201 for (TryNoteIterInterpreter
tni(cx
, regs
); !tni
.done(); ++tni
) {
1202 const TryNote
* tn
= *tni
;
1204 switch (tn
->kind()) {
1205 case TryNoteKind::Catch
:
1206 /* Catch cannot intercept the closing of a generator. */
1207 if (cx
->isClosingGenerator()) {
1211 SettleOnTryNote(cx
, tn
, ei
, regs
);
1212 return CatchContinuation
;
1214 case TryNoteKind::Finally
:
1215 SettleOnTryNote(cx
, tn
, ei
, regs
);
1216 return FinallyContinuation
;
1218 case TryNoteKind::ForIn
: {
1219 /* This is similar to JSOp::EndIter in the interpreter loop. */
1220 MOZ_ASSERT(tn
->stackDepth
<= regs
.stackDepth());
1221 Value
* sp
= regs
.spForStackDepth(tn
->stackDepth
);
1222 JSObject
* obj
= &sp
[-1].toObject();
1227 case TryNoteKind::Destructuring
: {
1228 // Whether the destructuring iterator is done is at the top of the
1229 // stack. The iterator object is second from the top.
1230 MOZ_ASSERT(tn
->stackDepth
> 1);
1231 Value
* sp
= regs
.spForStackDepth(tn
->stackDepth
);
1232 RootedValue
doneValue(cx
, sp
[-1]);
1233 MOZ_RELEASE_ASSERT(!doneValue
.isMagic());
1234 bool done
= ToBoolean(doneValue
);
1236 RootedObject
iterObject(cx
, &sp
[-2].toObject());
1237 if (!IteratorCloseForException(cx
, iterObject
)) {
1238 SettleOnTryNote(cx
, tn
, ei
, regs
);
1239 return ErrorReturnContinuation
;
1245 case TryNoteKind::ForOf
:
1246 case TryNoteKind::Loop
:
1249 // TryNoteKind::ForOfIterClose is handled internally by the try note
1252 MOZ_CRASH("Invalid try note");
1256 return SuccessfulReturnContinuation
;
1259 bool js::HandleClosingGeneratorReturn(JSContext
* cx
, AbstractFramePtr frame
,
1262 * Propagate the exception or error to the caller unless the exception
1263 * is an asynchronous return from a generator.
1265 if (cx
->isClosingGenerator()) {
1266 cx
->clearPendingException();
1268 auto* genObj
= GetGeneratorObjectForFrame(cx
, frame
);
1269 genObj
->setClosed();
1274 static HandleErrorContinuation
HandleError(JSContext
* cx
,
1275 InterpreterRegs
& regs
) {
1276 MOZ_ASSERT(regs
.fp()->script()->containsPC(regs
.pc
));
1277 MOZ_ASSERT(cx
->realm() == regs
.fp()->script()->realm());
1279 if (regs
.fp()->script()->hasScriptCounts()) {
1280 PCCounts
* counts
= regs
.fp()->script()->getThrowCounts(regs
.pc
);
1281 // If we failed to allocate, then skip the increment and continue to
1282 // handle the exception.
1284 counts
->numExec()++;
1288 EnvironmentIter
ei(cx
, regs
.fp(), regs
.pc
);
1292 if (cx
->isExceptionPending()) {
1293 /* Call debugger throw hooks. */
1294 if (!cx
->isClosingGenerator()) {
1295 if (!DebugAPI::onExceptionUnwind(cx
, regs
.fp())) {
1296 if (!cx
->isExceptionPending()) {
1300 // Ensure that the debugger hasn't returned 'true' while clearing the
1302 MOZ_ASSERT(cx
->isExceptionPending());
1305 HandleErrorContinuation res
= ProcessTryNotes(cx
, ei
, regs
);
1307 case SuccessfulReturnContinuation
:
1309 case ErrorReturnContinuation
:
1311 case CatchContinuation
:
1312 case FinallyContinuation
:
1313 // No need to increment the PCCounts number of execution here, as
1314 // the interpreter increments any PCCounts if present.
1315 MOZ_ASSERT_IF(regs
.fp()->script()->hasScriptCounts(),
1316 regs
.fp()->script()->maybeGetPCCounts(regs
.pc
));
1320 ok
= HandleClosingGeneratorReturn(cx
, regs
.fp(), ok
);
1322 UnwindIteratorsForUncatchableException(cx
, regs
);
1324 // We may be propagating a forced return from a debugger hook function.
1325 if (MOZ_UNLIKELY(cx
->isPropagatingForcedReturn())) {
1326 cx
->clearPropagatingForcedReturn();
1331 ok
= DebugAPI::onLeaveFrame(cx
, regs
.fp(), regs
.pc
, ok
);
1333 // After this point, we will pop the frame regardless. Settle the frame on
1334 // the end of the script.
1335 regs
.setToEndOfScript();
1337 return ok
? SuccessfulReturnContinuation
: ErrorReturnContinuation
;
1340 #define REGS (activation.regs())
1341 #define PUSH_COPY(v) \
1344 cx->debugOnlyCheck(REGS.sp[-1]); \
1346 #define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
1347 #define PUSH_NULL() REGS.sp++->setNull()
1348 #define PUSH_UNDEFINED() REGS.sp++->setUndefined()
1349 #define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
1350 #define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
1351 #define PUSH_INT32(i) REGS.sp++->setInt32(i)
1352 #define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
1353 #define PUSH_BIGINT(b) REGS.sp++->setBigInt(b)
1354 #define PUSH_STRING(s) \
1356 REGS.sp++->setString(s); \
1357 cx->debugOnlyCheck(REGS.sp[-1]); \
1359 #define PUSH_OBJECT(obj) \
1361 REGS.sp++->setObject(obj); \
1362 cx->debugOnlyCheck(REGS.sp[-1]); \
1364 #define PUSH_OBJECT_OR_NULL(obj) \
1366 REGS.sp++->setObjectOrNull(obj); \
1367 cx->debugOnlyCheck(REGS.sp[-1]); \
1369 #ifdef ENABLE_RECORD_TUPLE
1370 # define PUSH_EXTENDED_PRIMITIVE(obj) \
1372 REGS.sp++->setExtendedPrimitive(obj); \
1373 cx->debugOnlyCheck(REGS.sp[-1]); \
1376 #define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
1377 #define POP_COPY_TO(v) (v) = *--REGS.sp
1378 #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
1381 * Same for JSOp::SetName and JSOp::SetProp, which differ only slightly but
1382 * remain distinct for the decompiler.
1384 static_assert(JSOpLength_SetName
== JSOpLength_SetProp
);
1386 /* See TRY_BRANCH_AFTER_COND. */
1387 static_assert(JSOpLength_JumpIfTrue
== JSOpLength_JumpIfFalse
);
1388 static_assert(uint8_t(JSOp::JumpIfTrue
) == uint8_t(JSOp::JumpIfFalse
) + 1);
1391 * Compute the implicit |this| value used by a call expression with an
1392 * unqualified name reference. The environment the binding was found on is
1393 * passed as argument, env.
1395 * The implicit |this| is |undefined| for all environment types except
1396 * WithEnvironmentObject. This is the case for |with(...) {...}| expressions or
1397 * if the embedding uses a non-syntactic WithEnvironmentObject.
1399 * NOTE: A non-syntactic WithEnvironmentObject may have a corresponding
1400 * extensible LexicalEnviornmentObject, but it will not be considered as an
1401 * implicit |this|. This is for compatibility with the Gecko subscript loader.
1403 static inline Value
ComputeImplicitThis(JSObject
* env
) {
1404 // Fast-path for GlobalObject
1405 if (env
->is
<GlobalObject
>()) {
1406 return UndefinedValue();
1409 // WithEnvironmentObjects have an actual implicit |this|
1410 if (env
->is
<WithEnvironmentObject
>()) {
1411 return ObjectValue(*GetThisObjectOfWith(env
));
1414 // Debugger environments need special casing, as despite being
1415 // non-syntactic, they wrap syntactic environments and should not be
1416 // treated like other embedding-specific non-syntactic environments.
1417 if (env
->is
<DebugEnvironmentProxy
>()) {
1418 return ComputeImplicitThis(&env
->as
<DebugEnvironmentProxy
>().environment());
1421 MOZ_ASSERT(env
->is
<EnvironmentObject
>());
1422 return UndefinedValue();
1425 // BigInt proposal 3.2.4 Abstract Relational Comparison
1426 // Returns Nothing when at least one operand is a NaN, or when
1427 // ToNumeric or StringToBigInt can't interpret a string as a numeric
1428 // value. (These cases correspond to a NaN result in the spec.)
1429 // Otherwise, return a boolean to indicate whether lhs is less than
1430 // rhs. The operands must be primitives; the caller is responsible for
1431 // evaluating them in the correct order.
1432 static MOZ_ALWAYS_INLINE
bool LessThanImpl(JSContext
* cx
,
1433 MutableHandleValue lhs
,
1434 MutableHandleValue rhs
,
1435 mozilla::Maybe
<bool>& res
) {
1436 // Steps 1 and 2 are performed by the caller.
1439 if (lhs
.isString() && rhs
.isString()) {
1440 JSString
* l
= lhs
.toString();
1441 JSString
* r
= rhs
.toString();
1443 if (!CompareStrings(cx
, l
, r
, &result
)) {
1446 res
= mozilla::Some(result
< 0);
1451 if (lhs
.isBigInt() && rhs
.isString()) {
1452 return BigInt::lessThan(cx
, lhs
, rhs
, res
);
1456 if (lhs
.isString() && rhs
.isBigInt()) {
1457 return BigInt::lessThan(cx
, lhs
, rhs
, res
);
1461 if (!ToNumeric(cx
, lhs
) || !ToNumeric(cx
, rhs
)) {
1466 if (lhs
.isBigInt() || rhs
.isBigInt()) {
1467 return BigInt::lessThan(cx
, lhs
, rhs
, res
);
1470 // Step 4e for Number operands.
1471 MOZ_ASSERT(lhs
.isNumber() && rhs
.isNumber());
1472 double lhsNum
= lhs
.toNumber();
1473 double rhsNum
= rhs
.toNumber();
1475 if (std::isnan(lhsNum
) || std::isnan(rhsNum
)) {
1476 res
= mozilla::Maybe
<bool>(mozilla::Nothing());
1480 res
= mozilla::Some(lhsNum
< rhsNum
);
1484 static MOZ_ALWAYS_INLINE
bool LessThanOperation(JSContext
* cx
,
1485 MutableHandleValue lhs
,
1486 MutableHandleValue rhs
,
1488 if (lhs
.isInt32() && rhs
.isInt32()) {
1489 *res
= lhs
.toInt32() < rhs
.toInt32();
1493 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1497 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1501 mozilla::Maybe
<bool> tmpResult
;
1502 if (!LessThanImpl(cx
, lhs
, rhs
, tmpResult
)) {
1505 *res
= tmpResult
.valueOr(false);
1509 static MOZ_ALWAYS_INLINE
bool LessThanOrEqualOperation(JSContext
* cx
,
1510 MutableHandleValue lhs
,
1511 MutableHandleValue rhs
,
1513 if (lhs
.isInt32() && rhs
.isInt32()) {
1514 *res
= lhs
.toInt32() <= rhs
.toInt32();
1518 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1522 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1526 mozilla::Maybe
<bool> tmpResult
;
1527 if (!LessThanImpl(cx
, rhs
, lhs
, tmpResult
)) {
1530 *res
= !tmpResult
.valueOr(true);
1534 static MOZ_ALWAYS_INLINE
bool GreaterThanOperation(JSContext
* cx
,
1535 MutableHandleValue lhs
,
1536 MutableHandleValue rhs
,
1538 if (lhs
.isInt32() && rhs
.isInt32()) {
1539 *res
= lhs
.toInt32() > rhs
.toInt32();
1543 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1547 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1551 mozilla::Maybe
<bool> tmpResult
;
1552 if (!LessThanImpl(cx
, rhs
, lhs
, tmpResult
)) {
1555 *res
= tmpResult
.valueOr(false);
1559 static MOZ_ALWAYS_INLINE
bool GreaterThanOrEqualOperation(
1560 JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
, bool* res
) {
1561 if (lhs
.isInt32() && rhs
.isInt32()) {
1562 *res
= lhs
.toInt32() >= rhs
.toInt32();
1566 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, lhs
)) {
1570 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, rhs
)) {
1574 mozilla::Maybe
<bool> tmpResult
;
1575 if (!LessThanImpl(cx
, lhs
, rhs
, tmpResult
)) {
1578 *res
= !tmpResult
.valueOr(true);
1582 static MOZ_ALWAYS_INLINE
bool SetObjectElementOperation(
1583 JSContext
* cx
, HandleObject obj
, HandleId id
, HandleValue value
,
1584 HandleValue receiver
, bool strict
) {
1585 ObjectOpResult result
;
1586 return SetProperty(cx
, obj
, id
, value
, receiver
, result
) &&
1587 result
.checkStrictModeError(cx
, obj
, id
, strict
);
1590 void js::ReportInNotObjectError(JSContext
* cx
, HandleValue lref
,
1592 auto uniqueCharsFromString
= [](JSContext
* cx
,
1593 HandleValue ref
) -> UniqueChars
{
1594 static const size_t MaxStringLength
= 16;
1595 RootedString
str(cx
, ref
.toString());
1596 if (str
->length() > MaxStringLength
) {
1597 JSStringBuilder
buf(cx
);
1598 if (!buf
.appendSubstring(str
, 0, MaxStringLength
)) {
1601 if (!buf
.append("...")) {
1604 str
= buf
.finishString();
1609 return QuoteString(cx
, str
, '"');
1612 if (lref
.isString() && rref
.isString()) {
1613 UniqueChars lbytes
= uniqueCharsFromString(cx
, lref
);
1617 UniqueChars rbytes
= uniqueCharsFromString(cx
, rref
);
1621 JS_ReportErrorNumberUTF8(cx
, GetErrorMessage
, nullptr, JSMSG_IN_STRING
,
1622 lbytes
.get(), rbytes
.get());
1626 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_IN_NOT_OBJECT
,
1627 InformalValueTypeName(rref
));
1630 bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER
js::Interpret(JSContext
* cx
,
1633 * Define macros for an interpreter loop. Opcode dispatch is done by
1634 * indirect goto (aka a threaded interpreter), which is technically
1635 * non-standard but is supported by all of our supported compilers.
1637 #define INTERPRETER_LOOP()
1638 #define CASE(OP) label_##OP:
1641 #define DISPATCH_TO(OP) goto* addresses[(OP)]
1643 #define LABEL(X) (&&label_##X)
1645 // Use addresses instead of offsets to optimize for runtime speed over
1646 // load-time relocation overhead.
1647 static const void* const addresses
[EnableInterruptsPseudoOpcode
+ 1] = {
1648 #define OPCODE_LABEL(op, ...) LABEL(op),
1649 FOR_EACH_OPCODE(OPCODE_LABEL
)
1651 #define TRAILING_LABEL(v) \
1652 ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
1654 FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL
)
1655 #undef TRAILING_LABEL
1659 * Increment REGS.pc by N, load the opcode at that position,
1660 * and jump to the code to execute it.
1662 * When Debugger puts a script in single-step mode, all js::Interpret
1663 * invocations that might be presently running that script must have
1664 * interrupts enabled. It's not practical to simply check
1665 * script->stepModeEnabled() at each point some callee could have changed
1666 * it, because there are so many places js::Interpret could possibly cause
1667 * JavaScript to run: each place an object might be coerced to a primitive
1668 * or a number, for example. So instead, we expose a simple mechanism to
1669 * let Debugger tweak the affected js::Interpret frames when an onStep
1670 * handler is added: calling activation.enableInterruptsUnconditionally()
1671 * will enable interrupts, and activation.opMask() is or'd with the opcode
1672 * to implement a simple alternate dispatch.
1674 #define ADVANCE_AND_DISPATCH(N) \
1678 DISPATCH_TO(*REGS.pc | activation.opMask()); \
1682 * Shorthand for the common sequence at the end of a fixed-size opcode.
1684 #define END_CASE(OP) ADVANCE_AND_DISPATCH(JSOpLength_##OP);
1687 * Prepare to call a user-supplied branch handler, and abort the script
1688 * if it returns false.
1690 #define CHECK_BRANCH() \
1692 if (!CheckForInterrupt(cx)) goto error; \
1696 * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
1697 * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
1698 * is the backedge of a loop.
1702 int32_t nlen = (n); \
1703 if (nlen <= 0) CHECK_BRANCH(); \
1704 ADVANCE_AND_DISPATCH(nlen); \
1708 * Initialize code coverage vectors.
1710 #define INIT_COVERAGE() \
1712 if (!script->hasScriptCounts()) { \
1713 if (cx->realm()->collectCoverageForDebug()) { \
1714 if (!script->initScriptCounts(cx)) goto error; \
1720 * Increment the code coverage counter associated with the given pc.
1722 #define COUNT_COVERAGE_PC(PC) \
1724 if (script->hasScriptCounts()) { \
1725 PCCounts* counts = script->maybeGetPCCounts(PC); \
1726 MOZ_ASSERT(counts); \
1727 counts->numExec()++; \
1731 #define COUNT_COVERAGE_MAIN() \
1733 jsbytecode* main = script->main(); \
1734 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
1737 #define COUNT_COVERAGE() \
1739 MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
1740 COUNT_COVERAGE_PC(REGS.pc); \
1743 #define SET_SCRIPT(s) \
1746 MOZ_ASSERT(cx->realm() == script->realm()); \
1747 if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
1748 script->hasScriptCounts()) \
1749 activation.enableInterruptsUnconditionally(); \
1752 #define SANITY_CHECKS() \
1754 js::gc::MaybeVerifyBarriers(cx); \
1757 // Verify that an uninitialized lexical is followed by a correct check op.
1759 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
1761 if (IsUninitializedLexical(val)) { \
1762 JSOp next = JSOp(*GetNextPc(REGS.pc)); \
1763 MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn || \
1764 next == JSOp::CheckThisReinit || \
1765 next == JSOp::CheckAliasedLexical); \
1769 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
1775 gc::MaybeVerifyBarriers(cx
, true);
1777 InterpreterFrame
* entryFrame
= state
.pushInterpreterFrame(cx
);
1782 ActivationEntryMonitor
entryMonitor(cx
, entryFrame
);
1783 InterpreterActivation
activation(state
, cx
, entryFrame
);
1785 /* The script is used frequently, so keep a local copy. */
1786 RootedScript
script(cx
);
1787 SET_SCRIPT(REGS
.fp()->script());
1790 * Pool of rooters for use in this interpreter frame. References to these
1791 * are used for local variables within interpreter cases. This avoids
1792 * creating new rooters each time an interpreter case is entered, and also
1793 * correctness pitfalls due to incorrect compilation of destructor calls
1794 * around computed gotos.
1796 RootedValue
rootValue0(cx
), rootValue1(cx
);
1797 RootedObject
rootObject0(cx
), rootObject1(cx
);
1798 RootedFunction
rootFunction0(cx
);
1799 Rooted
<JSAtom
*> rootAtom0(cx
);
1800 Rooted
<PropertyName
*> rootName0(cx
);
1801 RootedId
rootId0(cx
);
1802 RootedScript
rootScript0(cx
);
1803 Rooted
<Scope
*> rootScope0(cx
);
1804 DebugOnly
<uint32_t> blockDepth
;
1806 /* State communicated between non-local jumps: */
1807 bool interpReturnOK
;
1808 bool frameHalfInitialized
;
1810 if (!activation
.entryFrame()->prologue(cx
)) {
1811 goto prologue_error
;
1814 if (!DebugAPI::onEnterFrame(cx
, activation
.entryFrame())) {
1818 // Increment the coverage for the main entry point.
1820 COUNT_COVERAGE_MAIN();
1822 // Enter the interpreter loop starting at the current pc.
1823 ADVANCE_AND_DISPATCH(0);
1825 INTERPRETER_LOOP() {
1826 CASE(EnableInterruptsPseudoOpcode
) {
1827 bool moreInterrupts
= false;
1828 jsbytecode op
= *REGS
.pc
;
1830 if (!script
->hasScriptCounts() &&
1831 cx
->realm()->collectCoverageForDebug()) {
1832 if (!script
->initScriptCounts(cx
)) {
1837 if (script
->isDebuggee()) {
1838 if (DebugAPI::stepModeEnabled(script
)) {
1839 if (!DebugAPI::onSingleStep(cx
)) {
1842 moreInterrupts
= true;
1845 if (DebugAPI::hasAnyBreakpointsOrStepMode(script
)) {
1846 moreInterrupts
= true;
1849 if (DebugAPI::hasBreakpointsAt(script
, REGS
.pc
)) {
1850 if (!DebugAPI::onTrap(cx
)) {
1856 MOZ_ASSERT(activation
.opMask() == EnableInterruptsPseudoOpcode
);
1857 if (!moreInterrupts
) {
1858 activation
.clearInterruptsMask();
1861 /* Commence executing the actual opcode. */
1866 /* Various 1-byte no-ops. */
1869 CASE(NopDestructuring
)
1871 CASE(TryDestructuring
) {
1872 MOZ_ASSERT(GetBytecodeLength(REGS
.pc
) == 1);
1873 ADVANCE_AND_DISPATCH(1);
1878 END_CASE(JumpTarget
)
1883 // Attempt on-stack replacement into the Baseline Interpreter.
1884 if (jit::IsBaselineInterpreterEnabled()) {
1885 script
->incWarmUpCounter();
1887 jit::MethodStatus status
=
1888 jit::CanEnterBaselineInterpreterAtBranch(cx
, REGS
.fp());
1889 if (status
== jit::Method_Error
) {
1892 if (status
== jit::Method_Compiled
) {
1893 bool wasProfiler
= REGS
.fp()->hasPushedGeckoProfilerFrame();
1895 jit::JitExecStatus maybeOsr
;
1897 GeckoProfilerBaselineOSRMarker
osr(cx
, wasProfiler
);
1899 jit::EnterBaselineInterpreterAtBranch(cx
, REGS
.fp(), REGS
.pc
);
1902 // We failed to call into baseline at all, so treat as an error.
1903 if (maybeOsr
== jit::JitExec_Aborted
) {
1907 interpReturnOK
= (maybeOsr
== jit::JitExec_Ok
);
1909 // Pop the profiler frame pushed by the interpreter. (The compiled
1910 // version of the function popped a copy of the frame pushed by the
1913 cx
->geckoProfiler().exit(cx
, script
);
1916 if (activation
.entryFrame() != REGS
.fp()) {
1917 goto jit_return_pop_frame
;
1919 goto leave_on_safe_point
;
1928 CASE(ForceInterpreter
) {
1929 // Ensure pattern matching still works.
1930 MOZ_ASSERT(script
->hasForceInterpreterOp());
1932 END_CASE(ForceInterpreter
)
1934 CASE(Undefined
) { PUSH_UNDEFINED(); }
1937 CASE(Pop
) { REGS
.sp
--; }
1941 MOZ_ASSERT(GET_UINT16(REGS
.pc
) <= REGS
.stackDepth());
1942 REGS
.sp
-= GET_UINT16(REGS
.pc
);
1947 MOZ_ASSERT(GET_UINT24(REGS
.pc
) < REGS
.stackDepth());
1948 unsigned i
= GET_UINT24(REGS
.pc
);
1949 const Value
& rref
= REGS
.sp
[-int(i
+ 1)];
1954 CASE(SetRval
) { POP_RETURN_VALUE(); }
1957 CASE(GetRval
) { PUSH_COPY(REGS
.fp()->returnValue()); }
1961 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
1963 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
1965 if (!EnterWithOperation(cx
, REGS
.fp(), val
, scope
.as
<WithScope
>())) {
1972 REGS
.fp()->popOffEnvironmentChain
<WithEnvironmentObject
>();
1982 * When the inlined frame exits with an exception or an error, ok will be
1983 * false after the inline_return label.
1987 successful_return_continuation
:
1988 interpReturnOK
= true;
1990 return_continuation
:
1991 frameHalfInitialized
= false;
1993 prologue_return_continuation
:
1995 if (activation
.entryFrame() != REGS
.fp()) {
1996 // Stop the engine. (No details about which engine exactly, could be
1997 // interpreter, Baseline or IonMonkey.)
1998 if (MOZ_LIKELY(!frameHalfInitialized
)) {
2000 DebugAPI::onLeaveFrame(cx
, REGS
.fp(), REGS
.pc
, interpReturnOK
);
2002 REGS
.fp()->epilogue(cx
, REGS
.pc
);
2005 jit_return_pop_frame
:
2007 activation
.popInlineFrame(REGS
.fp());
2009 JSScript
* callerScript
= REGS
.fp()->script();
2010 if (cx
->realm() != callerScript
->realm()) {
2011 cx
->leaveRealm(callerScript
->realm());
2013 SET_SCRIPT(callerScript
);
2018 MOZ_ASSERT(IsInvokePC(REGS
.pc
));
2019 MOZ_ASSERT(cx
->realm() == script
->realm());
2021 /* Resume execution in the calling frame. */
2022 if (MOZ_LIKELY(interpReturnOK
)) {
2023 if (JSOp(*REGS
.pc
) == JSOp::Resume
) {
2024 ADVANCE_AND_DISPATCH(JSOpLength_Resume
);
2027 MOZ_ASSERT(GetBytecodeLength(REGS
.pc
) == JSOpLength_Call
);
2028 ADVANCE_AND_DISPATCH(JSOpLength_Call
);
2033 // Stack should be empty for the outer frame, unless we executed the
2034 // first |await| expression in an async function.
2035 MOZ_ASSERT(REGS
.stackDepth() == 0 ||
2036 (JSOp(*REGS
.pc
) == JSOp::Await
&&
2037 !REGS
.fp()->isResumedGenerator()));
2046 CASE(Goto
) { BRANCH(GET_JUMP_OFFSET(REGS
.pc
)); }
2049 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2052 BRANCH(GET_JUMP_OFFSET(REGS
.pc
));
2055 END_CASE(JumpIfFalse
)
2058 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2061 BRANCH(GET_JUMP_OFFSET(REGS
.pc
));
2064 END_CASE(JumpIfTrue
)
2067 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2069 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS
.pc
));
2075 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2076 bool cond
= !res
.isNullOrUndefined();
2078 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS
.pc
));
2084 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2086 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS
.pc
));
2091 #define FETCH_ELEMENT_ID(n, id) \
2093 if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
2096 #define TRY_BRANCH_AFTER_COND(cond, spdec) \
2098 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1); \
2100 (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
2102 REGS.sp -= (spdec); \
2103 if ((cond) == (diff_ != 0)) { \
2105 BRANCH(GET_JUMP_OFFSET(REGS.pc)); \
2107 ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse); \
2112 HandleValue rref
= REGS
.stackHandleAt(-1);
2113 if (!rref
.isObject()) {
2114 HandleValue lref
= REGS
.stackHandleAt(-2);
2115 ReportInNotObjectError(cx
, lref
, rref
);
2120 ReservedRooted
<JSObject
*> obj(&rootObject0
, &rref
.toObject());
2121 ReservedRooted
<jsid
> id(&rootId0
);
2122 FETCH_ELEMENT_ID(-2, id
);
2123 if (!HasProperty(cx
, obj
, id
, &found
)) {
2127 TRY_BRANCH_AFTER_COND(found
, 2);
2129 REGS
.sp
[-1].setBoolean(found
);
2134 HandleValue val
= REGS
.stackHandleAt(-1);
2135 HandleValue idval
= REGS
.stackHandleAt(-2);
2138 if (!HasOwnProperty(cx
, val
, idval
, &found
)) {
2143 REGS
.sp
[-1].setBoolean(found
);
2147 CASE(CheckPrivateField
) {
2148 /* Load the object being initialized into lval/val. */
2149 HandleValue val
= REGS
.stackHandleAt(-2);
2150 HandleValue idval
= REGS
.stackHandleAt(-1);
2152 bool result
= false;
2153 if (!CheckPrivateFieldOperation(cx
, REGS
.pc
, val
, idval
, &result
)) {
2157 PUSH_BOOLEAN(result
);
2159 END_CASE(CheckPrivateField
)
2161 CASE(NewPrivateName
) {
2162 ReservedRooted
<JSAtom
*> name(&rootAtom0
, script
->getAtom(REGS
.pc
));
2164 auto* symbol
= NewPrivateName(cx
, name
);
2169 PUSH_SYMBOL(symbol
);
2171 END_CASE(NewPrivateName
)
2173 CASE(IsNullOrUndefined
) {
2174 bool b
= REGS
.sp
[-1].isNullOrUndefined();
2177 END_CASE(IsNullOrUndefined
)
2180 MOZ_ASSERT(REGS
.stackDepth() >= 1);
2181 HandleValue val
= REGS
.stackHandleAt(-1);
2182 JSObject
* iter
= ValueToIterator(cx
, val
);
2186 REGS
.sp
[-1].setObject(*iter
);
2191 MOZ_ASSERT(REGS
.stackDepth() >= 1);
2192 MOZ_ASSERT(REGS
.sp
[-1].isObject());
2193 Value v
= IteratorMore(®S
.sp
[-1].toObject());
2199 bool b
= REGS
.sp
[-1].isMagic(JS_NO_ITER_VALUE
);
2205 MOZ_ASSERT(REGS
.stackDepth() >= 2);
2206 CloseIterator(®S
.sp
[-2].toObject());
2212 ReservedRooted
<JSObject
*> iter(&rootObject0
, ®S
.sp
[-1].toObject());
2213 CompletionKind kind
= CompletionKind(GET_UINT8(REGS
.pc
));
2214 if (!CloseIterOperation(cx
, iter
, kind
)) {
2221 CASE(OptimizeGetIterator
) {
2222 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
2223 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2225 if (!OptimizeGetIterator(cx
, val
, &result
)) {
2228 rval
.setBoolean(result
);
2230 END_CASE(OptimizeGetIterator
)
2232 CASE(IsGenClosing
) {
2233 bool b
= REGS
.sp
[-1].isMagic(JS_GENERATOR_CLOSING
);
2236 END_CASE(IsGenClosing
)
2239 MOZ_ASSERT(REGS
.stackDepth() >= 1);
2240 const Value
& rref
= REGS
.sp
[-1];
2246 MOZ_ASSERT(REGS
.stackDepth() >= 2);
2247 const Value
& lref
= REGS
.sp
[-2];
2248 const Value
& rref
= REGS
.sp
[-1];
2255 MOZ_ASSERT(REGS
.stackDepth() >= 2);
2256 Value
& lref
= REGS
.sp
[-2];
2257 Value
& rref
= REGS
.sp
[-1];
2263 unsigned i
= GET_UINT8(REGS
.pc
);
2264 MOZ_ASSERT(REGS
.stackDepth() >= i
+ 1);
2265 Value lval
= REGS
.sp
[-int(i
+ 1)];
2266 memmove(REGS
.sp
- (i
+ 1), REGS
.sp
- i
, sizeof(Value
) * i
);
2272 int i
= GET_UINT8(REGS
.pc
);
2273 MOZ_ASSERT(REGS
.stackDepth() >= unsigned(i
) + 1);
2274 Value lval
= REGS
.sp
[-1];
2275 memmove(REGS
.sp
- i
, REGS
.sp
- (i
+ 1), sizeof(Value
) * i
);
2276 REGS
.sp
[-(i
+ 1)] = lval
;
2282 JSOp op
= JSOp(*REGS
.pc
);
2283 ReservedRooted
<JSObject
*> envChain(&rootObject0
);
2284 if (op
== JSOp::BindName
) {
2285 envChain
.set(REGS
.fp()->environmentChain());
2287 MOZ_ASSERT(!script
->hasNonSyntacticScope());
2288 envChain
.set(®S
.fp()->global().lexicalEnvironment());
2290 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2292 // Assigning to an undeclared name adds a property to the global object.
2293 ReservedRooted
<JSObject
*> env(&rootObject1
);
2294 if (!LookupNameUnqualified(cx
, name
, envChain
, &env
)) {
2300 static_assert(JSOpLength_BindName
== JSOpLength_BindGName
,
2301 "We're sharing the END_CASE so the lengths better match");
2306 JSObject
* varObj
= BindVarOperation(cx
, REGS
.fp()->environmentChain());
2307 PUSH_OBJECT(*varObj
);
2312 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2313 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2314 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2315 if (!BitOrOperation(cx
, lhs
, rhs
, res
)) {
2323 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2324 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2325 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2326 if (!BitXorOperation(cx
, lhs
, rhs
, res
)) {
2334 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2335 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2336 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2337 if (!BitAndOperation(cx
, lhs
, rhs
, res
)) {
2345 if (!LooseEqualityOp
<true>(cx
, REGS
)) {
2352 if (!LooseEqualityOp
<false>(cx
, REGS
)) {
2358 #define STRICT_EQUALITY_OP(OP, COND) \
2360 HandleValue lval = REGS.stackHandleAt(-2); \
2361 HandleValue rval = REGS.stackHandleAt(-1); \
2363 if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
2366 (COND) = equal OP true; \
2372 STRICT_EQUALITY_OP(==, cond
);
2373 REGS
.sp
[-1].setBoolean(cond
);
2379 STRICT_EQUALITY_OP(!=, cond
);
2380 REGS
.sp
[-1].setBoolean(cond
);
2384 #undef STRICT_EQUALITY_OP
2387 bool cond
= REGS
.sp
[-1].toBoolean();
2391 BRANCH(GET_JUMP_OFFSET(REGS
.pc
));
2398 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2399 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2400 if (!LessThanOperation(cx
, lval
, rval
, &cond
)) {
2403 TRY_BRANCH_AFTER_COND(cond
, 2);
2404 REGS
.sp
[-2].setBoolean(cond
);
2411 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2412 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2413 if (!LessThanOrEqualOperation(cx
, lval
, rval
, &cond
)) {
2416 TRY_BRANCH_AFTER_COND(cond
, 2);
2417 REGS
.sp
[-2].setBoolean(cond
);
2424 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2425 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2426 if (!GreaterThanOperation(cx
, lval
, rval
, &cond
)) {
2429 TRY_BRANCH_AFTER_COND(cond
, 2);
2430 REGS
.sp
[-2].setBoolean(cond
);
2437 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2438 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2439 if (!GreaterThanOrEqualOperation(cx
, lval
, rval
, &cond
)) {
2442 TRY_BRANCH_AFTER_COND(cond
, 2);
2443 REGS
.sp
[-2].setBoolean(cond
);
2449 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2450 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2451 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2452 if (!BitLshOperation(cx
, lhs
, rhs
, res
)) {
2460 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2461 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2462 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2463 if (!BitRshOperation(cx
, lhs
, rhs
, res
)) {
2471 MutableHandleValue lhs
= REGS
.stackHandleAt(-2);
2472 MutableHandleValue rhs
= REGS
.stackHandleAt(-1);
2473 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2474 if (!UrshOperation(cx
, lhs
, rhs
, res
)) {
2482 MutableHandleValue lval
= REGS
.stackHandleAt(-2);
2483 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2484 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2485 if (!AddOperation(cx
, lval
, rval
, res
)) {
2493 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2494 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2495 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2496 if (!SubOperation(cx
, &lval
, &rval
, res
)) {
2504 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2505 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2506 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2507 if (!MulOperation(cx
, &lval
, &rval
, res
)) {
2515 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2516 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2517 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2518 if (!DivOperation(cx
, &lval
, &rval
, res
)) {
2526 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2527 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2528 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2529 if (!ModOperation(cx
, &lval
, &rval
, res
)) {
2537 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-2]);
2538 ReservedRooted
<Value
> rval(&rootValue1
, REGS
.sp
[-1]);
2539 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2540 if (!PowOperation(cx
, &lval
, &rval
, res
)) {
2548 bool cond
= ToBoolean(REGS
.stackHandleAt(-1));
2550 PUSH_BOOLEAN(!cond
);
2555 MutableHandleValue val
= REGS
.stackHandleAt(-1);
2556 if (!BitNotOperation(cx
, val
, val
)) {
2563 MutableHandleValue val
= REGS
.stackHandleAt(-1);
2564 if (!NegOperation(cx
, val
, val
)) {
2571 if (!ToNumber(cx
, REGS
.stackHandleAt(-1))) {
2578 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2579 ReservedRooted
<JSObject
*> envObj(&rootObject0
,
2580 REGS
.fp()->environmentChain());
2583 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2584 if (!DeleteNameOperation(cx
, name
, envObj
, res
)) {
2591 CASE(StrictDelProp
) {
2592 static_assert(JSOpLength_DelProp
== JSOpLength_StrictDelProp
,
2593 "delprop and strictdelprop must be the same size");
2594 HandleValue val
= REGS
.stackHandleAt(-1);
2595 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2597 if (JSOp(*REGS
.pc
) == JSOp::StrictDelProp
) {
2598 if (!DelPropOperation
<true>(cx
, val
, name
, &res
)) {
2602 if (!DelPropOperation
<false>(cx
, val
, name
, &res
)) {
2606 REGS
.sp
[-1].setBoolean(res
);
2611 CASE(StrictDelElem
) {
2612 static_assert(JSOpLength_DelElem
== JSOpLength_StrictDelElem
,
2613 "delelem and strictdelelem must be the same size");
2614 HandleValue val
= REGS
.stackHandleAt(-2);
2615 HandleValue propval
= REGS
.stackHandleAt(-1);
2617 if (JSOp(*REGS
.pc
) == JSOp::StrictDelElem
) {
2618 if (!DelElemOperation
<true>(cx
, val
, propval
, &res
)) {
2622 if (!DelElemOperation
<false>(cx
, val
, propval
, &res
)) {
2626 REGS
.sp
[-2].setBoolean(res
);
2631 CASE(ToPropertyKey
) {
2632 ReservedRooted
<Value
> idval(&rootValue1
, REGS
.sp
[-1]);
2633 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2634 if (!ToPropertyKeyOperation(cx
, idval
, res
)) {
2638 END_CASE(ToPropertyKey
)
2642 REGS
.sp
[-1].setString(TypeOfOperation(REGS
.sp
[-1], cx
->runtime()));
2646 CASE(Void
) { REGS
.sp
[-1].setUndefined(); }
2649 CASE(FunctionThis
) {
2651 if (!GetFunctionThis(cx
, REGS
.fp(), REGS
.stackHandleAt(-1))) {
2655 END_CASE(FunctionThis
)
2658 MOZ_ASSERT(!script
->hasNonSyntacticScope());
2659 PUSH_OBJECT(*cx
->global()->lexicalEnvironment().thisObject());
2661 END_CASE(GlobalThis
)
2663 CASE(NonSyntacticGlobalThis
) {
2665 GetNonSyntacticGlobalThis(cx
, REGS
.fp()->environmentChain(),
2666 REGS
.stackHandleAt(-1));
2668 END_CASE(NonSyntacticGlobalThis
)
2671 if (!REGS
.sp
[-1].isObject()) {
2673 ThrowCheckIsObject(cx
, CheckIsObjectKind(GET_UINT8(REGS
.pc
))));
2677 END_CASE(CheckIsObj
)
2680 if (REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
2681 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx
));
2687 CASE(CheckThisReinit
) {
2688 if (!REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
2689 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx
));
2693 END_CASE(CheckThisReinit
)
2696 ReservedRooted
<Value
> thisv(&rootValue0
, REGS
.sp
[-1]);
2697 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2698 if (!REGS
.fp()->checkReturn(cx
, thisv
, rval
)) {
2702 END_CASE(CheckReturn
)
2705 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[-1]);
2706 MutableHandleValue res
= REGS
.stackHandleAt(-1);
2707 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2708 if (!GetPropertyOperation(cx
, name
, lval
, res
)) {
2711 cx
->debugOnlyCheck(res
);
2715 CASE(GetPropSuper
) {
2716 ReservedRooted
<Value
> receiver(&rootValue0
, REGS
.sp
[-2]);
2717 HandleValue lval
= REGS
.stackHandleAt(-1);
2718 MOZ_ASSERT(lval
.isObjectOrNull());
2719 MutableHandleValue rref
= REGS
.stackHandleAt(-2);
2720 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
2722 ReservedRooted
<JSObject
*> obj(&rootObject0
);
2723 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -1, name
);
2728 if (!GetProperty(cx
, obj
, receiver
, name
, rref
)) {
2732 cx
->debugOnlyCheck(rref
);
2736 END_CASE(GetPropSuper
)
2738 CASE(GetBoundName
) {
2739 ReservedRooted
<JSObject
*> env(&rootObject0
, ®S
.sp
[-1].toObject());
2740 ReservedRooted
<jsid
> id(&rootId0
, NameToId(script
->getName(REGS
.pc
)));
2741 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
2742 if (!GetNameBoundInEnvironment(cx
, env
, id
, rval
)) {
2745 cx
->debugOnlyCheck(rval
);
2747 END_CASE(GetBoundName
)
2749 CASE(SetIntrinsic
) {
2750 HandleValue value
= REGS
.stackHandleAt(-1);
2752 if (!SetIntrinsicOperation(cx
, script
, REGS
.pc
, value
)) {
2756 END_CASE(SetIntrinsic
)
2759 CASE(StrictSetGName
)
2761 CASE(StrictSetName
) {
2762 static_assert(JSOpLength_SetName
== JSOpLength_StrictSetName
,
2763 "setname and strictsetname must be the same size");
2764 static_assert(JSOpLength_SetGName
== JSOpLength_StrictSetGName
,
2765 "setgname and strictsetgname must be the same size");
2766 static_assert(JSOpLength_SetName
== JSOpLength_SetGName
,
2767 "We're sharing the END_CASE so the lengths better match");
2769 ReservedRooted
<JSObject
*> env(&rootObject0
, ®S
.sp
[-2].toObject());
2770 HandleValue value
= REGS
.stackHandleAt(-1);
2772 if (!SetNameOperation(cx
, script
, REGS
.pc
, env
, value
)) {
2776 REGS
.sp
[-2] = REGS
.sp
[-1];
2782 CASE(StrictSetProp
) {
2783 static_assert(JSOpLength_SetProp
== JSOpLength_StrictSetProp
,
2784 "setprop and strictsetprop must be the same size");
2786 HandleValue lval
= REGS
.stackHandleAt(lvalIndex
);
2787 HandleValue rval
= REGS
.stackHandleAt(-1);
2789 ReservedRooted
<jsid
> id(&rootId0
, NameToId(script
->getName(REGS
.pc
)));
2791 bool strict
= JSOp(*REGS
.pc
) == JSOp::StrictSetProp
;
2793 ReservedRooted
<JSObject
*> obj(&rootObject0
);
2794 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, lvalIndex
, id
);
2799 if (!SetObjectElementOperation(cx
, obj
, id
, rval
, lval
, strict
)) {
2803 REGS
.sp
[-2] = REGS
.sp
[-1];
2809 CASE(StrictSetPropSuper
) {
2811 JSOpLength_SetPropSuper
== JSOpLength_StrictSetPropSuper
,
2812 "setprop-super and strictsetprop-super must be the same size");
2814 HandleValue receiver
= REGS
.stackHandleAt(-3);
2815 HandleValue lval
= REGS
.stackHandleAt(-2);
2816 MOZ_ASSERT(lval
.isObjectOrNull());
2817 HandleValue rval
= REGS
.stackHandleAt(-1);
2818 ReservedRooted
<jsid
> id(&rootId0
, NameToId(script
->getName(REGS
.pc
)));
2820 bool strict
= JSOp(*REGS
.pc
) == JSOp::StrictSetPropSuper
;
2822 ReservedRooted
<JSObject
*> obj(&rootObject0
);
2823 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -2, id
);
2828 if (!SetObjectElementOperation(cx
, obj
, id
, rval
, receiver
, strict
)) {
2832 REGS
.sp
[-3] = REGS
.sp
[-1];
2835 END_CASE(SetPropSuper
)
2839 ReservedRooted
<Value
> lval(&rootValue0
, REGS
.sp
[lvalIndex
]);
2840 HandleValue rval
= REGS
.stackHandleAt(-1);
2841 MutableHandleValue res
= REGS
.stackHandleAt(-2);
2843 if (!GetElementOperationWithStackIndex(cx
, lval
, lvalIndex
, rval
, res
)) {
2851 CASE(GetElemSuper
) {
2852 ReservedRooted
<Value
> receiver(&rootValue0
, REGS
.sp
[-3]);
2853 HandleValue index
= REGS
.stackHandleAt(-2);
2854 HandleValue lval
= REGS
.stackHandleAt(-1);
2855 MOZ_ASSERT(lval
.isObjectOrNull());
2857 MutableHandleValue res
= REGS
.stackHandleAt(-3);
2859 ReservedRooted
<JSObject
*> obj(&rootObject0
);
2860 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -1, index
);
2865 if (!GetObjectElementOperation(cx
, JSOp(*REGS
.pc
), obj
, receiver
, index
,
2872 END_CASE(GetElemSuper
)
2875 CASE(StrictSetElem
) {
2876 static_assert(JSOpLength_SetElem
== JSOpLength_StrictSetElem
,
2877 "setelem and strictsetelem must be the same size");
2878 int receiverIndex
= -3;
2879 HandleValue receiver
= REGS
.stackHandleAt(receiverIndex
);
2880 HandleValue value
= REGS
.stackHandleAt(-1);
2882 ReservedRooted
<JSObject
*> obj(&rootObject0
);
2883 obj
= ToObjectFromStackForPropertyAccess(cx
, receiver
, receiverIndex
,
2884 REGS
.stackHandleAt(-2));
2889 ReservedRooted
<jsid
> id(&rootId0
);
2890 FETCH_ELEMENT_ID(-2, id
);
2892 if (!SetObjectElementOperation(cx
, obj
, id
, value
, receiver
,
2893 JSOp(*REGS
.pc
) == JSOp::StrictSetElem
)) {
2896 REGS
.sp
[-3] = value
;
2902 CASE(StrictSetElemSuper
) {
2904 JSOpLength_SetElemSuper
== JSOpLength_StrictSetElemSuper
,
2905 "setelem-super and strictsetelem-super must be the same size");
2907 HandleValue receiver
= REGS
.stackHandleAt(-4);
2908 HandleValue lval
= REGS
.stackHandleAt(-2);
2909 MOZ_ASSERT(lval
.isObjectOrNull());
2910 HandleValue value
= REGS
.stackHandleAt(-1);
2912 ReservedRooted
<JSObject
*> obj(&rootObject0
);
2913 obj
= ToObjectFromStackForPropertyAccess(cx
, lval
, -2,
2914 REGS
.stackHandleAt(-3));
2919 ReservedRooted
<jsid
> id(&rootId0
);
2920 FETCH_ELEMENT_ID(-3, id
);
2922 bool strict
= JSOp(*REGS
.pc
) == JSOp::StrictSetElemSuper
;
2923 if (!SetObjectElementOperation(cx
, obj
, id
, value
, receiver
, strict
)) {
2926 REGS
.sp
[-4] = value
;
2929 END_CASE(SetElemSuper
)
2933 static_assert(JSOpLength_Eval
== JSOpLength_StrictEval
,
2934 "eval and stricteval must be the same size");
2936 CallArgs args
= CallArgsFromSp(GET_ARGC(REGS
.pc
), REGS
.sp
);
2937 if (cx
->global()->valueIsEval(args
.calleev())) {
2938 if (!DirectEval(cx
, args
.get(0), args
.rval())) {
2942 if (!CallFromStack(cx
, args
, CallReason::Call
)) {
2947 REGS
.sp
= args
.spAfterCall();
2953 CASE(SpreadSuperCall
) {
2954 if (REGS
.fp()->hasPushedGeckoProfilerFrame()) {
2955 cx
->geckoProfiler().updatePC(cx
, script
, REGS
.pc
);
2961 CASE(StrictSpreadEval
) {
2962 static_assert(JSOpLength_SpreadEval
== JSOpLength_StrictSpreadEval
,
2963 "spreadeval and strictspreadeval must be the same size");
2964 bool construct
= JSOp(*REGS
.pc
) == JSOp::SpreadNew
||
2965 JSOp(*REGS
.pc
) == JSOp::SpreadSuperCall
;
2967 MOZ_ASSERT(REGS
.stackDepth() >= 3u + construct
);
2969 HandleValue callee
= REGS
.stackHandleAt(-3 - construct
);
2970 HandleValue thisv
= REGS
.stackHandleAt(-2 - construct
);
2971 HandleValue arr
= REGS
.stackHandleAt(-1 - construct
);
2972 MutableHandleValue ret
= REGS
.stackHandleAt(-3 - construct
);
2974 RootedValue
& newTarget
= rootValue0
;
2976 newTarget
= REGS
.sp
[-1];
2978 newTarget
= NullValue();
2981 if (!SpreadCallOperation(cx
, script
, REGS
.pc
, thisv
, callee
, arr
,
2986 REGS
.sp
-= 2 + construct
;
2988 END_CASE(SpreadCall
)
2996 CASE(CallContentIter
)
2998 static_assert(JSOpLength_Call
== JSOpLength_New
,
2999 "call and new must be the same size");
3000 static_assert(JSOpLength_Call
== JSOpLength_CallContent
,
3001 "call and call-content must be the same size");
3002 static_assert(JSOpLength_Call
== JSOpLength_CallIgnoresRv
,
3003 "call and call-ignores-rv must be the same size");
3004 static_assert(JSOpLength_Call
== JSOpLength_CallIter
,
3005 "call and calliter must be the same size");
3006 static_assert(JSOpLength_Call
== JSOpLength_CallContentIter
,
3007 "call and call-content-iter must be the same size");
3008 static_assert(JSOpLength_Call
== JSOpLength_SuperCall
,
3009 "call and supercall must be the same size");
3011 if (REGS
.fp()->hasPushedGeckoProfilerFrame()) {
3012 cx
->geckoProfiler().updatePC(cx
, script
, REGS
.pc
);
3015 JSOp op
= JSOp(*REGS
.pc
);
3016 MaybeConstruct construct
= MaybeConstruct(
3017 op
== JSOp::New
|| op
== JSOp::NewContent
|| op
== JSOp::SuperCall
);
3018 bool ignoresReturnValue
= op
== JSOp::CallIgnoresRv
;
3019 unsigned argStackSlots
= GET_ARGC(REGS
.pc
) + construct
;
3021 MOZ_ASSERT(REGS
.stackDepth() >= 2u + GET_ARGC(REGS
.pc
));
3023 CallArgsFromSp(argStackSlots
, REGS
.sp
, construct
, ignoresReturnValue
);
3025 JSFunction
* maybeFun
;
3026 bool isFunction
= IsFunctionObject(args
.calleev(), &maybeFun
);
3028 // Use the slow path if the callee is not an interpreted function, if we
3029 // have to throw an exception, or if we might have to invoke the
3030 // OnNativeCall hook for a self-hosted builtin.
3031 if (!isFunction
|| !maybeFun
->isInterpreted() ||
3032 (construct
&& !maybeFun
->isConstructor()) ||
3033 (!construct
&& maybeFun
->isClassConstructor()) ||
3034 cx
->insideDebuggerEvaluationWithOnNativeCallHook
) {
3036 CallReason reason
= op
== JSOp::NewContent
? CallReason::CallContent
3038 if (!ConstructFromStack(cx
, args
, reason
)) {
3042 if ((op
== JSOp::CallIter
|| op
== JSOp::CallContentIter
) &&
3043 args
.calleev().isPrimitive()) {
3044 MOZ_ASSERT(args
.length() == 0, "thisv must be on top of the stack");
3045 ReportValueError(cx
, JSMSG_NOT_ITERABLE
, -1, args
.thisv(), nullptr);
3050 (op
== JSOp::CallContent
|| op
== JSOp::CallContentIter
)
3051 ? CallReason::CallContent
3053 if (!CallFromStack(cx
, args
, reason
)) {
3057 Value
* newsp
= args
.spAfterCall();
3059 ADVANCE_AND_DISPATCH(JSOpLength_Call
);
3063 MOZ_ASSERT(maybeFun
);
3064 ReservedRooted
<JSFunction
*> fun(&rootFunction0
, maybeFun
);
3065 ReservedRooted
<JSScript
*> funScript(
3066 &rootScript0
, JSFunction::getOrCreateScript(cx
, fun
));
3071 // Enter the callee's realm if this is a cross-realm call. Use
3072 // MakeScopeExit to leave this realm on all error/JIT-return paths
3074 const bool isCrossRealm
= cx
->realm() != funScript
->realm();
3076 cx
->enterRealmOf(funScript
);
3078 auto leaveRealmGuard
=
3079 mozilla::MakeScopeExit([isCrossRealm
, cx
, &script
] {
3081 cx
->leaveRealm(script
->realm());
3085 if (construct
&& !MaybeCreateThisForConstructor(cx
, args
)) {
3090 InvokeState
state(cx
, args
, construct
);
3092 jit::EnterJitStatus status
= jit::MaybeEnterJit(cx
, state
);
3094 case jit::EnterJitStatus::Error
:
3096 case jit::EnterJitStatus::Ok
:
3097 interpReturnOK
= true;
3099 REGS
.sp
= args
.spAfterCall();
3101 case jit::EnterJitStatus::NotEntered
:
3105 #ifdef NIGHTLY_BUILD
3106 // If entry trampolines are enabled, call back into
3107 // MaybeEnterInterpreterTrampoline so we can generate an
3108 // entry trampoline for the new frame.
3109 if (jit::JitOptions
.emitInterpreterEntryTrampoline
) {
3110 if (MaybeEnterInterpreterTrampoline(cx
, state
)) {
3111 interpReturnOK
= true;
3113 REGS
.sp
= args
.spAfterCall();
3121 funScript
= fun
->nonLazyScript();
3123 if (!activation
.pushInlineFrame(args
, funScript
, construct
)) {
3126 leaveRealmGuard
.release(); // We leave the callee's realm when we
3127 // call popInlineFrame.
3130 SET_SCRIPT(REGS
.fp()->script());
3132 if (!REGS
.fp()->prologue(cx
)) {
3133 goto prologue_error
;
3136 if (!DebugAPI::onEnterFrame(cx
, REGS
.fp())) {
3140 // Increment the coverage for the main entry point.
3142 COUNT_COVERAGE_MAIN();
3144 /* Load first op and dispatch it (safe since JSOp::RetRval). */
3145 ADVANCE_AND_DISPATCH(0);
3148 CASE(OptimizeSpreadCall
) {
3149 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
3150 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
3152 if (!OptimizeSpreadCall(cx
, val
, rval
)) {
3156 END_CASE(OptimizeSpreadCall
)
3159 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx
, GET_UINT8(REGS
.pc
)));
3164 CASE(ImplicitThis
) {
3165 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3166 ReservedRooted
<JSObject
*> envObj(&rootObject0
,
3167 REGS
.fp()->environmentChain());
3168 ReservedRooted
<JSObject
*> env(&rootObject1
);
3169 if (!LookupNameWithGlobalDefault(cx
, name
, envObj
, &env
)) {
3173 Value v
= ComputeImplicitThis(env
);
3176 END_CASE(ImplicitThis
)
3179 ReservedRooted
<Value
> rval(&rootValue0
);
3180 ReservedRooted
<JSObject
*> env(&rootObject0
,
3181 &cx
->global()->lexicalEnvironment());
3182 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3183 MOZ_ASSERT(!script
->hasNonSyntacticScope());
3184 if (!GetNameOperation(cx
, env
, name
, JSOp(REGS
.pc
[JSOpLength_GetGName
]),
3194 ReservedRooted
<Value
> rval(&rootValue0
);
3195 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3196 if (!GetNameOperation(cx
, REGS
.fp()->environmentChain(), name
,
3197 JSOp(REGS
.pc
[JSOpLength_GetName
]), &rval
)) {
3207 MutableHandleValue rval
= REGS
.stackHandleAt(-1);
3208 HandleObject envChain
= REGS
.fp()->environmentChain();
3209 if (!GetImportOperation(cx
, envChain
, script
, REGS
.pc
, rval
)) {
3215 CASE(GetIntrinsic
) {
3216 ReservedRooted
<Value
> rval(&rootValue0
);
3217 if (!GetIntrinsicOperation(cx
, script
, REGS
.pc
, &rval
)) {
3223 END_CASE(GetIntrinsic
)
3225 CASE(Uint16
) { PUSH_INT32((int32_t)GET_UINT16(REGS
.pc
)); }
3228 CASE(Uint24
) { PUSH_INT32((int32_t)GET_UINT24(REGS
.pc
)); }
3231 CASE(Int8
) { PUSH_INT32(GET_INT8(REGS
.pc
)); }
3234 CASE(Int32
) { PUSH_INT32(GET_INT32(REGS
.pc
)); }
3237 CASE(Double
) { PUSH_COPY(GET_INLINE_VALUE(REGS
.pc
)); }
3240 CASE(String
) { PUSH_STRING(script
->getString(REGS
.pc
)); }
3244 MutableHandleValue oper
= REGS
.stackHandleAt(-1);
3246 if (!oper
.isString()) {
3247 JSString
* operString
= ToString
<CanGC
>(cx
, oper
);
3251 oper
.setString(operString
);
3257 PUSH_SYMBOL(cx
->wellKnownSymbols().get(GET_UINT8(REGS
.pc
)));
3262 MOZ_ASSERT(script
->treatAsRunOnce());
3263 PUSH_OBJECT(*script
->getObject(REGS
.pc
));
3268 JSObject
* cso
= script
->getObject(REGS
.pc
);
3269 MOZ_ASSERT(!cso
->as
<ArrayObject
>().isExtensible());
3270 MOZ_ASSERT(cso
->as
<ArrayObject
>().containsPure(cx
->names().raw
));
3273 END_CASE(CallSiteObj
)
3277 * Push a regexp object cloned from the regexp literal object mapped by
3278 * the bytecode at pc.
3280 ReservedRooted
<JSObject
*> re(&rootObject0
, script
->getRegExp(REGS
.pc
));
3281 JSObject
* obj
= CloneRegExpObject(cx
, re
.as
<RegExpObject
>());
3289 CASE(Zero
) { PUSH_INT32(0); }
3292 CASE(One
) { PUSH_INT32(1); }
3295 CASE(Null
) { PUSH_NULL(); }
3298 CASE(False
) { PUSH_BOOLEAN(false); }
3301 CASE(True
) { PUSH_BOOLEAN(true); }
3305 jsbytecode
* pc2
= REGS
.pc
;
3306 int32_t len
= GET_JUMP_OFFSET(pc2
);
3309 * ECMAv2+ forbids conversion of discriminant, so we will skip to the
3310 * default case if the discriminant isn't already an int jsval. (This
3311 * opcode is emitted only for dense int-domain switches.)
3313 const Value
& rref
= *--REGS
.sp
;
3315 if (rref
.isInt32()) {
3318 /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
3319 if (!rref
.isDouble() || !NumberEqualsInt32(rref
.toDouble(), &i
)) {
3320 ADVANCE_AND_DISPATCH(len
);
3324 pc2
+= JUMP_OFFSET_LEN
;
3325 int32_t low
= GET_JUMP_OFFSET(pc2
);
3326 pc2
+= JUMP_OFFSET_LEN
;
3327 int32_t high
= GET_JUMP_OFFSET(pc2
);
3329 i
= uint32_t(i
) - uint32_t(low
);
3330 if (uint32_t(i
) < uint32_t(high
- low
+ 1)) {
3331 len
= script
->tableSwitchCaseOffset(REGS
.pc
, uint32_t(i
)) -
3332 script
->pcToOffset(REGS
.pc
);
3334 ADVANCE_AND_DISPATCH(len
);
3338 MOZ_ASSERT(script
->needsArgsObj());
3339 ArgumentsObject
* obj
= ArgumentsObject::createExpected(cx
, REGS
.fp());
3343 PUSH_COPY(ObjectValue(*obj
));
3348 ReservedRooted
<JSObject
*> rest(&rootObject0
,
3349 REGS
.fp()->createRestParameter(cx
));
3353 PUSH_COPY(ObjectValue(*rest
));
3357 CASE(GetAliasedVar
) {
3358 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3359 ReservedRooted
<Value
> val(
3360 &rootValue0
, REGS
.fp()->aliasedEnvironment(ec
).aliasedBinding(ec
));
3362 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val
);
3366 END_CASE(GetAliasedVar
)
3368 CASE(GetAliasedDebugVar
) {
3369 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3370 ReservedRooted
<Value
> val(
3372 REGS
.fp()->aliasedEnvironmentMaybeDebug(ec
).aliasedBinding(ec
));
3374 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val
);
3378 END_CASE(GetAliasedVar
)
3380 CASE(SetAliasedVar
) {
3381 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3382 EnvironmentObject
& obj
= REGS
.fp()->aliasedEnvironment(ec
);
3383 MOZ_ASSERT(!IsUninitializedLexical(obj
.aliasedBinding(ec
)));
3384 obj
.setAliasedBinding(ec
, REGS
.sp
[-1]);
3386 END_CASE(SetAliasedVar
)
3388 CASE(ThrowSetConst
) {
3389 ReportRuntimeLexicalError(cx
, JSMSG_BAD_CONST_ASSIGN
, script
, REGS
.pc
);
3392 END_CASE(ThrowSetConst
)
3394 CASE(CheckLexical
) {
3395 if (REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
3396 ReportRuntimeLexicalError(cx
, JSMSG_UNINITIALIZED_LEXICAL
, script
,
3401 END_CASE(CheckLexical
)
3403 CASE(CheckAliasedLexical
) {
3404 if (REGS
.sp
[-1].isMagic(JS_UNINITIALIZED_LEXICAL
)) {
3405 ReportRuntimeLexicalError(cx
, JSMSG_UNINITIALIZED_LEXICAL
, script
,
3410 END_CASE(CheckAliasedLexical
)
3413 uint32_t i
= GET_LOCALNO(REGS
.pc
);
3414 REGS
.fp()->unaliasedLocal(i
) = REGS
.sp
[-1];
3416 END_CASE(InitLexical
)
3418 CASE(InitAliasedLexical
) {
3419 EnvironmentCoordinate ec
= EnvironmentCoordinate(REGS
.pc
);
3420 EnvironmentObject
& obj
= REGS
.fp()->aliasedEnvironment(ec
);
3421 obj
.setAliasedBinding(ec
, REGS
.sp
[-1]);
3423 END_CASE(InitAliasedLexical
)
3425 CASE(InitGLexical
) {
3426 ExtensibleLexicalEnvironmentObject
* lexicalEnv
;
3427 if (script
->hasNonSyntacticScope()) {
3428 lexicalEnv
= ®S
.fp()->extensibleLexicalEnvironment();
3430 lexicalEnv
= &cx
->global()->lexicalEnvironment();
3432 HandleValue value
= REGS
.stackHandleAt(-1);
3433 InitGlobalLexicalOperation(cx
, lexicalEnv
, script
, REGS
.pc
, value
);
3435 END_CASE(InitGLexical
)
3437 CASE(Uninitialized
) { PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL
); }
3438 END_CASE(Uninitialized
)
3441 unsigned i
= GET_ARGNO(REGS
.pc
);
3442 if (script
->argsObjAliasesFormals()) {
3443 PUSH_COPY(REGS
.fp()->argsObj().arg(i
));
3445 PUSH_COPY(REGS
.fp()->unaliasedFormal(i
));
3451 uint32_t i
= GET_ARGNO(REGS
.pc
);
3452 PUSH_COPY(REGS
.fp()->unaliasedFormal(i
, DONT_CHECK_ALIASING
));
3454 END_CASE(GetFrameArg
)
3457 unsigned i
= GET_ARGNO(REGS
.pc
);
3458 if (script
->argsObjAliasesFormals()) {
3459 REGS
.fp()->argsObj().setArg(i
, REGS
.sp
[-1]);
3461 REGS
.fp()->unaliasedFormal(i
) = REGS
.sp
[-1];
3467 uint32_t i
= GET_LOCALNO(REGS
.pc
);
3468 PUSH_COPY_SKIP_CHECK(REGS
.fp()->unaliasedLocal(i
));
3471 if (IsUninitializedLexical(REGS
.sp
[-1])) {
3472 JSOp next
= JSOp(*GetNextPc(REGS
.pc
));
3473 MOZ_ASSERT(next
== JSOp::CheckThis
|| next
== JSOp::CheckReturn
||
3474 next
== JSOp::CheckThisReinit
|| next
== JSOp::CheckLexical
);
3478 * Skip the same-compartment assertion if the local will be immediately
3479 * popped. We do not guarantee sync for dead locals when coming in from
3480 * the method JIT, and a GetLocal followed by Pop is not considered to
3481 * be a use of the variable.
3483 if (JSOp(REGS
.pc
[JSOpLength_GetLocal
]) != JSOp::Pop
) {
3484 cx
->debugOnlyCheck(REGS
.sp
[-1]);
3491 uint32_t i
= GET_LOCALNO(REGS
.pc
);
3493 MOZ_ASSERT(!IsUninitializedLexical(REGS
.fp()->unaliasedLocal(i
)));
3495 REGS
.fp()->unaliasedLocal(i
) = REGS
.sp
[-1];
3499 CASE(ArgumentsLength
) {
3500 MOZ_ASSERT(!script
->needsArgsObj());
3501 PUSH_INT32(REGS
.fp()->numActualArgs());
3503 END_CASE(ArgumentsLength
)
3505 CASE(GetActualArg
) {
3506 MOZ_ASSERT(!script
->needsArgsObj());
3507 uint32_t index
= REGS
.sp
[-1].toInt32();
3508 REGS
.sp
[-1] = REGS
.fp()->unaliasedActual(index
);
3510 END_CASE(GetActualArg
)
3512 CASE(GlobalOrEvalDeclInstantiation
) {
3513 GCThingIndex lastFun
= GET_GCTHING_INDEX(REGS
.pc
);
3514 HandleObject env
= REGS
.fp()->environmentChain();
3515 if (!GlobalOrEvalDeclInstantiation(cx
, env
, script
, lastFun
)) {
3519 END_CASE(GlobalOrEvalDeclInstantiation
)
3522 /* Load the specified function object literal. */
3523 ReservedRooted
<JSFunction
*> fun(&rootFunction0
,
3524 script
->getFunction(REGS
.pc
));
3525 JSObject
* obj
= Lambda(cx
, fun
, REGS
.fp()->environmentChain());
3530 MOZ_ASSERT(obj
->staticPrototype());
3536 ReservedRooted
<Value
> nextMethod(&rootValue0
, REGS
.sp
[-1]);
3537 ReservedRooted
<JSObject
*> iter(&rootObject1
, ®S
.sp
[-2].toObject());
3538 JSObject
* asyncIter
= CreateAsyncFromSyncIterator(cx
, iter
, nextMethod
);
3544 REGS
.sp
[-1].setObject(*asyncIter
);
3546 END_CASE(ToAsyncIter
)
3548 CASE(CanSkipAwait
) {
3549 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-1]);
3551 if (!CanSkipAwait(cx
, val
, &canSkip
)) {
3555 PUSH_BOOLEAN(canSkip
);
3557 END_CASE(CanSkipAwait
)
3559 CASE(MaybeExtractAwaitValue
) {
3560 MutableHandleValue val
= REGS
.stackHandleAt(-2);
3561 ReservedRooted
<Value
> canSkip(&rootValue0
, REGS
.sp
[-1]);
3563 if (canSkip
.toBoolean()) {
3564 if (!ExtractAwaitValue(cx
, val
, val
)) {
3569 END_CASE(MaybeExtractAwaitValue
)
3572 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3573 ReservedRooted
<JSObject
*> gen(&rootObject1
, ®S
.sp
[-1].toObject());
3574 ReservedRooted
<Value
> value(&rootValue0
, REGS
.sp
[-2]);
3576 AsyncFunctionAwait(cx
, gen
.as
<AsyncFunctionGeneratorObject
>(), value
);
3582 REGS
.sp
[-1].setObject(*promise
);
3584 END_CASE(AsyncAwait
)
3586 CASE(AsyncResolve
) {
3587 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3588 auto resolveKind
= AsyncFunctionResolveKind(GET_UINT8(REGS
.pc
));
3589 ReservedRooted
<JSObject
*> gen(&rootObject1
, ®S
.sp
[-1].toObject());
3590 ReservedRooted
<Value
> valueOrReason(&rootValue0
, REGS
.sp
[-2]);
3592 AsyncFunctionResolve(cx
, gen
.as
<AsyncFunctionGeneratorObject
>(),
3593 valueOrReason
, resolveKind
);
3599 REGS
.sp
[-1].setObject(*promise
);
3601 END_CASE(AsyncResolve
)
3604 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3605 FunctionPrefixKind prefixKind
= FunctionPrefixKind(GET_UINT8(REGS
.pc
));
3606 ReservedRooted
<Value
> name(&rootValue0
, REGS
.sp
[-1]);
3607 ReservedRooted
<JSFunction
*> fun(&rootFunction0
,
3608 ®S
.sp
[-2].toObject().as
<JSFunction
>());
3609 if (!SetFunctionName(cx
, fun
, name
, prefixKind
)) {
3615 END_CASE(SetFunName
)
3618 MOZ_ASSERT(REGS
.fp()->isFunctionFrame());
3619 PUSH_COPY(REGS
.fp()->calleev());
3623 CASE(InitPropGetter
)
3624 CASE(InitHiddenPropGetter
)
3625 CASE(InitPropSetter
)
3626 CASE(InitHiddenPropSetter
) {
3627 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3629 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
3630 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3631 ReservedRooted
<JSObject
*> val(&rootObject1
, ®S
.sp
[-1].toObject());
3633 if (!InitPropGetterSetterOperation(cx
, REGS
.pc
, obj
, name
, val
)) {
3639 END_CASE(InitPropGetter
)
3641 CASE(InitElemGetter
)
3642 CASE(InitHiddenElemGetter
)
3643 CASE(InitElemSetter
)
3644 CASE(InitHiddenElemSetter
) {
3645 MOZ_ASSERT(REGS
.stackDepth() >= 3);
3647 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-3].toObject());
3648 ReservedRooted
<Value
> idval(&rootValue0
, REGS
.sp
[-2]);
3649 ReservedRooted
<JSObject
*> val(&rootObject1
, ®S
.sp
[-1].toObject());
3651 if (!InitElemGetterSetterOperation(cx
, REGS
.pc
, obj
, idval
, val
)) {
3657 END_CASE(InitElemGetter
)
3659 CASE(Hole
) { PUSH_MAGIC(JS_ELEMENTS_HOLE
); }
3663 JSObject
* obj
= NewObjectOperation(cx
, script
, REGS
.pc
);
3673 uint32_t length
= GET_UINT32(REGS
.pc
);
3674 ArrayObject
* obj
= NewArrayOperation(cx
, length
);
3683 JSObject
* obj
= NewObjectOperation(cx
, script
, REGS
.pc
);
3692 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3694 if (REGS
.sp
[-1].isObjectOrNull()) {
3695 ReservedRooted
<JSObject
*> newProto(&rootObject1
,
3696 REGS
.sp
[-1].toObjectOrNull());
3697 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
3698 MOZ_ASSERT(obj
->is
<PlainObject
>());
3700 if (!SetPrototype(cx
, obj
, newProto
)) {
3707 END_CASE(MutateProto
)
3710 CASE(InitLockedProp
)
3711 CASE(InitHiddenProp
) {
3712 static_assert(JSOpLength_InitProp
== JSOpLength_InitLockedProp
,
3713 "initprop and initlockedprop must be the same size");
3714 static_assert(JSOpLength_InitProp
== JSOpLength_InitHiddenProp
,
3715 "initprop and inithiddenprop must be the same size");
3716 /* Load the property's initial value into rval. */
3717 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3718 ReservedRooted
<Value
> rval(&rootValue0
, REGS
.sp
[-1]);
3720 /* Load the object being initialized into lval/obj. */
3721 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
3723 ReservedRooted
<PropertyName
*> name(&rootName0
, script
->getName(REGS
.pc
));
3725 if (!InitPropertyOperation(cx
, REGS
.pc
, obj
, name
, rval
)) {
3734 CASE(InitHiddenElem
)
3735 CASE(InitLockedElem
) {
3736 MOZ_ASSERT(REGS
.stackDepth() >= 3);
3737 HandleValue val
= REGS
.stackHandleAt(-1);
3738 HandleValue id
= REGS
.stackHandleAt(-2);
3740 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-3].toObject());
3742 if (!InitElemOperation(cx
, REGS
.pc
, obj
, id
, val
)) {
3750 CASE(InitElemArray
) {
3751 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3752 HandleValue val
= REGS
.stackHandleAt(-1);
3753 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-2].toObject());
3755 InitElemArrayOperation(cx
, REGS
.pc
, obj
.as
<ArrayObject
>(), val
);
3758 END_CASE(InitElemArray
)
3761 MOZ_ASSERT(REGS
.stackDepth() >= 3);
3762 HandleValue val
= REGS
.stackHandleAt(-1);
3764 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-3].toObject());
3766 uint32_t index
= REGS
.sp
[-2].toInt32();
3767 if (!InitElemIncOperation(cx
, obj
.as
<ArrayObject
>(), index
, val
)) {
3771 REGS
.sp
[-2].setInt32(index
+ 1);
3774 END_CASE(InitElemInc
)
3776 #ifdef ENABLE_RECORD_TUPLE
3778 uint32_t length
= GET_UINT32(REGS
.pc
);
3779 RecordType
* rec
= RecordType::createUninitialized(cx
, length
);
3783 PUSH_EXTENDED_PRIMITIVE(*rec
);
3785 END_CASE(InitRecord
)
3787 CASE(AddRecordProperty
) {
3788 MOZ_ASSERT(REGS
.stackDepth() >= 3);
3790 ReservedRooted
<JSObject
*> rec(&rootObject0
,
3791 ®S
.sp
[-3].toExtendedPrimitive());
3792 MOZ_ASSERT(rec
->is
<RecordType
>());
3794 ReservedRooted
<Value
> key(&rootValue0
, REGS
.sp
[-2]);
3795 ReservedRooted
<jsid
> id(&rootId0
);
3796 if (!JS_ValueToId(cx
, key
, &id
)) {
3799 if (!rec
->as
<RecordType
>().initializeNextProperty(
3800 cx
, id
, REGS
.stackHandleAt(-1))) {
3806 END_CASE(AddRecordProperty
)
3808 CASE(AddRecordSpread
) {
3809 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3811 if (!AddRecordSpreadOperation(cx
, REGS
.stackHandleAt(-2),
3812 REGS
.stackHandleAt(-1))) {
3817 END_CASE(AddRecordSpread
)
3819 CASE(FinishRecord
) {
3820 MOZ_ASSERT(REGS
.stackDepth() >= 1);
3821 RecordType
* rec
= ®S
.sp
[-1].toExtendedPrimitive().as
<RecordType
>();
3822 if (!rec
->finishInitialization(cx
)) {
3826 END_CASE(FinishRecord
)
3829 uint32_t length
= GET_UINT32(REGS
.pc
);
3830 TupleType
* tup
= TupleType::createUninitialized(cx
, length
);
3834 PUSH_EXTENDED_PRIMITIVE(*tup
);
3838 CASE(AddTupleElement
) {
3839 MOZ_ASSERT(REGS
.stackDepth() >= 2);
3841 ReservedRooted
<JSObject
*> tup(&rootObject0
,
3842 ®S
.sp
[-2].toExtendedPrimitive());
3843 HandleValue val
= REGS
.stackHandleAt(-1);
3845 if (!tup
->as
<TupleType
>().initializeNextElement(cx
, val
)) {
3851 END_CASE(AddTupleElement
)
3854 MOZ_ASSERT(REGS
.stackDepth() >= 1);
3855 TupleType
& tup
= REGS
.sp
[-1].toExtendedPrimitive().as
<TupleType
>();
3856 tup
.finishInitialization(cx
);
3858 END_CASE(FinishTuple
)
3863 MutableHandleValue res
= REGS
.stackHandleAt(-1);
3864 if (!GetAndClearException(cx
, res
)) {
3870 CASE(Finally
) { CHECK_BRANCH(); }
3875 ReservedRooted
<Value
> v(&rootValue0
);
3877 MOZ_ALWAYS_FALSE(ThrowOperation(cx
, v
));
3878 /* let the code at error try to catch the exception. */
3883 ReservedRooted
<Value
> rref(&rootValue0
, REGS
.sp
[-1]);
3884 if (HandleValue(rref
).isPrimitive()) {
3885 ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
, -1, rref
, nullptr);
3888 ReservedRooted
<JSObject
*> obj(&rootObject0
, &rref
.toObject());
3890 if (!InstanceofOperator(cx
, obj
, REGS
.stackHandleAt(-2), &cond
)) {
3894 REGS
.sp
[-1].setBoolean(cond
);
3896 END_CASE(Instanceof
)
3899 if (!DebugAPI::onDebuggerStatement(cx
, REGS
.fp())) {
3905 CASE(PushLexicalEnv
) {
3906 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
3908 // Create block environment and push on scope chain.
3909 if (!REGS
.fp()->pushLexicalEnvironment(cx
, scope
.as
<LexicalScope
>())) {
3913 END_CASE(PushLexicalEnv
)
3915 CASE(PopLexicalEnv
) {
3917 Scope
* scope
= script
->lookupScope(REGS
.pc
);
3919 MOZ_ASSERT(scope
->is
<LexicalScope
>() || scope
->is
<ClassBodyScope
>());
3920 MOZ_ASSERT_IF(scope
->is
<LexicalScope
>(),
3921 scope
->as
<LexicalScope
>().hasEnvironment());
3922 MOZ_ASSERT_IF(scope
->is
<ClassBodyScope
>(),
3923 scope
->as
<ClassBodyScope
>().hasEnvironment());
3926 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
3927 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
3930 // Pop block from scope chain.
3931 REGS
.fp()->popOffEnvironmentChain
<LexicalEnvironmentObject
>();
3933 END_CASE(PopLexicalEnv
)
3935 CASE(DebugLeaveLexicalEnv
) {
3937 Scope
* scope
= script
->lookupScope(REGS
.pc
);
3939 MOZ_ASSERT(scope
->is
<LexicalScope
>() || scope
->is
<ClassBodyScope
>());
3940 MOZ_ASSERT_IF(scope
->is
<LexicalScope
>(),
3941 !scope
->as
<LexicalScope
>().hasEnvironment());
3942 MOZ_ASSERT_IF(scope
->is
<ClassBodyScope
>(),
3943 !scope
->as
<ClassBodyScope
>().hasEnvironment());
3945 // FIXME: This opcode should not be necessary. The debugger shouldn't
3946 // need help from bytecode to do its job. See bug 927782.
3948 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
3949 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
3952 END_CASE(DebugLeaveLexicalEnv
)
3954 CASE(FreshenLexicalEnv
) {
3956 Scope
* scope
= script
->getScope(REGS
.pc
);
3957 auto envChain
= REGS
.fp()->environmentChain();
3958 auto* envScope
= &envChain
->as
<BlockLexicalEnvironmentObject
>().scope();
3959 MOZ_ASSERT(scope
== envScope
);
3962 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
3963 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
3966 if (!REGS
.fp()->freshenLexicalEnvironment(cx
)) {
3970 END_CASE(FreshenLexicalEnv
)
3972 CASE(RecreateLexicalEnv
) {
3974 Scope
* scope
= script
->getScope(REGS
.pc
);
3975 auto envChain
= REGS
.fp()->environmentChain();
3976 auto* envScope
= &envChain
->as
<BlockLexicalEnvironmentObject
>().scope();
3977 MOZ_ASSERT(scope
== envScope
);
3980 if (MOZ_UNLIKELY(cx
->realm()->isDebuggee())) {
3981 DebugEnvironments::onPopLexical(cx
, REGS
.fp(), REGS
.pc
);
3984 if (!REGS
.fp()->recreateLexicalEnvironment(cx
)) {
3988 END_CASE(RecreateLexicalEnv
)
3990 CASE(PushClassBodyEnv
) {
3991 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
3993 if (!REGS
.fp()->pushClassBodyEnvironment(cx
,
3994 scope
.as
<ClassBodyScope
>())) {
3998 END_CASE(PushClassBodyEnv
)
4001 ReservedRooted
<Scope
*> scope(&rootScope0
, script
->getScope(REGS
.pc
));
4003 if (!REGS
.fp()->pushVarEnvironment(cx
, scope
)) {
4007 END_CASE(PushVarEnv
)
4010 MOZ_ASSERT(!cx
->isExceptionPending());
4011 MOZ_ASSERT(REGS
.stackDepth() == 0);
4012 JSObject
* obj
= AbstractGeneratorObject::createFromFrame(cx
, REGS
.fp());
4020 CASE(InitialYield
) {
4021 MOZ_ASSERT(!cx
->isExceptionPending());
4022 MOZ_ASSERT_IF(script
->isModule() && script
->isAsync(),
4023 REGS
.fp()->isModuleFrame());
4024 MOZ_ASSERT_IF(!script
->isModule() && script
->isAsync(),
4025 REGS
.fp()->isFunctionFrame());
4026 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-1].toObject());
4028 MOZ_ASSERT(REGS
.stackDepth() == 0);
4029 if (!AbstractGeneratorObject::suspend(cx
, obj
, REGS
.fp(), REGS
.pc
,
4030 script
->nfixed())) {
4033 goto successful_return_continuation
;
4038 MOZ_ASSERT(!cx
->isExceptionPending());
4039 MOZ_ASSERT_IF(script
->isModule() && script
->isAsync(),
4040 REGS
.fp()->isModuleFrame());
4041 MOZ_ASSERT_IF(!script
->isModule() && script
->isAsync(),
4042 REGS
.fp()->isFunctionFrame());
4043 ReservedRooted
<JSObject
*> obj(&rootObject0
, ®S
.sp
[-1].toObject());
4044 if (!AbstractGeneratorObject::suspend(
4045 cx
, obj
, REGS
.fp(), REGS
.pc
,
4046 script
->nfixed() + REGS
.stackDepth() - 2)) {
4053 goto successful_return_continuation
;
4057 GeneratorResumeKind resumeKind
= ResumeKindFromPC(REGS
.pc
);
4058 PUSH_INT32(int32_t(resumeKind
));
4060 END_CASE(ResumeKind
)
4062 CASE(CheckResumeKind
) {
4063 int32_t kindInt
= REGS
.sp
[-1].toInt32();
4064 GeneratorResumeKind resumeKind
= IntToResumeKind(kindInt
);
4065 if (MOZ_UNLIKELY(resumeKind
!= GeneratorResumeKind::Next
)) {
4066 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-3]);
4067 Rooted
<AbstractGeneratorObject
*> gen(
4068 cx
, ®S
.sp
[-2].toObject().as
<AbstractGeneratorObject
>());
4069 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx
, activation
.regs().fp(), gen
,
4075 END_CASE(CheckResumeKind
)
4079 Rooted
<AbstractGeneratorObject
*> gen(
4080 cx
, ®S
.sp
[-3].toObject().as
<AbstractGeneratorObject
>());
4081 ReservedRooted
<Value
> val(&rootValue0
, REGS
.sp
[-2]);
4082 ReservedRooted
<Value
> resumeKindVal(&rootValue1
, REGS
.sp
[-1]);
4084 // popInlineFrame expects there to be an additional value on the stack
4085 // to pop off, so leave "gen" on the stack.
4088 if (!AbstractGeneratorObject::resume(cx
, activation
, gen
, val
,
4093 JSScript
* generatorScript
= REGS
.fp()->script();
4094 if (cx
->realm() != generatorScript
->realm()) {
4095 cx
->enterRealmOf(generatorScript
);
4097 SET_SCRIPT(generatorScript
);
4099 if (!probes::EnterScript(cx
, generatorScript
,
4100 generatorScript
->function(), REGS
.fp())) {
4104 if (!DebugAPI::onResumeFrame(cx
, REGS
.fp())) {
4105 if (cx
->isPropagatingForcedReturn()) {
4109 .isGenerator(), // as opposed to an async function
4115 ADVANCE_AND_DISPATCH(0);
4119 // AbstractGeneratorObject::resume takes care of setting the frame's
4121 MOZ_ASSERT_IF(REGS
.fp()->script()->isDebuggee(), REGS
.fp()->isDebuggee());
4124 END_CASE(AfterYield
)
4126 CASE(FinalYieldRval
) {
4127 ReservedRooted
<JSObject
*> gen(&rootObject0
, ®S
.sp
[-1].toObject());
4129 AbstractGeneratorObject::finalSuspend(gen
);
4130 goto successful_return_continuation
;
4133 CASE(CheckClassHeritage
) {
4134 HandleValue heritage
= REGS
.stackHandleAt(-1);
4136 if (!CheckClassHeritageOperation(cx
, heritage
)) {
4140 END_CASE(CheckClassHeritage
)
4142 CASE(BuiltinObject
) {
4143 auto kind
= BuiltinObjectKind(GET_UINT8(REGS
.pc
));
4144 JSObject
* builtin
= BuiltinObjectOperation(cx
, kind
);
4148 PUSH_OBJECT(*builtin
);
4150 END_CASE(BuiltinObject
)
4152 CASE(FunWithProto
) {
4153 ReservedRooted
<JSObject
*> proto(&rootObject1
, ®S
.sp
[-1].toObject());
4155 /* Load the specified function object literal. */
4156 ReservedRooted
<JSFunction
*> fun(&rootFunction0
,
4157 script
->getFunction(REGS
.pc
));
4160 FunWithProtoOperation(cx
, fun
, REGS
.fp()->environmentChain(), proto
);
4165 REGS
.sp
[-1].setObject(*obj
);
4167 END_CASE(FunWithProto
)
4169 CASE(ObjWithProto
) {
4170 JSObject
* obj
= ObjectWithProtoOperation(cx
, REGS
.stackHandleAt(-1));
4175 REGS
.sp
[-1].setObject(*obj
);
4177 END_CASE(ObjWithProto
)
4179 CASE(InitHomeObject
) {
4180 MOZ_ASSERT(REGS
.stackDepth() >= 2);
4182 /* Load the function to be initialized */
4183 JSFunction
* func
= ®S
.sp
[-2].toObject().as
<JSFunction
>();
4184 MOZ_ASSERT(func
->allowSuperProperty());
4186 /* Load the home object */
4187 JSObject
* obj
= ®S
.sp
[-1].toObject();
4188 MOZ_ASSERT(obj
->is
<PlainObject
>() || obj
->is
<JSFunction
>());
4190 func
->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT
,
4194 END_CASE(InitHomeObject
)
4197 JSFunction
& superEnvFunc
= REGS
.sp
[-1].toObject().as
<JSFunction
>();
4198 MOZ_ASSERT(superEnvFunc
.allowSuperProperty());
4199 MOZ_ASSERT(superEnvFunc
.baseScript()->needsHomeObject());
4200 const Value
& homeObjVal
= superEnvFunc
.getExtendedSlot(
4201 FunctionExtended::METHOD_HOMEOBJECT_SLOT
);
4203 JSObject
* homeObj
= &homeObjVal
.toObject();
4204 JSObject
* superBase
= HomeObjectSuperBase(homeObj
);
4206 REGS
.sp
[-1].setObjectOrNull(superBase
);
4211 PUSH_COPY(REGS
.fp()->newTarget());
4212 MOZ_ASSERT(REGS
.sp
[-1].isObject() || REGS
.sp
[-1].isUndefined());
4217 JSObject
* metaObject
= ImportMetaOperation(cx
, script
);
4222 PUSH_OBJECT(*metaObject
);
4224 END_CASE(ImportMeta
)
4226 CASE(DynamicImport
) {
4227 ReservedRooted
<Value
> options(&rootValue0
, REGS
.sp
[-1]);
4230 ReservedRooted
<Value
> specifier(&rootValue1
);
4231 POP_COPY_TO(specifier
);
4234 StartDynamicModuleImport(cx
, script
, specifier
, options
);
4235 if (!promise
) goto error
;
4237 PUSH_OBJECT(*promise
);
4239 END_CASE(DynamicImport
)
4242 uint8_t numHops
= GET_UINT8(REGS
.pc
);
4243 JSObject
* env
= ®S
.fp()->environmentChain()->as
<EnvironmentObject
>();
4244 for (unsigned i
= 0; i
< numHops
; i
++) {
4245 env
= &env
->as
<EnvironmentObject
>().enclosingEnvironment();
4247 PUSH_OBJECT(env
->as
<CallObject
>().callee());
4252 JSObject
* superEnvFunc
= ®S
.sp
[-1].toObject();
4253 JSObject
* superFun
= SuperFunOperation(superEnvFunc
);
4254 REGS
.sp
[-1].setObjectOrNull(superFun
);
4258 CASE(CheckObjCoercible
) {
4259 ReservedRooted
<Value
> checkVal(&rootValue0
, REGS
.sp
[-1]);
4260 if (checkVal
.isNullOrUndefined()) {
4261 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx
, checkVal
));
4265 END_CASE(CheckObjCoercible
)
4267 CASE(DebugCheckSelfHosted
) {
4269 ReservedRooted
<Value
> checkVal(&rootValue0
, REGS
.sp
[-1]);
4270 if (!Debug_CheckSelfHosted(cx
, checkVal
)) {
4275 END_CASE(DebugCheckSelfHosted
)
4277 CASE(IsConstructing
) { PUSH_MAGIC(JS_IS_CONSTRUCTING
); }
4278 END_CASE(IsConstructing
)
4281 MutableHandleValue val
= REGS
.stackHandleAt(-1);
4282 if (!IncOperation(cx
, val
, val
)) {
4289 MutableHandleValue val
= REGS
.stackHandleAt(-1);
4290 if (!DecOperation(cx
, val
, val
)) {
4297 if (!ToNumeric(cx
, REGS
.stackHandleAt(-1))) {
4303 CASE(BigInt
) { PUSH_BIGINT(script
->getBigInt(REGS
.pc
)); }
4308 SprintfLiteral(numBuf
, "%d", *REGS
.pc
);
4309 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
4310 JSMSG_BAD_BYTECODE
, numBuf
);
4314 } /* interpreter loop */
4316 MOZ_CRASH("Interpreter loop exited via fallthrough");
4319 switch (HandleError(cx
, REGS
)) {
4320 case SuccessfulReturnContinuation
:
4321 goto successful_return_continuation
;
4323 case ErrorReturnContinuation
:
4324 interpReturnOK
= false;
4325 goto return_continuation
;
4327 case CatchContinuation
:
4328 ADVANCE_AND_DISPATCH(0);
4330 case FinallyContinuation
: {
4332 * Push (exception, true) pair for finally to indicate that we
4333 * should rethrow the exception.
4335 ReservedRooted
<Value
> exception(&rootValue0
);
4336 if (!cx
->getPendingException(&exception
)) {
4337 interpReturnOK
= false;
4338 goto return_continuation
;
4340 PUSH_COPY(exception
);
4342 cx
->clearPendingException();
4344 ADVANCE_AND_DISPATCH(0);
4347 MOZ_CRASH("Invalid HandleError continuation");
4350 if (MOZ_LIKELY(!frameHalfInitialized
)) {
4352 DebugAPI::onLeaveFrame(cx
, REGS
.fp(), REGS
.pc
, interpReturnOK
);
4354 REGS
.fp()->epilogue(cx
, REGS
.pc
);
4357 gc::MaybeVerifyBarriers(cx
, true);
4360 * This path is used when it's guaranteed the method can be finished
4363 leave_on_safe_point
:
4365 if (interpReturnOK
) {
4366 state
.setReturnValue(activation
.entryFrame()->returnValue());
4369 return interpReturnOK
;
4372 interpReturnOK
= false;
4373 frameHalfInitialized
= true;
4374 goto prologue_return_continuation
;
4377 bool js::ThrowOperation(JSContext
* cx
, HandleValue v
) {
4378 MOZ_ASSERT(!cx
->isExceptionPending());
4379 cx
->setPendingException(v
, ShouldCaptureStack::Maybe
);
4383 bool js::GetProperty(JSContext
* cx
, HandleValue v
, Handle
<PropertyName
*> name
,
4384 MutableHandleValue vp
) {
4385 if (name
== cx
->names().length
) {
4386 // Fast path for strings, arrays and arguments.
4387 if (GetLengthProperty(v
, vp
)) {
4392 // Optimize common cases like (2).toString() or "foo".valueOf() to not
4393 // create a wrapper object.
4394 if (v
.isPrimitive() && !v
.isNullOrUndefined()) {
4398 case ValueType::Double
:
4399 case ValueType::Int32
:
4400 proto
= GlobalObject::getOrCreateNumberPrototype(cx
, cx
->global());
4402 case ValueType::Boolean
:
4403 proto
= GlobalObject::getOrCreateBooleanPrototype(cx
, cx
->global());
4405 case ValueType::String
:
4406 proto
= GlobalObject::getOrCreateStringPrototype(cx
, cx
->global());
4408 case ValueType::Symbol
:
4409 proto
= GlobalObject::getOrCreateSymbolPrototype(cx
, cx
->global());
4411 case ValueType::BigInt
:
4412 proto
= GlobalObject::getOrCreateBigIntPrototype(cx
, cx
->global());
4414 #ifdef ENABLE_RECORD_TUPLE
4415 case ValueType::ExtendedPrimitive
: {
4416 RootedObject
obj(cx
, &v
.toExtendedPrimitive());
4417 RootedId
id(cx
, NameToId(name
));
4418 return ExtendedPrimitiveGetProperty(cx
, obj
, v
, id
, vp
);
4421 case ValueType::Undefined
:
4422 case ValueType::Null
:
4423 case ValueType::Magic
:
4424 case ValueType::PrivateGCThing
:
4425 case ValueType::Object
:
4426 MOZ_CRASH("unexpected type");
4433 if (GetPropertyPure(cx
, proto
, NameToId(name
), vp
.address())) {
4438 RootedValue
receiver(cx
, v
);
4440 cx
, ToObjectFromStackForPropertyAccess(cx
, v
, JSDVG_SEARCH_STACK
, name
));
4445 return GetProperty(cx
, obj
, receiver
, name
, vp
);
4448 JSObject
* js::Lambda(JSContext
* cx
, HandleFunction fun
, HandleObject parent
) {
4450 if (fun
->isNativeFun()) {
4451 MOZ_ASSERT(IsAsmJSModule(fun
));
4452 clone
= CloneAsmJSModuleFunction(cx
, fun
);
4454 RootedObject
proto(cx
, fun
->staticPrototype());
4455 clone
= CloneFunctionReuseScript(cx
, fun
, parent
, proto
);
4461 MOZ_ASSERT(fun
->global() == clone
->global());
4465 JSObject
* js::BindVarOperation(JSContext
* cx
, JSObject
* envChain
) {
4466 // Note: BindVarOperation has an unused cx argument because the JIT callVM
4467 // machinery requires this.
4468 return &GetVariablesObject(envChain
);
4471 JSObject
* js::ImportMetaOperation(JSContext
* cx
, HandleScript script
) {
4472 RootedObject
module(cx
, GetModuleObjectForScript(script
));
4474 return GetOrCreateModuleMetaObject(cx
, module
);
4477 JSObject
* js::BuiltinObjectOperation(JSContext
* cx
, BuiltinObjectKind kind
) {
4478 return GetOrCreateBuiltinObject(cx
, kind
);
4481 bool js::ThrowMsgOperation(JSContext
* cx
, const unsigned throwMsgKind
) {
4482 auto errorNum
= ThrowMsgKindToErrNum(ThrowMsgKind(throwMsgKind
));
4483 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, errorNum
);
4487 bool js::GetAndClearExceptionAndStack(JSContext
* cx
, MutableHandleValue res
,
4488 MutableHandle
<SavedFrame
*> stack
) {
4489 if (!cx
->getPendingException(res
)) {
4492 stack
.set(cx
->getPendingExceptionStack());
4493 cx
->clearPendingException();
4495 // Allow interrupting deeply nested exception handling.
4496 return CheckForInterrupt(cx
);
4499 bool js::GetAndClearException(JSContext
* cx
, MutableHandleValue res
) {
4500 Rooted
<SavedFrame
*> stack(cx
);
4501 return GetAndClearExceptionAndStack(cx
, res
, &stack
);
4504 template <bool strict
>
4505 bool js::DelPropOperation(JSContext
* cx
, HandleValue val
,
4506 Handle
<PropertyName
*> name
, bool* res
) {
4507 const int valIndex
= -1;
4508 RootedObject
obj(cx
,
4509 ToObjectFromStackForPropertyAccess(cx
, val
, valIndex
, name
));
4514 RootedId
id(cx
, NameToId(name
));
4515 ObjectOpResult result
;
4516 if (!DeleteProperty(cx
, obj
, id
, result
)) {
4522 return result
.reportError(cx
, obj
, id
);
4531 template bool js::DelPropOperation
<true>(JSContext
* cx
, HandleValue val
,
4532 Handle
<PropertyName
*> name
, bool* res
);
4533 template bool js::DelPropOperation
<false>(JSContext
* cx
, HandleValue val
,
4534 Handle
<PropertyName
*> name
,
4537 template <bool strict
>
4538 bool js::DelElemOperation(JSContext
* cx
, HandleValue val
, HandleValue index
,
4540 const int valIndex
= -2;
4542 cx
, ToObjectFromStackForPropertyAccess(cx
, val
, valIndex
, index
));
4548 if (!ToPropertyKey(cx
, index
, &id
)) {
4551 ObjectOpResult result
;
4552 if (!DeleteProperty(cx
, obj
, id
, result
)) {
4558 return result
.reportError(cx
, obj
, id
);
4567 template bool js::DelElemOperation
<true>(JSContext
*, HandleValue
, HandleValue
,
4569 template bool js::DelElemOperation
<false>(JSContext
*, HandleValue
, HandleValue
,
4572 bool js::SetObjectElement(JSContext
* cx
, HandleObject obj
, HandleValue index
,
4573 HandleValue value
, bool strict
) {
4575 if (!ToPropertyKey(cx
, index
, &id
)) {
4578 RootedValue
receiver(cx
, ObjectValue(*obj
));
4579 return SetObjectElementOperation(cx
, obj
, id
, value
, receiver
, strict
);
4582 bool js::SetObjectElementWithReceiver(JSContext
* cx
, HandleObject obj
,
4583 HandleValue index
, HandleValue value
,
4584 HandleValue receiver
, bool strict
) {
4586 if (!ToPropertyKey(cx
, index
, &id
)) {
4589 return SetObjectElementOperation(cx
, obj
, id
, value
, receiver
, strict
);
4592 bool js::AddValues(JSContext
* cx
, MutableHandleValue lhs
,
4593 MutableHandleValue rhs
, MutableHandleValue res
) {
4594 return AddOperation(cx
, lhs
, rhs
, res
);
4597 bool js::SubValues(JSContext
* cx
, MutableHandleValue lhs
,
4598 MutableHandleValue rhs
, MutableHandleValue res
) {
4599 return SubOperation(cx
, lhs
, rhs
, res
);
4602 bool js::MulValues(JSContext
* cx
, MutableHandleValue lhs
,
4603 MutableHandleValue rhs
, MutableHandleValue res
) {
4604 return MulOperation(cx
, lhs
, rhs
, res
);
4607 bool js::DivValues(JSContext
* cx
, MutableHandleValue lhs
,
4608 MutableHandleValue rhs
, MutableHandleValue res
) {
4609 return DivOperation(cx
, lhs
, rhs
, res
);
4612 bool js::ModValues(JSContext
* cx
, MutableHandleValue lhs
,
4613 MutableHandleValue rhs
, MutableHandleValue res
) {
4614 return ModOperation(cx
, lhs
, rhs
, res
);
4617 bool js::PowValues(JSContext
* cx
, MutableHandleValue lhs
,
4618 MutableHandleValue rhs
, MutableHandleValue res
) {
4619 return PowOperation(cx
, lhs
, rhs
, res
);
4622 bool js::BitNot(JSContext
* cx
, MutableHandleValue in
, MutableHandleValue res
) {
4623 return BitNotOperation(cx
, in
, res
);
4626 bool js::BitXor(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4627 MutableHandleValue res
) {
4628 return BitXorOperation(cx
, lhs
, rhs
, res
);
4631 bool js::BitOr(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4632 MutableHandleValue res
) {
4633 return BitOrOperation(cx
, lhs
, rhs
, res
);
4636 bool js::BitAnd(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4637 MutableHandleValue res
) {
4638 return BitAndOperation(cx
, lhs
, rhs
, res
);
4641 bool js::BitLsh(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4642 MutableHandleValue res
) {
4643 return BitLshOperation(cx
, lhs
, rhs
, res
);
4646 bool js::BitRsh(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4647 MutableHandleValue res
) {
4648 return BitRshOperation(cx
, lhs
, rhs
, res
);
4651 bool js::UrshValues(JSContext
* cx
, MutableHandleValue lhs
,
4652 MutableHandleValue rhs
, MutableHandleValue res
) {
4653 return UrshOperation(cx
, lhs
, rhs
, res
);
4656 bool js::LessThan(JSContext
* cx
, MutableHandleValue lhs
, MutableHandleValue rhs
,
4658 return LessThanOperation(cx
, lhs
, rhs
, res
);
4661 bool js::LessThanOrEqual(JSContext
* cx
, MutableHandleValue lhs
,
4662 MutableHandleValue rhs
, bool* res
) {
4663 return LessThanOrEqualOperation(cx
, lhs
, rhs
, res
);
4666 bool js::GreaterThan(JSContext
* cx
, MutableHandleValue lhs
,
4667 MutableHandleValue rhs
, bool* res
) {
4668 return GreaterThanOperation(cx
, lhs
, rhs
, res
);
4671 bool js::GreaterThanOrEqual(JSContext
* cx
, MutableHandleValue lhs
,
4672 MutableHandleValue rhs
, bool* res
) {
4673 return GreaterThanOrEqualOperation(cx
, lhs
, rhs
, res
);
4676 bool js::AtomicIsLockFree(JSContext
* cx
, HandleValue in
, int* out
) {
4678 if (!ToInt32(cx
, in
, &i
)) {
4681 *out
= js::jit::AtomicOperations::isLockfreeJS(i
);
4685 bool js::DeleteNameOperation(JSContext
* cx
, Handle
<PropertyName
*> name
,
4686 HandleObject scopeObj
, MutableHandleValue res
) {
4687 RootedObject
scope(cx
), pobj(cx
);
4688 PropertyResult prop
;
4689 if (!LookupName(cx
, name
, scopeObj
, &scope
, &pobj
, &prop
)) {
4694 // Return true for non-existent names.
4695 res
.setBoolean(true);
4699 ObjectOpResult result
;
4700 RootedId
id(cx
, NameToId(name
));
4701 if (!DeleteProperty(cx
, scope
, id
, result
)) {
4705 bool status
= result
.ok();
4706 res
.setBoolean(status
);
4709 // Deleting a name from the global object removes it from [[VarNames]].
4710 if (pobj
== scope
&& scope
->is
<GlobalObject
>()) {
4711 scope
->as
<GlobalObject
>().removeFromVarNames(name
);
4718 bool js::ImplicitThisOperation(JSContext
* cx
, HandleObject scopeObj
,
4719 Handle
<PropertyName
*> name
,
4720 MutableHandleValue res
) {
4721 RootedObject
obj(cx
);
4722 if (!LookupNameWithGlobalDefault(cx
, name
, scopeObj
, &obj
)) {
4726 res
.set(ComputeImplicitThis(obj
));
4730 unsigned js::GetInitDataPropAttrs(JSOp op
) {
4732 case JSOp::InitProp
:
4733 case JSOp::InitElem
:
4734 return JSPROP_ENUMERATE
;
4735 case JSOp::InitLockedProp
:
4736 case JSOp::InitLockedElem
:
4737 return JSPROP_PERMANENT
| JSPROP_READONLY
;
4738 case JSOp::InitHiddenProp
:
4739 case JSOp::InitHiddenElem
:
4740 // Non-enumerable, but writable and configurable
4744 MOZ_CRASH("Unknown data initprop");
4747 static bool InitGetterSetterOperation(JSContext
* cx
, jsbytecode
* pc
,
4748 HandleObject obj
, HandleId id
,
4750 MOZ_ASSERT(val
->isCallable());
4752 JSOp op
= JSOp(*pc
);
4755 if (!IsHiddenInitOp(op
)) {
4756 attrs
|= JSPROP_ENUMERATE
;
4759 if (op
== JSOp::InitPropGetter
|| op
== JSOp::InitElemGetter
||
4760 op
== JSOp::InitHiddenPropGetter
|| op
== JSOp::InitHiddenElemGetter
) {
4761 return DefineAccessorProperty(cx
, obj
, id
, val
, nullptr, attrs
);
4764 MOZ_ASSERT(op
== JSOp::InitPropSetter
|| op
== JSOp::InitElemSetter
||
4765 op
== JSOp::InitHiddenPropSetter
||
4766 op
== JSOp::InitHiddenElemSetter
);
4767 return DefineAccessorProperty(cx
, obj
, id
, nullptr, val
, attrs
);
4770 bool js::InitPropGetterSetterOperation(JSContext
* cx
, jsbytecode
* pc
,
4772 Handle
<PropertyName
*> name
,
4774 RootedId
id(cx
, NameToId(name
));
4775 return InitGetterSetterOperation(cx
, pc
, obj
, id
, val
);
4778 bool js::InitElemGetterSetterOperation(JSContext
* cx
, jsbytecode
* pc
,
4779 HandleObject obj
, HandleValue idval
,
4782 if (!ToPropertyKey(cx
, idval
, &id
)) {
4786 return InitGetterSetterOperation(cx
, pc
, obj
, id
, val
);
4789 bool js::SpreadCallOperation(JSContext
* cx
, HandleScript script
, jsbytecode
* pc
,
4790 HandleValue thisv
, HandleValue callee
,
4791 HandleValue arr
, HandleValue newTarget
,
4792 MutableHandleValue res
) {
4793 Rooted
<ArrayObject
*> aobj(cx
, &arr
.toObject().as
<ArrayObject
>());
4794 uint32_t length
= aobj
->length();
4795 JSOp op
= JSOp(*pc
);
4796 bool constructing
= op
== JSOp::SpreadNew
|| op
== JSOp::SpreadSuperCall
;
4798 // {Construct,Invoke}Args::init does this too, but this gives us a better
4800 if (length
> ARGS_LENGTH_MAX
) {
4801 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
4802 constructing
? JSMSG_TOO_MANY_CON_SPREADARGS
4803 : JSMSG_TOO_MANY_FUN_SPREADARGS
);
4807 // Do our own checks for the callee being a function, as Invoke uses the
4808 // expression decompiler to decompile the callee stack operand based on
4809 // the number of arguments. Spread operations have the callee at sp - 3
4810 // when not constructing, and sp - 4 when constructing.
4811 if (callee
.isPrimitive()) {
4812 return ReportIsNotFunction(cx
, callee
, 2 + constructing
,
4813 constructing
? CONSTRUCT
: NO_CONSTRUCT
);
4816 if (!callee
.toObject().isCallable()) {
4817 return ReportIsNotFunction(cx
, callee
, 2 + constructing
,
4818 constructing
? CONSTRUCT
: NO_CONSTRUCT
);
4821 // The object must be an array with dense elements and no holes. Baseline's
4822 // optimized spread call stubs rely on this.
4823 MOZ_ASSERT(IsPackedArray(aobj
));
4826 if (!StackCheckIsConstructorCalleeNewTarget(cx
, callee
, newTarget
)) {
4830 ConstructArgs
cargs(cx
);
4831 if (!cargs
.init(cx
, length
)) {
4835 if (!GetElements(cx
, aobj
, length
, cargs
.array())) {
4839 RootedObject
obj(cx
);
4840 if (!Construct(cx
, callee
, cargs
, newTarget
, &obj
)) {
4843 res
.setObject(*obj
);
4845 InvokeArgs
args(cx
);
4846 if (!args
.init(cx
, length
)) {
4850 if (!GetElements(cx
, aobj
, length
, args
.array())) {
4854 if ((op
== JSOp::SpreadEval
|| op
== JSOp::StrictSpreadEval
) &&
4855 cx
->global()->valueIsEval(callee
)) {
4856 if (!DirectEval(cx
, args
.get(0), res
)) {
4860 MOZ_ASSERT(op
== JSOp::SpreadCall
|| op
== JSOp::SpreadEval
||
4861 op
== JSOp::StrictSpreadEval
,
4862 "bad spread opcode");
4864 if (!Call(cx
, callee
, thisv
, args
, res
)) {
4873 static bool OptimizeArrayIteration(JSContext
* cx
, HandleObject obj
,
4877 // Optimize spread call by skipping spread operation when following
4878 // conditions are met:
4879 // * the argument is an array
4880 // * the array has no hole
4881 // * array[@@iterator] is not modified
4882 // * the array's prototype is Array.prototype
4883 // * Array.prototype[@@iterator] is not modified
4884 // * %ArrayIteratorPrototype%.next is not modified
4885 // * %ArrayIteratorPrototype%.return is not defined
4886 // * return is nowhere on the proto chain
4887 if (!IsPackedArray(obj
)) {
4891 ForOfPIC::Chain
* stubChain
= ForOfPIC::getOrCreate(cx
);
4896 if (!stubChain
->tryOptimizeArray(cx
, obj
.as
<ArrayObject
>(), optimized
)) {
4903 static bool OptimizeArgumentsSpreadCall(JSContext
* cx
, HandleObject obj
,
4904 MutableHandleValue result
) {
4905 MOZ_ASSERT(result
.isUndefined());
4907 // Optimize spread call by skipping the spread operation when the following
4908 // conditions are met:
4909 // * the argument is an arguments object
4910 // * the arguments object has no deleted elements
4911 // * arguments.length is not overridden
4912 // * arguments[@@iterator] is not overridden
4913 // * %ArrayIteratorPrototype%.next is not modified
4915 if (!obj
->is
<ArgumentsObject
>()) {
4919 Handle
<ArgumentsObject
*> args
= obj
.as
<ArgumentsObject
>();
4920 if (args
->hasOverriddenElement() || args
->hasOverriddenLength() ||
4921 args
->hasOverriddenIterator()) {
4925 ForOfPIC::Chain
* stubChain
= ForOfPIC::getOrCreate(cx
);
4931 if (!stubChain
->tryOptimizeArrayIteratorNext(cx
, &optimized
)) {
4938 auto* array
= ArrayFromArgumentsObject(cx
, args
);
4943 result
.setObject(*array
);
4947 bool js::OptimizeSpreadCall(JSContext
* cx
, HandleValue arg
,
4948 MutableHandleValue result
) {
4949 // This function returns |undefined| if the spread operation can't be
4951 result
.setUndefined();
4953 if (!arg
.isObject()) {
4957 RootedObject
obj(cx
, &arg
.toObject());
4959 if (!OptimizeArrayIteration(cx
, obj
, &optimized
)) {
4963 result
.setObject(*obj
);
4967 if (!OptimizeArgumentsSpreadCall(cx
, obj
, result
)) {
4970 if (result
.isObject()) {
4974 MOZ_ASSERT(result
.isUndefined());
4978 bool js::OptimizeGetIterator(JSContext
* cx
, HandleValue arg
, bool* result
) {
4979 // This function returns |false| if the iteration can't be optimized.
4982 if (!arg
.isObject()) {
4986 RootedObject
obj(cx
, &arg
.toObject());
4989 if (!OptimizeArrayIteration(cx
, obj
, &optimized
)) {
4998 MOZ_ASSERT(!*result
);
5002 ArrayObject
* js::ArrayFromArgumentsObject(JSContext
* cx
,
5003 Handle
<ArgumentsObject
*> args
) {
5004 MOZ_ASSERT(!args
->hasOverriddenLength());
5005 MOZ_ASSERT(!args
->hasOverriddenElement());
5007 uint32_t length
= args
->initialLength();
5008 auto* array
= NewDenseFullyAllocatedArray(cx
, length
);
5012 array
->setDenseInitializedLength(length
);
5014 for (uint32_t index
= 0; index
< length
; index
++) {
5015 const Value
& v
= args
->element(index
);
5016 array
->initDenseElement(index
, v
);
5022 JSObject
* js::NewObjectOperation(JSContext
* cx
, HandleScript script
,
5023 const jsbytecode
* pc
) {
5024 if (JSOp(*pc
) == JSOp::NewObject
) {
5025 Rooted
<SharedShape
*> shape(cx
, script
->getShape(pc
));
5026 return PlainObject::createWithShape(cx
, shape
);
5029 MOZ_ASSERT(JSOp(*pc
) == JSOp::NewInit
);
5030 return NewPlainObject(cx
);
5033 JSObject
* js::NewPlainObjectBaselineFallback(JSContext
* cx
,
5034 Handle
<SharedShape
*> shape
,
5035 gc::AllocKind allocKind
,
5036 gc::AllocSite
* site
) {
5037 MOZ_ASSERT(shape
->getObjectClass() == &PlainObject::class_
);
5039 mozilla::Maybe
<AutoRealm
> ar
;
5040 if (cx
->realm() != shape
->realm()) {
5041 MOZ_ASSERT(cx
->compartment() == shape
->compartment());
5042 ar
.emplace(cx
, shape
);
5045 gc::Heap initialHeap
= site
->initialHeap();
5046 return NativeObject::create
<PlainObject
>(cx
, allocKind
, initialHeap
, shape
,
5050 JSObject
* js::NewPlainObjectOptimizedFallback(JSContext
* cx
,
5051 Handle
<SharedShape
*> shape
,
5052 gc::AllocKind allocKind
,
5053 gc::Heap initialHeap
) {
5054 MOZ_ASSERT(shape
->getObjectClass() == &PlainObject::class_
);
5056 mozilla::Maybe
<AutoRealm
> ar
;
5057 if (cx
->realm() != shape
->realm()) {
5058 MOZ_ASSERT(cx
->compartment() == shape
->compartment());
5059 ar
.emplace(cx
, shape
);
5062 gc::AllocSite
* site
= cx
->zone()->optimizedAllocSite();
5063 return NativeObject::create
<PlainObject
>(cx
, allocKind
, initialHeap
, shape
,
5067 ArrayObject
* js::NewArrayOperation(
5068 JSContext
* cx
, uint32_t length
,
5069 NewObjectKind newKind
/* = GenericObject */) {
5070 return NewDenseFullyAllocatedArray(cx
, length
, newKind
);
5073 ArrayObject
* js::NewArrayObjectBaselineFallback(JSContext
* cx
, uint32_t length
,
5074 gc::AllocKind allocKind
,
5075 gc::AllocSite
* site
) {
5076 NewObjectKind newKind
=
5077 site
->initialHeap() == gc::Heap::Tenured
? TenuredObject
: GenericObject
;
5078 ArrayObject
* array
= NewDenseFullyAllocatedArray(cx
, length
, newKind
, site
);
5079 // It's important that we allocate an object with the alloc kind we were
5080 // expecting so that a new arena gets allocated if the current arena for that
5082 MOZ_ASSERT_IF(array
&& array
->isTenured(),
5083 array
->asTenured().getAllocKind() == allocKind
);
5087 ArrayObject
* js::NewArrayObjectOptimizedFallback(JSContext
* cx
, uint32_t length
,
5088 gc::AllocKind allocKind
,
5089 NewObjectKind newKind
) {
5090 gc::AllocSite
* site
= cx
->zone()->optimizedAllocSite();
5091 ArrayObject
* array
= NewDenseFullyAllocatedArray(cx
, length
, newKind
, site
);
5092 // It's important that we allocate an object with the alloc kind we were
5093 // expecting so that a new arena gets allocated if the current arena for that
5095 MOZ_ASSERT_IF(array
&& array
->isTenured(),
5096 array
->asTenured().getAllocKind() == allocKind
);
5100 void js::ReportRuntimeLexicalError(JSContext
* cx
, unsigned errorNumber
,
5102 MOZ_ASSERT(errorNumber
== JSMSG_UNINITIALIZED_LEXICAL
||
5103 errorNumber
== JSMSG_BAD_CONST_ASSIGN
);
5104 if (UniqueChars printable
=
5105 IdToPrintableUTF8(cx
, id
, IdToPrintableBehavior::IdIsIdentifier
)) {
5106 JS_ReportErrorNumberUTF8(cx
, GetErrorMessage
, nullptr, errorNumber
,
5111 void js::ReportRuntimeLexicalError(JSContext
* cx
, unsigned errorNumber
,
5112 Handle
<PropertyName
*> name
) {
5113 RootedId
id(cx
, NameToId(name
));
5114 ReportRuntimeLexicalError(cx
, errorNumber
, id
);
5117 void js::ReportRuntimeLexicalError(JSContext
* cx
, unsigned errorNumber
,
5118 HandleScript script
, jsbytecode
* pc
) {
5119 JSOp op
= JSOp(*pc
);
5120 MOZ_ASSERT(op
== JSOp::CheckLexical
|| op
== JSOp::CheckAliasedLexical
||
5121 op
== JSOp::ThrowSetConst
|| op
== JSOp::GetImport
);
5123 Rooted
<PropertyName
*> name(cx
);
5124 if (IsLocalOp(op
)) {
5125 name
= FrameSlotName(script
, pc
)->asPropertyName();
5126 } else if (IsAliasedVarOp(op
)) {
5127 name
= EnvironmentCoordinateNameSlow(script
, pc
);
5129 MOZ_ASSERT(IsAtomOp(op
));
5130 name
= script
->getName(pc
);
5133 ReportRuntimeLexicalError(cx
, errorNumber
, name
);
5136 void js::ReportRuntimeRedeclaration(JSContext
* cx
, Handle
<PropertyName
*> name
,
5137 const char* redeclKind
) {
5138 if (UniqueChars printable
= AtomToPrintableString(cx
, name
)) {
5139 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5140 JSMSG_REDECLARED_VAR
, redeclKind
,
5145 bool js::ThrowCheckIsObject(JSContext
* cx
, CheckIsObjectKind kind
) {
5147 case CheckIsObjectKind::IteratorNext
:
5148 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5149 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE
, "next");
5151 case CheckIsObjectKind::IteratorReturn
:
5152 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5153 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE
, "return");
5155 case CheckIsObjectKind::IteratorThrow
:
5156 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5157 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE
, "throw");
5159 case CheckIsObjectKind::GetIterator
:
5160 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5161 JSMSG_GET_ITER_RETURNED_PRIMITIVE
);
5163 case CheckIsObjectKind::GetAsyncIterator
:
5164 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5165 JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE
);
5167 #ifdef ENABLE_DECORATORS
5168 case CheckIsObjectKind::DecoratorReturn
:
5169 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5170 JSMSG_DECORATOR_INVALID_RETURN_TYPE
);
5174 MOZ_CRASH("Unknown kind");
5179 bool js::ThrowUninitializedThis(JSContext
* cx
) {
5180 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
5181 JSMSG_UNINITIALIZED_THIS
);
5185 bool js::ThrowInitializedThis(JSContext
* cx
) {
5186 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_REINIT_THIS
);
5190 bool js::ThrowObjectCoercible(JSContext
* cx
, HandleValue value
) {
5191 MOZ_ASSERT(value
.isNullOrUndefined());
5192 ReportIsNullOrUndefinedForPropertyAccess(cx
, value
, JSDVG_SEARCH_STACK
);
5196 bool js::SetPropertySuper(JSContext
* cx
, HandleValue lval
, HandleValue receiver
,
5197 Handle
<PropertyName
*> name
, HandleValue rval
,
5199 MOZ_ASSERT(lval
.isObjectOrNull());
5201 RootedObject
obj(cx
, ToObjectFromStackForPropertyAccess(
5202 cx
, lval
, JSDVG_SEARCH_STACK
, name
));
5207 RootedId
id(cx
, NameToId(name
));
5208 return SetObjectElementOperation(cx
, obj
, id
, rval
, receiver
, strict
);
5211 bool js::SetElementSuper(JSContext
* cx
, HandleValue lval
, HandleValue receiver
,
5212 HandleValue index
, HandleValue rval
, bool strict
) {
5213 MOZ_ASSERT(lval
.isObjectOrNull());
5215 RootedObject
obj(cx
, ToObjectFromStackForPropertyAccess(
5216 cx
, lval
, JSDVG_SEARCH_STACK
, index
));
5221 return SetObjectElementWithReceiver(cx
, obj
, index
, rval
, receiver
, strict
);
5224 bool js::LoadAliasedDebugVar(JSContext
* cx
, JSObject
* env
, jsbytecode
* pc
,
5225 MutableHandleValue result
) {
5226 EnvironmentCoordinate
ec(pc
);
5228 for (unsigned i
= ec
.hops(); i
; i
--) {
5229 if (env
->is
<EnvironmentObject
>()) {
5230 env
= &env
->as
<EnvironmentObject
>().enclosingEnvironment();
5232 MOZ_ASSERT(env
->is
<DebugEnvironmentProxy
>());
5233 env
= &env
->as
<DebugEnvironmentProxy
>().enclosingEnvironment();
5237 EnvironmentObject
& finalEnv
=
5238 env
->is
<EnvironmentObject
>()
5239 ? env
->as
<EnvironmentObject
>()
5240 : env
->as
<DebugEnvironmentProxy
>().environment();
5242 result
.set(finalEnv
.aliasedBinding(ec
));
5246 // https://tc39.es/ecma262/#sec-iteratorclose
5247 bool js::CloseIterOperation(JSContext
* cx
, HandleObject iter
,
5248 CompletionKind kind
) {
5249 // Steps 1-2 are implicit.
5252 RootedValue
returnMethod(cx
);
5254 GetProperty(cx
, iter
, iter
, cx
->names().return_
, &returnMethod
);
5257 RootedValue
result(cx
);
5260 if (returnMethod
.isNullOrUndefined()) {
5264 if (IsCallable(returnMethod
)) {
5265 RootedValue
thisVal(cx
, ObjectValue(*iter
));
5266 innerResult
= Call(cx
, returnMethod
, thisVal
, &result
);
5268 innerResult
= ReportIsNotFunction(cx
, returnMethod
);
5273 if (kind
== CompletionKind::Throw
) {
5274 // If we close an iterator while unwinding for an exception,
5275 // the initial exception takes priority over any exception thrown
5276 // while closing the iterator.
5277 if (cx
->isExceptionPending()) {
5278 cx
->clearPendingException();
5289 if (!result
.isObject()) {
5290 return ThrowCheckIsObject(cx
, CheckIsObjectKind::IteratorReturn
);