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/. */
6
7 /*
8 * JavaScript bytecode interpreter.
9 */
10
11 #include "vm/Interpreter-inl.h"
12
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/WrappingOperations.h"
19
20 #include <string.h>
21
22 #include "jslibmath.h"
23 #include "jsmath.h"
24 #include "jsnum.h"
25
26 #include "builtin/Array.h"
27 #include "builtin/Eval.h"
28 #include "builtin/ModuleObject.h"
29 #include "builtin/Promise.h"
30 #include "jit/AtomicOperations.h"
31 #include "jit/BaselineJIT.h"
32 #include "jit/Ion.h"
33 #include "jit/IonAnalysis.h"
34 #include "jit/Jit.h"
35 #include "jit/JitRuntime.h"
36 #include "js/CharacterEncoding.h"
37 #include "js/experimental/JitInfo.h" // JSJitInfo
38 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
39 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
40 #include "js/friend/WindowProxy.h" // js::IsWindowProxy
41 #include "util/CheckedArithmetic.h"
42 #include "util/StringBuffer.h"
43 #include "vm/AsyncFunction.h"
44 #include "vm/AsyncIteration.h"
45 #include "vm/BigIntType.h"
46 #include "vm/BytecodeUtil.h" // JSDVG_SEARCH_STACK
47 #include "vm/EqualityOperations.h" // js::StrictlyEqual
48 #include "vm/FunctionFlags.h" // js::FunctionFlags
49 #include "vm/GeneratorObject.h"
50 #include "vm/Iteration.h"
51 #include "vm/JSAtom.h"
52 #include "vm/JSContext.h"
53 #include "vm/JSFunction.h"
54 #include "vm/JSObject.h"
55 #include "vm/JSScript.h"
56 #include "vm/Opcodes.h"
57 #include "vm/PIC.h"
58 #include "vm/PlainObject.h" // js::PlainObject
59 #include "vm/Printer.h"
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/TraceLogging.h"
66
67 #include "builtin/Boolean-inl.h"
68 #include "debugger/DebugAPI-inl.h"
69 #include "vm/EnvironmentObject-inl.h"
70 #include "vm/GeckoProfiler-inl.h"
71 #include "vm/JSAtom-inl.h"
72 #include "vm/JSFunction-inl.h"
73 #include "vm/JSScript-inl.h"
74 #include "vm/NativeObject-inl.h"
75 #include "vm/ObjectOperations-inl.h"
76 #include "vm/PlainObject-inl.h" // js::CopyInitializerObject, js::CreateThis
77 #include "vm/Probes-inl.h"
78 #include "vm/Stack-inl.h"
79
80 using namespace js;
81
82 using mozilla::DebugOnly;
83 using mozilla::NumberEqualsInt32;
84
85 using js::jit::JitScript;
86
87 template <bool Eq>
LooseEqualityOp(JSContext * cx,InterpreterRegs & regs)88 static MOZ_ALWAYS_INLINE bool LooseEqualityOp(JSContext* cx,
89 InterpreterRegs& regs) {
90 HandleValue rval = regs.stackHandleAt(-1);
91 HandleValue lval = regs.stackHandleAt(-2);
92 bool cond;
93 if (!LooselyEqual(cx, lval, rval, &cond)) {
94 return false;
95 }
96 cond = (cond == Eq);
97 regs.sp--;
98 regs.sp[-1].setBoolean(cond);
99 return true;
100 }
101
BoxNonStrictThis(JSContext * cx,HandleValue thisv)102 JSObject* js::BoxNonStrictThis(JSContext* cx, HandleValue thisv) {
103 MOZ_ASSERT(!thisv.isMagic());
104
105 if (thisv.isNullOrUndefined()) {
106 return cx->global()->lexicalEnvironment().thisObject();
107 }
108
109 if (thisv.isObject()) {
110 return &thisv.toObject();
111 }
112
113 return PrimitiveToObject(cx, thisv);
114 }
115
GetFunctionThis(JSContext * cx,AbstractFramePtr frame,MutableHandleValue res)116 bool js::GetFunctionThis(JSContext* cx, AbstractFramePtr frame,
117 MutableHandleValue res) {
118 MOZ_ASSERT(frame.isFunctionFrame());
119 MOZ_ASSERT(!frame.callee()->isArrow());
120
121 if (frame.thisArgument().isObject() || frame.callee()->strict()) {
122 res.set(frame.thisArgument());
123 return true;
124 }
125
126 MOZ_ASSERT(!frame.callee()->isSelfHostedBuiltin(),
127 "Self-hosted builtins must be strict");
128
129 RootedValue thisv(cx, frame.thisArgument());
130
131 // If there is a NSVO on environment chain, use it as basis for fallback
132 // global |this|. This gives a consistent definition of global lexical
133 // |this| between function and global contexts.
134 //
135 // NOTE: If only non-syntactic WithEnvironments are on the chain, we use the
136 // global lexical |this| value. This is for compatibility with the Subscript
137 // Loader.
138 if (frame.script()->hasNonSyntacticScope() && thisv.isNullOrUndefined()) {
139 RootedObject env(cx, frame.environmentChain());
140 while (true) {
141 if (IsNSVOLexicalEnvironment(env) || IsGlobalLexicalEnvironment(env)) {
142 res.setObject(*GetThisObjectOfLexical(env));
143 return true;
144 }
145 if (!env->enclosingEnvironment()) {
146 // This can only happen in Debugger eval frames: in that case we
147 // don't always have a global lexical env, see EvaluateInEnv.
148 MOZ_ASSERT(env->is<GlobalObject>());
149 res.setObject(*GetThisObject(env));
150 return true;
151 }
152 env = env->enclosingEnvironment();
153 }
154 }
155
156 JSObject* obj = BoxNonStrictThis(cx, thisv);
157 if (!obj) {
158 return false;
159 }
160
161 res.setObject(*obj);
162 return true;
163 }
164
GetNonSyntacticGlobalThis(JSContext * cx,HandleObject envChain,MutableHandleValue res)165 void js::GetNonSyntacticGlobalThis(JSContext* cx, HandleObject envChain,
166 MutableHandleValue res) {
167 RootedObject env(cx, envChain);
168 while (true) {
169 if (IsExtensibleLexicalEnvironment(env)) {
170 res.setObject(*GetThisObjectOfLexical(env));
171 return;
172 }
173 if (!env->enclosingEnvironment()) {
174 // This can only happen in Debugger eval frames: in that case we
175 // don't always have a global lexical env, see EvaluateInEnv.
176 MOZ_ASSERT(env->is<GlobalObject>());
177 res.setObject(*GetThisObject(env));
178 return;
179 }
180 env = env->enclosingEnvironment();
181 }
182 }
183
Debug_CheckSelfHosted(JSContext * cx,HandleValue fun)184 bool js::Debug_CheckSelfHosted(JSContext* cx, HandleValue fun) {
185 #ifndef DEBUG
186 MOZ_CRASH("self-hosted checks should only be done in Debug builds");
187 #endif
188
189 RootedObject funObj(cx, UncheckedUnwrap(&fun.toObject()));
190 MOZ_ASSERT(funObj->as<JSFunction>().isSelfHostedOrIntrinsic());
191
192 // This is purely to police self-hosted code. There is no actual operation.
193 return true;
194 }
195
GetPropertyOperation(JSContext * cx,InterpreterFrame * fp,HandleScript script,jsbytecode * pc,MutableHandleValue lval,MutableHandleValue vp)196 static inline bool GetPropertyOperation(JSContext* cx, InterpreterFrame* fp,
197 HandleScript script, jsbytecode* pc,
198 MutableHandleValue lval,
199 MutableHandleValue vp) {
200 RootedPropertyName name(cx, script->getName(pc));
201
202 if (name == cx->names().length && GetLengthProperty(lval, vp)) {
203 return true;
204 }
205
206 // Copy lval, because it might alias vp.
207 RootedValue v(cx, lval);
208 return GetProperty(cx, v, name, vp);
209 }
210
GetNameOperation(JSContext * cx,InterpreterFrame * fp,jsbytecode * pc,MutableHandleValue vp)211 static inline bool GetNameOperation(JSContext* cx, InterpreterFrame* fp,
212 jsbytecode* pc, MutableHandleValue vp) {
213 RootedObject envChain(cx, fp->environmentChain());
214 RootedPropertyName name(cx, fp->script()->getName(pc));
215
216 /*
217 * Skip along the env chain to the enclosing global object. This is
218 * used for GNAME opcodes where the bytecode emitter has determined a
219 * name access must be on the global. It also insulates us from bugs
220 * in the emitter: type inference will assume that GNAME opcodes are
221 * accessing the global object, and the inferred behavior should match
222 * the actual behavior even if the id could be found on the env chain
223 * before the global object.
224 */
225 if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope()) {
226 envChain = &cx->global()->lexicalEnvironment();
227 }
228
229 /* Kludge to allow (typeof foo == "undefined") tests. */
230 JSOp op2 = JSOp(pc[JSOpLength_GetName]);
231 if (op2 == JSOp::Typeof) {
232 return GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, vp);
233 }
234 return GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, vp);
235 }
236
GetImportOperation(JSContext * cx,HandleObject envChain,HandleScript script,jsbytecode * pc,MutableHandleValue vp)237 bool js::GetImportOperation(JSContext* cx, HandleObject envChain,
238 HandleScript script, jsbytecode* pc,
239 MutableHandleValue vp) {
240 RootedObject env(cx), pobj(cx);
241 RootedPropertyName name(cx, script->getName(pc));
242 PropertyResult prop;
243
244 MOZ_ALWAYS_TRUE(LookupName(cx, name, envChain, &env, &pobj, &prop));
245 MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
246 MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
247 return FetchName<GetNameMode::Normal>(cx, env, pobj, name, prop, vp);
248 }
249
SetPropertyOperation(JSContext * cx,JSOp op,HandleValue lval,int lvalIndex,HandleId id,HandleValue rval)250 static bool SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval,
251 int lvalIndex, HandleId id, HandleValue rval) {
252 MOZ_ASSERT(op == JSOp::SetProp || op == JSOp::StrictSetProp);
253
254 RootedObject obj(cx,
255 ToObjectFromStackForPropertyAccess(cx, lval, lvalIndex, id));
256 if (!obj) {
257 return false;
258 }
259
260 ObjectOpResult result;
261 return SetProperty(cx, obj, id, rval, lval, result) &&
262 result.checkStrictModeError(cx, obj, id, op == JSOp::StrictSetProp);
263 }
264
SuperFunOperation(JSObject * callee)265 static JSObject* SuperFunOperation(JSObject* callee) {
266 MOZ_ASSERT(callee->as<JSFunction>().isClassConstructor());
267 MOZ_ASSERT(
268 callee->as<JSFunction>().baseScript()->isDerivedClassConstructor());
269
270 return callee->as<JSFunction>().staticPrototype();
271 }
272
HomeObjectSuperBase(JSContext * cx,JSObject * homeObj)273 static JSObject* HomeObjectSuperBase(JSContext* cx, JSObject* homeObj) {
274 MOZ_ASSERT(homeObj->is<PlainObject>() || homeObj->is<JSFunction>());
275
276 if (JSObject* superBase = homeObj->staticPrototype()) {
277 return superBase;
278 }
279
280 ThrowHomeObjectNotObject(cx);
281 return nullptr;
282 }
283
ReportIsNotFunction(JSContext * cx,HandleValue v,int numToSkip,MaybeConstruct construct)284 bool js::ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip,
285 MaybeConstruct construct) {
286 unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
287 int spIndex = numToSkip >= 0 ? -(numToSkip + 1) : JSDVG_SEARCH_STACK;
288
289 ReportValueError(cx, error, spIndex, v, nullptr);
290 return false;
291 }
292
ValueToCallable(JSContext * cx,HandleValue v,int numToSkip,MaybeConstruct construct)293 JSObject* js::ValueToCallable(JSContext* cx, HandleValue v, int numToSkip,
294 MaybeConstruct construct) {
295 if (v.isObject() && v.toObject().isCallable()) {
296 return &v.toObject();
297 }
298
299 ReportIsNotFunction(cx, v, numToSkip, construct);
300 return nullptr;
301 }
302
MaybeCreateThisForConstructor(JSContext * cx,const CallArgs & args)303 static bool MaybeCreateThisForConstructor(JSContext* cx, const CallArgs& args) {
304 if (args.thisv().isObject()) {
305 return true;
306 }
307
308 RootedFunction callee(cx, &args.callee().as<JSFunction>());
309 RootedObject newTarget(cx, &args.newTarget().toObject());
310
311 MOZ_ASSERT(callee->hasBytecode());
312
313 if (!CreateThis(cx, callee, newTarget, GenericObject, args.mutableThisv())) {
314 return false;
315 }
316
317 // Ensure the callee still has a non-lazy script. We normally don't relazify
318 // in active compartments, but the .prototype lookup might have called the
319 // relazifyFunctions testing function that doesn't have this restriction.
320 return JSFunction::getOrCreateScript(cx, callee);
321 }
322
323 static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
324 RunState& state);
325
pushInterpreterFrame(JSContext * cx)326 InterpreterFrame* InvokeState::pushInterpreterFrame(JSContext* cx) {
327 return cx->interpreterStack().pushInvokeFrame(cx, args_, construct_);
328 }
329
pushInterpreterFrame(JSContext * cx)330 InterpreterFrame* ExecuteState::pushInterpreterFrame(JSContext* cx) {
331 return cx->interpreterStack().pushExecuteFrame(cx, script_, newTargetValue_,
332 envChain_, evalInFrame_);
333 }
334
pushInterpreterFrame(JSContext * cx)335 InterpreterFrame* RunState::pushInterpreterFrame(JSContext* cx) {
336 if (isInvoke()) {
337 return asInvoke()->pushInterpreterFrame(cx);
338 }
339 return asExecute()->pushInterpreterFrame(cx);
340 }
341
342 // MSVC with PGO inlines a lot of functions in RunScript, resulting in large
343 // stack frames and stack overflow issues, see bug 1167883. Turn off PGO to
344 // avoid this.
345 #ifdef _MSC_VER
346 # pragma optimize("g", off)
347 #endif
RunScript(JSContext * cx,RunState & state)348 bool js::RunScript(JSContext* cx, RunState& state) {
349 AutoCheckRecursionLimit recursion(cx);
350 if (!recursion.check(cx)) {
351 return false;
352 }
353
354 MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(),
355 !cx->runtime()->jitRuntime()->disallowArbitraryCode());
356
357 // Since any script can conceivably GC, make sure it's safe to do so.
358 cx->verifyIsSafeToGC();
359
360 MOZ_ASSERT(cx->realm() == state.script()->realm());
361
362 MOZ_DIAGNOSTIC_ASSERT(cx->realm()->isSystem() ||
363 cx->runtime()->allowContentJS());
364
365 if (!DebugAPI::checkNoExecute(cx, state.script())) {
366 return false;
367 }
368
369 GeckoProfilerEntryMarker marker(cx, state.script());
370
371 bool measuringTime = !cx->isMeasuringExecutionTime();
372 mozilla::TimeStamp startTime;
373 if (measuringTime) {
374 cx->setIsMeasuringExecutionTime(true);
375 startTime = ReallyNow();
376 }
377 auto timerEnd = mozilla::MakeScopeExit([&]() {
378 if (measuringTime) {
379 mozilla::TimeDuration delta = ReallyNow() - startTime;
380 cx->realm()->timers.executionTime += delta;
381 cx->setIsMeasuringExecutionTime(false);
382 }
383 });
384
385 jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
386 switch (status) {
387 case jit::EnterJitStatus::Error:
388 return false;
389 case jit::EnterJitStatus::Ok:
390 return true;
391 case jit::EnterJitStatus::NotEntered:
392 break;
393 }
394
395 bool ok = Interpret(cx, state);
396
397 return ok;
398 }
399 #ifdef _MSC_VER
400 # pragma optimize("", on)
401 #endif
402
403 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
CallJSNative(JSContext * cx,Native native,CallReason reason,const CallArgs & args)404 MOZ_ALWAYS_INLINE bool CallJSNative(JSContext* cx, Native native,
405 CallReason reason, const CallArgs& args) {
406 TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
407 AutoTraceLog traceLog(logger, TraceLogger_Call);
408
409 AutoCheckRecursionLimit recursion(cx);
410 if (!recursion.check(cx)) {
411 return false;
412 }
413
414 NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
415 if (resumeMode != NativeResumeMode::Continue) {
416 return resumeMode == NativeResumeMode::Override;
417 }
418
419 #ifdef DEBUG
420 bool alreadyThrowing = cx->isExceptionPending();
421 #endif
422 cx->check(args);
423 MOZ_ASSERT(!args.callee().is<ProxyObject>());
424
425 AutoRealm ar(cx, &args.callee());
426 bool ok = native(cx, args.length(), args.base());
427 if (ok) {
428 cx->check(args.rval());
429 MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
430 }
431 return ok;
432 }
433
434 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
CallJSNativeConstructor(JSContext * cx,Native native,const CallArgs & args)435 MOZ_ALWAYS_INLINE bool CallJSNativeConstructor(JSContext* cx, Native native,
436 const CallArgs& args) {
437 #ifdef DEBUG
438 RootedObject callee(cx, &args.callee());
439 #endif
440
441 MOZ_ASSERT(args.thisv().isMagic());
442 if (!CallJSNative(cx, native, CallReason::Call, args)) {
443 return false;
444 }
445
446 /*
447 * Native constructors must return non-primitive values on success.
448 * Although it is legal, if a constructor returns the callee, there is a
449 * 99.9999% chance it is a bug. If any valid code actually wants the
450 * constructor to return the callee, the assertion can be removed or
451 * (another) conjunct can be added to the antecedent.
452 *
453 * Exception: (new Object(Object)) returns the callee.
454 */
455 MOZ_ASSERT_IF((!callee->is<JSFunction>() ||
456 callee->as<JSFunction>().native() != obj_construct),
457 args.rval().isObject() && callee != &args.rval().toObject());
458
459 return true;
460 }
461
462 /*
463 * Find a function reference and its 'this' value implicit first parameter
464 * under argc arguments on cx's stack, and call the function. Push missing
465 * required arguments, allocate declared local variables, and pop everything
466 * when done. Then push the return value.
467 *
468 * Note: This function DOES NOT call GetThisValue to munge |args.thisv()| if
469 * necessary. The caller (usually the interpreter) must have performed
470 * this step already!
471 */
InternalCallOrConstruct(JSContext * cx,const CallArgs & args,MaybeConstruct construct,CallReason reason)472 bool js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args,
473 MaybeConstruct construct, CallReason reason) {
474 MOZ_ASSERT(args.length() <= ARGS_LENGTH_MAX);
475
476 unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
477 if (args.calleev().isPrimitive()) {
478 return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
479 }
480
481 /* Invoke non-functions. */
482 if (MOZ_UNLIKELY(!args.callee().is<JSFunction>())) {
483 MOZ_ASSERT_IF(construct, !args.callee().isConstructor());
484
485 if (!args.callee().isCallable()) {
486 return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
487 }
488
489 if (args.callee().is<ProxyObject>()) {
490 RootedObject proxy(cx, &args.callee());
491 return Proxy::call(cx, proxy, args);
492 }
493
494 JSNative call = args.callee().callHook();
495 MOZ_ASSERT(call, "isCallable without a callHook?");
496
497 return CallJSNative(cx, call, reason, args);
498 }
499
500 /* Invoke native functions. */
501 RootedFunction fun(cx, &args.callee().as<JSFunction>());
502 if (fun->isNativeFun()) {
503 MOZ_ASSERT_IF(construct, !fun->isConstructor());
504 JSNative native = fun->native();
505 if (!construct && args.ignoresReturnValue() && fun->hasJitInfo()) {
506 const JSJitInfo* jitInfo = fun->jitInfo();
507 if (jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) {
508 native = jitInfo->ignoresReturnValueMethod;
509 }
510 }
511 return CallJSNative(cx, native, reason, args);
512 }
513
514 // Self-hosted builtins are considered native by the onNativeCall hook.
515 if (fun->isSelfHostedBuiltin()) {
516 NativeResumeMode resumeMode = DebugAPI::onNativeCall(cx, args, reason);
517 if (resumeMode != NativeResumeMode::Continue) {
518 return resumeMode == NativeResumeMode::Override;
519 }
520 }
521
522 if (!JSFunction::getOrCreateScript(cx, fun)) {
523 return false;
524 }
525
526 /* Run function until JSOp::RetRval, JSOp::Return or error. */
527 InvokeState state(cx, args, construct);
528
529 // Create |this| if we're constructing. Switch to the callee's realm to
530 // ensure this object has the correct realm.
531 AutoRealm ar(cx, state.script());
532 if (construct && !MaybeCreateThisForConstructor(cx, args)) {
533 return false;
534 }
535
536 // Calling class constructors throws an error from the callee's realm.
537 if (construct != CONSTRUCT && fun->isClassConstructor()) {
538 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
539 JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
540 return false;
541 }
542
543 bool ok = RunScript(cx, state);
544
545 MOZ_ASSERT_IF(ok && construct, args.rval().isObject());
546 return ok;
547 }
548
InternalCall(JSContext * cx,const AnyInvokeArgs & args,CallReason reason=CallReason::Call)549 static bool InternalCall(JSContext* cx, const AnyInvokeArgs& args,
550 CallReason reason = CallReason::Call) {
551 MOZ_ASSERT(args.array() + args.length() == args.end(),
552 "must pass calling arguments to a calling attempt");
553
554 if (args.thisv().isObject()) {
555 // We must call the thisValue hook in case we are not called from the
556 // interpreter, where a prior bytecode has computed an appropriate
557 // |this| already. But don't do that if fval is a DOM function.
558 HandleValue fval = args.calleev();
559 if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
560 !fval.toObject().as<JSFunction>().isNativeFun() ||
561 !fval.toObject().as<JSFunction>().hasJitInfo() ||
562 fval.toObject()
563 .as<JSFunction>()
564 .jitInfo()
565 ->needsOuterizedThisObject()) {
566 JSObject* thisObj = GetThisObject(&args.thisv().toObject());
567 args.mutableThisv().setObject(*thisObj);
568 }
569 }
570
571 return InternalCallOrConstruct(cx, args, NO_CONSTRUCT, reason);
572 }
573
CallFromStack(JSContext * cx,const CallArgs & args)574 bool js::CallFromStack(JSContext* cx, const CallArgs& args) {
575 return InternalCall(cx, static_cast<const AnyInvokeArgs&>(args));
576 }
577
578 // ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
579 // 7.3.12 Call.
Call(JSContext * cx,HandleValue fval,HandleValue thisv,const AnyInvokeArgs & args,MutableHandleValue rval,CallReason reason)580 bool js::Call(JSContext* cx, HandleValue fval, HandleValue thisv,
581 const AnyInvokeArgs& args, MutableHandleValue rval,
582 CallReason reason) {
583 // Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
584 // shadowing.
585 args.CallArgs::setCallee(fval);
586 args.CallArgs::setThis(thisv);
587
588 if (!InternalCall(cx, args, reason)) {
589 return false;
590 }
591
592 rval.set(args.rval());
593 return true;
594 }
595
InternalConstruct(JSContext * cx,const AnyConstructArgs & args)596 static bool InternalConstruct(JSContext* cx, const AnyConstructArgs& args) {
597 MOZ_ASSERT(args.array() + args.length() + 1 == args.end(),
598 "must pass constructing arguments to a construction attempt");
599 MOZ_ASSERT(!JSFunction::class_.getConstruct());
600
601 // Callers are responsible for enforcing these preconditions.
602 MOZ_ASSERT(IsConstructor(args.calleev()),
603 "trying to construct a value that isn't a constructor");
604 MOZ_ASSERT(IsConstructor(args.CallArgs::newTarget()),
605 "provided new.target value must be a constructor");
606
607 MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING) ||
608 args.thisv().isObject());
609
610 JSObject& callee = args.callee();
611 if (callee.is<JSFunction>()) {
612 RootedFunction fun(cx, &callee.as<JSFunction>());
613
614 if (fun->isNativeFun()) {
615 return CallJSNativeConstructor(cx, fun->native(), args);
616 }
617
618 if (!InternalCallOrConstruct(cx, args, CONSTRUCT)) {
619 return false;
620 }
621
622 MOZ_ASSERT(args.CallArgs::rval().isObject());
623 return true;
624 }
625
626 if (callee.is<ProxyObject>()) {
627 RootedObject proxy(cx, &callee);
628 return Proxy::construct(cx, proxy, args);
629 }
630
631 JSNative construct = callee.constructHook();
632 MOZ_ASSERT(construct != nullptr, "IsConstructor without a construct hook?");
633
634 return CallJSNativeConstructor(cx, construct, args);
635 }
636
637 // Check that |callee|, the callee in a |new| expression, is a constructor.
StackCheckIsConstructorCalleeNewTarget(JSContext * cx,HandleValue callee,HandleValue newTarget)638 static bool StackCheckIsConstructorCalleeNewTarget(JSContext* cx,
639 HandleValue callee,
640 HandleValue newTarget) {
641 // Calls from the stack could have any old non-constructor callee.
642 if (!IsConstructor(callee)) {
643 ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, callee,
644 nullptr);
645 return false;
646 }
647
648 // The new.target has already been vetted by previous calls, or is the callee.
649 // We can just assert that it's a constructor.
650 MOZ_ASSERT(IsConstructor(newTarget));
651
652 return true;
653 }
654
ConstructFromStack(JSContext * cx,const CallArgs & args)655 bool js::ConstructFromStack(JSContext* cx, const CallArgs& args) {
656 if (!StackCheckIsConstructorCalleeNewTarget(cx, args.calleev(),
657 args.newTarget())) {
658 return false;
659 }
660
661 return InternalConstruct(cx, static_cast<const AnyConstructArgs&>(args));
662 }
663
Construct(JSContext * cx,HandleValue fval,const AnyConstructArgs & args,HandleValue newTarget,MutableHandleObject objp)664 bool js::Construct(JSContext* cx, HandleValue fval,
665 const AnyConstructArgs& args, HandleValue newTarget,
666 MutableHandleObject objp) {
667 MOZ_ASSERT(args.thisv().isMagic(JS_IS_CONSTRUCTING));
668
669 // Explicitly qualify to bypass AnyConstructArgs's deliberate shadowing.
670 args.CallArgs::setCallee(fval);
671 args.CallArgs::newTarget().set(newTarget);
672
673 if (!InternalConstruct(cx, args)) {
674 return false;
675 }
676
677 MOZ_ASSERT(args.CallArgs::rval().isObject());
678 objp.set(&args.CallArgs::rval().toObject());
679 return true;
680 }
681
InternalConstructWithProvidedThis(JSContext * cx,HandleValue fval,HandleValue thisv,const AnyConstructArgs & args,HandleValue newTarget,MutableHandleValue rval)682 bool js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval,
683 HandleValue thisv,
684 const AnyConstructArgs& args,
685 HandleValue newTarget,
686 MutableHandleValue rval) {
687 args.CallArgs::setCallee(fval);
688
689 MOZ_ASSERT(thisv.isObject());
690 args.CallArgs::setThis(thisv);
691
692 args.CallArgs::newTarget().set(newTarget);
693
694 if (!InternalConstruct(cx, args)) {
695 return false;
696 }
697
698 rval.set(args.CallArgs::rval());
699 return true;
700 }
701
CallGetter(JSContext * cx,HandleValue thisv,HandleValue getter,MutableHandleValue rval)702 bool js::CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter,
703 MutableHandleValue rval) {
704 // Invoke could result in another try to get or set the same id again, see
705 // bug 355497.
706 AutoCheckRecursionLimit recursion(cx);
707 if (!recursion.check(cx)) {
708 return false;
709 }
710
711 FixedInvokeArgs<0> args(cx);
712
713 return Call(cx, getter, thisv, args, rval, CallReason::Getter);
714 }
715
CallSetter(JSContext * cx,HandleValue thisv,HandleValue setter,HandleValue v)716 bool js::CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter,
717 HandleValue v) {
718 AutoCheckRecursionLimit recursion(cx);
719 if (!recursion.check(cx)) {
720 return false;
721 }
722
723 FixedInvokeArgs<1> args(cx);
724
725 args[0].set(v);
726
727 RootedValue ignored(cx);
728 return Call(cx, setter, thisv, args, &ignored, CallReason::Setter);
729 }
730
ExecuteKernel(JSContext * cx,HandleScript script,HandleObject envChainArg,HandleValue newTargetValue,AbstractFramePtr evalInFrame,MutableHandleValue result)731 bool js::ExecuteKernel(JSContext* cx, HandleScript script,
732 HandleObject envChainArg, HandleValue newTargetValue,
733 AbstractFramePtr evalInFrame,
734 MutableHandleValue result) {
735 MOZ_ASSERT_IF(script->isGlobalCode(),
736 IsGlobalLexicalEnvironment(envChainArg) ||
737 !IsSyntacticEnvironment(envChainArg));
738 #ifdef DEBUG
739 RootedObject terminatingEnv(cx, envChainArg);
740 while (IsSyntacticEnvironment(terminatingEnv)) {
741 terminatingEnv = terminatingEnv->enclosingEnvironment();
742 }
743 MOZ_ASSERT(terminatingEnv->is<GlobalObject>() ||
744 script->hasNonSyntacticScope());
745 #endif
746
747 if (script->treatAsRunOnce()) {
748 if (script->hasRunOnce()) {
749 JS_ReportErrorASCII(cx,
750 "Trying to execute a run-once script multiple times");
751 return false;
752 }
753
754 script->setHasRunOnce();
755 }
756
757 if (script->isEmpty()) {
758 result.setUndefined();
759 return true;
760 }
761
762 probes::StartExecution(script);
763 ExecuteState state(cx, script, newTargetValue, envChainArg, evalInFrame,
764 result);
765 bool ok = RunScript(cx, state);
766 probes::StopExecution(script);
767
768 return ok;
769 }
770
Execute(JSContext * cx,HandleScript script,HandleObject envChain,MutableHandleValue rval)771 bool js::Execute(JSContext* cx, HandleScript script, HandleObject envChain,
772 MutableHandleValue rval) {
773 /* The env chain is something we control, so we know it can't
774 have any outer objects on it. */
775 MOZ_ASSERT(!IsWindowProxy(envChain));
776
777 if (script->isModule()) {
778 MOZ_RELEASE_ASSERT(
779 envChain == script->module()->environment(),
780 "Module scripts can only be executed in the module's environment");
781 } else {
782 MOZ_RELEASE_ASSERT(
783 IsGlobalLexicalEnvironment(envChain) || script->hasNonSyntacticScope(),
784 "Only global scripts with non-syntactic envs can be executed with "
785 "interesting envchains");
786 }
787
788 /* Ensure the env chain is all same-compartment and terminates in a global. */
789 #ifdef DEBUG
790 JSObject* s = envChain;
791 do {
792 cx->check(s);
793 MOZ_ASSERT_IF(!s->enclosingEnvironment(), s->is<GlobalObject>());
794 } while ((s = s->enclosingEnvironment()));
795 #endif
796
797 return ExecuteKernel(cx, script, envChain, NullHandleValue,
798 NullFramePtr() /* evalInFrame */, rval);
799 }
800
801 /*
802 * ES6 (4-25-16) 12.10.4 InstanceofOperator
803 */
InstanceofOperator(JSContext * cx,HandleObject obj,HandleValue v,bool * bp)804 extern bool JS::InstanceofOperator(JSContext* cx, HandleObject obj,
805 HandleValue v, bool* bp) {
806 /* Step 1. is handled by caller. */
807
808 /* Step 2. */
809 RootedValue hasInstance(cx);
810 RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().hasInstance));
811 if (!GetProperty(cx, obj, obj, id, &hasInstance)) {
812 return false;
813 }
814
815 if (!hasInstance.isNullOrUndefined()) {
816 if (!IsCallable(hasInstance)) {
817 return ReportIsNotFunction(cx, hasInstance);
818 }
819
820 /* Step 3. */
821 RootedValue rval(cx);
822 if (!Call(cx, hasInstance, obj, v, &rval)) {
823 return false;
824 }
825 *bp = ToBoolean(rval);
826 return true;
827 }
828
829 /* Step 4. */
830 if (!obj->isCallable()) {
831 RootedValue val(cx, ObjectValue(*obj));
832 return ReportIsNotFunction(cx, val);
833 }
834
835 /* Step 5. */
836 return OrdinaryHasInstance(cx, obj, v, bp);
837 }
838
HasInstance(JSContext * cx,HandleObject obj,HandleValue v,bool * bp)839 bool js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) {
840 const JSClass* clasp = obj->getClass();
841 RootedValue local(cx, v);
842 if (JSHasInstanceOp hasInstance = clasp->getHasInstance()) {
843 return hasInstance(cx, obj, &local, bp);
844 }
845 return JS::InstanceofOperator(cx, obj, local, bp);
846 }
847
TypeOfObject(JSObject * obj)848 JSType js::TypeOfObject(JSObject* obj) {
849 if (EmulatesUndefined(obj)) {
850 return JSTYPE_UNDEFINED;
851 }
852 if (obj->isCallable()) {
853 return JSTYPE_FUNCTION;
854 }
855 return JSTYPE_OBJECT;
856 }
857
TypeOfValue(const Value & v)858 JSType js::TypeOfValue(const Value& v) {
859 switch (v.type()) {
860 case ValueType::Double:
861 case ValueType::Int32:
862 return JSTYPE_NUMBER;
863 case ValueType::String:
864 return JSTYPE_STRING;
865 case ValueType::Null:
866 return JSTYPE_OBJECT;
867 case ValueType::Undefined:
868 return JSTYPE_UNDEFINED;
869 case ValueType::Object:
870 return TypeOfObject(&v.toObject());
871 case ValueType::Boolean:
872 return JSTYPE_BOOLEAN;
873 case ValueType::BigInt:
874 return JSTYPE_BIGINT;
875 case ValueType::Symbol:
876 return JSTYPE_SYMBOL;
877 case ValueType::Magic:
878 case ValueType::PrivateGCThing:
879 break;
880 }
881
882 ReportBadValueTypeAndCrash(v);
883 }
884
CheckClassHeritageOperation(JSContext * cx,HandleValue heritage)885 bool js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage) {
886 if (IsConstructor(heritage)) {
887 return true;
888 }
889
890 if (heritage.isNull()) {
891 return true;
892 }
893
894 if (heritage.isObject()) {
895 ReportIsNotFunction(cx, heritage, 0, CONSTRUCT);
896 return false;
897 }
898
899 ReportValueError(cx, JSMSG_BAD_HERITAGE, -1, heritage, nullptr,
900 "not an object or null");
901 return false;
902 }
903
ObjectWithProtoOperation(JSContext * cx,HandleValue val)904 PlainObject* js::ObjectWithProtoOperation(JSContext* cx, HandleValue val) {
905 if (!val.isObjectOrNull()) {
906 ReportValueError(cx, JSMSG_NOT_OBJORNULL, -1, val, nullptr);
907 return nullptr;
908 }
909
910 RootedObject proto(cx, val.toObjectOrNull());
911 return NewObjectWithGivenProto<PlainObject>(cx, proto);
912 }
913
FunWithProtoOperation(JSContext * cx,HandleFunction fun,HandleObject parent,HandleObject proto)914 JSObject* js::FunWithProtoOperation(JSContext* cx, HandleFunction fun,
915 HandleObject parent, HandleObject proto) {
916 return CloneFunctionObject(cx, fun, parent, proto);
917 }
918
919 /*
920 * Enter the new with environment using an object at sp[-1] and associate the
921 * depth of the with block with sp + stackIndex.
922 */
EnterWithOperation(JSContext * cx,AbstractFramePtr frame,HandleValue val,Handle<WithScope * > scope)923 bool js::EnterWithOperation(JSContext* cx, AbstractFramePtr frame,
924 HandleValue val, Handle<WithScope*> scope) {
925 RootedObject obj(cx);
926 if (val.isObject()) {
927 obj = &val.toObject();
928 } else {
929 obj = ToObject(cx, val);
930 if (!obj) {
931 return false;
932 }
933 }
934
935 RootedObject envChain(cx, frame.environmentChain());
936 WithEnvironmentObject* withobj =
937 WithEnvironmentObject::create(cx, obj, envChain, scope);
938 if (!withobj) {
939 return false;
940 }
941
942 frame.pushOnEnvironmentChain(*withobj);
943 return true;
944 }
945
PopEnvironment(JSContext * cx,EnvironmentIter & ei)946 static void PopEnvironment(JSContext* cx, EnvironmentIter& ei) {
947 switch (ei.scope().kind()) {
948 case ScopeKind::Lexical:
949 case ScopeKind::SimpleCatch:
950 case ScopeKind::Catch:
951 case ScopeKind::NamedLambda:
952 case ScopeKind::StrictNamedLambda:
953 case ScopeKind::FunctionLexical:
954 case ScopeKind::ClassBody:
955 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
956 DebugEnvironments::onPopLexical(cx, ei);
957 }
958 if (ei.scope().hasEnvironment()) {
959 ei.initialFrame()
960 .popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
961 }
962 break;
963 case ScopeKind::With:
964 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
965 DebugEnvironments::onPopWith(ei.initialFrame());
966 }
967 ei.initialFrame().popOffEnvironmentChain<WithEnvironmentObject>();
968 break;
969 case ScopeKind::Function:
970 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
971 DebugEnvironments::onPopCall(cx, ei.initialFrame());
972 }
973 if (ei.scope().hasEnvironment()) {
974 ei.initialFrame().popOffEnvironmentChain<CallObject>();
975 }
976 break;
977 case ScopeKind::FunctionBodyVar:
978 case ScopeKind::StrictEval:
979 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
980 DebugEnvironments::onPopVar(cx, ei);
981 }
982 if (ei.scope().hasEnvironment()) {
983 ei.initialFrame().popOffEnvironmentChain<VarEnvironmentObject>();
984 }
985 break;
986 case ScopeKind::Module:
987 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
988 DebugEnvironments::onPopModule(cx, ei);
989 }
990 break;
991 case ScopeKind::Eval:
992 case ScopeKind::Global:
993 case ScopeKind::NonSyntactic:
994 break;
995 case ScopeKind::WasmInstance:
996 case ScopeKind::WasmFunction:
997 MOZ_CRASH("wasm is not interpreted");
998 break;
999 }
1000 }
1001
1002 // Unwind environment chain and iterator to match the env corresponding to
1003 // the given bytecode position.
UnwindEnvironment(JSContext * cx,EnvironmentIter & ei,jsbytecode * pc)1004 void js::UnwindEnvironment(JSContext* cx, EnvironmentIter& ei, jsbytecode* pc) {
1005 if (!ei.withinInitialFrame()) {
1006 return;
1007 }
1008
1009 RootedScope scope(cx, ei.initialFrame().script()->innermostScope(pc));
1010
1011 #ifdef DEBUG
1012 // A frame's environment chain cannot be unwound to anything enclosing the
1013 // body scope of a script. This includes the parameter defaults
1014 // environment and the decl env object. These environments, once pushed
1015 // onto the environment chain, are expected to be there for the duration
1016 // of the frame.
1017 //
1018 // Attempting to unwind to the parameter defaults code in a script is a
1019 // bug; that section of code has no try-catch blocks.
1020 JSScript* script = ei.initialFrame().script();
1021 for (uint32_t i = 0; i < script->bodyScopeIndex(); i++) {
1022 MOZ_ASSERT(scope != script->getScope(GCThingIndex(i)));
1023 }
1024 #endif
1025
1026 for (; ei.maybeScope() != scope; ei++) {
1027 PopEnvironment(cx, ei);
1028 }
1029 }
1030
1031 // Unwind all environments. This is needed because block scopes may cover the
1032 // first bytecode at a script's main(). e.g.,
1033 //
1034 // function f() { { let i = 0; } }
1035 //
1036 // will have no pc location distinguishing the first block scope from the
1037 // outermost function scope.
UnwindAllEnvironmentsInFrame(JSContext * cx,EnvironmentIter & ei)1038 void js::UnwindAllEnvironmentsInFrame(JSContext* cx, EnvironmentIter& ei) {
1039 for (; ei.withinInitialFrame(); ei++) {
1040 PopEnvironment(cx, ei);
1041 }
1042 }
1043
1044 // Compute the pc needed to unwind the environment to the beginning of a try
1045 // block. We cannot unwind to *after* the JSOp::Try, because that might be the
1046 // first opcode of an inner scope, with the same problem as above. e.g.,
1047 //
1048 // try { { let x; } }
1049 //
1050 // will have no pc location distinguishing the try block scope from the inner
1051 // let block scope.
UnwindEnvironmentToTryPc(JSScript * script,const TryNote * tn)1052 jsbytecode* js::UnwindEnvironmentToTryPc(JSScript* script, const TryNote* tn) {
1053 jsbytecode* pc = script->offsetToPC(tn->start);
1054 if (tn->kind() == TryNoteKind::Catch || tn->kind() == TryNoteKind::Finally) {
1055 pc -= JSOpLength_Try;
1056 MOZ_ASSERT(JSOp(*pc) == JSOp::Try);
1057 } else if (tn->kind() == TryNoteKind::Destructuring) {
1058 pc -= JSOpLength_TryDestructuring;
1059 MOZ_ASSERT(JSOp(*pc) == JSOp::TryDestructuring);
1060 }
1061 return pc;
1062 }
1063
SettleOnTryNote(JSContext * cx,const TryNote * tn,EnvironmentIter & ei,InterpreterRegs & regs)1064 static void SettleOnTryNote(JSContext* cx, const TryNote* tn,
1065 EnvironmentIter& ei, InterpreterRegs& regs) {
1066 // Unwind the environment to the beginning of the JSOp::Try.
1067 UnwindEnvironment(cx, ei, UnwindEnvironmentToTryPc(regs.fp()->script(), tn));
1068
1069 // Set pc to the first bytecode after the the try note to point
1070 // to the beginning of catch or finally.
1071 regs.pc = regs.fp()->script()->offsetToPC(tn->start + tn->length);
1072 regs.sp = regs.spForStackDepth(tn->stackDepth);
1073 }
1074
1075 class InterpreterTryNoteFilter {
1076 const InterpreterRegs& regs_;
1077
1078 public:
InterpreterTryNoteFilter(const InterpreterRegs & regs)1079 explicit InterpreterTryNoteFilter(const InterpreterRegs& regs)
1080 : regs_(regs) {}
operator ()(const TryNote * note)1081 bool operator()(const TryNote* note) {
1082 return note->stackDepth <= regs_.stackDepth();
1083 }
1084 };
1085
1086 class TryNoteIterInterpreter : public TryNoteIter<InterpreterTryNoteFilter> {
1087 public:
TryNoteIterInterpreter(JSContext * cx,const InterpreterRegs & regs)1088 TryNoteIterInterpreter(JSContext* cx, const InterpreterRegs& regs)
1089 : TryNoteIter(cx, regs.fp()->script(), regs.pc,
1090 InterpreterTryNoteFilter(regs)) {}
1091 };
1092
UnwindIteratorsForUncatchableException(JSContext * cx,const InterpreterRegs & regs)1093 static void UnwindIteratorsForUncatchableException(
1094 JSContext* cx, const InterpreterRegs& regs) {
1095 // c.f. the regular (catchable) TryNoteIterInterpreter loop in
1096 // ProcessTryNotes.
1097 for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
1098 const TryNote* tn = *tni;
1099 switch (tn->kind()) {
1100 case TryNoteKind::ForIn: {
1101 Value* sp = regs.spForStackDepth(tn->stackDepth);
1102 UnwindIteratorForUncatchableException(&sp[-1].toObject());
1103 break;
1104 }
1105 default:
1106 break;
1107 }
1108 }
1109 }
1110
1111 enum HandleErrorContinuation {
1112 SuccessfulReturnContinuation,
1113 ErrorReturnContinuation,
1114 CatchContinuation,
1115 FinallyContinuation
1116 };
1117
ProcessTryNotes(JSContext * cx,EnvironmentIter & ei,InterpreterRegs & regs)1118 static HandleErrorContinuation ProcessTryNotes(JSContext* cx,
1119 EnvironmentIter& ei,
1120 InterpreterRegs& regs) {
1121 for (TryNoteIterInterpreter tni(cx, regs); !tni.done(); ++tni) {
1122 const TryNote* tn = *tni;
1123
1124 switch (tn->kind()) {
1125 case TryNoteKind::Catch:
1126 /* Catch cannot intercept the closing of a generator. */
1127 if (cx->isClosingGenerator()) {
1128 break;
1129 }
1130
1131 SettleOnTryNote(cx, tn, ei, regs);
1132 return CatchContinuation;
1133
1134 case TryNoteKind::Finally:
1135 SettleOnTryNote(cx, tn, ei, regs);
1136 return FinallyContinuation;
1137
1138 case TryNoteKind::ForIn: {
1139 /* This is similar to JSOp::EndIter in the interpreter loop. */
1140 MOZ_ASSERT(tn->stackDepth <= regs.stackDepth());
1141 Value* sp = regs.spForStackDepth(tn->stackDepth);
1142 JSObject* obj = &sp[-1].toObject();
1143 CloseIterator(obj);
1144 break;
1145 }
1146
1147 case TryNoteKind::Destructuring: {
1148 // Whether the destructuring iterator is done is at the top of the
1149 // stack. The iterator object is second from the top.
1150 MOZ_ASSERT(tn->stackDepth > 1);
1151 Value* sp = regs.spForStackDepth(tn->stackDepth);
1152 RootedValue doneValue(cx, sp[-1]);
1153 MOZ_RELEASE_ASSERT(!doneValue.isMagic());
1154 bool done = ToBoolean(doneValue);
1155 if (!done) {
1156 RootedObject iterObject(cx, &sp[-2].toObject());
1157 if (!IteratorCloseForException(cx, iterObject)) {
1158 SettleOnTryNote(cx, tn, ei, regs);
1159 return ErrorReturnContinuation;
1160 }
1161 }
1162 break;
1163 }
1164
1165 case TryNoteKind::ForOf:
1166 case TryNoteKind::Loop:
1167 break;
1168
1169 // TryNoteKind::ForOfIterClose is handled internally by the try note
1170 // iterator.
1171 default:
1172 MOZ_CRASH("Invalid try note");
1173 }
1174 }
1175
1176 return SuccessfulReturnContinuation;
1177 }
1178
HandleClosingGeneratorReturn(JSContext * cx,AbstractFramePtr frame,bool ok)1179 bool js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
1180 bool ok) {
1181 /*
1182 * Propagate the exception or error to the caller unless the exception
1183 * is an asynchronous return from a generator.
1184 */
1185 if (cx->isClosingGenerator()) {
1186 cx->clearPendingException();
1187 ok = true;
1188 auto* genObj = GetGeneratorObjectForFrame(cx, frame);
1189 genObj->setClosed();
1190 }
1191 return ok;
1192 }
1193
HandleError(JSContext * cx,InterpreterRegs & regs)1194 static HandleErrorContinuation HandleError(JSContext* cx,
1195 InterpreterRegs& regs) {
1196 MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
1197 MOZ_ASSERT(cx->realm() == regs.fp()->script()->realm());
1198
1199 if (regs.fp()->script()->hasScriptCounts()) {
1200 PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
1201 // If we failed to allocate, then skip the increment and continue to
1202 // handle the exception.
1203 if (counts) {
1204 counts->numExec()++;
1205 }
1206 }
1207
1208 EnvironmentIter ei(cx, regs.fp(), regs.pc);
1209 bool ok = false;
1210
1211 again:
1212 if (cx->isExceptionPending()) {
1213 /* Call debugger throw hooks. */
1214 if (!cx->isClosingGenerator()) {
1215 if (!DebugAPI::onExceptionUnwind(cx, regs.fp())) {
1216 if (!cx->isExceptionPending()) {
1217 goto again;
1218 }
1219 }
1220 // Ensure that the debugger hasn't returned 'true' while clearing the
1221 // exception state.
1222 MOZ_ASSERT(cx->isExceptionPending());
1223 }
1224
1225 HandleErrorContinuation res = ProcessTryNotes(cx, ei, regs);
1226 switch (res) {
1227 case SuccessfulReturnContinuation:
1228 break;
1229 case ErrorReturnContinuation:
1230 goto again;
1231 case CatchContinuation:
1232 case FinallyContinuation:
1233 // No need to increment the PCCounts number of execution here, as
1234 // the interpreter increments any PCCounts if present.
1235 MOZ_ASSERT_IF(regs.fp()->script()->hasScriptCounts(),
1236 regs.fp()->script()->maybeGetPCCounts(regs.pc));
1237 return res;
1238 }
1239
1240 ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
1241 } else {
1242 UnwindIteratorsForUncatchableException(cx, regs);
1243
1244 // We may be propagating a forced return from a debugger hook function.
1245 if (MOZ_UNLIKELY(cx->isPropagatingForcedReturn())) {
1246 cx->clearPropagatingForcedReturn();
1247 ok = true;
1248 }
1249 }
1250
1251 ok = DebugAPI::onLeaveFrame(cx, regs.fp(), regs.pc, ok);
1252
1253 // After this point, we will pop the frame regardless. Settle the frame on
1254 // the end of the script.
1255 regs.setToEndOfScript();
1256
1257 return ok ? SuccessfulReturnContinuation : ErrorReturnContinuation;
1258 }
1259
1260 #define REGS (activation.regs())
1261 #define PUSH_COPY(v) \
1262 do { \
1263 *REGS.sp++ = (v); \
1264 cx->debugOnlyCheck(REGS.sp[-1]); \
1265 } while (0)
1266 #define PUSH_COPY_SKIP_CHECK(v) *REGS.sp++ = (v)
1267 #define PUSH_NULL() REGS.sp++->setNull()
1268 #define PUSH_UNDEFINED() REGS.sp++->setUndefined()
1269 #define PUSH_BOOLEAN(b) REGS.sp++->setBoolean(b)
1270 #define PUSH_DOUBLE(d) REGS.sp++->setDouble(d)
1271 #define PUSH_INT32(i) REGS.sp++->setInt32(i)
1272 #define PUSH_SYMBOL(s) REGS.sp++->setSymbol(s)
1273 #define PUSH_BIGINT(b) REGS.sp++->setBigInt(b)
1274 #define PUSH_STRING(s) \
1275 do { \
1276 REGS.sp++->setString(s); \
1277 cx->debugOnlyCheck(REGS.sp[-1]); \
1278 } while (0)
1279 #define PUSH_OBJECT(obj) \
1280 do { \
1281 REGS.sp++->setObject(obj); \
1282 cx->debugOnlyCheck(REGS.sp[-1]); \
1283 } while (0)
1284 #define PUSH_OBJECT_OR_NULL(obj) \
1285 do { \
1286 REGS.sp++->setObjectOrNull(obj); \
1287 cx->debugOnlyCheck(REGS.sp[-1]); \
1288 } while (0)
1289 #define PUSH_MAGIC(magic) REGS.sp++->setMagic(magic)
1290 #define POP_COPY_TO(v) (v) = *--REGS.sp
1291 #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp)
1292
1293 /*
1294 * Same for JSOp::SetName and JSOp::SetProp, which differ only slightly but
1295 * remain distinct for the decompiler.
1296 */
1297 static_assert(JSOpLength_SetName == JSOpLength_SetProp);
1298
1299 /* See TRY_BRANCH_AFTER_COND. */
1300 static_assert(JSOpLength_JumpIfTrue == JSOpLength_JumpIfFalse);
1301 static_assert(uint8_t(JSOp::JumpIfTrue) == uint8_t(JSOp::JumpIfFalse) + 1);
1302
1303 /*
1304 * Compute the implicit |this| value used by a call expression with an
1305 * unqualified name reference. The environment the binding was found on is
1306 * passed as argument, env.
1307 *
1308 * The implicit |this| is |undefined| for all environment types except
1309 * WithEnvironmentObject. This is the case for |with(...) {...}| expressions or
1310 * if the embedding uses a non-syntactic WithEnvironmentObject.
1311 *
1312 * NOTE: A non-syntactic WithEnvironmentObject may have a corresponding
1313 * extensible LexicalEnviornmentObject, but it will not be considered as an
1314 * implicit |this|. This is for compatibility with the Gecko subscript loader.
1315 */
ComputeImplicitThis(JSObject * env)1316 static inline Value ComputeImplicitThis(JSObject* env) {
1317 // Fast-path for GlobalObject
1318 if (env->is<GlobalObject>()) {
1319 return UndefinedValue();
1320 }
1321
1322 // WithEnvironmentObjects have an actual implicit |this|
1323 if (env->is<WithEnvironmentObject>()) {
1324 return ObjectValue(*GetThisObjectOfWith(env));
1325 }
1326
1327 // Debugger environments need special casing, as despite being
1328 // non-syntactic, they wrap syntactic environments and should not be
1329 // treated like other embedding-specific non-syntactic environments.
1330 if (env->is<DebugEnvironmentProxy>()) {
1331 return ComputeImplicitThis(&env->as<DebugEnvironmentProxy>().environment());
1332 }
1333
1334 MOZ_ASSERT(env->is<EnvironmentObject>());
1335 return UndefinedValue();
1336 }
1337
AddOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1338 static MOZ_ALWAYS_INLINE bool AddOperation(JSContext* cx,
1339 MutableHandleValue lhs,
1340 MutableHandleValue rhs,
1341 MutableHandleValue res) {
1342 if (lhs.isInt32() && rhs.isInt32()) {
1343 int32_t l = lhs.toInt32(), r = rhs.toInt32();
1344 int32_t t;
1345 if (MOZ_LIKELY(SafeAdd(l, r, &t))) {
1346 res.setInt32(t);
1347 return true;
1348 }
1349 }
1350
1351 if (!ToPrimitive(cx, lhs)) {
1352 return false;
1353 }
1354 if (!ToPrimitive(cx, rhs)) {
1355 return false;
1356 }
1357
1358 bool lIsString = lhs.isString();
1359 bool rIsString = rhs.isString();
1360 if (lIsString || rIsString) {
1361 JSString* lstr;
1362 if (lIsString) {
1363 lstr = lhs.toString();
1364 } else {
1365 lstr = ToString<CanGC>(cx, lhs);
1366 if (!lstr) {
1367 return false;
1368 }
1369 }
1370
1371 JSString* rstr;
1372 if (rIsString) {
1373 rstr = rhs.toString();
1374 } else {
1375 // Save/restore lstr in case of GC activity under ToString.
1376 lhs.setString(lstr);
1377 rstr = ToString<CanGC>(cx, rhs);
1378 if (!rstr) {
1379 return false;
1380 }
1381 lstr = lhs.toString();
1382 }
1383 JSString* str = ConcatStrings<NoGC>(cx, lstr, rstr);
1384 if (!str) {
1385 RootedString nlstr(cx, lstr), nrstr(cx, rstr);
1386 str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
1387 if (!str) {
1388 return false;
1389 }
1390 }
1391 res.setString(str);
1392 return true;
1393 }
1394
1395 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1396 return false;
1397 }
1398
1399 if (lhs.isBigInt() || rhs.isBigInt()) {
1400 return BigInt::addValue(cx, lhs, rhs, res);
1401 }
1402
1403 res.setNumber(lhs.toNumber() + rhs.toNumber());
1404 return true;
1405 }
1406
SubOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1407 static MOZ_ALWAYS_INLINE bool SubOperation(JSContext* cx,
1408 MutableHandleValue lhs,
1409 MutableHandleValue rhs,
1410 MutableHandleValue res) {
1411 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1412 return false;
1413 }
1414
1415 if (lhs.isBigInt() || rhs.isBigInt()) {
1416 return BigInt::subValue(cx, lhs, rhs, res);
1417 }
1418
1419 res.setNumber(lhs.toNumber() - rhs.toNumber());
1420 return true;
1421 }
1422
MulOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1423 static MOZ_ALWAYS_INLINE bool MulOperation(JSContext* cx,
1424 MutableHandleValue lhs,
1425 MutableHandleValue rhs,
1426 MutableHandleValue res) {
1427 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1428 return false;
1429 }
1430
1431 if (lhs.isBigInt() || rhs.isBigInt()) {
1432 return BigInt::mulValue(cx, lhs, rhs, res);
1433 }
1434
1435 res.setNumber(lhs.toNumber() * rhs.toNumber());
1436 return true;
1437 }
1438
DivOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1439 static MOZ_ALWAYS_INLINE bool DivOperation(JSContext* cx,
1440 MutableHandleValue lhs,
1441 MutableHandleValue rhs,
1442 MutableHandleValue res) {
1443 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1444 return false;
1445 }
1446
1447 if (lhs.isBigInt() || rhs.isBigInt()) {
1448 return BigInt::divValue(cx, lhs, rhs, res);
1449 }
1450
1451 res.setNumber(NumberDiv(lhs.toNumber(), rhs.toNumber()));
1452 return true;
1453 }
1454
ModOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1455 static MOZ_ALWAYS_INLINE bool ModOperation(JSContext* cx,
1456 MutableHandleValue lhs,
1457 MutableHandleValue rhs,
1458 MutableHandleValue res) {
1459 int32_t l, r;
1460 if (lhs.isInt32() && rhs.isInt32() && (l = lhs.toInt32()) >= 0 &&
1461 (r = rhs.toInt32()) > 0) {
1462 int32_t mod = l % r;
1463 res.setInt32(mod);
1464 return true;
1465 }
1466
1467 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1468 return false;
1469 }
1470
1471 if (lhs.isBigInt() || rhs.isBigInt()) {
1472 return BigInt::modValue(cx, lhs, rhs, res);
1473 }
1474
1475 res.setNumber(NumberMod(lhs.toNumber(), rhs.toNumber()));
1476 return true;
1477 }
1478
PowOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)1479 static MOZ_ALWAYS_INLINE bool PowOperation(JSContext* cx,
1480 MutableHandleValue lhs,
1481 MutableHandleValue rhs,
1482 MutableHandleValue res) {
1483 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1484 return false;
1485 }
1486
1487 if (lhs.isBigInt() || rhs.isBigInt()) {
1488 return BigInt::powValue(cx, lhs, rhs, res);
1489 }
1490
1491 res.setNumber(ecmaPow(lhs.toNumber(), rhs.toNumber()));
1492 return true;
1493 }
1494
BitNotOperation(JSContext * cx,MutableHandleValue in,MutableHandleValue out)1495 static MOZ_ALWAYS_INLINE bool BitNotOperation(JSContext* cx,
1496 MutableHandleValue in,
1497 MutableHandleValue out) {
1498 if (!ToInt32OrBigInt(cx, in)) {
1499 return false;
1500 }
1501
1502 if (in.isBigInt()) {
1503 return BigInt::bitNotValue(cx, in, out);
1504 }
1505
1506 out.setInt32(~in.toInt32());
1507 return true;
1508 }
1509
BitXorOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1510 static MOZ_ALWAYS_INLINE bool BitXorOperation(JSContext* cx,
1511 MutableHandleValue lhs,
1512 MutableHandleValue rhs,
1513 MutableHandleValue out) {
1514 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1515 return false;
1516 }
1517
1518 if (lhs.isBigInt() || rhs.isBigInt()) {
1519 return BigInt::bitXorValue(cx, lhs, rhs, out);
1520 }
1521
1522 out.setInt32(lhs.toInt32() ^ rhs.toInt32());
1523 return true;
1524 }
1525
BitOrOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1526 static MOZ_ALWAYS_INLINE bool BitOrOperation(JSContext* cx,
1527 MutableHandleValue lhs,
1528 MutableHandleValue rhs,
1529 MutableHandleValue out) {
1530 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1531 return false;
1532 }
1533
1534 if (lhs.isBigInt() || rhs.isBigInt()) {
1535 return BigInt::bitOrValue(cx, lhs, rhs, out);
1536 }
1537
1538 out.setInt32(lhs.toInt32() | rhs.toInt32());
1539 return true;
1540 }
1541
BitAndOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1542 static MOZ_ALWAYS_INLINE bool BitAndOperation(JSContext* cx,
1543 MutableHandleValue lhs,
1544 MutableHandleValue rhs,
1545 MutableHandleValue out) {
1546 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1547 return false;
1548 }
1549
1550 if (lhs.isBigInt() || rhs.isBigInt()) {
1551 return BigInt::bitAndValue(cx, lhs, rhs, out);
1552 }
1553
1554 out.setInt32(lhs.toInt32() & rhs.toInt32());
1555 return true;
1556 }
1557
BitLshOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1558 static MOZ_ALWAYS_INLINE bool BitLshOperation(JSContext* cx,
1559 MutableHandleValue lhs,
1560 MutableHandleValue rhs,
1561 MutableHandleValue out) {
1562 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1563 return false;
1564 }
1565
1566 if (lhs.isBigInt() || rhs.isBigInt()) {
1567 return BigInt::lshValue(cx, lhs, rhs, out);
1568 }
1569
1570 // Signed left-shift is undefined on overflow, so |lhs << (rhs & 31)| won't
1571 // work. Instead, convert to unsigned space (where overflow is treated
1572 // modularly), perform the operation there, then convert back.
1573 uint32_t left = static_cast<uint32_t>(lhs.toInt32());
1574 uint8_t right = rhs.toInt32() & 31;
1575 out.setInt32(mozilla::WrapToSigned(left << right));
1576 return true;
1577 }
1578
BitRshOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1579 static MOZ_ALWAYS_INLINE bool BitRshOperation(JSContext* cx,
1580 MutableHandleValue lhs,
1581 MutableHandleValue rhs,
1582 MutableHandleValue out) {
1583 if (!ToInt32OrBigInt(cx, lhs) || !ToInt32OrBigInt(cx, rhs)) {
1584 return false;
1585 }
1586
1587 if (lhs.isBigInt() || rhs.isBigInt()) {
1588 return BigInt::rshValue(cx, lhs, rhs, out);
1589 }
1590
1591 out.setInt32(lhs.toInt32() >> (rhs.toInt32() & 31));
1592 return true;
1593 }
1594
UrshOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue out)1595 static MOZ_ALWAYS_INLINE bool UrshOperation(JSContext* cx,
1596 MutableHandleValue lhs,
1597 MutableHandleValue rhs,
1598 MutableHandleValue out) {
1599 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1600 return false;
1601 }
1602
1603 if (lhs.isBigInt() || rhs.isBigInt()) {
1604 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1605 JSMSG_BIGINT_TO_NUMBER);
1606 return false;
1607 }
1608
1609 uint32_t left;
1610 int32_t right;
1611 if (!ToUint32(cx, lhs, &left) || !ToInt32(cx, rhs, &right)) {
1612 return false;
1613 }
1614 left >>= right & 31;
1615 out.setNumber(uint32_t(left));
1616 return true;
1617 }
1618
1619 // BigInt proposal 3.2.4 Abstract Relational Comparison
1620 // Returns Nothing when at least one operand is a NaN, or when
1621 // ToNumeric or StringToBigInt can't interpret a string as a numeric
1622 // value. (These cases correspond to a NaN result in the spec.)
1623 // Otherwise, return a boolean to indicate whether lhs is less than
1624 // rhs. The operands must be primitives; the caller is responsible for
1625 // evaluating them in the correct order.
LessThanImpl(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,mozilla::Maybe<bool> & res)1626 static MOZ_ALWAYS_INLINE bool LessThanImpl(JSContext* cx,
1627 MutableHandleValue lhs,
1628 MutableHandleValue rhs,
1629 mozilla::Maybe<bool>& res) {
1630 // Steps 1 and 2 are performed by the caller.
1631
1632 // Step 3.
1633 if (lhs.isString() && rhs.isString()) {
1634 JSString* l = lhs.toString();
1635 JSString* r = rhs.toString();
1636 int32_t result;
1637 if (!CompareStrings(cx, l, r, &result)) {
1638 return false;
1639 }
1640 res = mozilla::Some(result < 0);
1641 return true;
1642 }
1643
1644 // Step 4a.
1645 if (lhs.isBigInt() && rhs.isString()) {
1646 return BigInt::lessThan(cx, lhs, rhs, res);
1647 }
1648
1649 // Step 4b.
1650 if (lhs.isString() && rhs.isBigInt()) {
1651 return BigInt::lessThan(cx, lhs, rhs, res);
1652 }
1653
1654 // Steps 4c and 4d.
1655 if (!ToNumeric(cx, lhs) || !ToNumeric(cx, rhs)) {
1656 return false;
1657 }
1658
1659 // Steps 4e-j.
1660 if (lhs.isBigInt() || rhs.isBigInt()) {
1661 return BigInt::lessThan(cx, lhs, rhs, res);
1662 }
1663
1664 // Step 4e for Number operands.
1665 MOZ_ASSERT(lhs.isNumber() && rhs.isNumber());
1666 double lhsNum = lhs.toNumber();
1667 double rhsNum = rhs.toNumber();
1668
1669 if (mozilla::IsNaN(lhsNum) || mozilla::IsNaN(rhsNum)) {
1670 res = mozilla::Maybe<bool>(mozilla::Nothing());
1671 return true;
1672 }
1673
1674 res = mozilla::Some(lhsNum < rhsNum);
1675 return true;
1676 }
1677
LessThanOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1678 static MOZ_ALWAYS_INLINE bool LessThanOperation(JSContext* cx,
1679 MutableHandleValue lhs,
1680 MutableHandleValue rhs,
1681 bool* res) {
1682 if (lhs.isInt32() && rhs.isInt32()) {
1683 *res = lhs.toInt32() < rhs.toInt32();
1684 return true;
1685 }
1686
1687 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1688 return false;
1689 }
1690
1691 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1692 return false;
1693 }
1694
1695 mozilla::Maybe<bool> tmpResult;
1696 if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1697 return false;
1698 }
1699 *res = tmpResult.valueOr(false);
1700 return true;
1701 }
1702
LessThanOrEqualOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1703 static MOZ_ALWAYS_INLINE bool LessThanOrEqualOperation(JSContext* cx,
1704 MutableHandleValue lhs,
1705 MutableHandleValue rhs,
1706 bool* res) {
1707 if (lhs.isInt32() && rhs.isInt32()) {
1708 *res = lhs.toInt32() <= rhs.toInt32();
1709 return true;
1710 }
1711
1712 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1713 return false;
1714 }
1715
1716 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1717 return false;
1718 }
1719
1720 mozilla::Maybe<bool> tmpResult;
1721 if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1722 return false;
1723 }
1724 *res = !tmpResult.valueOr(true);
1725 return true;
1726 }
1727
GreaterThanOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1728 static MOZ_ALWAYS_INLINE bool GreaterThanOperation(JSContext* cx,
1729 MutableHandleValue lhs,
1730 MutableHandleValue rhs,
1731 bool* res) {
1732 if (lhs.isInt32() && rhs.isInt32()) {
1733 *res = lhs.toInt32() > rhs.toInt32();
1734 return true;
1735 }
1736
1737 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1738 return false;
1739 }
1740
1741 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1742 return false;
1743 }
1744
1745 mozilla::Maybe<bool> tmpResult;
1746 if (!LessThanImpl(cx, rhs, lhs, tmpResult)) {
1747 return false;
1748 }
1749 *res = tmpResult.valueOr(false);
1750 return true;
1751 }
1752
GreaterThanOrEqualOperation(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)1753 static MOZ_ALWAYS_INLINE bool GreaterThanOrEqualOperation(
1754 JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs, bool* res) {
1755 if (lhs.isInt32() && rhs.isInt32()) {
1756 *res = lhs.toInt32() >= rhs.toInt32();
1757 return true;
1758 }
1759
1760 if (!ToPrimitive(cx, JSTYPE_NUMBER, lhs)) {
1761 return false;
1762 }
1763
1764 if (!ToPrimitive(cx, JSTYPE_NUMBER, rhs)) {
1765 return false;
1766 }
1767
1768 mozilla::Maybe<bool> tmpResult;
1769 if (!LessThanImpl(cx, lhs, rhs, tmpResult)) {
1770 return false;
1771 }
1772 *res = !tmpResult.valueOr(true);
1773 return true;
1774 }
1775
SetObjectElementOperation(JSContext * cx,HandleObject obj,HandleId id,HandleValue value,HandleValue receiver,bool strict)1776 static MOZ_ALWAYS_INLINE bool SetObjectElementOperation(
1777 JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
1778 HandleValue receiver, bool strict) {
1779 ObjectOpResult result;
1780 return SetProperty(cx, obj, id, value, receiver, result) &&
1781 result.checkStrictModeError(cx, obj, id, strict);
1782 }
1783
InitElemArrayOperation(JSContext * cx,jsbytecode * pc,HandleArrayObject arr,HandleValue val)1784 static MOZ_ALWAYS_INLINE void InitElemArrayOperation(JSContext* cx,
1785 jsbytecode* pc,
1786 HandleArrayObject arr,
1787 HandleValue val) {
1788 MOZ_ASSERT(JSOp(*pc) == JSOp::InitElemArray);
1789
1790 // The dense elements must have been initialized up to this index. The JIT
1791 // implementation also depends on this.
1792 uint32_t index = GET_UINT32(pc);
1793 MOZ_ASSERT(index < arr->getDenseCapacity());
1794 MOZ_ASSERT(index == arr->getDenseInitializedLength());
1795
1796 // Bump the initialized length even for hole values to ensure the
1797 // index == initLength invariant holds for later InitElemArray ops.
1798 arr->setDenseInitializedLength(index + 1);
1799
1800 if (val.isMagic(JS_ELEMENTS_HOLE)) {
1801 arr->initDenseElementHole(index);
1802 } else {
1803 arr->initDenseElement(index, val);
1804 }
1805 }
1806
1807 /*
1808 * As an optimization, the interpreter creates a handful of reserved Rooted<T>
1809 * variables at the beginning, thus inserting them into the Rooted list once
1810 * upon entry. ReservedRooted "borrows" a reserved Rooted variable and uses it
1811 * within a local scope, resetting the value to nullptr (or the appropriate
1812 * equivalent for T) at scope end. This avoids inserting/removing the Rooted
1813 * from the rooter list, while preventing stale values from being kept alive
1814 * unnecessarily.
1815 */
1816
1817 template <typename T>
1818 class ReservedRooted : public RootedBase<T, ReservedRooted<T>> {
1819 Rooted<T>* savedRoot;
1820
1821 public:
ReservedRooted(Rooted<T> * root,const T & ptr)1822 ReservedRooted(Rooted<T>* root, const T& ptr) : savedRoot(root) {
1823 *root = ptr;
1824 }
1825
ReservedRooted(Rooted<T> * root)1826 explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
1827 *root = JS::SafelyInitialized<T>();
1828 }
1829
~ReservedRooted()1830 ~ReservedRooted() { *savedRoot = JS::SafelyInitialized<T>(); }
1831
set(const T & p) const1832 void set(const T& p) const { *savedRoot = p; }
operator Handle<T>()1833 operator Handle<T>() { return *savedRoot; }
operator Rooted<T>&()1834 operator Rooted<T>&() { return *savedRoot; }
operator &()1835 MutableHandle<T> operator&() { return &*savedRoot; }
1836
1837 DECLARE_NONPOINTER_ACCESSOR_METHODS(savedRoot->get())
1838 DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(savedRoot->get())
1839 DECLARE_POINTER_CONSTREF_OPS(T)
1840 DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
1841 };
1842
ReportInNotObjectError(JSContext * cx,HandleValue lref,HandleValue rref)1843 void js::ReportInNotObjectError(JSContext* cx, HandleValue lref,
1844 HandleValue rref) {
1845 auto uniqueCharsFromString = [](JSContext* cx,
1846 HandleValue ref) -> UniqueChars {
1847 static const size_t MaxStringLength = 16;
1848 RootedString str(cx, ref.toString());
1849 if (str->length() > MaxStringLength) {
1850 JSStringBuilder buf(cx);
1851 if (!buf.appendSubstring(str, 0, MaxStringLength)) {
1852 return nullptr;
1853 }
1854 if (!buf.append("...")) {
1855 return nullptr;
1856 }
1857 str = buf.finishString();
1858 if (!str) {
1859 return nullptr;
1860 }
1861 }
1862 return QuoteString(cx, str, '"');
1863 };
1864
1865 if (lref.isString() && rref.isString()) {
1866 UniqueChars lbytes = uniqueCharsFromString(cx, lref);
1867 if (!lbytes) {
1868 return;
1869 }
1870 UniqueChars rbytes = uniqueCharsFromString(cx, rref);
1871 if (!rbytes) {
1872 return;
1873 }
1874 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_IN_STRING,
1875 lbytes.get(), rbytes.get());
1876 return;
1877 }
1878
1879 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_IN_NOT_OBJECT,
1880 InformalValueTypeName(rref));
1881 }
1882
Interpret(JSContext * cx,RunState & state)1883 static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
1884 RunState& state) {
1885 /*
1886 * Define macros for an interpreter loop. Opcode dispatch is done by
1887 * indirect goto (aka a threaded interpreter), which is technically
1888 * non-standard but is supported by all of our supported compilers.
1889 */
1890 #define INTERPRETER_LOOP()
1891 #define CASE(OP) label_##OP:
1892 #define DEFAULT() \
1893 label_default:
1894 #define DISPATCH_TO(OP) goto* addresses[(OP)]
1895
1896 #define LABEL(X) (&&label_##X)
1897
1898 // Use addresses instead of offsets to optimize for runtime speed over
1899 // load-time relocation overhead.
1900 static const void* const addresses[EnableInterruptsPseudoOpcode + 1] = {
1901 #define OPCODE_LABEL(op, ...) LABEL(op),
1902 FOR_EACH_OPCODE(OPCODE_LABEL)
1903 #undef OPCODE_LABEL
1904 #define TRAILING_LABEL(v) \
1905 ((v) == EnableInterruptsPseudoOpcode ? LABEL(EnableInterruptsPseudoOpcode) \
1906 : LABEL(default)),
1907 FOR_EACH_TRAILING_UNUSED_OPCODE(TRAILING_LABEL)
1908 #undef TRAILING_LABEL
1909 };
1910
1911 /*
1912 * Increment REGS.pc by N, load the opcode at that position,
1913 * and jump to the code to execute it.
1914 *
1915 * When Debugger puts a script in single-step mode, all js::Interpret
1916 * invocations that might be presently running that script must have
1917 * interrupts enabled. It's not practical to simply check
1918 * script->stepModeEnabled() at each point some callee could have changed
1919 * it, because there are so many places js::Interpret could possibly cause
1920 * JavaScript to run: each place an object might be coerced to a primitive
1921 * or a number, for example. So instead, we expose a simple mechanism to
1922 * let Debugger tweak the affected js::Interpret frames when an onStep
1923 * handler is added: calling activation.enableInterruptsUnconditionally()
1924 * will enable interrupts, and activation.opMask() is or'd with the opcode
1925 * to implement a simple alternate dispatch.
1926 */
1927 #define ADVANCE_AND_DISPATCH(N) \
1928 JS_BEGIN_MACRO \
1929 REGS.pc += (N); \
1930 SANITY_CHECKS(); \
1931 DISPATCH_TO(*REGS.pc | activation.opMask()); \
1932 JS_END_MACRO
1933
1934 /*
1935 * Shorthand for the common sequence at the end of a fixed-size opcode.
1936 */
1937 #define END_CASE(OP) ADVANCE_AND_DISPATCH(JSOpLength_##OP);
1938
1939 /*
1940 * Prepare to call a user-supplied branch handler, and abort the script
1941 * if it returns false.
1942 */
1943 #define CHECK_BRANCH() \
1944 JS_BEGIN_MACRO \
1945 if (!CheckForInterrupt(cx)) goto error; \
1946 JS_END_MACRO
1947
1948 /*
1949 * This is a simple wrapper around ADVANCE_AND_DISPATCH which also does
1950 * a CHECK_BRANCH() if n is not positive, which possibly indicates that it
1951 * is the backedge of a loop.
1952 */
1953 #define BRANCH(n) \
1954 JS_BEGIN_MACRO \
1955 int32_t nlen = (n); \
1956 if (nlen <= 0) CHECK_BRANCH(); \
1957 ADVANCE_AND_DISPATCH(nlen); \
1958 JS_END_MACRO
1959
1960 /*
1961 * Initialize code coverage vectors.
1962 */
1963 #define INIT_COVERAGE() \
1964 JS_BEGIN_MACRO \
1965 if (!script->hasScriptCounts()) { \
1966 if (cx->realm()->collectCoverageForDebug()) { \
1967 if (!script->initScriptCounts(cx)) goto error; \
1968 } \
1969 } \
1970 JS_END_MACRO
1971
1972 /*
1973 * Increment the code coverage counter associated with the given pc.
1974 */
1975 #define COUNT_COVERAGE_PC(PC) \
1976 JS_BEGIN_MACRO \
1977 if (script->hasScriptCounts()) { \
1978 PCCounts* counts = script->maybeGetPCCounts(PC); \
1979 MOZ_ASSERT(counts); \
1980 counts->numExec()++; \
1981 } \
1982 JS_END_MACRO
1983
1984 #define COUNT_COVERAGE_MAIN() \
1985 JS_BEGIN_MACRO \
1986 jsbytecode* main = script->main(); \
1987 if (!BytecodeIsJumpTarget(JSOp(*main))) COUNT_COVERAGE_PC(main); \
1988 JS_END_MACRO
1989
1990 #define COUNT_COVERAGE() \
1991 JS_BEGIN_MACRO \
1992 MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*REGS.pc))); \
1993 COUNT_COVERAGE_PC(REGS.pc); \
1994 JS_END_MACRO
1995
1996 #define SET_SCRIPT(s) \
1997 JS_BEGIN_MACRO \
1998 script = (s); \
1999 MOZ_ASSERT(cx->realm() == script->realm()); \
2000 if (DebugAPI::hasAnyBreakpointsOrStepMode(script) || \
2001 script->hasScriptCounts()) \
2002 activation.enableInterruptsUnconditionally(); \
2003 JS_END_MACRO
2004
2005 #define SANITY_CHECKS() \
2006 JS_BEGIN_MACRO \
2007 js::gc::MaybeVerifyBarriers(cx); \
2008 JS_END_MACRO
2009
2010 // Verify that an uninitialized lexical is followed by a correct check op.
2011 #ifdef DEBUG
2012 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2013 JS_BEGIN_MACRO \
2014 if (IsUninitializedLexical(val)) { \
2015 JSOp next = JSOp(*GetNextPc(REGS.pc)); \
2016 MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn || \
2017 next == JSOp::CheckThisReinit || \
2018 next == JSOp::CheckAliasedLexical); \
2019 } \
2020 JS_END_MACRO
2021 #else
2022 # define ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val) \
2023 JS_BEGIN_MACRO \
2024 /* nothing */ \
2025 JS_END_MACRO
2026 #endif
2027
2028 gc::MaybeVerifyBarriers(cx, true);
2029
2030 InterpreterFrame* entryFrame = state.pushInterpreterFrame(cx);
2031 if (!entryFrame) {
2032 return false;
2033 }
2034
2035 ActivationEntryMonitor entryMonitor(cx, entryFrame);
2036 InterpreterActivation activation(state, cx, entryFrame);
2037
2038 /* The script is used frequently, so keep a local copy. */
2039 RootedScript script(cx);
2040 SET_SCRIPT(REGS.fp()->script());
2041
2042 TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
2043 TraceLoggerEvent scriptEvent(TraceLogger_Scripts, script);
2044 TraceLogStartEvent(logger, scriptEvent);
2045 TraceLogStartEvent(logger, TraceLogger_Interpreter);
2046
2047 /*
2048 * Pool of rooters for use in this interpreter frame. References to these
2049 * are used for local variables within interpreter cases. This avoids
2050 * creating new rooters each time an interpreter case is entered, and also
2051 * correctness pitfalls due to incorrect compilation of destructor calls
2052 * around computed gotos.
2053 */
2054 RootedValue rootValue0(cx), rootValue1(cx);
2055 RootedString rootString0(cx), rootString1(cx);
2056 RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
2057 RootedNativeObject rootNativeObject0(cx);
2058 RootedFunction rootFunction0(cx);
2059 RootedPropertyName rootName0(cx);
2060 RootedId rootId0(cx);
2061 RootedShape rootShape0(cx);
2062 RootedScript rootScript0(cx);
2063 Rooted<Scope*> rootScope0(cx);
2064 DebugOnly<uint32_t> blockDepth;
2065
2066 /* State communicated between non-local jumps: */
2067 bool interpReturnOK;
2068 bool frameHalfInitialized;
2069
2070 if (!activation.entryFrame()->prologue(cx)) {
2071 goto prologue_error;
2072 }
2073
2074 if (!DebugAPI::onEnterFrame(cx, activation.entryFrame())) {
2075 goto error;
2076 }
2077
2078 // Increment the coverage for the main entry point.
2079 INIT_COVERAGE();
2080 COUNT_COVERAGE_MAIN();
2081
2082 // Enter the interpreter loop starting at the current pc.
2083 ADVANCE_AND_DISPATCH(0);
2084
2085 INTERPRETER_LOOP() {
2086 CASE(EnableInterruptsPseudoOpcode) {
2087 bool moreInterrupts = false;
2088 jsbytecode op = *REGS.pc;
2089
2090 if (!script->hasScriptCounts() &&
2091 cx->realm()->collectCoverageForDebug()) {
2092 if (!script->initScriptCounts(cx)) {
2093 goto error;
2094 }
2095 }
2096
2097 if (script->isDebuggee()) {
2098 if (DebugAPI::stepModeEnabled(script)) {
2099 if (!DebugAPI::onSingleStep(cx)) {
2100 goto error;
2101 }
2102 moreInterrupts = true;
2103 }
2104
2105 if (DebugAPI::hasAnyBreakpointsOrStepMode(script)) {
2106 moreInterrupts = true;
2107 }
2108
2109 if (DebugAPI::hasBreakpointsAt(script, REGS.pc)) {
2110 if (!DebugAPI::onTrap(cx)) {
2111 goto error;
2112 }
2113 }
2114 }
2115
2116 MOZ_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);
2117 if (!moreInterrupts) {
2118 activation.clearInterruptsMask();
2119 }
2120
2121 /* Commence executing the actual opcode. */
2122 SANITY_CHECKS();
2123 DISPATCH_TO(op);
2124 }
2125
2126 /* Various 1-byte no-ops. */
2127 CASE(Nop)
2128 CASE(Try)
2129 CASE(NopDestructuring)
2130 CASE(TryDestructuring) {
2131 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1);
2132 ADVANCE_AND_DISPATCH(1);
2133 }
2134
2135 CASE(JumpTarget)
2136 COUNT_COVERAGE();
2137 END_CASE(JumpTarget)
2138
2139 CASE(LoopHead) {
2140 COUNT_COVERAGE();
2141
2142 // Attempt on-stack replacement into the Baseline Interpreter.
2143 if (jit::IsBaselineInterpreterEnabled()) {
2144 script->incWarmUpCounter();
2145
2146 jit::MethodStatus status =
2147 jit::CanEnterBaselineInterpreterAtBranch(cx, REGS.fp());
2148 if (status == jit::Method_Error) {
2149 goto error;
2150 }
2151 if (status == jit::Method_Compiled) {
2152 bool wasProfiler = REGS.fp()->hasPushedGeckoProfilerFrame();
2153
2154 jit::JitExecStatus maybeOsr;
2155 {
2156 GeckoProfilerBaselineOSRMarker osr(cx, wasProfiler);
2157 maybeOsr =
2158 jit::EnterBaselineInterpreterAtBranch(cx, REGS.fp(), REGS.pc);
2159 }
2160
2161 // We failed to call into baseline at all, so treat as an error.
2162 if (maybeOsr == jit::JitExec_Aborted) {
2163 goto error;
2164 }
2165
2166 interpReturnOK = (maybeOsr == jit::JitExec_Ok);
2167
2168 // Pop the profiler frame pushed by the interpreter. (The compiled
2169 // version of the function popped a copy of the frame pushed by the
2170 // OSR trampoline.)
2171 if (wasProfiler) {
2172 cx->geckoProfiler().exit(cx, script);
2173 }
2174
2175 if (activation.entryFrame() != REGS.fp()) {
2176 goto jit_return_pop_frame;
2177 }
2178 goto leave_on_safe_point;
2179 }
2180 }
2181 }
2182 END_CASE(LoopHead)
2183
2184 CASE(Lineno)
2185 END_CASE(Lineno)
2186
2187 CASE(ForceInterpreter) {
2188 // Ensure pattern matching still works.
2189 MOZ_ASSERT(script->hasForceInterpreterOp());
2190 }
2191 END_CASE(ForceInterpreter)
2192
2193 CASE(Undefined) {
2194 // If this ever changes, change what JSOp::GImplicitThis does too.
2195 PUSH_UNDEFINED();
2196 }
2197 END_CASE(Undefined)
2198
2199 CASE(Pop) { REGS.sp--; }
2200 END_CASE(Pop)
2201
2202 CASE(PopN) {
2203 MOZ_ASSERT(GET_UINT16(REGS.pc) <= REGS.stackDepth());
2204 REGS.sp -= GET_UINT16(REGS.pc);
2205 }
2206 END_CASE(PopN)
2207
2208 CASE(DupAt) {
2209 MOZ_ASSERT(GET_UINT24(REGS.pc) < REGS.stackDepth());
2210 unsigned i = GET_UINT24(REGS.pc);
2211 const Value& rref = REGS.sp[-int(i + 1)];
2212 PUSH_COPY(rref);
2213 }
2214 END_CASE(DupAt)
2215
2216 CASE(SetRval) { POP_RETURN_VALUE(); }
2217 END_CASE(SetRval)
2218
2219 CASE(GetRval) { PUSH_COPY(REGS.fp()->returnValue()); }
2220 END_CASE(GetRval)
2221
2222 CASE(EnterWith) {
2223 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
2224 REGS.sp--;
2225 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
2226
2227 if (!EnterWithOperation(cx, REGS.fp(), val, scope.as<WithScope>())) {
2228 goto error;
2229 }
2230 }
2231 END_CASE(EnterWith)
2232
2233 CASE(LeaveWith) {
2234 REGS.fp()->popOffEnvironmentChain<WithEnvironmentObject>();
2235 }
2236 END_CASE(LeaveWith)
2237
2238 CASE(Return) {
2239 POP_RETURN_VALUE();
2240 /* FALL THROUGH */
2241 }
2242 CASE(RetRval) {
2243 /*
2244 * When the inlined frame exits with an exception or an error, ok will be
2245 * false after the inline_return label.
2246 */
2247 CHECK_BRANCH();
2248
2249 successful_return_continuation:
2250 interpReturnOK = true;
2251
2252 return_continuation:
2253 frameHalfInitialized = false;
2254
2255 prologue_return_continuation:
2256
2257 if (activation.entryFrame() != REGS.fp()) {
2258 // Stop the engine. (No details about which engine exactly, could be
2259 // interpreter, Baseline or IonMonkey.)
2260 TraceLogStopEvent(logger, TraceLogger_Engine);
2261 TraceLogStopEvent(logger, TraceLogger_Scripts);
2262
2263 if (MOZ_LIKELY(!frameHalfInitialized)) {
2264 interpReturnOK =
2265 DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
2266
2267 REGS.fp()->epilogue(cx, REGS.pc);
2268 }
2269
2270 jit_return_pop_frame:
2271
2272 activation.popInlineFrame(REGS.fp());
2273 {
2274 JSScript* callerScript = REGS.fp()->script();
2275 if (cx->realm() != callerScript->realm()) {
2276 cx->leaveRealm(callerScript->realm());
2277 }
2278 SET_SCRIPT(callerScript);
2279 }
2280
2281 jit_return:
2282
2283 MOZ_ASSERT(IsInvokePC(REGS.pc));
2284 MOZ_ASSERT(cx->realm() == script->realm());
2285
2286 /* Resume execution in the calling frame. */
2287 if (MOZ_LIKELY(interpReturnOK)) {
2288 if (JSOp(*REGS.pc) == JSOp::Resume) {
2289 ADVANCE_AND_DISPATCH(JSOpLength_Resume);
2290 }
2291
2292 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == JSOpLength_Call);
2293 ADVANCE_AND_DISPATCH(JSOpLength_Call);
2294 }
2295
2296 goto error;
2297 } else {
2298 // Stack should be empty for the outer frame, unless we executed the
2299 // first |await| expression in an async function.
2300 MOZ_ASSERT(REGS.stackDepth() == 0 ||
2301 (JSOp(*REGS.pc) == JSOp::Await &&
2302 !REGS.fp()->isResumedGenerator()));
2303 }
2304 goto exit;
2305 }
2306
2307 CASE(Default) {
2308 REGS.sp--;
2309 /* FALL THROUGH */
2310 }
2311 CASE(Goto) { BRANCH(GET_JUMP_OFFSET(REGS.pc)); }
2312
2313 CASE(JumpIfFalse) {
2314 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2315 REGS.sp--;
2316 if (!cond) {
2317 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2318 }
2319 }
2320 END_CASE(JumpIfFalse)
2321
2322 CASE(JumpIfTrue) {
2323 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2324 REGS.sp--;
2325 if (cond) {
2326 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2327 }
2328 }
2329 END_CASE(JumpIfTrue)
2330
2331 CASE(Or) {
2332 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2333 if (cond) {
2334 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2335 }
2336 }
2337 END_CASE(Or)
2338
2339 CASE(Coalesce) {
2340 MutableHandleValue res = REGS.stackHandleAt(-1);
2341 bool cond = !res.isNullOrUndefined();
2342 if (cond) {
2343 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2344 }
2345 }
2346 END_CASE(Coalesce)
2347
2348 CASE(And) {
2349 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2350 if (!cond) {
2351 ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
2352 }
2353 }
2354 END_CASE(And)
2355
2356 #define FETCH_ELEMENT_ID(n, id) \
2357 JS_BEGIN_MACRO \
2358 if (!ToPropertyKey(cx, REGS.stackHandleAt(n), &(id))) goto error; \
2359 JS_END_MACRO
2360
2361 #define TRY_BRANCH_AFTER_COND(cond, spdec) \
2362 JS_BEGIN_MACRO \
2363 MOZ_ASSERT(GetBytecodeLength(REGS.pc) == 1); \
2364 unsigned diff_ = \
2365 (unsigned)GET_UINT8(REGS.pc) - (unsigned)JSOp::JumpIfFalse; \
2366 if (diff_ <= 1) { \
2367 REGS.sp -= (spdec); \
2368 if ((cond) == (diff_ != 0)) { \
2369 ++REGS.pc; \
2370 BRANCH(GET_JUMP_OFFSET(REGS.pc)); \
2371 } \
2372 ADVANCE_AND_DISPATCH(1 + JSOpLength_JumpIfFalse); \
2373 } \
2374 JS_END_MACRO
2375
2376 CASE(In) {
2377 HandleValue rref = REGS.stackHandleAt(-1);
2378 if (!rref.isObject()) {
2379 HandleValue lref = REGS.stackHandleAt(-2);
2380 ReportInNotObjectError(cx, lref, rref);
2381 goto error;
2382 }
2383 bool found;
2384 {
2385 ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
2386 ReservedRooted<jsid> id(&rootId0);
2387 FETCH_ELEMENT_ID(-2, id);
2388 if (!HasProperty(cx, obj, id, &found)) {
2389 goto error;
2390 }
2391 }
2392 TRY_BRANCH_AFTER_COND(found, 2);
2393 REGS.sp--;
2394 REGS.sp[-1].setBoolean(found);
2395 }
2396 END_CASE(In)
2397
2398 CASE(HasOwn) {
2399 HandleValue val = REGS.stackHandleAt(-1);
2400 HandleValue idval = REGS.stackHandleAt(-2);
2401
2402 bool found;
2403 if (!HasOwnProperty(cx, val, idval, &found)) {
2404 goto error;
2405 }
2406
2407 REGS.sp--;
2408 REGS.sp[-1].setBoolean(found);
2409 }
2410 END_CASE(HasOwn)
2411
2412 CASE(CheckPrivateField) {
2413 /* Load the object being initialized into lval/val. */
2414 HandleValue val = REGS.stackHandleAt(-2);
2415 HandleValue idval = REGS.stackHandleAt(-1);
2416
2417 bool result = false;
2418 if (!CheckPrivateFieldOperation(cx, REGS.pc, val, idval, &result)) {
2419 goto error;
2420 }
2421
2422 PUSH_BOOLEAN(result);
2423 }
2424 END_CASE(CheckPrivateField)
2425
2426 CASE(Iter) {
2427 MOZ_ASSERT(REGS.stackDepth() >= 1);
2428 HandleValue val = REGS.stackHandleAt(-1);
2429 JSObject* iter = ValueToIterator(cx, val);
2430 if (!iter) {
2431 goto error;
2432 }
2433 REGS.sp[-1].setObject(*iter);
2434 }
2435 END_CASE(Iter)
2436
2437 CASE(MoreIter) {
2438 MOZ_ASSERT(REGS.stackDepth() >= 1);
2439 MOZ_ASSERT(REGS.sp[-1].isObject());
2440 Value v = IteratorMore(®S.sp[-1].toObject());
2441 PUSH_COPY(v);
2442 }
2443 END_CASE(MoreIter)
2444
2445 CASE(IsNoIter) {
2446 bool b = REGS.sp[-1].isMagic(JS_NO_ITER_VALUE);
2447 PUSH_BOOLEAN(b);
2448 }
2449 END_CASE(IsNoIter)
2450
2451 CASE(EndIter) {
2452 MOZ_ASSERT(REGS.stackDepth() >= 2);
2453 CloseIterator(®S.sp[-2].toObject());
2454 REGS.sp -= 2;
2455 }
2456 END_CASE(EndIter)
2457
2458 CASE(IsGenClosing) {
2459 bool b = REGS.sp[-1].isMagic(JS_GENERATOR_CLOSING);
2460 PUSH_BOOLEAN(b);
2461 }
2462 END_CASE(IsGenClosing)
2463
2464 CASE(Dup) {
2465 MOZ_ASSERT(REGS.stackDepth() >= 1);
2466 const Value& rref = REGS.sp[-1];
2467 PUSH_COPY(rref);
2468 }
2469 END_CASE(Dup)
2470
2471 CASE(Dup2) {
2472 MOZ_ASSERT(REGS.stackDepth() >= 2);
2473 const Value& lref = REGS.sp[-2];
2474 const Value& rref = REGS.sp[-1];
2475 PUSH_COPY(lref);
2476 PUSH_COPY(rref);
2477 }
2478 END_CASE(Dup2)
2479
2480 CASE(Swap) {
2481 MOZ_ASSERT(REGS.stackDepth() >= 2);
2482 Value& lref = REGS.sp[-2];
2483 Value& rref = REGS.sp[-1];
2484 lref.swap(rref);
2485 }
2486 END_CASE(Swap)
2487
2488 CASE(Pick) {
2489 unsigned i = GET_UINT8(REGS.pc);
2490 MOZ_ASSERT(REGS.stackDepth() >= i + 1);
2491 Value lval = REGS.sp[-int(i + 1)];
2492 memmove(REGS.sp - (i + 1), REGS.sp - i, sizeof(Value) * i);
2493 REGS.sp[-1] = lval;
2494 }
2495 END_CASE(Pick)
2496
2497 CASE(Unpick) {
2498 int i = GET_UINT8(REGS.pc);
2499 MOZ_ASSERT(REGS.stackDepth() >= unsigned(i) + 1);
2500 Value lval = REGS.sp[-1];
2501 memmove(REGS.sp - i, REGS.sp - (i + 1), sizeof(Value) * i);
2502 REGS.sp[-(i + 1)] = lval;
2503 }
2504 END_CASE(Unpick)
2505
2506 CASE(BindGName)
2507 CASE(BindName) {
2508 JSOp op = JSOp(*REGS.pc);
2509 ReservedRooted<JSObject*> envChain(&rootObject0);
2510 if (op == JSOp::BindName || script->hasNonSyntacticScope()) {
2511 envChain.set(REGS.fp()->environmentChain());
2512 } else {
2513 envChain.set(®S.fp()->global().lexicalEnvironment());
2514 }
2515 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2516
2517 // Assigning to an undeclared name adds a property to the global object.
2518 ReservedRooted<JSObject*> env(&rootObject1);
2519 if (!LookupNameUnqualified(cx, name, envChain, &env)) {
2520 goto error;
2521 }
2522
2523 PUSH_OBJECT(*env);
2524
2525 static_assert(JSOpLength_BindName == JSOpLength_BindGName,
2526 "We're sharing the END_CASE so the lengths better match");
2527 }
2528 END_CASE(BindName)
2529
2530 CASE(BindVar) {
2531 JSObject* varObj = BindVarOperation(cx, REGS.fp()->environmentChain());
2532 PUSH_OBJECT(*varObj);
2533 }
2534 END_CASE(BindVar)
2535
2536 CASE(BitOr) {
2537 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2538 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2539 MutableHandleValue res = REGS.stackHandleAt(-2);
2540 if (!BitOrOperation(cx, lhs, rhs, res)) {
2541 goto error;
2542 }
2543 REGS.sp--;
2544 }
2545 END_CASE(BitOr)
2546
2547 CASE(BitXor) {
2548 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2549 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2550 MutableHandleValue res = REGS.stackHandleAt(-2);
2551 if (!BitXorOperation(cx, lhs, rhs, res)) {
2552 goto error;
2553 }
2554 REGS.sp--;
2555 }
2556 END_CASE(BitXor)
2557
2558 CASE(BitAnd) {
2559 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2560 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2561 MutableHandleValue res = REGS.stackHandleAt(-2);
2562 if (!BitAndOperation(cx, lhs, rhs, res)) {
2563 goto error;
2564 }
2565 REGS.sp--;
2566 }
2567 END_CASE(BitAnd)
2568
2569 CASE(Eq) {
2570 if (!LooseEqualityOp<true>(cx, REGS)) {
2571 goto error;
2572 }
2573 }
2574 END_CASE(Eq)
2575
2576 CASE(Ne) {
2577 if (!LooseEqualityOp<false>(cx, REGS)) {
2578 goto error;
2579 }
2580 }
2581 END_CASE(Ne)
2582
2583 #define STRICT_EQUALITY_OP(OP, COND) \
2584 JS_BEGIN_MACRO \
2585 HandleValue lval = REGS.stackHandleAt(-2); \
2586 HandleValue rval = REGS.stackHandleAt(-1); \
2587 bool equal; \
2588 if (!js::StrictlyEqual(cx, lval, rval, &equal)) { \
2589 goto error; \
2590 } \
2591 (COND) = equal OP true; \
2592 REGS.sp--; \
2593 JS_END_MACRO
2594
2595 CASE(StrictEq) {
2596 bool cond;
2597 STRICT_EQUALITY_OP(==, cond);
2598 REGS.sp[-1].setBoolean(cond);
2599 }
2600 END_CASE(StrictEq)
2601
2602 CASE(StrictNe) {
2603 bool cond;
2604 STRICT_EQUALITY_OP(!=, cond);
2605 REGS.sp[-1].setBoolean(cond);
2606 }
2607 END_CASE(StrictNe)
2608
2609 #undef STRICT_EQUALITY_OP
2610
2611 CASE(Case) {
2612 bool cond = REGS.sp[-1].toBoolean();
2613 REGS.sp--;
2614 if (cond) {
2615 REGS.sp--;
2616 BRANCH(GET_JUMP_OFFSET(REGS.pc));
2617 }
2618 }
2619 END_CASE(Case)
2620
2621 CASE(Lt) {
2622 bool cond;
2623 MutableHandleValue lval = REGS.stackHandleAt(-2);
2624 MutableHandleValue rval = REGS.stackHandleAt(-1);
2625 if (!LessThanOperation(cx, lval, rval, &cond)) {
2626 goto error;
2627 }
2628 TRY_BRANCH_AFTER_COND(cond, 2);
2629 REGS.sp[-2].setBoolean(cond);
2630 REGS.sp--;
2631 }
2632 END_CASE(Lt)
2633
2634 CASE(Le) {
2635 bool cond;
2636 MutableHandleValue lval = REGS.stackHandleAt(-2);
2637 MutableHandleValue rval = REGS.stackHandleAt(-1);
2638 if (!LessThanOrEqualOperation(cx, lval, rval, &cond)) {
2639 goto error;
2640 }
2641 TRY_BRANCH_AFTER_COND(cond, 2);
2642 REGS.sp[-2].setBoolean(cond);
2643 REGS.sp--;
2644 }
2645 END_CASE(Le)
2646
2647 CASE(Gt) {
2648 bool cond;
2649 MutableHandleValue lval = REGS.stackHandleAt(-2);
2650 MutableHandleValue rval = REGS.stackHandleAt(-1);
2651 if (!GreaterThanOperation(cx, lval, rval, &cond)) {
2652 goto error;
2653 }
2654 TRY_BRANCH_AFTER_COND(cond, 2);
2655 REGS.sp[-2].setBoolean(cond);
2656 REGS.sp--;
2657 }
2658 END_CASE(Gt)
2659
2660 CASE(Ge) {
2661 bool cond;
2662 MutableHandleValue lval = REGS.stackHandleAt(-2);
2663 MutableHandleValue rval = REGS.stackHandleAt(-1);
2664 if (!GreaterThanOrEqualOperation(cx, lval, rval, &cond)) {
2665 goto error;
2666 }
2667 TRY_BRANCH_AFTER_COND(cond, 2);
2668 REGS.sp[-2].setBoolean(cond);
2669 REGS.sp--;
2670 }
2671 END_CASE(Ge)
2672
2673 CASE(Lsh) {
2674 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2675 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2676 MutableHandleValue res = REGS.stackHandleAt(-2);
2677 if (!BitLshOperation(cx, lhs, rhs, res)) {
2678 goto error;
2679 }
2680 REGS.sp--;
2681 }
2682 END_CASE(Lsh)
2683
2684 CASE(Rsh) {
2685 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2686 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2687 MutableHandleValue res = REGS.stackHandleAt(-2);
2688 if (!BitRshOperation(cx, lhs, rhs, res)) {
2689 goto error;
2690 }
2691 REGS.sp--;
2692 }
2693 END_CASE(Rsh)
2694
2695 CASE(Ursh) {
2696 MutableHandleValue lhs = REGS.stackHandleAt(-2);
2697 MutableHandleValue rhs = REGS.stackHandleAt(-1);
2698 MutableHandleValue res = REGS.stackHandleAt(-2);
2699 if (!UrshOperation(cx, lhs, rhs, res)) {
2700 goto error;
2701 }
2702 REGS.sp--;
2703 }
2704 END_CASE(Ursh)
2705
2706 CASE(Add) {
2707 MutableHandleValue lval = REGS.stackHandleAt(-2);
2708 MutableHandleValue rval = REGS.stackHandleAt(-1);
2709 MutableHandleValue res = REGS.stackHandleAt(-2);
2710 if (!AddOperation(cx, lval, rval, res)) {
2711 goto error;
2712 }
2713 REGS.sp--;
2714 }
2715 END_CASE(Add)
2716
2717 CASE(Sub) {
2718 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2719 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2720 MutableHandleValue res = REGS.stackHandleAt(-2);
2721 if (!SubOperation(cx, &lval, &rval, res)) {
2722 goto error;
2723 }
2724 REGS.sp--;
2725 }
2726 END_CASE(Sub)
2727
2728 CASE(Mul) {
2729 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2730 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2731 MutableHandleValue res = REGS.stackHandleAt(-2);
2732 if (!MulOperation(cx, &lval, &rval, res)) {
2733 goto error;
2734 }
2735 REGS.sp--;
2736 }
2737 END_CASE(Mul)
2738
2739 CASE(Div) {
2740 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2741 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2742 MutableHandleValue res = REGS.stackHandleAt(-2);
2743 if (!DivOperation(cx, &lval, &rval, res)) {
2744 goto error;
2745 }
2746 REGS.sp--;
2747 }
2748 END_CASE(Div)
2749
2750 CASE(Mod) {
2751 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2752 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2753 MutableHandleValue res = REGS.stackHandleAt(-2);
2754 if (!ModOperation(cx, &lval, &rval, res)) {
2755 goto error;
2756 }
2757 REGS.sp--;
2758 }
2759 END_CASE(Mod)
2760
2761 CASE(Pow) {
2762 ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
2763 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
2764 MutableHandleValue res = REGS.stackHandleAt(-2);
2765 if (!PowOperation(cx, &lval, &rval, res)) {
2766 goto error;
2767 }
2768 REGS.sp--;
2769 }
2770 END_CASE(Pow)
2771
2772 CASE(Not) {
2773 bool cond = ToBoolean(REGS.stackHandleAt(-1));
2774 REGS.sp--;
2775 PUSH_BOOLEAN(!cond);
2776 }
2777 END_CASE(Not)
2778
2779 CASE(BitNot) {
2780 MutableHandleValue val = REGS.stackHandleAt(-1);
2781 if (!BitNotOperation(cx, val, val)) {
2782 goto error;
2783 }
2784 }
2785 END_CASE(BitNot)
2786
2787 CASE(Neg) {
2788 MutableHandleValue val = REGS.stackHandleAt(-1);
2789 if (!NegOperation(cx, val, val)) {
2790 goto error;
2791 }
2792 }
2793 END_CASE(Neg)
2794
2795 CASE(Pos) {
2796 if (!ToNumber(cx, REGS.stackHandleAt(-1))) {
2797 goto error;
2798 }
2799 }
2800 END_CASE(Pos)
2801
2802 CASE(DelName) {
2803 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2804 ReservedRooted<JSObject*> envObj(&rootObject0,
2805 REGS.fp()->environmentChain());
2806
2807 PUSH_BOOLEAN(true);
2808 MutableHandleValue res = REGS.stackHandleAt(-1);
2809 if (!DeleteNameOperation(cx, name, envObj, res)) {
2810 goto error;
2811 }
2812 }
2813 END_CASE(DelName)
2814
2815 CASE(DelProp)
2816 CASE(StrictDelProp) {
2817 static_assert(JSOpLength_DelProp == JSOpLength_StrictDelProp,
2818 "delprop and strictdelprop must be the same size");
2819 HandleValue val = REGS.stackHandleAt(-1);
2820 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
2821 bool res = false;
2822 if (JSOp(*REGS.pc) == JSOp::StrictDelProp) {
2823 if (!DelPropOperation<true>(cx, val, name, &res)) {
2824 goto error;
2825 }
2826 } else {
2827 if (!DelPropOperation<false>(cx, val, name, &res)) {
2828 goto error;
2829 }
2830 }
2831 REGS.sp[-1].setBoolean(res);
2832 }
2833 END_CASE(DelProp)
2834
2835 CASE(DelElem)
2836 CASE(StrictDelElem) {
2837 static_assert(JSOpLength_DelElem == JSOpLength_StrictDelElem,
2838 "delelem and strictdelelem must be the same size");
2839 HandleValue val = REGS.stackHandleAt(-2);
2840 HandleValue propval = REGS.stackHandleAt(-1);
2841 bool res = false;
2842 if (JSOp(*REGS.pc) == JSOp::StrictDelElem) {
2843 if (!DelElemOperation<true>(cx, val, propval, &res)) {
2844 goto error;
2845 }
2846 } else {
2847 if (!DelElemOperation<false>(cx, val, propval, &res)) {
2848 goto error;
2849 }
2850 }
2851 REGS.sp[-2].setBoolean(res);
2852 REGS.sp--;
2853 }
2854 END_CASE(DelElem)
2855
2856 CASE(ToPropertyKey) {
2857 ReservedRooted<Value> idval(&rootValue1, REGS.sp[-1]);
2858 MutableHandleValue res = REGS.stackHandleAt(-1);
2859 if (!ToPropertyKeyOperation(cx, idval, res)) {
2860 goto error;
2861 }
2862 }
2863 END_CASE(ToPropertyKey)
2864
2865 CASE(TypeofExpr)
2866 CASE(Typeof) {
2867 REGS.sp[-1].setString(TypeOfOperation(REGS.sp[-1], cx->runtime()));
2868 }
2869 END_CASE(Typeof)
2870
2871 CASE(Void) { REGS.sp[-1].setUndefined(); }
2872 END_CASE(Void)
2873
2874 CASE(FunctionThis) {
2875 PUSH_NULL();
2876 if (!GetFunctionThis(cx, REGS.fp(), REGS.stackHandleAt(-1))) {
2877 goto error;
2878 }
2879 }
2880 END_CASE(FunctionThis)
2881
2882 CASE(GlobalThis) {
2883 if (script->hasNonSyntacticScope()) {
2884 PUSH_NULL();
2885 GetNonSyntacticGlobalThis(cx, REGS.fp()->environmentChain(),
2886 REGS.stackHandleAt(-1));
2887 } else {
2888 PUSH_OBJECT(*cx->global()->lexicalEnvironment().thisObject());
2889 }
2890 }
2891 END_CASE(GlobalThis)
2892
2893 CASE(CheckIsObj) {
2894 if (!REGS.sp[-1].isObject()) {
2895 MOZ_ALWAYS_FALSE(
2896 ThrowCheckIsObject(cx, CheckIsObjectKind(GET_UINT8(REGS.pc))));
2897 goto error;
2898 }
2899 }
2900 END_CASE(CheckIsObj)
2901
2902 CASE(CheckThis) {
2903 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2904 MOZ_ALWAYS_FALSE(ThrowUninitializedThis(cx));
2905 goto error;
2906 }
2907 }
2908 END_CASE(CheckThis)
2909
2910 CASE(CheckThisReinit) {
2911 if (!REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
2912 MOZ_ALWAYS_FALSE(ThrowInitializedThis(cx));
2913 goto error;
2914 }
2915 }
2916 END_CASE(CheckThisReinit)
2917
2918 CASE(CheckReturn) {
2919 if (!REGS.fp()->checkReturn(cx, REGS.stackHandleAt(-1))) {
2920 goto error;
2921 }
2922 REGS.sp--;
2923 }
2924 END_CASE(CheckReturn)
2925
2926 CASE(GetProp) {
2927 MutableHandleValue lval = REGS.stackHandleAt(-1);
2928 if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval)) {
2929 goto error;
2930 }
2931 cx->debugOnlyCheck(lval);
2932 }
2933 END_CASE(GetProp)
2934
2935 CASE(GetPropSuper) {
2936 ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-2]);
2937 ReservedRooted<JSObject*> obj(&rootObject1, ®S.sp[-1].toObject());
2938 MutableHandleValue rref = REGS.stackHandleAt(-2);
2939
2940 if (!GetProperty(cx, obj, receiver, script->getName(REGS.pc), rref)) {
2941 goto error;
2942 }
2943
2944 cx->debugOnlyCheck(rref);
2945
2946 REGS.sp--;
2947 }
2948 END_CASE(GetPropSuper)
2949
2950 CASE(GetBoundName) {
2951 ReservedRooted<JSObject*> env(&rootObject0, ®S.sp[-1].toObject());
2952 ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
2953 MutableHandleValue rval = REGS.stackHandleAt(-1);
2954 if (!GetNameBoundInEnvironment(cx, env, id, rval)) {
2955 goto error;
2956 }
2957 cx->debugOnlyCheck(rval);
2958 }
2959 END_CASE(GetBoundName)
2960
2961 CASE(SetIntrinsic) {
2962 HandleValue value = REGS.stackHandleAt(-1);
2963
2964 if (!SetIntrinsicOperation(cx, script, REGS.pc, value)) {
2965 goto error;
2966 }
2967 }
2968 END_CASE(SetIntrinsic)
2969
2970 CASE(SetGName)
2971 CASE(StrictSetGName)
2972 CASE(SetName)
2973 CASE(StrictSetName) {
2974 static_assert(JSOpLength_SetName == JSOpLength_StrictSetName,
2975 "setname and strictsetname must be the same size");
2976 static_assert(JSOpLength_SetGName == JSOpLength_StrictSetGName,
2977 "setganem adn strictsetgname must be the same size");
2978 static_assert(JSOpLength_SetName == JSOpLength_SetGName,
2979 "We're sharing the END_CASE so the lengths better match");
2980
2981 ReservedRooted<JSObject*> env(&rootObject0, ®S.sp[-2].toObject());
2982 HandleValue value = REGS.stackHandleAt(-1);
2983
2984 if (!SetNameOperation(cx, script, REGS.pc, env, value)) {
2985 goto error;
2986 }
2987
2988 REGS.sp[-2] = REGS.sp[-1];
2989 REGS.sp--;
2990 }
2991 END_CASE(SetName)
2992
2993 CASE(SetProp)
2994 CASE(StrictSetProp) {
2995 static_assert(JSOpLength_SetProp == JSOpLength_StrictSetProp,
2996 "setprop and strictsetprop must be the same size");
2997 int lvalIndex = -2;
2998 HandleValue lval = REGS.stackHandleAt(lvalIndex);
2999 HandleValue rval = REGS.stackHandleAt(-1);
3000
3001 ReservedRooted<jsid> id(&rootId0, NameToId(script->getName(REGS.pc)));
3002 if (!SetPropertyOperation(cx, JSOp(*REGS.pc), lval, lvalIndex, id,
3003 rval)) {
3004 goto error;
3005 }
3006
3007 REGS.sp[-2] = REGS.sp[-1];
3008 REGS.sp--;
3009 }
3010 END_CASE(SetProp)
3011
3012 CASE(SetPropSuper)
3013 CASE(StrictSetPropSuper) {
3014 static_assert(
3015 JSOpLength_SetPropSuper == JSOpLength_StrictSetPropSuper,
3016 "setprop-super and strictsetprop-super must be the same size");
3017
3018 ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-3]);
3019 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-2].toObject());
3020 ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
3021 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3022
3023 bool strict = JSOp(*REGS.pc) == JSOp::StrictSetPropSuper;
3024
3025 if (!SetPropertySuper(cx, obj, receiver, name, rval, strict)) {
3026 goto error;
3027 }
3028
3029 REGS.sp[-3] = REGS.sp[-1];
3030 REGS.sp -= 2;
3031 }
3032 END_CASE(SetPropSuper)
3033
3034 CASE(GetElem) {
3035 int lvalIndex = -2;
3036 MutableHandleValue lval = REGS.stackHandleAt(lvalIndex);
3037 HandleValue rval = REGS.stackHandleAt(-1);
3038 MutableHandleValue res = REGS.stackHandleAt(-2);
3039
3040 if (!GetElementOperationWithStackIndex(cx, lval, lvalIndex, rval, res)) {
3041 goto error;
3042 }
3043
3044 REGS.sp--;
3045 }
3046 END_CASE(GetElem)
3047
3048 CASE(GetElemSuper) {
3049 ReservedRooted<Value> receiver(&rootValue1, REGS.sp[-3]);
3050 ReservedRooted<Value> rval(&rootValue0, REGS.sp[-2]);
3051 ReservedRooted<JSObject*> obj(&rootObject1, ®S.sp[-1].toObject());
3052
3053 MutableHandleValue res = REGS.stackHandleAt(-3);
3054
3055 // Since we have asserted that obj has to be an object, it cannot be
3056 // either optimized arguments, or indeed any primitive. This simplifies
3057 // our task some.
3058 if (!GetObjectElementOperation(cx, JSOp(*REGS.pc), obj, receiver, rval,
3059 res)) {
3060 goto error;
3061 }
3062
3063 REGS.sp -= 2;
3064 }
3065 END_CASE(GetElemSuper)
3066
3067 CASE(SetElem)
3068 CASE(StrictSetElem) {
3069 static_assert(JSOpLength_SetElem == JSOpLength_StrictSetElem,
3070 "setelem and strictsetelem must be the same size");
3071 int receiverIndex = -3;
3072 HandleValue receiver = REGS.stackHandleAt(receiverIndex);
3073 ReservedRooted<JSObject*> obj(&rootObject0);
3074 obj = ToObjectFromStackForPropertyAccess(cx, receiver, receiverIndex,
3075 REGS.stackHandleAt(-2));
3076 if (!obj) {
3077 goto error;
3078 }
3079 ReservedRooted<jsid> id(&rootId0);
3080 FETCH_ELEMENT_ID(-2, id);
3081 HandleValue value = REGS.stackHandleAt(-1);
3082 if (!SetObjectElementOperation(cx, obj, id, value, receiver,
3083 JSOp(*REGS.pc) == JSOp::StrictSetElem)) {
3084 goto error;
3085 }
3086 REGS.sp[-3] = value;
3087 REGS.sp -= 2;
3088 }
3089 END_CASE(SetElem)
3090
3091 CASE(SetElemSuper)
3092 CASE(StrictSetElemSuper) {
3093 static_assert(
3094 JSOpLength_SetElemSuper == JSOpLength_StrictSetElemSuper,
3095 "setelem-super and strictsetelem-super must be the same size");
3096
3097 ReservedRooted<Value> receiver(&rootValue0, REGS.sp[-4]);
3098 ReservedRooted<Value> index(&rootValue1, REGS.sp[-3]);
3099 ReservedRooted<JSObject*> obj(&rootObject1, ®S.sp[-2].toObject());
3100 HandleValue value = REGS.stackHandleAt(-1);
3101
3102 bool strict = JSOp(*REGS.pc) == JSOp::StrictSetElemSuper;
3103 if (!SetObjectElementWithReceiver(cx, obj, index, value, receiver,
3104 strict)) {
3105 goto error;
3106 }
3107 REGS.sp[-4] = value;
3108 REGS.sp -= 3;
3109 }
3110 END_CASE(SetElemSuper)
3111
3112 CASE(Eval)
3113 CASE(StrictEval) {
3114 static_assert(JSOpLength_Eval == JSOpLength_StrictEval,
3115 "eval and stricteval must be the same size");
3116
3117 CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
3118 if (cx->global()->valueIsEval(args.calleev())) {
3119 if (!DirectEval(cx, args.get(0), args.rval())) {
3120 goto error;
3121 }
3122 } else {
3123 if (!CallFromStack(cx, args)) {
3124 goto error;
3125 }
3126 }
3127
3128 REGS.sp = args.spAfterCall();
3129 }
3130 END_CASE(Eval)
3131
3132 CASE(SpreadNew)
3133 CASE(SpreadCall)
3134 CASE(SpreadSuperCall) {
3135 if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
3136 cx->geckoProfiler().updatePC(cx, script, REGS.pc);
3137 }
3138 /* FALL THROUGH */
3139 }
3140
3141 CASE(SpreadEval)
3142 CASE(StrictSpreadEval) {
3143 static_assert(JSOpLength_SpreadEval == JSOpLength_StrictSpreadEval,
3144 "spreadeval and strictspreadeval must be the same size");
3145 bool construct = JSOp(*REGS.pc) == JSOp::SpreadNew ||
3146 JSOp(*REGS.pc) == JSOp::SpreadSuperCall;
3147 ;
3148
3149 MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
3150
3151 HandleValue callee = REGS.stackHandleAt(-3 - construct);
3152 HandleValue thisv = REGS.stackHandleAt(-2 - construct);
3153 HandleValue arr = REGS.stackHandleAt(-1 - construct);
3154 MutableHandleValue ret = REGS.stackHandleAt(-3 - construct);
3155
3156 RootedValue& newTarget = rootValue0;
3157 if (construct) {
3158 newTarget = REGS.sp[-1];
3159 } else {
3160 newTarget = NullValue();
3161 }
3162
3163 if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr,
3164 newTarget, ret)) {
3165 goto error;
3166 }
3167
3168 REGS.sp -= 2 + construct;
3169 }
3170 END_CASE(SpreadCall)
3171
3172 CASE(New)
3173 CASE(Call)
3174 CASE(CallIgnoresRv)
3175 CASE(CallIter)
3176 CASE(SuperCall)
3177 CASE(FunCall)
3178 CASE(FunApply) {
3179 static_assert(JSOpLength_Call == JSOpLength_New,
3180 "call and new must be the same size");
3181 static_assert(JSOpLength_Call == JSOpLength_CallIgnoresRv,
3182 "call and call-ignores-rv must be the same size");
3183 static_assert(JSOpLength_Call == JSOpLength_CallIter,
3184 "call and calliter must be the same size");
3185 static_assert(JSOpLength_Call == JSOpLength_SuperCall,
3186 "call and supercall must be the same size");
3187 static_assert(JSOpLength_Call == JSOpLength_FunCall,
3188 "call and funcall must be the same size");
3189 static_assert(JSOpLength_Call == JSOpLength_FunApply,
3190 "call and funapply must be the same size");
3191
3192 if (REGS.fp()->hasPushedGeckoProfilerFrame()) {
3193 cx->geckoProfiler().updatePC(cx, script, REGS.pc);
3194 }
3195
3196 MaybeConstruct construct = MaybeConstruct(
3197 JSOp(*REGS.pc) == JSOp::New || JSOp(*REGS.pc) == JSOp::SuperCall);
3198 bool ignoresReturnValue = JSOp(*REGS.pc) == JSOp::CallIgnoresRv;
3199 unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
3200
3201 MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
3202 CallArgs args =
3203 CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
3204
3205 JSFunction* maybeFun;
3206 bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
3207
3208 // Use the slow path if the callee is not an interpreted function, if we
3209 // have to throw an exception, or if we might have to invoke the
3210 // OnNativeCall hook for a self-hosted builtin.
3211 if (!isFunction || !maybeFun->isInterpreted() ||
3212 (construct && !maybeFun->isConstructor()) ||
3213 (!construct && maybeFun->isClassConstructor()) ||
3214 cx->insideDebuggerEvaluationWithOnNativeCallHook) {
3215 if (construct) {
3216 if (!ConstructFromStack(cx, args)) {
3217 goto error;
3218 }
3219 } else {
3220 if (JSOp(*REGS.pc) == JSOp::CallIter &&
3221 args.calleev().isPrimitive()) {
3222 MOZ_ASSERT(args.length() == 0, "thisv must be on top of the stack");
3223 ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, args.thisv(), nullptr);
3224 goto error;
3225 }
3226 if (!CallFromStack(cx, args)) {
3227 goto error;
3228 }
3229 }
3230 Value* newsp = args.spAfterCall();
3231 REGS.sp = newsp;
3232 ADVANCE_AND_DISPATCH(JSOpLength_Call);
3233 }
3234
3235 {
3236 MOZ_ASSERT(maybeFun);
3237 ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
3238 ReservedRooted<JSScript*> funScript(
3239 &rootScript0, JSFunction::getOrCreateScript(cx, fun));
3240 if (!funScript) {
3241 goto error;
3242 }
3243
3244 // Enter the callee's realm if this is a cross-realm call. Use
3245 // MakeScopeExit to leave this realm on all error/JIT-return paths
3246 // below.
3247 const bool isCrossRealm = cx->realm() != funScript->realm();
3248 if (isCrossRealm) {
3249 cx->enterRealmOf(funScript);
3250 }
3251 auto leaveRealmGuard =
3252 mozilla::MakeScopeExit([isCrossRealm, cx, &script] {
3253 if (isCrossRealm) {
3254 cx->leaveRealm(script->realm());
3255 }
3256 });
3257
3258 if (construct && !MaybeCreateThisForConstructor(cx, args)) {
3259 goto error;
3260 }
3261
3262 {
3263 InvokeState state(cx, args, construct);
3264
3265 jit::EnterJitStatus status = jit::MaybeEnterJit(cx, state);
3266 switch (status) {
3267 case jit::EnterJitStatus::Error:
3268 goto error;
3269 case jit::EnterJitStatus::Ok:
3270 interpReturnOK = true;
3271 CHECK_BRANCH();
3272 REGS.sp = args.spAfterCall();
3273 goto jit_return;
3274 case jit::EnterJitStatus::NotEntered:
3275 break;
3276 }
3277 }
3278
3279 funScript = fun->nonLazyScript();
3280
3281 if (!activation.pushInlineFrame(args, funScript, construct)) {
3282 goto error;
3283 }
3284 leaveRealmGuard.release(); // We leave the callee's realm when we
3285 // call popInlineFrame.
3286 }
3287
3288 SET_SCRIPT(REGS.fp()->script());
3289
3290 {
3291 TraceLoggerEvent event(TraceLogger_Scripts, script);
3292 TraceLogStartEvent(logger, event);
3293 TraceLogStartEvent(logger, TraceLogger_Interpreter);
3294 }
3295
3296 if (!REGS.fp()->prologue(cx)) {
3297 goto prologue_error;
3298 }
3299
3300 if (!DebugAPI::onEnterFrame(cx, REGS.fp())) {
3301 goto error;
3302 }
3303
3304 // Increment the coverage for the main entry point.
3305 INIT_COVERAGE();
3306 COUNT_COVERAGE_MAIN();
3307
3308 /* Load first op and dispatch it (safe since JSOp::RetRval). */
3309 ADVANCE_AND_DISPATCH(0);
3310 }
3311
3312 CASE(OptimizeSpreadCall) {
3313 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3314
3315 bool optimized = false;
3316 if (!OptimizeSpreadCall(cx, val, &optimized)) {
3317 goto error;
3318 }
3319
3320 PUSH_BOOLEAN(optimized);
3321 }
3322 END_CASE(OptimizeSpreadCall)
3323
3324 CASE(ThrowMsg) {
3325 MOZ_ALWAYS_FALSE(ThrowMsgOperation(cx, GET_UINT8(REGS.pc)));
3326 goto error;
3327 }
3328 END_CASE(ThrowMsg)
3329
3330 CASE(ImplicitThis)
3331 CASE(GImplicitThis) {
3332 JSOp op = JSOp(*REGS.pc);
3333 if (op == JSOp::ImplicitThis || script->hasNonSyntacticScope()) {
3334 ReservedRooted<PropertyName*> name(&rootName0,
3335 script->getName(REGS.pc));
3336 ReservedRooted<JSObject*> envObj(&rootObject0,
3337 REGS.fp()->environmentChain());
3338 ReservedRooted<JSObject*> env(&rootObject1);
3339 if (!LookupNameWithGlobalDefault(cx, name, envObj, &env)) {
3340 goto error;
3341 }
3342
3343 Value v = ComputeImplicitThis(env);
3344 PUSH_COPY(v);
3345 } else {
3346 // Treat it like JSOp::Undefined.
3347 PUSH_UNDEFINED();
3348 }
3349 static_assert(JSOpLength_ImplicitThis == JSOpLength_GImplicitThis,
3350 "We're sharing the END_CASE so the lengths better match");
3351 }
3352 END_CASE(ImplicitThis)
3353
3354 CASE(GetGName)
3355 CASE(GetName) {
3356 ReservedRooted<Value> rval(&rootValue0);
3357 if (!GetNameOperation(cx, REGS.fp(), REGS.pc, &rval)) {
3358 goto error;
3359 }
3360
3361 PUSH_COPY(rval);
3362 static_assert(JSOpLength_GetName == JSOpLength_GetGName,
3363 "We're sharing the END_CASE so the lengths better match");
3364 }
3365 END_CASE(GetName)
3366
3367 CASE(GetImport) {
3368 PUSH_NULL();
3369 MutableHandleValue rval = REGS.stackHandleAt(-1);
3370 HandleObject envChain = REGS.fp()->environmentChain();
3371 if (!GetImportOperation(cx, envChain, script, REGS.pc, rval)) {
3372 goto error;
3373 }
3374 }
3375 END_CASE(GetImport)
3376
3377 CASE(GetIntrinsic) {
3378 ReservedRooted<Value> rval(&rootValue0);
3379 if (!GetIntrinsicOperation(cx, script, REGS.pc, &rval)) {
3380 goto error;
3381 }
3382
3383 PUSH_COPY(rval);
3384 }
3385 END_CASE(GetIntrinsic)
3386
3387 CASE(Uint16) { PUSH_INT32((int32_t)GET_UINT16(REGS.pc)); }
3388 END_CASE(Uint16)
3389
3390 CASE(Uint24)
3391 CASE(ResumeIndex) { PUSH_INT32((int32_t)GET_UINT24(REGS.pc)); }
3392 END_CASE(Uint24)
3393
3394 CASE(Int8) { PUSH_INT32(GET_INT8(REGS.pc)); }
3395 END_CASE(Int8)
3396
3397 CASE(Int32) { PUSH_INT32(GET_INT32(REGS.pc)); }
3398 END_CASE(Int32)
3399
3400 CASE(Double) { PUSH_COPY(GET_INLINE_VALUE(REGS.pc)); }
3401 END_CASE(Double)
3402
3403 CASE(String) { PUSH_STRING(script->getAtom(REGS.pc)); }
3404 END_CASE(String)
3405
3406 CASE(ToString) {
3407 MutableHandleValue oper = REGS.stackHandleAt(-1);
3408
3409 if (!oper.isString()) {
3410 JSString* operString = ToString<CanGC>(cx, oper);
3411 if (!operString) {
3412 goto error;
3413 }
3414 oper.setString(operString);
3415 }
3416 }
3417 END_CASE(ToString)
3418
3419 CASE(Symbol) {
3420 PUSH_SYMBOL(cx->wellKnownSymbols().get(GET_UINT8(REGS.pc)));
3421 }
3422 END_CASE(Symbol)
3423
3424 CASE(Object) {
3425 MOZ_ASSERT(script->treatAsRunOnce());
3426 PUSH_OBJECT(*script->getObject(REGS.pc));
3427 }
3428 END_CASE(Object)
3429
3430 CASE(CallSiteObj) {
3431 JSObject* cso = ProcessCallSiteObjOperation(cx, script, REGS.pc);
3432 if (!cso) {
3433 goto error;
3434 }
3435 PUSH_OBJECT(*cso);
3436 }
3437 END_CASE(CallSiteObj)
3438
3439 CASE(RegExp) {
3440 /*
3441 * Push a regexp object cloned from the regexp literal object mapped by
3442 * the bytecode at pc.
3443 */
3444 ReservedRooted<JSObject*> re(&rootObject0, script->getRegExp(REGS.pc));
3445 JSObject* obj = CloneRegExpObject(cx, re.as<RegExpObject>());
3446 if (!obj) {
3447 goto error;
3448 }
3449 PUSH_OBJECT(*obj);
3450 }
3451 END_CASE(RegExp)
3452
3453 CASE(Zero) { PUSH_INT32(0); }
3454 END_CASE(Zero)
3455
3456 CASE(One) { PUSH_INT32(1); }
3457 END_CASE(One)
3458
3459 CASE(Null) { PUSH_NULL(); }
3460 END_CASE(Null)
3461
3462 CASE(False) { PUSH_BOOLEAN(false); }
3463 END_CASE(False)
3464
3465 CASE(True) { PUSH_BOOLEAN(true); }
3466 END_CASE(True)
3467
3468 CASE(TableSwitch) {
3469 jsbytecode* pc2 = REGS.pc;
3470 int32_t len = GET_JUMP_OFFSET(pc2);
3471
3472 /*
3473 * ECMAv2+ forbids conversion of discriminant, so we will skip to the
3474 * default case if the discriminant isn't already an int jsval. (This
3475 * opcode is emitted only for dense int-domain switches.)
3476 */
3477 const Value& rref = *--REGS.sp;
3478 int32_t i;
3479 if (rref.isInt32()) {
3480 i = rref.toInt32();
3481 } else {
3482 /* Use mozilla::NumberEqualsInt32 to treat -0 (double) as 0. */
3483 if (!rref.isDouble() || !NumberEqualsInt32(rref.toDouble(), &i)) {
3484 ADVANCE_AND_DISPATCH(len);
3485 }
3486 }
3487
3488 pc2 += JUMP_OFFSET_LEN;
3489 int32_t low = GET_JUMP_OFFSET(pc2);
3490 pc2 += JUMP_OFFSET_LEN;
3491 int32_t high = GET_JUMP_OFFSET(pc2);
3492
3493 i = uint32_t(i) - uint32_t(low);
3494 if (uint32_t(i) < uint32_t(high - low + 1)) {
3495 len = script->tableSwitchCaseOffset(REGS.pc, uint32_t(i)) -
3496 script->pcToOffset(REGS.pc);
3497 }
3498 ADVANCE_AND_DISPATCH(len);
3499 }
3500
3501 CASE(Arguments) {
3502 MOZ_ASSERT(script->needsArgsObj());
3503 ArgumentsObject* obj = ArgumentsObject::createExpected(cx, REGS.fp());
3504 if (!obj) {
3505 goto error;
3506 }
3507 PUSH_COPY(ObjectValue(*obj));
3508 }
3509 END_CASE(Arguments)
3510
3511 CASE(Rest) {
3512 ReservedRooted<JSObject*> rest(&rootObject0,
3513 REGS.fp()->createRestParameter(cx));
3514 if (!rest) {
3515 goto error;
3516 }
3517 PUSH_COPY(ObjectValue(*rest));
3518 }
3519 END_CASE(Rest)
3520
3521 CASE(GetAliasedVar) {
3522 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3523 ReservedRooted<Value> val(
3524 &rootValue0, REGS.fp()->aliasedEnvironment(ec).aliasedBinding(ec));
3525
3526 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3527
3528 PUSH_COPY(val);
3529 }
3530 END_CASE(GetAliasedVar)
3531
3532 CASE(GetAliasedDebugVar) {
3533 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3534 ReservedRooted<Value> val(
3535 &rootValue0,
3536 REGS.fp()->aliasedEnvironmentMaybeDebug(ec).aliasedBinding(ec));
3537
3538 ASSERT_UNINITIALIZED_ALIASED_LEXICAL(val);
3539
3540 PUSH_COPY(val);
3541 }
3542 END_CASE(GetAliasedVar)
3543
3544 CASE(SetAliasedVar) {
3545 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3546 EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
3547 SetAliasedVarOperation(cx, script, REGS.pc, obj, ec, REGS.sp[-1],
3548 CheckTDZ);
3549 }
3550 END_CASE(SetAliasedVar)
3551
3552 CASE(ThrowSetConst) {
3553 ReportRuntimeLexicalError(cx, JSMSG_BAD_CONST_ASSIGN, script, REGS.pc);
3554 goto error;
3555 }
3556 END_CASE(ThrowSetConst)
3557
3558 CASE(CheckLexical) {
3559 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3560 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3561 REGS.pc);
3562 goto error;
3563 }
3564 }
3565 END_CASE(CheckLexical)
3566
3567 CASE(CheckAliasedLexical) {
3568 if (REGS.sp[-1].isMagic(JS_UNINITIALIZED_LEXICAL)) {
3569 ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, script,
3570 REGS.pc);
3571 goto error;
3572 }
3573 }
3574 END_CASE(CheckAliasedLexical)
3575
3576 CASE(InitLexical) {
3577 uint32_t i = GET_LOCALNO(REGS.pc);
3578 REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3579 }
3580 END_CASE(InitLexical)
3581
3582 CASE(InitAliasedLexical) {
3583 EnvironmentCoordinate ec = EnvironmentCoordinate(REGS.pc);
3584 EnvironmentObject& obj = REGS.fp()->aliasedEnvironment(ec);
3585 SetAliasedVarOperation(cx, script, REGS.pc, obj, ec, REGS.sp[-1],
3586 DontCheckTDZ);
3587 }
3588 END_CASE(InitAliasedLexical)
3589
3590 CASE(InitGLexical) {
3591 ExtensibleLexicalEnvironmentObject* lexicalEnv;
3592 if (script->hasNonSyntacticScope()) {
3593 lexicalEnv = ®S.fp()->extensibleLexicalEnvironment();
3594 } else {
3595 lexicalEnv = &cx->global()->lexicalEnvironment();
3596 }
3597 HandleValue value = REGS.stackHandleAt(-1);
3598 InitGlobalLexicalOperation(cx, lexicalEnv, script, REGS.pc, value);
3599 }
3600 END_CASE(InitGLexical)
3601
3602 CASE(Uninitialized) { PUSH_MAGIC(JS_UNINITIALIZED_LEXICAL); }
3603 END_CASE(Uninitialized)
3604
3605 CASE(GetArg) {
3606 unsigned i = GET_ARGNO(REGS.pc);
3607 if (script->argsObjAliasesFormals()) {
3608 PUSH_COPY(REGS.fp()->argsObj().arg(i));
3609 } else {
3610 PUSH_COPY(REGS.fp()->unaliasedFormal(i));
3611 }
3612 }
3613 END_CASE(GetArg)
3614
3615 CASE(SetArg) {
3616 unsigned i = GET_ARGNO(REGS.pc);
3617 if (script->argsObjAliasesFormals()) {
3618 REGS.fp()->argsObj().setArg(i, REGS.sp[-1]);
3619 } else {
3620 REGS.fp()->unaliasedFormal(i) = REGS.sp[-1];
3621 }
3622 }
3623 END_CASE(SetArg)
3624
3625 CASE(GetLocal) {
3626 uint32_t i = GET_LOCALNO(REGS.pc);
3627 PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i));
3628
3629 #ifdef DEBUG
3630 if (IsUninitializedLexical(REGS.sp[-1])) {
3631 JSOp next = JSOp(*GetNextPc(REGS.pc));
3632 MOZ_ASSERT(next == JSOp::CheckThis || next == JSOp::CheckReturn ||
3633 next == JSOp::CheckThisReinit || next == JSOp::CheckLexical);
3634 }
3635
3636 /*
3637 * Skip the same-compartment assertion if the local will be immediately
3638 * popped. We do not guarantee sync for dead locals when coming in from
3639 * the method JIT, and a GetLocal followed by Pop is not considered to
3640 * be a use of the variable.
3641 */
3642 if (JSOp(REGS.pc[JSOpLength_GetLocal]) != JSOp::Pop) {
3643 cx->debugOnlyCheck(REGS.sp[-1]);
3644 }
3645 #endif
3646 }
3647 END_CASE(GetLocal)
3648
3649 CASE(SetLocal) {
3650 uint32_t i = GET_LOCALNO(REGS.pc);
3651
3652 MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i)));
3653
3654 REGS.fp()->unaliasedLocal(i) = REGS.sp[-1];
3655 }
3656 END_CASE(SetLocal)
3657
3658 CASE(GlobalOrEvalDeclInstantiation) {
3659 GCThingIndex lastFun = GET_GCTHING_INDEX(REGS.pc);
3660 HandleObject env = REGS.fp()->environmentChain();
3661 if (!GlobalOrEvalDeclInstantiation(cx, env, script, lastFun)) {
3662 goto error;
3663 }
3664 }
3665 END_CASE(GlobalOrEvalDeclInstantiation)
3666
3667 CASE(Lambda) {
3668 /* Load the specified function object literal. */
3669 ReservedRooted<JSFunction*> fun(&rootFunction0,
3670 script->getFunction(REGS.pc));
3671 JSObject* obj = Lambda(cx, fun, REGS.fp()->environmentChain());
3672 if (!obj) {
3673 goto error;
3674 }
3675
3676 MOZ_ASSERT(obj->staticPrototype());
3677 PUSH_OBJECT(*obj);
3678 }
3679 END_CASE(Lambda)
3680
3681 CASE(LambdaArrow) {
3682 /* Load the specified function object literal. */
3683 ReservedRooted<JSFunction*> fun(&rootFunction0,
3684 script->getFunction(REGS.pc));
3685 ReservedRooted<Value> newTarget(&rootValue1, REGS.sp[-1]);
3686 JSObject* obj =
3687 LambdaArrow(cx, fun, REGS.fp()->environmentChain(), newTarget);
3688 if (!obj) {
3689 goto error;
3690 }
3691
3692 MOZ_ASSERT(obj->staticPrototype());
3693 REGS.sp[-1].setObject(*obj);
3694 }
3695 END_CASE(LambdaArrow)
3696
3697 CASE(ToAsyncIter) {
3698 ReservedRooted<Value> nextMethod(&rootValue0, REGS.sp[-1]);
3699 ReservedRooted<JSObject*> iter(&rootObject1, ®S.sp[-2].toObject());
3700 JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter, nextMethod);
3701 if (!asyncIter) {
3702 goto error;
3703 }
3704
3705 REGS.sp--;
3706 REGS.sp[-1].setObject(*asyncIter);
3707 }
3708 END_CASE(ToAsyncIter)
3709
3710 CASE(CanSkipAwait) {
3711 ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
3712 bool canSkip;
3713 if (!CanSkipAwait(cx, val, &canSkip)) {
3714 goto error;
3715 }
3716
3717 PUSH_BOOLEAN(canSkip);
3718 }
3719 END_CASE(CanSkipAwait)
3720
3721 CASE(MaybeExtractAwaitValue) {
3722 MutableHandleValue val = REGS.stackHandleAt(-2);
3723 ReservedRooted<Value> canSkip(&rootValue0, REGS.sp[-1]);
3724
3725 if (canSkip.toBoolean()) {
3726 if (!ExtractAwaitValue(cx, val, val)) {
3727 goto error;
3728 }
3729 }
3730 }
3731 END_CASE(MaybeExtractAwaitValue)
3732
3733 CASE(AsyncAwait) {
3734 MOZ_ASSERT(REGS.stackDepth() >= 2);
3735 ReservedRooted<JSObject*> gen(&rootObject1, ®S.sp[-1].toObject());
3736 ReservedRooted<Value> value(&rootValue0, REGS.sp[-2]);
3737 JSObject* promise =
3738 AsyncFunctionAwait(cx, gen.as<AsyncFunctionGeneratorObject>(), value);
3739 if (!promise) {
3740 goto error;
3741 }
3742
3743 REGS.sp--;
3744 REGS.sp[-1].setObject(*promise);
3745 }
3746 END_CASE(AsyncAwait)
3747
3748 CASE(AsyncResolve) {
3749 MOZ_ASSERT(REGS.stackDepth() >= 2);
3750 auto resolveKind = AsyncFunctionResolveKind(GET_UINT8(REGS.pc));
3751 ReservedRooted<JSObject*> gen(&rootObject1, ®S.sp[-1].toObject());
3752 ReservedRooted<Value> valueOrReason(&rootValue0, REGS.sp[-2]);
3753 JSObject* promise =
3754 AsyncFunctionResolve(cx, gen.as<AsyncFunctionGeneratorObject>(),
3755 valueOrReason, resolveKind);
3756 if (!promise) {
3757 goto error;
3758 }
3759
3760 REGS.sp--;
3761 REGS.sp[-1].setObject(*promise);
3762 }
3763 END_CASE(AsyncResolve)
3764
3765 CASE(SetFunName) {
3766 MOZ_ASSERT(REGS.stackDepth() >= 2);
3767 FunctionPrefixKind prefixKind = FunctionPrefixKind(GET_UINT8(REGS.pc));
3768 ReservedRooted<Value> name(&rootValue0, REGS.sp[-1]);
3769 ReservedRooted<JSFunction*> fun(&rootFunction0,
3770 ®S.sp[-2].toObject().as<JSFunction>());
3771 if (!SetFunctionName(cx, fun, name, prefixKind)) {
3772 goto error;
3773 }
3774
3775 REGS.sp--;
3776 }
3777 END_CASE(SetFunName)
3778
3779 CASE(Callee) {
3780 MOZ_ASSERT(REGS.fp()->isFunctionFrame());
3781 PUSH_COPY(REGS.fp()->calleev());
3782 }
3783 END_CASE(Callee)
3784
3785 CASE(InitPropGetter)
3786 CASE(InitHiddenPropGetter)
3787 CASE(InitPropSetter)
3788 CASE(InitHiddenPropSetter) {
3789 MOZ_ASSERT(REGS.stackDepth() >= 2);
3790
3791 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-2].toObject());
3792 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3793 ReservedRooted<JSObject*> val(&rootObject1, ®S.sp[-1].toObject());
3794
3795 if (!InitPropGetterSetterOperation(cx, REGS.pc, obj, name, val)) {
3796 goto error;
3797 }
3798
3799 REGS.sp--;
3800 }
3801 END_CASE(InitPropGetter)
3802
3803 CASE(InitElemGetter)
3804 CASE(InitHiddenElemGetter)
3805 CASE(InitElemSetter)
3806 CASE(InitHiddenElemSetter) {
3807 MOZ_ASSERT(REGS.stackDepth() >= 3);
3808
3809 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-3].toObject());
3810 ReservedRooted<Value> idval(&rootValue0, REGS.sp[-2]);
3811 ReservedRooted<JSObject*> val(&rootObject1, ®S.sp[-1].toObject());
3812
3813 if (!InitElemGetterSetterOperation(cx, REGS.pc, obj, idval, val)) {
3814 goto error;
3815 }
3816
3817 REGS.sp -= 2;
3818 }
3819 END_CASE(InitElemGetter)
3820
3821 CASE(Hole) { PUSH_MAGIC(JS_ELEMENTS_HOLE); }
3822 END_CASE(Hole)
3823
3824 CASE(NewInit) {
3825 JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
3826
3827 if (!obj) {
3828 goto error;
3829 }
3830 PUSH_OBJECT(*obj);
3831 }
3832 END_CASE(NewInit)
3833
3834 CASE(NewArray) {
3835 uint32_t length = GET_UINT32(REGS.pc);
3836 ArrayObject* obj = NewArrayOperation(cx, length);
3837 if (!obj) {
3838 goto error;
3839 }
3840 PUSH_OBJECT(*obj);
3841 }
3842 END_CASE(NewArray)
3843
3844 CASE(NewObject) {
3845 JSObject* obj = NewObjectOperation(cx, script, REGS.pc);
3846 if (!obj) {
3847 goto error;
3848 }
3849 PUSH_OBJECT(*obj);
3850 }
3851 END_CASE(NewObject)
3852
3853 CASE(MutateProto) {
3854 MOZ_ASSERT(REGS.stackDepth() >= 2);
3855
3856 if (REGS.sp[-1].isObjectOrNull()) {
3857 ReservedRooted<JSObject*> newProto(&rootObject1,
3858 REGS.sp[-1].toObjectOrNull());
3859 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-2].toObject());
3860 MOZ_ASSERT(obj->is<PlainObject>());
3861
3862 if (!SetPrototype(cx, obj, newProto)) {
3863 goto error;
3864 }
3865 }
3866
3867 REGS.sp--;
3868 }
3869 END_CASE(MutateProto)
3870
3871 CASE(InitProp)
3872 CASE(InitLockedProp)
3873 CASE(InitHiddenProp) {
3874 static_assert(JSOpLength_InitProp == JSOpLength_InitLockedProp,
3875 "initprop and initlockedprop must be the same size");
3876 static_assert(JSOpLength_InitProp == JSOpLength_InitHiddenProp,
3877 "initprop and inithiddenprop must be the same size");
3878 /* Load the property's initial value into rval. */
3879 MOZ_ASSERT(REGS.stackDepth() >= 2);
3880 ReservedRooted<Value> rval(&rootValue0, REGS.sp[-1]);
3881
3882 /* Load the object being initialized into lval/obj. */
3883 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-2].toObject());
3884
3885 ReservedRooted<PropertyName*> name(&rootName0, script->getName(REGS.pc));
3886
3887 if (!InitPropertyOperation(cx, JSOp(*REGS.pc), obj, name, rval)) {
3888 goto error;
3889 }
3890
3891 REGS.sp--;
3892 }
3893 END_CASE(InitProp)
3894
3895 CASE(InitElem)
3896 CASE(InitHiddenElem)
3897 CASE(InitLockedElem) {
3898 MOZ_ASSERT(REGS.stackDepth() >= 3);
3899 HandleValue val = REGS.stackHandleAt(-1);
3900 HandleValue id = REGS.stackHandleAt(-2);
3901
3902 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-3].toObject());
3903
3904 if (!InitElemOperation(cx, REGS.pc, obj, id, val)) {
3905 goto error;
3906 }
3907
3908 REGS.sp -= 2;
3909 }
3910 END_CASE(InitElem)
3911
3912 CASE(InitElemArray) {
3913 MOZ_ASSERT(REGS.stackDepth() >= 2);
3914 HandleValue val = REGS.stackHandleAt(-1);
3915 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-2].toObject());
3916
3917 InitElemArrayOperation(cx, REGS.pc, obj.as<ArrayObject>(), val);
3918 REGS.sp--;
3919 }
3920 END_CASE(InitElemArray)
3921
3922 CASE(InitElemInc) {
3923 MOZ_ASSERT(REGS.stackDepth() >= 3);
3924 HandleValue val = REGS.stackHandleAt(-1);
3925
3926 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-3].toObject());
3927
3928 uint32_t index = REGS.sp[-2].toInt32();
3929 if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index, val)) {
3930 goto error;
3931 }
3932
3933 REGS.sp[-2].setInt32(index + 1);
3934 REGS.sp--;
3935 }
3936 END_CASE(InitElemInc)
3937
3938 CASE(Gosub) {
3939 int32_t len = GET_JUMP_OFFSET(REGS.pc);
3940 ADVANCE_AND_DISPATCH(len);
3941 }
3942
3943 CASE(Retsub) {
3944 /* Pop [exception or hole, retsub pc-index]. */
3945 Value rval, lval;
3946 POP_COPY_TO(rval);
3947 POP_COPY_TO(lval);
3948 MOZ_ASSERT(lval.isBoolean());
3949 if (lval.toBoolean()) {
3950 /*
3951 * Exception was pending during finally, throw it *before* we adjust
3952 * pc, because pc indexes into script->trynotes. This turns out not
3953 * to be necessary, but it seems clearer. And it points out a FIXME:
3954 * 350509, due to Igor Bukanov.
3955 */
3956 ReservedRooted<Value> v(&rootValue0, rval);
3957 cx->setPendingExceptionAndCaptureStack(v);
3958 goto error;
3959 }
3960
3961 MOZ_ASSERT(rval.toInt32() >= 0);
3962
3963 uint32_t offset = script->resumeOffsets()[rval.toInt32()];
3964 REGS.pc = script->offsetToPC(offset);
3965 ADVANCE_AND_DISPATCH(0);
3966 }
3967
3968 CASE(Exception) {
3969 PUSH_NULL();
3970 MutableHandleValue res = REGS.stackHandleAt(-1);
3971 if (!GetAndClearException(cx, res)) {
3972 goto error;
3973 }
3974 }
3975 END_CASE(Exception)
3976
3977 CASE(Finally) { CHECK_BRANCH(); }
3978 END_CASE(Finally)
3979
3980 CASE(Throw) {
3981 CHECK_BRANCH();
3982 ReservedRooted<Value> v(&rootValue0);
3983 POP_COPY_TO(v);
3984 MOZ_ALWAYS_FALSE(ThrowOperation(cx, v));
3985 /* let the code at error try to catch the exception. */
3986 goto error;
3987 }
3988
3989 CASE(Instanceof) {
3990 ReservedRooted<Value> rref(&rootValue0, REGS.sp[-1]);
3991 if (HandleValue(rref).isPrimitive()) {
3992 ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, nullptr);
3993 goto error;
3994 }
3995 ReservedRooted<JSObject*> obj(&rootObject0, &rref.toObject());
3996 bool cond = false;
3997 if (!HasInstance(cx, obj, REGS.stackHandleAt(-2), &cond)) {
3998 goto error;
3999 }
4000 REGS.sp--;
4001 REGS.sp[-1].setBoolean(cond);
4002 }
4003 END_CASE(Instanceof)
4004
4005 CASE(Debugger) {
4006 if (!DebugAPI::onDebuggerStatement(cx, REGS.fp())) {
4007 goto error;
4008 }
4009 }
4010 END_CASE(Debugger)
4011
4012 CASE(PushLexicalEnv) {
4013 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4014
4015 // Create block environment and push on scope chain.
4016 if (!REGS.fp()->pushLexicalEnvironment(cx, scope.as<LexicalScope>())) {
4017 goto error;
4018 }
4019 }
4020 END_CASE(PushLexicalEnv)
4021
4022 CASE(PopLexicalEnv) {
4023 #ifdef DEBUG
4024 Scope* scope = script->lookupScope(REGS.pc);
4025 MOZ_ASSERT(scope);
4026 MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
4027 MOZ_ASSERT_IF(scope->is<LexicalScope>(),
4028 scope->as<LexicalScope>().hasEnvironment());
4029 MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
4030 scope->as<ClassBodyScope>().hasEnvironment());
4031 #endif
4032
4033 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4034 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4035 }
4036
4037 // Pop block from scope chain.
4038 REGS.fp()->popOffEnvironmentChain<LexicalEnvironmentObject>();
4039 }
4040 END_CASE(PopLexicalEnv)
4041
4042 CASE(DebugLeaveLexicalEnv) {
4043 #ifdef DEBUG
4044 Scope* scope = script->lookupScope(REGS.pc);
4045 MOZ_ASSERT(scope);
4046 MOZ_ASSERT(scope->is<LexicalScope>() || scope->is<ClassBodyScope>());
4047 MOZ_ASSERT_IF(scope->is<LexicalScope>(),
4048 !scope->as<LexicalScope>().hasEnvironment());
4049 MOZ_ASSERT_IF(scope->is<ClassBodyScope>(),
4050 !scope->as<ClassBodyScope>().hasEnvironment());
4051 #endif
4052 // FIXME: This opcode should not be necessary. The debugger shouldn't
4053 // need help from bytecode to do its job. See bug 927782.
4054
4055 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4056 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4057 }
4058 }
4059 END_CASE(DebugLeaveLexicalEnv)
4060
4061 CASE(FreshenLexicalEnv) {
4062 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4063 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4064 }
4065
4066 if (!REGS.fp()->freshenLexicalEnvironment(cx)) {
4067 goto error;
4068 }
4069 }
4070 END_CASE(FreshenLexicalEnv)
4071
4072 CASE(RecreateLexicalEnv) {
4073 if (MOZ_UNLIKELY(cx->realm()->isDebuggee())) {
4074 DebugEnvironments::onPopLexical(cx, REGS.fp(), REGS.pc);
4075 }
4076
4077 if (!REGS.fp()->recreateLexicalEnvironment(cx)) {
4078 goto error;
4079 }
4080 }
4081 END_CASE(RecreateLexicalEnv)
4082
4083 CASE(PushClassBodyEnv) {
4084 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4085
4086 if (!REGS.fp()->pushClassBodyEnvironment(cx,
4087 scope.as<ClassBodyScope>())) {
4088 goto error;
4089 }
4090 }
4091 END_CASE(PushClassBodyEnv)
4092
4093 CASE(PushVarEnv) {
4094 ReservedRooted<Scope*> scope(&rootScope0, script->getScope(REGS.pc));
4095
4096 if (!REGS.fp()->pushVarEnvironment(cx, scope)) {
4097 goto error;
4098 }
4099 }
4100 END_CASE(PushVarEnv)
4101
4102 CASE(Generator) {
4103 MOZ_ASSERT(!cx->isExceptionPending());
4104 MOZ_ASSERT(REGS.stackDepth() == 0);
4105 JSObject* obj = AbstractGeneratorObject::createFromFrame(cx, REGS.fp());
4106 if (!obj) {
4107 goto error;
4108 }
4109 PUSH_OBJECT(*obj);
4110 }
4111 END_CASE(Generator)
4112
4113 CASE(InitialYield) {
4114 MOZ_ASSERT(!cx->isExceptionPending());
4115 MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
4116 REGS.fp()->isModuleFrame());
4117 MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
4118 REGS.fp()->isFunctionFrame());
4119 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-1].toObject());
4120 POP_RETURN_VALUE();
4121 MOZ_ASSERT(REGS.stackDepth() == 0);
4122 if (!AbstractGeneratorObject::suspend(cx, obj, REGS.fp(), REGS.pc,
4123 script->nfixed())) {
4124 goto error;
4125 }
4126 goto successful_return_continuation;
4127 }
4128
4129 CASE(Yield)
4130 CASE(Await) {
4131 MOZ_ASSERT(!cx->isExceptionPending());
4132 MOZ_ASSERT_IF(script->isModule() && script->isAsync(),
4133 REGS.fp()->isModuleFrame());
4134 MOZ_ASSERT_IF(!script->isModule() && script->isAsync(),
4135 REGS.fp()->isFunctionFrame());
4136 ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-1].toObject());
4137 if (!AbstractGeneratorObject::suspend(
4138 cx, obj, REGS.fp(), REGS.pc,
4139 script->nfixed() + REGS.stackDepth() - 2)) {
4140 goto error;
4141 }
4142
4143 REGS.sp--;
4144 POP_RETURN_VALUE();
4145
4146 goto successful_return_continuation;
4147 }
4148
4149 CASE(ResumeKind) {
4150 GeneratorResumeKind resumeKind = ResumeKindFromPC(REGS.pc);
4151 PUSH_INT32(int32_t(resumeKind));
4152 }
4153 END_CASE(ResumeKind)
4154
4155 CASE(CheckResumeKind) {
4156 int32_t kindInt = REGS.sp[-1].toInt32();
4157 GeneratorResumeKind resumeKind = IntToResumeKind(kindInt);
4158 if (MOZ_UNLIKELY(resumeKind != GeneratorResumeKind::Next)) {
4159 ReservedRooted<Value> val(&rootValue0, REGS.sp[-3]);
4160 Rooted<AbstractGeneratorObject*> gen(
4161 cx, ®S.sp[-2].toObject().as<AbstractGeneratorObject>());
4162 MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx, activation.regs().fp(), gen,
4163 val, resumeKind));
4164 goto error;
4165 }
4166 REGS.sp -= 2;
4167 }
4168 END_CASE(CheckResumeKind)
4169
4170 CASE(Resume) {
4171 {
4172 Rooted<AbstractGeneratorObject*> gen(
4173 cx, ®S.sp[-3].toObject().as<AbstractGeneratorObject>());
4174 ReservedRooted<Value> val(&rootValue0, REGS.sp[-2]);
4175 ReservedRooted<Value> resumeKindVal(&rootValue1, REGS.sp[-1]);
4176
4177 // popInlineFrame expects there to be an additional value on the stack
4178 // to pop off, so leave "gen" on the stack.
4179 REGS.sp -= 1;
4180
4181 if (!AbstractGeneratorObject::resume(cx, activation, gen, val,
4182 resumeKindVal)) {
4183 goto error;
4184 }
4185
4186 JSScript* generatorScript = REGS.fp()->script();
4187 if (cx->realm() != generatorScript->realm()) {
4188 cx->enterRealmOf(generatorScript);
4189 }
4190 SET_SCRIPT(generatorScript);
4191
4192 TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
4193 TraceLoggerEvent scriptEvent(TraceLogger_Scripts, script);
4194 TraceLogStartEvent(logger, scriptEvent);
4195 TraceLogStartEvent(logger, TraceLogger_Interpreter);
4196
4197 if (!DebugAPI::onResumeFrame(cx, REGS.fp())) {
4198 if (cx->isPropagatingForcedReturn()) {
4199 MOZ_ASSERT_IF(
4200 REGS.fp()
4201 ->callee()
4202 .isGenerator(), // as opposed to an async function
4203 gen->isClosed());
4204 }
4205 goto error;
4206 }
4207 }
4208 ADVANCE_AND_DISPATCH(0);
4209 }
4210
4211 CASE(AfterYield) {
4212 // AbstractGeneratorObject::resume takes care of setting the frame's
4213 // debuggee flag.
4214 MOZ_ASSERT_IF(REGS.fp()->script()->isDebuggee(), REGS.fp()->isDebuggee());
4215 COUNT_COVERAGE();
4216 }
4217 END_CASE(AfterYield)
4218
4219 CASE(FinalYieldRval) {
4220 ReservedRooted<JSObject*> gen(&rootObject0, ®S.sp[-1].toObject());
4221 REGS.sp--;
4222 AbstractGeneratorObject::finalSuspend(gen);
4223 goto successful_return_continuation;
4224 }
4225
4226 CASE(CheckClassHeritage) {
4227 HandleValue heritage = REGS.stackHandleAt(-1);
4228
4229 if (!CheckClassHeritageOperation(cx, heritage)) {
4230 goto error;
4231 }
4232 }
4233 END_CASE(CheckClassHeritage)
4234
4235 CASE(BuiltinObject) {
4236 auto kind = BuiltinObjectKind(GET_UINT8(REGS.pc));
4237 JSObject* builtin = BuiltinObjectOperation(cx, kind);
4238 if (!builtin) {
4239 goto error;
4240 }
4241 PUSH_OBJECT(*builtin);
4242 }
4243 END_CASE(BuiltinObject)
4244
4245 CASE(FunWithProto) {
4246 ReservedRooted<JSObject*> proto(&rootObject1, ®S.sp[-1].toObject());
4247
4248 /* Load the specified function object literal. */
4249 ReservedRooted<JSFunction*> fun(&rootFunction0,
4250 script->getFunction(REGS.pc));
4251
4252 JSObject* obj =
4253 FunWithProtoOperation(cx, fun, REGS.fp()->environmentChain(), proto);
4254 if (!obj) {
4255 goto error;
4256 }
4257
4258 REGS.sp[-1].setObject(*obj);
4259 }
4260 END_CASE(FunWithProto)
4261
4262 CASE(ObjWithProto) {
4263 JSObject* obj = ObjectWithProtoOperation(cx, REGS.stackHandleAt(-1));
4264 if (!obj) {
4265 goto error;
4266 }
4267
4268 REGS.sp[-1].setObject(*obj);
4269 }
4270 END_CASE(ObjWithProto)
4271
4272 CASE(InitHomeObject) {
4273 MOZ_ASSERT(REGS.stackDepth() >= 2);
4274
4275 /* Load the function to be initialized */
4276 JSFunction* func = ®S.sp[-2].toObject().as<JSFunction>();
4277 MOZ_ASSERT(func->allowSuperProperty());
4278
4279 /* Load the home object */
4280 JSObject* obj = ®S.sp[-1].toObject();
4281 MOZ_ASSERT(obj->is<PlainObject>() || obj->is<JSFunction>());
4282
4283 func->setExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT,
4284 ObjectValue(*obj));
4285 REGS.sp--;
4286 }
4287 END_CASE(InitHomeObject)
4288
4289 CASE(SuperBase) {
4290 JSFunction& superEnvFunc = REGS.sp[-1].toObject().as<JSFunction>();
4291 MOZ_ASSERT(superEnvFunc.allowSuperProperty());
4292 MOZ_ASSERT(superEnvFunc.baseScript()->needsHomeObject());
4293 const Value& homeObjVal = superEnvFunc.getExtendedSlot(
4294 FunctionExtended::METHOD_HOMEOBJECT_SLOT);
4295
4296 ReservedRooted<JSObject*> homeObj(&rootObject0, &homeObjVal.toObject());
4297 JSObject* superBase = HomeObjectSuperBase(cx, homeObj);
4298 if (!superBase) {
4299 goto error;
4300 }
4301
4302 REGS.sp[-1].setObject(*superBase);
4303 }
4304 END_CASE(SuperBase)
4305
4306 CASE(NewTarget) {
4307 PUSH_COPY(REGS.fp()->newTarget());
4308 MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
4309 }
4310 END_CASE(NewTarget)
4311
4312 CASE(ImportMeta) {
4313 JSObject* metaObject = ImportMetaOperation(cx, script);
4314 if (!metaObject) {
4315 goto error;
4316 }
4317
4318 PUSH_OBJECT(*metaObject);
4319 }
4320 END_CASE(ImportMeta)
4321
4322 CASE(DynamicImport) {
4323 ReservedRooted<Value> specifier(&rootValue1);
4324 POP_COPY_TO(specifier);
4325
4326 JSObject* promise = StartDynamicModuleImport(cx, script, specifier);
4327 if (!promise) goto error;
4328
4329 PUSH_OBJECT(*promise);
4330 }
4331 END_CASE(DynamicImport)
4332
4333 CASE(EnvCallee) {
4334 uint8_t numHops = GET_UINT8(REGS.pc);
4335 JSObject* env = ®S.fp()->environmentChain()->as<EnvironmentObject>();
4336 for (unsigned i = 0; i < numHops; i++) {
4337 env = &env->as<EnvironmentObject>().enclosingEnvironment();
4338 }
4339 PUSH_OBJECT(env->as<CallObject>().callee());
4340 }
4341 END_CASE(EnvCallee)
4342
4343 CASE(SuperFun) {
4344 JSObject* superEnvFunc = ®S.sp[-1].toObject();
4345 JSObject* superFun = SuperFunOperation(superEnvFunc);
4346 REGS.sp[-1].setObjectOrNull(superFun);
4347 }
4348 END_CASE(SuperFun)
4349
4350 CASE(CheckObjCoercible) {
4351 ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4352 if (checkVal.isNullOrUndefined()) {
4353 MOZ_ALWAYS_FALSE(ThrowObjectCoercible(cx, checkVal));
4354 goto error;
4355 }
4356 }
4357 END_CASE(CheckObjCoercible)
4358
4359 CASE(DebugCheckSelfHosted) {
4360 #ifdef DEBUG
4361 ReservedRooted<Value> checkVal(&rootValue0, REGS.sp[-1]);
4362 if (!Debug_CheckSelfHosted(cx, checkVal)) {
4363 goto error;
4364 }
4365 #endif
4366 }
4367 END_CASE(DebugCheckSelfHosted)
4368
4369 CASE(IsConstructing) { PUSH_MAGIC(JS_IS_CONSTRUCTING); }
4370 END_CASE(IsConstructing)
4371
4372 CASE(Inc) {
4373 MutableHandleValue val = REGS.stackHandleAt(-1);
4374 if (!IncOperation(cx, val, val)) {
4375 goto error;
4376 }
4377 }
4378 END_CASE(Inc)
4379
4380 CASE(Dec) {
4381 MutableHandleValue val = REGS.stackHandleAt(-1);
4382 if (!DecOperation(cx, val, val)) {
4383 goto error;
4384 }
4385 }
4386 END_CASE(Dec)
4387
4388 CASE(ToNumeric) {
4389 if (!ToNumeric(cx, REGS.stackHandleAt(-1))) {
4390 goto error;
4391 }
4392 }
4393 END_CASE(ToNumeric)
4394
4395 CASE(BigInt) { PUSH_BIGINT(script->getBigInt(REGS.pc)); }
4396 END_CASE(BigInt)
4397
4398 DEFAULT() {
4399 char numBuf[12];
4400 SprintfLiteral(numBuf, "%d", *REGS.pc);
4401 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4402 JSMSG_BAD_BYTECODE, numBuf);
4403 goto error;
4404 }
4405
4406 } /* interpreter loop */
4407
4408 MOZ_CRASH("Interpreter loop exited via fallthrough");
4409
4410 error:
4411 switch (HandleError(cx, REGS)) {
4412 case SuccessfulReturnContinuation:
4413 goto successful_return_continuation;
4414
4415 case ErrorReturnContinuation:
4416 interpReturnOK = false;
4417 goto return_continuation;
4418
4419 case CatchContinuation:
4420 ADVANCE_AND_DISPATCH(0);
4421
4422 case FinallyContinuation: {
4423 /*
4424 * Push (true, exception) pair for finally to indicate that [retsub]
4425 * should rethrow the exception.
4426 */
4427 ReservedRooted<Value> exception(&rootValue0);
4428 if (!cx->getPendingException(&exception)) {
4429 interpReturnOK = false;
4430 goto return_continuation;
4431 }
4432 PUSH_BOOLEAN(true);
4433 PUSH_COPY(exception);
4434 cx->clearPendingException();
4435 }
4436 ADVANCE_AND_DISPATCH(0);
4437 }
4438
4439 MOZ_CRASH("Invalid HandleError continuation");
4440
4441 exit:
4442 if (MOZ_LIKELY(!frameHalfInitialized)) {
4443 interpReturnOK =
4444 DebugAPI::onLeaveFrame(cx, REGS.fp(), REGS.pc, interpReturnOK);
4445
4446 REGS.fp()->epilogue(cx, REGS.pc);
4447 }
4448
4449 gc::MaybeVerifyBarriers(cx, true);
4450
4451 TraceLogStopEvent(logger, TraceLogger_Engine);
4452 TraceLogStopEvent(logger, scriptEvent);
4453
4454 /*
4455 * This path is used when it's guaranteed the method can be finished
4456 * inside the JIT.
4457 */
4458 leave_on_safe_point:
4459
4460 if (interpReturnOK) {
4461 state.setReturnValue(activation.entryFrame()->returnValue());
4462 }
4463
4464 return interpReturnOK;
4465
4466 prologue_error:
4467 interpReturnOK = false;
4468 frameHalfInitialized = true;
4469 goto prologue_return_continuation;
4470 }
4471
ThrowOperation(JSContext * cx,HandleValue v)4472 bool js::ThrowOperation(JSContext* cx, HandleValue v) {
4473 MOZ_ASSERT(!cx->isExceptionPending());
4474 cx->setPendingExceptionAndCaptureStack(v);
4475 return false;
4476 }
4477
GetProperty(JSContext * cx,HandleValue v,HandlePropertyName name,MutableHandleValue vp)4478 bool js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name,
4479 MutableHandleValue vp) {
4480 if (name == cx->names().length) {
4481 // Fast path for strings, arrays and arguments.
4482 if (GetLengthProperty(v, vp)) {
4483 return true;
4484 }
4485 }
4486
4487 // Optimize common cases like (2).toString() or "foo".valueOf() to not
4488 // create a wrapper object.
4489 if (v.isPrimitive() && !v.isNullOrUndefined()) {
4490 JSObject* proto;
4491
4492 switch (v.type()) {
4493 case ValueType::Double:
4494 case ValueType::Int32:
4495 proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
4496 break;
4497 case ValueType::Boolean:
4498 proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
4499 break;
4500 case ValueType::String:
4501 proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
4502 break;
4503 case ValueType::Symbol:
4504 proto = GlobalObject::getOrCreateSymbolPrototype(cx, cx->global());
4505 break;
4506 case ValueType::BigInt:
4507 proto = GlobalObject::getOrCreateBigIntPrototype(cx, cx->global());
4508 break;
4509 case ValueType::Undefined:
4510 case ValueType::Null:
4511 case ValueType::Magic:
4512 case ValueType::PrivateGCThing:
4513 case ValueType::Object:
4514 MOZ_CRASH("unexpected type");
4515 }
4516
4517 if (!proto) {
4518 return false;
4519 }
4520
4521 if (GetPropertyPure(cx, proto, NameToId(name), vp.address())) {
4522 return true;
4523 }
4524 }
4525
4526 RootedValue receiver(cx, v);
4527 RootedObject obj(
4528 cx, ToObjectFromStackForPropertyAccess(cx, v, JSDVG_SEARCH_STACK, name));
4529 if (!obj) {
4530 return false;
4531 }
4532
4533 return GetProperty(cx, obj, receiver, name, vp);
4534 }
4535
Lambda(JSContext * cx,HandleFunction fun,HandleObject parent)4536 JSObject* js::Lambda(JSContext* cx, HandleFunction fun, HandleObject parent) {
4537 MOZ_ASSERT(!fun->isArrow());
4538
4539 JSFunction* clone;
4540 if (fun->isNativeFun()) {
4541 MOZ_ASSERT(IsAsmJSModule(fun));
4542 clone = CloneAsmJSModuleFunction(cx, fun);
4543 } else {
4544 clone = CloneFunctionObject(cx, fun, parent);
4545 }
4546 if (!clone) {
4547 return nullptr;
4548 }
4549
4550 MOZ_ASSERT(fun->global() == clone->global());
4551 return clone;
4552 }
4553
LambdaArrow(JSContext * cx,HandleFunction fun,HandleObject parent,HandleValue newTargetv)4554 JSObject* js::LambdaArrow(JSContext* cx, HandleFunction fun,
4555 HandleObject parent, HandleValue newTargetv) {
4556 MOZ_ASSERT(fun->isArrow());
4557
4558 JSFunction* clone = CloneFunctionObject(cx, fun, parent);
4559 if (!clone) {
4560 return nullptr;
4561 }
4562
4563 MOZ_ASSERT(clone->isArrow());
4564 clone->setExtendedSlot(0, newTargetv);
4565
4566 MOZ_ASSERT(fun->global() == clone->global());
4567 return clone;
4568 }
4569
BindVarOperation(JSContext * cx,JSObject * envChain)4570 JSObject* js::BindVarOperation(JSContext* cx, JSObject* envChain) {
4571 // Note: BindVarOperation has an unused cx argument because the JIT callVM
4572 // machinery requires this.
4573 return &GetVariablesObject(envChain);
4574 }
4575
ImportMetaOperation(JSContext * cx,HandleScript script)4576 JSObject* js::ImportMetaOperation(JSContext* cx, HandleScript script) {
4577 RootedObject module(cx, GetModuleObjectForScript(script));
4578 MOZ_ASSERT(module);
4579 return GetOrCreateModuleMetaObject(cx, module);
4580 }
4581
BuiltinObjectOperation(JSContext * cx,BuiltinObjectKind kind)4582 JSObject* js::BuiltinObjectOperation(JSContext* cx, BuiltinObjectKind kind) {
4583 return GetOrCreateBuiltinObject(cx, kind);
4584 }
4585
ThrowMsgOperation(JSContext * cx,const unsigned throwMsgKind)4586 bool js::ThrowMsgOperation(JSContext* cx, const unsigned throwMsgKind) {
4587 auto errorNum = ThrowMsgKindToErrNum(ThrowMsgKind(throwMsgKind));
4588 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNum);
4589 return false;
4590 }
4591
GetAndClearExceptionAndStack(JSContext * cx,MutableHandleValue res,MutableHandleSavedFrame stack)4592 bool js::GetAndClearExceptionAndStack(JSContext* cx, MutableHandleValue res,
4593 MutableHandleSavedFrame stack) {
4594 if (!cx->getPendingException(res)) {
4595 return false;
4596 }
4597 stack.set(cx->getPendingExceptionStack());
4598 cx->clearPendingException();
4599
4600 // Allow interrupting deeply nested exception handling.
4601 return CheckForInterrupt(cx);
4602 }
4603
GetAndClearException(JSContext * cx,MutableHandleValue res)4604 bool js::GetAndClearException(JSContext* cx, MutableHandleValue res) {
4605 RootedSavedFrame stack(cx);
4606 return GetAndClearExceptionAndStack(cx, res, &stack);
4607 }
4608
4609 template <bool strict>
DelPropOperation(JSContext * cx,HandleValue val,HandlePropertyName name,bool * res)4610 bool js::DelPropOperation(JSContext* cx, HandleValue val,
4611 HandlePropertyName name, bool* res) {
4612 const int valIndex = -1;
4613 RootedObject obj(cx,
4614 ToObjectFromStackForPropertyAccess(cx, val, valIndex, name));
4615 if (!obj) {
4616 return false;
4617 }
4618
4619 RootedId id(cx, NameToId(name));
4620 ObjectOpResult result;
4621 if (!DeleteProperty(cx, obj, id, result)) {
4622 return false;
4623 }
4624
4625 if (strict) {
4626 if (!result) {
4627 return result.reportError(cx, obj, id);
4628 }
4629 *res = true;
4630 } else {
4631 *res = result.ok();
4632 }
4633 return true;
4634 }
4635
4636 template bool js::DelPropOperation<true>(JSContext* cx, HandleValue val,
4637 HandlePropertyName name, bool* res);
4638 template bool js::DelPropOperation<false>(JSContext* cx, HandleValue val,
4639 HandlePropertyName name, bool* res);
4640
4641 template <bool strict>
DelElemOperation(JSContext * cx,HandleValue val,HandleValue index,bool * res)4642 bool js::DelElemOperation(JSContext* cx, HandleValue val, HandleValue index,
4643 bool* res) {
4644 const int valIndex = -2;
4645 RootedObject obj(
4646 cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, index));
4647 if (!obj) {
4648 return false;
4649 }
4650
4651 RootedId id(cx);
4652 if (!ToPropertyKey(cx, index, &id)) {
4653 return false;
4654 }
4655 ObjectOpResult result;
4656 if (!DeleteProperty(cx, obj, id, result)) {
4657 return false;
4658 }
4659
4660 if (strict) {
4661 if (!result) {
4662 return result.reportError(cx, obj, id);
4663 }
4664 *res = true;
4665 } else {
4666 *res = result.ok();
4667 }
4668 return true;
4669 }
4670
4671 template bool js::DelElemOperation<true>(JSContext*, HandleValue, HandleValue,
4672 bool*);
4673 template bool js::DelElemOperation<false>(JSContext*, HandleValue, HandleValue,
4674 bool*);
4675
SetObjectElement(JSContext * cx,HandleObject obj,HandleValue index,HandleValue value,bool strict)4676 bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index,
4677 HandleValue value, bool strict) {
4678 RootedId id(cx);
4679 if (!ToPropertyKey(cx, index, &id)) {
4680 return false;
4681 }
4682 RootedValue receiver(cx, ObjectValue(*obj));
4683 return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
4684 }
4685
SetObjectElementWithReceiver(JSContext * cx,HandleObject obj,HandleValue index,HandleValue value,HandleValue receiver,bool strict)4686 bool js::SetObjectElementWithReceiver(JSContext* cx, HandleObject obj,
4687 HandleValue index, HandleValue value,
4688 HandleValue receiver, bool strict) {
4689 RootedId id(cx);
4690 if (!ToPropertyKey(cx, index, &id)) {
4691 return false;
4692 }
4693 return SetObjectElementOperation(cx, obj, id, value, receiver, strict);
4694 }
4695
AddValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4696 bool js::AddValues(JSContext* cx, MutableHandleValue lhs,
4697 MutableHandleValue rhs, MutableHandleValue res) {
4698 return AddOperation(cx, lhs, rhs, res);
4699 }
4700
SubValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4701 bool js::SubValues(JSContext* cx, MutableHandleValue lhs,
4702 MutableHandleValue rhs, MutableHandleValue res) {
4703 return SubOperation(cx, lhs, rhs, res);
4704 }
4705
MulValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4706 bool js::MulValues(JSContext* cx, MutableHandleValue lhs,
4707 MutableHandleValue rhs, MutableHandleValue res) {
4708 return MulOperation(cx, lhs, rhs, res);
4709 }
4710
DivValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4711 bool js::DivValues(JSContext* cx, MutableHandleValue lhs,
4712 MutableHandleValue rhs, MutableHandleValue res) {
4713 return DivOperation(cx, lhs, rhs, res);
4714 }
4715
ModValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4716 bool js::ModValues(JSContext* cx, MutableHandleValue lhs,
4717 MutableHandleValue rhs, MutableHandleValue res) {
4718 return ModOperation(cx, lhs, rhs, res);
4719 }
4720
PowValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4721 bool js::PowValues(JSContext* cx, MutableHandleValue lhs,
4722 MutableHandleValue rhs, MutableHandleValue res) {
4723 return PowOperation(cx, lhs, rhs, res);
4724 }
4725
BitNot(JSContext * cx,MutableHandleValue in,MutableHandleValue res)4726 bool js::BitNot(JSContext* cx, MutableHandleValue in, MutableHandleValue res) {
4727 return BitNotOperation(cx, in, res);
4728 }
4729
BitXor(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4730 bool js::BitXor(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4731 MutableHandleValue res) {
4732 return BitXorOperation(cx, lhs, rhs, res);
4733 }
4734
BitOr(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4735 bool js::BitOr(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4736 MutableHandleValue res) {
4737 return BitOrOperation(cx, lhs, rhs, res);
4738 }
4739
BitAnd(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4740 bool js::BitAnd(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4741 MutableHandleValue res) {
4742 return BitAndOperation(cx, lhs, rhs, res);
4743 }
4744
BitLsh(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4745 bool js::BitLsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4746 MutableHandleValue res) {
4747 return BitLshOperation(cx, lhs, rhs, res);
4748 }
4749
BitRsh(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4750 bool js::BitRsh(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4751 MutableHandleValue res) {
4752 return BitRshOperation(cx, lhs, rhs, res);
4753 }
4754
UrshValues(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,MutableHandleValue res)4755 bool js::UrshValues(JSContext* cx, MutableHandleValue lhs,
4756 MutableHandleValue rhs, MutableHandleValue res) {
4757 return UrshOperation(cx, lhs, rhs, res);
4758 }
4759
LessThan(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4760 bool js::LessThan(JSContext* cx, MutableHandleValue lhs, MutableHandleValue rhs,
4761 bool* res) {
4762 return LessThanOperation(cx, lhs, rhs, res);
4763 }
4764
LessThanOrEqual(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4765 bool js::LessThanOrEqual(JSContext* cx, MutableHandleValue lhs,
4766 MutableHandleValue rhs, bool* res) {
4767 return LessThanOrEqualOperation(cx, lhs, rhs, res);
4768 }
4769
GreaterThan(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4770 bool js::GreaterThan(JSContext* cx, MutableHandleValue lhs,
4771 MutableHandleValue rhs, bool* res) {
4772 return GreaterThanOperation(cx, lhs, rhs, res);
4773 }
4774
GreaterThanOrEqual(JSContext * cx,MutableHandleValue lhs,MutableHandleValue rhs,bool * res)4775 bool js::GreaterThanOrEqual(JSContext* cx, MutableHandleValue lhs,
4776 MutableHandleValue rhs, bool* res) {
4777 return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
4778 }
4779
AtomicIsLockFree(JSContext * cx,HandleValue in,int * out)4780 bool js::AtomicIsLockFree(JSContext* cx, HandleValue in, int* out) {
4781 int i;
4782 if (!ToInt32(cx, in, &i)) {
4783 return false;
4784 }
4785 *out = js::jit::AtomicOperations::isLockfreeJS(i);
4786 return true;
4787 }
4788
DeleteNameOperation(JSContext * cx,HandlePropertyName name,HandleObject scopeObj,MutableHandleValue res)4789 bool js::DeleteNameOperation(JSContext* cx, HandlePropertyName name,
4790 HandleObject scopeObj, MutableHandleValue res) {
4791 RootedObject scope(cx), pobj(cx);
4792 PropertyResult prop;
4793 if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop)) {
4794 return false;
4795 }
4796
4797 if (!scope) {
4798 // Return true for non-existent names.
4799 res.setBoolean(true);
4800 return true;
4801 }
4802
4803 ObjectOpResult result;
4804 RootedId id(cx, NameToId(name));
4805 if (!DeleteProperty(cx, scope, id, result)) {
4806 return false;
4807 }
4808
4809 bool status = result.ok();
4810 res.setBoolean(status);
4811
4812 if (status) {
4813 // Deleting a name from the global object removes it from [[VarNames]].
4814 if (pobj == scope && scope->is<GlobalObject>()) {
4815 scope->as<GlobalObject>().realm()->removeFromVarNames(name);
4816 }
4817 }
4818
4819 return true;
4820 }
4821
ImplicitThisOperation(JSContext * cx,HandleObject scopeObj,HandlePropertyName name,MutableHandleValue res)4822 bool js::ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
4823 HandlePropertyName name,
4824 MutableHandleValue res) {
4825 RootedObject obj(cx);
4826 if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj)) {
4827 return false;
4828 }
4829
4830 res.set(ComputeImplicitThis(obj));
4831 return true;
4832 }
4833
GetInitDataPropAttrs(JSOp op)4834 unsigned js::GetInitDataPropAttrs(JSOp op) {
4835 switch (op) {
4836 case JSOp::InitProp:
4837 case JSOp::InitElem:
4838 return JSPROP_ENUMERATE;
4839 case JSOp::InitLockedProp:
4840 case JSOp::InitLockedElem:
4841 return JSPROP_PERMANENT | JSPROP_READONLY;
4842 case JSOp::InitHiddenProp:
4843 case JSOp::InitHiddenElem:
4844 // Non-enumerable, but writable and configurable
4845 return 0;
4846 default:;
4847 }
4848 MOZ_CRASH("Unknown data initprop");
4849 }
4850
InitGetterSetterOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandleId id,HandleObject val)4851 static bool InitGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4852 HandleObject obj, HandleId id,
4853 HandleObject val) {
4854 MOZ_ASSERT(val->isCallable());
4855
4856 JSOp op = JSOp(*pc);
4857
4858 unsigned attrs = 0;
4859 if (!IsHiddenInitOp(op)) {
4860 attrs |= JSPROP_ENUMERATE;
4861 }
4862
4863 if (op == JSOp::InitPropGetter || op == JSOp::InitElemGetter ||
4864 op == JSOp::InitHiddenPropGetter || op == JSOp::InitHiddenElemGetter) {
4865 return DefineAccessorProperty(cx, obj, id, val, nullptr, attrs);
4866 }
4867
4868 MOZ_ASSERT(op == JSOp::InitPropSetter || op == JSOp::InitElemSetter ||
4869 op == JSOp::InitHiddenPropSetter ||
4870 op == JSOp::InitHiddenElemSetter);
4871 return DefineAccessorProperty(cx, obj, id, nullptr, val, attrs);
4872 }
4873
InitPropGetterSetterOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandlePropertyName name,HandleObject val)4874 bool js::InitPropGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4875 HandleObject obj,
4876 HandlePropertyName name,
4877 HandleObject val) {
4878 RootedId id(cx, NameToId(name));
4879 return InitGetterSetterOperation(cx, pc, obj, id, val);
4880 }
4881
InitElemGetterSetterOperation(JSContext * cx,jsbytecode * pc,HandleObject obj,HandleValue idval,HandleObject val)4882 bool js::InitElemGetterSetterOperation(JSContext* cx, jsbytecode* pc,
4883 HandleObject obj, HandleValue idval,
4884 HandleObject val) {
4885 RootedId id(cx);
4886 if (!ToPropertyKey(cx, idval, &id)) {
4887 return false;
4888 }
4889
4890 return InitGetterSetterOperation(cx, pc, obj, id, val);
4891 }
4892
SpreadCallOperation(JSContext * cx,HandleScript script,jsbytecode * pc,HandleValue thisv,HandleValue callee,HandleValue arr,HandleValue newTarget,MutableHandleValue res)4893 bool js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
4894 HandleValue thisv, HandleValue callee,
4895 HandleValue arr, HandleValue newTarget,
4896 MutableHandleValue res) {
4897 RootedArrayObject aobj(cx, &arr.toObject().as<ArrayObject>());
4898 uint32_t length = aobj->length();
4899 JSOp op = JSOp(*pc);
4900 bool constructing = op == JSOp::SpreadNew || op == JSOp::SpreadSuperCall;
4901
4902 // {Construct,Invoke}Args::init does this too, but this gives us a better
4903 // error message.
4904 if (length > ARGS_LENGTH_MAX) {
4905 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
4906 constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
4907 : JSMSG_TOO_MANY_FUN_SPREADARGS);
4908 return false;
4909 }
4910
4911 // Do our own checks for the callee being a function, as Invoke uses the
4912 // expression decompiler to decompile the callee stack operand based on
4913 // the number of arguments. Spread operations have the callee at sp - 3
4914 // when not constructing, and sp - 4 when constructing.
4915 if (callee.isPrimitive()) {
4916 return ReportIsNotFunction(cx, callee, 2 + constructing,
4917 constructing ? CONSTRUCT : NO_CONSTRUCT);
4918 }
4919
4920 if (!callee.toObject().isCallable()) {
4921 return ReportIsNotFunction(cx, callee, 2 + constructing,
4922 constructing ? CONSTRUCT : NO_CONSTRUCT);
4923 }
4924
4925 // The object must be an array with dense elements and no holes. Baseline's
4926 // optimized spread call stubs rely on this.
4927 MOZ_ASSERT(IsPackedArray(aobj));
4928
4929 if (constructing) {
4930 if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget)) {
4931 return false;
4932 }
4933
4934 ConstructArgs cargs(cx);
4935 if (!cargs.init(cx, length)) {
4936 return false;
4937 }
4938
4939 if (!GetElements(cx, aobj, length, cargs.array())) {
4940 return false;
4941 }
4942
4943 RootedObject obj(cx);
4944 if (!Construct(cx, callee, cargs, newTarget, &obj)) {
4945 return false;
4946 }
4947 res.setObject(*obj);
4948 } else {
4949 InvokeArgs args(cx);
4950 if (!args.init(cx, length)) {
4951 return false;
4952 }
4953
4954 if (!GetElements(cx, aobj, length, args.array())) {
4955 return false;
4956 }
4957
4958 if ((op == JSOp::SpreadEval || op == JSOp::StrictSpreadEval) &&
4959 cx->global()->valueIsEval(callee)) {
4960 if (!DirectEval(cx, args.get(0), res)) {
4961 return false;
4962 }
4963 } else {
4964 MOZ_ASSERT(op == JSOp::SpreadCall || op == JSOp::SpreadEval ||
4965 op == JSOp::StrictSpreadEval,
4966 "bad spread opcode");
4967
4968 if (!Call(cx, callee, thisv, args, res)) {
4969 return false;
4970 }
4971 }
4972 }
4973
4974 return true;
4975 }
4976
OptimizeSpreadCall(JSContext * cx,HandleValue arg,bool * optimized)4977 bool js::OptimizeSpreadCall(JSContext* cx, HandleValue arg, bool* optimized) {
4978 // Optimize spread call by skipping spread operation when following
4979 // conditions are met:
4980 // * the argument is an array
4981 // * the array has no hole
4982 // * array[@@iterator] is not modified
4983 // * the array's prototype is Array.prototype
4984 // * Array.prototype[@@iterator] is not modified
4985 // * %ArrayIteratorPrototype%.next is not modified
4986 if (!arg.isObject()) {
4987 *optimized = false;
4988 return true;
4989 }
4990
4991 RootedObject obj(cx, &arg.toObject());
4992 if (!IsPackedArray(obj)) {
4993 *optimized = false;
4994 return true;
4995 }
4996
4997 ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
4998 if (!stubChain) {
4999 return false;
5000 }
5001
5002 return stubChain->tryOptimizeArray(cx, obj.as<ArrayObject>(), optimized);
5003 }
5004
NewObjectOperation(JSContext * cx,HandleScript script,jsbytecode * pc,NewObjectKind newKind)5005 JSObject* js::NewObjectOperation(JSContext* cx, HandleScript script,
5006 jsbytecode* pc,
5007 NewObjectKind newKind /* = GenericObject */) {
5008 // Extract the template object, if one exists, and copy it.
5009 if (JSOp(*pc) == JSOp::NewObject) {
5010 RootedPlainObject baseObject(cx, &script->getObject(pc)->as<PlainObject>());
5011 return CopyTemplateObject(cx, baseObject, newKind);
5012 }
5013
5014 MOZ_ASSERT(JSOp(*pc) == JSOp::NewInit);
5015 return NewBuiltinClassInstanceWithKind<PlainObject>(cx, newKind);
5016 }
5017
NewObjectOperationWithTemplate(JSContext * cx,HandleObject templateObject)5018 JSObject* js::NewObjectOperationWithTemplate(JSContext* cx,
5019 HandleObject templateObject) {
5020 MOZ_ASSERT(cx->realm() == templateObject->nonCCWRealm());
5021
5022 NewObjectKind newKind = GenericObject;
5023 return CopyTemplateObject(cx, templateObject.as<PlainObject>(), newKind);
5024 }
5025
NewPlainObjectBaselineFallback(JSContext * cx,HandleShape shape,gc::AllocKind allocKind,gc::AllocSite * site)5026 JSObject* js::NewPlainObjectBaselineFallback(JSContext* cx, HandleShape shape,
5027 gc::AllocKind allocKind,
5028 gc::AllocSite* site) {
5029 MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
5030 gc::InitialHeap initialHeap = site->initialHeap();
5031 auto r = NativeObject::create(cx, allocKind, initialHeap, shape, site);
5032 return cx->resultToPtr(r);
5033 }
5034
NewPlainObjectOptimizedFallback(JSContext * cx,HandleShape shape,gc::AllocKind allocKind,gc::InitialHeap initialHeap)5035 JSObject* js::NewPlainObjectOptimizedFallback(JSContext* cx, HandleShape shape,
5036 gc::AllocKind allocKind,
5037 gc::InitialHeap initialHeap) {
5038 MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
5039 gc::AllocSite* site = cx->zone()->optimizedAllocSite();
5040 auto r = NativeObject::create(cx, allocKind, initialHeap, shape, site);
5041 return cx->resultToPtr(r);
5042 }
5043
CreateThisWithTemplate(JSContext * cx,HandleObject templateObject)5044 JSObject* js::CreateThisWithTemplate(JSContext* cx,
5045 HandleObject templateObject) {
5046 mozilla::Maybe<AutoRealm> ar;
5047 if (cx->realm() != templateObject->nonCCWRealm()) {
5048 MOZ_ASSERT(cx->compartment() == templateObject->compartment());
5049 ar.emplace(cx, templateObject);
5050 }
5051
5052 NewObjectKind newKind = GenericObject;
5053 return CopyTemplateObject(cx, templateObject.as<PlainObject>(), newKind);
5054 }
5055
NewArrayOperation(JSContext * cx,uint32_t length,NewObjectKind newKind)5056 ArrayObject* js::NewArrayOperation(
5057 JSContext* cx, uint32_t length,
5058 NewObjectKind newKind /* = GenericObject */) {
5059 return NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
5060 }
5061
NewArrayObjectBaselineFallback(JSContext * cx,uint32_t length,gc::AllocKind allocKind,gc::AllocSite * site)5062 ArrayObject* js::NewArrayObjectBaselineFallback(JSContext* cx, uint32_t length,
5063 gc::AllocKind allocKind,
5064 gc::AllocSite* site) {
5065 NewObjectKind newKind =
5066 site->initialHeap() == gc::TenuredHeap ? TenuredObject : GenericObject;
5067 ArrayObject* array =
5068 NewDenseFullyAllocatedArray(cx, length, nullptr, newKind, site);
5069 // It's important that we allocate an object with the alloc kind we were
5070 // expecting so that a new arena gets allocated if the current arena for that
5071 // kind is full.
5072 MOZ_ASSERT_IF(array && array->isTenured(),
5073 array->asTenured().getAllocKind() == allocKind);
5074 return array;
5075 }
5076
NewArrayObjectOptimizedFallback(JSContext * cx,uint32_t length,gc::AllocKind allocKind,NewObjectKind newKind)5077 ArrayObject* js::NewArrayObjectOptimizedFallback(JSContext* cx, uint32_t length,
5078 gc::AllocKind allocKind,
5079 NewObjectKind newKind) {
5080 gc::AllocSite* site = cx->zone()->optimizedAllocSite();
5081 ArrayObject* array =
5082 NewDenseFullyAllocatedArray(cx, length, nullptr, newKind, site);
5083 // It's important that we allocate an object with the alloc kind we were
5084 // expecting so that a new arena gets allocated if the current arena for that
5085 // kind is full.
5086 MOZ_ASSERT_IF(array && array->isTenured(),
5087 array->asTenured().getAllocKind() == allocKind);
5088 return array;
5089 }
5090
ReportRuntimeLexicalError(JSContext * cx,unsigned errorNumber,HandleId id)5091 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5092 HandleId id) {
5093 MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
5094 errorNumber == JSMSG_BAD_CONST_ASSIGN);
5095 if (UniqueChars printable =
5096 IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsIdentifier)) {
5097 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber,
5098 printable.get());
5099 }
5100 }
5101
ReportRuntimeLexicalError(JSContext * cx,unsigned errorNumber,HandlePropertyName name)5102 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5103 HandlePropertyName name) {
5104 RootedId id(cx, NameToId(name));
5105 ReportRuntimeLexicalError(cx, errorNumber, id);
5106 }
5107
ReportRuntimeLexicalError(JSContext * cx,unsigned errorNumber,HandleScript script,jsbytecode * pc)5108 void js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
5109 HandleScript script, jsbytecode* pc) {
5110 JSOp op = JSOp(*pc);
5111 MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical ||
5112 op == JSOp::ThrowSetConst || op == JSOp::GetImport);
5113
5114 RootedPropertyName name(cx);
5115 if (IsLocalOp(op)) {
5116 name = FrameSlotName(script, pc)->asPropertyName();
5117 } else if (IsAliasedVarOp(op)) {
5118 name = EnvironmentCoordinateNameSlow(script, pc);
5119 } else {
5120 MOZ_ASSERT(IsAtomOp(op));
5121 name = script->getName(pc);
5122 }
5123
5124 ReportRuntimeLexicalError(cx, errorNumber, name);
5125 }
5126
ReportRuntimeRedeclaration(JSContext * cx,HandlePropertyName name,const char * redeclKind)5127 void js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
5128 const char* redeclKind) {
5129 if (UniqueChars printable = AtomToPrintableString(cx, name)) {
5130 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5131 JSMSG_REDECLARED_VAR, redeclKind,
5132 printable.get());
5133 }
5134 }
5135
ThrowCheckIsObject(JSContext * cx,CheckIsObjectKind kind)5136 bool js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind) {
5137 switch (kind) {
5138 case CheckIsObjectKind::IteratorNext:
5139 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5140 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
5141 break;
5142 case CheckIsObjectKind::IteratorReturn:
5143 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5144 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "return");
5145 break;
5146 case CheckIsObjectKind::IteratorThrow:
5147 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5148 JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "throw");
5149 break;
5150 case CheckIsObjectKind::GetIterator:
5151 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5152 JSMSG_GET_ITER_RETURNED_PRIMITIVE);
5153 break;
5154 case CheckIsObjectKind::GetAsyncIterator:
5155 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5156 JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
5157 break;
5158 default:
5159 MOZ_CRASH("Unknown kind");
5160 }
5161 return false;
5162 }
5163
ThrowUninitializedThis(JSContext * cx)5164 bool js::ThrowUninitializedThis(JSContext* cx) {
5165 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
5166 JSMSG_UNINITIALIZED_THIS);
5167 return false;
5168 }
5169
ThrowInitializedThis(JSContext * cx)5170 bool js::ThrowInitializedThis(JSContext* cx) {
5171 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
5172 return false;
5173 }
5174
ThrowHomeObjectNotObject(JSContext * cx)5175 bool js::ThrowHomeObjectNotObject(JSContext* cx) {
5176 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
5177 "null", "object");
5178 return false;
5179 }
5180
ThrowObjectCoercible(JSContext * cx,HandleValue value)5181 bool js::ThrowObjectCoercible(JSContext* cx, HandleValue value) {
5182 MOZ_ASSERT(value.isNullOrUndefined());
5183 ReportIsNullOrUndefinedForPropertyAccess(cx, value, JSDVG_SEARCH_STACK);
5184 return false;
5185 }
5186
SetPropertySuper(JSContext * cx,HandleObject obj,HandleValue receiver,HandlePropertyName name,HandleValue rval,bool strict)5187 bool js::SetPropertySuper(JSContext* cx, HandleObject obj, HandleValue receiver,
5188 HandlePropertyName name, HandleValue rval,
5189 bool strict) {
5190 RootedId id(cx, NameToId(name));
5191 ObjectOpResult result;
5192 if (!SetProperty(cx, obj, id, rval, receiver, result)) {
5193 return false;
5194 }
5195
5196 return result.checkStrictModeError(cx, obj, id, strict);
5197 }
5198
LoadAliasedDebugVar(JSContext * cx,JSObject * env,jsbytecode * pc,MutableHandleValue result)5199 bool js::LoadAliasedDebugVar(JSContext* cx, JSObject* env, jsbytecode* pc,
5200 MutableHandleValue result) {
5201 EnvironmentCoordinate ec(pc);
5202
5203 for (unsigned i = ec.hops(); i; i--) {
5204 if (env->is<EnvironmentObject>()) {
5205 env = &env->as<EnvironmentObject>().enclosingEnvironment();
5206 } else {
5207 MOZ_ASSERT(env->is<DebugEnvironmentProxy>());
5208 env = &env->as<DebugEnvironmentProxy>().enclosingEnvironment();
5209 }
5210 }
5211
5212 EnvironmentObject& finalEnv =
5213 env->is<EnvironmentObject>()
5214 ? env->as<EnvironmentObject>()
5215 : env->as<DebugEnvironmentProxy>().environment();
5216
5217 result.set(finalEnv.aliasedBinding(ec));
5218 return true;
5219 }
5220