Backed out changeset 8f976ed899d7 (bug 1847231) for causing bc failures on browser_se...
[gecko.git] / js / src / vm / Interpreter.cpp
blobf10c0ef39d6541a29bfc6acb8ed130f5a208ca9a
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 static JSObject* SuperFunOperation(JSObject* callee) {
272 MOZ_ASSERT(callee->as<JSFunction>().isClassConstructor());
273 MOZ_ASSERT(
274 callee->as<JSFunction>().baseScript()->isDerivedClassConstructor());
276 return callee->as<JSFunction>().staticPrototype();
279 static JSObject* HomeObjectSuperBase(JSObject* homeObj) {
280 MOZ_ASSERT(homeObj->is<PlainObject>() || homeObj->is<JSFunction>());
282 return homeObj->staticPrototype();
285 bool js::ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
286 MaybeConstruct construct) {
287 unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
288 int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
290 ReportValueError(cx, error, spIndex, v, nullptr);
291 return false;
294 JSObject* js::ValueToCallable(JSContext* cx, HandleValue v, int numToSkip,
295 MaybeConstruct construct) {
296 if (v.isObject() && v.toObject().isCallable()) {
297 return &v.toObject();
300 ReportIsNotFunction(cx, v, numToSkip, construct);
301 return nullptr;
304 static bool MaybeCreateThisForConstructor(JSContext* cx, const CallArgs& args) {
305 if (args.thisv().isObject()) {
306 return true;
309 RootedFunction callee(cx, &args.callee().as<JSFunction>());
310 RootedObject newTarget(cx, &args.newTarget().toObject());
312 MOZ_ASSERT(callee->hasBytecode());
314 if (!CreateThis(cx, callee, newTarget, GenericObject, args.mutableThisv())) {
315 return false;
318 // Ensure the callee still has a non-lazy script. We normally don't relazify
319 // in active compartments, but the .prototype lookup might have called the
320 // relazifyFunctions testing function that doesn't have this restriction.
321 return JSFunction::getOrCreateScript(cx, callee);
324 #ifdef ENABLE_RECORD_TUPLE
325 static bool AddRecordSpreadOperation(JSContext* cx, HandleValue recHandle,
326 HandleValue spreadeeHandle) {
327 MOZ_ASSERT(recHandle.toExtendedPrimitive().is<RecordType>());
328 RecordType* rec = &recHandle.toExtendedPrimitive().as<RecordType>();
330 RootedObject obj(cx, ToObjectOrGetObjectPayload(cx, spreadeeHandle));
332 RootedIdVector keys(cx);
333 if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_SYMBOLS, &keys)) {
334 return false;
337 size_t len = keys.length();
338 RootedId propKey(cx);
339 RootedValue propValue(cx);
340 for (size_t i = 0; i < len; i++) {
341 propKey.set(keys[i]);
343 // Step 4.c.ii.1.
344 if (MOZ_UNLIKELY(!GetProperty(cx, obj, obj, propKey, &propValue))) {
345 return false;
348 if (MOZ_UNLIKELY(!rec->initializeNextProperty(cx, propKey, propValue))) {
349 return false;
353 return true;
355 #endif
357 InterpreterFrame* InvokeState::pushInterpreterFrame(JSContext* cx) {
358 return cx->interpreterStack().pushInvokeFrame(cx, args_, construct_);
361 InterpreterFrame* ExecuteState::pushInterpreterFrame(JSContext* cx) {
362 return cx->interpreterStack().pushExecuteFrame(cx, script_, envChain_,
363 evalInFrame_);
366 InterpreterFrame* RunState::pushInterpreterFrame(JSContext* cx) {
367 if (isInvoke()) {
368 return asInvoke()->pushInterpreterFrame(cx);
370 return asExecute()->pushInterpreterFrame(cx);
373 static MOZ_ALWAYS_INLINE bool MaybeEnterInterpreterTrampoline(JSContext* cx,
374 RunState& state) {
375 #ifdef NIGHTLY_BUILD
376 if (jit::JitOptions.emitInterpreterEntryTrampoline &&
377 cx->runtime()->hasJitRuntime()) {
378 js::jit::JitRuntime* jitRuntime = cx->runtime()->jitRuntime();
379 JSScript* script = state.script();
381 uint8_t* codeRaw = nullptr;
382 auto p = jitRuntime->getInterpreterEntryMap()->lookup(script);
383 if (p) {
384 codeRaw = p->value().raw();
385 } else if (js::jit::JitCode* code =
386 jitRuntime->generateEntryTrampolineForScript(cx, script)) {
387 js::jit::EntryTrampoline entry(cx, code);
388 if (!jitRuntime->getInterpreterEntryMap()->put(script, entry)) {
389 return false;
391 codeRaw = code->raw();
394 MOZ_ASSERT(codeRaw, "Should have a valid trampoline here.");
395 // The C++ entry thunk is located at the vmInterpreterEntryOffset offset.
396 codeRaw += jitRuntime->vmInterpreterEntryOffset();
397 return js::jit::EnterInterpreterEntryTrampoline(codeRaw, cx, &state);
399 #endif
400 return Interpret(cx, state);
403 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
404 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
405 // avoid this.
406 #ifdef _MSC_VER
407 # pragma optimize("g", off)
408 #endif
409 bool js::RunScript(JSContext* cx, RunState& state) {
410 AutoCheckRecursionLimit recursion(cx);
411 if (!recursion.check(cx)) {
412 return false;
415 MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(),
416 !cx->runtime()->jitRuntime()->disallowArbitraryCode());
418 // Since any script can conceivably GC, make sure it's safe to do so.
419 cx->verifyIsSafeToGC();
421 MOZ_ASSERT(cx->realm() == state.script()->realm());
423 MOZ_DIAGNOSTIC_ASSERT(cx->realm()->isSystem() ||
424 cx->runtime()->allowContentJS());
426 if (!DebugAPI::checkNoExecute(cx, state.script())) {
427 return false;
430 GeckoProfilerEntryMarker marker(cx, state.script());
432 bool measuringTime = !cx->isMeasuringExecutionTime();
433 mozilla::TimeStamp startTime;
434 if (measuringTime) {
435 cx->setIsMeasuringExecutionTime(true);
436 cx->setIsExecuting(true);
437 startTime = mozilla::TimeStamp::Now();
439 auto timerEnd = mozilla::MakeScopeExit([&]() {
440 if (measuringTime) {
441 mozilla::TimeDuration delta = mozilla::TimeStamp::Now() - startTime;
442 cx->realm()->timers.executionTime += delta;
443 cx->setIsMeasuringExecutionTime(false);
444 cx->setIsExecuting(false);
448 jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
449 switch (status) {
450 case jit::EnterJitStatus::Error:
451 return false;
452 case jit::EnterJitStatus::Ok:
453 return true;
454 case jit::EnterJitStatus::NotEntered:
455 break;
458 bool ok = MaybeEnterInterpreterTrampoline(cx, state);
460 return ok;
462 #ifdef _MSC_VER
463 # pragma optimize("", on)
464 #endif
466 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
467 MOZ_ALWAYS_INLINE bool CallJSNative(JSContext* cx, Native native,
468 CallReason reason, const CallArgs& args) {
469 AutoCheckRecursionLimit recursion(cx);
470 if (!recursion.check(cx)) {
471 return false;
474 NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
475 if (resumeMode != NativeResumeMode::Continue) {
476 return resumeMode == NativeResumeMode::Override;
479 #ifdef DEBUG
480 bool alreadyThrowing = cx->isExceptionPending();
481 #endif
482 cx->check(args);
483 MOZ_ASSERT(!args.callee().is<ProxyObject>());
485 AutoRealm ar(cx, &args.callee());
486 bool ok = native(cx, args.length(), args.base());
487 if (ok) {
488 cx->check(args.rval());
489 MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
491 return ok;
494 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
495 MOZ_ALWAYS_INLINE bool CallJSNativeConstructor(JSContext* cx, Native native,
496 const CallArgs& args) {
497 #ifdef DEBUG
498 RootedObject callee(cx, &args.callee());
499 #endif
501 MOZ_ASSERT(args.thisv().isMagic());
502 if (!CallJSNative(cx, native, CallReason::Call, args)) {
503 return false;
507 * Native constructors must return non-primitive values on success.
508 * Although it is legal, if a constructor returns the callee, there is a
509 * 99.9999% chance it is a bug. If any valid code actually wants the
510 * constructor to return the callee, the assertion can be removed or
511 * (another) conjunct can be added to the antecedent.
513 * Exceptions:
514 * - (new Object(Object)) returns the callee.
515 * - The bound function construct hook can return an arbitrary object,
516 * including the callee.
518 * Also allow if this may be due to a debugger hook since fuzzing may let this
519 * happen.
521 MOZ_ASSERT(args.rval().isObject());
522 MOZ_ASSERT_IF(!JS_IsNativeFunction(callee, obj_construct) &&
523 !callee->is<BoundFunctionObject>() &&
524 !cx->insideDebuggerEvaluationWithOnNativeCallHook,
525 args.rval() != ObjectValue(*callee));
527 return true;
531 * Find a function reference and its 'this' value implicit first parameter
532 * under argc arguments on cx's stack, and call the function. Push missing
533 * required arguments, allocate declared local variables, and pop everything
534 * when done. Then push the return value.
536 * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
537 * necessary. The caller (usually the interpreter) must have performed
538 * this step already!
540 bool js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
541 MaybeConstruct construct,
542 CallReason reason /* = CallReason::Call */) {
543 MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
545 unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
546 if (args.calleev().isPrimitive()) {
547 return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
550 /* Invoke non-functions. */
551 if (MOZ_UNLIKELY(!args.callee().is<JSFunction>())) {
552 MOZ_ASSERT_IF(construct, !args.callee().isConstructor());
554 if (!args.callee().isCallable()) {
555 return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
558 if (args.callee().is<ProxyObject>()) {
559 RootedObject proxy(cx, &args.callee());
560 return Proxy::call(cx, proxy, args);
563 JSNative call = args.callee().callHook();
564 MOZ_ASSERT(call, "isCallable without a callHook?");
566 return CallJSNative(cx, call, reason, args);
569 /* Invoke native functions. */
570 RootedFunction fun(cx, &args.callee().as<JSFunction>());
571 if (fun->isNativeFun()) {
572 MOZ_ASSERT_IF(construct, !fun->isConstructor());
573 JSNative native = fun->native();
574 if (!construct && args.ignoresReturnValue() && fun->hasJitInfo()) {
575 const JSJitInfo* jitInfo = fun->jitInfo();
576 if (jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) {
577 native = jitInfo->ignoresReturnValueMethod;
580 return CallJSNative(cx, native, reason, args);
583 // Self-hosted builtins are considered native by the onNativeCall hook.
584 if (fun->isSelfHostedBuiltin()) {
585 NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
586 if (resumeMode != NativeResumeMode::Continue) {
587 return resumeMode == NativeResumeMode::Override;
591 if (!JSFunction::getOrCreateScript(cx, fun)) {
592 return false;
595 /* Run function until JSOp::RetRval, JSOp::Return or error. */
596 InvokeState state(cx, args, construct);
598 // Create |this| if we're constructing. Switch to the callee's realm to
599 // ensure this object has the correct realm.
600 AutoRealm ar(cx, state.script());
601 if (construct && !MaybeCreateThisForConstructor(cx, args)) {
602 return false;
605 // Calling class constructors throws an error from the callee's realm.
606 if (construct != CONSTRUCT && fun->isClassConstructor()) {
607 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
608 JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
609 return false;
612 bool ok = RunScript(cx, state);
614 MOZ_ASSERT_IF(ok && construct, args.rval().isObject());
615 return ok;
618 // Returns true if the callee needs an outerized |this| object. Outerization
619 // means passing the WindowProxy instead of the Window (a GlobalObject) because
620 // we must never expose the Window to script. This returns false only for DOM
621 // getters or setters.
622 static bool CalleeNeedsOuterizedThisObject(const Value& callee) {
623 if (!callee.isObject() || !callee.toObject().is<JSFunction>()) {
624 return true;
626 JSFunction& fun = callee.toObject().as<JSFunction>();
627 if (!fun.isNativeFun() || !fun.hasJitInfo()) {
628 return true;
630 return fun.jitInfo()->needsOuterizedThisObject();
633 static bool InternalCall(JSContext* cx, const AnyInvokeArgs& args,
634 CallReason reason) {
635 MOZ_ASSERT(args.array() + args.length() == args.end(),
636 "must pass calling arguments to a calling attempt");
638 #ifdef DEBUG
639 // The caller is responsible for calling GetThisObject if needed.
640 if (args.thisv().isObject()) {
641 JSObject* thisObj = &args.thisv().toObject();
642 MOZ_ASSERT_IF(CalleeNeedsOuterizedThisObject(args.calleev()),
643 GetThisObject(thisObj) == thisObj);
645 #endif
647 return InternalCallOrConstruct(cx, args, NO_CONSTRUCT, reason);
650 bool js::CallFromStack(JSContext* cx, const CallArgs& args,
651 CallReason reason /* = CallReason::Call */) {
652 return InternalCall(cx, static_cast<const AnyInvokeArgs&>(args), reason);
655 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
656 // 7.3.12 Call.
657 bool js::Call(JSContext* cx, HandleValue fval, HandleValue thisv,
658 const AnyInvokeArgs& args, MutableHandleValue rval,
659 CallReason reason) {
660 // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
661 // shadowing.
662 args.CallArgs::setCallee(fval);
663 args.CallArgs::setThis(thisv);
665 if (thisv.isObject()) {
666 // If |this| is a global object, it might be a Window and in that case we
667 // usually have to pass the WindowProxy instead.
668 JSObject* thisObj = &thisv.toObject();
669 if (thisObj->is<GlobalObject>()) {
670 if (CalleeNeedsOuterizedThisObject(fval)) {
671 args.mutableThisv().setObject(*GetThisObject(thisObj));
673 } else {
674 // Fast path: we don't have to do anything if the object isn't a global.
675 MOZ_ASSERT(GetThisObject(thisObj) == thisObj);
679 if (!InternalCall(cx, args, reason)) {
680 return false;
683 rval.set(args.rval());
684 return true;
687 static bool InternalConstruct(JSContext* cx, const AnyConstructArgs& args,
688 CallReason reason = CallReason::Call) {
689 MOZ_ASSERT(args.array() + args.length() + 1 == args.end(),
690 "must pass constructing arguments to a construction attempt");
691 MOZ_ASSERT(!FunctionClass.getConstruct());
692 MOZ_ASSERT(!ExtendedFunctionClass.getConstruct());
694 // Callers are responsible for enforcing these preconditions.
695 MOZ_ASSERT(IsConstructor(args.calleev()),
696 "trying to construct a value that isn't a constructor");
697 MOZ_ASSERT(IsConstructor(args.CallArgs::newTarget()),
698 "provided new.target value must be a constructor");
700 MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING) ||
701 args.thisv().isObject());
703 JSObject& callee = args.callee();
704 if (callee.is<JSFunction>()) {
705 RootedFunction fun(cx, &callee.as<JSFunction>());
707 if (fun->isNativeFun()) {
708 return CallJSNativeConstructor(cx, fun->native(), args);
711 if (!InternalCallOrConstruct(cx, args, CONSTRUCT, reason)) {
712 return false;
715 MOZ_ASSERT(args.CallArgs::rval().isObject());
716 return true;
719 if (callee.is<ProxyObject>()) {
720 RootedObject proxy(cx, &callee);
721 return Proxy::construct(cx, proxy, args);
724 JSNative construct = callee.constructHook();
725 MOZ_ASSERT(construct != nullptr, "IsConstructor without a construct hook?");
727 return CallJSNativeConstructor(cx, construct, args);
730 // Check that |callee|, the callee in a |new| expression, is a constructor.
731 static bool StackCheckIsConstructorCalleeNewTarget(JSContext* cx,
732 HandleValue callee,
733 HandleValue newTarget) {
734 // Calls from the stack could have any old non-constructor callee.
735 if (!IsConstructor(callee)) {
736 ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, callee,
737 nullptr);
738 return false;
741 // The new.target has already been vetted by previous calls, or is the callee.
742 // We can just assert that it's a constructor.
743 MOZ_ASSERT(IsConstructor(newTarget));
745 return true;
748 bool js::ConstructFromStack(JSContext* cx, const CallArgs& args,
749 CallReason reason /* CallReason::Call */) {
750 if (!StackCheckIsConstructorCalleeNewTarget(cx, args.calleev(),
751 args.newTarget())) {
752 return false;
755 return InternalConstruct(cx, static_cast<const AnyConstructArgs&>(args),
756 reason);
759 bool js::Construct(JSContext* cx, HandleValue fval,
760 const AnyConstructArgs& args, HandleValue newTarget,
761 MutableHandleObject objp) {
762 MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING));
764 // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
765 args.CallArgs::setCallee(fval);
766 args.CallArgs::newTarget().set(newTarget);
768 if (!InternalConstruct(cx, args)) {
769 return false;
772 MOZ_ASSERT(args.CallArgs::rval().isObject());
773 objp.set(&args.CallArgs::rval().toObject());
774 return true;
777 bool js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
778 HandleValue thisv,
779 const AnyConstructArgs& args,
780 HandleValue newTarget,
781 MutableHandleValue rval) {
782 args.CallArgs::setCallee(fval);
784 MOZ_ASSERT(thisv.isObject());
785 args.CallArgs::setThis(thisv);
787 args.CallArgs::newTarget().set(newTarget);
789 if (!InternalConstruct(cx, args)) {
790 return false;
793 rval.set(args.CallArgs::rval());
794 return true;
797 bool js::CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter,
798 MutableHandleValue rval) {
799 FixedInvokeArgs<0> args(cx);
801 return Call(cx, getter, thisv, args, rval, CallReason::Getter);
804 bool js::CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter,
805 HandleValue v) {
806 FixedInvokeArgs<1> args(cx);
807 args[0].set(v);
809 RootedValue ignored(cx);
810 return Call(cx, setter, thisv, args, &ignored, CallReason::Setter);
813 bool js::ExecuteKernel(JSContext* cx, HandleScript script,
814 HandleObject envChainArg, AbstractFramePtr evalInFrame,
815 MutableHandleValue result) {
816 MOZ_ASSERT_IF(script->isGlobalCode(),
817 IsGlobalLexicalEnvironment(envChainArg) ||
818 !IsSyntacticEnvironment(envChainArg));
819 #ifdef DEBUG
820 RootedObject terminatingEnv(cx, envChainArg);
821 while (IsSyntacticEnvironment(terminatingEnv)) {
822 terminatingEnv = terminatingEnv->enclosingEnvironment();
824 MOZ_ASSERT(terminatingEnv->is<GlobalObject>() ||
825 script->hasNonSyntacticScope());
826 #endif
828 if (script->treatAsRunOnce()) {
829 if (script->hasRunOnce()) {
830 JS_ReportErrorASCII(cx,
831 "Trying to execute a run-once script multiple times");
832 return false;
835 script->setHasRunOnce();
838 if (script->isEmpty()) {
839 result.setUndefined();
840 return true;
843 probes::StartExecution(script);
844 ExecuteState state(cx, script, envChainArg, evalInFrame, result);
845 bool ok = RunScript(cx, state);
846 probes::StopExecution(script);
848 return ok;
851 bool js::Execute(JSContext* cx, HandleScript script, HandleObject envChain,
852 MutableHandleValue rval) {
853 /* The env chain is something we control, so we know it can't
854 have any outer objects on it. */
855 MOZ_ASSERT(!IsWindowProxy(envChain));
857 if (script->isModule()) {
858 MOZ_RELEASE_ASSERT(
859 envChain == script->module()->environment(),
860 "Module scripts can only be executed in the module's environment");
861 } else {
862 MOZ_RELEASE_ASSERT(
863 IsGlobalLexicalEnvironment(envChain) || script->hasNonSyntacticScope(),
864 "Only global scripts with non-syntactic envs can be executed with "
865 "interesting envchains");
868 /* Ensure the env chain is all same-compartment and terminates in a global. */
869 #ifdef DEBUG
870 JSObject* s = envChain;
871 do {
872 cx->check(s);
873 MOZ_ASSERT_IF(!s->enclosingEnvironment(), s->is<GlobalObject>());
874 } while ((s = s->enclosingEnvironment()));
875 #endif
877 return ExecuteKernel(cx, script, envChain, NullFramePtr() /* evalInFrame */,
878 rval);
882 * ES6 (4-25-16) 12.10.4 InstanceofOperator
884 bool js::InstanceofOperator(JSContext* cx, HandleObject obj, HandleValue v,
885 bool* bp) {
886 /* Step 1. is handled by caller. */
888 /* Step 2. */
889 RootedValue hasInstance(cx);
890 RootedId id(cx, PropertyKey::Symbol(cx->wellKnownSymbols().hasInstance));
891 if (!GetProperty(cx, obj, obj, id, &hasInstance)) {
892 return false;
895 if (!hasInstance.isNullOrUndefined()) {
896 if (!IsCallable(hasInstance)) {
897 return ReportIsNotFunction(cx, hasInstance);
900 /* Step 3. */
901 RootedValue rval(cx);
902 if (!Call(cx, hasInstance, obj, v, &rval)) {
903 return false;
905 *bp = ToBoolean(rval);
906 return true;
909 /* Step 4. */
910 if (!obj->isCallable()) {
911 RootedValue val(cx, ObjectValue(*obj));
912 return ReportIsNotFunction(cx, val);
915 /* Step 5. */
916 return OrdinaryHasInstance(cx, obj, v, bp);
919 JSType js::TypeOfObject(JSObject* obj) {
920 #ifdef ENABLE_RECORD_TUPLE
921 MOZ_ASSERT(!js::IsExtendedPrimitive(*obj));
922 #endif
924 AutoUnsafeCallWithABI unsafe;
925 if (EmulatesUndefined(obj)) {
926 return JSTYPE_UNDEFINED;
928 if (obj->isCallable()) {
929 return JSTYPE_FUNCTION;
931 return JSTYPE_OBJECT;
934 #ifdef ENABLE_RECORD_TUPLE
935 JSType TypeOfExtendedPrimitive(JSObject* obj) {
936 MOZ_ASSERT(js::IsExtendedPrimitive(*obj));
938 if (obj->is<RecordType>()) {
939 return JSTYPE_RECORD;
941 if (obj->is<TupleType>()) {
942 return JSTYPE_TUPLE;
944 MOZ_CRASH("Unknown ExtendedPrimitive");
946 #endif
948 JSType js::TypeOfValue(const Value& v) {
949 switch (v.type()) {
950 case ValueType::Double:
951 case ValueType::Int32:
952 return JSTYPE_NUMBER;
953 case ValueType::String:
954 return JSTYPE_STRING;
955 case ValueType::Null:
956 return JSTYPE_OBJECT;
957 case ValueType::Undefined:
958 return JSTYPE_UNDEFINED;
959 case ValueType::Object:
960 return TypeOfObject(&v.toObject());
961 #ifdef ENABLE_RECORD_TUPLE
962 case ValueType::ExtendedPrimitive:
963 return TypeOfExtendedPrimitive(&v.toExtendedPrimitive());
964 #endif
965 case ValueType::Boolean:
966 return JSTYPE_BOOLEAN;
967 case ValueType::BigInt:
968 return JSTYPE_BIGINT;
969 case ValueType::Symbol:
970 return JSTYPE_SYMBOL;
971 case ValueType::Magic:
972 case ValueType::PrivateGCThing:
973 break;
976 ReportBadValueTypeAndCrash(v);
979 bool js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage) {
980 if (IsConstructor(heritage)) {
981 return true;
984 if (heritage.isNull()) {
985 return true;
988 if (heritage.isObject()) {
989 ReportIsNotFunction(cx, heritage, 0, CONSTRUCT);
990 return false;
993 ReportValueError(cx, JSMSG_BAD_HERITAGE, -1, heritage, nullptr,
994 "not an object or null");
995 return false;
998 PlainObject* js::ObjectWithProtoOperation(JSContext* cx, HandleValue val) {
999 if (!val.isObjectOrNull()) {
1000 ReportValueError(cx, JSMSG_NOT_OBJORNULL, -1, val, nullptr);
1001 return nullptr;
1004 RootedObject proto(cx, val.toObjectOrNull());
1005 return NewPlainObjectWithProto(cx, proto);
1008 JSObject* js::FunWithProtoOperation(JSContext* cx, HandleFunction fun,
1009 HandleObject parent, HandleObject proto) {
1010 return CloneFunctionReuseScript(cx, fun, parent, proto);
1014 * Enter the new with environment using an object at sp[-1] and associate the
1015 * depth of the with block with sp + stackIndex.
1017 bool js::EnterWithOperation(JSContext* cx, AbstractFramePtr frame,
1018 HandleValue val, Handle<WithScope*> scope) {
1019 RootedObject obj(cx);
1020 if (val.isObject()) {
1021 obj = &val.toObject();
1022 } else {
1023 obj = ToObject(cx, val);
1024 if (!obj) {
1025 return false;
1029 RootedObject envChain(cx, frame.environmentChain());
1030 WithEnvironmentObject* withobj =
1031 WithEnvironmentObject::create(cx, obj, envChain, scope);
1032 if (!withobj) {
1033 return false;
1036 frame.pushOnEnvironmentChain(*withobj);
1037 return true;
1040 static void PopEnvironment(JSContext* cx, EnvironmentIter& ei) {
1041 switch (ei.scope().kind()) {
1042 case ScopeKind::Lexical:
1043 case ScopeKind::SimpleCatch:
1044 case ScopeKind::Catch:
1045 case ScopeKind::NamedLambda:
1046 case ScopeKind::StrictNamedLambda:
1047 case ScopeKind::FunctionLexical:
1048 case ScopeKind::ClassBody:
1049 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1050 DebugEnvironments::onPopLexical(cx, ei);
1052 if (ei.scope().hasEnvironment()) {
1053 ei.initialFrame()
1054 .popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
1056 break;
1057 case ScopeKind::With:
1058 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1059 DebugEnvironments::onPopWith(ei.initialFrame());
1061 ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
1062 break;
1063 case ScopeKind::Function:
1064 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1065 DebugEnvironments::onPopCall(cx, ei.initialFrame());
1067 if (ei.scope().hasEnvironment()) {
1068 ei.initialFrame().popOffEnvironmentChain<CallObject>();
1070 break;
1071 case ScopeKind::FunctionBodyVar:
1072 case ScopeKind::StrictEval:
1073 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1074 DebugEnvironments::onPopVar(cx, ei);
1076 if (ei.scope().hasEnvironment()) {
1077 ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
1079 break;
1080 case ScopeKind::Module:
1081 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
1082 DebugEnvironments::onPopModule(cx, ei);
1084 break;
1085 case ScopeKind::Eval:
1086 case ScopeKind::Global:
1087 case ScopeKind::NonSyntactic:
1088 break;
1089 case ScopeKind::WasmInstance:
1090 case ScopeKind::WasmFunction:
1091 MOZ_CRASH("wasm is not interpreted");
1092 break;
1096 // Unwind environment chain and iterator to match the env corresponding to
1097 // the given bytecode position.
1098 void js::UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, jsbytecode* pc) {
1099 if (!ei.withinInitialFrame()) {
1100 return;
1103 Rooted<Scope*> scope(cx, ei.initialFrame().script()->innermostScope(pc));
1105 #ifdef DEBUG
1106 // A frame's environment chain cannot be unwound to anything enclosing the
1107 // body scope of a script. This includes the parameter defaults
1108 // environment and the decl env object. These environments, once pushed
1109 // onto the environment chain, are expected to be there for the duration
1110 // of the frame.
1112 // Attempting to unwind to the parameter defaults code in a script is a
1113 // bug; that section of code has no try-catch blocks.
1114 JSScript* script = ei.initialFrame().script();
1115 for (uint32_t i = 0; i < script->bodyScopeIndex(); i++) {
1116 MOZ_ASSERT(scope != script->getScope(GCThingIndex(i)));
1118 #endif
1120 for (; ei.maybeScope() != scope; ei++) {
1121 PopEnvironment(cx, ei);
1125 // Unwind all environments. This is needed because block scopes may cover the
1126 // first bytecode at a script's main(). e.g.,
1128 // function f() { { let i = 0; } }
1130 // will have no pc location distinguishing the first block scope from the
1131 // outermost function scope.
1132 void js::UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei) {
1133 for (; ei.withinInitialFrame(); ei++) {
1134 PopEnvironment(cx, ei);
1138 // Compute the pc needed to unwind the environment to the beginning of a try
1139 // block. We cannot unwind to *after* the JSOp::Try, because that might be the
1140 // first opcode of an inner scope, with the same problem as above. e.g.,
1142 // try { { let x; } }
1144 // will have no pc location distinguishing the try block scope from the inner
1145 // let block scope.
1146 jsbytecode* js::UnwindEnvironmentToTryPc(JSScript* script, const TryNote* tn) {
1147 jsbytecode* pc = script->offsetToPC(tn->start);
1148 if (tn->kind() == TryNoteKind::Catch || tn->kind() == TryNoteKind::Finally) {
1149 pc -= JSOpLength_Try;
1150 MOZ_ASSERT(JSOp(*pc) == JSOp::Try);
1151 } else if (tn->kind() == TryNoteKind::Destructuring) {
1152 pc -= JSOpLength_TryDestructuring;
1153 MOZ_ASSERT(JSOp(*pc) == JSOp::TryDestructuring);
1155 return pc;
1158 static void SettleOnTryNote(JSContext* cx, const TryNote* tn,
1159 EnvironmentIter& ei, InterpreterRegs& regs) {
1160 // Unwind the environment to the beginning of the JSOp::Try.
1161 UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(regs.fp()->script(), tn));
1163 // Set pc to the first bytecode after the the try note to point
1164 // to the beginning of catch or finally.
1165 regs.pc = regs.fp()->script()->offsetToPC(tn->start + tn->length);
1166 regs.sp = regs.spForStackDepth(tn->stackDepth);
1169 class InterpreterTryNoteFilter {
1170 const InterpreterRegs& regs_;
1172 public:
1173 explicit InterpreterTryNoteFilter(const InterpreterRegs& regs)
1174 : regs_(regs) {}
1175 bool operator()(const TryNote* note) {
1176 return note->stackDepth <= regs_.stackDepth();
1180 class TryNoteIterInterpreter : public TryNoteIter<InterpreterTryNoteFilter> {
1181 public:
1182 TryNoteIterInterpreter(JSContext* cx, const InterpreterRegs& regs)
1183 : TryNoteIter(cx, regs.fp()->script(), regs.pc,
1184 InterpreterTryNoteFilter(regs)) {}
1187 static void UnwindIteratorsForUncatchableException(
1188 JSContext* cx, const InterpreterRegs& regs) {
1189 // c.f. the regular (catchable) TryNoteIterInterpreter loop in
1190 // ProcessTryNotes.
1191 for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
1192 const TryNote* tn = *tni;
1193 switch (tn->kind()) {
1194 case TryNoteKind::ForIn: {
1195 Value* sp = regs.spForStackDepth(tn->stackDepth);
1196 UnwindIteratorForUncatchableException(&sp[-1].toObject());
1197 break;
1199 default:
1200 break;
1205 enum HandleErrorContinuation {
1206 SuccessfulReturnContinuation,
1207 ErrorReturnContinuation,
1208 CatchContinuation,
1209 FinallyContinuation
1212 static HandleErrorContinuation ProcessTryNotes(JSContext* cx,
1213 EnvironmentIter& ei,
1214 InterpreterRegs& regs) {
1215 for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
1216 const TryNote* tn = *tni;
1218 switch (tn->kind()) {
1219 case TryNoteKind::Catch:
1220 /* Catch cannot intercept the closing of a generator. */
1221 if (cx->isClosingGenerator()) {
1222 break;
1225 SettleOnTryNote(cx, tn, ei, regs);
1226 return CatchContinuation;
1228 case TryNoteKind::Finally:
1229 SettleOnTryNote(cx, tn, ei, regs);
1230 return FinallyContinuation;
1232 case TryNoteKind::ForIn: {
1233 /* This is similar to JSOp::EndIter in the interpreter loop. */
1234 MOZ_ASSERT(tn->stackDepth <= regs.stackDepth());
1235 Value* sp = regs.spForStackDepth(tn->stackDepth);
1236 JSObject* obj = &sp[-1].toObject();
1237 CloseIterator(obj);
1238 break;
1241 case TryNoteKind::Destructuring: {
1242 // Whether the destructuring iterator is done is at the top of the
1243 // stack. The iterator object is second from the top.
1244 MOZ_ASSERT(tn->stackDepth > 1);
1245 Value* sp = regs.spForStackDepth(tn->stackDepth);
1246 RootedValue doneValue(cx, sp[-1]);
1247 MOZ_RELEASE_ASSERT(!doneValue.isMagic());
1248 bool done = ToBoolean(doneValue);
1249 if (!done) {
1250 RootedObject iterObject(cx, &sp[-2].toObject());
1251 if (!IteratorCloseForException(cx, iterObject)) {
1252 SettleOnTryNote(cx, tn, ei, regs);
1253 return ErrorReturnContinuation;
1256 break;
1259 case TryNoteKind::ForOf:
1260 case TryNoteKind::Loop:
1261 break;
1263 // TryNoteKind::ForOfIterClose is handled internally by the try note
1264 // iterator.
1265 default:
1266 MOZ_CRASH("Invalid try note");
1270 return SuccessfulReturnContinuation;
1273 bool js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
1274 bool ok) {
1276 * Propagate the exception or error to the caller unless the exception
1277 * is an asynchronous return from a generator.
1279 if (cx->isClosingGenerator()) {
1280 cx->clearPendingException();
1281 ok = true;
1282 auto* genObj = GetGeneratorObjectForFrame(cx, frame);
1283 genObj->setClosed();
1285 return ok;
1288 static HandleErrorContinuation HandleError(JSContext* cx,
1289 InterpreterRegs& regs) {
1290 MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
1291 MOZ_ASSERT(cx->realm() == regs.fp()->script()->realm());
1293 if (regs.fp()->script()->hasScriptCounts()) {
1294 PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
1295 // If we failed to allocate, then skip the increment and continue to
1296 // handle the exception.
1297 if (counts) {
1298 counts->numExec()++;
1302 EnvironmentIter ei(cx, regs.fp(), regs.pc);
1303 bool ok = false;
1305 again:
1306 if (cx->isExceptionPending()) {
1307 /* Call debugger throw hooks. */
1308 if (!cx->isClosingGenerator()) {
1309 if (!DebugAPI::onExceptionUnwind(cx, regs.fp())) {
1310 if (!cx->isExceptionPending()) {
1311 goto again;
1314 // Ensure that the debugger hasn't returned 'true' while clearing the
1315 // exception state.
1316 MOZ_ASSERT(cx->isExceptionPending());
1319 HandleErrorContinuation res = ProcessTryNotes(cx, ei, regs);
1320 switch (res) {
1321 case SuccessfulReturnContinuation:
1322 break;
1323 case ErrorReturnContinuation:
1324 goto again;
1325 case CatchContinuation:
1326 case FinallyContinuation:
1327 // No need to increment the PCCounts number of execution here, as
1328 // the interpreter increments any PCCounts if present.
1329 MOZ_ASSERT_IF(regs.fp()->script()->hasScriptCounts(),
1330 regs.fp()->script()->maybeGetPCCounts(regs.pc));
1331 return res;
1334 ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
1335 } else {
1336 UnwindIteratorsForUncatchableException(cx, regs);
1338 // We may be propagating a forced return from a debugger hook function.
1339 if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) {
1340 cx->clearPropagatingForcedReturn();
1341 ok = true;
1345 ok = DebugAPI::onLeaveFrame(cx, regs.fp(), regs.pc, ok);
1347 // After this point, we will pop the frame regardless. Settle the frame on
1348 // the end of the script.
1349 regs.setToEndOfScript();
1351 return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation;
1354 #define REGS (activation.regs())
1355 #define PUSH_COPY(v) \
1356 do { \
1357 *REGS.sp++ = (v); \
1358 cx->debugOnlyCheck(REGS.sp[-1]); \
1359 } while (0)
1360 #define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
1361 #define PUSH_NULL() REGS.sp++->setNull()
1362 #define PUSH_UNDEFINED() REGS.sp++->setUndefined()
1363 #define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
1364 #define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
1365 #define PUSH_INT32(i) REGS.sp++->setInt32(i)
1366 #define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
1367 #define PUSH_BIGINT(b) REGS.sp++->setBigInt(b)
1368 #define PUSH_STRING(s) \
1369 do { \
1370 REGS.sp++->setString(s); \
1371 cx->debugOnlyCheck(REGS.sp[-1]); \
1372 } while (0)
1373 #define PUSH_OBJECT(obj) \
1374 do { \
1375 REGS.sp++->setObject(obj); \
1376 cx->debugOnlyCheck(REGS.sp[-1]); \
1377 } while (0)
1378 #define PUSH_OBJECT_OR_NULL(obj) \
1379 do { \
1380 REGS.sp++->setObjectOrNull(obj); \
1381 cx->debugOnlyCheck(REGS.sp[-1]); \
1382 } while (0)
1383 #ifdef ENABLE_RECORD_TUPLE
1384 # define PUSH_EXTENDED_PRIMITIVE(obj) \
1385 do { \
1386 REGS.sp++->setExtendedPrimitive(obj); \
1387 cx->debugOnlyCheck(REGS.sp[-1]); \
1388 } while (0)
1389 #endif
1390 #define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
1391 #define POP_COPY_TO(v) (v) = *--REGS.sp
1392 #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
1395 * Same for JSOp::SetName and JSOp::SetProp, which differ only slightly but
1396 * remain distinct for the decompiler.
1398 static_assert(JSOpLength_SetName == JSOpLength_SetProp);
1400 /* See TRY_BRANCH_AFTER_COND. */
1401 static_assert(JSOpLength_JumpIfTrue == JSOpLength_JumpIfFalse);
1402 static_assert(uint8_t(JSOp::JumpIfTrue) == uint8_t(JSOp::JumpIfFalse) + 1);
1405 * Compute the implicit |this| value used by a call expression with an
1406 * unqualified name reference. The environment the binding was found on is
1407 * passed as argument, env.
1409 * The implicit |this| is |undefined| for all environment types except
1410 * WithEnvironmentObject. This is the case for |with(...) {...}| expressions or
1411 * if the embedding uses a non-syntactic WithEnvironmentObject.
1413 * NOTE: A non-syntactic WithEnvironmentObject may have a corresponding
1414 * extensible LexicalEnviornmentObject, but it will not be considered as an
1415 * implicit |this|. This is for compatibility with the Gecko subscript loader.
1417 static inline Value ComputeImplicitThis(JSObject* env) {
1418 // Fast-path for GlobalObject
1419 if (env->is<GlobalObject>()) {
1420 return UndefinedValue();
1423 // WithEnvironmentObjects have an actual implicit |this|
1424 if (env->is<WithEnvironmentObject>()) {
1425 return ObjectValue(*GetThisObjectOfWith(env));
1428 // Debugger environments need special casing, as despite being
1429 // non-syntactic, they wrap syntactic environments and should not be
1430 // treated like other embedding-specific non-syntactic environments.
1431 if (env->is<DebugEnvironmentProxy>()) {
1432 return ComputeImplicitThis(&env->as<DebugEnvironmentProxy>().environment());
1435 MOZ_ASSERT(env->is<EnvironmentObject>());
1436 return UndefinedValue();
1439 static MOZ_ALWAYS_INLINE bool AddOperation(JSContext* cx,
1440 MutableHandleValue lhs,
1441 MutableHandleValue rhs,
1442 MutableHandleValue res) {
1443 if (lhs.isInt32() && rhs.isInt32()) {
1444 int32_t l = lhs.toInt32(), r = rhs.toInt32();
1445 int32_t t;
1446 if (MOZ_LIKELY(SafeAdd(l, r, &t))) {
1447 res.setInt32(t);
1448 return true;
1452 if (!ToPrimitive(cx, lhs)) {
1453 return false;
1455 if (!ToPrimitive(cx, rhs)) {
1456 return false;
1459 bool lIsString = lhs.isString();
1460 bool rIsString = rhs.isString();
1461 if (lIsString || rIsString) {
1462 JSString* lstr;
1463 if (lIsString) {
1464 lstr = lhs.toString();
1465 } else {
1466 lstr = ToString<CanGC>(cx, lhs);
1467 if (!lstr) {
1468 return false;
1472 JSString* rstr;
1473 if (rIsString) {
1474 rstr = rhs.toString();
1475 } else {
1476 // Save/restore lstr in case of GC activity under ToString.
1477 lhs.setString(lstr);
1478 rstr = ToString<CanGC>(cx, rhs);
1479 if (!rstr) {
1480 return false;
1482 lstr = lhs.toString();
1484 JSString* str = ConcatStrings<NoGC>(cx, lstr, rstr);
1485 if (!str) {
1486 RootedString nlstr(cx, lstr), nrstr(cx, rstr);
1487 str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
1488 if (!str) {
1489 return false;
1492 res.setString(str);
1493 return true;
1496 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1497 return false;
1500 if (lhs.isBigInt() || rhs.isBigInt()) {
1501 return BigInt::addValue(cx, lhs, rhs, res);
1504 res.setNumber(lhs.toNumber() + rhs.toNumber());
1505 return true;
1508 static MOZ_ALWAYS_INLINE bool SubOperation(JSContext* cx,
1509 MutableHandleValue lhs,
1510 MutableHandleValue rhs,
1511 MutableHandleValue res) {
1512 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1513 return false;
1516 if (lhs.isBigInt() || rhs.isBigInt()) {
1517 return BigInt::subValue(cx, lhs, rhs, res);
1520 res.setNumber(lhs.toNumber() - rhs.toNumber());
1521 return true;
1524 static MOZ_ALWAYS_INLINE bool MulOperation(JSContext* cx,
1525 MutableHandleValue lhs,
1526 MutableHandleValue rhs,
1527 MutableHandleValue res) {
1528 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1529 return false;
1532 if (lhs.isBigInt() || rhs.isBigInt()) {
1533 return BigInt::mulValue(cx, lhs, rhs, res);
1536 res.setNumber(lhs.toNumber() * rhs.toNumber());
1537 return true;
1540 static MOZ_ALWAYS_INLINE bool DivOperation(JSContext* cx,
1541 MutableHandleValue lhs,
1542 MutableHandleValue rhs,
1543 MutableHandleValue res) {
1544 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1545 return false;
1548 if (lhs.isBigInt() || rhs.isBigInt()) {
1549 return BigInt::divValue(cx, lhs, rhs, res);
1552 res.setNumber(NumberDiv(lhs.toNumber(), rhs.toNumber()));
1553 return true;
1556 static MOZ_ALWAYS_INLINE bool ModOperation(JSContext* cx,
1557 MutableHandleValue lhs,
1558 MutableHandleValue rhs,
1559 MutableHandleValue res) {
1560 int32_t l, r;
1561 if (lhs.isInt32() && rhs.isInt32() && (l = lhs.toInt32()) >= 0 &&
1562 (r = rhs.toInt32()) > 0) {
1563 int32_t mod = l % r;
1564 res.setInt32(mod);
1565 return true;
1568 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1569 return false;
1572 if (lhs.isBigInt() || rhs.isBigInt()) {
1573 return BigInt::modValue(cx, lhs, rhs, res);
1576 res.setNumber(NumberMod(lhs.toNumber(), rhs.toNumber()));
1577 return true;
1580 static MOZ_ALWAYS_INLINE bool PowOperation(JSContext* cx,
1581 MutableHandleValue lhs,
1582 MutableHandleValue rhs,
1583 MutableHandleValue res) {
1584 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1585 return false;
1588 if (lhs.isBigInt() || rhs.isBigInt()) {
1589 return BigInt::powValue(cx, lhs, rhs, res);
1592 res.setNumber(ecmaPow(lhs.toNumber(), rhs.toNumber()));
1593 return true;
1596 static MOZ_ALWAYS_INLINE bool BitNotOperation(JSContext* cx,
1597 MutableHandleValue in,
1598 MutableHandleValue out) {
1599 if (!ToInt32OrBigInt(cx, in)) {
1600 return false;
1603 if (in.isBigInt()) {
1604 return BigInt::bitNotValue(cx, in, out);
1607 out.setInt32(~in.toInt32());
1608 return true;
1611 static MOZ_ALWAYS_INLINE bool BitXorOperation(JSContext* cx,
1612 MutableHandleValue lhs,
1613 MutableHandleValue rhs,
1614 MutableHandleValue out) {
1615 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1616 return false;
1619 if (lhs.isBigInt() || rhs.isBigInt()) {
1620 return BigInt::bitXorValue(cx, lhs, rhs, out);
1623 out.setInt32(lhs.toInt32() ^ rhs.toInt32());
1624 return true;
1627 static MOZ_ALWAYS_INLINE bool BitOrOperation(JSContext* cx,
1628 MutableHandleValue lhs,
1629 MutableHandleValue rhs,
1630 MutableHandleValue out) {
1631 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1632 return false;
1635 if (lhs.isBigInt() || rhs.isBigInt()) {
1636 return BigInt::bitOrValue(cx, lhs, rhs, out);
1639 out.setInt32(lhs.toInt32() | rhs.toInt32());
1640 return true;
1643 static MOZ_ALWAYS_INLINE bool BitAndOperation(JSContext* cx,
1644 MutableHandleValue lhs,
1645 MutableHandleValue rhs,
1646 MutableHandleValue out) {
1647 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1648 return false;
1651 if (lhs.isBigInt() || rhs.isBigInt()) {
1652 return BigInt::bitAndValue(cx, lhs, rhs, out);
1655 out.setInt32(lhs.toInt32() & rhs.toInt32());
1656 return true;
1659 static MOZ_ALWAYS_INLINE bool BitLshOperation(JSContext* cx,
1660 MutableHandleValue lhs,
1661 MutableHandleValue rhs,
1662 MutableHandleValue out) {
1663 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1664 return false;
1667 if (lhs.isBigInt() || rhs.isBigInt()) {
1668 return BigInt::lshValue(cx, lhs, rhs, out);
1671 // Signed left-shift is undefined on overflow, so |lhs << (rhs & 31)| won't
1672 // work. Instead, convert to unsigned space (where overflow is treated
1673 // modularly), perform the operation there, then convert back.
1674 uint32_t left = static_cast<uint32_t>(lhs.toInt32());
1675 uint8_t right = rhs.toInt32() & 31;
1676 out.setInt32(mozilla::WrapToSigned(left << right));
1677 return true;
1680 static MOZ_ALWAYS_INLINE bool BitRshOperation(JSContext* cx,
1681 MutableHandleValue lhs,
1682 MutableHandleValue rhs,
1683 MutableHandleValue out) {
1684 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1685 return false;
1688 if (lhs.isBigInt() || rhs.isBigInt()) {
1689 return BigInt::rshValue(cx, lhs, rhs, out);
1692 out.setInt32(lhs.toInt32() >> (rhs.toInt32() & 31));
1693 return true;
1696 static MOZ_ALWAYS_INLINE bool UrshOperation(JSContext* cx,
1697 MutableHandleValue lhs,
1698 MutableHandleValue rhs,
1699 MutableHandleValue out) {
1700 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1701 return false;
1704 if (lhs.isBigInt() || rhs.isBigInt()) {
1705 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1706 JSMSG_BIGINT_TO_NUMBER);
1707 return false;
1710 uint32_t left;
1711 int32_t right;
1712 if (!ToUint32(cx, lhs, &left) || !ToInt32(cx, rhs, &right)) {
1713 return false;
1715 left >>= right & 31;
1716 out.setNumber(uint32_t(left));
1717 return true;
1720 // BigInt proposal 3.2.4 Abstract Relational Comparison
1721 // Returns Nothing when at least one operand is a NaN, or when
1722 // ToNumeric or StringToBigInt can't interpret a string as a numeric
1723 // value. (These cases correspond to a NaN result in the spec.)
1724 // Otherwise, return a boolean to indicate whether lhs is less than
1725 // rhs. The operands must be primitives; the caller is responsible for
1726 // evaluating them in the correct order.
1727 static MOZ_ALWAYS_INLINE bool LessThanImpl(JSContext* cx,
1728 MutableHandleValue lhs,
1729 MutableHandleValue rhs,
1730 mozilla::Maybe<bool>& res) {
1731 // Steps 1 and 2 are performed by the caller.
1733 // Step 3.
1734 if (lhs.isString() && rhs.isString()) {
1735 JSString* l = lhs.toString();
1736 JSString* r = rhs.toString();
1737 int32_t result;
1738 if (!CompareStrings(cx, l, r, &result)) {
1739 return false;
1741 res = mozilla::Some(result < 0);
1742 return true;
1745 // Step 4a.
1746 if (lhs.isBigInt() && rhs.isString()) {
1747 return BigInt::lessThan(cx, lhs, rhs, res);
1750 // Step 4b.
1751 if (lhs.isString() && rhs.isBigInt()) {
1752 return BigInt::lessThan(cx, lhs, rhs, res);
1755 // Steps 4c and 4d.
1756 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1757 return false;
1760 // Steps 4e-j.
1761 if (lhs.isBigInt() || rhs.isBigInt()) {
1762 return BigInt::lessThan(cx, lhs, rhs, res);
1765 // Step 4e for Number operands.
1766 MOZ_ASSERT(lhs.isNumber() && rhs.isNumber());
1767 double lhsNum = lhs.toNumber();
1768 double rhsNum = rhs.toNumber();
1770 if (std::isnan(lhsNum) || std::isnan(rhsNum)) {
1771 res = mozilla::Maybe<bool>(mozilla::Nothing());
1772 return true;
1775 res = mozilla::Some(lhsNum < rhsNum);
1776 return true;
1779 static MOZ_ALWAYS_INLINE bool LessThanOperation(JSContext* cx,
1780 MutableHandleValue lhs,
1781 MutableHandleValue rhs,
1782 bool* res) {
1783 if (lhs.isInt32() && rhs.isInt32()) {
1784 *res = lhs.toInt32() < rhs.toInt32();
1785 return true;
1788 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1789 return false;
1792 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1793 return false;
1796 mozilla::Maybe<bool> tmpResult;
1797 if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1798 return false;
1800 *res = tmpResult.valueOr(false);
1801 return true;
1804 static MOZ_ALWAYS_INLINE bool LessThanOrEqualOperation(JSContext* cx,
1805 MutableHandleValue lhs,
1806 MutableHandleValue rhs,
1807 bool* res) {
1808 if (lhs.isInt32() && rhs.isInt32()) {
1809 *res = lhs.toInt32() <= rhs.toInt32();
1810 return true;
1813 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1814 return false;
1817 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1818 return false;
1821 mozilla::Maybe<bool> tmpResult;
1822 if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1823 return false;
1825 *res = !tmpResult.valueOr(true);
1826 return true;
1829 static MOZ_ALWAYS_INLINE bool GreaterThanOperation(JSContext* cx,
1830 MutableHandleValue lhs,
1831 MutableHandleValue rhs,
1832 bool* res) {
1833 if (lhs.isInt32() && rhs.isInt32()) {
1834 *res = lhs.toInt32() > rhs.toInt32();
1835 return true;
1838 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1839 return false;
1842 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1843 return false;
1846 mozilla::Maybe<bool> tmpResult;
1847 if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1848 return false;
1850 *res = tmpResult.valueOr(false);
1851 return true;
1854 static MOZ_ALWAYS_INLINE bool GreaterThanOrEqualOperation(
1855 JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
1856 if (lhs.isInt32() && rhs.isInt32()) {
1857 *res = lhs.toInt32() >= rhs.toInt32();
1858 return true;
1861 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1862 return false;
1865 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1866 return false;
1869 mozilla::Maybe<bool> tmpResult;
1870 if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1871 return false;
1873 *res = !tmpResult.valueOr(true);
1874 return true;
1877 static MOZ_ALWAYS_INLINE bool SetObjectElementOperation(
1878 JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
1879 HandleValue receiver, bool strict) {
1880 ObjectOpResult result;
1881 return SetProperty(cx, obj, id, value, receiver, result) &&
1882 result.checkStrictModeError(cx, obj, id, strict);
1885 static MOZ_ALWAYS_INLINE void InitElemArrayOperation(JSContext* cx,
1886 jsbytecode* pc,
1887 Handle<ArrayObject*> arr,
1888 HandleValue val) {
1889 MOZ_ASSERT(JSOp(*pc) == JSOp::InitElemArray);
1891 // The dense elements must have been initialized up to this index. The JIT
1892 // implementation also depends on this.
1893 uint32_t index = GET_UINT32(pc);
1894 MOZ_ASSERT(index < arr->getDenseCapacity());
1895 MOZ_ASSERT(index == arr->getDenseInitializedLength());
1897 // Bump the initialized length even for hole values to ensure the
1898 // index == initLength invariant holds for later InitElemArray ops.
1899 arr->setDenseInitializedLength(index + 1);
1901 if (val.isMagic(JS_ELEMENTS_HOLE)) {
1902 arr->initDenseElementHole(index);
1903 } else {
1904 arr->initDenseElement(index, val);
1909 * As an optimization, the interpreter creates a handful of reserved Rooted<T>
1910 * variables at the beginning, thus inserting them into the Rooted list once
1911 * upon entry. ReservedRooted "borrows" a reserved Rooted variable and uses it
1912 * within a local scope, resetting the value to nullptr (or the appropriate
1913 * equivalent for T) at scope end. This avoids inserting/removing the Rooted
1914 * from the rooter list, while preventing stale values from being kept alive
1915 * unnecessarily.
1918 template <typename T>
1919 class ReservedRooted : public RootedOperations<T, ReservedRooted<T>> {
1920 Rooted<T>* savedRoot;
1922 public:
1923 ReservedRooted(Rooted<T>* root, const T& ptr) : savedRoot(root) {
1924 *root = ptr;
1927 explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
1928 *root = JS::SafelyInitialized<T>::create();
1931 ~ReservedRooted() { *savedRoot = JS::SafelyInitialized<T>::create(); }
1933 void set(const T& p) const { *savedRoot = p; }
1934 operator Handle<T>() { return *savedRoot; }
1935 operator Rooted<T>&() { return *savedRoot; }
1936 MutableHandle<T> operator&() { return &*savedRoot; }
1938 DECLARE_NONPOINTER_ACCESSOR_METHODS(savedRoot->get())
1939 DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(savedRoot->get())
1940 DECLARE_POINTER_CONSTREF_OPS(T)
1941 DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
1944 void js::ReportInNotObjectError(JSContext* cx, HandleValue lref,
1945 HandleValue rref) {
1946 auto uniqueCharsFromString = [](JSContext* cx,
1947 HandleValue ref) -> UniqueChars {
1948 static const size_t MaxStringLength = 16;
1949 RootedString str(cx, ref.toString());
1950 if (str->length() > MaxStringLength) {
1951 JSStringBuilder buf(cx);
1952 if (!buf.appendSubstring(str, 0, MaxStringLength)) {
1953 return nullptr;
1955 if (!buf.append("...")) {
1956 return nullptr;
1958 str = buf.finishString();
1959 if (!str) {
1960 return nullptr;
1963 return QuoteString(cx, str, '"');
1966 if (lref.isString() && rref.isString()) {
1967 UniqueChars lbytes = uniqueCharsFromString(cx, lref);
1968 if (!lbytes) {
1969 return;
1971 UniqueChars rbytes = uniqueCharsFromString(cx, rref);
1972 if (!rbytes) {
1973 return;
1975 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_IN_STRING,
1976 lbytes.get(), rbytes.get());
1977 return;
1980 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_IN_NOT_OBJECT,
1981 InformalValueTypeName(rref));
1984 bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER js::Interpret(JSContext* cx,
1985 RunState& state) {
1987 * Define macros for an interpreter loop. Opcode dispatch is done by
1988 * indirect goto (aka a threaded interpreter), which is technically
1989 * non-standard but is supported by all of our supported compilers.
1991 #define INTERPRETER_LOOP()
1992 #define CASE(OP) label_##OP:
1993 #define DEFAULT() \
1994 label_default:
1995 #define DISPATCH_TO(OP) goto* addresses[(OP)]
1997 #define LABEL(X) (&&label_##X)
1999 // Use addresses instead of offsets to optimize for runtime speed over
2000 // load-time relocation overhead.
2001 static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = {
2002 #define OPCODE_LABEL(op, ...) LABEL(op),
2003 FOR_EACH_OPCODE(OPCODE_LABEL)
2004 #undef OPCODE_LABEL
2005 #define TRAILING_LABEL(v) \
2006 ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
2007 : LABEL(default)),
2008 FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)
2009 #undef TRAILING_LABEL
2013 * Increment REGS.pc by N, load the opcode at that position,
2014 * and jump to the code to execute it.
2016 * When Debugger puts a script in single-step mode, all js::Interpret
2017 * invocations that might be presently running that script must have
2018 * interrupts enabled. It's not practical to simply check
2019 * script->stepModeEnabled() at each point some callee could have changed
2020 * it, because there are so many places js::Interpret could possibly cause
2021 * JavaScript to run: each place an object might be coerced to a primitive
2022 * or a number, for example. So instead, we expose a simple mechanism to
2023 * let Debugger tweak the affected js::Interpret frames when an onStep
2024 * handler is added: calling activation.enableInterruptsUnconditionally()
2025 * will enable interrupts, and activation.opMask() is or'd with the opcode
2026 * to implement a simple alternate dispatch.
2028 #define ADVANCE_AND_DISPATCH(N) \
2029 JS_BEGIN_MACRO \
2030 REGS.pc += (N); \
2031 SANITY_CHECKS(); \
2032 DISPATCH_TO(*REGS.pc | activation.opMask()); \
2033 JS_END_MACRO
2036 * Shorthand for the common sequence at the end of a fixed-size opcode.
2038 #define END_CASE(OP) ADVANCE_AND_DISPATCH(JSOpLength_##OP);
2041 * Prepare to call a user-supplied branch handler, and abort the script
2042 * if it returns false.
2044 #define CHECK_BRANCH() \
2045 JS_BEGIN_MACRO \
2046 if (!CheckForInterrupt(cx)) goto error; \
2047 JS_END_MACRO
2050 * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
2051 * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
2052 * is the backedge of a loop.
2054 #define BRANCH(n) \
2055 JS_BEGIN_MACRO \
2056 int32_t nlen = (n); \
2057 if (nlen <= 0) CHECK_BRANCH(); \
2058 ADVANCE_AND_DISPATCH(nlen); \
2059 JS_END_MACRO
2062 * Initialize code coverage vectors.
2064 #define INIT_COVERAGE() \
2065 JS_BEGIN_MACRO \
2066 if (!script->hasScriptCounts()) { \
2067 if (cx->realm()->collectCoverageForDebug()) { \
2068 if (!script->initScriptCounts(cx)) goto error; \
2071 JS_END_MACRO
2074 * Increment the code coverage counter associated with the given pc.
2076 #define COUNT_COVERAGE_PC(PC) \
2077 JS_BEGIN_MACRO \
2078 if (script->hasScriptCounts()) { \
2079 PCCounts* counts = script->maybeGetPCCounts(PC); \
2080 MOZ_ASSERT(counts); \
2081 counts->numExec()++; \
2083 JS_END_MACRO
2085 #define COUNT_COVERAGE_MAIN() \
2086 JS_BEGIN_MACRO \
2087 jsbytecode* main = script->main(); \
2088 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
2089 JS_END_MACRO
2091 #define COUNT_COVERAGE() \
2092 JS_BEGIN_MACRO \
2093 MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
2094 COUNT_COVERAGE_PC(REGS.pc); \
2095 JS_END_MACRO
2097 #define SET_SCRIPT(s) \
2098 JS_BEGIN_MACRO \
2099 script = (s); \
2100 MOZ_ASSERT(cx->realm() == script->realm()); \
2101 if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
2102 script->hasScriptCounts()) \
2103 activation.enableInterruptsUnconditionally(); \
2104 JS_END_MACRO
2106 #define SANITY_CHECKS() \
2107 JS_BEGIN_MACRO \
2108 js::gc::MaybeVerifyBarriers(cx); \
2109 JS_END_MACRO
2111 // Verify that an uninitialized lexical is followed by a correct check op.
2112 #ifdef DEBUG
2113 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2114 JS_BEGIN_MACRO \
2115 if (IsUninitializedLexical(val)) { \
2116 JSOp next = JSOp(*GetNextPc(REGS.pc)); \
2117 MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn || \
2118 next == JSOp::CheckThisReinit || \
2119 next == JSOp::CheckAliasedLexical); \
2121 JS_END_MACRO
2122 #else
2123 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2124 JS_BEGIN_MACRO \
2125 /* nothing */ \
2126 JS_END_MACRO
2127 #endif
2129 gc::MaybeVerifyBarriers(cx, true);
2131 InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
2132 if (!entryFrame) {
2133 return false;
2136 ActivationEntryMonitor entryMonitor(cx, entryFrame);
2137 InterpreterActivation activation(state, cx, entryFrame);
2139 /* The script is used frequently, so keep a local copy. */
2140 RootedScript script(cx);
2141 SET_SCRIPT(REGS.fp()->script());
2144 * Pool of rooters for use in this interpreter frame. References to these
2145 * are used for local variables within interpreter cases. This avoids
2146 * creating new rooters each time an interpreter case is entered, and also
2147 * correctness pitfalls due to incorrect compilation of destructor calls
2148 * around computed gotos.
2150 RootedValue rootValue0(cx), rootValue1(cx);
2151 RootedObject rootObject0(cx), rootObject1(cx);
2152 RootedFunction rootFunction0(cx);
2153 Rooted<JSAtom*> rootAtom0(cx);
2154 Rooted<PropertyName*> rootName0(cx);
2155 RootedId rootId0(cx);
2156 RootedScript rootScript0(cx);
2157 Rooted<Scope*> rootScope0(cx);
2158 DebugOnly<uint32_t> blockDepth;
2160 /* State communicated between non-local jumps: */
2161 bool interpReturnOK;
2162 bool frameHalfInitialized;
2164 if (!activation.entryFrame()->prologue(cx)) {
2165 goto prologue_error;
2168 if (!DebugAPI::onEnterFrame(cx, activation.entryFrame())) {
2169 goto error;
2172 // Increment the coverage for the main entry point.
2173 INIT_COVERAGE();
2174 COUNT_COVERAGE_MAIN();
2176 // Enter the interpreter loop starting at the current pc.
2177 ADVANCE_AND_DISPATCH(0);
2179 INTERPRETER_LOOP() {
2180 CASE(EnableInterruptsPseudoOpcode) {
2181 bool moreInterrupts = false;
2182 jsbytecode op = *REGS.pc;
2184 if (!script->hasScriptCounts() &&
2185 cx->realm()->collectCoverageForDebug()) {
2186 if (!script->initScriptCounts(cx)) {
2187 goto error;
2191 if (script->isDebuggee()) {
2192 if (DebugAPI::stepModeEnabled(script)) {
2193 if (!DebugAPI::onSingleStep(cx)) {
2194 goto error;
2196 moreInterrupts = true;
2199 if (DebugAPI::hasAnyBreakpointsOrStepMode(script)) {
2200 moreInterrupts = true;
2203 if (DebugAPI::hasBreakpointsAt(script, REGS.pc)) {
2204 if (!DebugAPI::onTrap(cx)) {
2205 goto error;
2210 MOZ_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
2211 if (!moreInterrupts) {
2212 activation.clearInterruptsMask();
2215 /* Commence executing the actual opcode. */
2216 SANITY_CHECKS();
2217 DISPATCH_TO(op);
2220 /* Various 1-byte no-ops. */
2221 CASE(Nop)
2222 CASE(Try)
2223 CASE(NopDestructuring)
2224 CASE(TryDestructuring) {
2225 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);
2226 ADVANCE_AND_DISPATCH(1);
2229 CASE(JumpTarget)
2230 COUNT_COVERAGE();
2231 END_CASE(JumpTarget)
2233 CASE(LoopHead) {
2234 COUNT_COVERAGE();
2236 // Attempt on-stack replacement into the Baseline Interpreter.
2237 if (jit::IsBaselineInterpreterEnabled()) {
2238 script->incWarmUpCounter();
2240 jit::MethodStatus status =
2241 jit::CanEnterBaselineInterpreterAtBranch(cx, REGS.fp());
2242 if (status == jit::Method_Error) {
2243 goto error;
2245 if (status == jit::Method_Compiled) {
2246 bool wasProfiler = REGS.fp()->hasPushedGeckoProfilerFrame();
2248 jit::JitExecStatus maybeOsr;
2250 GeckoProfilerBaselineOSRMarker osr(cx, wasProfiler);
2251 maybeOsr =
2252 jit::EnterBaselineInterpreterAtBranch(cx, REGS.fp(), REGS.pc);
2255 // We failed to call into baseline at all, so treat as an error.
2256 if (maybeOsr == jit::JitExec_Aborted) {
2257 goto error;
2260 interpReturnOK = (maybeOsr == jit::JitExec_Ok);
2262 // Pop the profiler frame pushed by the interpreter. (The compiled
2263 // version of the function popped a copy of the frame pushed by the
2264 // OSR trampoline.)
2265 if (wasProfiler) {
2266 cx->geckoProfiler().exit(cx, script);
2269 if (activation.entryFrame() != REGS.fp()) {
2270 goto jit_return_pop_frame;
2272 goto leave_on_safe_point;
2276 END_CASE(LoopHead)
2278 CASE(Lineno)
2279 END_CASE(Lineno)
2281 CASE(ForceInterpreter) {
2282 // Ensure pattern matching still works.
2283 MOZ_ASSERT(script->hasForceInterpreterOp());
2285 END_CASE(ForceInterpreter)
2287 CASE(Undefined) { PUSH_UNDEFINED(); }
2288 END_CASE(Undefined)
2290 CASE(Pop) { REGS.sp--; }
2291 END_CASE(Pop)
2293 CASE(PopN) {
2294 MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
2295 REGS.sp -= GET_UINT16(REGS.pc);
2297 END_CASE(PopN)
2299 CASE(DupAt) {
2300 MOZ_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
2301 unsigned i = GET_UINT24(REGS.pc);
2302 const Value& rref = REGS.sp[-int(i + 1)];
2303 PUSH_COPY(rref);
2305 END_CASE(DupAt)
2307 CASE(SetRval) { POP_RETURN_VALUE(); }
2308 END_CASE(SetRval)
2310 CASE(GetRval) { PUSH_COPY(REGS.fp()->returnValue()); }
2311 END_CASE(GetRval)
2313 CASE(EnterWith) {
2314 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
2315 REGS.sp--;
2316 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
2318 if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>())) {
2319 goto error;
2322 END_CASE(EnterWith)
2324 CASE(LeaveWith) {
2325 REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
2327 END_CASE(LeaveWith)
2329 CASE(Return) {
2330 POP_RETURN_VALUE();
2331 /* FALL THROUGH */
2333 CASE(RetRval) {
2335 * When the inlined frame exits with an exception or an error, ok will be
2336 * false after the inline_return label.
2338 CHECK_BRANCH();
2340 successful_return_continuation:
2341 interpReturnOK = true;
2343 return_continuation:
2344 frameHalfInitialized = false;
2346 prologue_return_continuation:
2348 if (activation.entryFrame() != REGS.fp()) {
2349 // Stop the engine. (No details about which engine exactly, could be
2350 // interpreter, Baseline or IonMonkey.)
2351 if (MOZ_LIKELY(!frameHalfInitialized)) {
2352 interpReturnOK =
2353 DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
2355 REGS.fp()->epilogue(cx, REGS.pc);
2358 jit_return_pop_frame:
2360 activation.popInlineFrame(REGS.fp());
2362 JSScript* callerScript = REGS.fp()->script();
2363 if (cx->realm() != callerScript->realm()) {
2364 cx->leaveRealm(callerScript->realm());
2366 SET_SCRIPT(callerScript);
2369 jit_return:
2371 MOZ_ASSERT(IsInvokePC(REGS.pc));
2372 MOZ_ASSERT(cx->realm() == script->realm());
2374 /* Resume execution in the calling frame. */
2375 if (MOZ_LIKELY(interpReturnOK)) {
2376 if (JSOp(*REGS.pc) == JSOp::Resume) {
2377 ADVANCE_AND_DISPATCH(JSOpLength_Resume);
2380 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == JSOpLength_Call);
2381 ADVANCE_AND_DISPATCH(JSOpLength_Call);
2384 goto error;
2385 } else {
2386 // Stack should be empty for the outer frame, unless we executed the
2387 // first |await| expression in an async function.
2388 MOZ_ASSERT(REGS.stackDepth() == 0 ||
2389 (JSOp(*REGS.pc) == JSOp::Await &&
2390 !REGS.fp()->isResumedGenerator()));
2392 goto exit;
2395 CASE(Default) {
2396 REGS.sp--;
2397 /* FALL THROUGH */
2399 CASE(Goto) { BRANCH(GET_JUMP_OFFSET(REGS.pc)); }
2401 CASE(JumpIfFalse) {
2402 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2403 REGS.sp--;
2404 if (!cond) {
2405 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2408 END_CASE(JumpIfFalse)
2410 CASE(JumpIfTrue) {
2411 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2412 REGS.sp--;
2413 if (cond) {
2414 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2417 END_CASE(JumpIfTrue)
2419 CASE(Or) {
2420 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2421 if (cond) {
2422 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2425 END_CASE(Or)
2427 CASE(Coalesce) {
2428 MutableHandleValue res = REGS.stackHandleAt(-1);
2429 bool cond = !res.isNullOrUndefined();
2430 if (cond) {
2431 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2434 END_CASE(Coalesce)
2436 CASE(And) {
2437 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2438 if (!cond) {
2439 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2442 END_CASE(And)
2444 #define FETCH_ELEMENT_ID(n, id) \
2445 JS_BEGIN_MACRO \
2446 if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
2447 JS_END_MACRO
2449 #define TRY_BRANCH_AFTER_COND(cond, spdec) \
2450 JS_BEGIN_MACRO \
2451 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1); \
2452 unsigned diff_ = \
2453 (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
2454 if (diff_ <= 1) { \
2455 REGS.sp -= (spdec); \
2456 if ((cond) == (diff_ != 0)) { \
2457 ++REGS.pc; \
2458 BRANCH(GET_JUMP_OFFSET(REGS.pc)); \
2460 ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse); \
2462 JS_END_MACRO
2464 CASE(In) {
2465 HandleValue rref = REGS.stackHandleAt(-1);
2466 if (!rref.isObject()) {
2467 HandleValue lref = REGS.stackHandleAt(-2);
2468 ReportInNotObjectError(cx, lref, rref);
2469 goto error;
2471 bool found;
2473 ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
2474 ReservedRooted<jsid> id(&rootId0);
2475 FETCH_ELEMENT_ID(-2, id);
2476 if (!HasProperty(cx, obj, id, &found)) {
2477 goto error;
2480 TRY_BRANCH_AFTER_COND(found, 2);
2481 REGS.sp--;
2482 REGS.sp[-1].setBoolean(found);
2484 END_CASE(In)
2486 CASE(HasOwn) {
2487 HandleValue val = REGS.stackHandleAt(-1);
2488 HandleValue idval = REGS.stackHandleAt(-2);
2490 bool found;
2491 if (!HasOwnProperty(cx, val, idval, &found)) {
2492 goto error;
2495 REGS.sp--;
2496 REGS.sp[-1].setBoolean(found);
2498 END_CASE(HasOwn)
2500 CASE(CheckPrivateField) {
2501 /* Load the object being initialized into lval/val. */
2502 HandleValue val = REGS.stackHandleAt(-2);
2503 HandleValue idval = REGS.stackHandleAt(-1);
2505 bool result = false;
2506 if (!CheckPrivateFieldOperation(cx, REGS.pc, val, idval, &result)) {
2507 goto error;
2510 PUSH_BOOLEAN(result);
2512 END_CASE(CheckPrivateField)
2514 CASE(NewPrivateName) {
2515 ReservedRooted<JSAtom*> name(&rootAtom0, script->getAtom(REGS.pc));
2517 auto* symbol = NewPrivateName(cx, name);
2518 if (!symbol) {
2519 goto error;
2522 PUSH_SYMBOL(symbol);
2524 END_CASE(NewPrivateName)
2526 CASE(IsNullOrUndefined) {
2527 bool b = REGS.sp[-1].isNullOrUndefined();
2528 PUSH_BOOLEAN(b);
2530 END_CASE(IsNullOrUndefined)
2532 CASE(Iter) {
2533 MOZ_ASSERT(REGS.stackDepth() >= 1);
2534 HandleValue val = REGS.stackHandleAt(-1);
2535 JSObject* iter = ValueToIterator(cx, val);
2536 if (!iter) {
2537 goto error;
2539 REGS.sp[-1].setObject(*iter);
2541 END_CASE(Iter)
2543 CASE(MoreIter) {
2544 MOZ_ASSERT(REGS.stackDepth() >= 1);
2545 MOZ_ASSERT(REGS.sp[-1].isObject());
2546 Value v = IteratorMore(&REGS.sp[-1].toObject());
2547 PUSH_COPY(v);
2549 END_CASE(MoreIter)
2551 CASE(IsNoIter) {
2552 bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
2553 PUSH_BOOLEAN(b);
2555 END_CASE(IsNoIter)
2557 CASE(EndIter) {
2558 MOZ_ASSERT(REGS.stackDepth() >= 2);
2559 CloseIterator(&REGS.sp[-2].toObject());
2560 REGS.sp -= 2;
2562 END_CASE(EndIter)
2564 CASE(CloseIter) {
2565 ReservedRooted<JSObject*> iter(&rootObject0, &REGS.sp[-1].toObject());
2566 CompletionKind kind = CompletionKind(GET_UINT8(REGS.pc));
2567 if (!CloseIterOperation(cx, iter, kind)) {
2568 goto error;
2570 REGS.sp--;
2572 END_CASE(CloseIter)
2574 CASE(IsGenClosing) {
2575 bool b = REGS.sp[-1].isMagic(JS_GENERATOR_CLOSING);
2576 PUSH_BOOLEAN(b);
2578 END_CASE(IsGenClosing)
2580 CASE(Dup) {
2581 MOZ_ASSERT(REGS.stackDepth() >= 1);
2582 const Value& rref = REGS.sp[-1];
2583 PUSH_COPY(rref);
2585 END_CASE(Dup)
2587 CASE(Dup2) {
2588 MOZ_ASSERT(REGS.stackDepth() >= 2);
2589 const Value& lref = REGS.sp[-2];
2590 const Value& rref = REGS.sp[-1];
2591 PUSH_COPY(lref);
2592 PUSH_COPY(rref);
2594 END_CASE(Dup2)
2596 CASE(Swap) {
2597 MOZ_ASSERT(REGS.stackDepth() >= 2);
2598 Value& lref = REGS.sp[-2];
2599 Value& rref = REGS.sp[-1];
2600 lref.swap(rref);
2602 END_CASE(Swap)
2604 CASE(Pick) {
2605 unsigned i = GET_UINT8(REGS.pc);
2606 MOZ_ASSERT(REGS.stackDepth() >= i + 1);
2607 Value lval = REGS.sp[-int(i + 1)];
2608 memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i);
2609 REGS.sp[-1] = lval;
2611 END_CASE(Pick)
2613 CASE(Unpick) {
2614 int i = GET_UINT8(REGS.pc);
2615 MOZ_ASSERT(REGS.stackDepth() >= unsigned(i) + 1);
2616 Value lval = REGS.sp[-1];
2617 memmove(REGS.sp - i, REGS.sp - (i + 1), sizeof(Value) * i);
2618 REGS.sp[-(i + 1)] = lval;
2620 END_CASE(Unpick)
2622 CASE(BindGName)
2623 CASE(BindName) {
2624 JSOp op = JSOp(*REGS.pc);
2625 ReservedRooted<JSObject*> envChain(&rootObject0);
2626 if (op == JSOp::BindName) {
2627 envChain.set(REGS.fp()->environmentChain());
2628 } else {
2629 MOZ_ASSERT(!script->hasNonSyntacticScope());
2630 envChain.set(&REGS.fp()->global().lexicalEnvironment());
2632 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2634 // Assigning to an undeclared name adds a property to the global object.
2635 ReservedRooted<JSObject*> env(&rootObject1);
2636 if (!LookupNameUnqualified(cx, name, envChain, &env)) {
2637 goto error;
2640 PUSH_OBJECT(*env);
2642 static_assert(JSOpLength_BindName == JSOpLength_BindGName,
2643 "We're sharing the END_CASE so the lengths better match");
2645 END_CASE(BindName)
2647 CASE(BindVar) {
2648 JSObject* varObj = BindVarOperation(cx, REGS.fp()->environmentChain());
2649 PUSH_OBJECT(*varObj);
2651 END_CASE(BindVar)
2653 CASE(BitOr) {
2654 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2655 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2656 MutableHandleValue res = REGS.stackHandleAt(-2);
2657 if (!BitOrOperation(cx, lhs, rhs, res)) {
2658 goto error;
2660 REGS.sp--;
2662 END_CASE(BitOr)
2664 CASE(BitXor) {
2665 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2666 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2667 MutableHandleValue res = REGS.stackHandleAt(-2);
2668 if (!BitXorOperation(cx, lhs, rhs, res)) {
2669 goto error;
2671 REGS.sp--;
2673 END_CASE(BitXor)
2675 CASE(BitAnd) {
2676 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2677 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2678 MutableHandleValue res = REGS.stackHandleAt(-2);
2679 if (!BitAndOperation(cx, lhs, rhs, res)) {
2680 goto error;
2682 REGS.sp--;
2684 END_CASE(BitAnd)
2686 CASE(Eq) {
2687 if (!LooseEqualityOp<true>(cx, REGS)) {
2688 goto error;
2691 END_CASE(Eq)
2693 CASE(Ne) {
2694 if (!LooseEqualityOp<false>(cx, REGS)) {
2695 goto error;
2698 END_CASE(Ne)
2700 #define STRICT_EQUALITY_OP(OP, COND) \
2701 JS_BEGIN_MACRO \
2702 HandleValue lval = REGS.stackHandleAt(-2); \
2703 HandleValue rval = REGS.stackHandleAt(-1); \
2704 bool equal; \
2705 if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
2706 goto error; \
2708 (COND) = equal OP true; \
2709 REGS.sp--; \
2710 JS_END_MACRO
2712 CASE(StrictEq) {
2713 bool cond;
2714 STRICT_EQUALITY_OP(==, cond);
2715 REGS.sp[-1].setBoolean(cond);
2717 END_CASE(StrictEq)
2719 CASE(StrictNe) {
2720 bool cond;
2721 STRICT_EQUALITY_OP(!=, cond);
2722 REGS.sp[-1].setBoolean(cond);
2724 END_CASE(StrictNe)
2726 #undef STRICT_EQUALITY_OP
2728 CASE(Case) {
2729 bool cond = REGS.sp[-1].toBoolean();
2730 REGS.sp--;
2731 if (cond) {
2732 REGS.sp--;
2733 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2736 END_CASE(Case)
2738 CASE(Lt) {
2739 bool cond;
2740 MutableHandleValue lval = REGS.stackHandleAt(-2);
2741 MutableHandleValue rval = REGS.stackHandleAt(-1);
2742 if (!LessThanOperation(cx, lval, rval, &cond)) {
2743 goto error;
2745 TRY_BRANCH_AFTER_COND(cond, 2);
2746 REGS.sp[-2].setBoolean(cond);
2747 REGS.sp--;
2749 END_CASE(Lt)
2751 CASE(Le) {
2752 bool cond;
2753 MutableHandleValue lval = REGS.stackHandleAt(-2);
2754 MutableHandleValue rval = REGS.stackHandleAt(-1);
2755 if (!LessThanOrEqualOperation(cx, lval, rval, &cond)) {
2756 goto error;
2758 TRY_BRANCH_AFTER_COND(cond, 2);
2759 REGS.sp[-2].setBoolean(cond);
2760 REGS.sp--;
2762 END_CASE(Le)
2764 CASE(Gt) {
2765 bool cond;
2766 MutableHandleValue lval = REGS.stackHandleAt(-2);
2767 MutableHandleValue rval = REGS.stackHandleAt(-1);
2768 if (!GreaterThanOperation(cx, lval, rval, &cond)) {
2769 goto error;
2771 TRY_BRANCH_AFTER_COND(cond, 2);
2772 REGS.sp[-2].setBoolean(cond);
2773 REGS.sp--;
2775 END_CASE(Gt)
2777 CASE(Ge) {
2778 bool cond;
2779 MutableHandleValue lval = REGS.stackHandleAt(-2);
2780 MutableHandleValue rval = REGS.stackHandleAt(-1);
2781 if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond)) {
2782 goto error;
2784 TRY_BRANCH_AFTER_COND(cond, 2);
2785 REGS.sp[-2].setBoolean(cond);
2786 REGS.sp--;
2788 END_CASE(Ge)
2790 CASE(Lsh) {
2791 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2792 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2793 MutableHandleValue res = REGS.stackHandleAt(-2);
2794 if (!BitLshOperation(cx, lhs, rhs, res)) {
2795 goto error;
2797 REGS.sp--;
2799 END_CASE(Lsh)
2801 CASE(Rsh) {
2802 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2803 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2804 MutableHandleValue res = REGS.stackHandleAt(-2);
2805 if (!BitRshOperation(cx, lhs, rhs, res)) {
2806 goto error;
2808 REGS.sp--;
2810 END_CASE(Rsh)
2812 CASE(Ursh) {
2813 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2814 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2815 MutableHandleValue res = REGS.stackHandleAt(-2);
2816 if (!UrshOperation(cx, lhs, rhs, res)) {
2817 goto error;
2819 REGS.sp--;
2821 END_CASE(Ursh)
2823 CASE(Add) {
2824 MutableHandleValue lval = REGS.stackHandleAt(-2);
2825 MutableHandleValue rval = REGS.stackHandleAt(-1);
2826 MutableHandleValue res = REGS.stackHandleAt(-2);
2827 if (!AddOperation(cx, lval, rval, res)) {
2828 goto error;
2830 REGS.sp--;
2832 END_CASE(Add)
2834 CASE(Sub) {
2835 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2836 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2837 MutableHandleValue res = REGS.stackHandleAt(-2);
2838 if (!SubOperation(cx, &lval, &rval, res)) {
2839 goto error;
2841 REGS.sp--;
2843 END_CASE(Sub)
2845 CASE(Mul) {
2846 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2847 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2848 MutableHandleValue res = REGS.stackHandleAt(-2);
2849 if (!MulOperation(cx, &lval, &rval, res)) {
2850 goto error;
2852 REGS.sp--;
2854 END_CASE(Mul)
2856 CASE(Div) {
2857 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2858 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2859 MutableHandleValue res = REGS.stackHandleAt(-2);
2860 if (!DivOperation(cx, &lval, &rval, res)) {
2861 goto error;
2863 REGS.sp--;
2865 END_CASE(Div)
2867 CASE(Mod) {
2868 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2869 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2870 MutableHandleValue res = REGS.stackHandleAt(-2);
2871 if (!ModOperation(cx, &lval, &rval, res)) {
2872 goto error;
2874 REGS.sp--;
2876 END_CASE(Mod)
2878 CASE(Pow) {
2879 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2880 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2881 MutableHandleValue res = REGS.stackHandleAt(-2);
2882 if (!PowOperation(cx, &lval, &rval, res)) {
2883 goto error;
2885 REGS.sp--;
2887 END_CASE(Pow)
2889 CASE(Not) {
2890 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2891 REGS.sp--;
2892 PUSH_BOOLEAN(!cond);
2894 END_CASE(Not)
2896 CASE(BitNot) {
2897 MutableHandleValue val = REGS.stackHandleAt(-1);
2898 if (!BitNotOperation(cx, val, val)) {
2899 goto error;
2902 END_CASE(BitNot)
2904 CASE(Neg) {
2905 MutableHandleValue val = REGS.stackHandleAt(-1);
2906 if (!NegOperation(cx, val, val)) {
2907 goto error;
2910 END_CASE(Neg)
2912 CASE(Pos) {
2913 if (!ToNumber(cx, REGS.stackHandleAt(-1))) {
2914 goto error;
2917 END_CASE(Pos)
2919 CASE(DelName) {
2920 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2921 ReservedRooted<JSObject*> envObj(&rootObject0,
2922 REGS.fp()->environmentChain());
2924 PUSH_BOOLEAN(true);
2925 MutableHandleValue res = REGS.stackHandleAt(-1);
2926 if (!DeleteNameOperation(cx, name, envObj, res)) {
2927 goto error;
2930 END_CASE(DelName)
2932 CASE(DelProp)
2933 CASE(StrictDelProp) {
2934 static_assert(JSOpLength_DelProp == JSOpLength_StrictDelProp,
2935 "delprop and strictdelprop must be the same size");
2936 HandleValue val = REGS.stackHandleAt(-1);
2937 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2938 bool res = false;
2939 if (JSOp(*REGS.pc) == JSOp::StrictDelProp) {
2940 if (!DelPropOperation<true>(cx, val, name, &res)) {
2941 goto error;
2943 } else {
2944 if (!DelPropOperation<false>(cx, val, name, &res)) {
2945 goto error;
2948 REGS.sp[-1].setBoolean(res);
2950 END_CASE(DelProp)
2952 CASE(DelElem)
2953 CASE(StrictDelElem) {
2954 static_assert(JSOpLength_DelElem == JSOpLength_StrictDelElem,
2955 "delelem and strictdelelem must be the same size");
2956 HandleValue val = REGS.stackHandleAt(-2);
2957 HandleValue propval = REGS.stackHandleAt(-1);
2958 bool res = false;
2959 if (JSOp(*REGS.pc) == JSOp::StrictDelElem) {
2960 if (!DelElemOperation<true>(cx, val, propval, &res)) {
2961 goto error;
2963 } else {
2964 if (!DelElemOperation<false>(cx, val, propval, &res)) {
2965 goto error;
2968 REGS.sp[-2].setBoolean(res);
2969 REGS.sp--;
2971 END_CASE(DelElem)
2973 CASE(ToPropertyKey) {
2974 ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
2975 MutableHandleValue res = REGS.stackHandleAt(-1);
2976 if (!ToPropertyKeyOperation(cx, idval, res)) {
2977 goto error;
2980 END_CASE(ToPropertyKey)
2982 CASE(TypeofExpr)
2983 CASE(Typeof) {
2984 REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
2986 END_CASE(Typeof)
2988 CASE(Void) { REGS.sp[-1].setUndefined(); }
2989 END_CASE(Void)
2991 CASE(FunctionThis) {
2992 PUSH_NULL();
2993 if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1))) {
2994 goto error;
2997 END_CASE(FunctionThis)
2999 CASE(GlobalThis) {
3000 MOZ_ASSERT(!script->hasNonSyntacticScope());
3001 PUSH_OBJECT(*cx->global()->lexicalEnvironment().thisObject());
3003 END_CASE(GlobalThis)
3005 CASE(NonSyntacticGlobalThis) {
3006 PUSH_NULL();
3007 GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(),
3008 REGS.stackHandleAt(-1));
3010 END_CASE(NonSyntacticGlobalThis)
3012 CASE(CheckIsObj) {
3013 if (!REGS.sp[-1].isObject()) {
3014 MOZ_ALWAYS_FALSE(
3015 ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
3016 goto error;
3019 END_CASE(CheckIsObj)
3021 CASE(CheckThis) {
3022 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3023 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
3024 goto error;
3027 END_CASE(CheckThis)
3029 CASE(CheckThisReinit) {
3030 if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3031 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx));
3032 goto error;
3035 END_CASE(CheckThisReinit)
3037 CASE(CheckReturn) {
3038 ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-1]);
3039 MutableHandleValue rval = REGS.stackHandleAt(-1);
3040 if (!REGS.fp()->checkReturn(cx, thisv, rval)) {
3041 goto error;
3044 END_CASE(CheckReturn)
3046 CASE(GetProp) {
3047 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-1]);
3048 MutableHandleValue res = REGS.stackHandleAt(-1);
3049 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3050 if (!GetPropertyOperation(cx, name, lval, res)) {
3051 goto error;
3053 cx->debugOnlyCheck(res);
3055 END_CASE(GetProp)
3057 CASE(GetPropSuper) {
3058 ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-2]);
3059 HandleValue lval = REGS.stackHandleAt(-1);
3060 MOZ_ASSERT(lval.isObjectOrNull());
3061 MutableHandleValue rref = REGS.stackHandleAt(-2);
3062 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3064 ReservedRooted<JSObject*> obj(&rootObject0);
3065 obj = ToObjectFromStackForPropertyAccess(cx, lval, -1, name);
3066 if (!obj) {
3067 goto error;
3070 if (!GetProperty(cx, obj, receiver, name, rref)) {
3071 goto error;
3074 cx->debugOnlyCheck(rref);
3076 REGS.sp--;
3078 END_CASE(GetPropSuper)
3080 CASE(GetBoundName) {
3081 ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-1].toObject());
3082 ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
3083 MutableHandleValue rval = REGS.stackHandleAt(-1);
3084 if (!GetNameBoundInEnvironment(cx, env, id, rval)) {
3085 goto error;
3087 cx->debugOnlyCheck(rval);
3089 END_CASE(GetBoundName)
3091 CASE(SetIntrinsic) {
3092 HandleValue value = REGS.stackHandleAt(-1);
3094 if (!SetIntrinsicOperation(cx, script, REGS.pc, value)) {
3095 goto error;
3098 END_CASE(SetIntrinsic)
3100 CASE(SetGName)
3101 CASE(StrictSetGName)
3102 CASE(SetName)
3103 CASE(StrictSetName) {
3104 static_assert(JSOpLength_SetName == JSOpLength_StrictSetName,
3105 "setname and strictsetname must be the same size");
3106 static_assert(JSOpLength_SetGName == JSOpLength_StrictSetGName,
3107 "setgname and strictsetgname must be the same size");
3108 static_assert(JSOpLength_SetName == JSOpLength_SetGName,
3109 "We're sharing the END_CASE so the lengths better match");
3111 ReservedRooted<JSObject*> env(&rootObject0, &REGS.sp[-2].toObject());
3112 HandleValue value = REGS.stackHandleAt(-1);
3114 if (!SetNameOperation(cx, script, REGS.pc, env, value)) {
3115 goto error;
3118 REGS.sp[-2] = REGS.sp[-1];
3119 REGS.sp--;
3121 END_CASE(SetName)
3123 CASE(SetProp)
3124 CASE(StrictSetProp) {
3125 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp,
3126 "setprop and strictsetprop must be the same size");
3127 int lvalIndex = -2;
3128 HandleValue lval = REGS.stackHandleAt(lvalIndex);
3129 HandleValue rval = REGS.stackHandleAt(-1);
3131 ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
3133 bool strict = JSOp(*REGS.pc) == JSOp::StrictSetProp;
3135 ReservedRooted<JSObject*> obj(&rootObject0);
3136 obj = ToObjectFromStackForPropertyAccess(cx, lval, lvalIndex, id);
3137 if (!obj) {
3138 goto error;
3141 if (!SetObjectElementOperation(cx, obj, id, rval, lval, strict)) {
3142 goto error;
3145 REGS.sp[-2] = REGS.sp[-1];
3146 REGS.sp--;
3148 END_CASE(SetProp)
3150 CASE(SetPropSuper)
3151 CASE(StrictSetPropSuper) {
3152 static_assert(
3153 JSOpLength_SetPropSuper == JSOpLength_StrictSetPropSuper,
3154 "setprop-super and strictsetprop-super must be the same size");
3156 HandleValue receiver = REGS.stackHandleAt(-3);
3157 HandleValue lval = REGS.stackHandleAt(-2);
3158 MOZ_ASSERT(lval.isObjectOrNull());
3159 HandleValue rval = REGS.stackHandleAt(-1);
3160 ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
3162 bool strict = JSOp(*REGS.pc) == JSOp::StrictSetPropSuper;
3164 ReservedRooted<JSObject*> obj(&rootObject0);
3165 obj = ToObjectFromStackForPropertyAccess(cx, lval, -2, id);
3166 if (!obj) {
3167 goto error;
3170 if (!SetObjectElementOperation(cx, obj, id, rval, receiver, strict)) {
3171 goto error;
3174 REGS.sp[-3] = REGS.sp[-1];
3175 REGS.sp -= 2;
3177 END_CASE(SetPropSuper)
3179 CASE(GetElem) {
3180 int lvalIndex = -2;
3181 ReservedRooted<Value> lval(&rootValue0, REGS.sp[lvalIndex]);
3182 HandleValue rval = REGS.stackHandleAt(-1);
3183 MutableHandleValue res = REGS.stackHandleAt(-2);
3185 if (!GetElementOperationWithStackIndex(cx, lval, lvalIndex, rval, res)) {
3186 goto error;
3189 REGS.sp--;
3191 END_CASE(GetElem)
3193 CASE(GetElemSuper) {
3194 ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
3195 HandleValue index = REGS.stackHandleAt(-2);
3196 HandleValue lval = REGS.stackHandleAt(-1);
3197 MOZ_ASSERT(lval.isObjectOrNull());
3199 MutableHandleValue res = REGS.stackHandleAt(-3);
3201 ReservedRooted<JSObject*> obj(&rootObject0);
3202 obj = ToObjectFromStackForPropertyAccess(cx, lval, -1, index);
3203 if (!obj) {
3204 goto error;
3207 if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, index,
3208 res)) {
3209 goto error;
3212 REGS.sp -= 2;
3214 END_CASE(GetElemSuper)
3216 CASE(SetElem)
3217 CASE(StrictSetElem) {
3218 static_assert(JSOpLength_SetElem == JSOpLength_StrictSetElem,
3219 "setelem and strictsetelem must be the same size");
3220 int receiverIndex = -3;
3221 HandleValue receiver = REGS.stackHandleAt(receiverIndex);
3222 HandleValue value = REGS.stackHandleAt(-1);
3224 ReservedRooted<JSObject*> obj(&rootObject0);
3225 obj = ToObjectFromStackForPropertyAccess(cx, receiver, receiverIndex,
3226 REGS.stackHandleAt(-2));
3227 if (!obj) {
3228 goto error;
3231 ReservedRooted<jsid> id(&rootId0);
3232 FETCH_ELEMENT_ID(-2, id);
3234 if (!SetObjectElementOperation(cx, obj, id, value, receiver,
3235 JSOp(*REGS.pc) == JSOp::StrictSetElem)) {
3236 goto error;
3238 REGS.sp[-3] = value;
3239 REGS.sp -= 2;
3241 END_CASE(SetElem)
3243 CASE(SetElemSuper)
3244 CASE(StrictSetElemSuper) {
3245 static_assert(
3246 JSOpLength_SetElemSuper == JSOpLength_StrictSetElemSuper,
3247 "setelem-super and strictsetelem-super must be the same size");
3249 HandleValue receiver = REGS.stackHandleAt(-4);
3250 HandleValue lval = REGS.stackHandleAt(-2);
3251 MOZ_ASSERT(lval.isObjectOrNull());
3252 HandleValue value = REGS.stackHandleAt(-1);
3254 ReservedRooted<JSObject*> obj(&rootObject0);
3255 obj = ToObjectFromStackForPropertyAccess(cx, lval, -2,
3256 REGS.stackHandleAt(-3));
3257 if (!obj) {
3258 goto error;
3261 ReservedRooted<jsid> id(&rootId0);
3262 FETCH_ELEMENT_ID(-3, id);
3264 bool strict = JSOp(*REGS.pc) == JSOp::StrictSetElemSuper;
3265 if (!SetObjectElementOperation(cx, obj, id, value, receiver, strict)) {
3266 goto error;
3268 REGS.sp[-4] = value;
3269 REGS.sp -= 3;
3271 END_CASE(SetElemSuper)
3273 CASE(Eval)
3274 CASE(StrictEval) {
3275 static_assert(JSOpLength_Eval == JSOpLength_StrictEval,
3276 "eval and stricteval must be the same size");
3278 CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
3279 if (cx->global()->valueIsEval(args.calleev())) {
3280 if (!DirectEval(cx, args.get(0), args.rval())) {
3281 goto error;
3283 } else {
3284 if (!CallFromStack(cx, args, CallReason::Call)) {
3285 goto error;
3289 REGS.sp = args.spAfterCall();
3291 END_CASE(Eval)
3293 CASE(SpreadNew)
3294 CASE(SpreadCall)
3295 CASE(SpreadSuperCall) {
3296 if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
3297 cx->geckoProfiler().updatePC(cx, script, REGS.pc);
3299 /* FALL THROUGH */
3302 CASE(SpreadEval)
3303 CASE(StrictSpreadEval) {
3304 static_assert(JSOpLength_SpreadEval == JSOpLength_StrictSpreadEval,
3305 "spreadeval and strictspreadeval must be the same size");
3306 bool construct = JSOp(*REGS.pc) == JSOp::SpreadNew ||
3307 JSOp(*REGS.pc) == JSOp::SpreadSuperCall;
3309 MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
3311 HandleValue callee = REGS.stackHandleAt(-3 - construct);
3312 HandleValue thisv = REGS.stackHandleAt(-2 - construct);
3313 HandleValue arr = REGS.stackHandleAt(-1 - construct);
3314 MutableHandleValue ret = REGS.stackHandleAt(-3 - construct);
3316 RootedValue& newTarget = rootValue0;
3317 if (construct) {
3318 newTarget = REGS.sp[-1];
3319 } else {
3320 newTarget = NullValue();
3323 if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr,
3324 newTarget, ret)) {
3325 goto error;
3328 REGS.sp -= 2 + construct;
3330 END_CASE(SpreadCall)
3332 CASE(New)
3333 CASE(NewContent)
3334 CASE(Call)
3335 CASE(CallContent)
3336 CASE(CallIgnoresRv)
3337 CASE(CallIter)
3338 CASE(CallContentIter)
3339 CASE(SuperCall) {
3340 static_assert(JSOpLength_Call == JSOpLength_New,
3341 "call and new must be the same size");
3342 static_assert(JSOpLength_Call == JSOpLength_CallContent,
3343 "call and call-content must be the same size");
3344 static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv,
3345 "call and call-ignores-rv must be the same size");
3346 static_assert(JSOpLength_Call == JSOpLength_CallIter,
3347 "call and calliter must be the same size");
3348 static_assert(JSOpLength_Call == JSOpLength_CallContentIter,
3349 "call and call-content-iter must be the same size");
3350 static_assert(JSOpLength_Call == JSOpLength_SuperCall,
3351 "call and supercall must be the same size");
3353 if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
3354 cx->geckoProfiler().updatePC(cx, script, REGS.pc);
3357 JSOp op = JSOp(*REGS.pc);
3358 MaybeConstruct construct = MaybeConstruct(
3359 op == JSOp::New || op == JSOp::NewContent || op == JSOp::SuperCall);
3360 bool ignoresReturnValue = op == JSOp::CallIgnoresRv;
3361 unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
3363 MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
3364 CallArgs args =
3365 CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
3367 JSFunction* maybeFun;
3368 bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
3370 // Use the slow path if the callee is not an interpreted function, if we
3371 // have to throw an exception, or if we might have to invoke the
3372 // OnNativeCall hook for a self-hosted builtin.
3373 if (!isFunction || !maybeFun->isInterpreted() ||
3374 (construct && !maybeFun->isConstructor()) ||
3375 (!construct && maybeFun->isClassConstructor()) ||
3376 cx->insideDebuggerEvaluationWithOnNativeCallHook) {
3377 if (construct) {
3378 CallReason reason = op == JSOp::NewContent ? CallReason::CallContent
3379 : CallReason::Call;
3380 if (!ConstructFromStack(cx, args, reason)) {
3381 goto error;
3383 } else {
3384 if ((op == JSOp::CallIter || op == JSOp::CallContentIter) &&
3385 args.calleev().isPrimitive()) {
3386 MOZ_ASSERT(args.length() == 0, "thisv must be on top of the stack");
3387 ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, args.thisv(), nullptr);
3388 goto error;
3391 CallReason reason =
3392 (op == JSOp::CallContent || op == JSOp::CallContentIter)
3393 ? CallReason::CallContent
3394 : CallReason::Call;
3395 if (!CallFromStack(cx, args, reason)) {
3396 goto error;
3399 Value* newsp = args.spAfterCall();
3400 REGS.sp = newsp;
3401 ADVANCE_AND_DISPATCH(JSOpLength_Call);
3405 MOZ_ASSERT(maybeFun);
3406 ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
3407 ReservedRooted<JSScript*> funScript(
3408 &rootScript0, JSFunction::getOrCreateScript(cx, fun));
3409 if (!funScript) {
3410 goto error;
3413 // Enter the callee's realm if this is a cross-realm call. Use
3414 // MakeScopeExit to leave this realm on all error/JIT-return paths
3415 // below.
3416 const bool isCrossRealm = cx->realm() != funScript->realm();
3417 if (isCrossRealm) {
3418 cx->enterRealmOf(funScript);
3420 auto leaveRealmGuard =
3421 mozilla::MakeScopeExit([isCrossRealm, cx, &script] {
3422 if (isCrossRealm) {
3423 cx->leaveRealm(script->realm());
3427 if (construct && !MaybeCreateThisForConstructor(cx, args)) {
3428 goto error;
3432 InvokeState state(cx, args, construct);
3434 jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
3435 switch (status) {
3436 case jit::EnterJitStatus::Error:
3437 goto error;
3438 case jit::EnterJitStatus::Ok:
3439 interpReturnOK = true;
3440 CHECK_BRANCH();
3441 REGS.sp = args.spAfterCall();
3442 goto jit_return;
3443 case jit::EnterJitStatus::NotEntered:
3444 break;
3447 #ifdef NIGHTLY_BUILD
3448 // If entry trampolines are enabled, call back into
3449 // MaybeEnterInterpreterTrampoline so we can generate an
3450 // entry trampoline for the new frame.
3451 if (jit::JitOptions.emitInterpreterEntryTrampoline) {
3452 if (MaybeEnterInterpreterTrampoline(cx, state)) {
3453 interpReturnOK = true;
3454 CHECK_BRANCH();
3455 REGS.sp = args.spAfterCall();
3456 goto jit_return;
3458 goto error;
3460 #endif
3463 funScript = fun->nonLazyScript();
3465 if (!activation.pushInlineFrame(args, funScript, construct)) {
3466 goto error;
3468 leaveRealmGuard.release(); // We leave the callee's realm when we
3469 // call popInlineFrame.
3472 SET_SCRIPT(REGS.fp()->script());
3474 if (!REGS.fp()->prologue(cx)) {
3475 goto prologue_error;
3478 if (!DebugAPI::onEnterFrame(cx, REGS.fp())) {
3479 goto error;
3482 // Increment the coverage for the main entry point.
3483 INIT_COVERAGE();
3484 COUNT_COVERAGE_MAIN();
3486 /* Load first op and dispatch it (safe since JSOp::RetRval). */
3487 ADVANCE_AND_DISPATCH(0);
3490 CASE(OptimizeSpreadCall) {
3491 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3492 MutableHandleValue rval = REGS.stackHandleAt(-1);
3494 if (!OptimizeSpreadCall(cx, val, rval)) {
3495 goto error;
3498 END_CASE(OptimizeSpreadCall)
3500 CASE(ThrowMsg) {
3501 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(REGS.pc)));
3502 goto error;
3504 END_CASE(ThrowMsg)
3506 CASE(ImplicitThis) {
3507 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3508 ReservedRooted<JSObject*> envObj(&rootObject0,
3509 REGS.fp()->environmentChain());
3510 ReservedRooted<JSObject*> env(&rootObject1);
3511 if (!LookupNameWithGlobalDefault(cx, name, envObj, &env)) {
3512 goto error;
3515 Value v = ComputeImplicitThis(env);
3516 PUSH_COPY(v);
3518 END_CASE(ImplicitThis)
3520 CASE(GetGName) {
3521 ReservedRooted<Value> rval(&rootValue0);
3522 ReservedRooted<JSObject*> env(&rootObject0,
3523 &cx->global()->lexicalEnvironment());
3524 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3525 MOZ_ASSERT(!script->hasNonSyntacticScope());
3526 if (!GetNameOperation(cx, env, name, JSOp(REGS.pc[JSOpLength_GetGName]),
3527 &rval)) {
3528 goto error;
3531 PUSH_COPY(rval);
3533 END_CASE(GetGName)
3535 CASE(GetName) {
3536 ReservedRooted<Value> rval(&rootValue0);
3537 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3538 if (!GetNameOperation(cx, REGS.fp()->environmentChain(), name,
3539 JSOp(REGS.pc[JSOpLength_GetName]), &rval)) {
3540 goto error;
3543 PUSH_COPY(rval);
3545 END_CASE(GetName)
3547 CASE(GetImport) {
3548 PUSH_NULL();
3549 MutableHandleValue rval = REGS.stackHandleAt(-1);
3550 HandleObject envChain = REGS.fp()->environmentChain();
3551 if (!GetImportOperation(cx, envChain, script, REGS.pc, rval)) {
3552 goto error;
3555 END_CASE(GetImport)
3557 CASE(GetIntrinsic) {
3558 ReservedRooted<Value> rval(&rootValue0);
3559 if (!GetIntrinsicOperation(cx, script, REGS.pc, &rval)) {
3560 goto error;
3563 PUSH_COPY(rval);
3565 END_CASE(GetIntrinsic)
3567 CASE(Uint16) { PUSH_INT32((int32_t)GET_UINT16(REGS.pc)); }
3568 END_CASE(Uint16)
3570 CASE(Uint24) { PUSH_INT32((int32_t)GET_UINT24(REGS.pc)); }
3571 END_CASE(Uint24)
3573 CASE(Int8) { PUSH_INT32(GET_INT8(REGS.pc)); }
3574 END_CASE(Int8)
3576 CASE(Int32) { PUSH_INT32(GET_INT32(REGS.pc)); }
3577 END_CASE(Int32)
3579 CASE(Double) { PUSH_COPY(GET_INLINE_VALUE(REGS.pc)); }
3580 END_CASE(Double)
3582 CASE(String) { PUSH_STRING(script->getString(REGS.pc)); }
3583 END_CASE(String)
3585 CASE(ToString) {
3586 MutableHandleValue oper = REGS.stackHandleAt(-1);
3588 if (!oper.isString()) {
3589 JSString* operString = ToString<CanGC>(cx, oper);
3590 if (!operString) {
3591 goto error;
3593 oper.setString(operString);
3596 END_CASE(ToString)
3598 CASE(Symbol) {
3599 PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
3601 END_CASE(Symbol)
3603 CASE(Object) {
3604 MOZ_ASSERT(script->treatAsRunOnce());
3605 PUSH_OBJECT(*script->getObject(REGS.pc));
3607 END_CASE(Object)
3609 CASE(CallSiteObj) {
3610 JSObject* cso = script->getObject(REGS.pc);
3611 MOZ_ASSERT(!cso->as<ArrayObject>().isExtensible());
3612 MOZ_ASSERT(cso->as<ArrayObject>().containsPure(cx->names().raw));
3613 PUSH_OBJECT(*cso);
3615 END_CASE(CallSiteObj)
3617 CASE(RegExp) {
3619 * Push a regexp object cloned from the regexp literal object mapped by
3620 * the bytecode at pc.
3622 ReservedRooted<JSObject*> re(&rootObject0, script->getRegExp(REGS.pc));
3623 JSObject* obj = CloneRegExpObject(cx, re.as<RegExpObject>());
3624 if (!obj) {
3625 goto error;
3627 PUSH_OBJECT(*obj);
3629 END_CASE(RegExp)
3631 CASE(Zero) { PUSH_INT32(0); }
3632 END_CASE(Zero)
3634 CASE(One) { PUSH_INT32(1); }
3635 END_CASE(One)
3637 CASE(Null) { PUSH_NULL(); }
3638 END_CASE(Null)
3640 CASE(False) { PUSH_BOOLEAN(false); }
3641 END_CASE(False)
3643 CASE(True) { PUSH_BOOLEAN(true); }
3644 END_CASE(True)
3646 CASE(TableSwitch) {
3647 jsbytecode* pc2 = REGS.pc;
3648 int32_t len = GET_JUMP_OFFSET(pc2);
3651 * ECMAv2+ forbids conversion of discriminant, so we will skip to the
3652 * default case if the discriminant isn't already an int jsval. (This
3653 * opcode is emitted only for dense int-domain switches.)
3655 const Value& rref = *--REGS.sp;
3656 int32_t i;
3657 if (rref.isInt32()) {
3658 i = rref.toInt32();
3659 } else {
3660 /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
3661 if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i)) {
3662 ADVANCE_AND_DISPATCH(len);
3666 pc2 += JUMP_OFFSET_LEN;
3667 int32_t low = GET_JUMP_OFFSET(pc2);
3668 pc2 += JUMP_OFFSET_LEN;
3669 int32_t high = GET_JUMP_OFFSET(pc2);
3671 i = uint32_t(i) - uint32_t(low);
3672 if (uint32_t(i) < uint32_t(high - low + 1)) {
3673 len = script->tableSwitchCaseOffset(REGS.pc, uint32_t(i)) -
3674 script->pcToOffset(REGS.pc);
3676 ADVANCE_AND_DISPATCH(len);
3679 CASE(Arguments) {
3680 MOZ_ASSERT(script->needsArgsObj());
3681 ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
3682 if (!obj) {
3683 goto error;
3685 PUSH_COPY(ObjectValue(*obj));
3687 END_CASE(Arguments)
3689 CASE(Rest) {
3690 ReservedRooted<JSObject*> rest(&rootObject0,
3691 REGS.fp()->createRestParameter(cx));
3692 if (!rest) {
3693 goto error;
3695 PUSH_COPY(ObjectValue(*rest));
3697 END_CASE(Rest)
3699 CASE(GetAliasedVar) {
3700 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3701 ReservedRooted<Value> val(
3702 &rootValue0, REGS.fp()->aliasedEnvironment(ec).aliasedBinding(ec));
3704 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3706 PUSH_COPY(val);
3708 END_CASE(GetAliasedVar)
3710 CASE(GetAliasedDebugVar) {
3711 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3712 ReservedRooted<Value> val(
3713 &rootValue0,
3714 REGS.fp()->aliasedEnvironmentMaybeDebug(ec).aliasedBinding(ec));
3716 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3718 PUSH_COPY(val);
3720 END_CASE(GetAliasedVar)
3722 CASE(SetAliasedVar) {
3723 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3724 EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
3725 MOZ_ASSERT(!IsUninitializedLexical(obj.aliasedBinding(ec)));
3726 obj.setAliasedBinding(ec, REGS.sp[-1]);
3728 END_CASE(SetAliasedVar)
3730 CASE(ThrowSetConst) {
3731 ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script, REGS.pc);
3732 goto error;
3734 END_CASE(ThrowSetConst)
3736 CASE(CheckLexical) {
3737 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3738 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3739 REGS.pc);
3740 goto error;
3743 END_CASE(CheckLexical)
3745 CASE(CheckAliasedLexical) {
3746 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3747 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3748 REGS.pc);
3749 goto error;
3752 END_CASE(CheckAliasedLexical)
3754 CASE(InitLexical) {
3755 uint32_t i = GET_LOCALNO(REGS.pc);
3756 REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3758 END_CASE(InitLexical)
3760 CASE(InitAliasedLexical) {
3761 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3762 EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
3763 obj.setAliasedBinding(ec, REGS.sp[-1]);
3765 END_CASE(InitAliasedLexical)
3767 CASE(InitGLexical) {
3768 ExtensibleLexicalEnvironmentObject* lexicalEnv;
3769 if (script->hasNonSyntacticScope()) {
3770 lexicalEnv = &REGS.fp()->extensibleLexicalEnvironment();
3771 } else {
3772 lexicalEnv = &cx->global()->lexicalEnvironment();
3774 HandleValue value = REGS.stackHandleAt(-1);
3775 InitGlobalLexicalOperation(cx, lexicalEnv, script, REGS.pc, value);
3777 END_CASE(InitGLexical)
3779 CASE(Uninitialized) { PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL); }
3780 END_CASE(Uninitialized)
3782 CASE(GetArg) {
3783 unsigned i = GET_ARGNO(REGS.pc);
3784 if (script->argsObjAliasesFormals()) {
3785 PUSH_COPY(REGS.fp()->argsObj().arg(i));
3786 } else {
3787 PUSH_COPY(REGS.fp()->unaliasedFormal(i));
3790 END_CASE(GetArg)
3792 CASE(GetFrameArg) {
3793 uint32_t i = GET_ARGNO(REGS.pc);
3794 PUSH_COPY(REGS.fp()->unaliasedFormal(i, DONT_CHECK_ALIASING));
3796 END_CASE(GetFrameArg)
3798 CASE(SetArg) {
3799 unsigned i = GET_ARGNO(REGS.pc);
3800 if (script->argsObjAliasesFormals()) {
3801 REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
3802 } else {
3803 REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
3806 END_CASE(SetArg)
3808 CASE(GetLocal) {
3809 uint32_t i = GET_LOCALNO(REGS.pc);
3810 PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
3812 #ifdef DEBUG
3813 if (IsUninitializedLexical(REGS.sp[-1])) {
3814 JSOp next = JSOp(*GetNextPc(REGS.pc));
3815 MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn ||
3816 next == JSOp::CheckThisReinit || next == JSOp::CheckLexical);
3820 * Skip the same-compartment assertion if the local will be immediately
3821 * popped. We do not guarantee sync for dead locals when coming in from
3822 * the method JIT, and a GetLocal followed by Pop is not considered to
3823 * be a use of the variable.
3825 if (JSOp(REGS.pc[JSOpLength_GetLocal]) != JSOp::Pop) {
3826 cx->debugOnlyCheck(REGS.sp[-1]);
3828 #endif
3830 END_CASE(GetLocal)
3832 CASE(SetLocal) {
3833 uint32_t i = GET_LOCALNO(REGS.pc);
3835 MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
3837 REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3839 END_CASE(SetLocal)
3841 CASE(ArgumentsLength) {
3842 MOZ_ASSERT(!script->needsArgsObj());
3843 PUSH_INT32(REGS.fp()->numActualArgs());
3845 END_CASE(ArgumentsLength)
3847 CASE(GetActualArg) {
3848 MOZ_ASSERT(!script->needsArgsObj());
3849 uint32_t index = REGS.sp[-1].toInt32();
3850 REGS.sp[-1] = REGS.fp()->unaliasedActual(index);
3852 END_CASE(GetActualArg)
3854 CASE(GlobalOrEvalDeclInstantiation) {
3855 GCThingIndex lastFun = GET_GCTHING_INDEX(REGS.pc);
3856 HandleObject env = REGS.fp()->environmentChain();
3857 if (!GlobalOrEvalDeclInstantiation(cx, env, script, lastFun)) {
3858 goto error;
3861 END_CASE(GlobalOrEvalDeclInstantiation)
3863 CASE(Lambda) {
3864 /* Load the specified function object literal. */
3865 ReservedRooted<JSFunction*> fun(&rootFunction0,
3866 script->getFunction(REGS.pc));
3867 JSObject* obj = Lambda(cx, fun, REGS.fp()->environmentChain());
3868 if (!obj) {
3869 goto error;
3872 MOZ_ASSERT(obj->staticPrototype());
3873 PUSH_OBJECT(*obj);
3875 END_CASE(Lambda)
3877 CASE(ToAsyncIter) {
3878 ReservedRooted<Value> nextMethod(&rootValue0, REGS.sp[-1]);
3879 ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-2].toObject());
3880 JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter, nextMethod);
3881 if (!asyncIter) {
3882 goto error;
3885 REGS.sp--;
3886 REGS.sp[-1].setObject(*asyncIter);
3888 END_CASE(ToAsyncIter)
3890 CASE(CanSkipAwait) {
3891 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3892 bool canSkip;
3893 if (!CanSkipAwait(cx, val, &canSkip)) {
3894 goto error;
3897 PUSH_BOOLEAN(canSkip);
3899 END_CASE(CanSkipAwait)
3901 CASE(MaybeExtractAwaitValue) {
3902 MutableHandleValue val = REGS.stackHandleAt(-2);
3903 ReservedRooted<Value> canSkip(&rootValue0, REGS.sp[-1]);
3905 if (canSkip.toBoolean()) {
3906 if (!ExtractAwaitValue(cx, val, val)) {
3907 goto error;
3911 END_CASE(MaybeExtractAwaitValue)
3913 CASE(AsyncAwait) {
3914 MOZ_ASSERT(REGS.stackDepth() >= 2);
3915 ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
3916 ReservedRooted<Value> value(&rootValue0, REGS.sp[-2]);
3917 JSObject* promise =
3918 AsyncFunctionAwait(cx, gen.as<AsyncFunctionGeneratorObject>(), value);
3919 if (!promise) {
3920 goto error;
3923 REGS.sp--;
3924 REGS.sp[-1].setObject(*promise);
3926 END_CASE(AsyncAwait)
3928 CASE(AsyncResolve) {
3929 MOZ_ASSERT(REGS.stackDepth() >= 2);
3930 auto resolveKind = AsyncFunctionResolveKind(GET_UINT8(REGS.pc));
3931 ReservedRooted<JSObject*> gen(&rootObject1, &REGS.sp[-1].toObject());
3932 ReservedRooted<Value> valueOrReason(&rootValue0, REGS.sp[-2]);
3933 JSObject* promise =
3934 AsyncFunctionResolve(cx, gen.as<AsyncFunctionGeneratorObject>(),
3935 valueOrReason, resolveKind);
3936 if (!promise) {
3937 goto error;
3940 REGS.sp--;
3941 REGS.sp[-1].setObject(*promise);
3943 END_CASE(AsyncResolve)
3945 CASE(SetFunName) {
3946 MOZ_ASSERT(REGS.stackDepth() >= 2);
3947 FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(REGS.pc));
3948 ReservedRooted<Value> name(&rootValue0, REGS.sp[-1]);
3949 ReservedRooted<JSFunction*> fun(&rootFunction0,
3950 &REGS.sp[-2].toObject().as<JSFunction>());
3951 if (!SetFunctionName(cx, fun, name, prefixKind)) {
3952 goto error;
3955 REGS.sp--;
3957 END_CASE(SetFunName)
3959 CASE(Callee) {
3960 MOZ_ASSERT(REGS.fp()->isFunctionFrame());
3961 PUSH_COPY(REGS.fp()->calleev());
3963 END_CASE(Callee)
3965 CASE(InitPropGetter)
3966 CASE(InitHiddenPropGetter)
3967 CASE(InitPropSetter)
3968 CASE(InitHiddenPropSetter) {
3969 MOZ_ASSERT(REGS.stackDepth() >= 2);
3971 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
3972 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3973 ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
3975 if (!InitPropGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
3976 goto error;
3979 REGS.sp--;
3981 END_CASE(InitPropGetter)
3983 CASE(InitElemGetter)
3984 CASE(InitHiddenElemGetter)
3985 CASE(InitElemSetter)
3986 CASE(InitHiddenElemSetter) {
3987 MOZ_ASSERT(REGS.stackDepth() >= 3);
3989 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
3990 ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
3991 ReservedRooted<JSObject*> val(&rootObject1, &REGS.sp[-1].toObject());
3993 if (!InitElemGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
3994 goto error;
3997 REGS.sp -= 2;
3999 END_CASE(InitElemGetter)
4001 CASE(Hole) { PUSH_MAGIC(JS_ELEMENTS_HOLE); }
4002 END_CASE(Hole)
4004 CASE(NewInit) {
4005 JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
4007 if (!obj) {
4008 goto error;
4010 PUSH_OBJECT(*obj);
4012 END_CASE(NewInit)
4014 CASE(NewArray) {
4015 uint32_t length = GET_UINT32(REGS.pc);
4016 ArrayObject* obj = NewArrayOperation(cx, length);
4017 if (!obj) {
4018 goto error;
4020 PUSH_OBJECT(*obj);
4022 END_CASE(NewArray)
4024 CASE(NewObject) {
4025 JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
4026 if (!obj) {
4027 goto error;
4029 PUSH_OBJECT(*obj);
4031 END_CASE(NewObject)
4033 CASE(MutateProto) {
4034 MOZ_ASSERT(REGS.stackDepth() >= 2);
4036 if (REGS.sp[-1].isObjectOrNull()) {
4037 ReservedRooted<JSObject*> newProto(&rootObject1,
4038 REGS.sp[-1].toObjectOrNull());
4039 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
4040 MOZ_ASSERT(obj->is<PlainObject>());
4042 if (!SetPrototype(cx, obj, newProto)) {
4043 goto error;
4047 REGS.sp--;
4049 END_CASE(MutateProto)
4051 CASE(InitProp)
4052 CASE(InitLockedProp)
4053 CASE(InitHiddenProp) {
4054 static_assert(JSOpLength_InitProp == JSOpLength_InitLockedProp,
4055 "initprop and initlockedprop must be the same size");
4056 static_assert(JSOpLength_InitProp == JSOpLength_InitHiddenProp,
4057 "initprop and inithiddenprop must be the same size");
4058 /* Load the property's initial value into rval. */
4059 MOZ_ASSERT(REGS.stackDepth() >= 2);
4060 ReservedRooted<Value> rval(&rootValue0, REGS.sp[-1]);
4062 /* Load the object being initialized into lval/obj. */
4063 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
4065 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
4067 if (!InitPropertyOperation(cx, REGS.pc, obj, name, rval)) {
4068 goto error;
4071 REGS.sp--;
4073 END_CASE(InitProp)
4075 CASE(InitElem)
4076 CASE(InitHiddenElem)
4077 CASE(InitLockedElem) {
4078 MOZ_ASSERT(REGS.stackDepth() >= 3);
4079 HandleValue val = REGS.stackHandleAt(-1);
4080 HandleValue id = REGS.stackHandleAt(-2);
4082 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
4084 if (!InitElemOperation(cx, REGS.pc, obj, id, val)) {
4085 goto error;
4088 REGS.sp -= 2;
4090 END_CASE(InitElem)
4092 CASE(InitElemArray) {
4093 MOZ_ASSERT(REGS.stackDepth() >= 2);
4094 HandleValue val = REGS.stackHandleAt(-1);
4095 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
4097 InitElemArrayOperation(cx, REGS.pc, obj.as<ArrayObject>(), val);
4098 REGS.sp--;
4100 END_CASE(InitElemArray)
4102 CASE(InitElemInc) {
4103 MOZ_ASSERT(REGS.stackDepth() >= 3);
4104 HandleValue val = REGS.stackHandleAt(-1);
4106 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-3].toObject());
4108 uint32_t index = REGS.sp[-2].toInt32();
4109 if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index, val)) {
4110 goto error;
4113 REGS.sp[-2].setInt32(index + 1);
4114 REGS.sp--;
4116 END_CASE(InitElemInc)
4118 #ifdef ENABLE_RECORD_TUPLE
4119 CASE(InitRecord) {
4120 uint32_t length = GET_UINT32(REGS.pc);
4121 RecordType* rec = RecordType::createUninitialized(cx, length);
4122 if (!rec) {
4123 goto error;
4125 PUSH_EXTENDED_PRIMITIVE(*rec);
4127 END_CASE(InitRecord)
4129 CASE(AddRecordProperty) {
4130 MOZ_ASSERT(REGS.stackDepth() >= 3);
4132 ReservedRooted<JSObject*> rec(&rootObject0,
4133 &REGS.sp[-3].toExtendedPrimitive());
4134 MOZ_ASSERT(rec->is<RecordType>());
4136 ReservedRooted<Value> key(&rootValue0, REGS.sp[-2]);
4137 ReservedRooted<jsid> id(&rootId0);
4138 if (!JS_ValueToId(cx, key, &id)) {
4139 goto error;
4141 if (!rec->as<RecordType>().initializeNextProperty(
4142 cx, id, REGS.stackHandleAt(-1))) {
4143 goto error;
4146 REGS.sp -= 2;
4148 END_CASE(AddRecordProperty)
4150 CASE(AddRecordSpread) {
4151 MOZ_ASSERT(REGS.stackDepth() >= 2);
4153 if (!AddRecordSpreadOperation(cx, REGS.stackHandleAt(-2),
4154 REGS.stackHandleAt(-1))) {
4155 goto error;
4157 REGS.sp--;
4159 END_CASE(AddRecordSpread)
4161 CASE(FinishRecord) {
4162 MOZ_ASSERT(REGS.stackDepth() >= 1);
4163 RecordType* rec = &REGS.sp[-1].toExtendedPrimitive().as<RecordType>();
4164 if (!rec->finishInitialization(cx)) {
4165 goto error;
4168 END_CASE(FinishRecord)
4170 CASE(InitTuple) {
4171 uint32_t length = GET_UINT32(REGS.pc);
4172 TupleType* tup = TupleType::createUninitialized(cx, length);
4173 if (!tup) {
4174 goto error;
4176 PUSH_EXTENDED_PRIMITIVE(*tup);
4178 END_CASE(InitTuple)
4180 CASE(AddTupleElement) {
4181 MOZ_ASSERT(REGS.stackDepth() >= 2);
4183 ReservedRooted<JSObject*> tup(&rootObject0,
4184 &REGS.sp[-2].toExtendedPrimitive());
4185 HandleValue val = REGS.stackHandleAt(-1);
4187 if (!tup->as<TupleType>().initializeNextElement(cx, val)) {
4188 goto error;
4191 REGS.sp--;
4193 END_CASE(AddTupleElement)
4195 CASE(FinishTuple) {
4196 MOZ_ASSERT(REGS.stackDepth() >= 1);
4197 TupleType& tup = REGS.sp[-1].toExtendedPrimitive().as<TupleType>();
4198 tup.finishInitialization(cx);
4200 END_CASE(FinishTuple)
4201 #endif
4203 CASE(Exception) {
4204 PUSH_NULL();
4205 MutableHandleValue res = REGS.stackHandleAt(-1);
4206 if (!GetAndClearException(cx, res)) {
4207 goto error;
4210 END_CASE(Exception)
4212 CASE(Finally) { CHECK_BRANCH(); }
4213 END_CASE(Finally)
4215 CASE(Throw) {
4216 CHECK_BRANCH();
4217 ReservedRooted<Value> v(&rootValue0);
4218 POP_COPY_TO(v);
4219 MOZ_ALWAYS_FALSE(ThrowOperation(cx, v));
4220 /* let the code at error try to catch the exception. */
4221 goto error;
4224 CASE(Instanceof) {
4225 ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
4226 if (HandleValue(rref).isPrimitive()) {
4227 ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
4228 goto error;
4230 ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
4231 bool cond = false;
4232 if (!InstanceofOperator(cx, obj, REGS.stackHandleAt(-2), &cond)) {
4233 goto error;
4235 REGS.sp--;
4236 REGS.sp[-1].setBoolean(cond);
4238 END_CASE(Instanceof)
4240 CASE(Debugger) {
4241 if (!DebugAPI::onDebuggerStatement(cx, REGS.fp())) {
4242 goto error;
4245 END_CASE(Debugger)
4247 CASE(PushLexicalEnv) {
4248 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4250 // Create block environment and push on scope chain.
4251 if (!REGS.fp()->pushLexicalEnvironment(cx, scope.as<LexicalScope>())) {
4252 goto error;
4255 END_CASE(PushLexicalEnv)
4257 CASE(PopLexicalEnv) {
4258 #ifdef DEBUG
4259 Scope* scope = script->lookupScope(REGS.pc);
4260 MOZ_ASSERT(scope);
4261 MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
4262 MOZ_ASSERT_IF(scope->is<LexicalScope>(),
4263 scope->as<LexicalScope>().hasEnvironment());
4264 MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
4265 scope->as<ClassBodyScope>().hasEnvironment());
4266 #endif
4268 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4269 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4272 // Pop block from scope chain.
4273 REGS.fp()->popOffEnvironmentChain<LexicalEnvironmentObject>();
4275 END_CASE(PopLexicalEnv)
4277 CASE(DebugLeaveLexicalEnv) {
4278 #ifdef DEBUG
4279 Scope* scope = script->lookupScope(REGS.pc);
4280 MOZ_ASSERT(scope);
4281 MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
4282 MOZ_ASSERT_IF(scope->is<LexicalScope>(),
4283 !scope->as<LexicalScope>().hasEnvironment());
4284 MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
4285 !scope->as<ClassBodyScope>().hasEnvironment());
4286 #endif
4287 // FIXME: This opcode should not be necessary. The debugger shouldn't
4288 // need help from bytecode to do its job. See bug 927782.
4290 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4291 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4294 END_CASE(DebugLeaveLexicalEnv)
4296 CASE(FreshenLexicalEnv) {
4297 #ifdef DEBUG
4298 Scope* scope = script->getScope(REGS.pc);
4299 auto envChain = REGS.fp()->environmentChain();
4300 auto* envScope = &envChain->as<BlockLexicalEnvironmentObject>().scope();
4301 MOZ_ASSERT(scope == envScope);
4302 #endif
4304 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4305 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4308 if (!REGS.fp()->freshenLexicalEnvironment(cx)) {
4309 goto error;
4312 END_CASE(FreshenLexicalEnv)
4314 CASE(RecreateLexicalEnv) {
4315 #ifdef DEBUG
4316 Scope* scope = script->getScope(REGS.pc);
4317 auto envChain = REGS.fp()->environmentChain();
4318 auto* envScope = &envChain->as<BlockLexicalEnvironmentObject>().scope();
4319 MOZ_ASSERT(scope == envScope);
4320 #endif
4322 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4323 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4326 if (!REGS.fp()->recreateLexicalEnvironment(cx)) {
4327 goto error;
4330 END_CASE(RecreateLexicalEnv)
4332 CASE(PushClassBodyEnv) {
4333 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4335 if (!REGS.fp()->pushClassBodyEnvironment(cx,
4336 scope.as<ClassBodyScope>())) {
4337 goto error;
4340 END_CASE(PushClassBodyEnv)
4342 CASE(PushVarEnv) {
4343 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4345 if (!REGS.fp()->pushVarEnvironment(cx, scope)) {
4346 goto error;
4349 END_CASE(PushVarEnv)
4351 CASE(Generator) {
4352 MOZ_ASSERT(!cx->isExceptionPending());
4353 MOZ_ASSERT(REGS.stackDepth() == 0);
4354 JSObject* obj = AbstractGeneratorObject::createFromFrame(cx, REGS.fp());
4355 if (!obj) {
4356 goto error;
4358 PUSH_OBJECT(*obj);
4360 END_CASE(Generator)
4362 CASE(InitialYield) {
4363 MOZ_ASSERT(!cx->isExceptionPending());
4364 MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
4365 REGS.fp()->isModuleFrame());
4366 MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
4367 REGS.fp()->isFunctionFrame());
4368 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
4369 POP_RETURN_VALUE();
4370 MOZ_ASSERT(REGS.stackDepth() == 0);
4371 if (!AbstractGeneratorObject::suspend(cx, obj, REGS.fp(), REGS.pc,
4372 script->nfixed())) {
4373 goto error;
4375 goto successful_return_continuation;
4378 CASE(Yield)
4379 CASE(Await) {
4380 MOZ_ASSERT(!cx->isExceptionPending());
4381 MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
4382 REGS.fp()->isModuleFrame());
4383 MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
4384 REGS.fp()->isFunctionFrame());
4385 ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-1].toObject());
4386 if (!AbstractGeneratorObject::suspend(
4387 cx, obj, REGS.fp(), REGS.pc,
4388 script->nfixed() + REGS.stackDepth() - 2)) {
4389 goto error;
4392 REGS.sp--;
4393 POP_RETURN_VALUE();
4395 goto successful_return_continuation;
4398 CASE(ResumeKind) {
4399 GeneratorResumeKind resumeKind = ResumeKindFromPC(REGS.pc);
4400 PUSH_INT32(int32_t(resumeKind));
4402 END_CASE(ResumeKind)
4404 CASE(CheckResumeKind) {
4405 int32_t kindInt = REGS.sp[-1].toInt32();
4406 GeneratorResumeKind resumeKind = IntToResumeKind(kindInt);
4407 if (MOZ_UNLIKELY(resumeKind != GeneratorResumeKind::Next)) {
4408 ReservedRooted<Value> val(&rootValue0, REGS.sp[-3]);
4409 Rooted<AbstractGeneratorObject*> gen(
4410 cx, &REGS.sp[-2].toObject().as<AbstractGeneratorObject>());
4411 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx, activation.regs().fp(), gen,
4412 val, resumeKind));
4413 goto error;
4415 REGS.sp -= 2;
4417 END_CASE(CheckResumeKind)
4419 CASE(Resume) {
4421 Rooted<AbstractGeneratorObject*> gen(
4422 cx, &REGS.sp[-3].toObject().as<AbstractGeneratorObject>());
4423 ReservedRooted<Value> val(&rootValue0, REGS.sp[-2]);
4424 ReservedRooted<Value> resumeKindVal(&rootValue1, REGS.sp[-1]);
4426 // popInlineFrame expects there to be an additional value on the stack
4427 // to pop off, so leave "gen" on the stack.
4428 REGS.sp -= 1;
4430 if (!AbstractGeneratorObject::resume(cx, activation, gen, val,
4431 resumeKindVal)) {
4432 goto error;
4435 JSScript* generatorScript = REGS.fp()->script();
4436 if (cx->realm() != generatorScript->realm()) {
4437 cx->enterRealmOf(generatorScript);
4439 SET_SCRIPT(generatorScript);
4441 if (!probes::EnterScript(cx, generatorScript,
4442 generatorScript->function(), REGS.fp())) {
4443 goto error;
4446 if (!DebugAPI::onResumeFrame(cx, REGS.fp())) {
4447 if (cx->isPropagatingForcedReturn()) {
4448 MOZ_ASSERT_IF(
4449 REGS.fp()
4450 ->callee()
4451 .isGenerator(), // as opposed to an async function
4452 gen->isClosed());
4454 goto error;
4457 ADVANCE_AND_DISPATCH(0);
4460 CASE(AfterYield) {
4461 // AbstractGeneratorObject::resume takes care of setting the frame's
4462 // debuggee flag.
4463 MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
4464 COUNT_COVERAGE();
4466 END_CASE(AfterYield)
4468 CASE(FinalYieldRval) {
4469 ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-1].toObject());
4470 REGS.sp--;
4471 AbstractGeneratorObject::finalSuspend(gen);
4472 goto successful_return_continuation;
4475 CASE(CheckClassHeritage) {
4476 HandleValue heritage = REGS.stackHandleAt(-1);
4478 if (!CheckClassHeritageOperation(cx, heritage)) {
4479 goto error;
4482 END_CASE(CheckClassHeritage)
4484 CASE(BuiltinObject) {
4485 auto kind = BuiltinObjectKind(GET_UINT8(REGS.pc));
4486 JSObject* builtin = BuiltinObjectOperation(cx, kind);
4487 if (!builtin) {
4488 goto error;
4490 PUSH_OBJECT(*builtin);
4492 END_CASE(BuiltinObject)
4494 CASE(FunWithProto) {
4495 ReservedRooted<JSObject*> proto(&rootObject1, &REGS.sp[-1].toObject());
4497 /* Load the specified function object literal. */
4498 ReservedRooted<JSFunction*> fun(&rootFunction0,
4499 script->getFunction(REGS.pc));
4501 JSObject* obj =
4502 FunWithProtoOperation(cx, fun, REGS.fp()->environmentChain(), proto);
4503 if (!obj) {
4504 goto error;
4507 REGS.sp[-1].setObject(*obj);
4509 END_CASE(FunWithProto)
4511 CASE(ObjWithProto) {
4512 JSObject* obj = ObjectWithProtoOperation(cx, REGS.stackHandleAt(-1));
4513 if (!obj) {
4514 goto error;
4517 REGS.sp[-1].setObject(*obj);
4519 END_CASE(ObjWithProto)
4521 CASE(InitHomeObject) {
4522 MOZ_ASSERT(REGS.stackDepth() >= 2);
4524 /* Load the function to be initialized */
4525 JSFunction* func = &REGS.sp[-2].toObject().as<JSFunction>();
4526 MOZ_ASSERT(func->allowSuperProperty());
4528 /* Load the home object */
4529 JSObject* obj = &REGS.sp[-1].toObject();
4530 MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
4532 func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT,
4533 ObjectValue(*obj));
4534 REGS.sp--;
4536 END_CASE(InitHomeObject)
4538 CASE(SuperBase) {
4539 JSFunction& superEnvFunc = REGS.sp[-1].toObject().as<JSFunction>();
4540 MOZ_ASSERT(superEnvFunc.allowSuperProperty());
4541 MOZ_ASSERT(superEnvFunc.baseScript()->needsHomeObject());
4542 const Value& homeObjVal = superEnvFunc.getExtendedSlot(
4543 FunctionExtended::METHOD_HOMEOBJECT_SLOT);
4545 JSObject* homeObj = &homeObjVal.toObject();
4546 JSObject* superBase = HomeObjectSuperBase(homeObj);
4548 REGS.sp[-1].setObjectOrNull(superBase);
4550 END_CASE(SuperBase)
4552 CASE(NewTarget) {
4553 PUSH_COPY(REGS.fp()->newTarget());
4554 MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
4556 END_CASE(NewTarget)
4558 CASE(ImportMeta) {
4559 JSObject* metaObject = ImportMetaOperation(cx, script);
4560 if (!metaObject) {
4561 goto error;
4564 PUSH_OBJECT(*metaObject);
4566 END_CASE(ImportMeta)
4568 CASE(DynamicImport) {
4569 ReservedRooted<Value> options(&rootValue0, REGS.sp[-1]);
4570 REGS.sp--;
4572 ReservedRooted<Value> specifier(&rootValue1);
4573 POP_COPY_TO(specifier);
4575 JSObject* promise =
4576 StartDynamicModuleImport(cx, script, specifier, options);
4577 if (!promise) goto error;
4579 PUSH_OBJECT(*promise);
4581 END_CASE(DynamicImport)
4583 CASE(EnvCallee) {
4584 uint8_t numHops = GET_UINT8(REGS.pc);
4585 JSObject* env = &REGS.fp()->environmentChain()->as<EnvironmentObject>();
4586 for (unsigned i = 0; i < numHops; i++) {
4587 env = &env->as<EnvironmentObject>().enclosingEnvironment();
4589 PUSH_OBJECT(env->as<CallObject>().callee());
4591 END_CASE(EnvCallee)
4593 CASE(SuperFun) {
4594 JSObject* superEnvFunc = &REGS.sp[-1].toObject();
4595 JSObject* superFun = SuperFunOperation(superEnvFunc);
4596 REGS.sp[-1].setObjectOrNull(superFun);
4598 END_CASE(SuperFun)
4600 CASE(CheckObjCoercible) {
4601 ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4602 if (checkVal.isNullOrUndefined()) {
4603 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, checkVal));
4604 goto error;
4607 END_CASE(CheckObjCoercible)
4609 CASE(DebugCheckSelfHosted) {
4610 #ifdef DEBUG
4611 ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4612 if (!Debug_CheckSelfHosted(cx, checkVal)) {
4613 goto error;
4615 #endif
4617 END_CASE(DebugCheckSelfHosted)
4619 CASE(IsConstructing) { PUSH_MAGIC(JS_IS_CONSTRUCTING); }
4620 END_CASE(IsConstructing)
4622 CASE(Inc) {
4623 MutableHandleValue val = REGS.stackHandleAt(-1);
4624 if (!IncOperation(cx, val, val)) {
4625 goto error;
4628 END_CASE(Inc)
4630 CASE(Dec) {
4631 MutableHandleValue val = REGS.stackHandleAt(-1);
4632 if (!DecOperation(cx, val, val)) {
4633 goto error;
4636 END_CASE(Dec)
4638 CASE(ToNumeric) {
4639 if (!ToNumeric(cx, REGS.stackHandleAt(-1))) {
4640 goto error;
4643 END_CASE(ToNumeric)
4645 CASE(BigInt) { PUSH_BIGINT(script->getBigInt(REGS.pc)); }
4646 END_CASE(BigInt)
4648 DEFAULT() {
4649 char numBuf[12];
4650 SprintfLiteral(numBuf, "%d", *REGS.pc);
4651 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4652 JSMSG_BAD_BYTECODE, numBuf);
4653 goto error;
4656 } /* interpreter loop */
4658 MOZ_CRASH("Interpreter loop exited via fallthrough");
4660 error:
4661 switch (HandleError(cx, REGS)) {
4662 case SuccessfulReturnContinuation:
4663 goto successful_return_continuation;
4665 case ErrorReturnContinuation:
4666 interpReturnOK = false;
4667 goto return_continuation;
4669 case CatchContinuation:
4670 ADVANCE_AND_DISPATCH(0);
4672 case FinallyContinuation: {
4674 * Push (exception, true) pair for finally to indicate that we
4675 * should rethrow the exception.
4677 ReservedRooted<Value> exception(&rootValue0);
4678 if (!cx->getPendingException(&exception)) {
4679 interpReturnOK = false;
4680 goto return_continuation;
4682 PUSH_COPY(exception);
4683 PUSH_BOOLEAN(true);
4684 cx->clearPendingException();
4686 ADVANCE_AND_DISPATCH(0);
4689 MOZ_CRASH("Invalid HandleError continuation");
4691 exit:
4692 if (MOZ_LIKELY(!frameHalfInitialized)) {
4693 interpReturnOK =
4694 DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
4696 REGS.fp()->epilogue(cx, REGS.pc);
4699 gc::MaybeVerifyBarriers(cx, true);
4702 * This path is used when it's guaranteed the method can be finished
4703 * inside the JIT.
4705 leave_on_safe_point:
4707 if (interpReturnOK) {
4708 state.setReturnValue(activation.entryFrame()->returnValue());
4711 return interpReturnOK;
4713 prologue_error:
4714 interpReturnOK = false;
4715 frameHalfInitialized = true;
4716 goto prologue_return_continuation;
4719 bool js::ThrowOperation(JSContext* cx, HandleValue v) {
4720 MOZ_ASSERT(!cx->isExceptionPending());
4721 cx->setPendingException(v, ShouldCaptureStack::Maybe);
4722 return false;
4725 bool js::GetProperty(JSContext* cx, HandleValue v, Handle<PropertyName*> name,
4726 MutableHandleValue vp) {
4727 if (name == cx->names().length) {
4728 // Fast path for strings, arrays and arguments.
4729 if (GetLengthProperty(v, vp)) {
4730 return true;
4734 // Optimize common cases like (2).toString() or "foo".valueOf() to not
4735 // create a wrapper object.
4736 if (v.isPrimitive() && !v.isNullOrUndefined()) {
4737 JSObject* proto;
4739 switch (v.type()) {
4740 case ValueType::Double:
4741 case ValueType::Int32:
4742 proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
4743 break;
4744 case ValueType::Boolean:
4745 proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
4746 break;
4747 case ValueType::String:
4748 proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
4749 break;
4750 case ValueType::Symbol:
4751 proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
4752 break;
4753 case ValueType::BigInt:
4754 proto = GlobalObject::getOrCreateBigIntPrototype(cx, cx->global());
4755 break;
4756 #ifdef ENABLE_RECORD_TUPLE
4757 case ValueType::ExtendedPrimitive: {
4758 RootedObject obj(cx, &v.toExtendedPrimitive());
4759 RootedId id(cx, NameToId(name));
4760 return ExtendedPrimitiveGetProperty(cx, obj, v, id, vp);
4762 #endif
4763 case ValueType::Undefined:
4764 case ValueType::Null:
4765 case ValueType::Magic:
4766 case ValueType::PrivateGCThing:
4767 case ValueType::Object:
4768 MOZ_CRASH("unexpected type");
4771 if (!proto) {
4772 return false;
4775 if (GetPropertyPure(cx, proto, NameToId(name), vp.address())) {
4776 return true;
4780 RootedValue receiver(cx, v);
4781 RootedObject obj(
4782 cx, ToObjectFromStackForPropertyAccess(cx, v, JSDVG_SEARCH_STACK, name));
4783 if (!obj) {
4784 return false;
4787 return GetProperty(cx, obj, receiver, name, vp);
4790 JSObject* js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent) {
4791 JSFunction* clone;
4792 if (fun->isNativeFun()) {
4793 MOZ_ASSERT(IsAsmJSModule(fun));
4794 clone = CloneAsmJSModuleFunction(cx, fun);
4795 } else {
4796 RootedObject proto(cx, fun->staticPrototype());
4797 clone = CloneFunctionReuseScript(cx, fun, parent, proto);
4799 if (!clone) {
4800 return nullptr;
4803 MOZ_ASSERT(fun->global() == clone->global());
4804 return clone;
4807 JSObject* js::BindVarOperation(JSContext* cx, JSObject* envChain) {
4808 // Note: BindVarOperation has an unused cx argument because the JIT callVM
4809 // machinery requires this.
4810 return &GetVariablesObject(envChain);
4813 JSObject* js::ImportMetaOperation(JSContext* cx, HandleScript script) {
4814 RootedObject module(cx, GetModuleObjectForScript(script));
4815 MOZ_ASSERT(module);
4816 return GetOrCreateModuleMetaObject(cx, module);
4819 JSObject* js::BuiltinObjectOperation(JSContext* cx, BuiltinObjectKind kind) {
4820 return GetOrCreateBuiltinObject(cx, kind);
4823 bool js::ThrowMsgOperation(JSContext* cx, const unsigned throwMsgKind) {
4824 auto errorNum = ThrowMsgKindToErrNum(ThrowMsgKind(throwMsgKind));
4825 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNum);
4826 return false;
4829 bool js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
4830 MutableHandle<SavedFrame*> stack) {
4831 if (!cx->getPendingException(res)) {
4832 return false;
4834 stack.set(cx->getPendingExceptionStack());
4835 cx->clearPendingException();
4837 // Allow interrupting deeply nested exception handling.
4838 return CheckForInterrupt(cx);
4841 bool js::GetAndClearException(JSContext* cx, MutableHandleValue res) {
4842 Rooted<SavedFrame*> stack(cx);
4843 return GetAndClearExceptionAndStack(cx, res, &stack);
4846 template <bool strict>
4847 bool js::DelPropOperation(JSContext* cx, HandleValue val,
4848 Handle<PropertyName*> name, bool* res) {
4849 const int valIndex = -1;
4850 RootedObject obj(cx,
4851 ToObjectFromStackForPropertyAccess(cx, val, valIndex, name));
4852 if (!obj) {
4853 return false;
4856 RootedId id(cx, NameToId(name));
4857 ObjectOpResult result;
4858 if (!DeleteProperty(cx, obj, id, result)) {
4859 return false;
4862 if (strict) {
4863 if (!result) {
4864 return result.reportError(cx, obj, id);
4866 *res = true;
4867 } else {
4868 *res = result.ok();
4870 return true;
4873 template bool js::DelPropOperation<true>(JSContext* cx, HandleValue val,
4874 Handle<PropertyName*> name, bool* res);
4875 template bool js::DelPropOperation<false>(JSContext* cx, HandleValue val,
4876 Handle<PropertyName*> name,
4877 bool* res);
4879 template <bool strict>
4880 bool js::DelElemOperation(JSContext* cx, HandleValue val, HandleValue index,
4881 bool* res) {
4882 const int valIndex = -2;
4883 RootedObject obj(
4884 cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, index));
4885 if (!obj) {
4886 return false;
4889 RootedId id(cx);
4890 if (!ToPropertyKey(cx, index, &id)) {
4891 return false;
4893 ObjectOpResult result;
4894 if (!DeleteProperty(cx, obj, id, result)) {
4895 return false;
4898 if (strict) {
4899 if (!result) {
4900 return result.reportError(cx, obj, id);
4902 *res = true;
4903 } else {
4904 *res = result.ok();
4906 return true;
4909 template bool js::DelElemOperation<true>(JSContext*, HandleValue, HandleValue,
4910 bool*);
4911 template bool js::DelElemOperation<false>(JSContext*, HandleValue, HandleValue,
4912 bool*);
4914 bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
4915 HandleValue value, bool strict) {
4916 RootedId id(cx);
4917 if (!ToPropertyKey(cx, index, &id)) {
4918 return false;
4920 RootedValue receiver(cx, ObjectValue(*obj));
4921 return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
4924 bool js::SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
4925 HandleValue index, HandleValue value,
4926 HandleValue receiver, bool strict) {
4927 RootedId id(cx);
4928 if (!ToPropertyKey(cx, index, &id)) {
4929 return false;
4931 return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
4934 bool js::AddValues(JSContext* cx, MutableHandleValue lhs,
4935 MutableHandleValue rhs, MutableHandleValue res) {
4936 return AddOperation(cx, lhs, rhs, res);
4939 bool js::SubValues(JSContext* cx, MutableHandleValue lhs,
4940 MutableHandleValue rhs, MutableHandleValue res) {
4941 return SubOperation(cx, lhs, rhs, res);
4944 bool js::MulValues(JSContext* cx, MutableHandleValue lhs,
4945 MutableHandleValue rhs, MutableHandleValue res) {
4946 return MulOperation(cx, lhs, rhs, res);
4949 bool js::DivValues(JSContext* cx, MutableHandleValue lhs,
4950 MutableHandleValue rhs, MutableHandleValue res) {
4951 return DivOperation(cx, lhs, rhs, res);
4954 bool js::ModValues(JSContext* cx, MutableHandleValue lhs,
4955 MutableHandleValue rhs, MutableHandleValue res) {
4956 return ModOperation(cx, lhs, rhs, res);
4959 bool js::PowValues(JSContext* cx, MutableHandleValue lhs,
4960 MutableHandleValue rhs, MutableHandleValue res) {
4961 return PowOperation(cx, lhs, rhs, res);
4964 bool js::BitNot(JSContext* cx, MutableHandleValue in, MutableHandleValue res) {
4965 return BitNotOperation(cx, in, res);
4968 bool js::BitXor(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4969 MutableHandleValue res) {
4970 return BitXorOperation(cx, lhs, rhs, res);
4973 bool js::BitOr(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4974 MutableHandleValue res) {
4975 return BitOrOperation(cx, lhs, rhs, res);
4978 bool js::BitAnd(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4979 MutableHandleValue res) {
4980 return BitAndOperation(cx, lhs, rhs, res);
4983 bool js::BitLsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4984 MutableHandleValue res) {
4985 return BitLshOperation(cx, lhs, rhs, res);
4988 bool js::BitRsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4989 MutableHandleValue res) {
4990 return BitRshOperation(cx, lhs, rhs, res);
4993 bool js::UrshValues(JSContext* cx, MutableHandleValue lhs,
4994 MutableHandleValue rhs, MutableHandleValue res) {
4995 return UrshOperation(cx, lhs, rhs, res);
4998 bool js::LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4999 bool* res) {
5000 return LessThanOperation(cx, lhs, rhs, res);
5003 bool js::LessThanOrEqual(JSContext* cx, MutableHandleValue lhs,
5004 MutableHandleValue rhs, bool* res) {
5005 return LessThanOrEqualOperation(cx, lhs, rhs, res);
5008 bool js::GreaterThan(JSContext* cx, MutableHandleValue lhs,
5009 MutableHandleValue rhs, bool* res) {
5010 return GreaterThanOperation(cx, lhs, rhs, res);
5013 bool js::GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs,
5014 MutableHandleValue rhs, bool* res) {
5015 return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
5018 bool js::AtomicIsLockFree(JSContext* cx, HandleValue in, int* out) {
5019 int i;
5020 if (!ToInt32(cx, in, &i)) {
5021 return false;
5023 *out = js::jit::AtomicOperations::isLockfreeJS(i);
5024 return true;
5027 bool js::DeleteNameOperation(JSContext* cx, Handle<PropertyName*> name,
5028 HandleObject scopeObj, MutableHandleValue res) {
5029 RootedObject scope(cx), pobj(cx);
5030 PropertyResult prop;
5031 if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop)) {
5032 return false;
5035 if (!scope) {
5036 // Return true for non-existent names.
5037 res.setBoolean(true);
5038 return true;
5041 ObjectOpResult result;
5042 RootedId id(cx, NameToId(name));
5043 if (!DeleteProperty(cx, scope, id, result)) {
5044 return false;
5047 bool status = result.ok();
5048 res.setBoolean(status);
5050 if (status) {
5051 // Deleting a name from the global object removes it from [[VarNames]].
5052 if (pobj == scope && scope->is<GlobalObject>()) {
5053 scope->as<GlobalObject>().removeFromVarNames(name);
5057 return true;
5060 bool js::ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
5061 Handle<PropertyName*> name,
5062 MutableHandleValue res) {
5063 RootedObject obj(cx);
5064 if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj)) {
5065 return false;
5068 res.set(ComputeImplicitThis(obj));
5069 return true;
5072 unsigned js::GetInitDataPropAttrs(JSOp op) {
5073 switch (op) {
5074 case JSOp::InitProp:
5075 case JSOp::InitElem:
5076 return JSPROP_ENUMERATE;
5077 case JSOp::InitLockedProp:
5078 case JSOp::InitLockedElem:
5079 return JSPROP_PERMANENT | JSPROP_READONLY;
5080 case JSOp::InitHiddenProp:
5081 case JSOp::InitHiddenElem:
5082 // Non-enumerable, but writable and configurable
5083 return 0;
5084 default:;
5086 MOZ_CRASH("Unknown data initprop");
5089 static bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
5090 HandleObject obj, HandleId id,
5091 HandleObject val) {
5092 MOZ_ASSERT(val->isCallable());
5094 JSOp op = JSOp(*pc);
5096 unsigned attrs = 0;
5097 if (!IsHiddenInitOp(op)) {
5098 attrs |= JSPROP_ENUMERATE;
5101 if (op == JSOp::InitPropGetter || op == JSOp::InitElemGetter ||
5102 op == JSOp::InitHiddenPropGetter || op == JSOp::InitHiddenElemGetter) {
5103 return DefineAccessorProperty(cx, obj, id, val, nullptr, attrs);
5106 MOZ_ASSERT(op == JSOp::InitPropSetter || op == JSOp::InitElemSetter ||
5107 op == JSOp::InitHiddenPropSetter ||
5108 op == JSOp::InitHiddenElemSetter);
5109 return DefineAccessorProperty(cx, obj, id, nullptr, val, attrs);
5112 bool js::InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
5113 HandleObject obj,
5114 Handle<PropertyName*> name,
5115 HandleObject val) {
5116 RootedId id(cx, NameToId(name));
5117 return InitGetterSetterOperation(cx, pc, obj, id, val);
5120 bool js::InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
5121 HandleObject obj, HandleValue idval,
5122 HandleObject val) {
5123 RootedId id(cx);
5124 if (!ToPropertyKey(cx, idval, &id)) {
5125 return false;
5128 return InitGetterSetterOperation(cx, pc, obj, id, val);
5131 bool js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
5132 HandleValue thisv, HandleValue callee,
5133 HandleValue arr, HandleValue newTarget,
5134 MutableHandleValue res) {
5135 Rooted<ArrayObject*> aobj(cx, &arr.toObject().as<ArrayObject>());
5136 uint32_t length = aobj->length();
5137 JSOp op = JSOp(*pc);
5138 bool constructing = op == JSOp::SpreadNew || op == JSOp::SpreadSuperCall;
5140 // {Construct,Invoke}Args::init does this too, but this gives us a better
5141 // error message.
5142 if (length > ARGS_LENGTH_MAX) {
5143 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5144 constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
5145 : JSMSG_TOO_MANY_FUN_SPREADARGS);
5146 return false;
5149 // Do our own checks for the callee being a function, as Invoke uses the
5150 // expression decompiler to decompile the callee stack operand based on
5151 // the number of arguments. Spread operations have the callee at sp - 3
5152 // when not constructing, and sp - 4 when constructing.
5153 if (callee.isPrimitive()) {
5154 return ReportIsNotFunction(cx, callee, 2 + constructing,
5155 constructing ? CONSTRUCT : NO_CONSTRUCT);
5158 if (!callee.toObject().isCallable()) {
5159 return ReportIsNotFunction(cx, callee, 2 + constructing,
5160 constructing ? CONSTRUCT : NO_CONSTRUCT);
5163 // The object must be an array with dense elements and no holes. Baseline's
5164 // optimized spread call stubs rely on this.
5165 MOZ_ASSERT(IsPackedArray(aobj));
5167 if (constructing) {
5168 if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget)) {
5169 return false;
5172 ConstructArgs cargs(cx);
5173 if (!cargs.init(cx, length)) {
5174 return false;
5177 if (!GetElements(cx, aobj, length, cargs.array())) {
5178 return false;
5181 RootedObject obj(cx);
5182 if (!Construct(cx, callee, cargs, newTarget, &obj)) {
5183 return false;
5185 res.setObject(*obj);
5186 } else {
5187 InvokeArgs args(cx);
5188 if (!args.init(cx, length)) {
5189 return false;
5192 if (!GetElements(cx, aobj, length, args.array())) {
5193 return false;
5196 if ((op == JSOp::SpreadEval || op == JSOp::StrictSpreadEval) &&
5197 cx->global()->valueIsEval(callee)) {
5198 if (!DirectEval(cx, args.get(0), res)) {
5199 return false;
5201 } else {
5202 MOZ_ASSERT(op == JSOp::SpreadCall || op == JSOp::SpreadEval ||
5203 op == JSOp::StrictSpreadEval,
5204 "bad spread opcode");
5206 if (!Call(cx, callee, thisv, args, res)) {
5207 return false;
5212 return true;
5215 static bool OptimizeArraySpreadCall(JSContext* cx, HandleObject obj,
5216 MutableHandleValue result) {
5217 MOZ_ASSERT(result.isUndefined());
5219 // Optimize spread call by skipping spread operation when following
5220 // conditions are met:
5221 // * the argument is an array
5222 // * the array has no hole
5223 // * array[@@iterator] is not modified
5224 // * the array's prototype is Array.prototype
5225 // * Array.prototype[@@iterator] is not modified
5226 // * %ArrayIteratorPrototype%.next is not modified
5227 if (!IsPackedArray(obj)) {
5228 return true;
5231 ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
5232 if (!stubChain) {
5233 return false;
5236 bool optimized;
5237 if (!stubChain->tryOptimizeArray(cx, obj.as<ArrayObject>(), &optimized)) {
5238 return false;
5240 if (!optimized) {
5241 return true;
5244 result.setObject(*obj);
5245 return true;
5248 static bool OptimizeArgumentsSpreadCall(JSContext* cx, HandleObject obj,
5249 MutableHandleValue result) {
5250 MOZ_ASSERT(result.isUndefined());
5252 // Optimize spread call by skipping the spread operation when the following
5253 // conditions are met:
5254 // * the argument is an arguments object
5255 // * the arguments object has no deleted elements
5256 // * arguments.length is not overridden
5257 // * arguments[@@iterator] is not overridden
5258 // * %ArrayIteratorPrototype%.next is not modified
5260 if (!obj->is<ArgumentsObject>()) {
5261 return true;
5264 Handle<ArgumentsObject*> args = obj.as<ArgumentsObject>();
5265 if (args->hasOverriddenElement() || args->hasOverriddenLength() ||
5266 args->hasOverriddenIterator()) {
5267 return true;
5270 ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
5271 if (!stubChain) {
5272 return false;
5275 bool optimized;
5276 if (!stubChain->tryOptimizeArrayIteratorNext(cx, &optimized)) {
5277 return false;
5279 if (!optimized) {
5280 return true;
5283 auto* array = ArrayFromArgumentsObject(cx, args);
5284 if (!array) {
5285 return false;
5288 result.setObject(*array);
5289 return true;
5292 bool js::OptimizeSpreadCall(JSContext* cx, HandleValue arg,
5293 MutableHandleValue result) {
5294 // This function returns |undefined| if the spread operation can't be
5295 // optimized.
5296 result.setUndefined();
5298 if (!arg.isObject()) {
5299 return true;
5302 RootedObject obj(cx, &arg.toObject());
5303 if (!OptimizeArraySpreadCall(cx, obj, result)) {
5304 return false;
5306 if (result.isObject()) {
5307 return true;
5309 if (!OptimizeArgumentsSpreadCall(cx, obj, result)) {
5310 return false;
5312 if (result.isObject()) {
5313 return true;
5316 MOZ_ASSERT(result.isUndefined());
5317 return true;
5320 ArrayObject* js::ArrayFromArgumentsObject(JSContext* cx,
5321 Handle<ArgumentsObject*> args) {
5322 MOZ_ASSERT(!args->hasOverriddenLength());
5323 MOZ_ASSERT(!args->hasOverriddenElement());
5325 uint32_t length = args->initialLength();
5326 auto* array = NewDenseFullyAllocatedArray(cx, length);
5327 if (!array) {
5328 return nullptr;
5330 array->setDenseInitializedLength(length);
5332 for (uint32_t index = 0; index < length; index++) {
5333 const Value& v = args->element(index);
5334 array->initDenseElement(index, v);
5337 return array;
5340 JSObject* js::NewObjectOperation(JSContext* cx, HandleScript script,
5341 const jsbytecode* pc) {
5342 if (JSOp(*pc) == JSOp::NewObject) {
5343 Rooted<SharedShape*> shape(cx, script->getShape(pc));
5344 return PlainObject::createWithShape(cx, shape);
5347 MOZ_ASSERT(JSOp(*pc) == JSOp::NewInit);
5348 return NewPlainObject(cx);
5351 JSObject* js::NewPlainObjectBaselineFallback(JSContext* cx,
5352 Handle<SharedShape*> shape,
5353 gc::AllocKind allocKind,
5354 gc::AllocSite* site) {
5355 MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
5357 mozilla::Maybe<AutoRealm> ar;
5358 if (cx->realm() != shape->realm()) {
5359 MOZ_ASSERT(cx->compartment() == shape->compartment());
5360 ar.emplace(cx, shape);
5363 gc::Heap initialHeap = site->initialHeap();
5364 return NativeObject::create(cx, allocKind, initialHeap, shape, site);
5367 JSObject* js::NewPlainObjectOptimizedFallback(JSContext* cx,
5368 Handle<SharedShape*> shape,
5369 gc::AllocKind allocKind,
5370 gc::Heap initialHeap) {
5371 MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
5373 mozilla::Maybe<AutoRealm> ar;
5374 if (cx->realm() != shape->realm()) {
5375 MOZ_ASSERT(cx->compartment() == shape->compartment());
5376 ar.emplace(cx, shape);
5379 gc::AllocSite* site = cx->zone()->optimizedAllocSite();
5380 return NativeObject::create(cx, allocKind, initialHeap, shape, site);
5383 ArrayObject* js::NewArrayOperation(
5384 JSContext* cx, uint32_t length,
5385 NewObjectKind newKind /* = GenericObject */) {
5386 return NewDenseFullyAllocatedArray(cx, length, newKind);
5389 ArrayObject* js::NewArrayObjectBaselineFallback(JSContext* cx, uint32_t length,
5390 gc::AllocKind allocKind,
5391 gc::AllocSite* site) {
5392 NewObjectKind newKind =
5393 site->initialHeap() == gc::Heap::Tenured ? TenuredObject : GenericObject;
5394 ArrayObject* array = NewDenseFullyAllocatedArray(cx, length, newKind, site);
5395 // It's important that we allocate an object with the alloc kind we were
5396 // expecting so that a new arena gets allocated if the current arena for that
5397 // kind is full.
5398 MOZ_ASSERT_IF(array && array->isTenured(),
5399 array->asTenured().getAllocKind() == allocKind);
5400 return array;
5403 ArrayObject* js::NewArrayObjectOptimizedFallback(JSContext* cx, uint32_t length,
5404 gc::AllocKind allocKind,
5405 NewObjectKind newKind) {
5406 gc::AllocSite* site = cx->zone()->optimizedAllocSite();
5407 ArrayObject* array = NewDenseFullyAllocatedArray(cx, length, newKind, site);
5408 // It's important that we allocate an object with the alloc kind we were
5409 // expecting so that a new arena gets allocated if the current arena for that
5410 // kind is full.
5411 MOZ_ASSERT_IF(array && array->isTenured(),
5412 array->asTenured().getAllocKind() == allocKind);
5413 return array;
5416 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5417 HandleId id) {
5418 MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
5419 errorNumber == JSMSG_BAD_CONST_ASSIGN);
5420 if (UniqueChars printable =
5421 IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsIdentifier)) {
5422 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber,
5423 printable.get());
5427 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5428 Handle<PropertyName*> name) {
5429 RootedId id(cx, NameToId(name));
5430 ReportRuntimeLexicalError(cx, errorNumber, id);
5433 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5434 HandleScript script, jsbytecode* pc) {
5435 JSOp op = JSOp(*pc);
5436 MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical ||
5437 op == JSOp::ThrowSetConst || op == JSOp::GetImport);
5439 Rooted<PropertyName*> name(cx);
5440 if (IsLocalOp(op)) {
5441 name = FrameSlotName(script, pc)->asPropertyName();
5442 } else if (IsAliasedVarOp(op)) {
5443 name = EnvironmentCoordinateNameSlow(script, pc);
5444 } else {
5445 MOZ_ASSERT(IsAtomOp(op));
5446 name = script->getName(pc);
5449 ReportRuntimeLexicalError(cx, errorNumber, name);
5452 void js::ReportRuntimeRedeclaration(JSContext* cx, Handle<PropertyName*> name,
5453 const char* redeclKind) {
5454 if (UniqueChars printable = AtomToPrintableString(cx, name)) {
5455 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5456 JSMSG_REDECLARED_VAR, redeclKind,
5457 printable.get());
5461 bool js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind) {
5462 switch (kind) {
5463 case CheckIsObjectKind::IteratorNext:
5464 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5465 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
5466 break;
5467 case CheckIsObjectKind::IteratorReturn:
5468 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5469 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "return");
5470 break;
5471 case CheckIsObjectKind::IteratorThrow:
5472 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5473 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "throw");
5474 break;
5475 case CheckIsObjectKind::GetIterator:
5476 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5477 JSMSG_GET_ITER_RETURNED_PRIMITIVE);
5478 break;
5479 case CheckIsObjectKind::GetAsyncIterator:
5480 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5481 JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
5482 break;
5483 #ifdef ENABLE_DECORATORS
5484 case CheckIsObjectKind::DecoratorReturn:
5485 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5486 JSMSG_DECORATOR_INVALID_RETURN_TYPE);
5487 break;
5488 #endif
5489 default:
5490 MOZ_CRASH("Unknown kind");
5492 return false;
5495 bool js::ThrowUninitializedThis(JSContext* cx) {
5496 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5497 JSMSG_UNINITIALIZED_THIS);
5498 return false;
5501 bool js::ThrowInitializedThis(JSContext* cx) {
5502 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
5503 return false;
5506 bool js::ThrowObjectCoercible(JSContext* cx, HandleValue value) {
5507 MOZ_ASSERT(value.isNullOrUndefined());
5508 ReportIsNullOrUndefinedForPropertyAccess(cx, value, JSDVG_SEARCH_STACK);
5509 return false;
5512 bool js::SetPropertySuper(JSContext* cx, HandleValue lval, HandleValue receiver,
5513 Handle<PropertyName*> name, HandleValue rval,
5514 bool strict) {
5515 MOZ_ASSERT(lval.isObjectOrNull());
5517 RootedObject obj(cx, ToObjectFromStackForPropertyAccess(
5518 cx, lval, JSDVG_SEARCH_STACK, name));
5519 if (!obj) {
5520 return false;
5523 RootedId id(cx, NameToId(name));
5524 return SetObjectElementOperation(cx, obj, id, rval, receiver, strict);
5527 bool js::SetElementSuper(JSContext* cx, HandleValue lval, HandleValue receiver,
5528 HandleValue index, HandleValue rval, bool strict) {
5529 MOZ_ASSERT(lval.isObjectOrNull());
5531 RootedObject obj(cx, ToObjectFromStackForPropertyAccess(
5532 cx, lval, JSDVG_SEARCH_STACK, index));
5533 if (!obj) {
5534 return false;
5537 return SetObjectElementWithReceiver(cx, obj, index, rval, receiver, strict);
5540 bool js::LoadAliasedDebugVar(JSContext* cx, JSObject* env, jsbytecode* pc,
5541 MutableHandleValue result) {
5542 EnvironmentCoordinate ec(pc);
5544 for (unsigned i = ec.hops(); i; i--) {
5545 if (env->is<EnvironmentObject>()) {
5546 env = &env->as<EnvironmentObject>().enclosingEnvironment();
5547 } else {
5548 MOZ_ASSERT(env->is<DebugEnvironmentProxy>());
5549 env = &env->as<DebugEnvironmentProxy>().enclosingEnvironment();
5553 EnvironmentObject& finalEnv =
5554 env->is<EnvironmentObject>()
5555 ? env->as<EnvironmentObject>()
5556 : env->as<DebugEnvironmentProxy>().environment();
5558 result.set(finalEnv.aliasedBinding(ec));
5559 return true;
5562 // https://tc39.es/ecma262/#sec-iteratorclose
5563 bool js::CloseIterOperation(JSContext* cx, HandleObject iter,
5564 CompletionKind kind) {
5565 // Steps 1-2 are implicit.
5567 // Step 3
5568 RootedValue returnMethod(cx);
5569 bool innerResult =
5570 GetProperty(cx, iter, iter, cx->names().return_, &returnMethod);
5572 // Step 4
5573 RootedValue result(cx);
5574 if (innerResult) {
5575 // Step 4b
5576 if (returnMethod.isNullOrUndefined()) {
5577 return true;
5579 // Step 4c
5580 if (IsCallable(returnMethod)) {
5581 RootedValue thisVal(cx, ObjectValue(*iter));
5582 innerResult = Call(cx, returnMethod, thisVal, &result);
5583 } else {
5584 innerResult = ReportIsNotFunction(cx, returnMethod);
5588 // Step 5
5589 if (kind == CompletionKind::Throw) {
5590 // If we close an iterator while unwinding for an exception,
5591 // the initial exception takes priority over any exception thrown
5592 // while closing the iterator.
5593 if (cx->isExceptionPending()) {
5594 cx->clearPendingException();
5596 return true;
5599 // Step 6
5600 if (!innerResult) {
5601 return false;
5604 // Step 7
5605 if (!result.isObject()) {
5606 return ThrowCheckIsObject(cx, CheckIsObjectKind::IteratorReturn);
5609 // Step 8
5610 return true;