diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 4d3333cede7b..c6c0d929bc30 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -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") diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index e303054e3d47..892a56e512ef 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -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); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 65a6dae3aab9..f9b9852baf78 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5170,22 +5170,8 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC if (target && !target->isNative()) targetArgs = Max(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); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 7c6085dbeb7d..7182b56e183c 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -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); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 26ee6d83b860..f255bed2f92c 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -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) diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index c2cb5e6748f6..a7de8620a2f2 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -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) diff --git a/js/src/jit/ParallelSafetyAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp index c1ade1653768..b445c2ea749e 100644 --- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -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(); }