in js/src/jit/WarpOracle.cpp [293:746]
AbortReasonOr<WarpScriptSnapshot*> WarpScriptOracle::createScriptSnapshot() {
MOZ_ASSERT(script_->hasJitScript());
if (!script_->jitScript()->ensureHasCachedIonData(cx_, script_)) {
return abort(AbortReason::Error);
}
if (script_->failedBoundsCheck()) {
oracle_->bailoutInfo().setFailedBoundsCheck();
}
if (script_->failedLexicalCheck()) {
oracle_->bailoutInfo().setFailedLexicalCheck();
}
WarpEnvironment environment = createEnvironment();
// Unfortunately LinkedList<> asserts the list is empty in its destructor.
// Clear the list if we abort compilation.
WarpOpSnapshotList opSnapshots;
auto autoClearOpSnapshots =
mozilla::MakeScopeExit([&] { opSnapshots.clear(); });
ModuleObject* moduleObject = nullptr;
// Analyze the bytecode. Abort compilation for unsupported ops and create
// WarpOpSnapshots.
for (BytecodeLocation loc : AllBytecodesIterable(script_)) {
JSOp op = loc.getOp();
uint32_t offset = loc.bytecodeToOffset(script_);
switch (op) {
case JSOp::Arguments: {
MOZ_ASSERT(script_->needsArgsObj());
bool mapped = script_->hasMappedArgsObj();
ArgumentsObject* templateObj =
script_->global().maybeArgumentsTemplateObject(mapped);
if (!AddOpSnapshot<WarpArguments>(alloc_, opSnapshots, offset,
templateObj)) {
return abort(AbortReason::Alloc);
}
break;
}
case JSOp::RegExp: {
bool hasShared = loc.getRegExp(script_)->hasShared();
if (!AddOpSnapshot<WarpRegExp>(alloc_, opSnapshots, offset,
hasShared)) {
return abort(AbortReason::Alloc);
}
break;
}
case JSOp::FunctionThis:
if (!script_->strict() && script_->hasNonSyntacticScope()) {
// Abort because MBoxNonStrictThis doesn't support non-syntactic
// scopes (a deprecated SpiderMonkey mechanism). If this becomes an
// issue we could support it by refactoring GetFunctionThis to not
// take a frame pointer and then call that.
return abort(AbortReason::Disable,
"JSOp::FunctionThis with non-syntactic scope");
}
break;
case JSOp::GlobalThis:
MOZ_ASSERT(!script_->hasNonSyntacticScope());
break;
case JSOp::BuiltinObject: {
// If we already resolved this built-in we can bake it in.
auto kind = loc.getBuiltinObjectKind();
if (JSObject* proto = MaybeGetBuiltinObject(cx_->global(), kind)) {
if (!AddOpSnapshot<WarpBuiltinObject>(alloc_, opSnapshots, offset,
proto)) {
return abort(AbortReason::Alloc);
}
}
break;
}
case JSOp::GetIntrinsic: {
// If we already cloned this intrinsic we can bake it in.
// NOTE: When the initializer runs in a content global, we also have to
// worry about nursery objects. These quickly tenure and stay that
// way so this is only a temporary problem.
PropertyName* name = loc.getPropertyName(script_);
Value val;
if (cx_->global()->maybeGetIntrinsicValue(name, &val, cx_) &&
JS::GCPolicy<Value>::isTenured(val)) {
if (!AddOpSnapshot<WarpGetIntrinsic>(alloc_, opSnapshots, offset,
val)) {
return abort(AbortReason::Alloc);
}
}
break;
}
case JSOp::ImportMeta: {
if (!moduleObject) {
moduleObject = GetModuleObjectForScript(script_);
MOZ_ASSERT(moduleObject->isTenured());
}
break;
}
case JSOp::GetImport: {
PropertyName* name = loc.getPropertyName(script_);
if (!AddWarpGetImport(alloc_, opSnapshots, offset, script_, name)) {
return abort(AbortReason::Alloc);
}
break;
}
case JSOp::Lambda: {
JSFunction* fun = loc.getFunction(script_);
if (IsAsmJSModule(fun)) {
return abort(AbortReason::Disable, "asm.js module function lambda");
}
break;
}
case JSOp::GetElemSuper: {
#if defined(JS_CODEGEN_X86)
// x86 does not have enough registers.
return abort(AbortReason::Disable,
"GetElemSuper is not supported on x86");
#else
MOZ_TRY(maybeInlineIC(opSnapshots, loc));
break;
#endif
}
case JSOp::Rest: {
if (Shape* shape =
script_->global().maybeArrayShapeWithDefaultProto()) {
if (!AddOpSnapshot<WarpRest>(alloc_, opSnapshots, offset, shape)) {
return abort(AbortReason::Alloc);
}
}
break;
}
case JSOp::BindUnqualifiedGName: {
GlobalObject* global = &script_->global();
PropertyName* name = loc.getPropertyName(script_);
if (JSObject* env =
MaybeOptimizeBindUnqualifiedGlobalName(global, name)) {
MOZ_ASSERT(env->isTenured());
if (!AddOpSnapshot<WarpBindUnqualifiedGName>(alloc_, opSnapshots,
offset, env)) {
return abort(AbortReason::Alloc);
}
} else {
MOZ_TRY(maybeInlineIC(opSnapshots, loc));
}
break;
}
case JSOp::PushVarEnv: {
Rooted<VarScope*> scope(cx_, &loc.getScope(script_)->as<VarScope>());
auto* templateObj =
VarEnvironmentObject::createTemplateObject(cx_, scope);
if (!templateObj) {
return abort(AbortReason::Alloc);
}
MOZ_ASSERT(templateObj->isTenured());
if (!AddOpSnapshot<WarpVarEnvironment>(alloc_, opSnapshots, offset,
templateObj)) {
return abort(AbortReason::Alloc);
}
break;
}
case JSOp::PushLexicalEnv:
case JSOp::FreshenLexicalEnv:
case JSOp::RecreateLexicalEnv: {
Rooted<LexicalScope*> scope(cx_,
&loc.getScope(script_)->as<LexicalScope>());
auto* templateObj =
BlockLexicalEnvironmentObject::createTemplateObject(cx_, scope);
if (!templateObj) {
return abort(AbortReason::Alloc);
}
MOZ_ASSERT(templateObj->isTenured());
if (!AddOpSnapshot<WarpLexicalEnvironment>(alloc_, opSnapshots, offset,
templateObj)) {
return abort(AbortReason::Alloc);
}
break;
}
case JSOp::PushClassBodyEnv: {
Rooted<ClassBodyScope*> scope(
cx_, &loc.getScope(script_)->as<ClassBodyScope>());
auto* templateObj =
ClassBodyLexicalEnvironmentObject::createTemplateObject(cx_, scope);
if (!templateObj) {
return abort(AbortReason::Alloc);
}
MOZ_ASSERT(templateObj->isTenured());
if (!AddOpSnapshot<WarpClassBodyEnvironment>(alloc_, opSnapshots,
offset, templateObj)) {
return abort(AbortReason::Alloc);
}
break;
}
case JSOp::String:
if (!loc.atomizeString(cx_, script_)) {
return abort(AbortReason::Alloc);
}
break;
case JSOp::GetName:
case JSOp::GetGName:
case JSOp::GetProp:
case JSOp::GetElem:
case JSOp::SetProp:
case JSOp::StrictSetProp:
case JSOp::Call:
case JSOp::CallContent:
case JSOp::CallIgnoresRv:
case JSOp::CallIter:
case JSOp::CallContentIter:
case JSOp::New:
case JSOp::NewContent:
case JSOp::SuperCall:
case JSOp::SpreadCall:
case JSOp::SpreadNew:
case JSOp::SpreadSuperCall:
case JSOp::ToNumeric:
case JSOp::Pos:
case JSOp::Inc:
case JSOp::Dec:
case JSOp::Neg:
case JSOp::BitNot:
case JSOp::Iter:
case JSOp::Eq:
case JSOp::Ne:
case JSOp::Lt:
case JSOp::Le:
case JSOp::Gt:
case JSOp::Ge:
case JSOp::StrictEq:
case JSOp::StrictNe:
case JSOp::BindName:
case JSOp::BindUnqualifiedName:
case JSOp::GetBoundName:
case JSOp::Add:
case JSOp::Sub:
case JSOp::Mul:
case JSOp::Div:
case JSOp::Mod:
case JSOp::Pow:
case JSOp::BitAnd:
case JSOp::BitOr:
case JSOp::BitXor:
case JSOp::Lsh:
case JSOp::Rsh:
case JSOp::Ursh:
case JSOp::In:
case JSOp::HasOwn:
case JSOp::CheckPrivateField:
case JSOp::Instanceof:
case JSOp::GetPropSuper:
case JSOp::InitProp:
case JSOp::InitLockedProp:
case JSOp::InitHiddenProp:
case JSOp::InitElem:
case JSOp::InitHiddenElem:
case JSOp::InitLockedElem:
case JSOp::InitElemInc:
case JSOp::SetName:
case JSOp::StrictSetName:
case JSOp::SetGName:
case JSOp::StrictSetGName:
case JSOp::InitGLexical:
case JSOp::SetElem:
case JSOp::StrictSetElem:
case JSOp::ToPropertyKey:
case JSOp::OptimizeSpreadCall:
case JSOp::Typeof:
case JSOp::TypeofExpr:
case JSOp::TypeofEq:
case JSOp::NewObject:
case JSOp::NewInit:
case JSOp::NewArray:
case JSOp::JumpIfFalse:
case JSOp::JumpIfTrue:
case JSOp::And:
case JSOp::Or:
case JSOp::Not:
case JSOp::CloseIter:
case JSOp::OptimizeGetIterator:
MOZ_TRY(maybeInlineIC(opSnapshots, loc));
break;
case JSOp::Nop:
case JSOp::NopDestructuring:
case JSOp::NopIsAssignOp:
case JSOp::TryDestructuring:
case JSOp::Lineno:
case JSOp::DebugLeaveLexicalEnv:
case JSOp::Undefined:
case JSOp::Void:
case JSOp::Null:
case JSOp::Hole:
case JSOp::Uninitialized:
case JSOp::IsConstructing:
case JSOp::False:
case JSOp::True:
case JSOp::Zero:
case JSOp::One:
case JSOp::Int8:
case JSOp::Uint16:
case JSOp::Uint24:
case JSOp::Int32:
case JSOp::Double:
case JSOp::BigInt:
case JSOp::Symbol:
case JSOp::Pop:
case JSOp::PopN:
case JSOp::Dup:
case JSOp::Dup2:
case JSOp::DupAt:
case JSOp::Swap:
case JSOp::Pick:
case JSOp::Unpick:
case JSOp::GetLocal:
case JSOp::SetLocal:
case JSOp::InitLexical:
case JSOp::GetArg:
case JSOp::GetFrameArg:
case JSOp::SetArg:
case JSOp::ArgumentsLength:
case JSOp::GetActualArg:
case JSOp::JumpTarget:
case JSOp::LoopHead:
case JSOp::Case:
case JSOp::Default:
case JSOp::Coalesce:
case JSOp::Goto:
case JSOp::DebugCheckSelfHosted:
case JSOp::DynamicImport:
case JSOp::ToString:
case JSOp::GlobalOrEvalDeclInstantiation:
case JSOp::BindVar:
case JSOp::MutateProto:
case JSOp::Callee:
case JSOp::ToAsyncIter:
case JSOp::ObjWithProto:
case JSOp::GetAliasedVar:
case JSOp::SetAliasedVar:
case JSOp::InitAliasedLexical:
case JSOp::EnvCallee:
case JSOp::MoreIter:
case JSOp::EndIter:
case JSOp::IsNoIter:
case JSOp::IsNullOrUndefined:
case JSOp::DelProp:
case JSOp::StrictDelProp:
case JSOp::DelElem:
case JSOp::StrictDelElem:
case JSOp::SetFunName:
case JSOp::PopLexicalEnv:
case JSOp::ImplicitThis:
case JSOp::CheckClassHeritage:
case JSOp::CheckThis:
case JSOp::CheckThisReinit:
case JSOp::Generator:
case JSOp::AfterYield:
case JSOp::FinalYieldRval:
case JSOp::AsyncResolve:
case JSOp::AsyncReject:
case JSOp::CheckResumeKind:
case JSOp::CanSkipAwait:
case JSOp::MaybeExtractAwaitValue:
case JSOp::AsyncAwait:
case JSOp::Await:
case JSOp::CheckReturn:
case JSOp::CheckLexical:
case JSOp::CheckAliasedLexical:
case JSOp::InitHomeObject:
case JSOp::SuperBase:
case JSOp::SuperFun:
case JSOp::InitElemArray:
case JSOp::InitPropGetter:
case JSOp::InitPropSetter:
case JSOp::InitHiddenPropGetter:
case JSOp::InitHiddenPropSetter:
case JSOp::InitElemGetter:
case JSOp::InitElemSetter:
case JSOp::InitHiddenElemGetter:
case JSOp::InitHiddenElemSetter:
case JSOp::NewTarget:
case JSOp::Object:
case JSOp::CallSiteObj:
case JSOp::CheckIsObj:
case JSOp::CheckObjCoercible:
case JSOp::FunWithProto:
case JSOp::Debugger:
case JSOp::TableSwitch:
case JSOp::Exception:
case JSOp::ExceptionAndStack:
case JSOp::Throw:
case JSOp::ThrowWithStack:
case JSOp::ThrowSetConst:
case JSOp::SetRval:
case JSOp::GetRval:
case JSOp::Return:
case JSOp::RetRval:
case JSOp::InitialYield:
case JSOp::Yield:
case JSOp::ResumeKind:
case JSOp::ThrowMsg:
case JSOp::Try:
case JSOp::Finally:
case JSOp::NewPrivateName:
case JSOp::StrictConstantEq:
case JSOp::StrictConstantNe:
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
case JSOp::AddDisposable:
case JSOp::TakeDisposeCapability:
case JSOp::CreateSuppressedError:
#endif
// Supported by WarpBuilder. Nothing to do.
break;
// Unsupported ops. Don't use a 'default' here, we want to trigger a
// compiler warning when adding a new JSOp.
#define DEF_CASE(OP) case JSOp::OP:
WARP_UNSUPPORTED_OPCODE_LIST(DEF_CASE)
#undef DEF_CASE
#ifdef DEBUG
return abort(AbortReason::Disable, "Unsupported opcode: %s",
CodeName(op));
#else
return abort(AbortReason::Disable, "Unsupported opcode: %u",
uint8_t(op));
#endif
}
}
auto* scriptSnapshot = new (alloc_.fallible()) WarpScriptSnapshot(
script_, environment, std::move(opSnapshots), moduleObject);
if (!scriptSnapshot) {
return abort(AbortReason::Alloc);
}
autoClearOpSnapshots.release();
return scriptSnapshot;
}