зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 939581) to see if it fixes the apparently permanent rootanalysis orange
Backed out changeset 6034450c8684 (bug 939581) Backed out changeset 6badd39e9d6f (bug 939581) Backed out changeset 4abc092e62c5 (bug 939581)
This commit is contained in:
Родитель
4d93bc9db0
Коммит
ce414466c8
|
@ -6391,16 +6391,8 @@ class CGMemberJITInfo(CGThing):
|
|||
# one of them must take arguments.
|
||||
methodInfal = False
|
||||
args = None
|
||||
movable = False
|
||||
else:
|
||||
sig = sigs[0]
|
||||
# For pure methods, it's OK to set movable to our notion of
|
||||
# infallible on the C++ side, without considering argument
|
||||
# conversions, since argument conversions that can reliably
|
||||
# throw would be effectful anyway and the jit doesn't move
|
||||
# effectful things.
|
||||
hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
|
||||
movable = methodPure and hasInfallibleImpl
|
||||
# XXXbz can we move the smarts about fallibility due to arg
|
||||
# conversions into the JIT, using our new args stuff?
|
||||
if (len(sig[1]) != 0 or
|
||||
|
@ -6408,19 +6400,19 @@ class CGMemberJITInfo(CGThing):
|
|||
# We have arguments or our return-value boxing can fail
|
||||
methodInfal = False
|
||||
else:
|
||||
methodInfal = hasInfallibleImpl
|
||||
methodInfal = "infallible" in self.descriptor.getExtendedAttributes(self.member)
|
||||
# For now, only bother to output args if we're pure
|
||||
if methodPure:
|
||||
args = sig[1]
|
||||
else:
|
||||
args = None
|
||||
|
||||
if args is not None:
|
||||
if args:
|
||||
aliasSet = "AliasDOMSets"
|
||||
else:
|
||||
aliasSet = "AliasEverything"
|
||||
result = self.defineJitInfo(methodinfo, method, "Method",
|
||||
methodInfal, movable, aliasSet, False, "0",
|
||||
methodInfal, False, aliasSet, False, "0",
|
||||
[s[0] for s in sigs], args)
|
||||
return result
|
||||
raise TypeError("Illegal member type to CGPropertyJITInfo")
|
||||
|
|
|
@ -1781,7 +1781,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
|
|||
JS_ASSERT(target);
|
||||
JS_ASSERT(target->isNative());
|
||||
JS_ASSERT(target->jitInfo());
|
||||
JS_ASSERT(call->mir()->isCallDOMNative());
|
||||
JS_ASSERT(call->mir()->isDOMFunction());
|
||||
|
||||
int callargslot = call->argslot();
|
||||
int unusedStack = StackOffsetOfPassedArg(callargslot);
|
||||
|
|
|
@ -5170,22 +5170,8 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC
|
|||
if (target && !target->isNative())
|
||||
targetArgs = Max<uint32_t>(target->nargs(), callInfo.argc());
|
||||
|
||||
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);
|
||||
MCall *call =
|
||||
MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(), callInfo.constructing());
|
||||
if (!call)
|
||||
return nullptr;
|
||||
|
||||
|
@ -5202,9 +5188,6 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC
|
|||
for (int32_t i = callInfo.argc() - 1; i >= 0; i--)
|
||||
call->addArg(i + 1, callInfo.getArg(i));
|
||||
|
||||
// Now that we've told it about all the args, compute whether it's movable
|
||||
call->computeMovable();
|
||||
|
||||
// Inline the constructor on the caller-side.
|
||||
if (callInfo.constructing()) {
|
||||
MDefinition *create = createThis(target, callInfo.fun());
|
||||
|
@ -5228,6 +5211,19 @@ 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();
|
||||
|
||||
|
@ -5267,12 +5263,12 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit
|
|||
return false;
|
||||
|
||||
current->push(call);
|
||||
if (call->isEffectful() && !resumeAfter(call))
|
||||
if (!resumeAfter(call))
|
||||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
|
||||
if (call->isCallDOMNative())
|
||||
if (call->isDOMFunction())
|
||||
return pushDOMTypeBarrier(call, types, call->getSingleTarget());
|
||||
|
||||
return pushTypeBarrier(call, types, true);
|
||||
|
|
|
@ -408,7 +408,7 @@ LIRGenerator::visitCall(MCall *call)
|
|||
JSFunction *target = call->getSingleTarget();
|
||||
|
||||
// Call DOM functions.
|
||||
if (call->isCallDOMNative()) {
|
||||
if (call->isDOMFunction()) {
|
||||
JS_ASSERT(target && target->isNative());
|
||||
Register cxReg, objReg, privReg, argsReg;
|
||||
GetTempRegForIntArg(0, 0, &cxReg);
|
||||
|
|
|
@ -648,120 +648,15 @@ MParameter::congruentTo(MDefinition *ins) const
|
|||
|
||||
MCall *
|
||||
MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
|
||||
bool construct, bool isDOMCall)
|
||||
bool construct)
|
||||
{
|
||||
JS_ASSERT(maxArgc >= numActualArgs);
|
||||
MCall *ins;
|
||||
if (isDOMCall) {
|
||||
JS_ASSERT(!construct);
|
||||
ins = new(alloc) MCallDOMNative(target, numActualArgs);
|
||||
} else {
|
||||
ins = new(alloc) MCall(target, numActualArgs, construct);
|
||||
}
|
||||
MCall *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 reliably avoid side-effects given the informtion we
|
||||
// have here is if we're passing in a known primitive value to an
|
||||
// argument that expects a primitive value. XXXbz maybe we need to
|
||||
// communicate better information. For example, a sequence argument
|
||||
// will sort of unavoidably have side effects, while a typed array
|
||||
// argument won't have any, but both are claimed to be
|
||||
// JSJitInfo::Object.
|
||||
if ((actualType == MIRType_Value || actualType == MIRType_Object) ||
|
||||
(*argType & JSJitInfo::Object))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
MCallDOMNative::computeMovable()
|
||||
{
|
||||
// We are movable if the jitinfo says we can be and if we're also not
|
||||
// effectful. The jitinfo can't check for the latter, since it depends on
|
||||
// the types of our arguments.
|
||||
JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
|
||||
|
||||
const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
|
||||
JS_ASSERT(jitInfo);
|
||||
|
||||
JS_ASSERT_IF(jitInfo->isMovable,
|
||||
jitInfo->aliasSet != JSJitInfo::AliasEverything);
|
||||
|
||||
if (jitInfo->isMovable && !isEffectful())
|
||||
setMovable();
|
||||
}
|
||||
|
||||
bool
|
||||
MCallDOMNative::congruentTo(MDefinition *ins) const
|
||||
{
|
||||
if (!isMovable())
|
||||
return false;
|
||||
|
||||
if (!ins->isCall())
|
||||
return false;
|
||||
|
||||
MCall *call = ins->toCall();
|
||||
|
||||
if (!call->isCallDOMNative())
|
||||
return false;
|
||||
|
||||
if (getSingleTarget() != call->getSingleTarget())
|
||||
return false;
|
||||
|
||||
if (isConstructing() != call->isConstructing())
|
||||
return false;
|
||||
|
||||
if (numActualArgs() != call->numActualArgs())
|
||||
return false;
|
||||
|
||||
if (needsArgCheck() != call->needsArgCheck())
|
||||
return false;
|
||||
|
||||
if (!congruentIfOperandsEqual(call))
|
||||
return false;
|
||||
|
||||
// The other call had better be movable at this point!
|
||||
JS_ASSERT(call->isMovable());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MApplyArgs *
|
||||
MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDefinition *argc,
|
||||
MDefinition *self)
|
||||
|
|
|
@ -59,6 +59,8 @@ 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
|
||||
|
@ -1804,7 +1806,7 @@ class MCall
|
|||
public:
|
||||
INSTRUCTION_HEADER(Call)
|
||||
static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
|
||||
bool construct, bool isDOMCall);
|
||||
bool construct);
|
||||
|
||||
void initFunction(MDefinition *func) {
|
||||
return setOperand(FunctionOperandIndex, func);
|
||||
|
@ -1830,6 +1832,10 @@ class MCall
|
|||
return getOperand(NumNonArgumentOperands + index);
|
||||
}
|
||||
|
||||
void replaceArg(uint32_t index, MDefinition *def) {
|
||||
replaceOperand(NumNonArgumentOperands + index, def);
|
||||
}
|
||||
|
||||
static size_t IndexOfThis() {
|
||||
return NumNonArgumentOperands;
|
||||
}
|
||||
|
@ -1865,48 +1871,49 @@ 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;
|
||||
}
|
||||
|
||||
// A method that can be called to tell the MCall to figure out whether it's
|
||||
// movable or not. This can't be done in the constructor, because it
|
||||
// depends on the arguments to the call, and those aren't passed to the
|
||||
// constructor but are set up later via addArg.
|
||||
virtual void computeMovable() {
|
||||
}
|
||||
};
|
||||
|
||||
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 congruentTo(MDefinition *ins) const MOZ_OVERRIDE;
|
||||
|
||||
virtual bool isCallDOMNative() const MOZ_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void computeMovable() MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
// fun.apply(self, arguments)
|
||||
|
|
|
@ -697,7 +697,7 @@ bool
|
|||
ParallelSafetyVisitor::visitCall(MCall *ins)
|
||||
{
|
||||
// DOM? Scary.
|
||||
if (ins->isCallDOMNative()) {
|
||||
if (ins->isDOMFunction()) {
|
||||
SpewMIR(ins, "call to dom function");
|
||||
return markUnsafe();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче