Bug 1002473 - Make IsConstructing fast for JIT frames. r=nbp

This commit is contained in:
Jan de Mooij 2014-09-03 18:12:16 +02:00
parent cf9599d1bf
commit fe5fcf8f71
31 changed files with 239 additions and 93 deletions

View File

@ -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);

View 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();

View File

@ -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

View File

@ -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;

View File

@ -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 {

View File

@ -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.

View File

@ -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());
}

View File

@ -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.

View File

@ -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);

View File

@ -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());

View File

@ -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);

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -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> {

View File

@ -33,6 +33,7 @@
_(CloneLiteral) \
_(Parameter) \
_(Callee) \
_(IsConstructing) \
_(TableSwitch) \
_(TableSwitchV) \
_(Goto) \

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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:

View File

@ -24,6 +24,7 @@ namespace jit {
_(CloneLiteral) \
_(Parameter) \
_(Callee) \
_(IsConstructing) \
_(TableSwitch) \
_(Goto) \
_(Test) \

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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),

View File

@ -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)
{

View File

@ -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_);
}