author | Jan de Mooij <jdemooij@mozilla.com> |
Thu, 27 Sep 2012 12:45:55 +0200 | |
changeset 108264 | 385dbb23bb344d9390a756bb9422fc07b7f29699 |
parent 108263 | 978385fba015b69a5efd23763e8c6ca31007de3d |
child 108265 | 385bc6d035973f3909fb943484d1485583199608 |
push id | 23552 |
push user | ryanvm@gmail.com |
push date | Fri, 28 Sep 2012 03:05:08 +0000 |
treeherder | mozilla-central@2d96ee8d9dd4 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dvander |
bugs | 794475 |
milestone | 18.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/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -9,16 +9,18 @@ #include "IonLinker.h" #include "IonSpewer.h" #include "MIRGenerator.h" #include "shared/CodeGenerator-shared-inl.h" #include "jsnum.h" #include "jsmath.h" #include "jsinterpinlines.h" +#include "vm/StringObject-inl.h" + using namespace js; using namespace js::ion; namespace js { namespace ion { CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph &graph) : CodeGeneratorSpecific(gen, graph) @@ -1524,16 +1526,45 @@ CodeGenerator::visitNewCallObject(LNewCa if (lir->slots()->isRegister()) masm.storePtr(ToRegister(lir->slots()), Address(obj, JSObject::offsetOfSlots())); masm.bind(ool->rejoin()); return true; } bool +CodeGenerator::visitNewStringObject(LNewStringObject *lir) +{ + Register input = ToRegister(lir->input()); + Register output = ToRegister(lir->output()); + Register temp = ToRegister(lir->temp()); + + typedef JSObject *(*pf)(JSContext *, HandleString); + static const VMFunction NewStringObjectInfo = FunctionInfo<pf>(NewStringObject); + + StringObject *templateObj = lir->mir()->templateObj(); + + OutOfLineCode *ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input), + StoreRegisterTo(output)); + if (!ool) + return false; + + masm.newGCThing(output, templateObj, ool->entry()); + masm.initGCThing(output, templateObj); + + masm.loadStringLength(input, temp); + + masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue())); + masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength())); + + masm.bind(ool->rejoin()); + return true; +} + +bool CodeGenerator::visitInitProp(LInitProp *lir) { Register objReg = ToRegister(lir->getObject()); typedef bool(*pf)(JSContext *, HandleObject, HandlePropertyName, HandleValue); static const VMFunction InitPropInfo = FunctionInfo<pf>(InitProp); pushArg(ToValue(lir, LInitProp::ValueIndex)); @@ -1647,21 +1678,20 @@ CodeGenerator::visitTypedArrayElements(L Register out = ToRegister(lir->output()); masm.loadPtr(Address(obj, TypedArray::dataOffset()), out); return true; } bool CodeGenerator::visitStringLength(LStringLength *lir) { - Address lengthAndFlags(ToRegister(lir->string()), JSString::offsetOfLengthAndFlags()); + Register input = ToRegister(lir->string()); Register output = ToRegister(lir->output()); - masm.loadPtr(lengthAndFlags, output); - masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), output); + masm.loadStringLength(input, output); return true; } bool CodeGenerator::visitMinMaxI(LMinMaxI *ins) { Register first = ToRegister(ins->first()); Register output = ToRegister(ins->output());
--- a/js/src/ion/CodeGenerator.h +++ b/js/src/ion/CodeGenerator.h @@ -84,16 +84,17 @@ class CodeGenerator : public CodeGenerat bool visitNewSlots(LNewSlots *lir); bool visitNewArrayCallVM(LNewArray *lir); bool visitNewArray(LNewArray *lir); bool visitOutOfLineNewArray(OutOfLineNewArray *ool); bool visitNewObjectVMCall(LNewObject *lir); bool visitNewObject(LNewObject *lir); bool visitOutOfLineNewObject(OutOfLineNewObject *ool); bool visitNewCallObject(LNewCallObject *lir); + bool visitNewStringObject(LNewStringObject *lir); bool visitInitProp(LInitProp *lir); bool visitCreateThis(LCreateThis *lir); bool visitCreateThisVM(LCreateThisVM *lir); bool visitReturnFromCtor(LReturnFromCtor *lir); bool visitArrayLength(LArrayLength *lir); bool visitTypedArrayLength(LTypedArrayLength *lir); bool visitTypedArrayElements(LTypedArrayElements *lir); bool visitStringLength(LStringLength *lir);
--- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -377,16 +377,17 @@ class IonBuilder : public MIRGenerator InliningStatus inlineMathRound(uint32 argc, bool constructing); InliningStatus inlineMathSqrt(uint32 argc, bool constructing); InliningStatus inlineMathMinMax(bool max, uint32 argc, bool constructing); InliningStatus inlineMathPow(uint32 argc, bool constructing); InliningStatus inlineMathFunction(MMathFunction::Function function, uint32 argc, bool constructing); // String natives. + InliningStatus inlineStringObject(uint32 argc, bool constructing); InliningStatus inlineStrCharCodeAt(uint32 argc, bool constructing); InliningStatus inlineStrFromCharCode(uint32 argc, bool constructing); InliningStatus inlineStrCharAt(uint32 argc, bool constructing); InliningStatus inlineNativeCall(JSNative native, uint32 argc, bool constructing); bool jsop_call_inline(HandleFunction callee, uint32 argc, bool constructing, MConstant *constFun, MBasicBlock *bottom,
--- a/js/src/ion/IonMacroAssembler.h +++ b/js/src/ion/IonMacroAssembler.h @@ -144,16 +144,21 @@ class MacroAssembler : public MacroAssem loadPtr(Address(obj, JSObject::getPrivateDataOffset(nfixed)), dest); } void loadObjProto(Register obj, Register dest) { loadPtr(Address(obj, JSObject::offsetOfType()), dest); loadPtr(Address(dest, offsetof(types::TypeObject, proto)), dest); } + void loadStringLength(Register str, Register dest) { + loadPtr(Address(str, JSString::offsetOfLengthAndFlags()), dest); + rshiftPtr(Imm32(JSString::LENGTH_SHIFT), dest); + } + void loadJSContext(const Register &dest) { movePtr(ImmWord(GetIonContext()->cx->runtime), dest); loadPtr(Address(dest, offsetof(JSRuntime, ionJSContext)), dest); } void loadIonActivation(const Register &dest) { movePtr(ImmWord(GetIonContext()->cx->runtime), dest); loadPtr(Address(dest, offsetof(JSRuntime, ionActivation)), dest); }
--- a/js/src/ion/LIR-Common.h +++ b/js/src/ion/LIR-Common.h @@ -287,16 +287,37 @@ class LNewCallObject : public LInstructi const LAllocation *slots() { return getOperand(0); } MNewCallObject *mir() const { return mir_->toNewCallObject(); } }; +class LNewStringObject : public LInstructionHelper<1, 1, 1> +{ + public: + LIR_HEADER(NewStringObject); + + LNewStringObject(const LAllocation &input, const LDefinition &temp) { + setOperand(0, input); + setTemp(0, temp); + } + + const LAllocation *input() { + return getOperand(0); + } + const LDefinition *temp() { + return getTemp(0); + } + MNewStringObject *mir() const { + return mir_->toNewStringObject(); + } +}; + // Takes in an Object and a Value. class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> { public: LIR_HEADER(InitProp); LInitProp(const LAllocation &object) { setOperand(0, object);
--- a/js/src/ion/LOpcodes.h +++ b/js/src/ion/LOpcodes.h @@ -20,16 +20,17 @@ _(Parameter) \ _(Callee) \ _(TableSwitch) \ _(Goto) \ _(NewArray) \ _(NewObject) \ _(NewSlots) \ _(NewCallObject) \ + _(NewStringObject) \ _(InitProp) \ _(CheckOverRecursed) \ _(RecompileCheck) \ _(DefVar) \ _(CallKnown) \ _(CallGeneric) \ _(CallNative) \ _(CallConstructor) \
--- a/js/src/ion/Lowering.cpp +++ b/js/src/ion/Lowering.cpp @@ -134,16 +134,25 @@ LIRGenerator::visitNewCallObject(MNewCal if (!assignSafepoint(lir, ins)) return false; return true; } bool +LIRGenerator::visitNewStringObject(MNewStringObject *ins) +{ + JS_ASSERT(ins->input()->type() == MIRType_String); + + LNewStringObject *lir = new LNewStringObject(useRegister(ins->input()), temp()); + return define(lir, ins) && assignSafepoint(lir, ins); +} + +bool LIRGenerator::visitInitProp(MInitProp *ins) { LInitProp *lir = new LInitProp(useRegisterAtStart(ins->getObject())); if (!useBoxAtStart(lir, LInitProp::ValueIndex, ins->getValue())) return false; return add(lir, ins) && assignSafepoint(lir, ins); }
--- a/js/src/ion/Lowering.h +++ b/js/src/ion/Lowering.h @@ -76,16 +76,17 @@ class LIRGenerator : public LIRGenerator // intercept without a bunch of explicit gunk in the .cpp. bool visitParameter(MParameter *param); bool visitCallee(MCallee *callee); bool visitGoto(MGoto *ins); bool visitNewSlots(MNewSlots *ins); bool visitNewArray(MNewArray *ins); bool visitNewObject(MNewObject *ins); bool visitNewCallObject(MNewCallObject *ins); + bool visitNewStringObject(MNewStringObject *ins); bool visitInitProp(MInitProp *ins); bool visitCheckOverRecursed(MCheckOverRecursed *ins); bool visitDefVar(MDefVar *ins); bool visitPrepareCall(MPrepareCall *ins); bool visitPassArg(MPassArg *arg); bool visitCreateThis(MCreateThis *ins); bool visitReturnFromCtor(MReturnFromCtor *ins); bool visitCall(MCall *call);
--- a/js/src/ion/MCallOptimize.cpp +++ b/js/src/ion/MCallOptimize.cpp @@ -7,16 +7,18 @@ #include "jslibmath.h" #include "jsmath.h" #include "MIR.h" #include "MIRGraph.h" #include "IonBuilder.h" +#include "vm/StringObject-inl.h" + namespace js { namespace ion { IonBuilder::InliningStatus IonBuilder::inlineNativeCall(JSNative native, uint32 argc, bool constructing) { // Array natives. if (native == js_Array) @@ -48,16 +50,18 @@ IonBuilder::inlineNativeCall(JSNative na if (native == js::math_cos) return inlineMathFunction(MMathFunction::Cos, argc, constructing); if (native == js::math_tan) return inlineMathFunction(MMathFunction::Tan, argc, constructing); if (native == js::math_log) return inlineMathFunction(MMathFunction::Log, argc, constructing); // String natives. + if (native == js_String) + return inlineStringObject(argc, constructing); if (native == js_str_charCodeAt) return inlineStrCharCodeAt(argc, constructing); if (native == js::str_fromCharCode) return inlineStrFromCharCode(argc, constructing); if (native == js_str_charAt) return inlineStrCharAt(argc, constructing); return InliningStatus_NotInlined; @@ -552,16 +556,46 @@ IonBuilder::inlineMathMinMax(bool max, u MMinMax *ins = MMinMax::New(argv[1], argv[2], returnType, max); current->add(ins); current->push(ins); return InliningStatus_Inlined; } IonBuilder::InliningStatus +IonBuilder::inlineStringObject(uint32 argc, bool constructing) +{ + if (argc != 1 || !constructing) + return InliningStatus_NotInlined; + + // MToString only supports int32 or string values. + MIRType type = getInlineArgType(argc, 1); + if (type != MIRType_Int32 && type != MIRType_String) + return InliningStatus_NotInlined; + + MDefinitionVector argv; + if (!discardCall(argc, argv, current)) + return InliningStatus_Error; + + RootedString emptyString(cx, cx->runtime->emptyString); + RootedObject templateObj(cx, StringObject::create(cx, emptyString)); + if (!templateObj) + return InliningStatus_Error; + + MNewStringObject *ins = MNewStringObject::New(argv[1], templateObj); + current->add(ins); + current->push(ins); + + if (!resumeAfter(ins)) + return InliningStatus_Error; + + return InliningStatus_Inlined; +} + +IonBuilder::InliningStatus IonBuilder::inlineStrCharCodeAt(uint32 argc, bool constructing) { if (argc != 1 || constructing) return InliningStatus_NotInlined; if (getInlineReturnType() != MIRType_Int32) return InliningStatus_NotInlined; if (getInlineArgType(argc, 0) != MIRType_String)
--- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -5283,16 +5283,47 @@ class MNewCallObject : public MUnaryInst JSObject *templateObj() { return templateObj_; } AliasSet getAliasSet() const { return AliasSet::None(); } }; +class MNewStringObject : + public MUnaryInstruction, + public StringPolicy +{ + CompilerRootObject templateObj_; + + MNewStringObject(MDefinition *input, HandleObject templateObj) + : MUnaryInstruction(input), + templateObj_(templateObj) + { + setResultType(MIRType_Object); + } + + public: + INSTRUCTION_HEADER(NewStringObject); + + static MNewStringObject *New(MDefinition *input, HandleObject templateObj) { + return new MNewStringObject(input, templateObj); + } + + MDefinition *input() const { + return getOperand(0); + } + StringObject *templateObj() const { + return &templateObj_->asString(); + } + TypePolicy *typePolicy() { + return this; + } +}; + // Node that represents that a script has begun executing. This comes at the // start of the function and is called once per function (including inline // ones) class MFunctionBoundary : public MNullaryInstruction { public: enum Type { Enter, // a function has begun executing and it is not inline
--- a/js/src/ion/MOpcodes.h +++ b/js/src/ion/MOpcodes.h @@ -65,16 +65,17 @@ namespace ion { _(ToDouble) \ _(ToInt32) \ _(TruncateToInt32) \ _(ToString) \ _(NewSlots) \ _(NewArray) \ _(NewObject) \ _(NewCallObject) \ + _(NewStringObject) \ _(InitProp) \ _(Start) \ _(OsrEntry) \ _(RegExp) \ _(Lambda) \ _(ImplicitThis) \ _(Slots) \ _(Elements) \
--- a/js/src/ion/TypePolicy.cpp +++ b/js/src/ion/TypePolicy.cpp @@ -277,17 +277,25 @@ PowPolicy::adjustInputs(MInstruction *in bool StringPolicy::staticAdjustInputs(MInstruction *def) { MDefinition *in = def->getOperand(0); if (in->type() == MIRType_String) return true; - MUnbox *replace = MUnbox::New(in, MIRType_String, MUnbox::Fallible); + MInstruction *replace; + if (in->type() == MIRType_Int32) { + replace = MToString::New(in); + } else { + if (in->type() != MIRType_Value) + in = boxAt(def, in); + replace = MUnbox::New(in, MIRType_String, MUnbox::Fallible); + } + def->block()->insertBefore(def, replace); def->replaceOperand(0, replace); return true; } template <unsigned Op> bool IntPolicy<Op>::staticAdjustInputs(MInstruction *def)
--- a/js/src/ion/VMFunctions.cpp +++ b/js/src/ion/VMFunctions.cpp @@ -6,16 +6,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Ion.h" #include "IonCompartment.h" #include "jsinterp.h" #include "ion/IonFrames.h" #include "ion/IonFrames-inl.h" // for GetTopIonJSScript +#include "vm/StringObject-inl.h" + #include "jsinterpinlines.h" using namespace js; using namespace js::ion; namespace js { namespace ion { @@ -380,16 +382,22 @@ NewSlots(JSRuntime *rt, unsigned nslots) } JSObject * NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots) { return CallObject::create(cx, shape, type, slots); } +JSObject * +NewStringObject(JSContext *cx, HandleString str) +{ + return StringObject::create(cx, str); +} + bool SPSEnter(JSContext *cx, HandleScript script) { return cx->runtime->spsProfiler.enter(cx, script, script->function()); } bool SPSExit(JSContext *cx, HandleScript script) { cx->runtime->spsProfiler.exit(cx, script, script->function());
--- a/js/src/ion/VMFunctions.h +++ b/js/src/ion/VMFunctions.h @@ -434,16 +434,17 @@ JSFlatString *StringFromCharCode(JSConte bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value, bool strict, bool isSetName); bool InterruptCheck(JSContext *cx); HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots); JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots); +JSObject *NewStringObject(JSContext *cx, HandleString str); bool SPSEnter(JSContext *cx, HandleScript script); bool SPSExit(JSContext *cx, HandleScript script); } // namespace ion } // namespace js
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1310,16 +1310,26 @@ TypeConstraintCall::newType(JSContext *c if (callsite->argumentCount >= 2) { for (unsigned i = 0; i < callsite->argumentCount; i++) { PropertyAccess<PROPERTY_WRITE>(cx, script, pc, res, callsite->argumentTypes[i], JSID_VOID); } } } + if (native == js_String && callsite->isNew) { + // Note that "new String()" returns a String object and "String()" + // returns a primitive string. + TypeObject *res = TypeScript::StandardType(cx, script, JSProto_String); + if (!res) + return; + + callsite->returnTypes->addType(cx, Type::ObjectType(res)); + } + return; } callee = obj->toFunction(); } else if (type.isTypeObject()) { callee = type.typeObject()->interpretedFunction; if (!callee) return;
--- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -860,19 +860,17 @@ class GetPropCompiler : public PICStubCo LookupStatus generateStringObjLengthStub() { MJITInstrumentation sps(&f.cx->runtime->spsProfiler); Assembler masm(&sps, &f); Jump notStringObj = masm.guardShape(pic.objReg, obj); - masm.loadPayload(Address(pic.objReg, StringObject::getPrimitiveValueOffset()), pic.objReg); - masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg); - masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg); + masm.loadPayload(Address(pic.objReg, StringObject::offsetOfLength()), pic.objReg); masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); Jump done = masm.jump(); pic.updatePCCounters(f, masm); PICLinker buffer(masm, pic); if (!buffer.init(cx)) return error();
--- a/js/src/vm/StringObject.h +++ b/js/src/vm/StringObject.h @@ -36,19 +36,22 @@ class StringObject : public JSObject JSString *unbox() const { return getFixedSlot(PRIMITIVE_VALUE_SLOT).toString(); } inline size_t length() const { return size_t(getFixedSlot(LENGTH_SLOT).toInt32()); } - static size_t getPrimitiveValueOffset() { + static size_t offsetOfPrimitiveValue() { return getFixedSlotOffset(PRIMITIVE_VALUE_SLOT); } + static size_t offsetOfLength() { + return getFixedSlotOffset(LENGTH_SLOT); + } private: inline bool init(JSContext *cx, HandleString str); void setStringThis(JSString *str) { JS_ASSERT(getReservedSlot(PRIMITIVE_VALUE_SLOT).isUndefined()); setFixedSlot(PRIMITIVE_VALUE_SLOT, StringValue(str)); setFixedSlot(LENGTH_SLOT, Int32Value(int32_t(str->length())));