Bug 939581 part 1. Factor out MCallDOMNative from MCall. r=efaust,jandem

This commit is contained in:
Boris Zbarsky 2013-11-20 17:44:56 -05:00
parent f98a8d58d2
commit 5d40f3015e
6 changed files with 99 additions and 63 deletions

View File

@ -1781,7 +1781,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
JS_ASSERT(target);
JS_ASSERT(target->isNative());
JS_ASSERT(target->jitInfo());
JS_ASSERT(call->mir()->isDOMFunction());
JS_ASSERT(call->mir()->isCallDOMNative());
int callargslot = call->argslot();
int unusedStack = StackOffsetOfPassedArg(callargslot);

View File

@ -5170,8 +5170,22 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC
if (target && !target->isNative())
targetArgs = Max<uint32_t>(target->nargs(), callInfo.argc());
MCall *call =
MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(), callInfo.constructing());
bool isDOMCall = false;
if (target && !callInfo.constructing()) {
// We know we have a single call target. Check whether the "this" types
// are DOM types and our function a DOM function, and if so flag the
// MCall accordingly.
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
if (thisTypes &&
thisTypes->isDOMClass() &&
testShouldDOMCall(thisTypes, target, JSJitInfo::Method))
{
isDOMCall = true;
}
}
MCall *call = MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(),
callInfo.constructing(), isDOMCall);
if (!call)
return nullptr;
@ -5211,19 +5225,6 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC
callInfo.setFun(fun);
}
if (target && JSOp(*pc) == JSOP_CALL) {
// We know we have a single call target. Check whether the "this" types
// are DOM types and our function a DOM function, and if so flag the
// MCall accordingly.
types::TemporaryTypeSet *thisTypes = thisArg->resultTypeSet();
if (thisTypes &&
thisTypes->isDOMClass() &&
testShouldDOMCall(thisTypes, target, JSJitInfo::Method))
{
call->setDOMFunction();
}
}
if (target && !testNeedsArgumentCheck(target, callInfo))
call->disableArgCheck();
@ -5268,7 +5269,7 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit
types::TemporaryTypeSet *types = bytecodeTypes(pc);
if (call->isDOMFunction())
if (call->isCallDOMNative())
return pushDOMTypeBarrier(call, types, call->getSingleTarget());
return pushTypeBarrier(call, types, true);

View File

@ -408,7 +408,7 @@ LIRGenerator::visitCall(MCall *call)
JSFunction *target = call->getSingleTarget();
// Call DOM functions.
if (call->isDOMFunction()) {
if (call->isCallDOMNative()) {
JS_ASSERT(target && target->isNative());
Register cxReg, objReg, privReg, argsReg;
GetTempRegForIntArg(0, 0, &cxReg);

View File

@ -648,15 +648,64 @@ MParameter::congruentTo(MDefinition *ins) const
MCall *
MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
bool construct)
bool construct, bool isDOMCall)
{
JS_ASSERT(maxArgc >= numActualArgs);
MCall *ins = new(alloc) MCall(target, numActualArgs, construct);
MCall *ins;
if (isDOMCall) {
JS_ASSERT(!construct);
ins = new(alloc) MCallDOMNative(target, numActualArgs);
} else {
ins = new(alloc) MCall(target, numActualArgs, construct);
}
if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
return nullptr;
return ins;
}
AliasSet
MCallDOMNative::getAliasSet() const
{
JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
JS_ASSERT(jitInfo);
JS_ASSERT(jitInfo->aliasSet != JSJitInfo::AliasNone);
// If we don't know anything about the types of our arguments, we have to
// assume that type-coercions can have side-effects, so we need to alias
// everything.
if (jitInfo->aliasSet != JSJitInfo::AliasDOMSets || !jitInfo->argTypes)
return AliasSet::Store(AliasSet::Any);
uint32_t argIndex = 0;
for (const JSJitInfo::ArgType *argType = jitInfo->argTypes;
*argType != JSJitInfo::ArgTypeListEnd;
++argType, ++argIndex)
{
if (argIndex >= numActualArgs()) {
// Passing through undefined can't have side-effects
continue;
}
// getArg(0) is "this", so skip it
MDefinition *arg = getArg(argIndex+1);
MIRType actualType = arg->type();
// The only way to get side-effects is if we're passing in
// something that might be an object to an argument that
// expects a numeric, string, or boolean value.
if ((actualType == MIRType_Value || actualType == MIRType_Object) &&
(*argType &
(JSJitInfo::Boolean | JSJitInfo::String | JSJitInfo::Numeric)))
{
return AliasSet::Store(AliasSet::Any);
}
}
// We checked all the args, and they check out. So we only
// alias DOM mutations.
return AliasSet::Load(AliasSet::DOMProperty);
}
MApplyArgs *
MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDefinition *argc,
MDefinition *self)

View File

@ -59,8 +59,6 @@ MIRType MIRTypeFromValue(const js::Value &vp)
* points.
*/ \
_(Unused) \
_(DOMFunction) /* Contains or uses a common DOM method function */ \
\
/* Marks if an instruction has fewer uses than the original code.
* E.g. UCE can remove code.
* Every instruction where an use is/was removed from an instruction and
@ -1806,7 +1804,7 @@ class MCall
public:
INSTRUCTION_HEADER(Call)
static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
bool construct);
bool construct, bool isDOMCall);
void initFunction(MDefinition *func) {
return setOperand(FunctionOperandIndex, func);
@ -1871,49 +1869,37 @@ class MCall
TypePolicy *typePolicy() {
return this;
}
AliasSet getAliasSet() const {
if (isDOMFunction()) {
JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
const JSJitInfo* jitInfo = getSingleTarget()->jitInfo();
JS_ASSERT(jitInfo);
JS_ASSERT(jitInfo->aliasSet != JSJitInfo::AliasNone);
if (jitInfo->aliasSet == JSJitInfo::AliasDOMSets &&
jitInfo->argTypes) {
uint32_t argIndex = 0;
for (const JSJitInfo::ArgType* argType = jitInfo->argTypes;
*argType != JSJitInfo::ArgTypeListEnd;
++argType, ++argIndex)
{
if (argIndex >= numActualArgs()) {
// Passing through undefined can't have side-effects
continue;
}
// getArg(0) is "this", so skip it
MDefinition *arg = getArg(argIndex+1);
MIRType actualType = arg->type();
// The only way to get side-effects is if we're passing in
// something that might be an object to an argument that
// expects a numeric, string, or boolean value.
if ((actualType == MIRType_Value || actualType == MIRType_Object) &&
(*argType &
(JSJitInfo::Boolean | JSJitInfo::String | JSJitInfo::Numeric)))
{
return AliasSet::Store(AliasSet::Any);
}
}
// We checked all the args, and they check out. So we only
// alias DOM mutations.
return AliasSet::Load(AliasSet::DOMProperty);
}
}
return AliasSet::Store(AliasSet::Any);
}
bool possiblyCalls() const {
return true;
}
virtual bool isCallDOMNative() const {
return false;
}
};
class MCallDOMNative : public MCall
{
// A helper class for MCalls for DOM natives. Note that this is NOT
// actually a separate MIR op from MCall, because all sorts of places use
// isCall() to check for calls and all we really want is to overload a few
// virtual things from MCall.
protected:
MCallDOMNative(JSFunction *target, uint32_t numActualArgs)
: MCall(target, numActualArgs, false)
{
}
friend MCall *MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc,
size_t numActualArgs, bool construct, bool isDOMCall);
public:
virtual AliasSet getAliasSet() const MOZ_OVERRIDE;
virtual bool isCallDOMNative() const MOZ_OVERRIDE {
return true;
}
};
// fun.apply(self, arguments)

View File

@ -697,7 +697,7 @@ bool
ParallelSafetyVisitor::visitCall(MCall *ins)
{
// DOM? Scary.
if (ins->isDOMFunction()) {
if (ins->isCallDOMNative()) {
SpewMIR(ins, "call to dom function");
return markUnsafe();
}