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