diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index b7addc635be..f886024288a 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -204,15 +204,16 @@ CodeGenerator::visitPolyInlineDispatch(LPolyInlineDispatch *lir) return true; } +typedef JSFlatString *(*IntToStringFn)(JSContext *, int); +static const VMFunction IntToStringInfo = + FunctionInfo(Int32ToString); + bool CodeGenerator::visitIntToString(LIntToString *lir) { Register input = ToRegister(lir->input()); Register output = ToRegister(lir->output()); - typedef JSFlatString *(*pf)(JSContext *, int); - static const VMFunction IntToStringInfo = FunctionInfo(Int32ToString); - OutOfLineCode *ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input), StoreRegisterTo(output)); if (!ool) @@ -228,26 +229,27 @@ CodeGenerator::visitIntToString(LIntToString *lir) return true; } +typedef JSObject *(*CloneRegExpObjectFn)(JSContext *, JSObject *, JSObject *); +static const VMFunction CloneRegExpObjectInfo = + FunctionInfo(CloneRegExpObject); + bool CodeGenerator::visitRegExp(LRegExp *lir) { JSObject *proto = lir->mir()->getRegExpPrototype(); - typedef JSObject *(*pf)(JSContext *, JSObject *, JSObject *); - static const VMFunction CloneRegExpObjectInfo = FunctionInfo(CloneRegExpObject); - pushArg(ImmGCPtr(proto)); pushArg(ImmGCPtr(lir->mir()->source())); return callVM(CloneRegExpObjectInfo, lir); } +typedef bool (*ExecuteRegExpFn)(JSContext *cx, RegExpExecType type, HandleObject regexp, + HandleString string, MutableHandleValue rval); +static const VMFunction ExecuteRegExpInfo = FunctionInfo(ExecuteRegExp); + bool CodeGenerator::visitRegExpTest(LRegExpTest *lir) { - typedef bool (*pf)(JSContext *cx, RegExpExecType type, HandleObject regexp, - HandleString string, MutableHandleValue rval); - static const VMFunction ExecuteRegExpInfo = FunctionInfo(ExecuteRegExp); - pushArg(ToRegister(lir->string())); pushArg(ToRegister(lir->regexp())); pushArg(Imm32(RegExpTest)); @@ -265,15 +267,16 @@ CodeGenerator::visitRegExpTest(LRegExpTest *lir) return true; } +typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject); +static const VMFunction LambdaInfo = + FunctionInfo(js::Lambda); + bool CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir) { - typedef JSObject *(*pf)(JSContext *, HandleFunction, HandleObject); - static const VMFunction Info = FunctionInfo(js::Lambda); - pushArg(ToRegister(lir->scopeChain())); pushArg(ImmGCPtr(lir->mir()->fun())); - return callVM(Info, lir); + return callVM(LambdaInfo, lir); } bool @@ -283,10 +286,7 @@ CodeGenerator::visitLambda(LLambda *lir) Register output = ToRegister(lir->output()); JSFunction *fun = lir->mir()->fun(); - typedef JSObject *(*pf)(JSContext *, HandleFunction, HandleObject); - static const VMFunction Info = FunctionInfo(js::Lambda); - - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), ImmGCPtr(fun), scopeChain), + OutOfLineCode *ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(fun), scopeChain), StoreRegisterTo(output)); if (!ool) return false; @@ -775,14 +775,14 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call) return true; } +typedef bool (*InvokeFunctionFn)(JSContext *, JSFunction *, uint32, Value *, Value *); +static const VMFunction InvokeFunctionInfo = + FunctionInfo(InvokeFunction); bool CodeGenerator::emitCallInvokeFunction(LInstruction *call, Register calleereg, uint32 argc, uint32 unusedStack) { - typedef bool (*pf)(JSContext *, JSFunction *, uint32, Value *, Value *); - static const VMFunction InvokeFunctionInfo = FunctionInfo(InvokeFunction); - // Nestle %esp up to the argument vector. // Each path must account for framePushed_ separately, for callVM to be valid. masm.freeStack(unusedStack); @@ -826,9 +826,7 @@ CodeGenerator::visitCallGeneric(LCallGeneric *call) // Generate an ArgumentsRectifier. IonCompartment *ion = gen->ionCompartment(); - IonCode *argumentsRectifier = ion->getArgumentsRectifier(GetIonContext()->cx); - if (!argumentsRectifier) - return false; + IonCode *argumentsRectifier = ion->getArgumentsRectifier(); masm.checkStackAlignment(); @@ -985,6 +983,10 @@ CodeGenerator::visitCallKnown(LCallKnown *call) return true; } +typedef bool (*InvokeConstructorFn)(JSContext *, JSObject *, uint32, Value *, Value *); +static const VMFunction InvokeConstructorInfo = + FunctionInfo(ion::InvokeConstructor); + bool CodeGenerator::visitCallConstructor(LCallConstructor *call) { @@ -997,9 +999,6 @@ CodeGenerator::visitCallConstructor(LCallConstructor *call) uint32 callargslot = call->argslot(); uint32 unusedStack = StackOffsetOfPassedArg(callargslot); - typedef bool (*pf)(JSContext *, JSObject *, uint32, Value *, Value *); - static const VMFunction InvokeConstructorInfo = FunctionInfo(ion::InvokeConstructor); - // Nestle %esp up to the argument vector. masm.freeStack(unusedStack); @@ -1023,9 +1022,6 @@ CodeGenerator::emitCallInvokeFunction(LApplyArgsGeneric *apply, Register extraSt Register objreg = ToRegister(apply->getTempObject()); JS_ASSERT(objreg != extraStackSize); - typedef bool (*pf)(JSContext *, JSFunction *, uint32, Value *, Value *); - static const VMFunction InvokeFunctionInfo = FunctionInfo(InvokeFunction); - // Push the space used by the arguments. masm.movePtr(StackPointer, objreg); masm.Push(extraStackSize); @@ -1197,9 +1193,7 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply) // Hardcode the address of the argumentsRectifier code. IonCompartment *ion = gen->ionCompartment(); - IonCode *argumentsRectifier = ion->getArgumentsRectifier(GetIonContext()->cx); - if (!argumentsRectifier) - return false; + IonCode *argumentsRectifier = ion->getArgumentsRectifier(); JS_ASSERT(ArgumentsRectifierReg != objreg); masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking. @@ -1335,15 +1329,16 @@ CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir) return true; } +typedef bool (*DefVarOrConstFn)(JSContext *, HandlePropertyName, unsigned, HandleObject); +static const VMFunction DefVarOrConstInfo = + FunctionInfo(DefVarOrConst); + bool CodeGenerator::visitDefVar(LDefVar *lir) { Register scopeChain = ToRegister(lir->getScopeChain()); Register nameTemp = ToRegister(lir->nameTemp()); - typedef bool (*pf)(JSContext *, HandlePropertyName, unsigned, HandleObject); - static const VMFunction DefVarOrConstInfo = FunctionInfo(DefVarOrConst); - masm.movePtr(ImmGCPtr(lir->mir()->name()), nameTemp); pushArg(scopeChain); // JSObject * @@ -1356,16 +1351,16 @@ CodeGenerator::visitDefVar(LDefVar *lir) return true; } +typedef bool (*ReportOverRecursedFn)(JSContext *); +static const VMFunction CheckOverRecursedInfo = + FunctionInfo(CheckOverRecursed); + bool CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool) { // The OOL path is hit if the recursion depth has been exceeded. // Throw an InternalError for over-recursion. - typedef bool (*pf)(JSContext *); - static const VMFunction CheckOverRecursedInfo = - FunctionInfo(CheckOverRecursed); - // LFunctionEnvironment can appear before LCheckOverRecursed, so we have // to save all live registers to avoid crashes if CheckOverRecursed triggers // a GC. @@ -1421,14 +1416,15 @@ class OutOfLineNewArray : public OutOfLineCodeBase } }; +typedef JSObject *(*NewInitArrayFn)(JSContext *, uint32, types::TypeObject *); +static const VMFunction NewInitArrayInfo = + FunctionInfo(NewInitArray); + bool CodeGenerator::visitNewArrayCallVM(LNewArray *lir) { Register objReg = ToRegister(lir->output()); - typedef JSObject *(*pf)(JSContext *, uint32, types::TypeObject *); - static const VMFunction NewInitArrayInfo = FunctionInfo(NewInitArray); - JS_ASSERT(!lir->isCall()); saveLive(lir); @@ -1531,19 +1527,19 @@ class OutOfLineNewObject : public OutOfLineCodeBase } }; +typedef JSObject *(*NewInitObjectFn)(JSContext *, HandleObject); +static const VMFunction NewInitObjectInfo = FunctionInfo(NewInitObject); + bool CodeGenerator::visitNewObjectVMCall(LNewObject *lir) { Register objReg = ToRegister(lir->output()); - typedef JSObject *(*pf)(JSContext *, HandleObject); - static const VMFunction Info = FunctionInfo(NewInitObject); - JS_ASSERT(!lir->isCall()); saveLive(lir); pushArg(ImmGCPtr(lir->mir()->templateObject())); - if (!callVM(Info, lir)) + if (!callVM(NewInitObjectInfo, lir)) return false; if (ReturnReg != objReg) @@ -1583,14 +1579,16 @@ CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject *ool) return true; } +typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape, + HandleTypeObject, HeapSlot *); +static const VMFunction NewCallObjectInfo = + FunctionInfo(NewCallObject); + bool CodeGenerator::visitNewCallObject(LNewCallObject *lir) { Register obj = ToRegister(lir->output()); - typedef JSObject *(*pf)(JSContext *, HandleShape, HandleTypeObject, HeapSlot *); - static const VMFunction NewCallObjectInfo = FunctionInfo(NewCallObject); - JSObject *templateObj = lir->mir()->templateObj(); // If we have a template object, we can inline call object creation. @@ -1620,6 +1618,9 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir) return true; } +typedef JSObject *(*NewStringObjectFn)(JSContext *, HandleString); +static const VMFunction NewStringObjectInfo = FunctionInfo(NewStringObject); + bool CodeGenerator::visitNewStringObject(LNewStringObject *lir) { @@ -1627,9 +1628,6 @@ CodeGenerator::visitNewStringObject(LNewStringObject *lir) Register output = ToRegister(lir->output()); Register temp = ToRegister(lir->temp()); - typedef JSObject *(*pf)(JSContext *, HandleString); - static const VMFunction NewStringObjectInfo = FunctionInfo(NewStringObject); - StringObject *templateObj = lir->mir()->templateObj(); OutOfLineCode *ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input), @@ -1649,14 +1647,16 @@ CodeGenerator::visitNewStringObject(LNewStringObject *lir) return true; } +typedef bool(*InitPropFn)(JSContext *cx, HandleObject obj, + HandlePropertyName name, HandleValue value); +static const VMFunction InitPropInfo = + FunctionInfo(InitProp); + bool CodeGenerator::visitInitProp(LInitProp *lir) { Register objReg = ToRegister(lir->getObject()); - typedef bool(*pf)(JSContext *, HandleObject, HandlePropertyName, HandleValue); - static const VMFunction InitPropInfo = FunctionInfo(InitProp); - pushArg(ToValue(lir, LInitProp::ValueIndex)); pushArg(ImmGCPtr(lir->mir()->propertyName())); pushArg(objReg); @@ -1664,6 +1664,10 @@ CodeGenerator::visitInitProp(LInitProp *lir) return callVM(InitPropInfo, lir); } +typedef JSObject *(*NewGCThingFn)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize); +static const VMFunction NewGCThingInfo = + FunctionInfo(js::ion::NewGCThing); + bool CodeGenerator::visitCreateThis(LCreateThis *lir) { @@ -1674,9 +1678,6 @@ CodeGenerator::visitCreateThis(LCreateThis *lir) int thingSize = (int)gc::Arena::thingSize(allocKind); Register objReg = ToRegister(lir->output()); - typedef JSObject *(*pf)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize); - static const VMFunction NewGCThingInfo = FunctionInfo(js::ion::NewGCThing); - OutOfLineCode *ool = oolCallVM(NewGCThingInfo, lir, (ArgList(), Imm32(allocKind), Imm32(thingSize)), StoreRegisterTo(objReg)); @@ -1693,16 +1694,16 @@ CodeGenerator::visitCreateThis(LCreateThis *lir) return true; } +typedef JSObject *(*CreateThisFn)(JSContext *cx, HandleObject callee, JSObject *proto); +static const VMFunction CreateThisInfo = + FunctionInfo(js_CreateThisForFunctionWithProto); + bool CodeGenerator::visitCreateThisVM(LCreateThisVM *lir) { const LAllocation *proto = lir->getPrototype(); const LAllocation *callee = lir->getCallee(); - typedef JSObject *(*pf)(JSContext *cx, HandleObject callee, JSObject *proto); - static const VMFunction CreateThisInfo = - FunctionInfo(js_CreateThisForFunctionWithProto); - // Push arguments. if (proto->isConstant()) pushArg(ImmGCPtr(&proto->toConstant()->toObject())); @@ -1933,17 +1934,19 @@ CodeGenerator::visitModD(LModD *ins) return true; } +typedef bool (*BinaryFn)(JSContext *, HandleScript, jsbytecode *, + HandleValue, HandleValue, Value *); + +static const VMFunction AddInfo = FunctionInfo(js::AddValues); +static const VMFunction SubInfo = FunctionInfo(js::SubValues); +static const VMFunction MulInfo = FunctionInfo(js::MulValues); +static const VMFunction DivInfo = FunctionInfo(js::DivValues); +static const VMFunction ModInfo = FunctionInfo(js::ModValues); +static const VMFunction UrshInfo = FunctionInfo(js::UrshValues); + bool CodeGenerator::visitBinaryV(LBinaryV *lir) { - typedef bool (*pf)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue, Value *); - static const VMFunction AddInfo = FunctionInfo(js::AddValues); - static const VMFunction SubInfo = FunctionInfo(js::SubValues); - static const VMFunction MulInfo = FunctionInfo(js::MulValues); - static const VMFunction DivInfo = FunctionInfo(js::DivValues); - static const VMFunction ModInfo = FunctionInfo(js::ModValues); - static const VMFunction UrshInfo = FunctionInfo(js::UrshValues); - pushArg(ToValue(lir, LBinaryV::RhsInput)); pushArg(ToValue(lir, LBinaryV::LhsInput)); pushArg(ImmWord(lir->mirRaw()->toInstruction()->resumePoint()->pc())); @@ -1974,6 +1977,12 @@ CodeGenerator::visitBinaryV(LBinaryV *lir) } } +typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, JSBool *); +static const VMFunction stringsEqualInfo = + FunctionInfo(ion::StringsEqual); +static const VMFunction stringsNotEqualInfo = + FunctionInfo(ion::StringsEqual); + bool CodeGenerator::visitCompareS(LCompareS *lir) { @@ -1983,10 +1992,6 @@ CodeGenerator::visitCompareS(LCompareS *lir) Register output = ToRegister(lir->output()); Register temp = ToRegister(lir->temp()); - typedef bool (*pf)(JSContext *, HandleString, HandleString, JSBool *); - static const VMFunction stringsEqualInfo = FunctionInfo(ion::StringsEqual); - static const VMFunction stringsNotEqualInfo = FunctionInfo(ion::StringsEqual); - OutOfLineCode *ool = NULL; if (op == JSOP_EQ || op == JSOP_STRICTEQ) { ool = oolCallVM(stringsEqualInfo, lir, (ArgList(), left, right), StoreRegisterTo(output)); @@ -2030,19 +2035,19 @@ CodeGenerator::visitCompareS(LCompareS *lir) return true; } +typedef bool (*CompareFn)(JSContext *, HandleValue, HandleValue, JSBool *); +static const VMFunction EqInfo = FunctionInfo(ion::LooselyEqual); +static const VMFunction NeInfo = FunctionInfo(ion::LooselyEqual); +static const VMFunction StrictEqInfo = FunctionInfo(ion::StrictlyEqual); +static const VMFunction StrictNeInfo = FunctionInfo(ion::StrictlyEqual); +static const VMFunction LtInfo = FunctionInfo(ion::LessThan); +static const VMFunction LeInfo = FunctionInfo(ion::LessThanOrEqual); +static const VMFunction GtInfo = FunctionInfo(ion::GreaterThan); +static const VMFunction GeInfo = FunctionInfo(ion::GreaterThanOrEqual); + bool CodeGenerator::visitCompareV(LCompareV *lir) { - typedef bool (*pf)(JSContext *, HandleValue, HandleValue, JSBool *); - static const VMFunction EqInfo = FunctionInfo(ion::LooselyEqual); - static const VMFunction NeInfo = FunctionInfo(ion::LooselyEqual); - static const VMFunction StrictEqInfo = FunctionInfo(ion::StrictlyEqual); - static const VMFunction StrictNeInfo = FunctionInfo(ion::StrictlyEqual); - static const VMFunction LtInfo = FunctionInfo(ion::LessThan); - static const VMFunction LeInfo = FunctionInfo(ion::LessThanOrEqual); - static const VMFunction GtInfo = FunctionInfo(ion::GreaterThan); - static const VMFunction GeInfo = FunctionInfo(ion::GreaterThanOrEqual); - pushArg(ToValue(lir, LBinaryV::RhsInput)); pushArg(ToValue(lir, LBinaryV::LhsInput)); @@ -2158,19 +2163,22 @@ CodeGenerator::visitIsNullOrUndefinedAndBranch(LIsNullOrUndefinedAndBranch *lir) return true; } +typedef JSString *(*ConcatStringsFn)(JSContext *, HandleString, HandleString); +static const VMFunction ConcatStringsInfo = FunctionInfo(js_ConcatStrings); + bool CodeGenerator::visitConcat(LConcat *lir) { - typedef JSString *(*pf)(JSContext *, HandleString, HandleString); - static const VMFunction js_ConcatStringsInfo = FunctionInfo(js_ConcatStrings); - pushArg(ToRegister(lir->rhs())); pushArg(ToRegister(lir->lhs())); - if (!callVM(js_ConcatStringsInfo, lir)) + if (!callVM(ConcatStringsInfo, lir)) return false; return true; } +typedef bool (*EnsureLinearFn)(JSContext *, JSString *); +static const VMFunction EnsureLinearInfo = FunctionInfo(JSString::ensureLinear); + bool CodeGenerator::visitCharCodeAt(LCharCodeAt *lir) { @@ -2178,9 +2186,7 @@ CodeGenerator::visitCharCodeAt(LCharCodeAt *lir) Register index = ToRegister(lir->index()); Register output = ToRegister(lir->output()); - typedef bool (*pf)(JSContext *, JSString *); - static const VMFunction ensureLinearInfo = FunctionInfo(JSString::ensureLinear); - OutOfLineCode *ool = oolCallVM(ensureLinearInfo, lir, (ArgList(), str), StoreNothing()); + OutOfLineCode *ool = oolCallVM(EnsureLinearInfo, lir, (ArgList(), str), StoreNothing()); if (!ool) return false; @@ -2198,15 +2204,16 @@ CodeGenerator::visitCharCodeAt(LCharCodeAt *lir) return true; } +typedef JSFlatString *(*StringFromCharCodeFn)(JSContext *, int32_t); +static const VMFunction StringFromCharCodeInfo = FunctionInfo(ion::StringFromCharCode); + bool CodeGenerator::visitFromCharCode(LFromCharCode *lir) { Register code = ToRegister(lir->code()); Register output = ToRegister(lir->output()); - typedef JSFlatString *(*pf)(JSContext *, int32_t); - static const VMFunction Info = FunctionInfo(ion::StringFromCharCode); - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), code), StoreRegisterTo(output)); + OutOfLineCode *ool = oolCallVM(StringFromCharCodeInfo, lir, (ArgList(), code), StoreRegisterTo(output)); if (!ool) return false; @@ -2451,6 +2458,11 @@ CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV *lir) return true; } +typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, + HandleValue, HandleValue, JSBool strict); +static const VMFunction SetObjectElementInfo = + FunctionInfo(SetObjectElement); + bool CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool) { @@ -2520,9 +2532,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool) masm.bind(&callStub); saveLive(ins); - typedef bool (*pf)(JSContext *, HandleObject, HandleValue, HandleValue, JSBool strict); - static const VMFunction Info = FunctionInfo(SetObjectElement); - pushArg(Imm32(current->mir()->strictModeCode())); pushArg(value); if (index->isConstant()) @@ -2530,7 +2539,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool) else pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(index))); pushArg(object); - if (!callVM(Info, ins)) + if (!callVM(SetObjectElementInfo, ins)) return false; restoreLive(ins); @@ -2538,22 +2547,23 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool) return true; } +typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue); +static const VMFunction ArrayPopDenseInfo = FunctionInfo(ion::ArrayPopDense); +static const VMFunction ArrayShiftDenseInfo = FunctionInfo(ion::ArrayShiftDense); + bool CodeGenerator::emitArrayPopShift(LInstruction *lir, const MArrayPopShift *mir, Register obj, Register elementsTemp, Register lengthTemp, TypedOrValueRegister out) { OutOfLineCode *ool; - typedef bool (*pf)(JSContext *, HandleObject, MutableHandleValue); if (mir->mode() == MArrayPopShift::Pop) { - static const VMFunction Info = FunctionInfo(ion::ArrayPopDense); - ool = oolCallVM(Info, lir, (ArgList(), obj), StoreValueTo(out)); + ool = oolCallVM(ArrayPopDenseInfo, lir, (ArgList(), obj), StoreValueTo(out)); if (!ool) return false; } else { JS_ASSERT(mir->mode() == MArrayPopShift::Shift); - static const VMFunction Info = FunctionInfo(ion::ArrayShiftDense); - ool = oolCallVM(Info, lir, (ArgList(), obj), StoreValueTo(out)); + ool = oolCallVM(ArrayShiftDenseInfo, lir, (ArgList(), obj), StoreValueTo(out)); if (!ool) return false; } @@ -2636,13 +2646,15 @@ CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT *lir) return emitArrayPopShift(lir, lir->mir(), obj, elements, length, out); } +typedef bool (*ArrayPushDenseFn)(JSContext *, HandleObject, HandleValue, uint32_t *); +static const VMFunction ArrayPushDenseInfo = + FunctionInfo(ion::ArrayPushDense); + bool CodeGenerator::emitArrayPush(LInstruction *lir, const MArrayPush *mir, Register obj, ConstantOrRegister value, Register elementsTemp, Register length) { - typedef bool (*pf)(JSContext *, HandleObject, HandleValue, uint32_t *); - static const VMFunction Info = FunctionInfo(ion::ArrayPushDense); - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj, value), StoreRegisterTo(length)); + OutOfLineCode *ool = oolCallVM(ArrayPushDenseInfo, lir, (ArgList(), obj, value), StoreRegisterTo(length)); if (!ool) return false; @@ -2694,6 +2706,9 @@ CodeGenerator::visitArrayPushT(LArrayPushT *lir) return emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length); } +typedef JSObject *(*ArrayConcatDenseFn)(JSContext *, HandleObject, HandleObject, HandleObject); +static const VMFunction ArrayConcatDenseInfo = FunctionInfo(ArrayConcatDense); + bool CodeGenerator::visitArrayConcat(LArrayConcat *lir) { @@ -2725,24 +2740,21 @@ CodeGenerator::visitArrayConcat(LArrayConcat *lir) } masm.bind(&call); - typedef JSObject *(*pf)(JSContext *, HandleObject, HandleObject, HandleObject); - static const VMFunction Info = FunctionInfo(ArrayConcatDense); - pushArg(temp1); pushArg(ToRegister(lir->rhs())); pushArg(ToRegister(lir->lhs())); - return callVM(Info, lir); + return callVM(ArrayConcatDenseInfo, lir); } +typedef JSObject *(*GetIteratorObjectFn)(JSContext *, HandleObject, uint32_t); +static const VMFunction GetIteratorObjectInfo = FunctionInfo(GetIteratorObject); + bool CodeGenerator::visitCallIteratorStart(LCallIteratorStart *lir) { - typedef JSObject *(*pf)(JSContext *, HandleObject, uint32_t); - static const VMFunction Info = FunctionInfo(GetIteratorObject); - pushArg(Imm32(lir->mir()->flags())); pushArg(ToRegister(lir->object())); - return callVM(Info, lir); + return callVM(GetIteratorObjectInfo, lir); } bool @@ -2753,10 +2765,8 @@ CodeGenerator::visitIteratorStart(LIteratorStart *lir) uint32_t flags = lir->mir()->flags(); - typedef JSObject *(*pf)(JSContext *, HandleObject, uint32_t); - static const VMFunction Info = FunctionInfo(GetIteratorObject); - - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj, Imm32(flags)), StoreRegisterTo(output)); + OutOfLineCode *ool = oolCallVM(GetIteratorObjectInfo, lir, + (ArgList(), obj, Imm32(flags)), StoreRegisterTo(output)); if (!ool) return false; @@ -2835,6 +2845,9 @@ LoadNativeIterator(MacroAssembler &masm, Register obj, Register dest, Label *fai masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, dest); } +typedef bool (*IteratorNextFn)(JSContext *, HandleObject, MutableHandleValue); +static const VMFunction IteratorNextInfo = FunctionInfo(js_IteratorNext); + bool CodeGenerator::visitIteratorNext(LIteratorNext *lir) { @@ -2842,10 +2855,7 @@ CodeGenerator::visitIteratorNext(LIteratorNext *lir) const Register temp = ToRegister(lir->temp()); const ValueOperand output = ToOutValue(lir); - typedef bool (*pf)(JSContext *, HandleObject, MutableHandleValue); - static const VMFunction Info = FunctionInfo(js_IteratorNext); - - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj), StoreValueTo(output)); + OutOfLineCode *ool = oolCallVM(IteratorNextInfo, lir, (ArgList(), obj), StoreValueTo(output)); if (!ool) return false; @@ -2866,6 +2876,9 @@ CodeGenerator::visitIteratorNext(LIteratorNext *lir) return true; } +typedef bool (*IteratorMoreFn)(JSContext *, HandleObject, JSBool *); +static const VMFunction IteratorMoreInfo = FunctionInfo(ion::IteratorMore); + bool CodeGenerator::visitIteratorMore(LIteratorMore *lir) { @@ -2873,9 +2886,8 @@ CodeGenerator::visitIteratorMore(LIteratorMore *lir) const Register output = ToRegister(lir->output()); const Register temp = ToRegister(lir->temp()); - typedef bool (*pf)(JSContext *, HandleObject, JSBool *); - static const VMFunction Info = FunctionInfo(ion::IteratorMore); - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj), StoreRegisterTo(output)); + OutOfLineCode *ool = oolCallVM(IteratorMoreInfo, lir, + (ArgList(), obj), StoreRegisterTo(output)); if (!ool) return false; @@ -2893,6 +2905,9 @@ CodeGenerator::visitIteratorMore(LIteratorMore *lir) return true; } +typedef bool (*CloseIteratorFn)(JSContext *, HandleObject); +static const VMFunction CloseIteratorInfo = FunctionInfo(CloseIterator); + bool CodeGenerator::visitIteratorEnd(LIteratorEnd *lir) { @@ -2900,10 +2915,7 @@ CodeGenerator::visitIteratorEnd(LIteratorEnd *lir) const Register temp1 = ToRegister(lir->temp1()); const Register temp2 = ToRegister(lir->temp2()); - typedef bool (*pf)(JSContext *, HandleObject); - static const VMFunction Info = FunctionInfo(CloseIterator); - - OutOfLineCode *ool = oolCallVM(Info, lir, (ArgList(), obj), StoreNothing()); + OutOfLineCode *ool = oolCallVM(CloseIteratorInfo, lir, (ArgList(), obj), StoreNothing()); if (!ool) return false; @@ -2976,7 +2988,7 @@ CodeGenerator::generate() return false; if (frameClass_ != FrameSizeClass::None()) { - deoptTable_ = cx->compartment->ionCompartment()->getBailoutTable(cx, frameClass_); + deoptTable_ = cx->compartment->ionCompartment()->getBailoutTable(frameClass_); if (!deoptTable_) return false; } @@ -3126,26 +3138,24 @@ CodeGenerator::visitOutOfLineUnboxDouble(OutOfLineUnboxDouble *ool) return true; } -typedef bool (*GetPropertyOrNameFn)(JSContext *, HandleObject, HandlePropertyName, Value *); +typedef bool (*GetPropertyFn)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue); +static const VMFunction GetPropertyInfo = FunctionInfo(GetProperty); bool CodeGenerator::visitCallGetProperty(LCallGetProperty *lir) { - typedef bool (*pf)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue); - static const VMFunction Info = FunctionInfo(GetProperty); - pushArg(ImmGCPtr(lir->mir()->name())); pushArg(ToValue(lir, LCallGetProperty::Value)); - return callVM(Info, lir); + return callVM(GetPropertyInfo, lir); } +typedef bool (*GetOrCallElementFn)(JSContext *, HandleValue, HandleValue, MutableHandleValue); +static const VMFunction GetElementInfo = FunctionInfo(js::GetElement); +static const VMFunction CallElementInfo = FunctionInfo(js::CallElement); + bool CodeGenerator::visitCallGetElement(LCallGetElement *lir) { - typedef bool (*pf)(JSContext *, HandleValue, HandleValue, MutableHandleValue); - static const VMFunction GetElementInfo = FunctionInfo(js::GetElement); - static const VMFunction CallElementInfo = FunctionInfo(js::CallElement); - pushArg(ToValue(lir, LCallGetElement::RhsInput)); pushArg(ToValue(lir, LCallGetElement::LhsInput)); @@ -3162,9 +3172,6 @@ CodeGenerator::visitCallGetElement(LCallGetElement *lir) bool CodeGenerator::visitCallSetElement(LCallSetElement *lir) { - typedef bool (*pf)(JSContext *, HandleObject, HandleValue, HandleValue, JSBool strict); - static const VMFunction SetObjectElementInfo = FunctionInfo(js::SetObjectElement); - pushArg(Imm32(current->mir()->strictModeCode())); pushArg(ToValue(lir, LCallSetElement::Value)); pushArg(ToValue(lir, LCallSetElement::Index)); @@ -3316,6 +3323,10 @@ CodeGenerator::visitCache(LInstruction *ins) return true; } +typedef bool (*GetNameCacheFn)(JSContext *, size_t, HandleObject, MutableHandleValue); +static const VMFunction GetNameCacheInfo = + FunctionInfo(GetNameCache); + bool CodeGenerator::visitOutOfLineGetNameCache(OutOfLineCache *ool) { @@ -3337,9 +3348,6 @@ CodeGenerator::visitOutOfLineGetNameCache(OutOfLineCache *ool) saveLive(lir); - typedef bool (*pf)(JSContext *, size_t, HandleObject, MutableHandleValue); - static const VMFunction GetNameCacheInfo = FunctionInfo(GetNameCache); - pushArg(scopeChain); pushArg(Imm32(cacheIndex)); if (!callVM(GetNameCacheInfo, lir)) @@ -3352,6 +3360,10 @@ CodeGenerator::visitOutOfLineGetNameCache(OutOfLineCache *ool) return true; } +typedef bool (*GetPropertyCacheFn)(JSContext *, size_t, HandleObject, MutableHandleValue); +static const VMFunction GetPropertyCacheInfo = + FunctionInfo(GetPropertyCache); + bool CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool) { @@ -3408,9 +3420,6 @@ CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool) saveLive(ins); - typedef bool (*pf)(JSContext *, size_t, HandleObject, MutableHandleValue); - static const VMFunction GetPropertyCacheInfo = FunctionInfo(GetPropertyCache); - pushArg(objReg); pushArg(Imm32(cacheIndex)); if (!callVM(GetPropertyCacheInfo, ins)) @@ -3424,6 +3433,9 @@ CodeGenerator::visitOutOfLineCacheGetProperty(OutOfLineCache *ool) return true; } +typedef bool (*GetElementCacheFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue); +static const VMFunction GetElementCacheInfo = FunctionInfo(GetElementCache); + bool CodeGenerator::visitOutOfLineGetElementCache(OutOfLineCache *ool) { @@ -3446,13 +3458,10 @@ CodeGenerator::visitOutOfLineGetElementCache(OutOfLineCache *ool) saveLive(ins); - typedef bool (*pf)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue); - static const VMFunction Info = FunctionInfo(GetElementCache); - pushArg(index); pushArg(obj); pushArg(Imm32(cacheIndex)); - if (!callVM(Info, ins)) + if (!callVM(GetElementCacheInfo, ins)) return false; masm.storeCallResultValue(output); @@ -3462,6 +3471,10 @@ CodeGenerator::visitOutOfLineGetElementCache(OutOfLineCache *ool) return true; } +typedef JSObject *(*BindNameCacheFn)(JSContext *, size_t, HandleObject); +static const VMFunction BindNameCacheInfo = + FunctionInfo(BindNameCache); + bool CodeGenerator::visitOutOfLineBindNameCache(OutOfLineCache *ool) { @@ -3480,9 +3493,6 @@ CodeGenerator::visitOutOfLineBindNameCache(OutOfLineCache *ool) saveLive(ins); - typedef JSObject *(*pf)(JSContext *, size_t, HandleObject); - static const VMFunction BindNameCacheInfo = FunctionInfo(BindNameCache); - pushArg(scopeChain); pushArg(Imm32(cacheIndex)); if (!callVM(BindNameCacheInfo, ins)) @@ -3518,6 +3528,11 @@ CodeGenerator::getSetPropertyValue(LInstruction *ins) } } +typedef bool (*SetPropertyFn)(JSContext *, HandleObject, + HandlePropertyName, const HandleValue, bool, bool); +static const VMFunction SetPropertyInfo = + FunctionInfo(SetProperty); + bool CodeGenerator::visitCallSetProperty(LCallSetProperty *ins) { @@ -3533,29 +3548,31 @@ CodeGenerator::visitCallSetProperty(LCallSetProperty *ins) pushArg(ImmGCPtr(ins->mir()->name())); pushArg(objReg); - typedef bool (*pf)(JSContext *, HandleObject, HandlePropertyName, const HandleValue, bool, bool); - static const VMFunction info = FunctionInfo(SetProperty); - - return callVM(info, ins); + return callVM(SetPropertyInfo, ins); } +typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, JSBool *); +static const VMFunction DeletePropertyStrictInfo = + FunctionInfo(DeleteProperty); +static const VMFunction DeletePropertyNonStrictInfo = + FunctionInfo(DeleteProperty); + bool CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir) { - typedef bool (*pf)(JSContext *, HandleValue, HandlePropertyName, JSBool *); - pushArg(ImmGCPtr(lir->mir()->name())); pushArg(ToValue(lir, LCallDeleteProperty::Value)); - if (lir->mir()->block()->info().script()->strictModeCode) { - static const VMFunction Info = FunctionInfo(DeleteProperty); - return callVM(Info, lir); - } else { - static const VMFunction Info = FunctionInfo(DeleteProperty); - return callVM(Info, lir); - } + if (lir->mir()->block()->info().script()->strictModeCode) + return callVM(DeletePropertyStrictInfo, lir); + else + return callVM(DeletePropertyNonStrictInfo, lir); } +typedef bool (*SetPropertyCacheFn)(JSContext *, size_t, HandleObject, HandleValue, bool); +static const VMFunction SetPropertyCacheInfo = + FunctionInfo(ion::SetPropertyCache); + bool CodeGenerator::visitOutOfLineSetPropertyCache(OutOfLineCache *ool) { @@ -3582,10 +3599,7 @@ CodeGenerator::visitOutOfLineSetPropertyCache(OutOfLineCache *ool) pushArg(objReg); pushArg(Imm32(cacheIndex)); - typedef bool (*pf)(JSContext *, size_t, HandleObject, HandleValue, bool); - static const VMFunction info = FunctionInfo(ion::SetPropertyCache); - - if (!callVM(info, ool->cache())) + if (!callVM(SetPropertyCacheInfo, ool->cache())) return false; restoreLive(ins); @@ -3595,36 +3609,36 @@ CodeGenerator::visitOutOfLineSetPropertyCache(OutOfLineCache *ool) return true; } +typedef bool (*ThrowFn)(JSContext *, HandleValue); +static const VMFunction ThrowInfo = FunctionInfo(js::Throw); + bool CodeGenerator::visitThrow(LThrow *lir) { - typedef bool (*pf)(JSContext *, HandleValue); - static const VMFunction ThrowInfo = FunctionInfo(js::Throw); - pushArg(ToValue(lir, LThrow::Value)); return callVM(ThrowInfo, lir); } +typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p); +static const VMFunction BitNotInfo = FunctionInfo(BitNot); + bool CodeGenerator::visitBitNotV(LBitNotV *lir) { - typedef bool (*pf)(JSContext *, HandleValue, int *p); - static const VMFunction info = FunctionInfo(BitNot); - pushArg(ToValue(lir, LBitNotV::Input)); - return callVM(info, lir); + return callVM(BitNotInfo, lir); } +typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p); +static const VMFunction BitAndInfo = FunctionInfo(BitAnd); +static const VMFunction BitOrInfo = FunctionInfo(BitOr); +static const VMFunction BitXorInfo = FunctionInfo(BitXor); +static const VMFunction BitLhsInfo = FunctionInfo(BitLsh); +static const VMFunction BitRhsInfo = FunctionInfo(BitRsh); + bool CodeGenerator::visitBitOpV(LBitOpV *lir) { - typedef bool (*pf)(JSContext *, HandleValue, HandleValue, int *p); - static const VMFunction BitAndInfo = FunctionInfo(BitAnd); - static const VMFunction BitOrInfo = FunctionInfo(BitOr); - static const VMFunction BitXorInfo = FunctionInfo(BitXor); - static const VMFunction BitLhsInfo = FunctionInfo(BitLsh); - static const VMFunction BitRhsInfo = FunctionInfo(BitRsh); - pushArg(ToValue(lir, LBitOpV::RhsInput)); pushArg(ToValue(lir, LBitOpV::LhsInput)); @@ -3713,17 +3727,17 @@ CodeGenerator::visitTypeOfV(LTypeOfV *lir) return true; } +typedef JSString *(*TypeOfFn)(JSContext *, HandleValue); +static const VMFunction TypeOfInfo = FunctionInfo(TypeOfOperation); + bool CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool) { - typedef JSString *(*pf)(JSContext *, HandleValue); - static const VMFunction Info = FunctionInfo(TypeOfOperation); - LTypeOfV *ins = ool->ins(); saveLive(ins); pushArg(ToValue(ins, LTypeOfV::Input)); - if (!callVM(Info, ins)) + if (!callVM(TypeOfInfo, ins)) return false; masm.storeCallResult(ToRegister(ins->output())); @@ -3733,18 +3747,18 @@ CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool) return true; } +typedef bool (*ToIdFn)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue, + MutableHandleValue); +static const VMFunction ToIdInfo = FunctionInfo(ToIdOperation); + bool CodeGenerator::visitToIdV(LToIdV *lir) { - typedef bool (*pf)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue, - MutableHandleValue); - static const VMFunction Info = FunctionInfo(ToIdOperation); - pushArg(ToValue(lir, LToIdV::Index)); pushArg(ToValue(lir, LToIdV::Object)); pushArg(ImmWord(lir->mir()->resumePoint()->pc())); pushArg(ImmGCPtr(current->mir()->info().script())); - return callVM(Info, lir); + return callVM(ToIdInfo, lir); } bool @@ -3881,6 +3895,10 @@ CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole *lir) return true; } +typedef bool (*GetElementMonitoredFn)(JSContext *, HandleValue, HandleValue, MutableHandleValue); +static const VMFunction GetElementMonitoredInfo = + FunctionInfo(js::GetElementMonitored); + bool CodeGenerator::visitOutOfLineLoadTypedArray(OutOfLineLoadTypedArray *ool) { @@ -3890,15 +3908,12 @@ CodeGenerator::visitOutOfLineLoadTypedArray(OutOfLineLoadTypedArray *ool) Register object = ToRegister(ins->object()); ValueOperand out = ToOutValue(ins); - typedef bool (*pf)(JSContext *, HandleValue, HandleValue, MutableHandleValue); - static const VMFunction Info = FunctionInfo(js::GetElementMonitored); - if (ins->index()->isConstant()) pushArg(*ins->index()->toConstant()); else pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()))); pushArg(TypedOrValueRegister(MIRType_Object, AnyRegister(object))); - if (!callVM(Info, ins)) + if (!callVM(GetElementMonitoredInfo, ins)) return false; masm.storeCallResultValue(out); @@ -4006,12 +4021,12 @@ CodeGenerator::visitClampVToUint8(LClampVToUint8 *lir) return true; } +typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, JSBool *); +static const VMFunction OperatorInInfo = FunctionInfo(OperatorIn); + bool CodeGenerator::visitIn(LIn *ins) { - typedef bool (*pf)(JSContext *, HandleValue, HandleObject, JSBool *); - static const VMFunction OperatorInInfo = FunctionInfo(OperatorIn); - pushArg(ToRegister(ins->rhs())); pushArg(ToValue(ins, LIn::LHS)); @@ -4032,6 +4047,9 @@ CodeGenerator::visitInstanceOfV(LInstanceOfV *ins) return emitInstanceOf(ins, rhs); } +typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, JSBool *); +static const VMFunction HasInstanceInfo = FunctionInfo(js::HasInstance); + bool CodeGenerator::emitInstanceOf(LInstruction *ins, Register rhs) { @@ -4051,9 +4069,6 @@ CodeGenerator::emitInstanceOf(LInstruction *ins, Register rhs) JS_ASSERT(ins->isInstanceOfO() || ins->isInstanceOfV()); bool lhsIsValue = ins->isInstanceOfV(); - typedef bool (*pf)(JSContext *, HandleObject, HandleValue, JSBool *); - static const VMFunction HasInstanceInfo = FunctionInfo(js::HasInstance); - // If the lhs is an object, then the ValueOperand that gets sent to // HasInstance must be boxed first. If the lhs is a value, it can // be sent directly. Hence the choice between ToValue and ToTempValue @@ -4320,6 +4335,10 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty *ins) return true; } +typedef bool(*SPSFn)(JSContext *, HandleScript); +static const VMFunction SPSEnterInfo = FunctionInfo(SPSEnter); +static const VMFunction SPSExitInfo = FunctionInfo(SPSExit); + bool CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir) { @@ -4350,9 +4369,6 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir) case MFunctionBoundary::Enter: if (sps_.slowAssertions()) { - typedef bool(*pf)(JSContext *, HandleScript); - static const VMFunction SPSEnterInfo = FunctionInfo(SPSEnter); - saveLive(lir); pushArg(ImmGCPtr(lir->script())); if (!callVM(SPSEnterInfo, lir)) @@ -4374,9 +4390,6 @@ CodeGenerator::visitFunctionBoundary(LFunctionBoundary *lir) case MFunctionBoundary::Exit: if (sps_.slowAssertions()) { - typedef bool(*pf)(JSContext *, HandleScript); - static const VMFunction SPSExitInfo = FunctionInfo(SPSExit); - saveLive(lir); pushArg(ImmGCPtr(lir->script())); // Once we've exited, then we shouldn't emit instrumentation for diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index c2073bf30a1..067596919fe 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -123,20 +123,32 @@ ion::InitializeIon() return true; } -IonCompartment::IonCompartment() +IonRuntime::IonRuntime() : execAlloc_(NULL), enterJIT_(NULL), bailoutHandler_(NULL), argumentsRectifier_(NULL), invalidator_(NULL), - functionWrappers_(NULL), - flusher_(NULL) + functionWrappers_(NULL) { } -bool -IonCompartment::initialize(JSContext *cx) +IonRuntime::~IonRuntime() { + js_delete(functionWrappers_); +} + +bool +IonRuntime::initialize(JSContext *cx) +{ + AutoEnterAtomsCompartment ac(cx); + + if (!cx->compartment->ensureIonCompartmentExists(cx)) + return false; + + IonContext ictx(cx, cx->compartment, NULL); + AutoFlushCache afc("IonRuntime::initialize"); + execAlloc_ = cx->runtime->getExecAlloc(cx); if (!execAlloc_) return false; @@ -145,9 +157,53 @@ IonCompartment::initialize(JSContext *cx) if (!functionWrappers_ || !functionWrappers_->init()) return false; + if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId())) + return false; + + for (uint32 id = 0;; id++) { + FrameSizeClass class_ = FrameSizeClass::FromClass(id); + if (class_ == FrameSizeClass::ClassLimit()) + break; + bailoutTables_.infallibleAppend(NULL); + bailoutTables_[id] = generateBailoutTable(cx, id); + if (!bailoutTables_[id]) + return false; + } + + bailoutHandler_ = generateBailoutHandler(cx); + if (!bailoutHandler_) + return false; + + argumentsRectifier_ = generateArgumentsRectifier(cx); + if (!argumentsRectifier_) + return false; + + invalidator_ = generateInvalidator(cx); + if (!invalidator_) + return false; + + enterJIT_ = generateEnterJIT(cx); + if (!enterJIT_) + return false; + + preBarrier_ = generatePreBarrier(cx); + if (!preBarrier_) + return false; + + for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) { + if (!generateVMWrapper(cx, *fun)) + return false; + } + return true; } +IonCompartment::IonCompartment(IonRuntime *rt) + : rt(rt), + flusher_(NULL) +{ +} + void ion::FinishOffThreadBuilder(IonBuilder *builder) { @@ -171,34 +227,18 @@ FinishAllOffThreadCompilations(IonCompartment *ion) compilations.clear(); } +/* static */ void +IonRuntime::Mark(JSTracer *trc) +{ + for (gc::CellIterUnderGC i(trc->runtime->atomsCompartment, gc::FINALIZE_IONCODE); !i.done(); i.next()) { + IonCode *code = i.get(); + MarkIonCodeRoot(trc, &code, "wrapper"); + } +} + void IonCompartment::mark(JSTracer *trc, JSCompartment *compartment) { - // This function marks Ion code objects that must be kept alive if there is - // any Ion code currently running. These pointers are marked at the start - // of incremental GC. Entering Ion code in the middle of an incremental GC - // triggers a read barrier on both these pointers, so they will still be - // marked in that case. - - bool runningIonCode = false; - for (IonActivationIterator iter(trc->runtime); iter.more(); ++iter) { - IonActivation *activation = iter.activation(); - - if (activation->compartment() != compartment) - continue; - - runningIonCode = true; - break; - } - - // Don't destroy enterJIT if we are running Ion code. Note that enterJIT is - // not used for JM -> Ion calls, so it may be NULL in that case. - if (runningIonCode && enterJIT_) - MarkIonCodeRoot(trc, enterJIT_.unsafeGet(), "enterJIT"); - - // functionWrappers_ are not marked because this is a WeakCache of VM - // function implementations. - // Cancel any active or pending off thread compilations. CancelOffThreadIonCompile(compartment, NULL); FinishAllOffThreadCompilations(this); @@ -207,55 +247,26 @@ IonCompartment::mark(JSTracer *trc, JSCompartment *compartment) void IonCompartment::sweep(FreeOp *fop) { - if (enterJIT_ && !IsIonCodeMarked(enterJIT_.unsafeGet())) - enterJIT_ = NULL; - if (bailoutHandler_ && !IsIonCodeMarked(bailoutHandler_.unsafeGet())) - bailoutHandler_ = NULL; - if (argumentsRectifier_ && !IsIonCodeMarked(argumentsRectifier_.unsafeGet())) - argumentsRectifier_ = NULL; - if (invalidator_ && !IsIonCodeMarked(invalidator_.unsafeGet())) - invalidator_ = NULL; - if (preBarrier_ && !IsIonCodeMarked(preBarrier_.unsafeGet())) - preBarrier_ = NULL; - - for (size_t i = 0; i < bailoutTables_.length(); i++) { - if (bailoutTables_[i] && !IsIonCodeMarked(bailoutTables_[i].unsafeGet())) - bailoutTables_[i] = NULL; - } - - // Sweep cache of VM function implementations. - functionWrappers_->sweep(fop); } IonCode * IonCompartment::getBailoutTable(const FrameSizeClass &frameClass) { JS_ASSERT(frameClass != FrameSizeClass::None()); - return bailoutTables_[frameClass.classId()]; + return rt->bailoutTables_[frameClass.classId()]; } IonCode * -IonCompartment::getBailoutTable(JSContext *cx, const FrameSizeClass &frameClass) +IonCompartment::getVMWrapper(const VMFunction &f) { - uint32 id = frameClass.classId(); + typedef MoveResolver::MoveOperand MoveOperand; - if (id >= bailoutTables_.length()) { - size_t numToPush = id - bailoutTables_.length() + 1; - if (!bailoutTables_.reserve(bailoutTables_.length() + numToPush)) - return NULL; - for (size_t i = 0; i < numToPush; i++) - bailoutTables_.infallibleAppend(NULL); - } + JS_ASSERT(rt->functionWrappers_); + JS_ASSERT(rt->functionWrappers_->initialized()); + IonRuntime::VMWrapperMap::Ptr p = rt->functionWrappers_->lookup(&f); + JS_ASSERT(p); - if (!bailoutTables_[id]) - bailoutTables_[id] = generateBailoutTable(cx, id); - - return bailoutTables_[id]; -} - -IonCompartment::~IonCompartment() -{ - js_delete(functionWrappers_); + return p->value; } IonActivation::IonActivation(JSContext *cx, StackFrame *fp) @@ -327,15 +338,8 @@ IonCode::trace(JSTracer *trc) { // Note that we cannot mark invalidated scripts, since we've basically // corrupted the code stream by injecting bailouts. - if (invalidated()) { - // Note that since we're invalidated, we won't mark the precious - // invalidator thunk referenced in the epilogue. We don't move - // executable code so the actual reference is okay, we just need to - // make sure it says alive before we return. - IonCompartment *ion = compartment()->ionCompartment(); - MarkIonCodeUnbarriered(trc, ion->getInvalidationThunkAddr(), "invalidator"); + if (invalidated()) return; - } if (jumpRelocTableBytes_) { uint8 *start = code_ + jumpRelocTableOffset(); @@ -999,6 +1003,8 @@ AttachFinishedCompilations(JSContext *cx) CodeGenerator codegen(builder, *builder->backgroundCompiledLir); + types::AutoEnterTypeInference enterTypes(cx); + ExecutionMode executionMode = builder->info().executionMode(); types::AutoEnterCompilation enterCompiler(cx, CompilerOutputKind(executionMode)); enterCompiler.initExisting(builder->recompileInfo); @@ -1311,13 +1317,6 @@ ion::CanEnterAtBranch(JSContext *cx, HandleScript script, StackFrame *fp, jsbyte if (script->ion->osrPc() != pc) return Method_Skipped; - // This can GC, so afterward, script->ion is not guaranteed to be valid. - if (!cx->compartment->ionCompartment()->enterJIT(cx)) - return Method_Error; - - if (!script->ion) - return Method_Skipped; - return Method_Compiled; } @@ -1364,13 +1363,6 @@ ion::CanEnter(JSContext *cx, HandleScript script, StackFrame *fp, bool newType) return status; } - // This can GC, so afterward, script->ion is not guaranteed to be valid. - if (!cx->compartment->ionCompartment()->enterJIT(cx)) - return Method_Error; - - if (!script->ion) - return Method_Skipped; - return Method_Compiled; } @@ -1393,7 +1385,7 @@ ion::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numAct // This can GC, so afterward, script->ion is not guaranteed to be valid. AssertCanGC(); - if (!cx->compartment->ionCompartment()->enterJIT(cx)) + if (!cx->compartment->ionCompartment()->enterJIT()) return Method_Error; if (!script->ion) @@ -1411,7 +1403,7 @@ EnterIon(JSContext *cx, StackFrame *fp, void *jitcode) JS_ASSERT(CheckFrame(fp)); JS_ASSERT(!fp->script()->ion->bailoutExpected()); - EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible(); + EnterIonCode enter = cx->compartment->ionCompartment()->enterJIT(); // maxArgc is the maximum of arguments between the number of actual // arguments and the number of formal arguments. It accounts for |this|. @@ -1585,7 +1577,7 @@ ion::FastInvoke(JSContext *cx, HandleFunction fun, CallArgsList &args) activation.setPrevPc(cx->regs().pc); - EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible(); + EnterIonCode enter = cx->compartment->ionCompartment()->enterJIT(); void *calleeToken = CalleeToToken(fun); Value result = Int32Value(args.length()); @@ -1878,6 +1870,8 @@ ion::ForbidCompilation(JSContext *cx, JSScript *script) IonSpew(IonSpew_Abort, "Disabling Ion compilation of script %s:%d", script->filename, script->lineno); + CancelOffThreadIonCompile(cx->compartment, script); + if (script->hasIonScript()) { // It is only safe to modify script->ion if the script is not currently // running, because IonFrameIterator needs to tell what ionScript to diff --git a/js/src/ion/IonCompartment.h b/js/src/ion/IonCompartment.h index 7ec8b45d6fd..a6b0e934492 100644 --- a/js/src/ion/IonCompartment.h +++ b/js/src/ion/IonCompartment.h @@ -27,37 +27,60 @@ class IonBuilder; typedef Vector OffThreadCompilationVector; -class IonCompartment +class IonRuntime { - typedef WeakCache > VMWrapperMap; + friend class IonCompartment; - friend class IonActivation; - - // Executable allocator (owned by the runtime). + // Executable allocator. JSC::ExecutableAllocator *execAlloc_; // Trampoline for entering JIT code. Contains OSR prologue. - ReadBarriered enterJIT_; + IonCode *enterJIT_; // Vector mapping frame class sizes to bailout tables. - Vector, 4, SystemAllocPolicy> bailoutTables_; + Vector bailoutTables_; // Generic bailout table; used if the bailout table overflows. - ReadBarriered bailoutHandler_; + IonCode *bailoutHandler_; // Argument-rectifying thunk, in the case of insufficient arguments passed // to a function call site. Pads with |undefined|. - ReadBarriered argumentsRectifier_; + IonCode *argumentsRectifier_; // Thunk that invalides an (Ion compiled) caller on the Ion stack. - ReadBarriered invalidator_; + IonCode *invalidator_; // Thunk that calls the GC pre barrier. - ReadBarriered preBarrier_; + IonCode *preBarrier_; // Map VMFunction addresses to the IonCode of the wrapper. + typedef WeakCache VMWrapperMap; VMWrapperMap *functionWrappers_; + private: + IonCode *generateEnterJIT(JSContext *cx); + IonCode *generateArgumentsRectifier(JSContext *cx); + IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass); + IonCode *generateBailoutHandler(JSContext *cx); + IonCode *generateInvalidator(JSContext *cx); + IonCode *generatePreBarrier(JSContext *cx); + IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f); + + public: + IonRuntime(); + ~IonRuntime(); + bool initialize(JSContext *cx); + + static void Mark(JSTracer *trc); +}; + +class IonCompartment +{ + friend class IonActivation; + + // Ion state for the compartment's runtime. + IonRuntime *rt; + // Any scripts for which off thread compilation has successfully finished, // failed, or been cancelled. All off thread compilations which are started // will eventually appear in this list asynchronously. Protected by the @@ -67,94 +90,45 @@ class IonCompartment // Keep track of memoryregions that are going to be flushed. AutoFlushCache *flusher_; - private: - IonCode *generateEnterJIT(JSContext *cx); - IonCode *generateReturnError(JSContext *cx); - IonCode *generateArgumentsRectifier(JSContext *cx); - IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass); - IonCode *generateBailoutHandler(JSContext *cx); - IonCode *generateInvalidator(JSContext *cx); - IonCode *generatePreBarrier(JSContext *cx); - public: - IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f); + IonCode *getVMWrapper(const VMFunction &f); OffThreadCompilationVector &finishedOffThreadCompilations() { return finishedOffThreadCompilations_; } public: - bool initialize(JSContext *cx); - IonCompartment(); - ~IonCompartment(); + IonCompartment(IonRuntime *rt); void mark(JSTracer *trc, JSCompartment *compartment); void sweep(FreeOp *fop); JSC::ExecutableAllocator *execAlloc() { - return execAlloc_; + return rt->execAlloc_; } - IonCode *getBailoutTable(JSContext *cx, const FrameSizeClass &frameClass); - IonCode *getGenericBailoutHandler(JSContext *cx) { - if (!bailoutHandler_) { - bailoutHandler_ = generateBailoutHandler(cx); - if (!bailoutHandler_) - return NULL; - } - return bailoutHandler_; + IonCode *getGenericBailoutHandler() { + return rt->bailoutHandler_; } - // Infallible; does not generate a table. IonCode *getBailoutTable(const FrameSizeClass &frameClass); - // Fallible; generates a thunk and returns the target. - IonCode *getArgumentsRectifier(JSContext *cx) { - if (!argumentsRectifier_) { - argumentsRectifier_ = generateArgumentsRectifier(cx); - if (!argumentsRectifier_) - return NULL; - } - return argumentsRectifier_; - } - IonCode **getArgumentsRectifierAddr() { - return argumentsRectifier_.unsafeGet(); + IonCode *getArgumentsRectifier() { + return rt->argumentsRectifier_; } - IonCode *getOrCreateInvalidationThunk(JSContext *cx) { - if (!invalidator_) { - invalidator_ = generateInvalidator(cx); - if (!invalidator_) - return NULL; - } - return invalidator_; - } - IonCode **getInvalidationThunkAddr() { - return invalidator_.unsafeGet(); + IonCode *getInvalidationThunk() { + return rt->invalidator_; } - EnterIonCode enterJITInfallible() { - JS_ASSERT(enterJIT_); - return enterJIT_.get()->as(); + EnterIonCode enterJIT() { + return rt->enterJIT_->as(); } - EnterIonCode enterJIT(JSContext *cx) { - if (!enterJIT_) { - enterJIT_ = generateEnterJIT(cx); - if (!enterJIT_) - return NULL; - } - return enterJIT_.get()->as(); + IonCode *preBarrier() { + return rt->preBarrier_; } - IonCode *preBarrier(JSContext *cx) { - if (!preBarrier_) { - preBarrier_ = generatePreBarrier(cx); - if (!preBarrier_) - return NULL; - } - return preBarrier_; - } AutoFlushCache *flusher() { return flusher_; } diff --git a/js/src/ion/IonFrames.cpp b/js/src/ion/IonFrames.cpp index 8877d38a97f..7ee5d8cd149 100644 --- a/js/src/ion/IonFrames.cpp +++ b/js/src/ion/IonFrames.cpp @@ -638,11 +638,8 @@ MarkIonActivation(JSTracer *trc, const IonActivationIterator &activations) JS_NOT_REACHED("invalid"); break; case IonFrame_Rectifier: - case IonFrame_Bailed_Rectifier: { - IonCompartment *ionCompartment = activations.activation()->compartment()->ionCompartment(); - MarkIonCodeRoot(trc, ionCompartment->getArgumentsRectifierAddr(), "Arguments Rectifier"); + case IonFrame_Bailed_Rectifier: break; - } case IonFrame_Osr: // The callee token will be marked by the callee JS frame; // otherwise, it does not need to be marked, since the frame is diff --git a/js/src/ion/IonFrames.h b/js/src/ion/IonFrames.h index 9245116f281..ad4c34c6d41 100644 --- a/js/src/ion/IonFrames.h +++ b/js/src/ion/IonFrames.h @@ -220,8 +220,9 @@ class FrameSizeClass return FrameSizeClass(class_); } - // These two functions are implemented in specific CodeGenerator-* files. + // These functions are implemented in specific CodeGenerator-* files. static FrameSizeClass FromDepth(uint32 frameDepth); + static FrameSizeClass ClassLimit(); uint32 frameSize() const; uint32 classId() const { diff --git a/js/src/ion/IonMacroAssembler.h b/js/src/ion/IonMacroAssembler.h index 9c2dff5a831..c3a3c7294ce 100644 --- a/js/src/ion/IonMacroAssembler.h +++ b/js/src/ion/IonMacroAssembler.h @@ -381,18 +381,15 @@ class MacroAssembler : public MacroAssemblerSpecific JS_ASSERT(type == MIRType_Value || type == MIRType_String || type == MIRType_Object); Label done; - JSContext *cx = GetIonContext()->cx; - IonCode *preBarrier = cx->compartment->ionCompartment()->preBarrier(cx); - if (!preBarrier) { - enoughMemory_ = false; - return; - } - if (type == MIRType_Value) branchTestGCThing(Assembler::NotEqual, address, &done); Push(PreBarrierReg); computeEffectiveAddress(address, PreBarrierReg); + + JSCompartment *compartment = GetIonContext()->compartment; + IonCode *preBarrier = compartment->ionCompartment()->preBarrier(); + call(preBarrier); Pop(PreBarrierReg); diff --git a/js/src/ion/VMFunctions.cpp b/js/src/ion/VMFunctions.cpp index 75407fa03aa..9c86ddc78e8 100644 --- a/js/src/ion/VMFunctions.cpp +++ b/js/src/ion/VMFunctions.cpp @@ -21,6 +21,22 @@ using namespace js::ion; namespace js { namespace ion { +// Don't explicitly initialize, it's not guaranteed that this initializer will +// run before the constructors for static VMFunctions. +/* static */ VMFunction *VMFunction::functions; + +void +VMFunction::addToFunctions() +{ + static bool initialized = false; + if (!initialized) { + initialized = true; + functions = NULL; + } + this->next = functions; + functions = this; +} + static inline bool ShouldMonitorReturnType(JSFunction *fun) { diff --git a/js/src/ion/VMFunctions.h b/js/src/ion/VMFunctions.h index cca973dd6aa..03bac46f581 100644 --- a/js/src/ion/VMFunctions.h +++ b/js/src/ion/VMFunctions.h @@ -34,6 +34,10 @@ enum DataType { // argument, and are treated as re-entrant into the VM and therefore fallible. struct VMFunction { + // Global linked list of all VMFunctions. + static VMFunction *functions; + VMFunction *next; + // Address of the C function. void *wrapped; @@ -168,6 +172,16 @@ struct VMFunction JS_ASSERT_IF(outParam != Type_Void, returnType == Type_Bool); JS_ASSERT(returnType == Type_Bool || returnType == Type_Object); } + + VMFunction(const VMFunction &o) + { + *this = o; + addToFunctions(); + } + + private: + // Add this to the global list of VMFunctions. + void addToFunctions(); }; template struct TypeToDataType { /* Unexpected return type for a VMFunction. */ }; diff --git a/js/src/ion/arm/CodeGenerator-arm.cpp b/js/src/ion/arm/CodeGenerator-arm.cpp index 97cd7d6321f..92f477da9aa 100644 --- a/js/src/ion/arm/CodeGenerator-arm.cpp +++ b/js/src/ion/arm/CodeGenerator-arm.cpp @@ -176,11 +176,9 @@ CodeGeneratorARM::generateOutOfLineCode() // Push the frame size, so the handler can recover the IonScript. masm.ma_mov(Imm32(frameSize()), lr); - JSContext *cx = GetIonContext()->cx; - IonCompartment *ion = cx->compartment->ionCompartment(); - IonCode *handler = ion->getGenericBailoutHandler(cx); - if (!handler) - return false; + IonCompartment *ion = GetIonContext()->compartment->ionCompartment(); + IonCode *handler = ion->getGenericBailoutHandler(); + masm.branch(handler); } @@ -982,11 +980,7 @@ CodeGeneratorARM::visitTruncateDToInt32(LTruncateDToInt32 *ins) return emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output())); } -// The first two size classes are 128 and 256 bytes respectively. After that we -// increment by 512. -static const uint32 LAST_FRAME_SIZE = 512; -static const uint32 LAST_FRAME_INCREMENT = 512; -static const uint32 FrameSizes[] = { 128, 256, LAST_FRAME_SIZE }; +static const uint32 FrameSizes[] = { 128, 256, 512, 1024 }; FrameSizeClass FrameSizeClass::FromDepth(uint32 frameDepth) @@ -996,21 +990,22 @@ FrameSizeClass::FromDepth(uint32 frameDepth) return FrameSizeClass(i); } - uint32 newFrameSize = frameDepth - LAST_FRAME_SIZE; - uint32 sizeClass = (newFrameSize / LAST_FRAME_INCREMENT) + 1; - - return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes) + sizeClass); + return FrameSizeClass::None(); } + +FrameSizeClass +FrameSizeClass::ClassLimit() +{ + return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes)); +} + uint32 FrameSizeClass::frameSize() const { JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID); + JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes)); - if (class_ < JS_ARRAY_LENGTH(FrameSizes)) - return FrameSizes[class_]; - - uint32 step = class_ - JS_ARRAY_LENGTH(FrameSizes); - return LAST_FRAME_SIZE + step * LAST_FRAME_INCREMENT; + return FrameSizes[class_]; } ValueOperand @@ -1471,13 +1466,13 @@ CodeGeneratorARM::visitRecompileCheck(LRecompileCheck *lir) return true; } +typedef bool (*InterruptCheckFn)(JSContext *); +static const VMFunction InterruptCheckInfo = FunctionInfo(InterruptCheck); + bool CodeGeneratorARM::visitInterruptCheck(LInterruptCheck *lir) { - typedef bool (*pf)(JSContext *); - static const VMFunction interruptCheckInfo = FunctionInfo(InterruptCheck); - - OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing()); + OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); if (!ool) return false; @@ -1503,13 +1498,9 @@ CodeGeneratorARM::generateInvalidateEpilogue() // Push the return address of the point that we bailed out at onto the stack masm.Push(lr); - JSContext *cx = GetIonContext()->cx; - // Push the Ion script onto the stack (when we determine what that pointer is). invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1))); - IonCode *thunk = cx->compartment->ionCompartment()->getOrCreateInvalidationThunk(cx); - if (!thunk) - return false; + IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk(); masm.branch(thunk); diff --git a/js/src/ion/arm/Trampoline-arm.cpp b/js/src/ion/arm/Trampoline-arm.cpp index 86edf179ce1..5cd2ab48b6c 100644 --- a/js/src/ion/arm/Trampoline-arm.cpp +++ b/js/src/ion/arm/Trampoline-arm.cpp @@ -70,7 +70,7 @@ struct EnterJITStack * ...using standard EABI calling convention */ IonCode * -IonCompartment::generateEnterJIT(JSContext *cx) +IonRuntime::generateEnterJIT(JSContext *cx) { const Register reg_code = r0; @@ -199,22 +199,9 @@ IonCompartment::generateEnterJIT(JSContext *cx) } IonCode * -IonCompartment::generateReturnError(JSContext *cx) +IonRuntime::generateInvalidator(JSContext *cx) { - MacroAssembler masm(cx); - // This is where the stack size is stored on x86. where is it stored here? - masm.ma_pop(r0); - masm.ma_add(r0, sp, sp); - - GenerateReturn(masm, JS_FALSE); - Linker linker(masm); - return linker.newCode(cx); -} - -IonCode * -IonCompartment::generateInvalidator(JSContext *cx) -{ - // See large comment in x86's IonCompartment::generateInvalidator. + // See large comment in x86's IonRuntime::generateInvalidator. AutoIonContextAlloc aica(cx); MacroAssembler masm(cx); //masm.as_bkpt(); @@ -261,7 +248,7 @@ IonCompartment::generateInvalidator(JSContext *cx) } IonCode * -IonCompartment::generateArgumentsRectifier(JSContext *cx) +IonRuntime::generateArgumentsRectifier(JSContext *cx) { MacroAssembler masm(cx); // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame. @@ -448,7 +435,7 @@ GenerateBailoutThunk(MacroAssembler &masm, uint32 frameClass) } IonCode * -IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass) +IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass) { MacroAssembler masm; @@ -464,7 +451,7 @@ IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass) } IonCode * -IonCompartment::generateBailoutHandler(JSContext *cx) +IonRuntime::generateBailoutHandler(JSContext *cx) { MacroAssembler masm; GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID); @@ -474,7 +461,7 @@ IonCompartment::generateBailoutHandler(JSContext *cx) } IonCode * -IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f) +IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { typedef MoveResolver::MoveOperand MoveOperand; @@ -622,7 +609,7 @@ IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f) } IonCode * -IonCompartment::generatePreBarrier(JSContext *cx) +IonRuntime::generatePreBarrier(JSContext *cx) { MacroAssembler masm; diff --git a/js/src/ion/shared/CodeGenerator-shared.cpp b/js/src/ion/shared/CodeGenerator-shared.cpp index 84462da23d9..226e02f7086 100644 --- a/js/src/ion/shared/CodeGenerator-shared.cpp +++ b/js/src/ion/shared/CodeGenerator-shared.cpp @@ -219,7 +219,8 @@ CodeGeneratorShared::encode(LSnapshot *snapshot) DebugOnly bailPC = pc; if (mir->mode() == MResumePoint::ResumeAfter) bailPC = GetNextPc(pc); - JS_ASSERT(exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC)); + JS_ASSERT_IF(GetIonContext()->cx, + exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC)); #ifdef TRACK_SNAPSHOTS LInstruction *ins = instruction(); @@ -374,10 +375,9 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi pushedArgs_ = 0; #endif - // Generate the wrapper of the VM function. - JSContext *cx = GetIonContext()->cx; - IonCompartment *ion = cx->compartment->ionCompartment(); - IonCode *wrapper = ion->generateVMWrapper(cx, fun); + // Get the wrapper of the VM function. + IonCompartment *ion = GetIonContext()->compartment->ionCompartment(); + IonCode *wrapper = ion->getVMWrapper(fun); if (!wrapper) return false; diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.cpp b/js/src/ion/shared/CodeGenerator-x86-shared.cpp index 8b9ae0f37ee..a58734651a4 100644 --- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp @@ -293,11 +293,8 @@ CodeGeneratorX86Shared::generateOutOfLineCode() // Push the frame size, so the handler can recover the IonScript. masm.push(Imm32(frameSize())); - JSContext *cx = GetIonContext()->cx; - IonCompartment *ion = cx->compartment->ionCompartment(); - IonCode *handler = ion->getGenericBailoutHandler(cx); - if (!handler) - return false; + IonCompartment *ion = GetIonContext()->compartment->ionCompartment(); + IonCode *handler = ion->getGenericBailoutHandler(); masm.jmp(handler->raw(), Relocation::IONCODE); } @@ -1329,13 +1326,9 @@ CodeGeneratorX86Shared::generateInvalidateEpilogue() masm.bind(&invalidate_); - JSContext *cx = GetIonContext()->cx; - // Push the Ion script onto the stack (when we determine what that pointer is). invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1))); - IonCode *thunk = cx->compartment->ionCompartment()->getOrCreateInvalidationThunk(cx); - if (!thunk) - return false; + IonCode *thunk = GetIonContext()->compartment->ionCompartment()->getInvalidationThunk(); masm.call(thunk); diff --git a/js/src/ion/x64/CodeGenerator-x64.cpp b/js/src/ion/x64/CodeGenerator-x64.cpp index 4f3b0a7dfe2..7de488a8918 100644 --- a/js/src/ion/x64/CodeGenerator-x64.cpp +++ b/js/src/ion/x64/CodeGenerator-x64.cpp @@ -53,6 +53,12 @@ FrameSizeClass::FromDepth(uint32 frameDepth) return FrameSizeClass::None(); } +FrameSizeClass +FrameSizeClass::ClassLimit() +{ + return FrameSizeClass(0); +} + uint32 FrameSizeClass::frameSize() const { @@ -293,13 +299,13 @@ CodeGeneratorX64::visitRecompileCheck(LRecompileCheck *lir) return true; } +typedef bool (*InterruptCheckFn)(JSContext *); +static const VMFunction InterruptCheckInfo = FunctionInfo(InterruptCheck); + bool CodeGeneratorX64::visitInterruptCheck(LInterruptCheck *lir) { - typedef bool (*pf)(JSContext *); - static const VMFunction interruptCheckInfo = FunctionInfo(InterruptCheck); - - OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing()); + OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); if (!ool) return false; diff --git a/js/src/ion/x64/MacroAssembler-x64.h b/js/src/ion/x64/MacroAssembler-x64.h index 572ab1c2144..b6cabc2b592 100644 --- a/js/src/ion/x64/MacroAssembler-x64.h +++ b/js/src/ion/x64/MacroAssembler-x64.h @@ -868,7 +868,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared // Save an exit frame (which must be aligned to the stack pointer) to // ThreadData::ionTop. void linkExitFrame() { - mov(ImmWord(GetIonContext()->cx->runtime), ScratchReg); + mov(ImmWord(GetIonContext()->compartment->rt), ScratchReg); mov(StackPointer, Operand(ScratchReg, offsetof(JSRuntime, ionTop))); } diff --git a/js/src/ion/x64/Trampoline-x64.cpp b/js/src/ion/x64/Trampoline-x64.cpp index a82ff3fc7ed..bcb09195d7c 100644 --- a/js/src/ion/x64/Trampoline-x64.cpp +++ b/js/src/ion/x64/Trampoline-x64.cpp @@ -25,7 +25,7 @@ using namespace js::ion; * ...using standard x64 fastcall calling convention */ IonCode * -IonCompartment::generateEnterJIT(JSContext *cx) +IonRuntime::generateEnterJIT(JSContext *cx) { MacroAssembler masm(cx); @@ -180,26 +180,12 @@ IonCompartment::generateEnterJIT(JSContext *cx) } IonCode * -IonCompartment::generateReturnError(JSContext *cx) -{ - MacroAssembler masm(cx); - - masm.pop(r14); // sizeDescriptor. - masm.xorl(Imm32(0x1), r14); // Unmark EntryFrame. - masm.addq(r14, rsp); // Remove arguments. - masm.pop(r11); // Discard |vp|: returning from error. - - Linker linker(masm); - return linker.newCode(cx); -} - -IonCode * -IonCompartment::generateInvalidator(JSContext *cx) +IonRuntime::generateInvalidator(JSContext *cx) { AutoIonContextAlloc aica(cx); MacroAssembler masm(cx); - // See explanatory comment in x86's IonCompartment::generateInvalidator. + // See explanatory comment in x86's IonRuntime::generateInvalidator. masm.addq(Imm32(sizeof(uintptr_t)), rsp); @@ -236,7 +222,7 @@ IonCompartment::generateInvalidator(JSContext *cx) } IonCode * -IonCompartment::generateArgumentsRectifier(JSContext *cx) +IonRuntime::generateArgumentsRectifier(JSContext *cx) { // Do not erase the frame pointer in this function. @@ -359,14 +345,14 @@ GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32 frameClass) } IonCode * -IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass) +IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass) { JS_NOT_REACHED("x64 does not use bailout tables"); return NULL; } IonCode * -IonCompartment::generateBailoutHandler(JSContext *cx) +IonRuntime::generateBailoutHandler(JSContext *cx) { MacroAssembler masm; @@ -377,7 +363,7 @@ IonCompartment::generateBailoutHandler(JSContext *cx) } IonCode * -IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f) +IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { typedef MoveResolver::MoveOperand MoveOperand; @@ -531,7 +517,7 @@ IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f) } IonCode * -IonCompartment::generatePreBarrier(JSContext *cx) +IonRuntime::generatePreBarrier(JSContext *cx) { MacroAssembler masm; diff --git a/js/src/ion/x86/CodeGenerator-x86.cpp b/js/src/ion/x86/CodeGenerator-x86.cpp index 96d5d6cb562..e52f9d1fa70 100644 --- a/js/src/ion/x86/CodeGenerator-x86.cpp +++ b/js/src/ion/x86/CodeGenerator-x86.cpp @@ -23,11 +23,7 @@ CodeGeneratorX86::CodeGeneratorX86(MIRGenerator *gen, LIRGraph &graph) { } -// The first two size classes are 128 and 256 bytes respectively. After that we -// increment by 512. -static const uint32 LAST_FRAME_SIZE = 512; -static const uint32 LAST_FRAME_INCREMENT = 512; -static const uint32 FrameSizes[] = { 128, 256, LAST_FRAME_SIZE }; +static const uint32 FrameSizes[] = { 128, 256, 512, 1024 }; FrameSizeClass FrameSizeClass::FromDepth(uint32 frameDepth) @@ -37,21 +33,22 @@ FrameSizeClass::FromDepth(uint32 frameDepth) return FrameSizeClass(i); } - uint32 newFrameSize = frameDepth - LAST_FRAME_SIZE; - uint32 sizeClass = (newFrameSize / LAST_FRAME_INCREMENT) + 1; - - return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes) + sizeClass); + return FrameSizeClass::None(); } + +FrameSizeClass +FrameSizeClass::ClassLimit() +{ + return FrameSizeClass(JS_ARRAY_LENGTH(FrameSizes)); +} + uint32 FrameSizeClass::frameSize() const { JS_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID); + JS_ASSERT(class_ < JS_ARRAY_LENGTH(FrameSizes)); - if (class_ < JS_ARRAY_LENGTH(FrameSizes)) - return FrameSizes[class_]; - - uint32 step = class_ - JS_ARRAY_LENGTH(FrameSizes); - return LAST_FRAME_SIZE + step * LAST_FRAME_INCREMENT; + return FrameSizes[class_]; } ValueOperand @@ -298,13 +295,13 @@ CodeGeneratorX86::visitRecompileCheck(LRecompileCheck *lir) return true; } +typedef bool (*InterruptCheckFn)(JSContext *); +static const VMFunction InterruptCheckInfo = FunctionInfo(InterruptCheck); + bool CodeGeneratorX86::visitInterruptCheck(LInterruptCheck *lir) { - typedef bool (*pf)(JSContext *); - static const VMFunction interruptCheckInfo = FunctionInfo(InterruptCheck); - - OutOfLineCode *ool = oolCallVM(interruptCheckInfo, lir, (ArgList()), StoreNothing()); + OutOfLineCode *ool = oolCallVM(InterruptCheckInfo, lir, (ArgList()), StoreNothing()); if (!ool) return false; diff --git a/js/src/ion/x86/Trampoline-x86.cpp b/js/src/ion/x86/Trampoline-x86.cpp index c403189d107..7a29c07c0b9 100644 --- a/js/src/ion/x86/Trampoline-x86.cpp +++ b/js/src/ion/x86/Trampoline-x86.cpp @@ -33,7 +33,7 @@ enum EnterJitEbpArgumentOffset { * using the standard cdecl calling convention. */ IonCode * -IonCompartment::generateEnterJIT(JSContext *cx) +IonRuntime::generateEnterJIT(JSContext *cx) { MacroAssembler masm(cx); @@ -161,7 +161,7 @@ IonCompartment::generateEnterJIT(JSContext *cx) } IonCode * -IonCompartment::generateInvalidator(JSContext *cx) +IonRuntime::generateInvalidator(JSContext *cx) { AutoIonContextAlloc aica(cx); MacroAssembler masm(cx); @@ -211,7 +211,7 @@ IonCompartment::generateInvalidator(JSContext *cx) } IonCode * -IonCompartment::generateArgumentsRectifier(JSContext *cx) +IonRuntime::generateArgumentsRectifier(JSContext *cx) { MacroAssembler masm(cx); @@ -357,7 +357,7 @@ GenerateBailoutThunk(JSContext *cx, MacroAssembler &masm, uint32 frameClass) } IonCode * -IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass) +IonRuntime::generateBailoutTable(JSContext *cx, uint32 frameClass) { MacroAssembler masm; @@ -373,7 +373,7 @@ IonCompartment::generateBailoutTable(JSContext *cx, uint32 frameClass) } IonCode * -IonCompartment::generateBailoutHandler(JSContext *cx) +IonRuntime::generateBailoutHandler(JSContext *cx) { MacroAssembler masm; @@ -384,7 +384,7 @@ IonCompartment::generateBailoutHandler(JSContext *cx) } IonCode * -IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f) +IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f) { AssertCanGC(); typedef MoveResolver::MoveOperand MoveOperand; @@ -544,7 +544,7 @@ IonCompartment::generateVMWrapper(JSContext *cx, const VMFunction &f) } IonCode * -IonCompartment::generatePreBarrier(JSContext *cx) +IonRuntime::generatePreBarrier(JSContext *cx) { MacroAssembler masm; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 23f22de7f05..6eb395e63c0 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -743,6 +743,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) #ifdef JS_METHODJIT jaegerRuntime_(NULL), #endif + ionRuntime_(NULL), selfHostedGlobal_(NULL), nativeStackBase(0), nativeStackQuota(0), @@ -1014,6 +1015,9 @@ JSRuntime::~JSRuntime() js_delete(mathCache_); #ifdef JS_METHODJIT js_delete(jaegerRuntime_); +#endif +#ifdef JS_ION + js_delete(ionRuntime_); #endif js_delete(execAlloc_); /* Delete after jaegerRuntime_. */ diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 53f542833f6..639b7c6f3b2 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -91,6 +91,7 @@ class JaegerRuntime; class MathCache; namespace ion { +class IonRuntime; class IonActivation; } @@ -499,12 +500,14 @@ struct JSRuntime : js::RuntimeFriendFields #ifdef JS_METHODJIT js::mjit::JaegerRuntime *jaegerRuntime_; #endif + js::ion::IonRuntime *ionRuntime_; JSObject *selfHostedGlobal_; JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx); WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx); js::mjit::JaegerRuntime *createJaegerRuntime(JSContext *cx); + js::ion::IonRuntime *createIonRuntime(JSContext *cx); public: JSC::ExecutableAllocator *getExecAlloc(JSContext *cx) { @@ -532,6 +535,9 @@ struct JSRuntime : js::RuntimeFriendFields return *jaegerRuntime_; } #endif + js::ion::IonRuntime *getIonRuntime(JSContext *cx) { + return ionRuntime_ ? ionRuntime_ : createIonRuntime(cx); + } bool initSelfHosting(JSContext *cx); void markSelfHostedGlobal(JSTracer *trc); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index e396a392b22..45ee1413b76 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -157,6 +157,29 @@ JSCompartment::setNeedsBarrier(bool needs, ShouldUpdateIon updateIon) } #ifdef JS_ION +ion::IonRuntime * +JSRuntime::createIonRuntime(JSContext *cx) +{ + ionRuntime_ = cx->new_(); + + if (!ionRuntime_) + return NULL; + + if (!ionRuntime_->initialize(cx)) { + js_delete(ionRuntime_); + ionRuntime_ = NULL; + + if (cx->runtime->atomsCompartment->ionCompartment_) { + js_delete(cx->runtime->atomsCompartment->ionCompartment_); + cx->runtime->atomsCompartment->ionCompartment_ = NULL; + } + + return NULL; + } + + return ionRuntime_; +} + bool JSCompartment::ensureIonCompartmentExists(JSContext *cx) { @@ -164,15 +187,15 @@ JSCompartment::ensureIonCompartmentExists(JSContext *cx) if (ionCompartment_) return true; - /* Set the compartment early, so linking works. */ - ionCompartment_ = cx->new_(); - - if (!ionCompartment_ || !ionCompartment_->initialize(cx)) { - if (ionCompartment_) - delete ionCompartment_; - ionCompartment_ = NULL; + IonRuntime *ionRuntime = cx->runtime->getIonRuntime(cx); + if (!ionRuntime) + return false; + + /* Set the compartment early, so linking works. */ + ionCompartment_ = cx->new_(ionRuntime); + + if (!ionCompartment_) return false; - } return true; } diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 894c6b49ba2..0fec7d8664b 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -122,6 +122,7 @@ struct JSCompartment JSPrincipals *principals; private: + friend struct JSRuntime; friend struct JSContext; js::GlobalObject *global_; public: diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 868fb7ed647..2363659e3d4 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2514,8 +2514,15 @@ MarkRuntime(JSTracer *trc, bool useSavedRoots = false) MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector"); } - if (!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment->isCollecting()) + if (!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment->isCollecting()) { MarkAtoms(trc); +#ifdef JS_ION + /* Any Ion wrappers survive until the runtime is being torn down. */ + if (rt->hasContexts()) + ion::IonRuntime::Mark(trc); +#endif + } + rt->staticStrings.trace(trc); for (ContextIter acx(rt); !acx.done(); acx.next()) diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 5bad37227f4..4127756cc05 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -465,7 +465,9 @@ NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize) AssertCanGC(); JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind)); JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment, - kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING); + kind == FINALIZE_STRING || + kind == FINALIZE_SHORT_STRING || + kind == FINALIZE_IONCODE); JS_ASSERT(!cx->runtime->isHeapBusy()); JS_ASSERT(!cx->runtime->noGCOrAllocationCheck); diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index 59a03e5cdcb..2ca901fa52c 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -20,8 +20,7 @@ using mozilla::DebugOnly; bool js::OffThreadCompilationAvailable(JSContext *cx) { - WorkerThreadState &state = *cx->runtime->workerThreadState; - return state.numThreads > 0; + return cx->runtime->useHelperThreads(); } bool @@ -77,6 +76,8 @@ CompiledScriptMatches(JSCompartment *compartment, JSScript *script, JSScript *ta void js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script) { + AutoAssertNoGC nogc; + if (!compartment->rt->workerThreadState) return;