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