зеркало из https://github.com/mozilla/gecko-dev.git
Bug 939581 part 1. Factor out MCallDOMNative from MCall. r=efaust,jandem
This commit is contained in:
Родитель
f98a8d58d2
Коммит
5d40f3015e
|
@ -1781,7 +1781,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
|
||||||
JS_ASSERT(target);
|
JS_ASSERT(target);
|
||||||
JS_ASSERT(target->isNative());
|
JS_ASSERT(target->isNative());
|
||||||
JS_ASSERT(target->jitInfo());
|
JS_ASSERT(target->jitInfo());
|
||||||
JS_ASSERT(call->mir()->isDOMFunction());
|
JS_ASSERT(call->mir()->isCallDOMNative());
|
||||||
|
|
||||||
int callargslot = call->argslot();
|
int callargslot = call->argslot();
|
||||||
int unusedStack = StackOffsetOfPassedArg(callargslot);
|
int unusedStack = StackOffsetOfPassedArg(callargslot);
|
||||||
|
|
|
@ -5170,8 +5170,22 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC
|
||||||
if (target && !target->isNative())
|
if (target && !target->isNative())
|
||||||
targetArgs = Max<uint32_t>(target->nargs(), callInfo.argc());
|
targetArgs = Max<uint32_t>(target->nargs(), callInfo.argc());
|
||||||
|
|
||||||
MCall *call =
|
bool isDOMCall = false;
|
||||||
MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(), callInfo.constructing());
|
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)
|
if (!call)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -5211,19 +5225,6 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC
|
||||||
callInfo.setFun(fun);
|
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))
|
if (target && !testNeedsArgumentCheck(target, callInfo))
|
||||||
call->disableArgCheck();
|
call->disableArgCheck();
|
||||||
|
|
||||||
|
@ -5268,7 +5269,7 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit
|
||||||
|
|
||||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||||
|
|
||||||
if (call->isDOMFunction())
|
if (call->isCallDOMNative())
|
||||||
return pushDOMTypeBarrier(call, types, call->getSingleTarget());
|
return pushDOMTypeBarrier(call, types, call->getSingleTarget());
|
||||||
|
|
||||||
return pushTypeBarrier(call, types, true);
|
return pushTypeBarrier(call, types, true);
|
||||||
|
|
|
@ -408,7 +408,7 @@ LIRGenerator::visitCall(MCall *call)
|
||||||
JSFunction *target = call->getSingleTarget();
|
JSFunction *target = call->getSingleTarget();
|
||||||
|
|
||||||
// Call DOM functions.
|
// Call DOM functions.
|
||||||
if (call->isDOMFunction()) {
|
if (call->isCallDOMNative()) {
|
||||||
JS_ASSERT(target && target->isNative());
|
JS_ASSERT(target && target->isNative());
|
||||||
Register cxReg, objReg, privReg, argsReg;
|
Register cxReg, objReg, privReg, argsReg;
|
||||||
GetTempRegForIntArg(0, 0, &cxReg);
|
GetTempRegForIntArg(0, 0, &cxReg);
|
||||||
|
|
|
@ -648,15 +648,64 @@ MParameter::congruentTo(MDefinition *ins) const
|
||||||
|
|
||||||
MCall *
|
MCall *
|
||||||
MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
|
MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
|
||||||
bool construct)
|
bool construct, bool isDOMCall)
|
||||||
{
|
{
|
||||||
JS_ASSERT(maxArgc >= numActualArgs);
|
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))
|
if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return ins;
|
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 *
|
||||||
MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDefinition *argc,
|
MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDefinition *argc,
|
||||||
MDefinition *self)
|
MDefinition *self)
|
||||||
|
|
|
@ -59,8 +59,6 @@ MIRType MIRTypeFromValue(const js::Value &vp)
|
||||||
* points.
|
* points.
|
||||||
*/ \
|
*/ \
|
||||||
_(Unused) \
|
_(Unused) \
|
||||||
_(DOMFunction) /* Contains or uses a common DOM method function */ \
|
|
||||||
\
|
|
||||||
/* Marks if an instruction has fewer uses than the original code.
|
/* Marks if an instruction has fewer uses than the original code.
|
||||||
* E.g. UCE can remove code.
|
* E.g. UCE can remove code.
|
||||||
* Every instruction where an use is/was removed from an instruction and
|
* Every instruction where an use is/was removed from an instruction and
|
||||||
|
@ -1806,7 +1804,7 @@ class MCall
|
||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(Call)
|
INSTRUCTION_HEADER(Call)
|
||||||
static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
|
static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
|
||||||
bool construct);
|
bool construct, bool isDOMCall);
|
||||||
|
|
||||||
void initFunction(MDefinition *func) {
|
void initFunction(MDefinition *func) {
|
||||||
return setOperand(FunctionOperandIndex, func);
|
return setOperand(FunctionOperandIndex, func);
|
||||||
|
@ -1871,49 +1869,37 @@ class MCall
|
||||||
TypePolicy *typePolicy() {
|
TypePolicy *typePolicy() {
|
||||||
return this;
|
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 {
|
bool possiblyCalls() const {
|
||||||
return true;
|
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)
|
// fun.apply(self, arguments)
|
||||||
|
|
|
@ -697,7 +697,7 @@ bool
|
||||||
ParallelSafetyVisitor::visitCall(MCall *ins)
|
ParallelSafetyVisitor::visitCall(MCall *ins)
|
||||||
{
|
{
|
||||||
// DOM? Scary.
|
// DOM? Scary.
|
||||||
if (ins->isDOMFunction()) {
|
if (ins->isCallDOMNative()) {
|
||||||
SpewMIR(ins, "call to dom function");
|
SpewMIR(ins, "call to dom function");
|
||||||
return markUnsafe();
|
return markUnsafe();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче