Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / Interpreter.cpp
blob4a855bae33742eceb5e11c48eef4b1ae0c57cbc4
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * JavaScript bytecode interpreter.
9 */
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"
21 #include <string.h>
23 #include "jsapi.h"
24 #include "jslibmath.h"
25 #include "jsmath.h"
26 #include "jsnum.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"
33 #include "gc/GC.h"
34 #include "jit/AtomicOperations.h"
35 #include "jit/BaselineJIT.h"
36 #include "jit/Jit.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"
58 #include "vm/PIC.h"
59 #include "vm/PlainObject.h" // js::PlainObject
60 #include "vm/Scope.h"
61 #include "vm/Shape.h"
62 #include "vm/SharedStencil.h" // GCThingIndex
63 #include "vm/StringType.h"
64 #include "vm/ThrowMsgKind.h" // ThrowMsgKind
65 #include "vm/Time.h"
66 #ifdef ENABLE_RECORD_TUPLE
67 # include "vm/RecordType.h"
68 # include "vm/TupleType.h"
69 #endif
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"
83 using namespace js;
85 using mozilla::DebugOnly;
86 using mozilla::NumberEqualsInt32;
88 using js::jit::JitScript;
90 template <bool Eq>
91 static MOZ_ALWAYS_INLINE bool LooseEqualityOp(JSContext* cx,
92 InterpreterRegs& regs) {
93 HandleValue rval = regs.stackHandleAt(-1);
94 HandleValue lval = regs.stackHandleAt(-2);
95 bool cond;
96 if (!LooselyEqual(cx, lval, rval, &cond)) {
97 return false;
99 cond = (cond == Eq);
100 regs.sp--;
101 regs.sp[-1].setBoolean(cond);
102 return true;
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());
126 return true;
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
140 // Loader.
141 if (frame.script()->hasNonSyntacticScope() && thisv.isNullOrUndefined()) {
142 RootedObject env(cx, frame.environmentChain());
143 while (true) {
144 if (IsNSVOLexicalEnvironment(env) || IsGlobalLexicalEnvironment(env)) {
145 res.setObject(*GetThisObjectOfLexical(env));
146 return true;
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));
153 return true;
155 env = env->enclosingEnvironment();
159 JSObject* obj = BoxNonStrictThis(cx, thisv);
160 if (!obj) {
161 return false;
164 res.setObject(*obj);
165 return true;
168 void js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain,
169 MutableHandleValue res) {
170 RootedObject env(cx, envChain);
171 while (true) {
172 if (IsExtensibleLexicalEnvironment(env)) {
173 res.setObject(*GetThisObjectOfLexical(env));
174 return;
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));
181 return;
183 env = env->enclosingEnvironment();
187 #ifdef DEBUG
188 static bool IsSelfHostedOrKnownBuiltinCtor(JSFunction* fun, JSContext* cx) {
189 if (fun->isSelfHostedOrIntrinsic()) {
190 return true;
193 // GetBuiltinConstructor in MapGroupBy
194 if (fun == cx->global()->maybeGetConstructor(JSProto_Map)) {
195 return true;
198 // GetBuiltinConstructor in intlFallbackSymbol
199 if (fun == cx->global()->maybeGetConstructor(JSProto_Symbol)) {
200 return true;
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)) {
215 return true;
218 return false;
220 #endif // DEBUG
222 bool js::Debug_CheckSelfHosted(JSContext* cx, HandleValue funVal) {
223 #ifdef DEBUG
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 "
228 "constructor");
229 #else
230 MOZ_CRASH("self-hosted checks should only be done in Debug builds");
231 #endif
233 // This is purely to police self-hosted code. There is no actual operation.
234 return true;
237 static inline bool GetPropertyOperation(JSContext* cx,
238 Handle<PropertyName*> name,
239 HandleValue lval,
240 MutableHandleValue vp) {
241 if (name == cx->names().length && GetLengthProperty(lval, vp)) {
242 return true;
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));
263 PropertyResult prop;
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);
277 return false;
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);
287 return nullptr;
290 static bool MaybeCreateThisForConstructor(JSContext* cx, const CallArgs& args) {
291 if (args.thisv().isObject()) {
292 return true;
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())) {
301 return false;
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)) {
320 return false;
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]);
329 // Step 4.c.ii.1.
330 if (MOZ_UNLIKELY(!GetProperty(cx, obj, obj, propKey, &propValue))) {
331 return false;
334 if (MOZ_UNLIKELY(!rec->initializeNextProperty(cx, propKey, propValue))) {
335 return false;
339 return true;
341 #endif
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_,
349 evalInFrame_);
352 InterpreterFrame* RunState::pushInterpreterFrame(JSContext* cx) {
353 if (isInvoke()) {
354 return asInvoke()->pushInterpreterFrame(cx);
356 return asExecute()->pushInterpreterFrame(cx);
359 static MOZ_ALWAYS_INLINE bool MaybeEnterInterpreterTrampoline(JSContext* cx,
360 RunState& state) {
361 #ifdef NIGHTLY_BUILD
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);
369 if (p) {
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)) {
375 return false;
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);
385 #endif
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
391 // avoid this.
392 #ifdef _MSC_VER
393 # pragma optimize("g", off)
394 #endif
395 bool js::RunScript(JSContext* cx, RunState& state) {
396 AutoCheckRecursionLimit recursion(cx);
397 if (!recursion.check(cx)) {
398 return false;
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())) {
413 return false;
416 GeckoProfilerEntryMarker marker(cx, state.script());
418 bool measuringTime = !cx->isMeasuringExecutionTime();
419 mozilla::TimeStamp startTime;
420 if (measuringTime) {
421 cx->setIsMeasuringExecutionTime(true);
422 cx->setIsExecuting(true);
423 startTime = mozilla::TimeStamp::Now();
425 auto timerEnd = mozilla::MakeScopeExit([&]() {
426 if (measuringTime) {
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);
435 switch (status) {
436 case jit::EnterJitStatus::Error:
437 return false;
438 case jit::EnterJitStatus::Ok:
439 return true;
440 case jit::EnterJitStatus::NotEntered:
441 break;
444 bool ok = MaybeEnterInterpreterTrampoline(cx, state);
446 return ok;
448 #ifdef _MSC_VER
449 # pragma optimize("", on)
450 #endif
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)) {
457 return false;
460 NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
461 if (resumeMode != NativeResumeMode::Continue) {
462 return resumeMode == NativeResumeMode::Override;
465 #ifdef DEBUG
466 bool alreadyThrowing = cx->isExceptionPending();
467 #endif
468 cx->check(args);
469 MOZ_ASSERT(!args.callee().is<ProxyObject>());
471 AutoRealm ar(cx, &args.callee());
472 bool ok = native(cx, args.length(), args.base());
473 if (ok) {
474 cx->check(args.rval());
475 MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
477 return ok;
480 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
481 MOZ_ALWAYS_INLINE bool CallJSNativeConstructor(JSContext* cx, Native native,
482 const CallArgs& args) {
483 #ifdef DEBUG
484 RootedObject callee(cx, &args.callee());
485 #endif
487 MOZ_ASSERT(args.thisv().isMagic());
488 if (!CallJSNative(cx, native, CallReason::Call, args)) {
489 return false;
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.
499 * Exceptions:
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
505 * happen.
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));
513 return true;
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
524 * this step already!
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)) {
578 return false;
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)) {
588 return false;
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);
595 return false;
598 bool ok = RunScript(cx, state);
600 MOZ_ASSERT_IF(ok && construct, args.rval().isObject());
601 return ok;
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>()) {
610 return true;
612 JSFunction& fun = callee.toObject().as<JSFunction>();
613 if (!fun.isNativeFun() || !fun.hasJitInfo()) {
614 return true;
616 return fun.jitInfo()->needsOuterizedThisObject();
619 static bool InternalCall(JSContext* cx, const AnyInvokeArgs& args,
620 CallReason reason) {
621 MOZ_ASSERT(args.array() + args.length() == args.end(),
622 "must pass calling arguments to a calling attempt");
624 #ifdef DEBUG
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);
631 #endif
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
642 // 7.3.12 Call.
643 bool js::Call(JSContext* cx, HandleValue fval, HandleValue thisv,
644 const AnyInvokeArgs& args, MutableHandleValue rval,
645 CallReason reason) {
646 // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
647 // shadowing.
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));
659 } else {
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)) {
666 return false;
669 rval.set(args.rval());
670 return true;
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)) {
698 return false;
701 MOZ_ASSERT(args.CallArgs::rval().isObject());
702 return true;
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,
718 HandleValue callee,
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,
723 nullptr);
724 return false;
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));
731 return true;
734 bool js::ConstructFromStack(JSContext* cx, const CallArgs& args,
735 CallReason reason /* CallReason::Call */) {
736 if (!StackCheckIsConstructorCalleeNewTarget(cx, args.calleev(),
737 args.newTarget())) {
738 return false;
741 return InternalConstruct(cx, static_cast<const AnyConstructArgs&>(args),
742 reason);
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)) {
755 return false;
758 MOZ_ASSERT(args.CallArgs::rval().isObject());
759 objp.set(&args.CallArgs::rval().toObject());
760 return true;
763 bool js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
764 HandleValue thisv,
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)) {
776 return false;
779 rval.set(args.CallArgs::rval());
780 return true;
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,
791 HandleValue v) {
792 FixedInvokeArgs<1> args(cx);
793 args[0].set(v);
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));
805 #ifdef DEBUG
806 RootedObject terminatingEnv(cx, envChainArg);
807 while (IsSyntacticEnvironment(terminatingEnv)) {
808 terminatingEnv = terminatingEnv->enclosingEnvironment();
810 MOZ_ASSERT(terminatingEnv->is<GlobalObject>() ||
811 script->hasNonSyntacticScope());
812 #endif
814 if (script->treatAsRunOnce()) {
815 if (script->hasRunOnce()) {
816 JS_ReportErrorASCII(cx,
817 "Trying to execute a run-once script multiple times");
818 return false;
821 script->setHasRunOnce();
824 if (script->isEmpty()) {
825 result.setUndefined();
826 return true;
829 probes::StartExecution(script);
830 ExecuteState state(cx, script, envChainArg, evalInFrame, result);
831 bool ok = RunScript(cx, state);
832 probes::StopExecution(script);
834 return ok;
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()) {
844 MOZ_RELEASE_ASSERT(
845 envChain == script->module()->environment(),
846 "Module scripts can only be executed in the module's environment");
847 } else {
848 MOZ_RELEASE_ASSERT(
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. */
855 #ifdef DEBUG
856 JSObject* s = envChain;
857 do {
858 cx->check(s);
859 MOZ_ASSERT_IF(!s->enclosingEnvironment(), s->is<GlobalObject>());
860 } while ((s = s->enclosingEnvironment()));
861 #endif
863 return ExecuteKernel(cx, script, envChain, NullFramePtr() /* evalInFrame */,
864 rval);
868 * ES6 (4-25-16) 12.10.4 InstanceofOperator
870 bool js::InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v,
871 bool* bp) {
872 /* Step 1. is handled by caller. */
874 /* Step 2. */
875 RootedValue hasInstance(cx);
876 RootedId id(cx, PropertyKey::Symbol(cx->wellKnownSymbols().hasInstance));
877 if (!GetProperty(cx, obj, obj, id, &hasInstance)) {
878 return false;
881 if (!hasInstance.isNullOrUndefined()) {
882 if (!IsCallable(hasInstance)) {
883 return ReportIsNotFunction(cx, hasInstance);
886 /* Step 3. */
887 RootedValue rval(cx);
888 if (!Call(cx, hasInstance, obj, v, &rval)) {
889 return false;
891 *bp = ToBoolean(rval);
892 return true;
895 /* Step 4. */
896 if (!obj->isCallable()) {
897 RootedValue val(cx, ObjectValue(*obj));
898 return ReportIsNotFunction(cx, val);
901 /* Step 5. */
902 return OrdinaryHasInstance(cx, obj, v, bp);
905 JSType js::TypeOfObject(JSObject* obj) {
906 #ifdef ENABLE_RECORD_TUPLE
907 MOZ_ASSERT(!js::IsExtendedPrimitive(*obj));
908 #endif
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>()) {
928 return JSTYPE_TUPLE;
930 MOZ_CRASH("Unknown ExtendedPrimitive");
932 #endif
934 JSType js::TypeOfValue(const Value& v) {
935 switch (v.type()) {
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());
950 #endif
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:
959 break;
962 ReportBadValueTypeAndCrash(v);
965 bool js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage) {
966 if (IsConstructor(heritage)) {
967 return true;
970 if (heritage.isNull()) {
971 return true;
974 if (heritage.isObject()) {
975 ReportIsNotFunction(cx, heritage, 0, CONSTRUCT);
976 return false;
979 ReportValueError(cx, JSMSG_BAD_HERITAGE, -1, heritage, nullptr,
980 "not an object or null");
981 return false;
984 PlainObject* js::ObjectWithProtoOperation(JSContext* cx, HandleValue val) {
985 if (!val.isObjectOrNull()) {
986 ReportValueError(cx, JSMSG_NOT_OBJORNULL, -1, val, nullptr);
987 return 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();
1008 } else {
1009 obj = ToObject(cx, val);
1010 if (!obj) {
1011 return false;
1015 RootedObject envChain(cx, frame.environmentChain());
1016 WithEnvironmentObject* withobj =
1017 WithEnvironmentObject::create(cx, obj, envChain, scope);
1018 if (!withobj) {
1019 return false;
1022 frame.pushOnEnvironmentChain(*withobj);
1023 return true;
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()) {
1039 ei.initialFrame()
1040 .popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
1042 break;
1043 case ScopeKind::With:
1044 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1045 DebugEnvironments::onPopWith(ei.initialFrame());
1047 ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
1048 break;
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>();
1056 break;
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>();
1065 break;
1066 case ScopeKind::Module:
1067 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1068 DebugEnvironments::onPopModule(cx, ei);
1070 break;
1071 case ScopeKind::Eval:
1072 case ScopeKind::Global:
1073 case ScopeKind::NonSyntactic:
1074 break;
1075 case ScopeKind::WasmInstance:
1076 case ScopeKind::WasmFunction:
1077 MOZ_CRASH("wasm is not interpreted");
1078 break;
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()) {
1086 return;
1089 Rooted<Scope*> scope(cx, ei.initialFrame().script()->innermostScope(pc));
1091 #ifdef DEBUG
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
1096 // of the frame.
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)));
1104 #endif
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
1131 // let block scope.
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);
1141 return pc;
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_;
1158 public:
1159 explicit InterpreterTryNoteFilter(const InterpreterRegs& regs)
1160 : regs_(regs) {}
1161 bool operator()(const TryNote* note) {
1162 return note->stackDepth <= regs_.stackDepth();
1166 class TryNoteIterInterpreter : public TryNoteIter<InterpreterTryNoteFilter> {
1167 public:
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
1176 // ProcessTryNotes.
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());
1183 break;
1185 default:
1186 break;
1191 enum HandleErrorContinuation {
1192 SuccessfulReturnContinuation,
1193 ErrorReturnContinuation,
1194 CatchContinuation,
1195 FinallyContinuation
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()) {
1208 break;
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();
1223 CloseIterator(obj);
1224 break;
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);
1235 if (!done) {
1236 RootedObject iterObject(cx, &sp[-2].toObject());
1237 if (!IteratorCloseForException(cx, iterObject)) {
1238 SettleOnTryNote(cx, tn, ei, regs);
1239 return ErrorReturnContinuation;
1242 break;
1245 case TryNoteKind::ForOf:
1246 case TryNoteKind::Loop:
1247 break;
1249 // TryNoteKind::ForOfIterClose is handled internally by the try note
1250 // iterator.
1251 default:
1252 MOZ_CRASH("Invalid try note");
1256 return SuccessfulReturnContinuation;
1259 bool js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
1260 bool ok) {
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();
1267 ok = true;
1268 auto* genObj = GetGeneratorObjectForFrame(cx, frame);
1269 genObj->setClosed();
1271 return ok;
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.
1283 if (counts) {
1284 counts->numExec()++;
1288 EnvironmentIter ei(cx, regs.fp(), regs.pc);
1289 bool ok = false;
1291 again:
1292 if (cx->isExceptionPending()) {
1293 /* Call debugger throw hooks. */
1294 if (!cx->isClosingGenerator()) {
1295 if (!DebugAPI::onExceptionUnwind(cx, regs.fp())) {
1296 if (!cx->isExceptionPending()) {
1297 goto again;
1300 // Ensure that the debugger hasn't returned 'true' while clearing the
1301 // exception state.
1302 MOZ_ASSERT(cx->isExceptionPending());
1305 HandleErrorContinuation res = ProcessTryNotes(cx, ei, regs);
1306 switch (res) {
1307 case SuccessfulReturnContinuation:
1308 break;
1309 case ErrorReturnContinuation:
1310 goto again;
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));
1317 return res;
1320 ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
1321 } else {
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();
1327 ok = true;
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) \
1342 do { \
1343 *REGS.sp++ = (v); \
1344 cx->debugOnlyCheck(REGS.sp[-1]); \
1345 } while (0)
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) \
1355 do { \
1356 REGS.sp++->setString(s); \
1357 cx->debugOnlyCheck(REGS.sp[-1]); \
1358 } while (0)
1359 #define PUSH_OBJECT(obj) \
1360 do { \
1361 REGS.sp++->setObject(obj); \
1362 cx->debugOnlyCheck(REGS.sp[-1]); \
1363 } while (0)
1364 #define PUSH_OBJECT_OR_NULL(obj) \
1365 do { \
1366 REGS.sp++->setObjectOrNull(obj); \
1367 cx->debugOnlyCheck(REGS.sp[-1]); \
1368 } while (0)
1369 #ifdef ENABLE_RECORD_TUPLE
1370 # define PUSH_EXTENDED_PRIMITIVE(obj) \
1371 do { \
1372 REGS.sp++->setExtendedPrimitive(obj); \
1373 cx->debugOnlyCheck(REGS.sp[-1]); \
1374 } while (0)
1375 #endif
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.
1438 // Step 3.
1439 if (lhs.isString() && rhs.isString()) {
1440 JSString* l = lhs.toString();
1441 JSString* r = rhs.toString();
1442 int32_t result;
1443 if (!CompareStrings(cx, l, r, &result)) {
1444 return false;
1446 res = mozilla::Some(result < 0);
1447 return true;
1450 // Step 4a.
1451 if (lhs.isBigInt() && rhs.isString()) {
1452 return BigInt::lessThan(cx, lhs, rhs, res);
1455 // Step 4b.
1456 if (lhs.isString() && rhs.isBigInt()) {
1457 return BigInt::lessThan(cx, lhs, rhs, res);
1460 // Steps 4c and 4d.
1461 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1462 return false;
1465 // Steps 4e-j.
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());
1477 return true;
1480 res = mozilla::Some(lhsNum < rhsNum);
1481 return true;
1484 static MOZ_ALWAYS_INLINE bool LessThanOperation(JSContext* cx,
1485 MutableHandleValue lhs,
1486 MutableHandleValue rhs,
1487 bool* res) {
1488 if (lhs.isInt32() && rhs.isInt32()) {
1489 *res = lhs.toInt32() < rhs.toInt32();
1490 return true;
1493 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1494 return false;
1497 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1498 return false;
1501 mozilla::Maybe<bool> tmpResult;
1502 if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1503 return false;
1505 *res = tmpResult.valueOr(false);
1506 return true;
1509 static MOZ_ALWAYS_INLINE bool LessThanOrEqualOperation(JSContext* cx,
1510 MutableHandleValue lhs,
1511 MutableHandleValue rhs,
1512 bool* res) {
1513 if (lhs.isInt32() && rhs.isInt32()) {
1514 *res = lhs.toInt32() <= rhs.toInt32();
1515 return true;
1518 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1519 return false;
1522 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1523 return false;
1526 mozilla::Maybe<bool> tmpResult;
1527 if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1528 return false;
1530 *res = !tmpResult.valueOr(true);
1531 return true;
1534 static MOZ_ALWAYS_INLINE bool GreaterThanOperation(JSContext* cx,
1535 MutableHandleValue lhs,
1536 MutableHandleValue rhs,
1537 bool* res) {
1538 if (lhs.isInt32() && rhs.isInt32()) {
1539 *res = lhs.toInt32() > rhs.toInt32();
1540 return true;
1543 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1544 return false;
1547 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1548 return false;
1551 mozilla::Maybe<bool> tmpResult;
1552 if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1553 return false;
1555 *res = tmpResult.valueOr(false);
1556 return true;
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();
1563 return true;
1566 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1567 return false;
1570 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1571 return false;
1574 mozilla::Maybe<bool> tmpResult;
1575 if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1576 return false;
1578 *res = !tmpResult.valueOr(true);
1579 return 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,
1591 HandleValue rref) {
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)) {
1599 return nullptr;
1601 if (!buf.append("...")) {
1602 return nullptr;
1604 str = buf.finishString();
1605 if (!str) {
1606 return nullptr;
1609 return QuoteString(cx, str, '"');
1612 if (lref.isString() && rref.isString()) {
1613 UniqueChars lbytes = uniqueCharsFromString(cx, lref);
1614 if (!lbytes) {
1615 return;
1617 UniqueChars rbytes = uniqueCharsFromString(cx, rref);
1618 if (!rbytes) {
1619 return;
1621 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_IN_STRING,
1622 lbytes.get(), rbytes.get());
1623 return;
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,
1631 RunState& state) {
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:
1639 #define DEFAULT() \
1640 label_default:
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)
1650 #undef OPCODE_LABEL
1651 #define TRAILING_LABEL(v) \
1652 ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
1653 : LABEL(default)),
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) \
1675 JS_BEGIN_MACRO \
1676 REGS.pc += (N); \
1677 SANITY_CHECKS(); \
1678 DISPATCH_TO(*REGS.pc | activation.opMask()); \
1679 JS_END_MACRO
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() \
1691 JS_BEGIN_MACRO \
1692 if (!CheckForInterrupt(cx)) goto error; \
1693 JS_END_MACRO
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.
1700 #define BRANCH(n) \
1701 JS_BEGIN_MACRO \
1702 int32_t nlen = (n); \
1703 if (nlen <= 0) CHECK_BRANCH(); \
1704 ADVANCE_AND_DISPATCH(nlen); \
1705 JS_END_MACRO
1708 * Initialize code coverage vectors.
1710 #define INIT_COVERAGE() \
1711 JS_BEGIN_MACRO \
1712 if (!script->hasScriptCounts()) { \
1713 if (cx->realm()->collectCoverageForDebug()) { \
1714 if (!script->initScriptCounts(cx)) goto error; \
1717 JS_END_MACRO
1720 * Increment the code coverage counter associated with the given pc.
1722 #define COUNT_COVERAGE_PC(PC) \
1723 JS_BEGIN_MACRO \
1724 if (script->hasScriptCounts()) { \
1725 PCCounts* counts = script->maybeGetPCCounts(PC); \
1726 MOZ_ASSERT(counts); \
1727 counts->numExec()++; \
1729 JS_END_MACRO
1731 #define COUNT_COVERAGE_MAIN() \
1732 JS_BEGIN_MACRO \
1733 jsbytecode* main = script->main(); \
1734 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
1735 JS_END_MACRO
1737 #define COUNT_COVERAGE() \
1738 JS_BEGIN_MACRO \
1739 MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
1740 COUNT_COVERAGE_PC(REGS.pc); \
1741 JS_END_MACRO
1743 #define SET_SCRIPT(s) \
1744 JS_BEGIN_MACRO \
1745 script = (s); \
1746 MOZ_ASSERT(cx->realm() == script->realm()); \
1747 if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
1748 script->hasScriptCounts()) \
1749 activation.enableInterruptsUnconditionally(); \
1750 JS_END_MACRO
1752 #define SANITY_CHECKS() \
1753 JS_BEGIN_MACRO \
1754 js::gc::MaybeVerifyBarriers(cx); \
1755 JS_END_MACRO
1757 // Verify that an uninitialized lexical is followed by a correct check op.
1758 #ifdef DEBUG
1759 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
1760 JS_BEGIN_MACRO \
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); \
1767 JS_END_MACRO
1768 #else
1769 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
1770 JS_BEGIN_MACRO \
1771 /* nothing */ \
1772 JS_END_MACRO
1773 #endif
1775 gc::MaybeVerifyBarriers(cx, true);
1777 InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
1778 if (!entryFrame) {
1779 return false;
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())) {
1815 goto error;
1818 // Increment the coverage for the main entry point.
1819 INIT_COVERAGE();
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)) {
1833 goto error;
1837 if (script->isDebuggee()) {
1838 if (DebugAPI::stepModeEnabled(script)) {
1839 if (!DebugAPI::onSingleStep(cx)) {
1840 goto error;
1842 moreInterrupts = true;
1845 if (DebugAPI::hasAnyBreakpointsOrStepMode(script)) {
1846 moreInterrupts = true;
1849 if (DebugAPI::hasBreakpointsAt(script, REGS.pc)) {
1850 if (!DebugAPI::onTrap(cx)) {
1851 goto error;
1856 MOZ_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
1857 if (!moreInterrupts) {
1858 activation.clearInterruptsMask();
1861 /* Commence executing the actual opcode. */
1862 SANITY_CHECKS();
1863 DISPATCH_TO(op);
1866 /* Various 1-byte no-ops. */
1867 CASE(Nop)
1868 CASE(Try)
1869 CASE(NopDestructuring)
1870 CASE(NopIsAssignOp)
1871 CASE(TryDestructuring) {
1872 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);
1873 ADVANCE_AND_DISPATCH(1);
1876 CASE(JumpTarget)
1877 COUNT_COVERAGE();
1878 END_CASE(JumpTarget)
1880 CASE(LoopHead) {
1881 COUNT_COVERAGE();
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) {
1890 goto error;
1892 if (status == jit::Method_Compiled) {
1893 bool wasProfiler = REGS.fp()->hasPushedGeckoProfilerFrame();
1895 jit::JitExecStatus maybeOsr;
1897 GeckoProfilerBaselineOSRMarker osr(cx, wasProfiler);
1898 maybeOsr =
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) {
1904 goto error;
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
1911 // OSR trampoline.)
1912 if (wasProfiler) {
1913 cx->geckoProfiler().exit(cx, script);
1916 if (activation.entryFrame() != REGS.fp()) {
1917 goto jit_return_pop_frame;
1919 goto leave_on_safe_point;
1923 END_CASE(LoopHead)
1925 CASE(Lineno)
1926 END_CASE(Lineno)
1928 CASE(ForceInterpreter) {
1929 // Ensure pattern matching still works.
1930 MOZ_ASSERT(script->hasForceInterpreterOp());
1932 END_CASE(ForceInterpreter)
1934 CASE(Undefined) { PUSH_UNDEFINED(); }
1935 END_CASE(Undefined)
1937 CASE(Pop) { REGS.sp--; }
1938 END_CASE(Pop)
1940 CASE(PopN) {
1941 MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
1942 REGS.sp -= GET_UINT16(REGS.pc);
1944 END_CASE(PopN)
1946 CASE(DupAt) {
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)];
1950 PUSH_COPY(rref);
1952 END_CASE(DupAt)
1954 CASE(SetRval) { POP_RETURN_VALUE(); }
1955 END_CASE(SetRval)
1957 CASE(GetRval) { PUSH_COPY(REGS.fp()->returnValue()); }
1958 END_CASE(GetRval)
1960 CASE(EnterWith) {
1961 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
1962 REGS.sp--;
1963 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
1965 if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>())) {
1966 goto error;
1969 END_CASE(EnterWith)
1971 CASE(LeaveWith) {
1972 REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
1974 END_CASE(LeaveWith)
1976 CASE(Return) {
1977 POP_RETURN_VALUE();
1978 /* FALL THROUGH */
1980 CASE(RetRval) {
1982 * When the inlined frame exits with an exception or an error, ok will be
1983 * false after the inline_return label.
1985 CHECK_BRANCH();
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)) {
1999 interpReturnOK =
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);
2016 jit_return:
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);
2031 goto error;
2032 } else {
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()));
2039 goto exit;
2042 CASE(Default) {
2043 REGS.sp--;
2044 /* FALL THROUGH */
2046 CASE(Goto) { BRANCH(GET_JUMP_OFFSET(REGS.pc)); }
2048 CASE(JumpIfFalse) {
2049 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2050 REGS.sp--;
2051 if (!cond) {
2052 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2055 END_CASE(JumpIfFalse)
2057 CASE(JumpIfTrue) {
2058 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2059 REGS.sp--;
2060 if (cond) {
2061 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2064 END_CASE(JumpIfTrue)
2066 CASE(Or) {
2067 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2068 if (cond) {
2069 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2072 END_CASE(Or)
2074 CASE(Coalesce) {
2075 MutableHandleValue res = REGS.stackHandleAt(-1);
2076 bool cond = !res.isNullOrUndefined();
2077 if (cond) {
2078 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2081 END_CASE(Coalesce)
2083 CASE(And) {
2084 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2085 if (!cond) {
2086 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2089 END_CASE(And)
2091 #define FETCH_ELEMENT_ID(n, id) \
2092 JS_BEGIN_MACRO \
2093 if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
2094 JS_END_MACRO
2096 #define TRY_BRANCH_AFTER_COND(cond, spdec) \
2097 JS_BEGIN_MACRO \
2098 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1); \
2099 unsigned diff_ = \
2100 (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
2101 if (diff_ <= 1) { \
2102 REGS.sp -= (spdec); \
2103 if ((cond) == (diff_ != 0)) { \
2104 ++REGS.pc; \
2105 BRANCH(GET_JUMP_OFFSET(REGS.pc)); \
2107 ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse); \
2109 JS_END_MACRO
2111 CASE(In) {
2112 HandleValue rref = REGS.stackHandleAt(-1);
2113 if (!rref.isObject()) {
2114 HandleValue lref = REGS.stackHandleAt(-2);
2115 ReportInNotObjectError(cx, lref, rref);
2116 goto error;
2118 bool found;
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)) {
2124 goto error;
2127 TRY_BRANCH_AFTER_COND(found, 2);
2128 REGS.sp--;
2129 REGS.sp[-1].setBoolean(found);
2131 END_CASE(In)
2133 CASE(HasOwn) {
2134 HandleValue val = REGS.stackHandleAt(-1);
2135 HandleValue idval = REGS.stackHandleAt(-2);
2137 bool found;
2138 if (!HasOwnProperty(cx, val, idval, &found)) {
2139 goto error;
2142 REGS.sp--;
2143 REGS.sp[-1].setBoolean(found);
2145 END_CASE(HasOwn)
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)) {
2154 goto error;
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);
2165 if (!symbol) {
2166 goto error;
2169 PUSH_SYMBOL(symbol);
2171 END_CASE(NewPrivateName)
2173 CASE(IsNullOrUndefined) {
2174 bool b = REGS.sp[-1].isNullOrUndefined();
2175 PUSH_BOOLEAN(b);
2177 END_CASE(IsNullOrUndefined)
2179 CASE(Iter) {
2180 MOZ_ASSERT(REGS.stackDepth() >= 1);
2181 HandleValue val = REGS.stackHandleAt(-1);
2182 JSObject* iter = ValueToIterator(cx, val);
2183 if (!iter) {
2184 goto error;
2186 REGS.sp[-1].setObject(*iter);
2188 END_CASE(Iter)
2190 CASE(MoreIter) {
2191 MOZ_ASSERT(REGS.stackDepth() >= 1);
2192 MOZ_ASSERT(REGS.sp[-1].isObject());
2193 Value v = IteratorMore(&REGS.sp[-1].toObject());
2194 PUSH_COPY(v);
2196 END_CASE(MoreIter)
2198 CASE(IsNoIter) {
2199 bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
2200 PUSH_BOOLEAN(b);
2202 END_CASE(IsNoIter)
2204 CASE(EndIter) {
2205 MOZ_ASSERT(REGS.stackDepth() >= 2);
2206 CloseIterator(&REGS.sp[-2].toObject());
2207 REGS.sp -= 2;
2209 END_CASE(EndIter)
2211 CASE(CloseIter) {
2212 ReservedRooted<JSObject*> iter(&rootObject0, &REGS.sp[-1].toObject());
2213 CompletionKind kind = CompletionKind(GET_UINT8(REGS.pc));
2214 if (!CloseIterOperation(cx, iter, kind)) {
2215 goto error;
2217 REGS.sp--;
2219 END_CASE(CloseIter)
2221 CASE(OptimizeGetIterator) {
2222 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
2223 MutableHandleValue rval = REGS.stackHandleAt(-1);
2224 bool result;
2225 if (!OptimizeGetIterator(cx, val, &result)) {
2226 goto error;
2228 rval.setBoolean(result);
2230 END_CASE(OptimizeGetIterator)
2232 CASE(IsGenClosing) {
2233 bool b = REGS.sp[-1].isMagic(JS_GENERATOR_CLOSING);
2234 PUSH_BOOLEAN(b);
2236 END_CASE(IsGenClosing)
2238 CASE(Dup) {
2239 MOZ_ASSERT(REGS.stackDepth() >= 1);
2240 const Value& rref = REGS.sp[-1];
2241 PUSH_COPY(rref);
2243 END_CASE(Dup)
2245 CASE(Dup2) {
2246 MOZ_ASSERT(REGS.stackDepth() >= 2);
2247 const Value& lref = REGS.sp[-2];
2248 const Value& rref = REGS.sp[-1];
2249 PUSH_COPY(lref);
2250 PUSH_COPY(rref);
2252 END_CASE(Dup2)
2254 CASE(Swap) {
2255 MOZ_ASSERT(REGS.stackDepth() >= 2);
2256 Value& lref = REGS.sp[-2];
2257 Value& rref = REGS.sp[-1];
2258 lref.swap(rref);
2260 END_CASE(Swap)
2262 CASE(Pick) {
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);
2267 REGS.sp[-1] = lval;
2269 END_CASE(Pick)
2271 CASE(Unpick) {
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;
2278 END_CASE(Unpick)
2280 CASE(BindGName)
2281 CASE(BindName) {
2282 JSOp op = JSOp(*REGS.pc);
2283 ReservedRooted<JSObject*> envChain(&rootObject0);
2284 if (op == JSOp::BindName) {
2285 envChain.set(REGS.fp()->environmentChain());
2286 } else {
2287 MOZ_ASSERT(!script->hasNonSyntacticScope());
2288 envChain.set(&REGS.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)) {
2295 goto error;
2298 PUSH_OBJECT(*env);
2300 static_assert(JSOpLength_BindName == JSOpLength_BindGName,
2301 "We're sharing the END_CASE so the lengths better match");
2303 END_CASE(BindName)
2305 CASE(BindVar) {
2306 JSObject* varObj = BindVarOperation(cx, REGS.fp()->environmentChain());
2307 PUSH_OBJECT(*varObj);
2309 END_CASE(BindVar)
2311 CASE(BitOr) {
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)) {
2316 goto error;
2318 REGS.sp--;
2320 END_CASE(BitOr)
2322 CASE(BitXor) {
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)) {
2327 goto error;
2329 REGS.sp--;
2331 END_CASE(BitXor)
2333 CASE(BitAnd) {
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)) {
2338 goto error;
2340 REGS.sp--;
2342 END_CASE(BitAnd)
2344 CASE(Eq) {
2345 if (!LooseEqualityOp<true>(cx, REGS)) {
2346 goto error;
2349 END_CASE(Eq)
2351 CASE(Ne) {
2352 if (!LooseEqualityOp<false>(cx, REGS)) {
2353 goto error;
2356 END_CASE(Ne)
2358 #define STRICT_EQUALITY_OP(OP, COND) \
2359 JS_BEGIN_MACRO \
2360 HandleValue lval = REGS.stackHandleAt(-2); \
2361 HandleValue rval = REGS.stackHandleAt(-1); \
2362 bool equal; \
2363 if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
2364 goto error; \
2366 (COND) = equal OP true; \
2367 REGS.sp--; \
2368 JS_END_MACRO
2370 CASE(StrictEq) {
2371 bool cond;
2372 STRICT_EQUALITY_OP(==, cond);
2373 REGS.sp[-1].setBoolean(cond);
2375 END_CASE(StrictEq)
2377 CASE(StrictNe) {
2378 bool cond;
2379 STRICT_EQUALITY_OP(!=, cond);
2380 REGS.sp[-1].setBoolean(cond);
2382 END_CASE(StrictNe)
2384 #undef STRICT_EQUALITY_OP
2386 CASE(Case) {
2387 bool cond = REGS.sp[-1].toBoolean();
2388 REGS.sp--;
2389 if (cond) {
2390 REGS.sp--;
2391 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2394 END_CASE(Case)
2396 CASE(Lt) {
2397 bool cond;
2398 MutableHandleValue lval = REGS.stackHandleAt(-2);
2399 MutableHandleValue rval = REGS.stackHandleAt(-1);
2400 if (!LessThanOperation(cx, lval, rval, &cond)) {
2401 goto error;
2403 TRY_BRANCH_AFTER_COND(cond, 2);
2404 REGS.sp[-2].setBoolean(cond);
2405 REGS.sp--;
2407 END_CASE(Lt)
2409 CASE(Le) {
2410 bool cond;
2411 MutableHandleValue lval = REGS.stackHandleAt(-2);
2412 MutableHandleValue rval = REGS.stackHandleAt(-1);
2413 if (!LessThanOrEqualOperation(cx, lval, rval, &cond)) {
2414 goto error;
2416 TRY_BRANCH_AFTER_COND(cond, 2);
2417 REGS.sp[-2].setBoolean(cond);
2418 REGS.sp--;
2420 END_CASE(Le)
2422 CASE(Gt) {
2423 bool cond;
2424 MutableHandleValue lval = REGS.stackHandleAt(-2);
2425 MutableHandleValue rval = REGS.stackHandleAt(-1);
2426 if (!GreaterThanOperation(cx, lval, rval, &cond)) {
2427 goto error;
2429 TRY_BRANCH_AFTER_COND(cond, 2);
2430 REGS.sp[-2].setBoolean(cond);
2431 REGS.sp--;
2433 END_CASE(Gt)
2435 CASE(Ge) {
2436 bool cond;
2437 MutableHandleValue lval = REGS.stackHandleAt(-2);
2438 MutableHandleValue rval = REGS.stackHandleAt(-1);
2439 if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond)) {
2440 goto error;
2442 TRY_BRANCH_AFTER_COND(cond, 2);
2443 REGS.sp[-2].setBoolean(cond);
2444 REGS.sp--;
2446 END_CASE(Ge)
2448 CASE(Lsh) {
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)) {
2453 goto error;
2455 REGS.sp--;
2457 END_CASE(Lsh)
2459 CASE(Rsh) {
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)) {
2464 goto error;
2466 REGS.sp--;
2468 END_CASE(Rsh)
2470 CASE(Ursh) {
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)) {
2475 goto error;
2477 REGS.sp--;
2479 END_CASE(Ursh)
2481 CASE(Add) {
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)) {
2486 goto error;
2488 REGS.sp--;
2490 END_CASE(Add)
2492 CASE(Sub) {
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)) {
2497 goto error;
2499 REGS.sp--;
2501 END_CASE(Sub)
2503 CASE(Mul) {
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)) {
2508 goto error;
2510 REGS.sp--;
2512 END_CASE(Mul)
2514 CASE(Div) {
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)) {
2519 goto error;
2521 REGS.sp--;
2523 END_CASE(Div)
2525 CASE(Mod) {
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)) {
2530 goto error;
2532 REGS.sp--;
2534 END_CASE(Mod)
2536 CASE(Pow) {
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)) {
2541 goto error;
2543 REGS.sp--;
2545 END_CASE(Pow)
2547 CASE(Not) {
2548 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2549 REGS.sp--;
2550 PUSH_BOOLEAN(!cond);
2552 END_CASE(Not)
2554 CASE(BitNot) {
2555 MutableHandleValue val = REGS.stackHandleAt(-1);
2556 if (!BitNotOperation(cx, val, val)) {
2557 goto error;
2560 END_CASE(BitNot)
2562 CASE(Neg) {
2563 MutableHandleValue val = REGS.stackHandleAt(-1);
2564 if (!NegOperation(cx, val, val)) {
2565 goto error;
2568 END_CASE(Neg)
2570 CASE(Pos) {
2571 if (!ToNumber(cx, REGS.stackHandleAt(-1))) {
2572 goto error;
2575 END_CASE(Pos)
2577 CASE(DelName) {
2578 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2579 ReservedRooted<JSObject*> envObj(&rootObject0,
2580 REGS.fp()->environmentChain());
2582 PUSH_BOOLEAN(true);
2583 MutableHandleValue res = REGS.stackHandleAt(-1);
2584 if (!DeleteNameOperation(cx, name, envObj, res)) {
2585 goto error;
2588 END_CASE(DelName)
2590 CASE(DelProp)
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));
2596 bool res = false;
2597 if (JSOp(*REGS.pc) == JSOp::StrictDelProp) {
2598 if (!DelPropOperation<true>(cx, val, name, &res)) {
2599 goto error;
2601 } else {
2602 if (!DelPropOperation<false>(cx, val, name, &res)) {
2603 goto error;
2606 REGS.sp[-1].setBoolean(res);
2608 END_CASE(DelProp)
2610 CASE(DelElem)
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);
2616 bool res = false;
2617 if (JSOp(*REGS.pc) == JSOp::StrictDelElem) {
2618 if (!DelElemOperation<true>(cx, val, propval, &res)) {
2619 goto error;
2621 } else {
2622 if (!DelElemOperation<false>(cx, val, propval, &res)) {
2623 goto error;
2626 REGS.sp[-2].setBoolean(res);
2627 REGS.sp--;
2629 END_CASE(DelElem)
2631 CASE(ToPropertyKey) {
2632 ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
2633 MutableHandleValue res = REGS.stackHandleAt(-1);
2634 if (!ToPropertyKeyOperation(cx, idval, res)) {
2635 goto error;
2638 END_CASE(ToPropertyKey)
2640 CASE(TypeofExpr)
2641 CASE(Typeof) {
2642 REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
2644 END_CASE(Typeof)
2646 CASE(Void) { REGS.sp[-1].setUndefined(); }
2647 END_CASE(Void)
2649 CASE(FunctionThis) {
2650 PUSH_NULL();
2651 if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1))) {
2652 goto error;
2655 END_CASE(FunctionThis)
2657 CASE(GlobalThis) {
2658 MOZ_ASSERT(!script->hasNonSyntacticScope());
2659 PUSH_OBJECT(*cx->global()->lexicalEnvironment().thisObject());
2661 END_CASE(GlobalThis)
2663 CASE(NonSyntacticGlobalThis) {
2664 PUSH_NULL();
2665 GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(),
2666 REGS.stackHandleAt(-1));
2668 END_CASE(NonSyntacticGlobalThis)
2670 CASE(CheckIsObj) {
2671 if (!REGS.sp[-1].isObject()) {
2672 MOZ_ALWAYS_FALSE(
2673 ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
2674 goto error;
2677 END_CASE(CheckIsObj)
2679 CASE(CheckThis) {
2680 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2681 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
2682 goto error;
2685 END_CASE(CheckThis)
2687 CASE(CheckThisReinit) {
2688 if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2689 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx));
2690 goto error;
2693 END_CASE(CheckThisReinit)
2695 CASE(CheckReturn) {
2696 ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-1]);
2697 MutableHandleValue rval = REGS.stackHandleAt(-1);
2698 if (!REGS.fp()->checkReturn(cx, thisv, rval)) {
2699 goto error;
2702 END_CASE(CheckReturn)
2704 CASE(GetProp) {
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)) {
2709 goto error;
2711 cx->debugOnlyCheck(res);
2713 END_CASE(GetProp)
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);
2724 if (!obj) {
2725 goto error;
2728 if (!GetProperty(cx, obj, receiver, name, rref)) {
2729 goto error;
2732 cx->debugOnlyCheck(rref);
2734 REGS.sp--;
2736 END_CASE(GetPropSuper)
2738 CASE(GetBoundName) {
2739 ReservedRooted<JSObject*> env(&rootObject0, &REGS.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)) {
2743 goto error;
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)) {
2753 goto error;
2756 END_CASE(SetIntrinsic)
2758 CASE(SetGName)
2759 CASE(StrictSetGName)
2760 CASE(SetName)
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, &REGS.sp[-2].toObject());
2770 HandleValue value = REGS.stackHandleAt(-1);
2772 if (!SetNameOperation(cx, script, REGS.pc, env, value)) {
2773 goto error;
2776 REGS.sp[-2] = REGS.sp[-1];
2777 REGS.sp--;
2779 END_CASE(SetName)
2781 CASE(SetProp)
2782 CASE(StrictSetProp) {
2783 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp,
2784 "setprop and strictsetprop must be the same size");
2785 int lvalIndex = -2;
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);
2795 if (!obj) {
2796 goto error;
2799 if (!SetObjectElementOperation(cx, obj, id, rval, lval, strict)) {
2800 goto error;
2803 REGS.sp[-2] = REGS.sp[-1];
2804 REGS.sp--;
2806 END_CASE(SetProp)
2808 CASE(SetPropSuper)
2809 CASE(StrictSetPropSuper) {
2810 static_assert(
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);
2824 if (!obj) {
2825 goto error;
2828 if (!SetObjectElementOperation(cx, obj, id, rval, receiver, strict)) {
2829 goto error;
2832 REGS.sp[-3] = REGS.sp[-1];
2833 REGS.sp -= 2;
2835 END_CASE(SetPropSuper)
2837 CASE(GetElem) {
2838 int lvalIndex = -2;
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)) {
2844 goto error;
2847 REGS.sp--;
2849 END_CASE(GetElem)
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);
2861 if (!obj) {
2862 goto error;
2865 if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, index,
2866 res)) {
2867 goto error;
2870 REGS.sp -= 2;
2872 END_CASE(GetElemSuper)
2874 CASE(SetElem)
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));
2885 if (!obj) {
2886 goto error;
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)) {
2894 goto error;
2896 REGS.sp[-3] = value;
2897 REGS.sp -= 2;
2899 END_CASE(SetElem)
2901 CASE(SetElemSuper)
2902 CASE(StrictSetElemSuper) {
2903 static_assert(
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));
2915 if (!obj) {
2916 goto error;
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)) {
2924 goto error;
2926 REGS.sp[-4] = value;
2927 REGS.sp -= 3;
2929 END_CASE(SetElemSuper)
2931 CASE(Eval)
2932 CASE(StrictEval) {
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())) {
2939 goto error;
2941 } else {
2942 if (!CallFromStack(cx, args, CallReason::Call)) {
2943 goto error;
2947 REGS.sp = args.spAfterCall();
2949 END_CASE(Eval)
2951 CASE(SpreadNew)
2952 CASE(SpreadCall)
2953 CASE(SpreadSuperCall) {
2954 if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
2955 cx->geckoProfiler().updatePC(cx, script, REGS.pc);
2957 /* FALL THROUGH */
2960 CASE(SpreadEval)
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;
2975 if (construct) {
2976 newTarget = REGS.sp[-1];
2977 } else {
2978 newTarget = NullValue();
2981 if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr,
2982 newTarget, ret)) {
2983 goto error;
2986 REGS.sp -= 2 + construct;
2988 END_CASE(SpreadCall)
2990 CASE(New)
2991 CASE(NewContent)
2992 CASE(Call)
2993 CASE(CallContent)
2994 CASE(CallIgnoresRv)
2995 CASE(CallIter)
2996 CASE(CallContentIter)
2997 CASE(SuperCall) {
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));
3022 CallArgs args =
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) {
3035 if (construct) {
3036 CallReason reason = op == JSOp::NewContent ? CallReason::CallContent
3037 : CallReason::Call;
3038 if (!ConstructFromStack(cx, args, reason)) {
3039 goto error;
3041 } else {
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);
3046 goto error;
3049 CallReason reason =
3050 (op == JSOp::CallContent || op == JSOp::CallContentIter)
3051 ? CallReason::CallContent
3052 : CallReason::Call;
3053 if (!CallFromStack(cx, args, reason)) {
3054 goto error;
3057 Value* newsp = args.spAfterCall();
3058 REGS.sp = newsp;
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));
3067 if (!funScript) {
3068 goto error;
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
3073 // below.
3074 const bool isCrossRealm = cx->realm() != funScript->realm();
3075 if (isCrossRealm) {
3076 cx->enterRealmOf(funScript);
3078 auto leaveRealmGuard =
3079 mozilla::MakeScopeExit([isCrossRealm, cx, &script] {
3080 if (isCrossRealm) {
3081 cx->leaveRealm(script->realm());
3085 if (construct && !MaybeCreateThisForConstructor(cx, args)) {
3086 goto error;
3090 InvokeState state(cx, args, construct);
3092 jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
3093 switch (status) {
3094 case jit::EnterJitStatus::Error:
3095 goto error;
3096 case jit::EnterJitStatus::Ok:
3097 interpReturnOK = true;
3098 CHECK_BRANCH();
3099 REGS.sp = args.spAfterCall();
3100 goto jit_return;
3101 case jit::EnterJitStatus::NotEntered:
3102 break;
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;
3112 CHECK_BRANCH();
3113 REGS.sp = args.spAfterCall();
3114 goto jit_return;
3116 goto error;
3118 #endif
3121 funScript = fun->nonLazyScript();
3123 if (!activation.pushInlineFrame(args, funScript, construct)) {
3124 goto error;
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())) {
3137 goto error;
3140 // Increment the coverage for the main entry point.
3141 INIT_COVERAGE();
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)) {
3153 goto error;
3156 END_CASE(OptimizeSpreadCall)
3158 CASE(ThrowMsg) {
3159 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(REGS.pc)));
3160 goto error;
3162 END_CASE(ThrowMsg)
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)) {
3170 goto error;
3173 Value v = ComputeImplicitThis(env);
3174 PUSH_COPY(v);
3176 END_CASE(ImplicitThis)
3178 CASE(GetGName) {
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]),
3185 &rval)) {
3186 goto error;
3189 PUSH_COPY(rval);
3191 END_CASE(GetGName)
3193 CASE(GetName) {
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)) {
3198 goto error;
3201 PUSH_COPY(rval);
3203 END_CASE(GetName)
3205 CASE(GetImport) {
3206 PUSH_NULL();
3207 MutableHandleValue rval = REGS.stackHandleAt(-1);
3208 HandleObject envChain = REGS.fp()->environmentChain();
3209 if (!GetImportOperation(cx, envChain, script, REGS.pc, rval)) {
3210 goto error;
3213 END_CASE(GetImport)
3215 CASE(GetIntrinsic) {
3216 ReservedRooted<Value> rval(&rootValue0);
3217 if (!GetIntrinsicOperation(cx, script, REGS.pc, &rval)) {
3218 goto error;
3221 PUSH_COPY(rval);
3223 END_CASE(GetIntrinsic)
3225 CASE(Uint16) { PUSH_INT32((int32_t)GET_UINT16(REGS.pc)); }
3226 END_CASE(Uint16)
3228 CASE(Uint24) { PUSH_INT32((int32_t)GET_UINT24(REGS.pc)); }
3229 END_CASE(Uint24)
3231 CASE(Int8) { PUSH_INT32(GET_INT8(REGS.pc)); }
3232 END_CASE(Int8)
3234 CASE(Int32) { PUSH_INT32(GET_INT32(REGS.pc)); }
3235 END_CASE(Int32)
3237 CASE(Double) { PUSH_COPY(GET_INLINE_VALUE(REGS.pc)); }
3238 END_CASE(Double)
3240 CASE(String) { PUSH_STRING(script->getString(REGS.pc)); }
3241 END_CASE(String)
3243 CASE(ToString) {
3244 MutableHandleValue oper = REGS.stackHandleAt(-1);
3246 if (!oper.isString()) {
3247 JSString* operString = ToString<CanGC>(cx, oper);
3248 if (!operString) {
3249 goto error;
3251 oper.setString(operString);
3254 END_CASE(ToString)
3256 CASE(Symbol) {
3257 PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
3259 END_CASE(Symbol)
3261 CASE(Object) {
3262 MOZ_ASSERT(script->treatAsRunOnce());
3263 PUSH_OBJECT(*script->getObject(REGS.pc));
3265 END_CASE(Object)
3267 CASE(CallSiteObj) {
3268 JSObject* cso = script->getObject(REGS.pc);
3269 MOZ_ASSERT(!cso->as<ArrayObject>().isExtensible());
3270 MOZ_ASSERT(cso->as<ArrayObject>().containsPure(cx->names().raw));
3271 PUSH_OBJECT(*cso);
3273 END_CASE(CallSiteObj)
3275 CASE(RegExp) {
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>());
3282 if (!obj) {
3283 goto error;
3285 PUSH_OBJECT(*obj);
3287 END_CASE(RegExp)
3289 CASE(Zero) { PUSH_INT32(0); }
3290 END_CASE(Zero)
3292 CASE(One) { PUSH_INT32(1); }
3293 END_CASE(One)
3295 CASE(Null) { PUSH_NULL(); }
3296 END_CASE(Null)
3298 CASE(False) { PUSH_BOOLEAN(false); }
3299 END_CASE(False)
3301 CASE(True) { PUSH_BOOLEAN(true); }
3302 END_CASE(True)
3304 CASE(TableSwitch) {
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;
3314 int32_t i;
3315 if (rref.isInt32()) {
3316 i = rref.toInt32();
3317 } else {
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);
3337 CASE(Arguments) {
3338 MOZ_ASSERT(script->needsArgsObj());
3339 ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
3340 if (!obj) {
3341 goto error;
3343 PUSH_COPY(ObjectValue(*obj));
3345 END_CASE(Arguments)
3347 CASE(Rest) {
3348 ReservedRooted<JSObject*> rest(&rootObject0,
3349 REGS.fp()->createRestParameter(cx));
3350 if (!rest) {
3351 goto error;
3353 PUSH_COPY(ObjectValue(*rest));
3355 END_CASE(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);
3364 PUSH_COPY(val);
3366 END_CASE(GetAliasedVar)
3368 CASE(GetAliasedDebugVar) {
3369 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3370 ReservedRooted<Value> val(
3371 &rootValue0,
3372 REGS.fp()->aliasedEnvironmentMaybeDebug(ec).aliasedBinding(ec));
3374 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3376 PUSH_COPY(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);
3390 goto error;
3392 END_CASE(ThrowSetConst)
3394 CASE(CheckLexical) {
3395 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3396 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3397 REGS.pc);
3398 goto error;
3401 END_CASE(CheckLexical)
3403 CASE(CheckAliasedLexical) {
3404 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3405 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3406 REGS.pc);
3407 goto error;
3410 END_CASE(CheckAliasedLexical)
3412 CASE(InitLexical) {
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 = &REGS.fp()->extensibleLexicalEnvironment();
3429 } else {
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)
3440 CASE(GetArg) {
3441 unsigned i = GET_ARGNO(REGS.pc);
3442 if (script->argsObjAliasesFormals()) {
3443 PUSH_COPY(REGS.fp()->argsObj().arg(i));
3444 } else {
3445 PUSH_COPY(REGS.fp()->unaliasedFormal(i));
3448 END_CASE(GetArg)
3450 CASE(GetFrameArg) {
3451 uint32_t i = GET_ARGNO(REGS.pc);
3452 PUSH_COPY(REGS.fp()->unaliasedFormal(i, DONT_CHECK_ALIASING));
3454 END_CASE(GetFrameArg)
3456 CASE(SetArg) {
3457 unsigned i = GET_ARGNO(REGS.pc);
3458 if (script->argsObjAliasesFormals()) {
3459 REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
3460 } else {
3461 REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
3464 END_CASE(SetArg)
3466 CASE(GetLocal) {
3467 uint32_t i = GET_LOCALNO(REGS.pc);
3468 PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
3470 #ifdef DEBUG
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]);
3486 #endif
3488 END_CASE(GetLocal)
3490 CASE(SetLocal) {
3491 uint32_t i = GET_LOCALNO(REGS.pc);
3493 MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
3495 REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3497 END_CASE(SetLocal)
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)) {
3516 goto error;
3519 END_CASE(GlobalOrEvalDeclInstantiation)
3521 CASE(Lambda) {
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());
3526 if (!obj) {
3527 goto error;
3530 MOZ_ASSERT(obj->staticPrototype());
3531 PUSH_OBJECT(*obj);
3533 END_CASE(Lambda)
3535 CASE(ToAsyncIter) {
3536 ReservedRooted<Value> nextMethod(&rootValue0, REGS.sp[-1]);
3537 ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-2].toObject());
3538 JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter, nextMethod);
3539 if (!asyncIter) {
3540 goto error;
3543 REGS.sp--;
3544 REGS.sp[-1].setObject(*asyncIter);
3546 END_CASE(ToAsyncIter)
3548 CASE(CanSkipAwait) {
3549 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3550 bool canSkip;
3551 if (!CanSkipAwait(cx, val, &canSkip)) {
3552 goto error;
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)) {
3565 goto error;
3569 END_CASE(MaybeExtractAwaitValue)
3571 CASE(AsyncAwait) {
3572 MOZ_ASSERT(REGS.stackDepth() >= 2);
3573 ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
3574 ReservedRooted<Value> value(&rootValue0, REGS.sp[-2]);
3575 JSObject* promise =
3576 AsyncFunctionAwait(cx, gen.as<AsyncFunctionGeneratorObject>(), value);
3577 if (!promise) {
3578 goto error;
3581 REGS.sp--;
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, &REGS.sp[-1].toObject());
3590 ReservedRooted<Value> valueOrReason(&rootValue0, REGS.sp[-2]);
3591 JSObject* promise =
3592 AsyncFunctionResolve(cx, gen.as<AsyncFunctionGeneratorObject>(),
3593 valueOrReason, resolveKind);
3594 if (!promise) {
3595 goto error;
3598 REGS.sp--;
3599 REGS.sp[-1].setObject(*promise);
3601 END_CASE(AsyncResolve)
3603 CASE(SetFunName) {
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 &REGS.sp[-2].toObject().as<JSFunction>());
3609 if (!SetFunctionName(cx, fun, name, prefixKind)) {
3610 goto error;
3613 REGS.sp--;
3615 END_CASE(SetFunName)
3617 CASE(Callee) {
3618 MOZ_ASSERT(REGS.fp()->isFunctionFrame());
3619 PUSH_COPY(REGS.fp()->calleev());
3621 END_CASE(Callee)
3623 CASE(InitPropGetter)
3624 CASE(InitHiddenPropGetter)
3625 CASE(InitPropSetter)
3626 CASE(InitHiddenPropSetter) {
3627 MOZ_ASSERT(REGS.stackDepth() >= 2);
3629 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3630 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3631 ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
3633 if (!InitPropGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
3634 goto error;
3637 REGS.sp--;
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, &REGS.sp[-3].toObject());
3648 ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
3649 ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
3651 if (!InitElemGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
3652 goto error;
3655 REGS.sp -= 2;
3657 END_CASE(InitElemGetter)
3659 CASE(Hole) { PUSH_MAGIC(JS_ELEMENTS_HOLE); }
3660 END_CASE(Hole)
3662 CASE(NewInit) {
3663 JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
3665 if (!obj) {
3666 goto error;
3668 PUSH_OBJECT(*obj);
3670 END_CASE(NewInit)
3672 CASE(NewArray) {
3673 uint32_t length = GET_UINT32(REGS.pc);
3674 ArrayObject* obj = NewArrayOperation(cx, length);
3675 if (!obj) {
3676 goto error;
3678 PUSH_OBJECT(*obj);
3680 END_CASE(NewArray)
3682 CASE(NewObject) {
3683 JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
3684 if (!obj) {
3685 goto error;
3687 PUSH_OBJECT(*obj);
3689 END_CASE(NewObject)
3691 CASE(MutateProto) {
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, &REGS.sp[-2].toObject());
3698 MOZ_ASSERT(obj->is<PlainObject>());
3700 if (!SetPrototype(cx, obj, newProto)) {
3701 goto error;
3705 REGS.sp--;
3707 END_CASE(MutateProto)
3709 CASE(InitProp)
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, &REGS.sp[-2].toObject());
3723 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3725 if (!InitPropertyOperation(cx, REGS.pc, obj, name, rval)) {
3726 goto error;
3729 REGS.sp--;
3731 END_CASE(InitProp)
3733 CASE(InitElem)
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, &REGS.sp[-3].toObject());
3742 if (!InitElemOperation(cx, REGS.pc, obj, id, val)) {
3743 goto error;
3746 REGS.sp -= 2;
3748 END_CASE(InitElem)
3750 CASE(InitElemArray) {
3751 MOZ_ASSERT(REGS.stackDepth() >= 2);
3752 HandleValue val = REGS.stackHandleAt(-1);
3753 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3755 InitElemArrayOperation(cx, REGS.pc, obj.as<ArrayObject>(), val);
3756 REGS.sp--;
3758 END_CASE(InitElemArray)
3760 CASE(InitElemInc) {
3761 MOZ_ASSERT(REGS.stackDepth() >= 3);
3762 HandleValue val = REGS.stackHandleAt(-1);
3764 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
3766 uint32_t index = REGS.sp[-2].toInt32();
3767 if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index, val)) {
3768 goto error;
3771 REGS.sp[-2].setInt32(index + 1);
3772 REGS.sp--;
3774 END_CASE(InitElemInc)
3776 #ifdef ENABLE_RECORD_TUPLE
3777 CASE(InitRecord) {
3778 uint32_t length = GET_UINT32(REGS.pc);
3779 RecordType* rec = RecordType::createUninitialized(cx, length);
3780 if (!rec) {
3781 goto error;
3783 PUSH_EXTENDED_PRIMITIVE(*rec);
3785 END_CASE(InitRecord)
3787 CASE(AddRecordProperty) {
3788 MOZ_ASSERT(REGS.stackDepth() >= 3);
3790 ReservedRooted<JSObject*> rec(&rootObject0,
3791 &REGS.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)) {
3797 goto error;
3799 if (!rec->as<RecordType>().initializeNextProperty(
3800 cx, id, REGS.stackHandleAt(-1))) {
3801 goto error;
3804 REGS.sp -= 2;
3806 END_CASE(AddRecordProperty)
3808 CASE(AddRecordSpread) {
3809 MOZ_ASSERT(REGS.stackDepth() >= 2);
3811 if (!AddRecordSpreadOperation(cx, REGS.stackHandleAt(-2),
3812 REGS.stackHandleAt(-1))) {
3813 goto error;
3815 REGS.sp--;
3817 END_CASE(AddRecordSpread)
3819 CASE(FinishRecord) {
3820 MOZ_ASSERT(REGS.stackDepth() >= 1);
3821 RecordType* rec = &REGS.sp[-1].toExtendedPrimitive().as<RecordType>();
3822 if (!rec->finishInitialization(cx)) {
3823 goto error;
3826 END_CASE(FinishRecord)
3828 CASE(InitTuple) {
3829 uint32_t length = GET_UINT32(REGS.pc);
3830 TupleType* tup = TupleType::createUninitialized(cx, length);
3831 if (!tup) {
3832 goto error;
3834 PUSH_EXTENDED_PRIMITIVE(*tup);
3836 END_CASE(InitTuple)
3838 CASE(AddTupleElement) {
3839 MOZ_ASSERT(REGS.stackDepth() >= 2);
3841 ReservedRooted<JSObject*> tup(&rootObject0,
3842 &REGS.sp[-2].toExtendedPrimitive());
3843 HandleValue val = REGS.stackHandleAt(-1);
3845 if (!tup->as<TupleType>().initializeNextElement(cx, val)) {
3846 goto error;
3849 REGS.sp--;
3851 END_CASE(AddTupleElement)
3853 CASE(FinishTuple) {
3854 MOZ_ASSERT(REGS.stackDepth() >= 1);
3855 TupleType& tup = REGS.sp[-1].toExtendedPrimitive().as<TupleType>();
3856 tup.finishInitialization(cx);
3858 END_CASE(FinishTuple)
3859 #endif
3861 CASE(Exception) {
3862 PUSH_NULL();
3863 MutableHandleValue res = REGS.stackHandleAt(-1);
3864 if (!GetAndClearException(cx, res)) {
3865 goto error;
3868 END_CASE(Exception)
3870 CASE(Finally) { CHECK_BRANCH(); }
3871 END_CASE(Finally)
3873 CASE(Throw) {
3874 CHECK_BRANCH();
3875 ReservedRooted<Value> v(&rootValue0);
3876 POP_COPY_TO(v);
3877 MOZ_ALWAYS_FALSE(ThrowOperation(cx, v));
3878 /* let the code at error try to catch the exception. */
3879 goto error;
3882 CASE(Instanceof) {
3883 ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
3884 if (HandleValue(rref).isPrimitive()) {
3885 ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
3886 goto error;
3888 ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
3889 bool cond = false;
3890 if (!InstanceofOperator(cx, obj, REGS.stackHandleAt(-2), &cond)) {
3891 goto error;
3893 REGS.sp--;
3894 REGS.sp[-1].setBoolean(cond);
3896 END_CASE(Instanceof)
3898 CASE(Debugger) {
3899 if (!DebugAPI::onDebuggerStatement(cx, REGS.fp())) {
3900 goto error;
3903 END_CASE(Debugger)
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>())) {
3910 goto error;
3913 END_CASE(PushLexicalEnv)
3915 CASE(PopLexicalEnv) {
3916 #ifdef DEBUG
3917 Scope* scope = script->lookupScope(REGS.pc);
3918 MOZ_ASSERT(scope);
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());
3924 #endif
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) {
3936 #ifdef DEBUG
3937 Scope* scope = script->lookupScope(REGS.pc);
3938 MOZ_ASSERT(scope);
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());
3944 #endif
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) {
3955 #ifdef DEBUG
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);
3960 #endif
3962 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
3963 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
3966 if (!REGS.fp()->freshenLexicalEnvironment(cx)) {
3967 goto error;
3970 END_CASE(FreshenLexicalEnv)
3972 CASE(RecreateLexicalEnv) {
3973 #ifdef DEBUG
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);
3978 #endif
3980 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
3981 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
3984 if (!REGS.fp()->recreateLexicalEnvironment(cx)) {
3985 goto error;
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>())) {
3995 goto error;
3998 END_CASE(PushClassBodyEnv)
4000 CASE(PushVarEnv) {
4001 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4003 if (!REGS.fp()->pushVarEnvironment(cx, scope)) {
4004 goto error;
4007 END_CASE(PushVarEnv)
4009 CASE(Generator) {
4010 MOZ_ASSERT(!cx->isExceptionPending());
4011 MOZ_ASSERT(REGS.stackDepth() == 0);
4012 JSObject* obj = AbstractGeneratorObject::createFromFrame(cx, REGS.fp());
4013 if (!obj) {
4014 goto error;
4016 PUSH_OBJECT(*obj);
4018 END_CASE(Generator)
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, &REGS.sp[-1].toObject());
4027 POP_RETURN_VALUE();
4028 MOZ_ASSERT(REGS.stackDepth() == 0);
4029 if (!AbstractGeneratorObject::suspend(cx, obj, REGS.fp(), REGS.pc,
4030 script->nfixed())) {
4031 goto error;
4033 goto successful_return_continuation;
4036 CASE(Yield)
4037 CASE(Await) {
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, &REGS.sp[-1].toObject());
4044 if (!AbstractGeneratorObject::suspend(
4045 cx, obj, REGS.fp(), REGS.pc,
4046 script->nfixed() + REGS.stackDepth() - 2)) {
4047 goto error;
4050 REGS.sp--;
4051 POP_RETURN_VALUE();
4053 goto successful_return_continuation;
4056 CASE(ResumeKind) {
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, &REGS.sp[-2].toObject().as<AbstractGeneratorObject>());
4069 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx, activation.regs().fp(), gen,
4070 val, resumeKind));
4071 goto error;
4073 REGS.sp -= 2;
4075 END_CASE(CheckResumeKind)
4077 CASE(Resume) {
4079 Rooted<AbstractGeneratorObject*> gen(
4080 cx, &REGS.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.
4086 REGS.sp -= 1;
4088 if (!AbstractGeneratorObject::resume(cx, activation, gen, val,
4089 resumeKindVal)) {
4090 goto error;
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())) {
4101 goto error;
4104 if (!DebugAPI::onResumeFrame(cx, REGS.fp())) {
4105 if (cx->isPropagatingForcedReturn()) {
4106 MOZ_ASSERT_IF(
4107 REGS.fp()
4108 ->callee()
4109 .isGenerator(), // as opposed to an async function
4110 gen->isClosed());
4112 goto error;
4115 ADVANCE_AND_DISPATCH(0);
4118 CASE(AfterYield) {
4119 // AbstractGeneratorObject::resume takes care of setting the frame's
4120 // debuggee flag.
4121 MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
4122 COUNT_COVERAGE();
4124 END_CASE(AfterYield)
4126 CASE(FinalYieldRval) {
4127 ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-1].toObject());
4128 REGS.sp--;
4129 AbstractGeneratorObject::finalSuspend(gen);
4130 goto successful_return_continuation;
4133 CASE(CheckClassHeritage) {
4134 HandleValue heritage = REGS.stackHandleAt(-1);
4136 if (!CheckClassHeritageOperation(cx, heritage)) {
4137 goto error;
4140 END_CASE(CheckClassHeritage)
4142 CASE(BuiltinObject) {
4143 auto kind = BuiltinObjectKind(GET_UINT8(REGS.pc));
4144 JSObject* builtin = BuiltinObjectOperation(cx, kind);
4145 if (!builtin) {
4146 goto error;
4148 PUSH_OBJECT(*builtin);
4150 END_CASE(BuiltinObject)
4152 CASE(FunWithProto) {
4153 ReservedRooted<JSObject*> proto(&rootObject1, &REGS.sp[-1].toObject());
4155 /* Load the specified function object literal. */
4156 ReservedRooted<JSFunction*> fun(&rootFunction0,
4157 script->getFunction(REGS.pc));
4159 JSObject* obj =
4160 FunWithProtoOperation(cx, fun, REGS.fp()->environmentChain(), proto);
4161 if (!obj) {
4162 goto error;
4165 REGS.sp[-1].setObject(*obj);
4167 END_CASE(FunWithProto)
4169 CASE(ObjWithProto) {
4170 JSObject* obj = ObjectWithProtoOperation(cx, REGS.stackHandleAt(-1));
4171 if (!obj) {
4172 goto error;
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 = &REGS.sp[-2].toObject().as<JSFunction>();
4184 MOZ_ASSERT(func->allowSuperProperty());
4186 /* Load the home object */
4187 JSObject* obj = &REGS.sp[-1].toObject();
4188 MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
4190 func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT,
4191 ObjectValue(*obj));
4192 REGS.sp--;
4194 END_CASE(InitHomeObject)
4196 CASE(SuperBase) {
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);
4208 END_CASE(SuperBase)
4210 CASE(NewTarget) {
4211 PUSH_COPY(REGS.fp()->newTarget());
4212 MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
4214 END_CASE(NewTarget)
4216 CASE(ImportMeta) {
4217 JSObject* metaObject = ImportMetaOperation(cx, script);
4218 if (!metaObject) {
4219 goto error;
4222 PUSH_OBJECT(*metaObject);
4224 END_CASE(ImportMeta)
4226 CASE(DynamicImport) {
4227 ReservedRooted<Value> options(&rootValue0, REGS.sp[-1]);
4228 REGS.sp--;
4230 ReservedRooted<Value> specifier(&rootValue1);
4231 POP_COPY_TO(specifier);
4233 JSObject* promise =
4234 StartDynamicModuleImport(cx, script, specifier, options);
4235 if (!promise) goto error;
4237 PUSH_OBJECT(*promise);
4239 END_CASE(DynamicImport)
4241 CASE(EnvCallee) {
4242 uint8_t numHops = GET_UINT8(REGS.pc);
4243 JSObject* env = &REGS.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());
4249 END_CASE(EnvCallee)
4251 CASE(SuperFun) {
4252 JSObject* superEnvFunc = &REGS.sp[-1].toObject();
4253 JSObject* superFun = SuperFunOperation(superEnvFunc);
4254 REGS.sp[-1].setObjectOrNull(superFun);
4256 END_CASE(SuperFun)
4258 CASE(CheckObjCoercible) {
4259 ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4260 if (checkVal.isNullOrUndefined()) {
4261 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, checkVal));
4262 goto error;
4265 END_CASE(CheckObjCoercible)
4267 CASE(DebugCheckSelfHosted) {
4268 #ifdef DEBUG
4269 ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4270 if (!Debug_CheckSelfHosted(cx, checkVal)) {
4271 goto error;
4273 #endif
4275 END_CASE(DebugCheckSelfHosted)
4277 CASE(IsConstructing) { PUSH_MAGIC(JS_IS_CONSTRUCTING); }
4278 END_CASE(IsConstructing)
4280 CASE(Inc) {
4281 MutableHandleValue val = REGS.stackHandleAt(-1);
4282 if (!IncOperation(cx, val, val)) {
4283 goto error;
4286 END_CASE(Inc)
4288 CASE(Dec) {
4289 MutableHandleValue val = REGS.stackHandleAt(-1);
4290 if (!DecOperation(cx, val, val)) {
4291 goto error;
4294 END_CASE(Dec)
4296 CASE(ToNumeric) {
4297 if (!ToNumeric(cx, REGS.stackHandleAt(-1))) {
4298 goto error;
4301 END_CASE(ToNumeric)
4303 CASE(BigInt) { PUSH_BIGINT(script->getBigInt(REGS.pc)); }
4304 END_CASE(BigInt)
4306 DEFAULT() {
4307 char numBuf[12];
4308 SprintfLiteral(numBuf, "%d", *REGS.pc);
4309 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4310 JSMSG_BAD_BYTECODE, numBuf);
4311 goto error;
4314 } /* interpreter loop */
4316 MOZ_CRASH("Interpreter loop exited via fallthrough");
4318 error:
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);
4341 PUSH_BOOLEAN(true);
4342 cx->clearPendingException();
4344 ADVANCE_AND_DISPATCH(0);
4347 MOZ_CRASH("Invalid HandleError continuation");
4349 exit:
4350 if (MOZ_LIKELY(!frameHalfInitialized)) {
4351 interpReturnOK =
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
4361 * inside the JIT.
4363 leave_on_safe_point:
4365 if (interpReturnOK) {
4366 state.setReturnValue(activation.entryFrame()->returnValue());
4369 return interpReturnOK;
4371 prologue_error:
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);
4380 return false;
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)) {
4388 return true;
4392 // Optimize common cases like (2).toString() or "foo".valueOf() to not
4393 // create a wrapper object.
4394 if (v.isPrimitive() && !v.isNullOrUndefined()) {
4395 JSObject* proto;
4397 switch (v.type()) {
4398 case ValueType::Double:
4399 case ValueType::Int32:
4400 proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
4401 break;
4402 case ValueType::Boolean:
4403 proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
4404 break;
4405 case ValueType::String:
4406 proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
4407 break;
4408 case ValueType::Symbol:
4409 proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
4410 break;
4411 case ValueType::BigInt:
4412 proto = GlobalObject::getOrCreateBigIntPrototype(cx, cx->global());
4413 break;
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);
4420 #endif
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");
4429 if (!proto) {
4430 return false;
4433 if (GetPropertyPure(cx, proto, NameToId(name), vp.address())) {
4434 return true;
4438 RootedValue receiver(cx, v);
4439 RootedObject obj(
4440 cx, ToObjectFromStackForPropertyAccess(cx, v, JSDVG_SEARCH_STACK, name));
4441 if (!obj) {
4442 return false;
4445 return GetProperty(cx, obj, receiver, name, vp);
4448 JSObject* js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent) {
4449 JSFunction* clone;
4450 if (fun->isNativeFun()) {
4451 MOZ_ASSERT(IsAsmJSModule(fun));
4452 clone = CloneAsmJSModuleFunction(cx, fun);
4453 } else {
4454 RootedObject proto(cx, fun->staticPrototype());
4455 clone = CloneFunctionReuseScript(cx, fun, parent, proto);
4457 if (!clone) {
4458 return nullptr;
4461 MOZ_ASSERT(fun->global() == clone->global());
4462 return clone;
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));
4473 MOZ_ASSERT(module);
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);
4484 return false;
4487 bool js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
4488 MutableHandle<SavedFrame*> stack) {
4489 if (!cx->getPendingException(res)) {
4490 return false;
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));
4510 if (!obj) {
4511 return false;
4514 RootedId id(cx, NameToId(name));
4515 ObjectOpResult result;
4516 if (!DeleteProperty(cx, obj, id, result)) {
4517 return false;
4520 if (strict) {
4521 if (!result) {
4522 return result.reportError(cx, obj, id);
4524 *res = true;
4525 } else {
4526 *res = result.ok();
4528 return true;
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,
4535 bool* res);
4537 template <bool strict>
4538 bool js::DelElemOperation(JSContext* cx, HandleValue val, HandleValue index,
4539 bool* res) {
4540 const int valIndex = -2;
4541 RootedObject obj(
4542 cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, index));
4543 if (!obj) {
4544 return false;
4547 RootedId id(cx);
4548 if (!ToPropertyKey(cx, index, &id)) {
4549 return false;
4551 ObjectOpResult result;
4552 if (!DeleteProperty(cx, obj, id, result)) {
4553 return false;
4556 if (strict) {
4557 if (!result) {
4558 return result.reportError(cx, obj, id);
4560 *res = true;
4561 } else {
4562 *res = result.ok();
4564 return true;
4567 template bool js::DelElemOperation<true>(JSContext*, HandleValue, HandleValue,
4568 bool*);
4569 template bool js::DelElemOperation<false>(JSContext*, HandleValue, HandleValue,
4570 bool*);
4572 bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
4573 HandleValue value, bool strict) {
4574 RootedId id(cx);
4575 if (!ToPropertyKey(cx, index, &id)) {
4576 return false;
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) {
4585 RootedId id(cx);
4586 if (!ToPropertyKey(cx, index, &id)) {
4587 return false;
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,
4657 bool* res) {
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) {
4677 int i;
4678 if (!ToInt32(cx, in, &i)) {
4679 return false;
4681 *out = js::jit::AtomicOperations::isLockfreeJS(i);
4682 return true;
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)) {
4690 return false;
4693 if (!scope) {
4694 // Return true for non-existent names.
4695 res.setBoolean(true);
4696 return true;
4699 ObjectOpResult result;
4700 RootedId id(cx, NameToId(name));
4701 if (!DeleteProperty(cx, scope, id, result)) {
4702 return false;
4705 bool status = result.ok();
4706 res.setBoolean(status);
4708 if (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);
4715 return true;
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)) {
4723 return false;
4726 res.set(ComputeImplicitThis(obj));
4727 return true;
4730 unsigned js::GetInitDataPropAttrs(JSOp op) {
4731 switch (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
4741 return 0;
4742 default:;
4744 MOZ_CRASH("Unknown data initprop");
4747 static bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4748 HandleObject obj, HandleId id,
4749 HandleObject val) {
4750 MOZ_ASSERT(val->isCallable());
4752 JSOp op = JSOp(*pc);
4754 unsigned attrs = 0;
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,
4771 HandleObject obj,
4772 Handle<PropertyName*> name,
4773 HandleObject val) {
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,
4780 HandleObject val) {
4781 RootedId id(cx);
4782 if (!ToPropertyKey(cx, idval, &id)) {
4783 return false;
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
4799 // error message.
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);
4804 return false;
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));
4825 if (constructing) {
4826 if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget)) {
4827 return false;
4830 ConstructArgs cargs(cx);
4831 if (!cargs.init(cx, length)) {
4832 return false;
4835 if (!GetElements(cx, aobj, length, cargs.array())) {
4836 return false;
4839 RootedObject obj(cx);
4840 if (!Construct(cx, callee, cargs, newTarget, &obj)) {
4841 return false;
4843 res.setObject(*obj);
4844 } else {
4845 InvokeArgs args(cx);
4846 if (!args.init(cx, length)) {
4847 return false;
4850 if (!GetElements(cx, aobj, length, args.array())) {
4851 return false;
4854 if ((op == JSOp::SpreadEval || op == JSOp::StrictSpreadEval) &&
4855 cx->global()->valueIsEval(callee)) {
4856 if (!DirectEval(cx, args.get(0), res)) {
4857 return false;
4859 } else {
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)) {
4865 return false;
4870 return true;
4873 static bool OptimizeArrayIteration(JSContext* cx, HandleObject obj,
4874 bool* optimized) {
4875 *optimized = false;
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)) {
4888 return true;
4891 ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
4892 if (!stubChain) {
4893 return false;
4896 if (!stubChain->tryOptimizeArray(cx, obj.as<ArrayObject>(), optimized)) {
4897 return false;
4900 return true;
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>()) {
4916 return true;
4919 Handle<ArgumentsObject*> args = obj.as<ArgumentsObject>();
4920 if (args->hasOverriddenElement() || args->hasOverriddenLength() ||
4921 args->hasOverriddenIterator()) {
4922 return true;
4925 ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
4926 if (!stubChain) {
4927 return false;
4930 bool optimized;
4931 if (!stubChain->tryOptimizeArrayIteratorNext(cx, &optimized)) {
4932 return false;
4934 if (!optimized) {
4935 return true;
4938 auto* array = ArrayFromArgumentsObject(cx, args);
4939 if (!array) {
4940 return false;
4943 result.setObject(*array);
4944 return true;
4947 bool js::OptimizeSpreadCall(JSContext* cx, HandleValue arg,
4948 MutableHandleValue result) {
4949 // This function returns |undefined| if the spread operation can't be
4950 // optimized.
4951 result.setUndefined();
4953 if (!arg.isObject()) {
4954 return true;
4957 RootedObject obj(cx, &arg.toObject());
4958 bool optimized;
4959 if (!OptimizeArrayIteration(cx, obj, &optimized)) {
4960 return false;
4962 if (optimized) {
4963 result.setObject(*obj);
4964 return true;
4967 if (!OptimizeArgumentsSpreadCall(cx, obj, result)) {
4968 return false;
4970 if (result.isObject()) {
4971 return true;
4974 MOZ_ASSERT(result.isUndefined());
4975 return true;
4978 bool js::OptimizeGetIterator(JSContext* cx, HandleValue arg, bool* result) {
4979 // This function returns |false| if the iteration can't be optimized.
4980 *result = false;
4982 if (!arg.isObject()) {
4983 return true;
4986 RootedObject obj(cx, &arg.toObject());
4988 bool optimized;
4989 if (!OptimizeArrayIteration(cx, obj, &optimized)) {
4990 return false;
4993 if (optimized) {
4994 *result = true;
4995 return true;
4998 MOZ_ASSERT(!*result);
4999 return true;
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);
5009 if (!array) {
5010 return nullptr;
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);
5019 return array;
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,
5047 site);
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,
5064 site);
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
5081 // kind is full.
5082 MOZ_ASSERT_IF(array && array->isTenured(),
5083 array->asTenured().getAllocKind() == allocKind);
5084 return array;
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
5094 // kind is full.
5095 MOZ_ASSERT_IF(array && array->isTenured(),
5096 array->asTenured().getAllocKind() == allocKind);
5097 return array;
5100 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5101 HandleId id) {
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,
5107 printable.get());
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);
5128 } else {
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,
5141 printable.get());
5145 bool js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind) {
5146 switch (kind) {
5147 case CheckIsObjectKind::IteratorNext:
5148 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5149 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
5150 break;
5151 case CheckIsObjectKind::IteratorReturn:
5152 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5153 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "return");
5154 break;
5155 case CheckIsObjectKind::IteratorThrow:
5156 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5157 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "throw");
5158 break;
5159 case CheckIsObjectKind::GetIterator:
5160 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5161 JSMSG_GET_ITER_RETURNED_PRIMITIVE);
5162 break;
5163 case CheckIsObjectKind::GetAsyncIterator:
5164 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5165 JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
5166 break;
5167 #ifdef ENABLE_DECORATORS
5168 case CheckIsObjectKind::DecoratorReturn:
5169 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5170 JSMSG_DECORATOR_INVALID_RETURN_TYPE);
5171 break;
5172 #endif
5173 default:
5174 MOZ_CRASH("Unknown kind");
5176 return false;
5179 bool js::ThrowUninitializedThis(JSContext* cx) {
5180 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5181 JSMSG_UNINITIALIZED_THIS);
5182 return false;
5185 bool js::ThrowInitializedThis(JSContext* cx) {
5186 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
5187 return false;
5190 bool js::ThrowObjectCoercible(JSContext* cx, HandleValue value) {
5191 MOZ_ASSERT(value.isNullOrUndefined());
5192 ReportIsNullOrUndefinedForPropertyAccess(cx, value, JSDVG_SEARCH_STACK);
5193 return false;
5196 bool js::SetPropertySuper(JSContext* cx, HandleValue lval, HandleValue receiver,
5197 Handle<PropertyName*> name, HandleValue rval,
5198 bool strict) {
5199 MOZ_ASSERT(lval.isObjectOrNull());
5201 RootedObject obj(cx, ToObjectFromStackForPropertyAccess(
5202 cx, lval, JSDVG_SEARCH_STACK, name));
5203 if (!obj) {
5204 return false;
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));
5217 if (!obj) {
5218 return false;
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();
5231 } else {
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));
5243 return true;
5246 // https://tc39.es/ecma262/#sec-iteratorclose
5247 bool js::CloseIterOperation(JSContext* cx, HandleObject iter,
5248 CompletionKind kind) {
5249 // Steps 1-2 are implicit.
5251 // Step 3
5252 RootedValue returnMethod(cx);
5253 bool innerResult =
5254 GetProperty(cx, iter, iter, cx->names().return_, &returnMethod);
5256 // Step 4
5257 RootedValue result(cx);
5258 if (innerResult) {
5259 // Step 4b
5260 if (returnMethod.isNullOrUndefined()) {
5261 return true;
5263 // Step 4c
5264 if (IsCallable(returnMethod)) {
5265 RootedValue thisVal(cx, ObjectValue(*iter));
5266 innerResult = Call(cx, returnMethod, thisVal, &result);
5267 } else {
5268 innerResult = ReportIsNotFunction(cx, returnMethod);
5272 // Step 5
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();
5280 return true;
5283 // Step 6
5284 if (!innerResult) {
5285 return false;
5288 // Step 7
5289 if (!result.isObject()) {
5290 return ThrowCheckIsObject(cx, CheckIsObjectKind::IteratorReturn);
5293 // Step 8
5294 return true;