From e7ad41c28f22aebf49703eabd523eaf61c342891 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sat, 17 Sep 2011 19:31:33 -0700 Subject: [PATCH] [INFER] Reapply f1c585415dd4 7c89b0ff453d 19794de530f1 (bug 686000). --- .../jit-test/tests/jaeger/getelem-sanity-8.js | 13 ++++ js/src/jsanalyze.h | 1 + js/src/jsinterp.cpp | 10 ++- js/src/methodjit/Compiler.cpp | 72 +++++++++++++++++-- js/src/methodjit/Compiler.h | 6 +- js/src/methodjit/FastOps.cpp | 9 ++- js/src/methodjit/InvokeHelpers.cpp | 14 ++-- js/src/methodjit/PolyIC.cpp | 41 ++--------- js/src/methodjit/PolyIC.h | 4 ++ js/src/methodjit/StubCalls.cpp | 48 ++++--------- js/src/methodjit/StubCalls.h | 3 +- 11 files changed, 132 insertions(+), 89 deletions(-) create mode 100644 js/src/jit-test/tests/jaeger/getelem-sanity-8.js diff --git a/js/src/jit-test/tests/jaeger/getelem-sanity-8.js b/js/src/jit-test/tests/jaeger/getelem-sanity-8.js new file mode 100644 index 000000000000..f203216ac2cc --- /dev/null +++ b/js/src/jit-test/tests/jaeger/getelem-sanity-8.js @@ -0,0 +1,13 @@ + +// TI does not account for GETELEM accessing strings, so the GETELEM PIC must +// update type constraints according to generated stubs. +function foo(a, b) { + for (var j = 0; j < 5; j++) + a[b[j]] + " what"; +} +var a = {a:"zero", b:"one", c:"two", d:"three", e:"four"}; +var b = ["a", "b", "c", "d", "e"]; +foo(a, b); +foo(a, b); +a.e = 4; +foo(a, b); diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h index ac6fd67865f7..9bbcb09ca906 100644 --- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -145,6 +145,7 @@ class Bytecode * hints about the script for use during compilation. */ bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */ + bool getStringElement:1; /* GETELEM which has accessed string properties. */ bool accessGetter: 1; /* Property read on a shape with a getter hook. */ /* Stack depth before this opcode. */ diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index a8ae2dcbe24f..1cd37947702a 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -3903,13 +3903,13 @@ BEGIN_CASE(JSOP_GETELEM) } } + if (JSID_IS_STRING(id) && script->hasAnalysis() && !regs.fp()->hasImacropc()) + script->analysis()->getCode(regs.pc).getStringElement = true; + if (!obj->getProperty(cx, id, &rval)) goto error; copyFrom = &rval; - if (!JSID_IS_INT(id)) - TypeScript::MonitorUnknown(cx, script, regs.pc); - end_getelem: regs.sp--; regs.sp[-1] = *copyFrom; @@ -3947,8 +3947,6 @@ BEGIN_CASE(JSOP_CALLELEM) regs.sp[-1] = thisv; } - if (!JSID_IS_INT(id)) - TypeScript::MonitorUnknown(cx, script, regs.pc); TypeScript::Monitor(cx, script, regs.pc, regs.sp[-2]); } END_CASE(JSOP_CALLELEM) @@ -3975,7 +3973,7 @@ BEGIN_CASE(JSOP_SETELEM) obj->setDenseArrayElementWithType(cx, i, regs.sp[-1]); goto end_setelem; } else { - if (script->hasAnalysis()) + if (script->hasAnalysis() && !regs.fp()->hasImacropc()) script->analysis()->getCode(regs.pc).arrayWriteHole = true; } } diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 0131485549af..7d4181135198 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -4199,6 +4199,7 @@ mjit::Compiler::jsop_getprop_slow(JSAtom *atom, bool usePropCache) prepareStubCall(Uses(1)); if (usePropCache) { INLINE_STUBCALL(stubs::GetProp, rejoin); + testPushedType(rejoin, -1, /* ool = */ false); } else { masm.move(ImmPtr(atom), Registers::ArgReg1); INLINE_STUBCALL(stubs::GetPropNoCache, rejoin); @@ -4214,6 +4215,7 @@ mjit::Compiler::jsop_callprop_slow(JSAtom *atom) prepareStubCall(Uses(1)); masm.move(ImmPtr(atom), Registers::ArgReg1); INLINE_STUBCALL(stubs::CallProp, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -1, /* ool = */ false); frame.pop(); pushSyncedEntry(0); pushSyncedEntry(1); @@ -4309,6 +4311,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, stubcc.linkExit(notObject, Uses(1)); stubcc.leave(); OOL_STUBCALL(stubs::GetProp, rejoin); + if (rejoin == REJOIN_GETTER) + testPushedType(rejoin, -1); } RegisterID reg = frame.tempRegForData(top); frame.pop(); @@ -4329,6 +4333,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, stubcc.linkExit(notObject, Uses(1)); stubcc.leave(); OOL_STUBCALL(stubs::GetProp, rejoin); + if (rejoin == REJOIN_GETTER) + testPushedType(rejoin, -1); } RegisterID reg = frame.copyDataIntoReg(top); frame.pop(); @@ -4391,6 +4397,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, stubcc.linkExit(notObject, Uses(1)); stubcc.leave(); OOL_STUBCALL(stubs::GetProp, rejoin); + if (rejoin == REJOIN_GETTER) + testPushedType(rejoin, -1); } RegisterID reg = frame.tempRegForData(top); frame.pop(); @@ -4454,7 +4462,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, * type barrier if inference is enabled (known property types do not * reflect properties with getter hooks). */ - pic.canCallHook = usePropCache && JSOp(*PC) == JSOP_GETPROP && analysis->getCode(PC).accessGetter; + pic.canCallHook = pic.forcedTypeBarrier = + usePropCache && JSOp(*PC) == JSOP_GETPROP && analysis->getCode(PC).accessGetter; if (pic.canCallHook) frame.syncAndKillEverything(); @@ -4478,6 +4487,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, passICAddress(&pic); pic.slowPathCall = OOL_STUBCALL(usePropCache ? ic::GetProp : ic::GetPropNoCache, rejoin); CHECK_OOL_SPACE(); + if (rejoin == REJOIN_GETTER) + testPushedType(rejoin, -1); /* Load the base slot address. */ Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), @@ -4561,7 +4572,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom) pic.shapeReg = shapeReg; pic.atom = atom; - pic.canCallHook = analysis->getCode(PC).accessGetter; + pic.canCallHook = pic.forcedTypeBarrier = analysis->getCode(PC).accessGetter; if (pic.canCallHook) frame.syncAndKillEverything(); @@ -4599,6 +4610,8 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom) pic.slowPathCall = OOL_STUBCALL(ic::CallProp, REJOIN_FALLTHROUGH); CHECK_OOL_SPACE(); + testPushedType(REJOIN_FALLTHROUGH, -1); + /* Load the base slot address. */ Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), objReg); @@ -4731,7 +4744,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom) objReg = frame.copyDataIntoReg(top); } - pic.canCallHook = analysis->getCode(PC).accessGetter; + pic.canCallHook = pic.forcedTypeBarrier = analysis->getCode(PC).accessGetter; if (pic.canCallHook) frame.syncAndKillEverything(); @@ -4753,6 +4766,8 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom) pic.slowPathCall = OOL_STUBCALL(ic::CallProp, REJOIN_FALLTHROUGH); CHECK_OOL_SPACE(); + testPushedType(REJOIN_FALLTHROUGH, -1); + /* Load the base slot address. */ Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)), objReg); @@ -5044,6 +5059,7 @@ mjit::Compiler::jsop_callprop_dispatch(JSAtom *atom) stubcc.leave(); stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1); OOL_STUBCALL(stubs::CallProp, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -1); frame.dup(); // THIS THIS @@ -5074,6 +5090,7 @@ mjit::Compiler::jsop_callprop(JSAtom *atom) stubcc.leave(); stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1); OOL_STUBCALL(stubs::CallProp, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -1); } // THIS @@ -5344,6 +5361,7 @@ mjit::Compiler::jsop_name(JSAtom *atom, JSValueType type, bool isCall) passICAddress(&pic); pic.slowPathCall = OOL_STUBCALL(isCall ? ic::CallName : ic::Name, rejoin); CHECK_OOL_SPACE(); + testPushedType(rejoin, 0); } pic.fastPathRejoin = masm.label(); @@ -5431,6 +5449,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom) passICAddress(&pic); pic.slowPathCall = OOL_STUBCALL(ic::XName, REJOIN_GETTER); CHECK_OOL_SPACE(); + testPushedType(REJOIN_GETTER, -1); } pic.fastPathRejoin = masm.label(); @@ -5527,7 +5546,8 @@ void mjit::Compiler::jsop_name(JSAtom *atom, JSValueType type, bool isCall) { prepareStubCall(Uses(0)); - INLINE_STUBCALL(isCall ? stubs::CallName : stubs::Name, REJOIN_FALLTHROUGH); + INLINE_STUBCALL(isCall ? stubs::CallName : stubs::Name, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, 0, /* ool = */ false); frame.pushSynced(type); if (isCall) frame.pushSynced(JSVAL_TYPE_UNKNOWN); @@ -5903,6 +5923,7 @@ mjit::Compiler::jsop_getgname_slow(uint32 index) { prepareStubCall(Uses(0)); INLINE_STUBCALL(stubs::GetGlobalName, REJOIN_GETTER); + testPushedType(REJOIN_GETTER, 0, /* ool = */ false); frame.pushSynced(JSVAL_TYPE_UNKNOWN); } @@ -6016,6 +6037,10 @@ mjit::Compiler::jsop_getgname(uint32 index) passMICAddress(ic); ic.slowPathCall = OOL_STUBCALL(ic::GetGlobalName, REJOIN_GETTER); + CHECK_IC_SPACE(); + + testPushedType(REJOIN_GETTER, 0); + /* Garbage value. */ uint32 slot = 1 << 24; @@ -6029,8 +6054,6 @@ mjit::Compiler::jsop_getgname(uint32 index) ic.load = masm.loadValueWithAddressOffsetPatch(address, treg, dreg); - CHECK_IC_SPACE(); - frame.pushRegs(treg, dreg, type); /* @@ -6289,6 +6312,7 @@ mjit::Compiler::jsop_getelem_slow() { prepareStubCall(Uses(2)); INLINE_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -2, /* ool = */ false); frame.popn(2); pushSyncedEntry(0); } @@ -7033,6 +7057,7 @@ mjit::Compiler::jsop_callelem_slow() { prepareStubCall(Uses(2)); INLINE_STUBCALL(stubs::CallElem, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -2, /* ool = */ false); frame.popn(2); pushSyncedEntry(0); pushSyncedEntry(1); @@ -7535,3 +7560,38 @@ mjit::Compiler::finishBarrier(const BarrierState &barrier, RejoinState rejoin, u OOL_STUBCALL(stubs::TypeBarrierHelper, rejoin); stubcc.rejoin(Changes(0)); } + +void +mjit::Compiler::testPushedType(RejoinState rejoin, int which, bool ool) +{ + if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET)) + return; + + types::TypeSet *types = analysis->bytecodeTypes(PC); + if (types->unknown()) + return; + + Assembler &masm = ool ? stubcc.masm : this->masm; + + JS_ASSERT(which <= 0); + Address address = (which == 0) ? frame.addressOfTop() : frame.addressOf(frame.peek(which)); + + Vector mismatches(cx); + if (!masm.generateTypeCheck(cx, address, types, &mismatches)) { + oomInVector = true; + return; + } + + Jump j = masm.jump(); + + for (unsigned i = 0; i < mismatches.length(); i++) + mismatches[i].linkTo(masm.label(), &masm); + + masm.move(Imm32(which), Registers::ArgReg1); + if (ool) + OOL_STUBCALL(stubs::StubTypeHelper, rejoin); + else + INLINE_STUBCALL(stubs::StubTypeHelper, rejoin); + + j.linkTo(masm.label(), &masm); +} diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index c59cd863099a..7a900d476de5 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -184,7 +184,7 @@ class Compiler : public BaseCompiler }; struct BaseICInfo { - BaseICInfo(JSOp op) : op(op), canCallHook(false) + BaseICInfo(JSOp op) : op(op), canCallHook(false), forcedTypeBarrier(false) { } Label fastPathStart; Label fastPathRejoin; @@ -193,6 +193,7 @@ class Compiler : public BaseCompiler DataLabelPtr paramAddr; JSOp op; bool canCallHook; + bool forcedTypeBarrier; void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) { to.fastPathStart = full.locationOf(fastPathStart); @@ -200,6 +201,7 @@ class Compiler : public BaseCompiler to.slowPathStart = stub.locationOf(slowPathStart); to.slowPathCall = stub.locationOf(slowPathCall); to.canCallHook = canCallHook; + to.forcedTypeBarrier = forcedTypeBarrier; to.op = op; JS_ASSERT(to.op == op); } @@ -571,6 +573,8 @@ class Compiler : public BaseCompiler bool force = false); void finishBarrier(const BarrierState &barrier, RejoinState rejoin, uint32 which); + void testPushedType(RejoinState rejoin, int which, bool ool = true); + /* Non-emitting helpers. */ void pushSyncedEntry(uint32 pushed); uint32 fullAtomIndex(jsbytecode *pc); diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index 2505f6e3989b..f7f9ac2c19ef 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -1746,6 +1746,7 @@ mjit::Compiler::jsop_getelem_dense(bool isPacked) stubcc.leave(); OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -2); frame.popn(2); @@ -1837,6 +1838,7 @@ mjit::Compiler::jsop_getelem_args() stubcc.leave(); OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -2); frame.popn(2); frame.pushRegs(typeReg, dataReg, knownPushedType(0)); @@ -1968,6 +1970,7 @@ mjit::Compiler::jsop_getelem_typed(int atype) stubcc.leave(); OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH); + testPushedType(REJOIN_FALLTHROUGH, -2); frame.popn(2); @@ -2149,13 +2152,17 @@ mjit::Compiler::jsop_getelem(bool isCall) ic.slowPathCall = OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH); #endif + testPushedType(REJOIN_FALLTHROUGH, -2); + ic.fastPathRejoin = masm.label(); + ic.forcedTypeBarrier = analysis->getCode(PC).getStringElement; CHECK_IC_SPACE(); frame.popn(2); frame.pushRegs(ic.typeReg, ic.objReg, knownPushedType(0)); - BarrierState barrier = testBarrier(ic.typeReg, ic.objReg, false); + BarrierState barrier = testBarrier(ic.typeReg, ic.objReg, false, false, + /* force = */ ic.forcedTypeBarrier); if (isCall) frame.pushSynced(knownPushedType(1)); diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index 87401ae5b5b9..d427bd4da7d5 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -1360,10 +1360,6 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM /* Release this reference on the orphaned native stub. */ RemoveOrphanedNative(cx, fp); - /* - * Note: there is no need to monitor the result of the native, the stub - * will always do a type check before finishing. - */ f.regs.pc = nextpc; break; } @@ -1582,6 +1578,16 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM nextDepth = analysis->getCode(f.regs.pc).stackDepth; f.regs.sp = fp->base() + nextDepth; + /* + * Monitor the result of the previous op when finishing a JOF_TYPESET op. + * The result may not have been marked if we bailed out while inside a stub + * for the op. + */ + if (f.regs.pc == nextpc && (js_CodeSpec[op].format & JOF_TYPESET)) { + int which = (js_CodeSpec[op].format & JOF_CALLOP) ? -2 : -1; /* Yuck. */ + types::TypeScript::Monitor(cx, script, pc, f.regs.sp[which]); + } + /* Mark the entry frame as unfinished, and update the regs to resume at. */ JaegerStatus status = skipTrap ? Jaeger_UnfinishedAtTrap : Jaeger_Unfinished; cx->compartment->jaegerCompartment()->setLastUnfinished(status); diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index c8e5e9619831..81ad652ca6c7 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -1940,11 +1940,9 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic) THROW(); JSString *str = f.regs.sp[-1].toString(); f.regs.sp[-1].setInt32(str->length()); - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-1]); return; } else if (f.regs.sp[-1].isMagic(JS_LAZY_ARGUMENTS)) { f.regs.sp[-1].setInt32(f.regs.fp()->numActualArgs()); - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-1]); return; } else if (!f.regs.sp[-1].isPrimitive()) { JSObject *obj = &f.regs.sp[-1].toObject(); @@ -1969,15 +1967,12 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic) JSString *str = obj->getPrimitiveThis().toString(); f.regs.sp[-1].setInt32(str->length()); } - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-1]); return; } } atom = f.cx->runtime->atomState.lengthAtom; } - bool usePropCache = pic->usePropCache; - /* * ValueToObject can trigger recompilations if it lazily initializes any * of the primitive classes (Boolean, Number, String). :XXX: if these @@ -2004,16 +1999,6 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic) if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v)) THROW(); - /* - * Ignore undefined reads for the 'prototype' property in constructors, - * which will be at the start of the script and are never holes due to fun_resolve. - * Any undefined value was explicitly stored here, and is known by inference. - * :FIXME: looking under the usePropCache abstraction, which is only unset for - * reads of the prototype. - */ - if (usePropCache) - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), v); - f.regs.sp[-1] = v; } @@ -2183,8 +2168,6 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic) } #endif - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), regs.sp[-2]); - if (monitor.recompiled()) return; @@ -2234,8 +2217,6 @@ ic::XName(VMFrame &f, ic::PICInfo *pic) if (!cc.retrieve(&rval, NULL, PICInfo::XNAME)) THROW(); f.regs.sp[-1] = rval; - - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), rval); } void JS_FASTCALL @@ -2253,8 +2234,6 @@ ic::Name(VMFrame &f, ic::PICInfo *pic) if (!cc.retrieve(&rval, NULL, PICInfo::NAME)) THROW(); f.regs.sp[0] = rval; - - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), rval); } static void JS_FASTCALL @@ -2280,8 +2259,6 @@ ic::CallName(VMFrame &f, ic::PICInfo *pic) f.regs.sp[0] = rval; f.regs.sp[1] = thisval; - - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), rval); } static void JS_FASTCALL @@ -2458,6 +2435,12 @@ GetElementIC::attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Valu if (status != Lookup_Cacheable) return status; + // With TI enabled, string property stubs can only be added to an opcode if + // the value read will go through a type barrier afterwards. TI only + // accounts for integer-valued properties accessed by GETELEM/CALLELEM. + if (cx->typeInferenceEnabled() && !forcedTypeBarrier) + return disable(cx, "string element access may not have type barrier"); + Assembler masm; // Guard on the string's type and identity. @@ -2921,9 +2904,6 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic) // If the result can be cached, the value was already retrieved. JS_ASSERT(!f.regs.sp[-2].isMagic()); f.regs.sp[-1].setObject(*thisObj); - if (!JSID_IS_INT(id)) - types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc()); - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]); return; } } @@ -2943,9 +2923,6 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic) { f.regs.sp[-1] = thisv; } - if (!JSID_IS_INT(id)) - types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc()); - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]); } void JS_FASTCALL @@ -2987,18 +2964,12 @@ ic::GetElement(VMFrame &f, ic::GetElementIC *ic) // If the result can be cached, the value was already retrieved. JS_ASSERT(!f.regs.sp[-2].isMagic()); - if (!JSID_IS_INT(id)) - types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc()); - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]); return; } } if (!obj->getProperty(cx, id, &f.regs.sp[-2])) THROW(); - if (!JSID_IS_INT(id)) - types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc()); - types::TypeScript::Monitor(f.cx, f.script(), f.pc(), f.regs.sp[-2]); } #define APPLY_STRICTNESS(f, s) \ diff --git a/js/src/methodjit/PolyIC.h b/js/src/methodjit/PolyIC.h index 9bf88a478a45..f408f91aed21 100644 --- a/js/src/methodjit/PolyIC.h +++ b/js/src/methodjit/PolyIC.h @@ -96,6 +96,9 @@ struct BaseIC : public MacroAssemblerTypedefs { // Whether getter/setter hooks can be called from IC stubs. bool canCallHook : 1; + // Whether a type barrier is in place for the result of the op. + bool forcedTypeBarrier : 1; + // Number of stubs generated. uint32 stubsGenerated : 5; @@ -105,6 +108,7 @@ struct BaseIC : public MacroAssemblerTypedefs { void reset() { hit = false; slowCallPatched = false; + forcedTypeBarrier = false; stubsGenerated = 0; secondShapeGuard = 0; } diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 6fc396e5dfd7..23b43218e603 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -375,7 +375,6 @@ NameOp(VMFrame &f, JSObject *obj, bool callname) if (op2 == JSOP_TYPEOF) { f.regs.sp++; f.regs.sp[-1].setUndefined(); - TypeScript::Monitor(cx, f.script(), f.pc(), f.regs.sp[-1]); return obj; } ReportAtomNotDefined(cx, atom); @@ -402,8 +401,6 @@ NameOp(VMFrame &f, JSObject *obj, bool callname) AddTypePropertyId(cx, obj, id, Type::UndefinedType()); } - TypeScript::Monitor(cx, f.script(), f.pc(), rval); - *f.regs.sp++ = rval; if (callname) @@ -443,7 +440,6 @@ stubs::GetElem(VMFrame &f) if (!str) THROW(); f.regs.sp[-2].setString(str); - TypeScript::Monitor(cx, f.script(), f.pc(), f.regs.sp[-2]); return; } } @@ -451,7 +447,6 @@ stubs::GetElem(VMFrame &f) if (lref.isMagic(JS_LAZY_ARGUMENTS)) { if (rref.isInt32() && size_t(rref.toInt32()) < regs.fp()->numActualArgs()) { regs.sp[-2] = regs.fp()->canonicalActualArg(rref.toInt32()); - TypeScript::Monitor(cx, f.script(), f.pc(), regs.sp[-2]); return; } MarkArgumentsCreated(cx, f.script()); @@ -508,12 +503,8 @@ stubs::GetElem(VMFrame &f) THROW(); copyFrom = &rval; - if (!JSID_IS_INT(id)) - TypeScript::MonitorUnknown(cx, f.script(), f.pc()); - end_getelem: f.regs.sp[-2] = *copyFrom; - TypeScript::Monitor(cx, f.script(), f.pc(), f.regs.sp[-2]); } static inline bool @@ -559,9 +550,6 @@ stubs::CallElem(VMFrame &f) { regs.sp[-1] = thisv; } - if (!JSID_IS_INT(id)) - TypeScript::MonitorUnknown(cx, f.script(), f.pc()); - TypeScript::Monitor(cx, f.script(), f.pc(), regs.sp[-2]); } template @@ -1573,7 +1561,6 @@ InlineGetProp(VMFrame &f) if (vp->isMagic(JS_LAZY_ARGUMENTS)) { JS_ASSERT(js_GetOpcode(cx, f.script(), f.pc()) == JSOP_LENGTH); regs.sp[-1] = Int32Value(regs.fp()->numActualArgs()); - TypeScript::Monitor(cx, f.script(), f.pc(), regs.sp[-1]); return true; } @@ -1622,8 +1609,6 @@ InlineGetProp(VMFrame &f) } } while(0); - TypeScript::Monitor(cx, f.script(), f.pc(), rval); - regs.sp[-1] = rval; return true; } @@ -1742,7 +1727,6 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom) THROW(); } #endif - TypeScript::Monitor(cx, f.script(), f.pc(), rval); } void JS_FASTCALL @@ -2394,6 +2378,19 @@ stubs::TypeBarrierHelper(VMFrame &f, uint32 which) TypeScript::Monitor(f.cx, f.script(), f.pc(), result); } +void JS_FASTCALL +stubs::StubTypeHelper(VMFrame &f, int32 which) +{ + const Value &result = f.regs.sp[which]; + + if (f.script()->hasAnalysis() && f.script()->analysis()->ranInference()) { + AutoEnterTypeInference enter(f.cx); + f.script()->analysis()->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false); + } + + TypeScript::Monitor(f.cx, f.script(), f.pc(), result); +} + /* * Variant of TypeBarrierHelper for checking types after making a native call. * The stack is already correct, and no fixup should be performed. @@ -2411,25 +2408,6 @@ stubs::NegZeroHelper(VMFrame &f) TypeScript::MonitorOverflow(f.cx, f.script(), f.pc()); } -void JS_FASTCALL -stubs::CallPropSwap(VMFrame &f) -{ - /* - * CALLPROP operations on strings are implemented in terms of GETPROP. - * If we rejoin from such a GETPROP, we come here at the end of the - * CALLPROP to fix up the stack. Right now the stack looks like: - * - * STRING PROP - * - * We need it to be: - * - * PROP STRING - */ - Value v = f.regs.sp[-1]; - f.regs.sp[-1] = f.regs.sp[-2]; - f.regs.sp[-2] = v; -} - void JS_FASTCALL stubs::CheckArgumentTypes(VMFrame &f) { diff --git a/js/src/methodjit/StubCalls.h b/js/src/methodjit/StubCalls.h index 374ed93d4dd3..41c712a24b7e 100644 --- a/js/src/methodjit/StubCalls.h +++ b/js/src/methodjit/StubCalls.h @@ -210,7 +210,8 @@ void JS_FASTCALL TypeBarrierHelper(VMFrame &f, uint32 which); void JS_FASTCALL TypeBarrierReturn(VMFrame &f, Value *vp); void JS_FASTCALL NegZeroHelper(VMFrame &f); -void JS_FASTCALL CallPropSwap(VMFrame &f); +void JS_FASTCALL StubTypeHelper(VMFrame &f, int32 which); + void JS_FASTCALL CheckArgumentTypes(VMFrame &f); #ifdef DEBUG