зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1520452 part 1 - Move script field from BaselineCodeGen to BaselineCompilerHandler. r=djvj
Differential Revision: https://phabricator.services.mozilla.com/D16689 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
05130382c0
Коммит
85e0ee0505
|
@ -64,7 +64,6 @@ BaselineCodeGen<Handler>::BaselineCodeGen(JSContext* cx, TempAllocator& alloc,
|
|||
HandlerArgs&&... args)
|
||||
: handler(masm, std::forward<HandlerArgs>(args)...),
|
||||
cx(cx),
|
||||
script(script),
|
||||
ionCompileable_(jit::IsIonEnabled(cx) && CanIonCompileScript(cx, script)),
|
||||
alloc_(alloc),
|
||||
analysis_(alloc, script),
|
||||
|
@ -130,7 +129,7 @@ bool BaselineCompiler::init() {
|
|||
bool BaselineCompiler::addPCMappingEntry(bool addIndexEntry) {
|
||||
// Don't add multiple entries for a single pc.
|
||||
size_t nentries = pcMappingEntries_.length();
|
||||
uint32_t pcOffset = script->pcToOffset(handler.pc());
|
||||
uint32_t pcOffset = handler.script()->pcToOffset(handler.pc());
|
||||
if (nentries > 0 && pcMappingEntries_[nentries - 1].pcOffset == pcOffset) {
|
||||
return true;
|
||||
}
|
||||
|
@ -145,6 +144,7 @@ bool BaselineCompiler::addPCMappingEntry(bool addIndexEntry) {
|
|||
}
|
||||
|
||||
MethodStatus BaselineCompiler::compile() {
|
||||
JSScript* script = handler.script();
|
||||
JitSpew(JitSpew_BaselineScripts, "Baseline compiling script %s:%u:%u (%p)",
|
||||
script->filename(), script->lineno(), script->column(), script);
|
||||
|
||||
|
@ -464,6 +464,7 @@ bool BaselineCompilerCodeGen::emitNextIC() {
|
|||
// ICEntry order in ICScript: first the non-op IC entries for |this| and
|
||||
// formal arguments, then the for-op IC entries for JOF_IC ops.
|
||||
|
||||
JSScript* script = handler.script();
|
||||
uint32_t pcOffset = script->pcToOffset(handler.pc());
|
||||
|
||||
// We don't use every ICEntry and we can skip unreachable ops, so we have
|
||||
|
@ -680,9 +681,53 @@ void BaselineCompiler::emitIsDebuggeeCheck() {
|
|||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::loadScript(Register dest) {
|
||||
masm.movePtr(ImmGCPtr(handler.script()), dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineInterpreterCodeGen::loadScript(Register dest) {
|
||||
MOZ_CRASH("NYI: interpreter loadScript");
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::loadGlobalLexicalEnvironment(Register dest) {
|
||||
masm.movePtr(ImmGCPtr(&cx->global()->lexicalEnvironment()), dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineInterpreterCodeGen::loadGlobalLexicalEnvironment(Register dest) {
|
||||
MOZ_CRASH("NYI: interpreter loadGlobalLexicalEnvironment");
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::pushGlobalLexicalEnvironmentValue(
|
||||
ValueOperand scratch) {
|
||||
frame.push(ObjectValue(cx->global()->lexicalEnvironment()));
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineInterpreterCodeGen::pushGlobalLexicalEnvironmentValue(
|
||||
ValueOperand scratch) {
|
||||
loadGlobalLexicalEnvironment(scratch.scratchReg());
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, scratch.scratchReg(), scratch);
|
||||
frame.push(scratch);
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::loadGlobalThisValue(ValueOperand dest) {
|
||||
masm.moveValue(cx->global()->lexicalEnvironment().thisValue(), dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineInterpreterCodeGen::loadGlobalThisValue(ValueOperand dest) {
|
||||
MOZ_CRASH("NYI: interpreter loadGlobalThisValue");
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::pushScriptArg() {
|
||||
pushArg(ImmGCPtr(script));
|
||||
pushArg(ImmGCPtr(handler.script()));
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -703,7 +748,7 @@ void BaselineInterpreterCodeGen::pushBytecodePCArg() {
|
|||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::pushScriptNameArg() {
|
||||
pushArg(ImmGCPtr(script->getName(handler.pc())));
|
||||
pushArg(ImmGCPtr(handler.script()->getName(handler.pc())));
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -713,6 +758,7 @@ void BaselineInterpreterCodeGen::pushScriptNameArg() {
|
|||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::pushScriptObjectArg(ScriptObjectType type) {
|
||||
JSScript* script = handler.script();
|
||||
switch (type) {
|
||||
case ScriptObjectType::RegExp:
|
||||
pushArg(ImmGCPtr(script->getRegExp(handler.pc())));
|
||||
|
@ -734,7 +780,7 @@ void BaselineInterpreterCodeGen::pushScriptObjectArg(ScriptObjectType type) {
|
|||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::pushScriptScopeArg() {
|
||||
pushArg(ImmGCPtr(script->getScope(handler.pc())));
|
||||
pushArg(ImmGCPtr(handler.script()->getScope(handler.pc())));
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -828,7 +874,7 @@ bool BaselineCompiler::initEnvironmentChain() {
|
|||
phase = CHECK_OVER_RECURSED;
|
||||
}
|
||||
|
||||
RootedFunction fun(cx, function());
|
||||
RootedFunction fun(cx, handler.function());
|
||||
if (fun) {
|
||||
// Use callee->environment as env chain. Note that we do this also
|
||||
// for needsSomeEnvironmentObject functions, so that the env chain
|
||||
|
@ -850,10 +896,10 @@ bool BaselineCompiler::initEnvironmentChain() {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
} else if (module()) {
|
||||
} else if (handler.module()) {
|
||||
// Modules use a pre-created scope object.
|
||||
Register scope = R1.scratchReg();
|
||||
masm.movePtr(ImmGCPtr(&module()->initialEnvironment()), scope);
|
||||
masm.movePtr(ImmGCPtr(&handler.module()->initialEnvironment()), scope);
|
||||
masm.storePtr(scope, frame.addressOfEnvironmentChain());
|
||||
} else {
|
||||
// EnvironmentChain pointer in BaselineFrame has already been initialized
|
||||
|
@ -915,6 +961,7 @@ bool BaselineCompilerCodeGen::emitWarmUpCounterIncrement() {
|
|||
Register countReg = R0.scratchReg();
|
||||
Address warmUpCounterAddr(scriptReg, JSScript::offsetOfWarmUpCounter());
|
||||
|
||||
JSScript* script = handler.script();
|
||||
masm.movePtr(ImmGCPtr(script), scriptReg);
|
||||
masm.load32(warmUpCounterAddr, countReg);
|
||||
masm.add32(Imm32(1), countReg);
|
||||
|
@ -980,7 +1027,7 @@ bool BaselineInterpreterCodeGen::emitWarmUpCounterIncrement() {
|
|||
}
|
||||
|
||||
bool BaselineCompiler::emitArgumentTypeChecks() {
|
||||
if (!function()) {
|
||||
if (!handler.function()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -991,7 +1038,9 @@ bool BaselineCompiler::emitArgumentTypeChecks() {
|
|||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < function()->nargs(); i++) {
|
||||
size_t nargs = handler.function()->nargs();
|
||||
|
||||
for (size_t i = 0; i < nargs; i++) {
|
||||
frame.pushArg(i);
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
|
@ -1007,6 +1056,7 @@ bool BaselineCompiler::emitDebugTrap() {
|
|||
MOZ_ASSERT(compileDebugInstrumentation());
|
||||
MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
|
||||
|
||||
JSScript* script = handler.script();
|
||||
bool enabled =
|
||||
script->stepModeEnabled() || script->hasBreakpointsAt(handler.pc());
|
||||
|
||||
|
@ -1054,7 +1104,7 @@ bool BaselineCompiler::emitTraceLoggerEnter() {
|
|||
masm.loadTraceLogger(loggerReg);
|
||||
|
||||
// Script start.
|
||||
masm.movePtr(ImmGCPtr(script), scriptReg);
|
||||
masm.movePtr(ImmGCPtr(handler.script()), scriptReg);
|
||||
masm.loadPtr(Address(scriptReg, JSScript::offsetOfBaselineScript()),
|
||||
scriptReg);
|
||||
Address scriptEvent(scriptReg,
|
||||
|
@ -1347,6 +1397,72 @@ void BaselineInterpreterCodeGen::emitTestBooleanTruthy(bool branchIfTrue,
|
|||
masm.bind(&done);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename F1, typename F2>
|
||||
MOZ_MUST_USE bool BaselineCompilerCodeGen::emitTestScriptFlag(
|
||||
JSScript::ImmutableFlags flag, const F1& ifSet, const F2& ifNotSet,
|
||||
Register scratch) {
|
||||
return handler.script()->hasFlag(flag) ? ifSet() : ifNotSet();
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename F1, typename F2>
|
||||
MOZ_MUST_USE bool BaselineInterpreterCodeGen::emitTestScriptFlag(
|
||||
JSScript::ImmutableFlags flag, const F1& ifSet, const F2& ifNotSet,
|
||||
Register scratch) {
|
||||
Label flagNotSet, done;
|
||||
loadScript(scratch);
|
||||
masm.branchTest32(Assembler::Zero,
|
||||
Address(scratch, JSScript::offsetOfImmutableFlags()),
|
||||
Imm32(uint32_t(flag)), &flagNotSet);
|
||||
{
|
||||
if (!ifSet()) {
|
||||
return false;
|
||||
}
|
||||
masm.jump(&done);
|
||||
}
|
||||
masm.bind(&flagNotSet);
|
||||
{
|
||||
if (!ifNotSet()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename F>
|
||||
MOZ_MUST_USE bool BaselineCompilerCodeGen::emitTestScriptFlag(
|
||||
JSScript::ImmutableFlags flag, bool value, const F& emit,
|
||||
Register scratch) {
|
||||
if (handler.script()->hasFlag(flag) == value) {
|
||||
return emit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename F>
|
||||
MOZ_MUST_USE bool BaselineInterpreterCodeGen::emitTestScriptFlag(
|
||||
JSScript::ImmutableFlags flag, bool value, const F& emit,
|
||||
Register scratch) {
|
||||
Label done;
|
||||
loadScript(scratch);
|
||||
masm.branchTest32(value ? Assembler::Zero : Assembler::NonZero,
|
||||
Address(scratch, JSScript::offsetOfImmutableFlags()),
|
||||
Imm32(uint32_t(flag)), &done);
|
||||
{
|
||||
if (!emit()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_GOTO() {
|
||||
frame.syncStack(0);
|
||||
|
@ -1473,11 +1589,14 @@ bool BaselineCodeGen<Handler>::emit_JSOP_LOOPENTRY() {
|
|||
if (!emitWarmUpCounterIncrement()) {
|
||||
return false;
|
||||
}
|
||||
if (script->trackRecordReplayProgress()) {
|
||||
|
||||
auto incCounter = [this]() {
|
||||
masm.inc64(
|
||||
AbsoluteAddress(mozilla::recordreplay::ExecutionProgressCounter()));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return emitTestScriptFlag(JSScript::ImmutableFlags::TrackRecordReplayProgress,
|
||||
true, incCounter, R2.scratchReg());
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
|
@ -1611,7 +1730,8 @@ static const VMFunction ThrowBadDerivedReturnInfo =
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_CHECKRETURN() {
|
||||
MOZ_ASSERT(script->isDerivedClassConstructor());
|
||||
MOZ_ASSERT_IF(handler.maybeScript(),
|
||||
handler.maybeScript()->isDerivedClassConstructor());
|
||||
|
||||
// Load |this| in R0, return value in R1.
|
||||
frame.popRegsAndSync(1);
|
||||
|
@ -1649,16 +1769,11 @@ static const VMFunction GetFunctionThisInfo = FunctionInfo<GetFunctionThisFn>(
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_FUNCTIONTHIS() {
|
||||
MOZ_ASSERT(function());
|
||||
MOZ_ASSERT(!function()->isArrow());
|
||||
MOZ_ASSERT_IF(handler.maybeFunction(), !handler.maybeFunction()->isArrow());
|
||||
|
||||
frame.pushThis();
|
||||
|
||||
// In strict mode code, |this| is left alone.
|
||||
if (script->strict()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto boxThis = [this]() {
|
||||
// Load |thisv| in R0. Skip the call if it's already an object.
|
||||
Label skipCall;
|
||||
frame.popRegsAndSync(1);
|
||||
|
@ -1676,6 +1791,11 @@ bool BaselineCodeGen<Handler>::emit_JSOP_FUNCTIONTHIS() {
|
|||
masm.bind(&skipCall);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
};
|
||||
|
||||
// In strict mode code, |this| is left alone.
|
||||
return emitTestScriptFlag(JSScript::ImmutableFlags::Strict, false, boxThis,
|
||||
R2.scratchReg());
|
||||
}
|
||||
|
||||
typedef void (*GetNonSyntacticGlobalThisFn)(JSContext*, HandleObject,
|
||||
|
@ -1688,14 +1808,7 @@ template <typename Handler>
|
|||
bool BaselineCodeGen<Handler>::emit_JSOP_GLOBALTHIS() {
|
||||
frame.syncStack(0);
|
||||
|
||||
if (!script->hasNonSyntacticScope()) {
|
||||
LexicalEnvironmentObject* globalLexical =
|
||||
&script->global().lexicalEnvironment();
|
||||
masm.moveValue(globalLexical->thisValue(), R0);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto getNonSyntacticThis = [this]() {
|
||||
prepareVMCall();
|
||||
|
||||
masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
|
||||
|
@ -1707,6 +1820,15 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GLOBALTHIS() {
|
|||
|
||||
frame.push(R0);
|
||||
return true;
|
||||
};
|
||||
auto getGlobalThis = [this]() {
|
||||
loadGlobalThisValue(R0);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
};
|
||||
return emitTestScriptFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
|
||||
getNonSyntacticThis, getGlobalThis,
|
||||
R2.scratchReg());
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
|
@ -1784,7 +1906,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_RESUMEINDEX() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_DOUBLE() {
|
||||
frame.push(script->getConst(GET_UINT32_INDEX(handler.pc())));
|
||||
frame.push(handler.script()->getConst(GET_UINT32_INDEX(handler.pc())));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1802,7 +1924,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_BIGINT() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_STRING() {
|
||||
frame.push(StringValue(script->getAtom(handler.pc())));
|
||||
frame.push(StringValue(handler.script()->getAtom(handler.pc())));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1849,7 +1971,7 @@ bool BaselineCompilerCodeGen::emit_JSOP_OBJECT() {
|
|||
}
|
||||
|
||||
cx->realm()->behaviors().setSingletonsAsValues();
|
||||
frame.push(ObjectValue(*script->getObject(handler.pc())));
|
||||
frame.push(ObjectValue(*handler.script()->getObject(handler.pc())));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1860,6 +1982,7 @@ bool BaselineInterpreterCodeGen::emit_JSOP_OBJECT() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_CALLSITEOBJ() {
|
||||
JSScript* script = handler.script();
|
||||
jsbytecode* pc = handler.pc();
|
||||
RootedObject cso(cx, script->getObject(pc));
|
||||
RootedObject raw(cx, script->getObject(GET_UINT32_INDEX(pc) + 1));
|
||||
|
@ -2199,7 +2322,7 @@ const VMFunction NewArrayCopyOnWriteInfo = FunctionInfo<NewArrayCopyOnWriteFn>(
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_NEWARRAY_COPYONWRITE() {
|
||||
RootedScript scriptRoot(cx, script);
|
||||
RootedScript scriptRoot(cx, handler.script());
|
||||
JSObject* obj =
|
||||
ObjectGroup::getOrFixupCopyOnWriteObject(cx, scriptRoot, handler.pc());
|
||||
if (!obj) {
|
||||
|
@ -2531,7 +2654,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_HASOWN() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::tryOptimizeGetGlobalName() {
|
||||
PropertyName* name = script->getName(handler.pc());
|
||||
PropertyName* name = handler.script()->getName(handler.pc());
|
||||
|
||||
// These names are non-configurable on the global and cannot be shadowed.
|
||||
if (name == cx->names().undefined) {
|
||||
|
@ -2558,18 +2681,16 @@ bool BaselineInterpreterCodeGen::tryOptimizeGetGlobalName() {
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_GETGNAME() {
|
||||
if (script->hasNonSyntacticScope()) {
|
||||
return emit_JSOP_GETNAME();
|
||||
}
|
||||
auto getName = [this]() { return emit_JSOP_GETNAME(); };
|
||||
|
||||
auto getGlobalName = [this]() {
|
||||
if (tryOptimizeGetGlobalName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
frame.syncStack(0);
|
||||
|
||||
masm.movePtr(ImmGCPtr(&script->global().lexicalEnvironment()),
|
||||
R0.scratchReg());
|
||||
loadGlobalLexicalEnvironment(R0.scratchReg());
|
||||
|
||||
// Call IC.
|
||||
if (!emitNextIC()) {
|
||||
|
@ -2579,10 +2700,14 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GETGNAME() {
|
|||
// Mark R0 as pushed stack value.
|
||||
frame.push(R0);
|
||||
return true;
|
||||
};
|
||||
return emitTestScriptFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
|
||||
getName, getGlobalName, R2.scratchReg());
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::tryOptimizeBindGlobalName() {
|
||||
JSScript* script = handler.script();
|
||||
if (script->hasNonSyntacticScope()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2840,6 +2965,7 @@ void BaselineInterpreterCodeGen::getEnvironmentCoordinateObject(Register reg) {
|
|||
template <>
|
||||
Address BaselineCompilerCodeGen::getEnvironmentCoordinateAddressFromObject(
|
||||
Register objReg, Register reg) {
|
||||
JSScript* script = handler.script();
|
||||
EnvironmentCoordinate ec(handler.pc());
|
||||
Shape* shape = EnvironmentCoordinateToEnvironmentShape(script, handler.pc());
|
||||
|
||||
|
@ -2932,15 +3058,30 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GETNAME() {
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emitBindName(JSOp op) {
|
||||
MOZ_ASSERT(op == JSOP_BINDNAME || op == JSOP_BINDGNAME);
|
||||
// If we have a BINDGNAME without a non-syntactic scope, we pass the global
|
||||
// lexical environment to the IC instead of the frame's environment.
|
||||
|
||||
frame.syncStack(0);
|
||||
|
||||
if (op == JSOP_BINDGNAME && !script->hasNonSyntacticScope()) {
|
||||
masm.movePtr(ImmGCPtr(&script->global().lexicalEnvironment()),
|
||||
R0.scratchReg());
|
||||
} else {
|
||||
auto loadGlobalLexical = [this]() {
|
||||
loadGlobalLexicalEnvironment(R0.scratchReg());
|
||||
return true;
|
||||
};
|
||||
auto loadFrameEnv = [this]() {
|
||||
masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
|
||||
return true;
|
||||
};
|
||||
|
||||
if (op == JSOP_BINDNAME) {
|
||||
if (!loadFrameEnv()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(op == JSOP_BINDGNAME);
|
||||
if (!emitTestScriptFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
|
||||
loadFrameEnv, loadGlobalLexical, R2.scratchReg())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Call IC.
|
||||
|
@ -2983,6 +3124,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_DELNAME() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_GETIMPORT() {
|
||||
JSScript* script = handler.script();
|
||||
ModuleEnvironmentObject* env = GetModuleEnvironmentForScript(script);
|
||||
MOZ_ASSERT(env);
|
||||
|
||||
|
@ -3278,7 +3420,7 @@ bool BaselineCompilerCodeGen::emitFormalArgAccess(JSOp op) {
|
|||
|
||||
// Fast path: the script does not use |arguments| or formals don't
|
||||
// alias the arguments object.
|
||||
if (!script->argumentsAliasesFormals()) {
|
||||
if (!handler.script()->argumentsAliasesFormals()) {
|
||||
if (op == JSOP_GETARG) {
|
||||
frame.pushArg(arg);
|
||||
} else {
|
||||
|
@ -3297,7 +3439,7 @@ bool BaselineCompilerCodeGen::emitFormalArgAccess(JSOp op) {
|
|||
// Else, we *may* have an arguments object (because we can't invalidate
|
||||
// when needsArgsObj becomes |true|), so we have to test HAS_ARGS_OBJ.
|
||||
Label done;
|
||||
if (!script->needsArgsObj()) {
|
||||
if (!handler.script()->needsArgsObj()) {
|
||||
Label hasArgsObj;
|
||||
masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
|
||||
Imm32(BaselineFrame::HAS_ARGS_OBJ), &hasArgsObj);
|
||||
|
@ -3363,26 +3505,28 @@ bool BaselineCodeGen<Handler>::emit_JSOP_GETARG() {
|
|||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_SETARG() {
|
||||
// Ionmonkey can't inline functions with SETARG with magic arguments.
|
||||
if (JSScript* script = handler.maybeScript()) {
|
||||
if (!script->argsObjAliasesFormals() && script->argumentsAliasesFormals()) {
|
||||
script->setUninlineable();
|
||||
}
|
||||
}
|
||||
|
||||
modifiesArguments_ = true;
|
||||
|
||||
return emitFormalArgAccess(JSOP_SETARG);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_NEWTARGET() {
|
||||
if (script->isForEval()) {
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_NEWTARGET() {
|
||||
if (handler.script()->isForEval()) {
|
||||
frame.pushEvalNewTarget();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(function());
|
||||
MOZ_ASSERT(handler.function());
|
||||
frame.syncStack(0);
|
||||
|
||||
if (function()->isArrow()) {
|
||||
if (handler.function()->isArrow()) {
|
||||
// Arrow functions store their |new.target| value in an
|
||||
// extended slot.
|
||||
Register scratch = R0.scratchReg();
|
||||
|
@ -3405,8 +3549,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_NEWTARGET() {
|
|||
|
||||
Label useNFormals;
|
||||
|
||||
masm.branchPtr(Assembler::Below, argvLen, Imm32(function()->nargs()),
|
||||
&useNFormals);
|
||||
uint32_t nargs = handler.function()->nargs();
|
||||
masm.branchPtr(Assembler::Below, argvLen, Imm32(nargs), &useNFormals);
|
||||
|
||||
{
|
||||
BaseValueIndex newTarget(BaselineFrameReg, argvLen,
|
||||
|
@ -3418,9 +3562,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_NEWTARGET() {
|
|||
masm.bind(&useNFormals);
|
||||
|
||||
{
|
||||
Address newTarget(
|
||||
BaselineFrameReg,
|
||||
BaselineFrame::offsetOfArg(0) + (function()->nargs() * sizeof(Value)));
|
||||
Address newTarget(BaselineFrameReg,
|
||||
BaselineFrame::offsetOfArg(0) + (nargs * sizeof(Value)));
|
||||
masm.loadValue(newTarget, R0);
|
||||
masm.jump(&done);
|
||||
}
|
||||
|
@ -3435,6 +3578,11 @@ bool BaselineCodeGen<Handler>::emit_JSOP_NEWTARGET() {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BaselineInterpreterCodeGen::emit_JSOP_NEWTARGET() {
|
||||
MOZ_CRASH("NYI: interpreter JSOP_NEWTARGET");
|
||||
}
|
||||
|
||||
typedef bool (*ThrowRuntimeLexicalErrorFn)(JSContext* cx, unsigned);
|
||||
static const VMFunction ThrowRuntimeLexicalErrorInfo =
|
||||
FunctionInfo<ThrowRuntimeLexicalErrorFn>(jit::ThrowRuntimeLexicalError,
|
||||
|
@ -3499,7 +3647,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_INITLEXICAL() {
|
|||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_INITGLEXICAL() {
|
||||
frame.popRegsAndSync(1);
|
||||
frame.push(ObjectValue(script->global().lexicalEnvironment()));
|
||||
pushGlobalLexicalEnvironmentValue(R1);
|
||||
frame.push(R0);
|
||||
return emit_JSOP_SETPROP();
|
||||
}
|
||||
|
@ -3684,12 +3832,14 @@ bool BaselineCodeGen<Handler>::emit_JSOP_IMPLICITTHIS() {
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_GIMPLICITTHIS() {
|
||||
if (!script->hasNonSyntacticScope()) {
|
||||
auto pushUndefined = [this]() {
|
||||
frame.push(UndefinedValue());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
auto emitImplicitThis = [this]() { return emit_JSOP_IMPLICITTHIS(); };
|
||||
|
||||
return emit_JSOP_IMPLICITTHIS();
|
||||
return emitTestScriptFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
|
||||
emitImplicitThis, pushUndefined, R2.scratchReg());
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
|
@ -3753,7 +3903,10 @@ bool BaselineCodeGen<Handler>::emit_JSOP_TRY() {
|
|||
}
|
||||
|
||||
// Ionmonkey can't inline function with JSOP_TRY.
|
||||
if (JSScript* script = handler.maybeScript()) {
|
||||
script->setUninlineable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3788,6 +3941,24 @@ static void LoadBaselineScriptResumeEntries(MacroAssembler& masm,
|
|||
masm.addPtr(scratch, dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::jumpToResumeEntry(Register resumeIndex,
|
||||
Register scratch1,
|
||||
Register scratch2) {
|
||||
LoadBaselineScriptResumeEntries(masm, handler.script(), scratch1, scratch2);
|
||||
masm.loadPtr(
|
||||
BaseIndex(scratch1, resumeIndex, ScaleFromElemWidth(sizeof(uintptr_t))),
|
||||
scratch1);
|
||||
masm.jump(scratch1);
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineInterpreterCodeGen::jumpToResumeEntry(Register resumeIndex,
|
||||
Register scratch1,
|
||||
Register scratch2) {
|
||||
MOZ_CRASH("NYI: interpreter jumpToResumeEntry");
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_RETSUB() {
|
||||
frame.popRegsAndSync(2);
|
||||
|
@ -3805,14 +3976,12 @@ bool BaselineCodeGen<Handler>::emit_JSOP_RETSUB() {
|
|||
masm.bind(&isReturn);
|
||||
|
||||
// R0 is |false|. R1 contains the resumeIndex to jump to.
|
||||
Register resumeIndexReg = R1.scratchReg();
|
||||
masm.unboxInt32(R1, resumeIndexReg);
|
||||
|
||||
Register scratch1 = R2.scratchReg();
|
||||
Register scratch2 = R0.scratchReg();
|
||||
LoadBaselineScriptResumeEntries(masm, script, scratch1, scratch2);
|
||||
masm.unboxInt32(R1, scratch2);
|
||||
masm.loadPtr(
|
||||
BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))),
|
||||
scratch1);
|
||||
masm.jump(scratch1);
|
||||
jumpToResumeEntry(resumeIndexReg, scratch1, scratch2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4165,7 +4334,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_RETRVAL() {
|
|||
|
||||
masm.moveValue(UndefinedValue(), JSReturnOperand);
|
||||
|
||||
if (!script->noScriptRval()) {
|
||||
if (!handler.maybeScript() || !handler.maybeScript()->noScriptRval()) {
|
||||
// Return the value in the return value slot, if any.
|
||||
Label done;
|
||||
Address flags = frame.addressOfFlags();
|
||||
|
@ -4406,7 +4575,7 @@ void BaselineCompilerCodeGen::emitTableSwitchJump(Register key,
|
|||
// |firstResumeIndex * sizeof(uintptr_t)| fits in int32_t.
|
||||
uint32_t firstResumeIndex =
|
||||
GET_RESUMEINDEX(handler.pc() + 3 * JUMP_OFFSET_LEN);
|
||||
LoadBaselineScriptResumeEntries(masm, script, scratch1, scratch2);
|
||||
LoadBaselineScriptResumeEntries(masm, handler.script(), scratch1, scratch2);
|
||||
masm.loadPtr(BaseIndex(scratch1, key, ScaleFromElemWidth(sizeof(uintptr_t)),
|
||||
firstResumeIndex * sizeof(uintptr_t)),
|
||||
scratch1);
|
||||
|
@ -4529,7 +4698,8 @@ bool BaselineCodeGen<Handler>::emit_JSOP_SETRVAL() {
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_CALLEE() {
|
||||
MOZ_ASSERT(function());
|
||||
MOZ_ASSERT_IF(handler.maybeScript(),
|
||||
handler.maybeScript()->functionNonDelazifying());
|
||||
frame.syncStack(0);
|
||||
masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(),
|
||||
R0.scratchReg());
|
||||
|
@ -4671,10 +4841,11 @@ template <typename Handler>
|
|||
bool BaselineCodeGen<Handler>::emit_JSOP_ARGUMENTS() {
|
||||
frame.syncStack(0);
|
||||
|
||||
MOZ_ASSERT(script->argumentsHasVarBinding());
|
||||
MOZ_ASSERT_IF(handler.maybeScript(),
|
||||
handler.maybeScript()->argumentsHasVarBinding());
|
||||
|
||||
Label done;
|
||||
if (!script->needsArgsObj()) {
|
||||
if (!handler.maybeScript() || !handler.maybeScript()->needsArgsObj()) {
|
||||
// We assume the script does not need an arguments object. However, this
|
||||
// assumption can be invalidated later, see argumentsOptimizationFailed
|
||||
// in JSScript. Guard on the script's NeedsArgsObj flag.
|
||||
|
@ -4682,7 +4853,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_ARGUMENTS() {
|
|||
|
||||
// If we don't need an arguments object, skip the VM call.
|
||||
Register scratch = R1.scratchReg();
|
||||
masm.movePtr(ImmGCPtr(script), scratch);
|
||||
loadScript(scratch);
|
||||
masm.branchTest32(
|
||||
Assembler::Zero, Address(scratch, JSScript::offsetOfMutableFlags()),
|
||||
Imm32(uint32_t(JSScript::MutableFlags::NeedsArgsObj)), &done);
|
||||
|
@ -5147,7 +5318,7 @@ bool BaselineCompilerCodeGen::emit_JSOP_RESUME() {
|
|||
masm.bind(&returnTarget);
|
||||
masm.computeEffectiveAddress(frame.addressOfStackValue(-1),
|
||||
masm.getStackPointer());
|
||||
masm.switchToRealm(script->realm(), R2.scratchReg());
|
||||
masm.switchToRealm(handler.script()->realm(), R2.scratchReg());
|
||||
frame.popn(2);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
|
@ -5186,6 +5357,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_IS_CONSTRUCTING() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_JUMPTARGET() {
|
||||
JSScript* script = handler.script();
|
||||
if (!script->hasScriptCounts()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -5356,9 +5528,9 @@ static const VMFunction GetOrCreateModuleMetaObjectInfo =
|
|||
FunctionInfo<GetOrCreateModuleMetaObjectFn>(js::GetOrCreateModuleMetaObject,
|
||||
"GetOrCreateModuleMetaObject");
|
||||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_IMPORTMETA() {
|
||||
RootedModuleObject module(cx, GetModuleObjectForScript(script));
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_IMPORTMETA() {
|
||||
RootedModuleObject module(cx, GetModuleObjectForScript(handler.script()));
|
||||
MOZ_ASSERT(module);
|
||||
|
||||
frame.syncStack(0);
|
||||
|
@ -5374,6 +5546,11 @@ bool BaselineCodeGen<Handler>::emit_JSOP_IMPORTMETA() {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BaselineInterpreterCodeGen::emit_JSOP_IMPORTMETA() {
|
||||
MOZ_CRASH("NYI: interpreter JSOP_IMPORTMETA");
|
||||
}
|
||||
|
||||
typedef JSObject* (*StartDynamicModuleImportFn)(JSContext*, HandleObject,
|
||||
HandleValue);
|
||||
static const VMFunction StartDynamicModuleImportInfo =
|
||||
|
@ -5382,6 +5559,7 @@ static const VMFunction StartDynamicModuleImportInfo =
|
|||
|
||||
template <typename Handler>
|
||||
bool BaselineCodeGen<Handler>::emit_JSOP_DYNAMIC_IMPORT() {
|
||||
JSScript* script = handler.script();
|
||||
RootedObject referencingScriptSource(cx, script->sourceObject());
|
||||
|
||||
// Put specifier value in R0.
|
||||
|
@ -5399,6 +5577,11 @@ bool BaselineCodeGen<Handler>::emit_JSOP_DYNAMIC_IMPORT() {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BaselineInterpreterCodeGen::emit_JSOP_DYNAMIC_IMPORT() {
|
||||
MOZ_CRASH("NYI: interpreter JSOP_DYNAMIC_IMPORT");
|
||||
}
|
||||
|
||||
bool BaselineCompiler::emitPrologue() {
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
// Push link register from generateEnterJIT()'s BLR.
|
||||
|
@ -5407,6 +5590,7 @@ bool BaselineCompiler::emitPrologue() {
|
|||
#endif
|
||||
emitProfilerEnterFrame();
|
||||
|
||||
JSScript* script = handler.script();
|
||||
if (script->trackRecordReplayProgress()) {
|
||||
masm.inc64(
|
||||
AbsoluteAddress(mozilla::recordreplay::ExecutionProgressCounter()));
|
||||
|
@ -5427,7 +5611,7 @@ bool BaselineCompiler::emitPrologue() {
|
|||
// chain is in R1. For function scripts, the env chain is in
|
||||
// the callee, nullptr is stored for now so that GC doesn't choke
|
||||
// on a bogus EnvironmentChain value in the frame.
|
||||
if (function()) {
|
||||
if (handler.function()) {
|
||||
masm.storePtr(ImmPtr(nullptr), frame.addressOfEnvironmentChain());
|
||||
} else {
|
||||
masm.storePtr(R1.scratchReg(), frame.addressOfEnvironmentChain());
|
||||
|
@ -5540,6 +5724,7 @@ bool BaselineCompiler::emitEpilogue() {
|
|||
}
|
||||
|
||||
MethodStatus BaselineCompiler::emitBody() {
|
||||
JSScript* script = handler.script();
|
||||
MOZ_ASSERT(handler.pc() == script->code());
|
||||
|
||||
bool lastOpUnreachable = false;
|
||||
|
|
|
@ -261,7 +261,6 @@ class BaselineCodeGen {
|
|||
Handler handler;
|
||||
|
||||
JSContext* cx;
|
||||
JSScript* script;
|
||||
StackMacroAssembler masm;
|
||||
bool ionCompileable_;
|
||||
|
||||
|
@ -289,14 +288,6 @@ class BaselineCodeGen {
|
|||
BaselineCodeGen(JSContext* cx, TempAllocator& alloc, JSScript* script,
|
||||
HandlerArgs&&... args);
|
||||
|
||||
JSFunction* function() const {
|
||||
// Not delazifying here is ok as the function is guaranteed to have
|
||||
// been delazified before compilation started.
|
||||
return script->functionNonDelazifying();
|
||||
}
|
||||
|
||||
ModuleObject* module() const { return script->module(); }
|
||||
|
||||
template <typename T>
|
||||
void pushArg(const T& t) {
|
||||
masm.Push(t);
|
||||
|
@ -321,6 +312,20 @@ class BaselineCodeGen {
|
|||
|
||||
void loadResumeIndexBytecodeOperand(Register dest);
|
||||
|
||||
// Loads the current JSScript* in dest.
|
||||
void loadScript(Register dest);
|
||||
|
||||
// Jump to the script's resume entry indicated by resumeIndex.
|
||||
void jumpToResumeEntry(Register resumeIndex, Register scratch1,
|
||||
Register scratch2);
|
||||
|
||||
// Load the global's lexical environment.
|
||||
void loadGlobalLexicalEnvironment(Register dest);
|
||||
void pushGlobalLexicalEnvironmentValue(ValueOperand scratch);
|
||||
|
||||
// Load the |this|-value from the global's lexical environment.
|
||||
void loadGlobalThisValue(ValueOperand dest);
|
||||
|
||||
void prepareVMCall();
|
||||
|
||||
void storeFrameSizeAndPushDescriptor(uint32_t frameBaseSize, uint32_t argSize,
|
||||
|
@ -349,6 +354,19 @@ class BaselineCodeGen {
|
|||
return emitDebugInstrumentation(ifDebuggee, mozilla::Maybe<F>());
|
||||
}
|
||||
|
||||
// ifSet should be a function emitting code for when the script has |flag|
|
||||
// set. ifNotSet emits code for when the flag isn't set.
|
||||
template <typename F1, typename F2>
|
||||
MOZ_MUST_USE bool emitTestScriptFlag(JSScript::ImmutableFlags flag,
|
||||
const F1& ifSet, const F2& ifNotSet,
|
||||
Register scratch);
|
||||
|
||||
// If |script->hasFlag(flag) == value|, execute the code emitted by |emit|.
|
||||
template <typename F>
|
||||
MOZ_MUST_USE bool emitTestScriptFlag(JSScript::ImmutableFlags flag,
|
||||
bool value, const F& emit,
|
||||
Register scratch);
|
||||
|
||||
MOZ_MUST_USE bool emitCheckThis(ValueOperand val, bool reinit = false);
|
||||
void emitLoadReturnValue(ValueOperand val);
|
||||
|
||||
|
@ -454,6 +472,18 @@ class BaselineCompilerHandler {
|
|||
|
||||
bool isDefinitelyLastOp() const { return pc_ == script_->lastPC(); }
|
||||
|
||||
JSScript* script() const { return script_; }
|
||||
JSScript* maybeScript() const { return script_; }
|
||||
|
||||
JSFunction* function() const {
|
||||
// Not delazifying here is ok as the function is guaranteed to have
|
||||
// been delazified before compilation started.
|
||||
return script_->functionNonDelazifying();
|
||||
}
|
||||
JSFunction* maybeFunction() const { return function(); }
|
||||
|
||||
ModuleObject* module() const { return script_->module(); }
|
||||
|
||||
void setCompileDebugInstrumentation() { compileDebugInstrumentation_ = true; }
|
||||
bool compileDebugInstrumentation() const {
|
||||
return compileDebugInstrumentation_;
|
||||
|
@ -513,7 +543,7 @@ class BaselineCompiler final : private BaselineCompilerCodeGen {
|
|||
// early stack check.
|
||||
static const unsigned EARLY_STACK_CHECK_SLOT_COUNT = 128;
|
||||
bool needsEarlyStackCheck() const {
|
||||
return script->nslots() > EARLY_STACK_CHECK_SLOT_COUNT;
|
||||
return handler.script()->nslots() > EARLY_STACK_CHECK_SLOT_COUNT;
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -583,9 +613,11 @@ class BaselineInterpreterHandler {
|
|||
|
||||
InterpreterFrameInfo& frame() { return frame_; }
|
||||
|
||||
// Interpreter doesn't know the pc statically.
|
||||
// Interpreter doesn't know the script and pc statically.
|
||||
jsbytecode* maybePC() const { return nullptr; }
|
||||
bool isDefinitelyLastOp() const { return false; }
|
||||
JSScript* maybeScript() const { return nullptr; }
|
||||
JSFunction* maybeFunction() const { return nullptr; }
|
||||
|
||||
// Interpreter doesn't need to keep track of RetAddrEntries, so these methods
|
||||
// are no-ops.
|
||||
|
|
|
@ -1614,7 +1614,9 @@ class JSScript : public js::gc::TenuredCell {
|
|||
|
||||
// Immutable flags should not be modified after this script has been
|
||||
// initialized. These flags should likely be preserved when serializing
|
||||
// (XDR) or copying (CopyScript) this script.
|
||||
// (XDR) or copying (CopyScript) this script. This is only public for the
|
||||
// JITs.
|
||||
public:
|
||||
enum class ImmutableFlags : uint32_t {
|
||||
// No need for result value of last expression statement.
|
||||
NoScriptRval = 1 << 0,
|
||||
|
@ -1687,6 +1689,8 @@ class JSScript : public js::gc::TenuredCell {
|
|||
// should be updated as this script runs.
|
||||
TrackRecordReplayProgress = 1 << 23,
|
||||
};
|
||||
|
||||
private:
|
||||
// Note: don't make this a bitfield! It makes it hard to read these flags
|
||||
// from JIT code.
|
||||
uint32_t immutableFlags_ = 0;
|
||||
|
@ -1855,9 +1859,12 @@ class JSScript : public js::gc::TenuredCell {
|
|||
|
||||
// ImmutableFlags accessors.
|
||||
|
||||
public:
|
||||
MOZ_MUST_USE bool hasFlag(ImmutableFlags flag) const {
|
||||
return immutableFlags_ & uint32_t(flag);
|
||||
}
|
||||
|
||||
private:
|
||||
void setFlag(ImmutableFlags flag) { immutableFlags_ |= uint32_t(flag); }
|
||||
void setFlag(ImmutableFlags flag, bool b) {
|
||||
if (b) {
|
||||
|
@ -2202,6 +2209,9 @@ class JSScript : public js::gc::TenuredCell {
|
|||
static constexpr size_t offsetOfMutableFlags() {
|
||||
return offsetof(JSScript, mutableFlags_);
|
||||
}
|
||||
static size_t offsetOfImmutableFlags() {
|
||||
return offsetof(JSScript, immutableFlags_);
|
||||
}
|
||||
|
||||
bool hasAnyIonScript() const { return hasIonScript(); }
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче