author | Jan de Mooij <jdemooij@mozilla.com> |
Fri, 27 Dec 2013 20:49:33 +0100 | |
changeset 161818 | 1ed3e04b050b17fac55c0a951917beae6cbd28ba |
parent 161817 | 07f8896db19cbc95ac470406e0b810f8e68eed8b |
child 161819 | a3afdb32b40e60ebc144cc035ce8c9c94df2f6a5 |
push id | 37994 |
push user | jandemooij@gmail.com |
push date | Fri, 27 Dec 2013 19:51:47 +0000 |
treeherder | mozilla-inbound@1ed3e04b050b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | nbp |
bugs | 952992 |
milestone | 29.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1136,17 +1136,17 @@ CodeGenerator::visitOsrReturnValue(LOsrR return true; } bool CodeGenerator::visitStackArgT(LStackArgT *lir) { const LAllocation *arg = lir->getArgument(); - MIRType argType = lir->mir()->getArgument()->type(); + MIRType argType = lir->type(); uint32_t argslot = lir->argslot(); JS_ASSERT(argslot - 1u < graph.argumentSlotCount()); int32_t stack_offset = StackOffsetOfPassedArg(argslot); Address dest(StackPointer, stack_offset); if (arg->isFloatReg()) masm.storeDouble(ToFloatRegister(arg), dest);
--- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -104,17 +104,16 @@ jit::EliminateDeadResumePointOperands(MI // current block, and keep track of its last use in a definition // (not resume point). This requires the instructions in the block // to be numbered, ensured by running this immediately after alias // analysis. uint32_t maxDefinition = 0; for (MUseDefIterator uses(*ins); uses; uses++) { if (uses.def()->block() != *block || uses.def()->isBox() || - uses.def()->isPassArg() || uses.def()->isPhi()) { maxDefinition = UINT32_MAX; break; } maxDefinition = Max(maxDefinition, uses.def()->id()); } if (maxDefinition == UINT32_MAX) @@ -968,18 +967,16 @@ TypeAnalyzer::checkFloatCoherency() // operations for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); ++block) { if (mir->shouldCancel("Check Float32 coherency")) return false; for (MDefinitionIterator def(*block); def; def++) { if (def->type() != MIRType_Float32) continue; - if (def->isPassArg()) // no check for PassArg as it is broken, see bug 915479 - continue; for (MUseDefIterator use(*def); use; use++) { MDefinition *consumer = use.def(); JS_ASSERT(consumer->isConsistentFloat32Use()); } } } #endif
--- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1295,20 +1295,16 @@ IonBuilder::traverseBytecode() if (++lockOpcodeCount == LOCK_OPCODE_GRANULARITY) { unlock(); lock(); lockOpcodeCount = 0; } #ifdef DEBUG for (size_t i = 0; i < popped.length(); i++) { - // Call instructions can discard PassArg instructions. Ignore them. - if (popped[i]->isPassArg() && !popped[i]->hasUses()) - continue; - switch (op) { case JSOP_POP: case JSOP_POPN: case JSOP_POPNV: case JSOP_DUP: case JSOP_DUP2: case JSOP_PICK: case JSOP_SWAP: @@ -3815,23 +3811,17 @@ IonBuilder::jsop_neg() if (!jsop_binary(JSOP_MUL, negator, right)) return false; return true; } bool IonBuilder::jsop_notearg() { - // JSOP_NOTEARG notes that the value in current->pop() has just - // been pushed onto the stack for use in calling a function. - MDefinition *def = current->pop(); - MPassArg *arg = MPassArg::New(alloc(), def); - - current->add(arg); - current->push(arg); + // :TODO: Remove JSOP_NOTEARG (bug 953284). return true; } class AutoAccumulateReturns { MIRGraph &graph_; MIRGraphReturns *prev_; @@ -3848,19 +3838,17 @@ class AutoAccumulateReturns }; bool IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) { JS_ASSERT(target->isInterpreted()); JS_ASSERT(IsIonInlinablePC(pc)); - // Remove any MPassArgs. - if (callInfo.isWrapped()) - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); // Ensure sufficient space in the slots: needed for inlining from FUNAPPLY. uint32_t depth = current->stackDepth() + callInfo.numFormals(); if (depth > current->nslots()) { if (!current->increaseSlots(depth - current->nslots())) return false; } @@ -4159,20 +4147,16 @@ IonBuilder::getInlineableGetPropertyCach { if (callInfo.constructing()) return nullptr; MDefinition *thisDef = callInfo.thisArg(); if (thisDef->type() != MIRType_Object) return nullptr; - // Unwrap thisDef for pointer comparison purposes. - if (thisDef->isPassArg()) - thisDef = thisDef->toPassArg()->getArgument(); - MDefinition *funcDef = callInfo.fun(); if (funcDef->type() != MIRType_Object) return nullptr; // MGetPropertyCache with no uses may be optimized away. if (funcDef->isGetPropertyCache()) { MGetPropertyCache *cache = funcDef->toGetPropertyCache(); if (cache->hasUses()) @@ -4283,17 +4267,16 @@ IonBuilder::inlineGenericFallback(JSFunc if (!fallbackBlock) return false; // Create a new CallInfo to track modified state within this block. CallInfo fallbackInfo(alloc(), callInfo.constructing()); if (!fallbackInfo.init(callInfo)) return false; fallbackInfo.popFormals(fallbackBlock); - fallbackInfo.wrapArgs(alloc(), fallbackBlock); // Generate an MCall, which uses stateful |current|. setCurrentAndSpecializePhis(fallbackBlock); if (!makeCall(target, fallbackInfo, clonedAtCallsite)) return false; // Pass return block to caller as |current|. return true; @@ -4402,20 +4385,17 @@ IonBuilder::inlineCalls(CallInfo &callIn { // Only handle polymorphic inlining. JS_ASSERT(IsIonInlinablePC(pc)); JS_ASSERT(choiceSet.length() == targets.length()); JS_ASSERT_IF(!maybeCache, targets.length() >= 2); JS_ASSERT_IF(maybeCache, targets.length() >= 1); MBasicBlock *dispatchBlock = current; - - // Unwrap the arguments. - JS_ASSERT(callInfo.isWrapped()); - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); callInfo.pushFormals(dispatchBlock); // Patch any InlinePropertyTable to only contain functions that are inlineable. // // Note that we trim using originals, as callsite clones are not user // visible. We don't patch the entries inside the table with the cloned // targets, as the entries should only be used for comparison. // @@ -4504,17 +4484,16 @@ IonBuilder::inlineCalls(CallInfo &callIn inlineBlock->rewriteSlot(funIndex, funcDef); // Create a new CallInfo to track modified state within the inline block. CallInfo inlineInfo(alloc(), callInfo.constructing()); if (!inlineInfo.init(callInfo)) return false; inlineInfo.popFormals(inlineBlock); inlineInfo.setFun(funcDef); - inlineInfo.wrapArgs(alloc(), inlineBlock); if (maybeCache) { JS_ASSERT(callInfo.thisArg() == maybeCache->object()); types::TemporaryTypeSet *targetThisTypes = maybeCache->propTable()->buildTypeSetForFunction(original); if (!targetThisTypes) return false; maybeCache->object()->setResultTypeSet(targetThisTypes); @@ -4819,20 +4798,20 @@ IonBuilder::createThis(JSFunction *targe return createThisScripted(callee); } bool IonBuilder::jsop_funcall(uint32_t argc) { // Stack for JSOP_FUNCALL: - // 1: MPassArg(arg0) + // 1: arg0 // ... - // argc: MPassArg(argN) - // argc+1: MPassArg(JSFunction *), the 'f' in |f.call()|, in |this| position. + // argc: argN + // argc+1: JSFunction*, the 'f' in |f.call()|, in |this| position. // argc+2: The native 'call' function. int calleeDepth = -((int)argc + 2); int funcDepth = -((int)argc + 1); // If |Function.prototype.call| may be overridden, don't optimize callsite. types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet(); JSFunction *native = getSingleCallTarget(calleeTypes); @@ -4843,37 +4822,25 @@ IonBuilder::jsop_funcall(uint32_t argc) return makeCall(native, callInfo, false); } current->peek(calleeDepth)->setFoldedUnchecked(); // Extract call target. types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet(); JSFunction *target = getSingleCallTarget(funTypes); - // Unwrap the (JSFunction *) parameter. - MPassArg *passFunc = current->peek(funcDepth)->toPassArg(); - current->rewriteAtDepth(funcDepth, passFunc->getArgument()); - - // Remove the MPassArg(JSFunction *). - passFunc->replaceAllUsesWith(passFunc->getArgument()); - passFunc->block()->discard(passFunc); - // Shimmy the slots down to remove the native 'call' function. current->shimmySlots(funcDepth - 1); bool zeroArguments = (argc == 0); // If no |this| argument was provided, explicitly pass Undefined. // Pushing is safe here, since one stack slot has been removed. if (zeroArguments) { - MConstant *undef = MConstant::New(alloc(), UndefinedValue()); - current->add(undef); - MPassArg *pass = MPassArg::New(alloc(), undef); - current->add(pass); - current->push(pass); + pushConstant(UndefinedValue()); } else { // |this| becomes implicit in the call. argc -= 1; } CallInfo callInfo(alloc(), false); if (!callInfo.init(current, argc)) return false; @@ -4941,48 +4908,41 @@ IonBuilder::jsop_funapply(uint32_t argc) // Use funapply that definitely uses |arguments| return jsop_funapplyarguments(argc); } bool IonBuilder::jsop_funapplyarguments(uint32_t argc) { // Stack for JSOP_FUNAPPLY: - // 1: MPassArg(Vp) - // 2: MPassArg(This) - // argc+1: MPassArg(JSFunction *), the 'f' in |f.call()|, in |this| position. + // 1: Vp + // 2: This + // argc+1: JSFunction*, the 'f' in |f.call()|, in |this| position. // argc+2: The native 'apply' function. int funcDepth = -((int)argc + 1); // Extract call target. types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet(); JSFunction *target = getSingleCallTarget(funTypes); // When this script isn't inlined, use MApplyArgs, // to copy the arguments from the stack and call the function if (inliningDepth_ == 0 && info().executionMode() != DefinitePropertiesAnalysis) { - - // Vp - MPassArg *passVp = current->pop()->toPassArg(); - passVp->getArgument()->setFoldedUnchecked(); - passVp->replaceAllUsesWith(passVp->getArgument()); - passVp->block()->discard(passVp); - - // This - MPassArg *passThis = current->pop()->toPassArg(); - MDefinition *argThis = passThis->getArgument(); - passThis->replaceAllUsesWith(argThis); - passThis->block()->discard(passThis); + // The array argument corresponds to the arguments object. As the JIT + // is implicitly reading the arguments object in the next instruction, + // we need to prevent the deletion of the arguments object from resume + // points, so that Baseline will behave correctly after a bailout. + MDefinition *vp = current->pop(); + vp->setFoldedUnchecked(); + + MDefinition *argThis = current->pop(); // Unwrap the (JSFunction *) parameter. - MPassArg *passFunc = current->pop()->toPassArg(); - MDefinition *argFunc = passFunc->getArgument(); - passFunc->replaceAllUsesWith(argFunc); - passFunc->block()->discard(passFunc); + MDefinition *argFunc = current->pop(); // Pop apply function. current->pop(); MArgumentsLength *numArgs = MArgumentsLength::New(alloc()); current->add(numArgs); MApplyArgs *apply = MApplyArgs::New(alloc(), target, argFunc, numArgs, argThis); @@ -4999,42 +4959,33 @@ IonBuilder::jsop_funapplyarguments(uint3 // and can optimize even more, by just calling the functions with the args. // We also try this path when doing the definite properties analysis, as we // can inline the apply() target and don't care about the actual arguments // that were passed in. CallInfo callInfo(alloc(), false); // Vp - MPassArg *passVp = current->pop()->toPassArg(); - passVp->getArgument()->setFoldedUnchecked(); - passVp->replaceAllUsesWith(passVp->getArgument()); - passVp->block()->discard(passVp); + MDefinition *vp = current->pop(); + vp->setFoldedUnchecked(); // Arguments MDefinitionVector args(alloc()); if (inliningDepth_) { if (!args.appendAll(inlineCallInfo_->argv())) return false; } callInfo.setArgs(&args); // This - MPassArg *passThis = current->pop()->toPassArg(); - MDefinition *argThis = passThis->getArgument(); - passThis->replaceAllUsesWith(argThis); - passThis->block()->discard(passThis); + MDefinition *argThis = current->pop(); callInfo.setThis(argThis); - // Unwrap the (JSFunction *) parameter. - MPassArg *passFunc = current->pop()->toPassArg(); - MDefinition *argFunc = passFunc->getArgument(); - passFunc->replaceAllUsesWith(argFunc); - passFunc->block()->discard(passFunc); - + // Pop function parameter. + MDefinition *argFunc = current->pop(); callInfo.setFun(argFunc); // Pop apply function. current->pop(); // Try to inline the call. InliningDecision decision = makeInliningDecision(target, callInfo); switch (decision) { @@ -5042,17 +4993,16 @@ IonBuilder::jsop_funapplyarguments(uint3 return false; case InliningDecision_DontInline: break; case InliningDecision_Inline: if (target->isInterpreted()) return inlineScriptedCall(callInfo, target); } - callInfo.wrapArgs(alloc(), current); return makeCall(target, callInfo, false); } bool IonBuilder::jsop_call(uint32_t argc, bool constructing) { // If this call has never executed, try to seed the observed type set // based on how the call result is used. @@ -5215,18 +5165,16 @@ IonBuilder::testNeedsArgumentCheck(JSFun } return false; } MCall * IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite) { - JS_ASSERT(callInfo.isWrapped()); - // This function may be called with mutated stack. // Querying TI for popped types is invalid. uint32_t targetArgs = callInfo.argc(); // Collect number of missing arguments provided that the target is // scripted. Native functions are passed an explicit 'argc' parameter. if (target && !target->isNative()) @@ -5236,58 +5184,39 @@ IonBuilder::makeCallHelper(JSFunction *t MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(), callInfo.constructing()); if (!call) return nullptr; // Explicitly pad any missing arguments with |undefined|. // This permits skipping the argumentsRectifier. for (int i = targetArgs; i > (int)callInfo.argc(); i--) { JS_ASSERT_IF(target, !target->isNative()); - MConstant *undef = MConstant::New(alloc(), UndefinedValue()); - current->add(undef); - MPassArg *pass = MPassArg::New(alloc(), undef); - current->add(pass); - call->addArg(i, pass); + MConstant *undef = constant(UndefinedValue()); + call->addArg(i, undef); } // Add explicit arguments. // Skip addArg(0) because it is reserved for this - for (int32_t i = callInfo.argc() - 1; i >= 0; i--) { - JS_ASSERT(callInfo.getArg(i)->isPassArg()); - call->addArg(i + 1, callInfo.getArg(i)->toPassArg()); - } - - // Place an MPrepareCall before the first passed argument, before we - // potentially perform rearrangement. - JS_ASSERT(callInfo.thisArg()->isPassArg()); - MPassArg *thisArg = callInfo.thisArg()->toPassArg(); - MPrepareCall *start = MPrepareCall::New(alloc()); - thisArg->block()->insertBefore(thisArg, start); - call->initPrepareCall(start); + for (int32_t i = callInfo.argc() - 1; i >= 0; i--) + call->addArg(i + 1, callInfo.getArg(i)); // Inline the constructor on the caller-side. if (callInfo.constructing()) { MDefinition *create = createThis(target, callInfo.fun()); if (!create) { abort("Failure inlining constructor for call."); return nullptr; } - // Unwrap the MPassArg before discarding: it may have been captured by an MResumePoint. - thisArg->replaceAllUsesWith(thisArg->getArgument()); - thisArg->block()->discard(thisArg); - - MPassArg *newThis = MPassArg::New(alloc(), create); - current->add(newThis); - - thisArg = newThis; - callInfo.setThis(newThis); + callInfo.thisArg()->setFoldedUnchecked(); + callInfo.setThis(create); } // Pass |this| and function. + MDefinition *thisArg = callInfo.thisArg(); call->addArg(0, thisArg); // Add a callsite clone IC for multiple targets which all should be // callsite cloned, or bake in the clone for a single target. if (cloneAtCallsite) { MDefinition *fun = makeCallsiteClone(target, callInfo.fun()); callInfo.setFun(fun); } @@ -5383,17 +5312,17 @@ IonBuilder::jsop_eval(uint32_t argc) // boxed into different objects if accessed via 'this'. JSValueType type = thisTypes->getKnownTypeTag(); if (type != JSVAL_TYPE_OBJECT && type != JSVAL_TYPE_NULL && type != JSVAL_TYPE_UNDEFINED) return abort("Direct eval from script with maybe-primitive 'this'"); CallInfo callInfo(alloc(), /* constructing = */ false); if (!callInfo.init(current, argc)) return false; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); callInfo.fun()->setFoldedUnchecked(); MDefinition *scopeChain = current->scopeChain(); MDefinition *string = callInfo.getArg(0); // Direct eval acts as identity on non-string types according to // ES5 15.1.2.1 step 1. @@ -5416,21 +5345,18 @@ IonBuilder::jsop_eval(uint32_t argc) JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom(); AutoThreadSafeAccess ts(atom); if (StringEqualsAscii(atom, "()")) { MDefinition *name = string->getOperand(0); MInstruction *dynamicName = MGetDynamicName::New(alloc(), scopeChain, name); current->add(dynamicName); - MInstruction *thisv = MPassArg::New(alloc(), thisValue); - current->add(thisv); - current->push(dynamicName); - current->push(thisv); + current->push(thisValue); CallInfo evalCallInfo(alloc(), /* constructing = */ false); if (!evalCallInfo.init(current, /* argc = */ 0)) return false; return makeCall(nullptr, evalCallInfo, false); } } @@ -8558,19 +8484,17 @@ IonBuilder::getPropTryCommonGetter(bool MGuardObject *guardObj = MGuardObject::New(alloc(), obj); current->add(guardObj); obj = guardObj; } // Spoof stack to expected state for call. pushConstant(ObjectValue(*commonGetter)); - MPassArg *wrapper = MPassArg::New(alloc(), obj); - current->add(wrapper); - current->push(wrapper); + current->push(obj); CallInfo callInfo(alloc(), false); if (!callInfo.init(current, 0)) return false; // Inline if we can, otherwise, forget it and just generate a call. bool inlineable = false; if (commonGetter->isInterpreted()) { @@ -8853,23 +8777,18 @@ IonBuilder::setPropTryCommonSetter(bool uint32_t depth = current->stackDepth() + 3; if (depth > current->nslots()) { if (!current->increaseSlots(depth - current->nslots())) return false; } pushConstant(ObjectValue(*commonSetter)); - MPassArg *wrapper = MPassArg::New(alloc(), obj); - current->push(wrapper); - current->add(wrapper); - - MPassArg *arg = MPassArg::New(alloc(), value); - current->push(arg); - current->add(arg); + current->push(obj); + current->push(value); // Call the setter. Note that we have to push the original value, not // the setter's return value. CallInfo callInfo(alloc(), false); if (!callInfo.init(current, 1)) return false; // Ensure that we know we are calling a setter in case we inline it.
--- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -927,85 +927,48 @@ class CallInfo return args_[i]; } void setArg(uint32_t i, MDefinition *def) { JS_ASSERT(i < argc()); args_[i] = def; } - MDefinition *thisArg() { + MDefinition *thisArg() const { JS_ASSERT(thisArg_); return thisArg_; } void setThis(MDefinition *thisArg) { thisArg_ = thisArg; } - bool constructing() { + bool constructing() const { return constructing_; } bool isSetter() const { return setter_; } void markAsSetter() { setter_ = true; } - void wrapArgs(TempAllocator &alloc, MBasicBlock *current) { - thisArg_ = wrap(alloc, current, thisArg_); - for (uint32_t i = 0; i < argc(); i++) - args_[i] = wrap(alloc, current, args_[i]); - } - - void unwrapArgs() { - thisArg_ = unwrap(thisArg_); - for (uint32_t i = 0; i < argc(); i++) - args_[i] = unwrap(args_[i]); - } - MDefinition *fun() const { JS_ASSERT(fun_); return fun_; } void setFun(MDefinition *fun) { - JS_ASSERT(!fun->isPassArg()); fun_ = fun; } - - bool isWrapped() { - bool wrapped = thisArg()->isPassArg(); - -#if DEBUG + void setFoldedUnchecked() { + thisArg_->setFoldedUnchecked(); for (uint32_t i = 0; i < argc(); i++) - JS_ASSERT(args_[i]->isPassArg() == wrapped); -#endif - - return wrapped; - } - - private: - static MDefinition *unwrap(MDefinition *arg) { - JS_ASSERT(arg->isPassArg()); - MPassArg *passArg = arg->toPassArg(); - MBasicBlock *block = passArg->block(); - MDefinition *wrapped = passArg->getArgument(); - wrapped->setFoldedUnchecked(); - passArg->replaceAllUsesWith(wrapped); - block->discard(passArg); - return wrapped; - } - static MDefinition *wrap(TempAllocator &alloc, MBasicBlock *current, MDefinition *arg) { - JS_ASSERT(!arg->isPassArg()); - MPassArg *passArg = MPassArg::New(alloc, arg); - current->add(passArg); - return passArg; + getArg(i)->setFoldedUnchecked(); } }; bool TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes); bool NeedsPostBarrier(CompileInfo &info, MDefinition *value); } // namespace jit
--- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -956,32 +956,33 @@ class LComputeThis : public LInstruction return mir_->toComputeThis(); } }; // Writes a typed argument for a function call to the frame's argument vector. class LStackArgT : public LInstructionHelper<0, 1, 0> { uint32_t argslot_; // Index into frame-scope argument vector. + MIRType type_; public: LIR_HEADER(StackArgT) - LStackArgT(uint32_t argslot, const LAllocation &arg) - : argslot_(argslot) + LStackArgT(uint32_t argslot, MIRType type, const LAllocation &arg) + : argslot_(argslot), + type_(type) { setOperand(0, arg); } - - MPassArg *mir() const { - return this->mir_->toPassArg(); - } uint32_t argslot() const { return argslot_; } + MIRType type() const { + return type_; + } const LAllocation *getArgument() { return getOperand(0); } }; // Writes an untyped argument for a function call to the frame's argument vector. class LStackArgV : public LInstructionHelper<0, BOX_PIECES, 0> {
--- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -283,54 +283,16 @@ LIRGenerator::visitInitPropGetterSetter( { LInitPropGetterSetter *lir = new(alloc()) LInitPropGetterSetter(useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value())); return add(lir, ins) && assignSafepoint(lir, ins); } bool -LIRGenerator::visitPrepareCall(MPrepareCall *ins) -{ - allocateArguments(ins->argc()); - -#ifdef DEBUG - if (!prepareCallStack_.append(ins)) - return false; -#endif - - return true; -} - -bool -LIRGenerator::visitPassArg(MPassArg *arg) -{ - MDefinition *opd = arg->getArgument(); - uint32_t argslot = getArgumentSlot(arg->getArgnum()); - JS_ASSERT(arg->getArgnum() < prepareCallStack_.back()->argc()); - - // Pass through the virtual register of the operand. - // This causes snapshots to correctly copy the operand on the stack. - // - // This keeps the backing store around longer than strictly required. - // We could do better by informing snapshots about the argument vector. - arg->setVirtualRegister(opd->virtualRegister()); - - // Values take a slow path. - if (opd->type() == MIRType_Value) { - LStackArgV *stack = new(alloc()) LStackArgV(argslot); - return useBox(stack, 0, opd) && add(stack); - } - - // Known types can move constant types and/or payloads. - LStackArgT *stack = new(alloc()) LStackArgT(argslot, useRegisterOrConstant(opd)); - return add(stack, arg); -} - -bool LIRGenerator::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins) { LCreateThisWithTemplate *lir = new(alloc()) LCreateThisWithTemplate(); return define(lir, ins) && assignSafepoint(lir, ins); } bool LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto *ins) @@ -398,32 +360,56 @@ LIRGenerator::visitComputeThis(MComputeT // have its inputs in different registers than its return value so that // they aren't clobbered. if (!useBox(lir, LComputeThis::ValueIndex, ins->input())) return false; return define(lir, ins) && assignSafepoint(lir, ins); } +bool +LIRGenerator::lowerCallArguments(MCall *call) +{ + uint32_t argc = call->numStackArgs(); + if (argc > maxargslots_) + maxargslots_ = argc; + + for (size_t i = 0; i < argc; i++) { + MDefinition *arg = call->getArg(i); + uint32_t argslot = argc - i; + + // Values take a slow path. + if (arg->type() == MIRType_Value) { + LStackArgV *stack = new(alloc()) LStackArgV(argslot); + if (!useBox(stack, 0, arg) || !add(stack)) + return false; + } else { + // Known types can move constant types and/or payloads. + LStackArgT *stack = new(alloc()) LStackArgT(argslot, arg->type(), useRegisterOrConstant(arg)); + if (!add(stack)) + return false; + } + } + + return true; +} bool LIRGenerator::visitCall(MCall *call) { JS_ASSERT(CallTempReg0 != CallTempReg1); JS_ASSERT(CallTempReg0 != ArgumentsRectifierReg); JS_ASSERT(CallTempReg1 != ArgumentsRectifierReg); JS_ASSERT(call->getFunction()->type() == MIRType_Object); + if (!lowerCallArguments(call)) + return false; + // Height of the current argument vector. - uint32_t argslot = getArgumentSlotForCall(); - freeArguments(call->numStackArgs()); - - // Check MPrepareCall/MCall nesting. - JS_ASSERT(prepareCallStack_.popCopy() == call->getPrepareCall()); - + uint32_t argslot = call->numStackArgs(); JSFunction *target = call->getSingleTarget(); // Call DOM functions. if (call->isDOMFunction()) { JS_ASSERT(target && target->isNative()); Register cxReg, objReg, privReg, argsReg; GetTempRegForIntArg(0, 0, &cxReg); GetTempRegForIntArg(1, 0, &objReg); @@ -1856,56 +1842,41 @@ LIRGenerator::visitToString(MToString *i default: // Objects might be effectful. (see ToPrimitive) MOZ_ASSUME_UNREACHABLE("unexpected type"); } } static bool -MustCloneRegExpForCall(MPassArg *arg) +MustCloneRegExpForCall(MCall *call, uint32_t useIndex) { - // |arg| is a regex literal flowing into a call. Return |false| iff + // We have a regex literal flowing into a call. Return |false| iff // this is a native call that does not let the regex escape. - JS_ASSERT(arg->getArgument()->isRegExp()); - - for (MUseIterator iter(arg->usesBegin()); iter != arg->usesEnd(); iter++) { - MNode *node = iter->consumer(); - if (!node->isDefinition()) - return true; - - MDefinition *def = node->toDefinition(); - if (!def->isCall()) - return true; - - MCall *call = def->toCall(); - JSFunction *target = call->getSingleTarget(); - if (!target || !target->isNative()) - return true; - - if (iter->index() == MCall::IndexOfThis() && - (target->native() == regexp_exec || target->native() == regexp_test)) - { - continue; - } - - if (iter->index() == MCall::IndexOfArgument(0) && - (target->native() == str_split || - target->native() == str_replace || - target->native() == str_match || - target->native() == str_search)) - { - continue; - } - + JSFunction *target = call->getSingleTarget(); + if (!target || !target->isNative()) return true; + + if (useIndex == MCall::IndexOfThis() && + (target->native() == regexp_exec || target->native() == regexp_test)) + { + return false; } - return false; + if (useIndex == MCall::IndexOfArgument(0) && + (target->native() == str_split || + target->native() == str_replace || + target->native() == str_match || + target->native() == str_search)) + { + return false; + } + + return true; } static bool MustCloneRegExp(MRegExp *regexp) { if (regexp->mustClone()) return true; @@ -1920,17 +1891,17 @@ MustCloneRegExp(MRegExp *regexp) MDefinition *def = node->toDefinition(); if (def->isRegExpTest() && iter->index() == 1) { // Optimized RegExp.prototype.test. JS_ASSERT(def->toRegExpTest()->regexp() == regexp); continue; } - if (def->isPassArg() && !MustCloneRegExpForCall(def->toPassArg())) + if (def->isCall() && !MustCloneRegExpForCall(def->toCall(), iter->index())) continue; return true; } return false; } bool @@ -3504,39 +3475,16 @@ LIRGenerator::updateResumeState(MInstruc void LIRGenerator::updateResumeState(MBasicBlock *block) { lastResumePoint_ = block->entryResumePoint(); if (IonSpewEnabled(IonSpew_Snapshots) && lastResumePoint_) SpewResumePoint(block, nullptr, lastResumePoint_); } -void -LIRGenerator::allocateArguments(uint32_t argc) -{ - argslots_ += argc; - if (argslots_ > maxargslots_) - maxargslots_ = argslots_; -} - -uint32_t -LIRGenerator::getArgumentSlot(uint32_t argnum) -{ - // First slot has index 1. - JS_ASSERT(argnum < argslots_); - return argslots_ - argnum ; -} - -void -LIRGenerator::freeArguments(uint32_t argc) -{ - JS_ASSERT(argc <= argslots_); - argslots_ -= argc; -} - bool LIRGenerator::visitBlock(MBasicBlock *block) { current = block->lir(); updateResumeState(block); if (!definePhis()) return false; @@ -3626,13 +3574,10 @@ LIRGenerator::generate() if (!visitBlock(*block)) return false; } if (graph.osrBlock()) lirGraph_.setOsrBlock(graph.osrBlock()->lir()); lirGraph_.setArgumentSlotCount(maxargslots_); - - JS_ASSERT(argslots_ == 0); - JS_ASSERT(prepareCallStack_.empty()); return true; }
--- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -24,31 +24,23 @@ namespace js { namespace jit { class LIRGenerator : public LIRGeneratorSpecific { void updateResumeState(MInstruction *ins); void updateResumeState(MBasicBlock *block); - // The active depth of the (perhaps nested) call argument vectors. - uint32_t argslots_; // The maximum depth, for framesizeclass determination. uint32_t maxargslots_; -#ifdef DEBUG - // In debug builds, check MPrepareCall and MCall are properly - // nested. The argslots_ mechanism relies on this. - Vector<MPrepareCall *, 4, SystemAllocPolicy> prepareCallStack_; -#endif - public: LIRGenerator(MIRGenerator *gen, MIRGraph &graph, LIRGraph &lirGraph) : LIRGeneratorSpecific(gen, graph, lirGraph), - argslots_(0), maxargslots_(0) + maxargslots_(0) { } bool generate(); private: bool useBoxAtStart(LInstruction *lir, size_t n, MDefinition *mir, LUse::Policy policy = LUse::REGISTER) { @@ -56,24 +48,17 @@ class LIRGenerator : public LIRGenerator } bool lowerBitOp(JSOp op, MInstruction *ins); bool lowerShiftOp(JSOp op, MShiftInstruction *ins); bool lowerBinaryV(JSOp op, MBinaryInstruction *ins); bool precreatePhi(LBlock *block, MPhi *phi); bool definePhis(); - // Allocate argument slots for a future function call. - void allocateArguments(uint32_t argc); - // Map an MPassArg's argument number to a slot in the frame arg vector. - // Slots are indexed from 1. argnum is indexed from 0. - uint32_t getArgumentSlot(uint32_t argnum); - uint32_t getArgumentSlotForCall() { return argslots_; } - // Free argument slots following a function call. - void freeArguments(uint32_t argc); + bool lowerCallArguments(MCall *call); public: bool visitInstruction(MInstruction *ins); bool visitBlock(MBasicBlock *block); // Visitor hooks are explicit, to give CPU-specific versions a chance to // intercept without a bunch of explicit gunk in the .cpp. bool visitParameter(MParameter *param); @@ -94,18 +79,16 @@ class LIRGenerator : public LIRGenerator bool visitInitElem(MInitElem *ins); bool visitInitElemGetterSetter(MInitElemGetterSetter *ins); bool visitInitProp(MInitProp *ins); bool visitInitPropGetterSetter(MInitPropGetterSetter *ins); bool visitCheckOverRecursed(MCheckOverRecursed *ins); bool visitCheckOverRecursedPar(MCheckOverRecursedPar *ins); bool visitDefVar(MDefVar *ins); bool visitDefFun(MDefFun *ins); - bool visitPrepareCall(MPrepareCall *ins); - bool visitPassArg(MPassArg *arg); bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins); bool visitCreateThisWithProto(MCreateThisWithProto *ins); bool visitCreateThis(MCreateThis *ins); bool visitCreateArgumentsObject(MCreateArgumentsObject *ins); bool visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins); bool visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins); bool visitReturnFromCtor(MReturnFromCtor *ins); bool visitComputeThis(MComputeThis *ins);
--- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -187,17 +187,17 @@ IonBuilder::inlineMathFunction(CallInfo return InliningStatus_NotInlined; if (!IsNumberType(callInfo.getArg(0)->type())) return InliningStatus_NotInlined; const MathCache *cache = compartment->runtime()->maybeGetMathCache(); if (!cache) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.thisArg()->setFoldedUnchecked(); MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), function, cache); current->add(ins); current->push(ins); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -229,27 +229,27 @@ IonBuilder::inlineArray(CallInfo &callIn } } } // A single integer argument denotes initial length. if (callInfo.argc() == 1) { if (callInfo.getArg(0)->type() != MIRType_Int32) return InliningStatus_NotInlined; - MDefinition *arg = callInfo.getArg(0)->toPassArg()->getArgument(); + MDefinition *arg = callInfo.getArg(0); if (!arg->isConstant()) return InliningStatus_NotInlined; // Negative lengths generate a RangeError, unhandled by the inline path. initLength = arg->toConstant()->value().toInt32(); if (initLength >= JSObject::NELEMENTS_LIMIT) return InliningStatus_NotInlined; } - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); types::TemporaryTypeSet::DoubleConversion conversion = getInlineReturnTypeSet()->convertDoubleElements(constraints()); if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) { AutoThreadSafeAccess ts(templateObject); templateObject->setShouldConvertDoubleElements(); } @@ -321,17 +321,17 @@ IonBuilder::inlineArrayPopShift(CallInfo if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) return InliningStatus_NotInlined; if (types::ArrayPrototypeHasIndexedProperty(constraints(), script())) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet(); bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED); bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType()); bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), callInfo.thisArg(), nullptr, returnTypes); if (barrier) @@ -384,17 +384,17 @@ IonBuilder::inlineArrayPush(CallInfo &ca if (types::ArrayPrototypeHasIndexedProperty(constraints(), script())) return InliningStatus_NotInlined; types::TemporaryTypeSet::DoubleConversion conversion = thisTypes->convertDoubleElements(constraints()); if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); value = callInfo.getArg(0); if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles || conversion == types::TemporaryTypeSet::MaybeConvertToDoubles) { MInstruction *valueDouble = MToDouble::New(alloc(), value); current->add(valueDouble); value = valueDouble; @@ -495,17 +495,17 @@ IonBuilder::inlineArrayConcat(CallInfo & } // Inline the call. JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat); if (!templateObj || templateObj->type() != baseThisType) return InliningStatus_NotInlined; JS_ASSERT(templateObj->is<ArrayObject>()); - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MArrayConcat *ins = MArrayConcat::New(alloc(), constraints(), callInfo.thisArg(), callInfo.getArg(0), templateObj, templateObj->type()->initialHeap(constraints())); current->add(ins); current->push(ins); if (!resumeAfter(ins)) return InliningStatus_Error; @@ -530,17 +530,17 @@ IonBuilder::inlineMathAbs(CallInfo &call // argType == Double or Float32, returnType == Int, or // argType == Float32, returnType == Double if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType_Int32) && !(argType == MIRType_Float32 && returnType == MIRType_Double)) { return InliningStatus_NotInlined; } - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); // If the arg is a Float32, we specialize the op as double, it will be specialized // as float32 if necessary later. MIRType absType = (argType == MIRType_Float32) ? MIRType_Double : argType; MInstruction *ins = MAbs::New(alloc(), callInfo.getArg(0), absType); current->add(ins); if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { @@ -563,31 +563,31 @@ IonBuilder::inlineMathFloor(CallInfo &ca if (callInfo.argc() != 1) return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); MIRType returnType = getInlineReturnType(); // Math.floor(int(x)) == int(x) if (argType == MIRType_Int32 && returnType == MIRType_Int32) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); current->push(callInfo.getArg(0)); return InliningStatus_Inlined; } if (IsFloatingPointType(argType) && returnType == MIRType_Int32) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MFloor *ins = MFloor::New(alloc(), callInfo.getArg(0)); current->add(ins); current->push(ins); return InliningStatus_Inlined; } if (IsFloatingPointType(argType) && returnType == MIRType_Double) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor, nullptr); current->add(ins); current->push(ins); return InliningStatus_Inlined; } return InliningStatus_NotInlined; } @@ -601,23 +601,23 @@ IonBuilder::inlineMathCeil(CallInfo &cal if (callInfo.argc() != 1) return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); MIRType returnType = getInlineReturnType(); // Math.ceil(int(x)) == int(x) if (argType == MIRType_Int32 && returnType == MIRType_Int32) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); current->push(callInfo.getArg(0)); return InliningStatus_Inlined; } if (IsFloatingPointType(argType) && returnType == MIRType_Double) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil, nullptr); current->add(ins); current->push(ins); return InliningStatus_Inlined; } return InliningStatus_NotInlined; } @@ -631,31 +631,31 @@ IonBuilder::inlineMathRound(CallInfo &ca if (callInfo.argc() != 1) return InliningStatus_NotInlined; MIRType returnType = getInlineReturnType(); MIRType argType = callInfo.getArg(0)->type(); // Math.round(int(x)) == int(x) if (argType == MIRType_Int32 && returnType == MIRType_Int32) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); current->push(callInfo.getArg(0)); return InliningStatus_Inlined; } if (argType == MIRType_Double && returnType == MIRType_Int32) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MRound *ins = MRound::New(alloc(), callInfo.getArg(0)); current->add(ins); current->push(ins); return InliningStatus_Inlined; } if (argType == MIRType_Double && returnType == MIRType_Double) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round, nullptr); current->add(ins); current->push(ins); return InliningStatus_Inlined; } return InliningStatus_NotInlined; } @@ -670,17 +670,17 @@ IonBuilder::inlineMathSqrt(CallInfo &cal return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); if (getInlineReturnType() != MIRType_Double) return InliningStatus_NotInlined; if (!IsNumberType(argType)) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MSqrt *sqrt = MSqrt::New(alloc(), callInfo.getArg(0)); current->add(sqrt); current->push(sqrt); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -696,17 +696,17 @@ IonBuilder::inlineMathAtan2(CallInfo &ca return InliningStatus_NotInlined; MIRType argType0 = callInfo.getArg(0)->type(); MIRType argType1 = callInfo.getArg(1)->type(); if (!IsNumberType(argType0) || !IsNumberType(argType1)) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MAtan2 *atan2 = MAtan2::New(alloc(), callInfo.getArg(0), callInfo.getArg(1)); current->add(atan2); current->push(atan2); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -722,17 +722,17 @@ IonBuilder::inlineMathHypot(CallInfo &ca return InliningStatus_NotInlined; MIRType argType0 = callInfo.getArg(0)->type(); MIRType argType1 = callInfo.getArg(1)->type(); if (!IsNumberType(argType0) || !IsNumberType(argType1)) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MHypot *hypot = MHypot::New(alloc(), callInfo.getArg(0), callInfo.getArg(1)); current->add(hypot); current->push(hypot); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -751,17 +751,17 @@ IonBuilder::inlineMathPow(CallInfo &call if (outputType != MIRType_Int32 && outputType != MIRType_Double) return InliningStatus_NotInlined; if (baseType != MIRType_Int32 && baseType != MIRType_Double) return InliningStatus_NotInlined; if (powerType != MIRType_Int32 && powerType != MIRType_Double) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MDefinition *base = callInfo.getArg(0); MDefinition *power = callInfo.getArg(1); MDefinition *output = nullptr; // Optimize some constant powers. if (callInfo.getArg(1)->isConstant() && callInfo.getArg(1)->toConstant()->value().isNumber()) @@ -843,17 +843,17 @@ IonBuilder::InliningStatus IonBuilder::inlineMathRandom(CallInfo &callInfo) { if (callInfo.constructing()) return InliningStatus_NotInlined; if (getInlineReturnType() != MIRType_Double) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MRandom *rand = MRandom::New(alloc()); current->add(rand); current->push(rand); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -866,17 +866,17 @@ IonBuilder::inlineMathImul(CallInfo &cal if (returnType != MIRType_Int32) return InliningStatus_NotInlined; if (!IsNumberType(callInfo.getArg(0)->type())) return InliningStatus_NotInlined; if (!IsNumberType(callInfo.getArg(1)->type())) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MInstruction *first = MTruncateToInt32::New(alloc(), callInfo.getArg(0)); current->add(first); MInstruction *second = MTruncateToInt32::New(alloc(), callInfo.getArg(1)); current->add(second); MMul *ins = MMul::New(alloc(), first, second, MIRType_Int32, MMul::Integer); @@ -907,17 +907,17 @@ IonBuilder::inlineMathFRound(CallInfo &c if (!IsNumberType(returnType)) return InliningStatus_NotInlined; } MIRType arg = callInfo.getArg(0)->type(); if (!IsNumberType(arg)) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MToFloat32 *ins = MToFloat32::New(alloc(), callInfo.getArg(0)); current->add(ins); current->push(ins); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -935,17 +935,17 @@ IonBuilder::inlineMathMinMax(CallInfo &c if (!IsNumberType(argType)) return InliningStatus_NotInlined; // We would need to inform TI if we happen to return a double. if (returnType == MIRType_Int32 && IsFloatingPointType(argType)) return InliningStatus_NotInlined; } - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); // Chain N-1 MMinMax instructions to compute the MinMax. MMinMax *last = MMinMax::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), returnType, max); current->add(last); for (unsigned i = 2; i < callInfo.argc(); i++) { MMinMax *ins = MMinMax::New(alloc(), last, callInfo.getArg(i), returnType, max); current->add(ins); @@ -967,17 +967,17 @@ IonBuilder::inlineStringObject(CallInfo if (type != MIRType_Int32 && type != MIRType_String) return InliningStatus_NotInlined; JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js_String); if (!templateObj) return InliningStatus_NotInlined; JS_ASSERT(templateObj->is<StringObject>()); - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MNewStringObject *ins = MNewStringObject::New(alloc(), callInfo.getArg(0), templateObj); current->add(ins); current->push(ins); if (!resumeAfter(ins)) return InliningStatus_Error; @@ -1007,17 +1007,17 @@ IonBuilder::inlineStringSplit(CallInfo & if (!key.maybeTypes()) return InliningStatus_NotInlined; if (!key.maybeTypes()->hasType(types::Type::StringType())) { key.freeze(constraints()); return InliningStatus_NotInlined; } - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MStringSplit *ins = MStringSplit::New(alloc(), constraints(), callInfo.thisArg(), callInfo.getArg(0), templateObject); current->add(ins); current->push(ins); return InliningStatus_Inlined; } @@ -1031,17 +1031,17 @@ IonBuilder::inlineStrCharCodeAt(CallInfo if (getInlineReturnType() != MIRType_Int32) return InliningStatus_NotInlined; if (callInfo.thisArg()->type() != MIRType_String && callInfo.thisArg()->type() != MIRType_Value) return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); if (argType != MIRType_Int32 && argType != MIRType_Double) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MInstruction *index = MToInt32::New(alloc(), callInfo.getArg(0)); current->add(index); MStringLength *length = MStringLength::New(alloc(), callInfo.thisArg()); current->add(length); index = addBoundsCheck(index, length); @@ -1058,17 +1058,17 @@ IonBuilder::inlineStrFromCharCode(CallIn if (callInfo.argc() != 1 || callInfo.constructing()) return InliningStatus_NotInlined; if (getInlineReturnType() != MIRType_String) return InliningStatus_NotInlined; if (callInfo.getArg(0)->type() != MIRType_Int32) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MToInt32 *charCode = MToInt32::New(alloc(), callInfo.getArg(0)); current->add(charCode); MFromCharCode *string = MFromCharCode::New(alloc(), charCode); current->add(string); current->push(string); return InliningStatus_Inlined; @@ -1083,17 +1083,17 @@ IonBuilder::inlineStrCharAt(CallInfo &ca if (getInlineReturnType() != MIRType_String) return InliningStatus_NotInlined; if (callInfo.thisArg()->type() != MIRType_String) return InliningStatus_NotInlined; MIRType argType = callInfo.getArg(0)->type(); if (argType != MIRType_Int32 && argType != MIRType_Double) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MInstruction *index = MToInt32::New(alloc(), callInfo.getArg(0)); current->add(index); MStringLength *length = MStringLength::New(alloc(), callInfo.thisArg()); current->add(length); index = addBoundsCheck(index, length); @@ -1122,17 +1122,17 @@ IonBuilder::inlineRegExpTest(CallInfo &c return InliningStatus_NotInlined; types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet(); const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr; if (clasp != &RegExpObject::class_) return InliningStatus_NotInlined; if (callInfo.getArg(0)->type() != MIRType_String) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MInstruction *match = MRegExpTest::New(alloc(), callInfo.thisArg(), callInfo.getArg(0)); current->add(match); current->push(match); if (!resumeAfter(match)) return InliningStatus_Error; return InliningStatus_Inlined; @@ -1176,17 +1176,17 @@ IonBuilder::inlineUnsafePutElements(Call ScalarTypeRepresentation::Type arrayType; if ((!isDenseNative || writeNeedsBarrier) && !ElementAccessIsTypedArray(obj, id, &arrayType)) { return InliningStatus_NotInlined; } } - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); // Push the result first so that the stack depth matches up for // the potential bailouts that will occur in the stores below. MConstant *udef = MConstant::New(alloc(), UndefinedValue()); current->add(udef); current->push(udef); for (uint32_t base = 0; base < argc; base += 3) { @@ -1269,17 +1269,17 @@ IonBuilder::inlineForceSequentialOrInPar // In sequential mode, leave as is, because we'd have to // access the "in warmup" flag of the runtime. return InliningStatus_NotInlined; case ParallelExecution: { // During Parallel Exec, we always force sequential, so // replace with true. This permits UCE to eliminate the // entire path as dead, which is important. - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MConstant *ins = MConstant::New(alloc(), BooleanValue(true)); current->add(ins); current->push(ins); return InliningStatus_Inlined; } } MOZ_ASSUME_UNREACHABLE("Invalid execution mode"); @@ -1326,17 +1326,17 @@ IonBuilder::inlineNewDenseArrayForParall if (callInfo.getArg(0)->type() != MIRType_Int32) return InliningStatus_NotInlined; types::TypeObject *typeObject = returnTypes->getTypeObject(0); JSObject *templateObject = inspector->getTemplateObjectForNative(pc, intrinsic_NewDenseArray); if (!templateObject || templateObject->type() != typeObject) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MNewDenseArrayPar *newObject = MNewDenseArrayPar::New(alloc(), graph().forkJoinSlice(), callInfo.getArg(0), templateObject); current->add(newObject); current->push(newObject); @@ -1351,22 +1351,22 @@ IonBuilder::inlineUnsafeSetReservedSlot( if (getInlineReturnType() != MIRType_Undefined) return InliningStatus_NotInlined; if (callInfo.getArg(0)->type() != MIRType_Object) return InliningStatus_NotInlined; if (callInfo.getArg(1)->type() != MIRType_Int32) return InliningStatus_NotInlined; // Don't inline if we don't have a constant slot. - MDefinition *arg = callInfo.getArg(1)->toPassArg()->getArgument(); + MDefinition *arg = callInfo.getArg(1); if (!arg->isConstant()) return InliningStatus_NotInlined; uint32_t slot = arg->toConstant()->value().toPrivateUint32(); - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MStoreFixedSlot *store = MStoreFixedSlot::New(alloc(), callInfo.getArg(0), slot, callInfo.getArg(2)); current->add(store); current->push(store); if (NeedsPostBarrier(info(), callInfo.getArg(2))) current->add(MPostWriteBarrier::New(alloc(), callInfo.thisArg(), callInfo.getArg(2))); @@ -1379,22 +1379,22 @@ IonBuilder::inlineUnsafeGetReservedSlot( if (callInfo.argc() != 2 || callInfo.constructing()) return InliningStatus_NotInlined; if (callInfo.getArg(0)->type() != MIRType_Object) return InliningStatus_NotInlined; if (callInfo.getArg(1)->type() != MIRType_Int32) return InliningStatus_NotInlined; // Don't inline if we don't have a constant slot. - MDefinition *arg = callInfo.getArg(1)->toPassArg()->getArgument(); + MDefinition *arg = callInfo.getArg(1); if (!arg->isConstant()) return InliningStatus_NotInlined; uint32_t slot = arg->toConstant()->value().toPrivateUint32(); - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MLoadFixedSlot *load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot); current->add(load); current->push(load); // We don't track reserved slot types, so always emit a barrier. if (!pushTypeBarrier(load, getInlineReturnTypeSet(), true)) return InliningStatus_Error; @@ -1418,17 +1418,17 @@ IonBuilder::inlineHaveSameClass(CallInfo const Class *arg2Clasp = arg2Types ? arg2Types->getKnownClass() : nullptr; if (arg1Clasp && arg2Clasp) { MConstant *constant = MConstant::New(alloc(), BooleanValue(arg1Clasp == arg2Clasp)); current->add(constant); current->push(constant); return InliningStatus_Inlined; } - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MHaveSameClass *sameClass = MHaveSameClass::New(alloc(), callInfo.getArg(0), callInfo.getArg(1)); current->add(sameClass); current->push(sameClass); return InliningStatus_Inlined; } @@ -1454,25 +1454,25 @@ IonBuilder::inlineIsCallable(CallInfo &c types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet(); const Class *clasp = types ? types->getKnownClass() : nullptr; if (clasp) { isCallableKnown = true; isCallableConstant = clasp->isCallable(); } } + callInfo.setFoldedUnchecked(); + if (isCallableKnown) { MConstant *constant = MConstant::New(alloc(), BooleanValue(isCallableConstant)); current->add(constant); current->push(constant); return InliningStatus_Inlined; } - callInfo.unwrapArgs(); - MIsCallable *isCallable = MIsCallable::New(alloc(), callInfo.getArg(0)); current->add(isCallable); current->push(isCallable); return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -1482,40 +1482,40 @@ IonBuilder::inlineToObject(CallInfo &cal return InliningStatus_NotInlined; // If we know the input type is an object, nop ToObject. if (getInlineReturnType() != MIRType_Object) return InliningStatus_NotInlined; if (callInfo.getArg(0)->type() != MIRType_Object) return InliningStatus_NotInlined; - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MDefinition *object = callInfo.getArg(0); current->push(object); return InliningStatus_Inlined; } IonBuilder::InliningStatus IonBuilder::inlineBailout(CallInfo &callInfo) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); current->add(MBail::New(alloc())); MConstant *undefined = MConstant::New(alloc(), UndefinedValue()); current->add(undefined); current->push(undefined); return InliningStatus_Inlined; } IonBuilder::InliningStatus IonBuilder::inlineAssertFloat32(CallInfo &callInfo) { - callInfo.unwrapArgs(); + callInfo.setFoldedUnchecked(); MDefinition *secondArg = callInfo.getArg(1); JS_ASSERT(secondArg->type() == MIRType_Boolean); JS_ASSERT(secondArg->isConstant()); bool mustBeFloat32 = JSVAL_TO_BOOLEAN(secondArg->toConstant()->value()); current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32));
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1011,39 +1011,22 @@ MPhi::addInputSlow(MDefinition *ins, boo MUse *use = &inputs_[i]; use->producer()->addUse(use); } } return true; } -uint32_t -MPrepareCall::argc() const -{ - JS_ASSERT(hasOneUse()); - MCall *call = usesBegin()->consumer()->toDefinition()->toCall(); - return call->numStackArgs(); -} - void -MPassArg::printOpcode(FILE *fp) const -{ - PrintOpcodeName(fp, op()); - fprintf(fp, " %d ", argnum_); - getOperand(0)->printName(fp); -} - -void -MCall::addArg(size_t argnum, MPassArg *arg) +MCall::addArg(size_t argnum, MDefinition *arg) { // The operand vector is initialized in reverse order by the IonBuilder. // It cannot be checked for consistency until all arguments are added. - arg->setArgnum(argnum); - setOperand(argnum + NumNonArgumentOperands, arg->toDefinition()); + setOperand(argnum + NumNonArgumentOperands, arg); } void MBitNot::infer() { if (getOperand(0)->mightBeType(MIRType_Object)) specialization_ = MIRType_None; else @@ -2105,20 +2088,16 @@ MResumePoint::MResumePoint(MBasicBlock * block->addResumePoint(this); } void MResumePoint::inherit(MBasicBlock *block) { for (size_t i = 0; i < stackDepth(); i++) { MDefinition *def = block->getSlot(i); - // We have to unwrap MPassArg: it's removed when inlining calls - // and LStackArg does not define a value. - if (def->isPassArg()) - def = def->toPassArg()->getArgument(); setOperand(i, def); } } MDefinition * MToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers) { MDefinition *input = getOperand(0);
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1742,36 +1742,16 @@ class MInitElemGetterSetter MDefinition *value() const { return getOperand(2); } TypePolicy *typePolicy() { return this; } }; -// Designates the start of call frame construction. -// Generates code to adjust the stack pointer for the argument vector. -// Argc is inferred by checking the use chain during lowering. -class MPrepareCall : public MNullaryInstruction -{ - public: - INSTRUCTION_HEADER(PrepareCall) - - static MPrepareCall *New(TempAllocator &alloc) { - return new(alloc) MPrepareCall(); - } - - // Get the vector size for the upcoming call by looking at the call. - uint32_t argc() const; - - AliasSet getAliasSet() const { - return AliasSet::None(); - } -}; - class MVariadicInstruction : public MInstruction { FixedList<MUse> operands_; protected: bool init(TempAllocator &alloc, size_t length) { return operands_.init(alloc, length); } @@ -1796,19 +1776,18 @@ class MVariadicInstruction : public MIns class MCall : public MVariadicInstruction, public CallPolicy { private: // An MCall uses the MPrepareCall, MDefinition for the function, and // MPassArg instructions. They are stored in the same list. - static const size_t PrepareCallOperandIndex = 0; - static const size_t FunctionOperandIndex = 1; - static const size_t NumNonArgumentOperands = 2; + static const size_t FunctionOperandIndex = 0; + static const size_t NumNonArgumentOperands = 1; protected: // True if the call is for JSOP_NEW. bool construct_; // Monomorphic cache of single target from TI, or nullptr. CompilerRootFunction target_; // Original value of argc from the bytecode. uint32_t numActualArgs_; @@ -1824,59 +1803,53 @@ class MCall setResultType(MIRType_Value); } public: INSTRUCTION_HEADER(Call) static MCall *New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs, bool construct); - void initPrepareCall(MDefinition *start) { - JS_ASSERT(start->isPrepareCall()); - return setOperand(PrepareCallOperandIndex, start); - } void initFunction(MDefinition *func) { - JS_ASSERT(!func->isPassArg()); return setOperand(FunctionOperandIndex, func); } bool needsArgCheck() const { return needsArgCheck_; } void disableArgCheck() { needsArgCheck_ = false; } - - MPrepareCall *getPrepareCall() { - return getOperand(PrepareCallOperandIndex)->toPrepareCall(); - } MDefinition *getFunction() const { return getOperand(FunctionOperandIndex); } void replaceFunction(MInstruction *newfunc) { replaceOperand(FunctionOperandIndex, newfunc); } - void addArg(size_t argnum, MPassArg *arg); + void addArg(size_t argnum, MDefinition *arg); MDefinition *getArg(uint32_t index) const { return getOperand(NumNonArgumentOperands + index); } void replaceArg(uint32_t index, MDefinition *def) { replaceOperand(NumNonArgumentOperands + index, def); } static size_t IndexOfThis() { return NumNonArgumentOperands; } static size_t IndexOfArgument(size_t index) { return NumNonArgumentOperands + index + 1; // +1 to skip |this|. } + static size_t IndexOfStackArg(size_t index) { + return NumNonArgumentOperands + index; + } // For TI-informed monomorphic callsites. JSFunction *getSingleTarget() const { return target_; } bool isConstructing() const { return construct_; @@ -2798,65 +2771,16 @@ class MReturnFromCtor AliasSet getAliasSet() const { return AliasSet::None(); } TypePolicy *typePolicy() { return this; } }; -// Passes an MDefinition to an MCall. Must occur between an MPrepareCall and -// MCall. Boxes the input and stores it to the correct location on stack. -// -// Arguments are *not* simply pushed onto a call stack: they are evaluated -// left-to-right, but stored in the arg vector in C-style, right-to-left. -class MPassArg - : public MUnaryInstruction, - public NoFloatPolicy<0> -{ - int32_t argnum_; - - private: - MPassArg(MDefinition *def) - : MUnaryInstruction(def), argnum_(-1) - { - setResultType(def->type()); - setResultTypeSet(def->resultTypeSet()); - } - - public: - INSTRUCTION_HEADER(PassArg) - static MPassArg *New(TempAllocator &alloc, MDefinition *def) - { - return new(alloc) MPassArg(def); - } - - MDefinition *getArgument() const { - return getOperand(0); - } - - // Set by the MCall. - void setArgnum(uint32_t argnum) { - argnum_ = argnum; - JS_ASSERT(argnum_ >= 0); - } - uint32_t getArgnum() const { - JS_ASSERT(argnum_ >= 0); - return (uint32_t)argnum_; - } - AliasSet getAliasSet() const { - return AliasSet::None(); - } - void printOpcode(FILE *fp) const; - - TypePolicy *typePolicy() { - return this; - } -}; - // Converts a primitive (either typed or untyped) to a double. If the input is // not primitive at runtime, a bailout occurs. class MToDouble : public MUnaryInstruction, public ToDoublePolicy { public: // Types of values which can be converted.
--- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -32,18 +32,16 @@ namespace jit { _(DefFun) \ _(CreateThis) \ _(CreateThisWithProto) \ _(CreateThisWithTemplate) \ _(CreateArgumentsObject) \ _(GetArgumentsObjectArg) \ _(SetArgumentsObjectArg) \ _(ComputeThis) \ - _(PrepareCall) \ - _(PassArg) \ _(Call) \ _(ApplyArgs) \ _(Bail) \ _(AssertFloat32) \ _(GetDynamicName) \ _(FilterArgumentsOrEval) \ _(CallDirectEval) \ _(BitNot) \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -130,18 +130,16 @@ class ParallelSafetyVisitor : public MIn UNSAFE_OP(DefFun) UNSAFE_OP(CreateThis) CUSTOM_OP(CreateThisWithTemplate) UNSAFE_OP(CreateThisWithProto) UNSAFE_OP(CreateArgumentsObject) UNSAFE_OP(GetArgumentsObjectArg) UNSAFE_OP(SetArgumentsObjectArg) UNSAFE_OP(ComputeThis) - SAFE_OP(PrepareCall) - SAFE_OP(PassArg) CUSTOM_OP(Call) UNSAFE_OP(ApplyArgs) UNSAFE_OP(Bail) UNSAFE_OP(AssertFloat32) UNSAFE_OP(GetDynamicName) UNSAFE_OP(FilterArgumentsOrEval) UNSAFE_OP(CallDirectEval) SAFE_OP(BitNot)
--- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -2064,20 +2064,16 @@ RangeAnalysis::addRangeAssertions() } Range r(ins); // Don't insert assertions if there's nothing interesting to assert. if (r.isUnknown() || (ins->type() == MIRType_Int32 && r.isUnknownInt32())) continue; - // Range-checking PassArgs breaks stuff. - if (ins->isPassArg()) - continue; - MAssertRange *guard = MAssertRange::New(alloc(), ins, new(alloc()) Range(r)); // The code that removes beta nodes assumes that it can find them // in a contiguous run at the top of each block. Don't insert // range assertions in between beta nodes. MInstructionIterator insertIter = iter; while (insertIter->isBeta()) insertIter++;
--- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -520,26 +520,32 @@ Float32Policy<Op>::staticAdjustInputs(Te def->replaceOperand(Op, replace); return true; } template bool Float32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); template bool Float32Policy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); template bool Float32Policy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); +static void +EnsureOperandNotFloat32(TempAllocator &alloc, MInstruction *def, unsigned op) +{ + MDefinition *in = def->getOperand(op); + if (in->type() == MIRType_Float32) { + MToDouble *replace = MToDouble::New(alloc, in); + def->block()->insertBefore(def, replace); + def->replaceOperand(op, replace); + } +} + template <unsigned Op> bool NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) { - MDefinition *in = def->getOperand(Op); - if (in->type() == MIRType_Float32) { - MToDouble *replace = MToDouble::New(alloc, in); - def->block()->insertBefore(def, replace); - def->replaceOperand(Op, replace); - } + EnsureOperandNotFloat32(alloc, def, Op); return true; } template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); @@ -635,27 +641,29 @@ template bool ObjectPolicy<2>::staticAdj template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); bool CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { MCall *call = ins->toCall(); MDefinition *func = call->getFunction(); - if (func->type() == MIRType_Object) - return true; + if (func->type() != MIRType_Object) { + // If the function is impossible to call, + // bail out by causing a subsequent unbox to fail. + if (func->type() != MIRType_Value) + func = boxAt(alloc, call, func); - // If the function is impossible to call, - // bail out by causing a subsequent unbox to fail. - if (func->type() != MIRType_Value) - func = boxAt(alloc, call, func); + MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible); + call->block()->insertBefore(call, unbox); + call->replaceFunction(unbox); + } - MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible); - call->block()->insertBefore(call, unbox); - call->replaceFunction(unbox); + for (uint32_t i = 0; i < call->numStackArgs(); i++) + EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i)); return true; } bool CallSetElementPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) { // The first operand should be an object.
--- a/js/src/jit/UnreachableCodeElimination.cpp +++ b/js/src/jit/UnreachableCodeElimination.cpp @@ -283,32 +283,16 @@ UnreachableCodeElimination::removeUnmark redundantPhis_ = true; break; } } } } } - // When we remove a call, we can't leave the corresponding MPassArg - // in the graph. Since lowering will fail. Replace it with the - // argument for the exceptional case when it is kept alive in a - // ResumePoint. DCE will remove the unused MPassArg instruction. - for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) { - if (iter->isCall()) { - MCall *call = iter->toCall(); - for (size_t i = 0; i < call->numStackArgs(); i++) { - JS_ASSERT(call->getArg(i)->isPassArg()); - JS_ASSERT(call->getArg(i)->hasOneDefUse()); - MPassArg *arg = call->getArg(i)->toPassArg(); - arg->replaceAllUsesWith(arg->getArgument()); - } - } - } - graph_.removeBlock(block); } } JS_ASSERT(id == 0); return true; }
--- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -135,20 +135,16 @@ CodeGeneratorShared::encodeSlots(LSnapsh uint32_t *startIndex) { IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u", resumePoint->numOperands(), (void *) resumePoint, *startIndex); for (uint32_t slotno = 0, e = resumePoint->numOperands(); slotno < e; slotno++) { uint32_t i = slotno + *startIndex; MDefinition *mir = resumePoint->getOperand(slotno); - if (mir->isPassArg()) - mir = mir->toPassArg()->getArgument(); - JS_ASSERT(!mir->isPassArg()); - if (mir->isBox()) mir = mir->toBox()->getOperand(0); MIRType type = mir->isUnused() ? MIRType_Undefined : mir->type(); switch (type) {
--- a/js/src/jit/shared/Lowering-shared.cpp +++ b/js/src/jit/shared/Lowering-shared.cpp @@ -72,20 +72,16 @@ LIRGeneratorShared::buildSnapshot(LInstr for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) { MResumePoint *mir = *it; for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { MDefinition *ins = mir->getOperand(j); LAllocation *type = snapshot->typeOfSlot(i); LAllocation *payload = snapshot->payloadOfSlot(i); - if (ins->isPassArg()) - ins = ins->toPassArg()->getArgument(); - JS_ASSERT(!ins->isPassArg()); - if (ins->isBox()) ins = ins->toBox()->getOperand(0); // Guards should never be eliminated. JS_ASSERT_IF(ins->isUnused(), !ins->isGuard()); // Snapshot operands other than constants should never be // emitted-at-uses. Try-catch support depends on there being no @@ -127,20 +123,16 @@ LIRGeneratorShared::buildSnapshot(LInstr return nullptr; size_t i = 0; for (MResumePoint **it = iter.begin(), **end = iter.end(); it != end; ++it) { MResumePoint *mir = *it; for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { MDefinition *def = mir->getOperand(j); - if (def->isPassArg()) - def = def->toPassArg()->getArgument(); - JS_ASSERT(!def->isPassArg()); - if (def->isBox()) def = def->toBox()->getOperand(0); // Guards should never be eliminated. JS_ASSERT_IF(def->isUnused(), !def->isGuard()); // Snapshot operands other than constants should never be // emitted-at-uses. Try-catch support depends on there being no