mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1002473 - Make IsConstructing fast for JIT frames. r=nbp
This commit is contained in:
parent
7e52e17364
commit
7ea3e080b1
@ -651,7 +651,7 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
|
||||
// very fast) can avoid doing so. The JitActivation is marked as
|
||||
// inactive so stack iteration will skip over it.
|
||||
AsmJSActivation activation(cx, module);
|
||||
JitActivation jitActivation(cx, /* firstFrameIsConstructing = */ false, /* active */ false);
|
||||
JitActivation jitActivation(cx, /* active */ false);
|
||||
|
||||
// Call the per-exported-function trampoline created by GenerateEntry.
|
||||
AsmJSModule::CodePtr enter = module.entryTrampoline(func);
|
||||
|
62
js/src/jit-test/tests/ion/is-constructing.js
Normal file
62
js/src/jit-test/tests/ion/is-constructing.js
Normal file
@ -0,0 +1,62 @@
|
||||
var isConstructing = getSelfHostedValue("_IsConstructing");
|
||||
|
||||
function testBasic() {
|
||||
var f = function(expected) {
|
||||
with(this) {}; // Don't inline.
|
||||
assertEq(isConstructing(), expected);
|
||||
};
|
||||
for (var i=0; i<40; i++) {
|
||||
f(false);
|
||||
new f(true);
|
||||
}
|
||||
}
|
||||
testBasic();
|
||||
|
||||
function testGeneric() {
|
||||
var f1 = function(expected) {
|
||||
with(this) {};
|
||||
assertEq(isConstructing(), expected);
|
||||
};
|
||||
var f2 = function(expected) {
|
||||
assertEq(isConstructing(), expected);
|
||||
}
|
||||
var funs = [f1, f2];
|
||||
for (var i=0; i<40; i++) {
|
||||
var f = funs[i % 2];
|
||||
f(false);
|
||||
new f(true);
|
||||
}
|
||||
}
|
||||
testGeneric();
|
||||
|
||||
function testArgsRectifier() {
|
||||
var f = function(x) {
|
||||
with(this) {};
|
||||
assertEq(isConstructing(), true);
|
||||
};
|
||||
for (var i=0; i<40; i++)
|
||||
new f();
|
||||
}
|
||||
testArgsRectifier();
|
||||
|
||||
function testBailout() {
|
||||
var f1 = function(x, expected) {
|
||||
if (x > 20) {
|
||||
bailout();
|
||||
assertEq(isConstructing(), expected);
|
||||
}
|
||||
};
|
||||
var f2 = function(x) {
|
||||
return new f1(x, true);
|
||||
};
|
||||
var f3 = function(x) {
|
||||
return f1(x, false);
|
||||
};
|
||||
for (var i=0; i<40; i++) {
|
||||
f2(i);
|
||||
f3(i);
|
||||
}
|
||||
for (var i=0; i<40; i++)
|
||||
f1(i, false);
|
||||
}
|
||||
testBailout();
|
@ -1163,7 +1163,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
JitSpew(JitSpew_BaselineBailouts, " Callee = %016llx", *((uint64_t *) &callee));
|
||||
JS_ASSERT(callee.isObject() && callee.toObject().is<JSFunction>());
|
||||
JSFunction *calleeFun = &callee.toObject().as<JSFunction>();
|
||||
if (!builder.writePtr(CalleeToToken(calleeFun), "CalleeToken"))
|
||||
if (!builder.writePtr(CalleeToToken(calleeFun, JSOp(*pc) == JSOP_NEW), "CalleeToken"))
|
||||
return false;
|
||||
nextCallee.set(calleeFun);
|
||||
|
||||
@ -1242,7 +1242,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
return false;
|
||||
|
||||
// Push calleeToken again.
|
||||
if (!builder.writePtr(CalleeToToken(calleeFun), "CalleeToken"))
|
||||
if (!builder.writePtr(CalleeToToken(calleeFun, JSOp(*pc) == JSOP_NEW), "CalleeToken"))
|
||||
return false;
|
||||
|
||||
// Push rectifier frame descriptor
|
||||
|
@ -593,7 +593,7 @@ BaselineCompiler::initScopeChain()
|
||||
// chain slot is properly initialized if the call triggers GC.
|
||||
Register callee = R0.scratchReg();
|
||||
Register scope = R1.scratchReg();
|
||||
masm.loadPtr(frame.addressOfCallee(), callee);
|
||||
masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), callee);
|
||||
masm.loadPtr(Address(callee, JSFunction::offsetOfEnvironment()), scope);
|
||||
masm.storePtr(scope, frame.addressOfScopeChain());
|
||||
|
||||
@ -1145,7 +1145,7 @@ BaselineCompiler::emit_JSOP_THIS()
|
||||
// extended slot.
|
||||
frame.syncStack(0);
|
||||
Register scratch = R0.scratchReg();
|
||||
masm.loadPtr(frame.addressOfCallee(), scratch);
|
||||
masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), scratch);
|
||||
masm.loadValue(Address(scratch, FunctionExtended::offsetOfArrowThisSlot()), R0);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
@ -3065,7 +3065,7 @@ BaselineCompiler::emit_JSOP_CALLEE()
|
||||
{
|
||||
JS_ASSERT(function());
|
||||
frame.syncStack(0);
|
||||
masm.loadPtr(frame.addressOfCallee(), R0.scratchReg());
|
||||
masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), R0.scratchReg());
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
|
@ -269,7 +269,7 @@ class FrameInfo
|
||||
Address addressOfThis() const {
|
||||
return Address(BaselineFrameReg, BaselineFrame::offsetOfThis());
|
||||
}
|
||||
Address addressOfCallee() const {
|
||||
Address addressOfCalleeToken() const {
|
||||
return Address(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
|
||||
}
|
||||
Address addressOfScopeChain() const {
|
||||
|
@ -7437,7 +7437,7 @@ ICGetProp_ArgumentsCallee::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
&failure);
|
||||
|
||||
Address callee(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
|
||||
masm.loadPtr(callee, R0.scratchReg());
|
||||
masm.loadFunctionFromCalleeToken(callee, R0.scratchReg());
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
|
||||
|
||||
EmitEnterTypeMonitorIC(masm);
|
||||
@ -9167,7 +9167,7 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler &masm)
|
||||
// Note that we use Push, not push, so that callIon will align the stack
|
||||
// properly on ARM.
|
||||
masm.Push(argcReg);
|
||||
masm.Push(callee);
|
||||
masm.PushCalleeToken(callee, isConstructing_);
|
||||
masm.Push(scratch);
|
||||
|
||||
// Handle arguments underflow.
|
||||
|
@ -106,7 +106,7 @@ EnterBaseline(JSContext *cx, EnterJitData &data)
|
||||
data.result.setInt32(data.numActualArgs);
|
||||
{
|
||||
AssertCompartmentUnchanged pcc(cx);
|
||||
JitActivation activation(cx, data.constructing);
|
||||
JitActivation activation(cx);
|
||||
|
||||
if (data.osrFrame)
|
||||
data.osrFrame->setRunningInJit();
|
||||
@ -178,7 +178,7 @@ jit::EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc)
|
||||
data.maxArgc = Max(fp->numActualArgs(), fp->numFormalArgs()) + 1; // +1 = include |this|
|
||||
data.maxArgv = fp->argv() - 1; // -1 = include |this|
|
||||
data.scopeChain = nullptr;
|
||||
data.calleeToken = CalleeToToken(&fp->callee());
|
||||
data.calleeToken = CalleeToToken(&fp->callee(), data.constructing);
|
||||
} else {
|
||||
thisv = fp->thisValue();
|
||||
data.constructing = false;
|
||||
@ -189,7 +189,7 @@ jit::EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc)
|
||||
|
||||
// For eval function frames, set the callee token to the enclosing function.
|
||||
if (fp->isFunctionFrame())
|
||||
data.calleeToken = CalleeToToken(&fp->callee());
|
||||
data.calleeToken = CalleeToToken(&fp->callee(), /* constructing = */ false);
|
||||
else
|
||||
data.calleeToken = CalleeToToken(fp->script());
|
||||
}
|
||||
|
@ -1397,11 +1397,28 @@ CodeGenerator::visitParameter(LParameter *lir)
|
||||
bool
|
||||
CodeGenerator::visitCallee(LCallee *lir)
|
||||
{
|
||||
// read number of actual arguments from the JS frame.
|
||||
Register callee = ToRegister(lir->output());
|
||||
Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
|
||||
|
||||
masm.loadPtr(ptr, callee);
|
||||
masm.loadFunctionFromCalleeToken(ptr, callee);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitIsConstructing(LIsConstructing *lir)
|
||||
{
|
||||
Register output = ToRegister(lir->output());
|
||||
Address calleeToken(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
|
||||
masm.loadPtr(calleeToken, output);
|
||||
|
||||
// We must be inside a function.
|
||||
MOZ_ASSERT(current->mir()->info().script()->functionNonDelazifying());
|
||||
|
||||
// The low bit indicates whether this call is constructing, just clear the
|
||||
// other bits.
|
||||
static_assert(CalleeToken_Function == 0x0, "CalleeTokenTag value should match");
|
||||
static_assert(CalleeToken_FunctionConstructing == 0x1, "CalleeTokenTag value should match");
|
||||
masm.andPtr(Imm32(0x1), output);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2395,7 +2412,7 @@ CodeGenerator::visitCallGeneric(LCallGeneric *call)
|
||||
// Construct the IonFramePrefix.
|
||||
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
|
||||
masm.Push(Imm32(call->numActualArgs()));
|
||||
masm.Push(calleereg);
|
||||
masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
|
||||
masm.Push(Imm32(descriptor));
|
||||
|
||||
// Check whether the provided arguments satisfy target argc.
|
||||
@ -2510,7 +2527,7 @@ CodeGenerator::visitCallKnown(LCallKnown *call)
|
||||
// Construct the IonFramePrefix.
|
||||
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
|
||||
masm.Push(Imm32(call->numActualArgs()));
|
||||
masm.Push(calleereg);
|
||||
masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
|
||||
masm.Push(Imm32(descriptor));
|
||||
|
||||
// Finally call the function in objreg.
|
||||
|
@ -67,6 +67,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitCloneLiteral(LCloneLiteral *lir);
|
||||
bool visitParameter(LParameter *lir);
|
||||
bool visitCallee(LCallee *lir);
|
||||
bool visitIsConstructing(LIsConstructing *lir);
|
||||
bool visitStart(LStart *lir);
|
||||
bool visitReturn(LReturn *ret);
|
||||
bool visitDefVar(LDefVar *lir);
|
||||
|
@ -2440,7 +2440,7 @@ EnterIon(JSContext *cx, EnterJitData &data)
|
||||
data.result.setInt32(data.numActualArgs);
|
||||
{
|
||||
AssertCompartmentUnchanged pcc(cx);
|
||||
JitActivation activation(cx, data.constructing);
|
||||
JitActivation activation(cx);
|
||||
|
||||
CALL_GENERATED_CODE(enter, data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */nullptr, data.calleeToken,
|
||||
/* scopeChain = */ nullptr, 0, data.result.address());
|
||||
@ -2471,7 +2471,7 @@ jit::SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoVal
|
||||
data.numActualArgs = args.length();
|
||||
data.maxArgc = Max(args.length(), numFormals) + 1;
|
||||
data.scopeChain = nullptr;
|
||||
data.calleeToken = CalleeToToken(&args.callee().as<JSFunction>());
|
||||
data.calleeToken = CalleeToToken(&args.callee().as<JSFunction>(), data.constructing);
|
||||
|
||||
if (data.numActualArgs >= numFormals) {
|
||||
data.maxArgv = args.base() + 1;
|
||||
@ -2504,7 +2504,7 @@ jit::SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoVal
|
||||
{
|
||||
ScriptFrameIter iter(cx);
|
||||
if (iter.isFunctionFrame())
|
||||
data.calleeToken = CalleeToToken(iter.callee());
|
||||
data.calleeToken = CalleeToToken(iter.callee(), /* constructing = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2543,10 +2543,10 @@ jit::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args)
|
||||
JS_ASSERT(jit::IsIonEnabled(cx));
|
||||
JS_ASSERT(!ion->bailoutExpected());
|
||||
|
||||
JitActivation activation(cx, /* firstFrameIsConstructing = */false);
|
||||
JitActivation activation(cx);
|
||||
|
||||
EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
|
||||
void *calleeToken = CalleeToToken(fun);
|
||||
void *calleeToken = CalleeToToken(fun, /* constructing = */ false);
|
||||
|
||||
RootedValue result(cx, Int32Value(args.length()));
|
||||
JS_ASSERT(args.length() >= fun->nargs());
|
||||
|
@ -747,6 +747,7 @@ class IonBuilder : public MIRGenerator
|
||||
return inlineHasClasses(callInfo, clasp, nullptr);
|
||||
}
|
||||
InliningStatus inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Class *clasp2);
|
||||
InliningStatus inlineIsConstructing(CallInfo &callInfo);
|
||||
|
||||
// Testing functions.
|
||||
InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
|
||||
|
@ -828,17 +828,18 @@ EnsureExitFrame(IonCommonFrameLayout *frame)
|
||||
CalleeToken
|
||||
MarkCalleeToken(JSTracer *trc, CalleeToken token)
|
||||
{
|
||||
switch (GetCalleeTokenTag(token)) {
|
||||
switch (CalleeTokenTag tag = GetCalleeTokenTag(token)) {
|
||||
case CalleeToken_Function:
|
||||
case CalleeToken_FunctionConstructing:
|
||||
{
|
||||
JSFunction *fun = CalleeTokenToFunction(token);
|
||||
MarkObjectRoot(trc, &fun, "ion-callee");
|
||||
return CalleeToToken(fun);
|
||||
MarkObjectRoot(trc, &fun, "jit-callee");
|
||||
return CalleeToToken(fun, tag == CalleeToken_FunctionConstructing);
|
||||
}
|
||||
case CalleeToken_Script:
|
||||
{
|
||||
JSScript *script = CalleeTokenToScript(token);
|
||||
MarkScriptRoot(trc, &script, "ion-entry");
|
||||
MarkScriptRoot(trc, &script, "jit-script");
|
||||
return CalleeToToken(script);
|
||||
}
|
||||
default:
|
||||
@ -1767,19 +1768,13 @@ JitFrameIterator::ionScriptFromCalleeToken() const
|
||||
JS_ASSERT(type() == JitFrame_IonJS);
|
||||
JS_ASSERT(!checkInvalidation());
|
||||
|
||||
switch (GetCalleeTokenTag(calleeToken())) {
|
||||
case CalleeToken_Function:
|
||||
case CalleeToken_Script:
|
||||
switch (mode_) {
|
||||
case SequentialExecution:
|
||||
return script()->ionScript();
|
||||
case ParallelExecution:
|
||||
return script()->parallelIonScript();
|
||||
default:
|
||||
MOZ_CRASH("No such execution mode");
|
||||
}
|
||||
switch (mode_) {
|
||||
case SequentialExecution:
|
||||
return script()->ionScript();
|
||||
case ParallelExecution:
|
||||
return script()->parallelIonScript();
|
||||
default:
|
||||
MOZ_CRASH("unknown callee token type");
|
||||
MOZ_CRASH("No such execution mode");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2020,42 +2015,7 @@ InlineFrameIterator::isConstructing() const
|
||||
bool
|
||||
JitFrameIterator::isConstructing() const
|
||||
{
|
||||
JitFrameIterator parent(*this);
|
||||
|
||||
// Skip the current frame and look at the caller's.
|
||||
do {
|
||||
++parent;
|
||||
} while (!parent.done() && !parent.isScripted());
|
||||
|
||||
if (parent.isIonJS()) {
|
||||
// In the case of a JS frame, look up the pc from the snapshot.
|
||||
InlineFrameIterator inlinedParent(GetJSContextFromJitCode(), &parent);
|
||||
|
||||
//Inlined Getters and Setters are never constructing.
|
||||
if (IsGetPropPC(inlinedParent.pc()) || IsSetPropPC(inlinedParent.pc()))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(IsCallPC(inlinedParent.pc()));
|
||||
|
||||
return (JSOp)*inlinedParent.pc() == JSOP_NEW;
|
||||
}
|
||||
|
||||
if (parent.isBaselineJS()) {
|
||||
jsbytecode *pc;
|
||||
parent.baselineScriptAndPc(nullptr, &pc);
|
||||
|
||||
// Inlined Getters and Setters are never constructing.
|
||||
// Baseline may call getters from [GET|SET]PROP or [GET|SET]ELEM ops.
|
||||
if (IsGetPropPC(pc) || IsSetPropPC(pc) || IsGetElemPC(pc) || IsSetElemPC(pc))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(IsCallPC(pc));
|
||||
|
||||
return JSOp(*pc) == JSOP_NEW;
|
||||
}
|
||||
|
||||
JS_ASSERT(parent.done());
|
||||
return activation_->firstFrameIsConstructing();
|
||||
return GetCalleeTokenTag(calleeToken()) == CalleeToken_FunctionConstructing;
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -22,9 +22,12 @@ typedef void * CalleeToken;
|
||||
enum CalleeTokenTag
|
||||
{
|
||||
CalleeToken_Function = 0x0, // untagged
|
||||
CalleeToken_Script = 0x1
|
||||
CalleeToken_FunctionConstructing = 0x1,
|
||||
CalleeToken_Script = 0x2
|
||||
};
|
||||
|
||||
static const uintptr_t CalleeTokenMask = ~uintptr_t(0x3);
|
||||
|
||||
static inline CalleeTokenTag
|
||||
GetCalleeTokenTag(CalleeToken token)
|
||||
{
|
||||
@ -33,9 +36,10 @@ GetCalleeTokenTag(CalleeToken token)
|
||||
return tag;
|
||||
}
|
||||
static inline CalleeToken
|
||||
CalleeToToken(JSFunction *fun)
|
||||
CalleeToToken(JSFunction *fun, bool constructing)
|
||||
{
|
||||
return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function));
|
||||
CalleeTokenTag tag = constructing ? CalleeToken_FunctionConstructing : CalleeToken_Function;
|
||||
return CalleeToken(uintptr_t(fun) | uintptr_t(tag));
|
||||
}
|
||||
static inline CalleeToken
|
||||
CalleeToToken(JSScript *script)
|
||||
@ -45,19 +49,20 @@ CalleeToToken(JSScript *script)
|
||||
static inline bool
|
||||
CalleeTokenIsFunction(CalleeToken token)
|
||||
{
|
||||
return GetCalleeTokenTag(token) == CalleeToken_Function;
|
||||
CalleeTokenTag tag = GetCalleeTokenTag(token);
|
||||
return tag == CalleeToken_Function || tag == CalleeToken_FunctionConstructing;
|
||||
}
|
||||
static inline JSFunction *
|
||||
CalleeTokenToFunction(CalleeToken token)
|
||||
{
|
||||
JS_ASSERT(CalleeTokenIsFunction(token));
|
||||
return (JSFunction *)token;
|
||||
MOZ_ASSERT(CalleeTokenIsFunction(token));
|
||||
return (JSFunction *)(uintptr_t(token) & CalleeTokenMask);
|
||||
}
|
||||
static inline JSScript *
|
||||
CalleeTokenToScript(CalleeToken token)
|
||||
{
|
||||
JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
|
||||
return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3));
|
||||
return (JSScript *)(uintptr_t(token) & CalleeTokenMask);
|
||||
}
|
||||
|
||||
static inline JSScript *
|
||||
@ -67,6 +72,7 @@ ScriptFromCalleeToken(CalleeToken token)
|
||||
case CalleeToken_Script:
|
||||
return CalleeTokenToScript(token);
|
||||
case CalleeToken_Function:
|
||||
case CalleeToken_FunctionConstructing:
|
||||
return CalleeTokenToFunction(token)->nonLazyScript();
|
||||
}
|
||||
MOZ_CRASH("invalid callee token tag");
|
||||
|
@ -376,6 +376,21 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
load32(Address(str, JSString::offsetOfLength()), dest);
|
||||
}
|
||||
|
||||
void loadFunctionFromCalleeToken(Address token, Register dest) {
|
||||
loadPtr(token, dest);
|
||||
andPtr(Imm32(uint32_t(CalleeTokenMask)), dest);
|
||||
}
|
||||
void PushCalleeToken(Register callee, bool constructing) {
|
||||
if (constructing) {
|
||||
orPtr(Imm32(CalleeToken_FunctionConstructing), callee);
|
||||
Push(callee);
|
||||
andPtr(Imm32(uint32_t(CalleeTokenMask)), callee);
|
||||
} else {
|
||||
static_assert(CalleeToken_Function == 0, "Non-constructing call requires no tagging");
|
||||
Push(callee);
|
||||
}
|
||||
}
|
||||
|
||||
void loadStringChars(Register str, Register dest);
|
||||
void loadStringChar(Register str, Register index, Register output);
|
||||
|
||||
|
@ -487,6 +487,12 @@ class LCallee : public LInstructionHelper<1, 0, 0>
|
||||
LIR_HEADER(Callee)
|
||||
};
|
||||
|
||||
class LIsConstructing : public LInstructionHelper<1, 0, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(IsConstructing)
|
||||
};
|
||||
|
||||
// Base class for control instructions (goto, branch, etc.)
|
||||
template <size_t Succs, size_t Operands, size_t Temps>
|
||||
class LControlInstructionHelper : public LInstructionHelper<0, Operands, Temps> {
|
||||
|
@ -33,6 +33,7 @@
|
||||
_(CloneLiteral) \
|
||||
_(Parameter) \
|
||||
_(Callee) \
|
||||
_(IsConstructing) \
|
||||
_(TableSwitch) \
|
||||
_(TableSwitchV) \
|
||||
_(Goto) \
|
||||
|
@ -70,6 +70,12 @@ LIRGenerator::visitCallee(MCallee *ins)
|
||||
return define(new(alloc()) LCallee(), ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitIsConstructing(MIsConstructing *ins)
|
||||
{
|
||||
return define(new(alloc()) LIsConstructing(), ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitGoto(MGoto *ins)
|
||||
{
|
||||
|
@ -67,6 +67,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitCloneLiteral(MCloneLiteral *ins);
|
||||
bool visitParameter(MParameter *param);
|
||||
bool visitCallee(MCallee *callee);
|
||||
bool visitIsConstructing(MIsConstructing *ins);
|
||||
bool visitGoto(MGoto *ins);
|
||||
bool visitTableSwitch(MTableSwitch *tableswitch);
|
||||
bool visitNewArray(MNewArray *ins);
|
||||
|
@ -173,6 +173,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
|
||||
return inlineToInteger(callInfo);
|
||||
if (native == intrinsic_ToString)
|
||||
return inlineToString(callInfo);
|
||||
if (native == intrinsic_IsConstructing)
|
||||
return inlineIsConstructing(callInfo);
|
||||
|
||||
// TypedObject intrinsics.
|
||||
if (native == intrinsic_ObjectIsTypedObject)
|
||||
@ -2153,5 +2155,30 @@ IonBuilder::inlineBoundFunction(CallInfo &nativeCallInfo, JSFunction *target)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineIsConstructing(CallInfo &callInfo)
|
||||
{
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 0);
|
||||
MOZ_ASSERT(script()->functionNonDelazifying(),
|
||||
"isConstructing() should only be called in function scripts");
|
||||
|
||||
if (getInlineReturnType() != MIRType_Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
if (inliningDepth_ == 0) {
|
||||
MInstruction *ins = MIsConstructing::New(alloc());
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
bool constructing = inlineCallInfo_->constructing();
|
||||
pushConstant(BooleanValue(constructing));
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
@ -1698,6 +1698,28 @@ class MCallee : public MNullaryInstruction
|
||||
}
|
||||
};
|
||||
|
||||
class MIsConstructing : public MNullaryInstruction
|
||||
{
|
||||
public:
|
||||
MIsConstructing() {
|
||||
setResultType(MIRType_Boolean);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(IsConstructing)
|
||||
|
||||
bool congruentTo(const MDefinition *ins) const {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
static MIsConstructing *New(TempAllocator &alloc) {
|
||||
return new(alloc) MIsConstructing();
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
class MControlInstruction : public MInstruction
|
||||
{
|
||||
public:
|
||||
|
@ -24,6 +24,7 @@ namespace jit {
|
||||
_(CloneLiteral) \
|
||||
_(Parameter) \
|
||||
_(Callee) \
|
||||
_(IsConstructing) \
|
||||
_(TableSwitch) \
|
||||
_(Goto) \
|
||||
_(Test) \
|
||||
|
@ -124,6 +124,7 @@ class ParallelSafetyVisitor : public MDefinitionVisitor
|
||||
UNSAFE_OP(CloneLiteral)
|
||||
SAFE_OP(Parameter)
|
||||
SAFE_OP(Callee)
|
||||
SAFE_OP(IsConstructing)
|
||||
SAFE_OP(TableSwitch)
|
||||
SAFE_OP(Goto)
|
||||
SAFE_OP(Test)
|
||||
|
@ -428,7 +428,8 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Load the number of |undefined|s to push into r6.
|
||||
masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfCalleeToken())), r1);
|
||||
masm.ma_ldrh(EDtrAddr(r1, EDtrOffImm(JSFunction::offsetOfNargs())), r6);
|
||||
masm.ma_and(Imm32(CalleeTokenMask), r1, r6);
|
||||
masm.ma_ldrh(EDtrAddr(r6, EDtrOffImm(JSFunction::offsetOfNargs())), r6);
|
||||
|
||||
masm.ma_sub(r6, r8, r2);
|
||||
|
||||
@ -477,6 +478,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Call the target function.
|
||||
// Note that this code assumes the function is JITted.
|
||||
masm.andPtr(Imm32(CalleeTokenMask), r1);
|
||||
masm.ma_ldr(DTRAddr(r1, DtrOffImm(JSFunction::offsetOfNativeOrScript())), r3);
|
||||
masm.loadBaselineOrIonRaw(r3, r3, mode, nullptr);
|
||||
masm.ma_callIonHalfPush(r3);
|
||||
|
@ -406,7 +406,9 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
// Load the number of |undefined|s to push into t1.
|
||||
masm.loadPtr(Address(StackPointer, IonRectifierFrameLayout::offsetOfCalleeToken()),
|
||||
calleeTokenReg);
|
||||
masm.load16ZeroExtend(Address(calleeTokenReg, JSFunction::offsetOfNargs()), numArgsReg);
|
||||
masm.mov(calleeTokenReg, numArgsReg);
|
||||
masm.andPtr(Imm32(CalleeTokenMask), numArgsReg);
|
||||
masm.load16ZeroExtend(Address(numArgsReg, JSFunction::offsetOfNargs()), numArgsReg);
|
||||
|
||||
masm.ma_subu(t1, numArgsReg, s3);
|
||||
|
||||
@ -472,6 +474,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Call the target function.
|
||||
// Note that this code assumes the function is JITted.
|
||||
masm.andPtr(Imm32(CalleeTokenMask), calleeTokenReg);
|
||||
masm.loadPtr(Address(calleeTokenReg, JSFunction::offsetOfNativeOrScript()), t1);
|
||||
masm.loadBaselineOrIonRaw(t1, t1, mode, nullptr);
|
||||
masm.ma_callIonHalfPush(t1);
|
||||
|
@ -371,7 +371,9 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Load the number of |undefined|s to push into %rcx.
|
||||
masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfCalleeToken()), rax);
|
||||
masm.movzwl(Operand(rax, JSFunction::offsetOfNargs()), rcx);
|
||||
masm.mov(rax, rcx);
|
||||
masm.andq(Imm32(uint32_t(CalleeTokenMask)), rcx);
|
||||
masm.movzwl(Operand(rcx, JSFunction::offsetOfNargs()), rcx);
|
||||
masm.subq(r8, rcx);
|
||||
|
||||
// Copy the number of actual arguments
|
||||
@ -418,6 +420,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Call the target function.
|
||||
// Note that this code assumes the function is JITted.
|
||||
masm.andq(Imm32(uint32_t(CalleeTokenMask)), rax);
|
||||
masm.loadPtr(Address(rax, JSFunction::offsetOfNativeOrScript()), rax);
|
||||
masm.loadBaselineOrIonRaw(rax, rax, mode, nullptr);
|
||||
masm.call(rax);
|
||||
|
@ -365,7 +365,9 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Load the number of |undefined|s to push into %ecx.
|
||||
masm.loadPtr(Address(esp, IonRectifierFrameLayout::offsetOfCalleeToken()), eax);
|
||||
masm.movzwl(Operand(eax, JSFunction::offsetOfNargs()), ecx);
|
||||
masm.mov(eax, ecx);
|
||||
masm.andl(Imm32(CalleeTokenMask), ecx);
|
||||
masm.movzwl(Operand(ecx, JSFunction::offsetOfNargs()), ecx);
|
||||
masm.subl(esi, ecx);
|
||||
|
||||
// Copy the number of actual arguments.
|
||||
@ -422,6 +424,7 @@ JitRuntime::generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void *
|
||||
|
||||
// Call the target function.
|
||||
// Note that this assumes the function is JITted.
|
||||
masm.andl(Imm32(CalleeTokenMask), eax);
|
||||
masm.loadPtr(Address(eax, JSFunction::offsetOfNativeOrScript()), eax);
|
||||
masm.loadBaselineOrIonRaw(eax, eax, mode, nullptr);
|
||||
masm.call(eax);
|
||||
|
@ -988,6 +988,7 @@ bool intrinsic_ToString(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_IsConstructing(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
bool intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp);
|
||||
bool intrinsic_DefineDataProperty(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
@ -1351,7 +1351,7 @@ class ParallelIonInvoke
|
||||
JitCode *code = ion->method();
|
||||
jitcode_ = code->raw();
|
||||
enter_ = rt->jitRuntime()->enterIon();
|
||||
calleeToken_ = CalleeToToken(callee);
|
||||
calleeToken_ = CalleeToToken(callee, /* constructing = */ false);
|
||||
}
|
||||
|
||||
bool invoke(ForkJoinContext *cx) {
|
||||
|
@ -790,6 +790,18 @@ intrinsic_RuntimeDefaultLocale(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intrinsic_IsConstructing(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
ScriptFrameIter iter(cx);
|
||||
bool isConstructing = iter.isConstructing();
|
||||
args.rval().setBoolean(isConstructing);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("ToObject", intrinsic_ToObject, 1,0),
|
||||
JS_FN("IsObject", intrinsic_IsObject, 1,0),
|
||||
@ -802,6 +814,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
|
||||
JS_FN("SetScriptHints", intrinsic_SetScriptHints, 2,0),
|
||||
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 1,0),
|
||||
JS_FN("_IsConstructing", intrinsic_IsConstructing, 0,0),
|
||||
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
|
||||
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
|
||||
|
||||
|
@ -1398,9 +1398,8 @@ js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint
|
||||
}
|
||||
#endif
|
||||
|
||||
jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active)
|
||||
jit::JitActivation::JitActivation(JSContext *cx, bool active)
|
||||
: Activation(cx, Jit),
|
||||
firstFrameIsConstructing_(firstFrameIsConstructing),
|
||||
active_(active),
|
||||
rematerializedFrames_(nullptr)
|
||||
{
|
||||
@ -1416,7 +1415,6 @@ jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing,
|
||||
|
||||
jit::JitActivation::JitActivation(ForkJoinContext *cx)
|
||||
: Activation(cx, Jit),
|
||||
firstFrameIsConstructing_(false),
|
||||
active_(true),
|
||||
rematerializedFrames_(nullptr)
|
||||
{
|
||||
|
@ -1302,7 +1302,6 @@ class JitActivation : public Activation
|
||||
{
|
||||
uint8_t *prevJitTop_;
|
||||
JSContext *prevJitJSContext_;
|
||||
bool firstFrameIsConstructing_;
|
||||
bool active_;
|
||||
|
||||
// Rematerialized Ion frames which has info copied out of snapshots. Maps
|
||||
@ -1325,7 +1324,7 @@ class JitActivation : public Activation
|
||||
#endif
|
||||
|
||||
public:
|
||||
JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active = true);
|
||||
explicit JitActivation(JSContext *cx, bool active = true);
|
||||
explicit JitActivation(ForkJoinContext *cx);
|
||||
~JitActivation();
|
||||
|
||||
@ -1341,9 +1340,6 @@ class JitActivation : public Activation
|
||||
uint8_t *prevJitTop() const {
|
||||
return prevJitTop_;
|
||||
}
|
||||
bool firstFrameIsConstructing() const {
|
||||
return firstFrameIsConstructing_;
|
||||
}
|
||||
static size_t offsetOfPrevJitTop() {
|
||||
return offsetof(JitActivation, prevJitTop_);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user