From 866500404d58c76a1e71f1be2c5f98adb104df38 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Feb 2011 13:49:14 -0800 Subject: [PATCH] Backed out changeset 54a515a97151 --- js/src/jit-test/tests/jaeger/bug627486.js | 23 --- js/src/methodjit/Compiler.cpp | 132 +++++++------- js/src/methodjit/Compiler.h | 26 +-- js/src/methodjit/MonoIC.cpp | 200 ++++------------------ js/src/methodjit/MonoIC.h | 34 ++-- 5 files changed, 134 insertions(+), 281 deletions(-) delete mode 100644 js/src/jit-test/tests/jaeger/bug627486.js diff --git a/js/src/jit-test/tests/jaeger/bug627486.js b/js/src/jit-test/tests/jaeger/bug627486.js deleted file mode 100644 index f87d27e18a4..00000000000 --- a/js/src/jit-test/tests/jaeger/bug627486.js +++ /dev/null @@ -1,23 +0,0 @@ -// |jit-test| error: TypeError -// vim: set ts=4 sw=4 tw=99 et: -g = undefined; -function L() { } - -function h() { - with (h) { } - for (var i = 0; i < 10; i++) - g(); -} - -function f(x) { - g = x; -} - -f(L); -h(); -f(L); -f(2); -h(); - -/* Don't assert/crash. */ - diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index f86d0749528..5d9c7196c7c 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -500,33 +500,24 @@ mjit::Compiler::finishThisUp(JITScript **jitp) if (ic::MICInfo *scriptMICs = jit->mics) { for (size_t i = 0; i < mics.length(); i++) { scriptMICs[i].kind = mics[i].kind; - scriptMICs[i].fastPathStart = fullCode.locationOf(mics[i].fastPathStart); - scriptMICs[i].slowPathStart = stubCode.locationOf(mics[i].slowPathStart); - if (mics[i].kind == ic::MICInfo::GET) - scriptMICs[i].load = fullCode.locationOf(mics[i].load); - else - scriptMICs[i].load = fullCode.locationOf(mics[i].store).labelAtOffset(0); - scriptMICs[i].shape = fullCode.locationOf(mics[i].shape); - scriptMICs[i].stubCall = stubCode.locationOf(mics[i].call); - scriptMICs[i].usePropertyCache = mics[i].usePropertyCache; - scriptMICs[i].extraShapeGuard = 0; - scriptMICs[i].objConst = mics[i].objConst; - scriptMICs[i].shapeReg = mics[i].shapeReg; - scriptMICs[i].objReg = mics[i].objReg; - scriptMICs[i].vr = mics[i].vr; - - if (mics[i].kind == ic::MICInfo::SET) { - int offset = fullCode.locationOf(mics[i].shapeGuardJump) - - scriptMICs[i].fastPathStart; - scriptMICs[i].inlineShapeJump = offset; - JS_ASSERT(scriptMICs[i].inlineShapeJump == offset); - - offset = fullCode.locationOf(mics[i].fastPathRejoin) - - scriptMICs[i].fastPathStart; - scriptMICs[i].fastRejoinOffset = offset; - JS_ASSERT(scriptMICs[i].fastRejoinOffset == offset); + scriptMICs[i].entry = fullCode.locationOf(mics[i].entry); + switch (mics[i].kind) { + case ic::MICInfo::GET: + case ic::MICInfo::SET: + if (mics[i].kind == ic::MICInfo::GET) + scriptMICs[i].load = fullCode.locationOf(mics[i].load); + else + scriptMICs[i].load = fullCode.locationOf(mics[i].store).labelAtOffset(0); + scriptMICs[i].shape = fullCode.locationOf(mics[i].shape); + scriptMICs[i].stubCall = stubCode.locationOf(mics[i].call); + scriptMICs[i].stubEntry = stubCode.locationOf(mics[i].stubEntry); + scriptMICs[i].u.name.typeConst = mics[i].u.name.typeConst; + scriptMICs[i].u.name.dataConst = mics[i].u.name.dataConst; + scriptMICs[i].u.name.usePropertyCache = mics[i].u.name.usePropertyCache; + break; + default: + JS_NOT_REACHED("Bad MIC kind"); } - stubCode.patch(mics[i].addrLabel, &scriptMICs[i]); } } @@ -4317,7 +4308,7 @@ mjit::Compiler::jsop_getgname(uint32 index) RegisterID objReg; Jump shapeGuard; - mic.fastPathStart = masm.label(); + mic.entry = masm.label(); if (fe->isConstant()) { JSObject *obj = &fe->getValue().toObject(); frame.pop(); @@ -4339,10 +4330,11 @@ mjit::Compiler::jsop_getgname(uint32 index) Imm32(int32(JSObjectMap::INVALID_SHAPE)), mic.shape); frame.freeReg(reg); } - mic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(0)); + stubcc.linkExit(shapeGuard, Uses(0)); stubcc.leave(); passMICAddress(mic); + mic.stubEntry = stubcc.masm.label(); mic.call = OOL_STUBCALL(ic::GetGlobalName); /* Garbage value. */ @@ -4361,8 +4353,6 @@ mjit::Compiler::jsop_getgname(uint32 index) frame.pushRegs(treg, dreg); stubcc.rejoin(Changes(1)); - - mic.fastPathRejoin = masm.label(); mics.append(mic); #else @@ -4388,71 +4378,91 @@ mjit::Compiler::jsop_setgname(JSAtom *atom, bool usePropertyCache) { #if defined JS_MONOIC FrameEntry *objFe = frame.peek(-2); - FrameEntry *fe = frame.peek(-1); JS_ASSERT_IF(objFe->isTypeKnown(), objFe->getKnownType() == JSVAL_TYPE_OBJECT); MICGenInfo mic(ic::MICInfo::SET); - frame.pinEntry(fe, mic.vr); - RESERVE_IC_SPACE(masm); + RegisterID objReg; Jump shapeGuard; - mic.fastPathStart = masm.label(); + mic.entry = masm.label(); if (objFe->isConstant()) { JSObject *obj = &objFe->getValue().toObject(); JS_ASSERT(obj->isNative()); - mic.objReg = frame.allocReg(); - mic.shapeReg = mic.objReg; - mic.objConst = true; + objReg = frame.allocReg(); - masm.load32FromImm(&obj->objShape, mic.shapeReg); - shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, mic.shapeReg, + masm.load32FromImm(&obj->objShape, objReg); + shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, objReg, Imm32(int32(JSObjectMap::INVALID_SHAPE)), mic.shape); - masm.move(ImmPtr(obj), mic.objReg); + masm.move(ImmPtr(obj), objReg); } else { - mic.objReg = frame.copyDataIntoReg(objFe); - mic.shapeReg = frame.allocReg(); - mic.objConst = false; + objReg = frame.copyDataIntoReg(objFe); + RegisterID reg = frame.allocReg(); - masm.loadShape(mic.objReg, mic.shapeReg); - shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, mic.shapeReg, + masm.loadShape(objReg, reg); + shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, reg, Imm32(int32(JSObjectMap::INVALID_SHAPE)), mic.shape); - frame.freeReg(mic.shapeReg); + frame.freeReg(reg); } - mic.shapeGuardJump = shapeGuard; - mic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(2)); + stubcc.linkExit(shapeGuard, Uses(2)); stubcc.leave(); passMICAddress(mic); + mic.stubEntry = stubcc.masm.label(); mic.call = OOL_STUBCALL(ic::SetGlobalName); /* Garbage value. */ uint32 slot = 1 << 24; - mic.usePropertyCache = usePropertyCache; + /* Get both type and reg into registers. */ + FrameEntry *fe = frame.peek(-1); - masm.loadPtr(Address(mic.objReg, offsetof(JSObject, slots)), mic.objReg); - Address address(mic.objReg, slot); + Value v; + RegisterID typeReg = Registers::ReturnReg; + RegisterID dataReg = Registers::ReturnReg; + JSValueType typeTag = JSVAL_TYPE_INT32; - if (mic.vr.isConstant()) { - mic.store = masm.storeValueWithAddressOffsetPatch(mic.vr.value(), address); - } else if (mic.vr.isTypeKnown()) { - mic.store = masm.storeValueWithAddressOffsetPatch(ImmType(mic.vr.knownType()), - mic.vr.dataReg(), address); + mic.u.name.typeConst = fe->isTypeKnown(); + mic.u.name.dataConst = fe->isConstant(); + mic.u.name.usePropertyCache = usePropertyCache; + + if (!mic.u.name.dataConst) { + dataReg = frame.ownRegForData(fe); + if (!mic.u.name.typeConst) + typeReg = frame.ownRegForType(fe); + else + typeTag = fe->getKnownType(); } else { - mic.store = masm.storeValueWithAddressOffsetPatch(mic.vr.typeReg(), mic.vr.dataReg(), address); + v = fe->getValue(); } - frame.freeReg(mic.objReg); - frame.unpinEntry(mic.vr); - frame.shimmy(1); + masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg); + Address address(objReg, slot); + + if (mic.u.name.dataConst) { + mic.store = masm.storeValueWithAddressOffsetPatch(v, address); + } else if (mic.u.name.typeConst) { + mic.store = masm.storeValueWithAddressOffsetPatch(ImmType(typeTag), dataReg, address); + } else { + mic.store = masm.storeValueWithAddressOffsetPatch(typeReg, dataReg, address); + } + + frame.freeReg(objReg); + frame.popn(2); + if (mic.u.name.dataConst) { + frame.push(v); + } else { + if (mic.u.name.typeConst) + frame.pushTypedPayload(typeTag, dataReg); + else + frame.pushRegs(typeReg, dataReg); + } stubcc.rejoin(Changes(1)); - mic.fastPathRejoin = masm.label(); mics.append(mic); #else jsop_setgname_slow(atom, usePropertyCache); diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index 4d8d8d0aa5d..b3646620468 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -70,21 +70,27 @@ class Compiler : public BaseCompiler struct MICGenInfo { MICGenInfo(ic::MICInfo::Kind kind) : kind(kind) { } - Label fastPathStart; - Label slowPathStart; - Label fastPathRejoin; - Label load; + Label entry; + Label stubEntry; DataLabel32 shape; DataLabelPtr addrLabel; + Label load; DataLabel32 store; Call call; ic::MICInfo::Kind kind; - Jump shapeGuardJump; - ValueRemat vr; - RegisterID objReg; - RegisterID shapeReg; - bool objConst; - bool usePropertyCache; + jsbytecode *jumpTarget; + Jump traceHint; + MaybeJump slowTraceHint; + union { + struct { + bool typeConst; + bool dataConst; + bool usePropertyCache; + } name; + struct { + uint32 pcOffs; + } tracer; + } u; }; struct EqualityGenInfo { diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 90a6bd4ce00..cc640c271f6 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -48,7 +48,6 @@ #include "methodjit/CodeGenIncludes.h" #include "methodjit/Compiler.h" #include "methodjit/ICRepatcher.h" -#include "methodjit/PolyIC.h" #include "InlineFrameAssembler.h" #include "jsobj.h" @@ -67,8 +66,6 @@ typedef JSC::MacroAssembler::Jump Jump; typedef JSC::MacroAssembler::Imm32 Imm32; typedef JSC::MacroAssembler::ImmPtr ImmPtr; typedef JSC::MacroAssembler::Call Call; -typedef JSC::MacroAssembler::Label Label; -typedef JSC::MacroAssembler::DataLabel32 DataLabel32; #if defined JS_MONOIC @@ -101,6 +98,8 @@ ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic) } uint32 slot = shape->slot; + ic->u.name.touched = true; + /* Patch shape guard. */ Repatcher repatcher(f.jit()); repatcher.repatch(ic->shape, obj->shape()); @@ -142,174 +141,51 @@ PatchSetFallback(VMFrame &f, ic::MICInfo *ic) JSScript *script = f.fp()->script(); Repatcher repatch(f.jit()); - VoidStubMIC stub = ic->usePropertyCache + VoidStubMIC stub = ic->u.name.usePropertyCache ? STRICT_VARIANT(DisabledSetGlobal) : STRICT_VARIANT(DisabledSetGlobalNoCache); JSC::FunctionPtr fptr(JS_FUNC_TO_DATA_PTR(void *, stub)); repatch.relink(ic->stubCall, fptr); } -static LookupStatus -UpdateSetGlobalNameStub(VMFrame &f, ic::MICInfo *ic, JSObject *obj, const Shape *shape) -{ - Repatcher repatcher(ic->extraStub); - - JSC::CodeLocationLabel label(JSC::MacroAssemblerCodePtr(ic->extraStub.start())); - repatcher.repatch(label.dataLabel32AtOffset(ic->extraShapeGuard), obj->shape()); - - label = label.labelAtOffset(ic->extraStoreOffset); - repatcher.patchAddressOffsetForValueStore(label, shape->slot * sizeof(Value), - ic->vr.isTypeKnown()); - - return Lookup_Cacheable; -} - -static LookupStatus -AttachSetGlobalNameStub(VMFrame &f, ic::MICInfo *ic, JSObject *obj, const Shape *shape) -{ - Assembler masm; - - Label start = masm.label(); - - DataLabel32 shapeLabel; - Jump guard = masm.branch32WithPatch(Assembler::NotEqual, ic->shapeReg, Imm32(obj->shape()), - shapeLabel); - - /* A constant object needs rematerialization. */ - if (ic->objConst) - masm.move(ImmPtr(obj), ic->objReg); - - JS_ASSERT(obj->branded()); - - /* - * Load obj->slots. If ic->objConst, then this clobbers objReg, because - * ic->objReg == ic->shapeReg. - */ - masm.loadPtr(Address(ic->objReg, offsetof(JSObject, slots)), ic->shapeReg); - - /* Test if overwriting a function-tagged slot. */ - Address slot(ic->shapeReg, sizeof(Value) * shape->slot); - Jump isNotObject = masm.testObject(Assembler::NotEqual, slot); - - /* Now, test if the object is a function object. */ - masm.loadPayload(slot, ic->shapeReg); - Jump isFun = masm.testFunction(Assembler::Equal, ic->shapeReg); - - /* Restore shapeReg to obj->slots, since we clobbered it. */ - if (ic->objConst) { - masm.move(ImmPtr(obj), ic->objReg); - masm.loadPtr(Address(ic->objReg, offsetof(JSObject, slots)), ic->shapeReg); - } - - /* If the object test fails, shapeReg is still obj->slots. */ - isNotObject.linkTo(masm.label(), &masm); - DataLabel32 store = masm.storeValueWithAddressOffsetPatch(ic->vr, slot); - - Jump done = masm.jump(); - - JITScript *jit = f.jit(); - LinkerHelper linker(masm); - JSC::ExecutablePool *ep = linker.init(f.cx); - if (!ep) - return Lookup_Error; - if (!jit->execPools.append(ep)) { - ep->release(); - js_ReportOutOfMemory(f.cx); - return Lookup_Error; - } - - if (!linker.verifyRange(jit)) { - ep->release(); - return Lookup_Uncacheable; - } - - linker.link(done, ic->fastPathStart.labelAtOffset(ic->fastRejoinOffset)); - linker.link(guard, ic->slowPathStart); - linker.link(isFun, ic->slowPathStart); - - JSC::CodeLocationLabel cs = linker.finalize(); - JaegerSpew(JSpew_PICs, "generated setgname stub at %p\n", cs.executableAddress()); - - Repatcher repatcher(f.jit()); - repatcher.relink(ic->fastPathStart.jumpAtOffset(ic->inlineShapeJump), cs); - - int offset = linker.locationOf(shapeLabel) - linker.locationOf(start); - ic->extraShapeGuard = offset; - JS_ASSERT(ic->extraShapeGuard == offset); - JS_ASSERT(offset); - - ic->extraStub = JSC::JITCode(cs.executableAddress(), linker.size()); - offset = linker.locationOf(store) - linker.locationOf(start); - ic->extraStoreOffset = offset; - JS_ASSERT(ic->extraStoreOffset == offset); - - return Lookup_Cacheable; -} - -static LookupStatus -UpdateGlobalName(VMFrame &f, ic::MICInfo *ic, JSObject *obj, const Shape *shape) -{ - /* Give globals a chance to appear. */ - if (!shape) - return Lookup_Uncacheable; - - if (shape->isMethod() || - !shape->hasDefaultSetter() || - !shape->writable() || - !shape->hasSlot()) - { - /* Disable the IC for weird shape attributes. */ - PatchSetFallback(f, ic); - return Lookup_Uncacheable; - } - - /* Branded sets must guard that they don't overwrite method-valued properties. */ - if (obj->branded()) { - /* - * If this slot has a function valued property, the tail of this opcode - * could change the shape. Even if it doesn't, the IC is probably - * pointless, because it will always hit the function-test path and - * bail out. In these cases, don't bother building or updating the IC. - */ - const Value &v = obj->getSlot(shape->slot); - if (v.isObject() && v.toObject().isFunction()) { - /* - * If we're going to rebrand, the object may unbrand, allowing this - * IC to come back to life. In that case, we don't disable the IC. - */ - if (!ChangesMethodValue(v, f.regs.sp[-1])) - PatchSetFallback(f, ic); - return Lookup_Uncacheable; - } - - if (ic->extraShapeGuard) - return UpdateSetGlobalNameStub(f, ic, obj, shape); - - return AttachSetGlobalNameStub(f, ic, obj, shape); - } - - /* Object is not branded, so we can use the inline path. */ - Repatcher repatcher(f.jit()); - repatcher.repatch(ic->shape, obj->shape()); - repatcher.patchAddressOffsetForValueStore(ic->load, shape->slot * sizeof(Value), - ic->vr.isTypeKnown()); - - return Lookup_Cacheable; -} - void JS_FASTCALL ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic) { JSObject *obj = f.fp()->scopeChain().getGlobal(); JSScript *script = f.fp()->script(); JSAtom *atom = script->getAtom(GET_INDEX(f.regs.pc)); - const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom)); + jsid id = ATOM_TO_JSID(atom); - LookupStatus status = UpdateGlobalName(f, ic, obj, shape); - if (status == Lookup_Error) - THROW(); + JS_ASSERT(ic->kind == ic::MICInfo::SET); - if (ic->usePropertyCache) + const Shape *shape = obj->nativeLookup(id); + if (!shape || + shape->isMethod() || + !shape->hasDefaultSetter() || + !shape->writable() || + !shape->hasSlot()) + { + if (shape) + PatchSetFallback(f, ic); + if (ic->u.name.usePropertyCache) + STRICT_VARIANT(stubs::SetGlobalName)(f, atom); + else + STRICT_VARIANT(stubs::SetGlobalNameNoCache)(f, atom); + return; + } + uint32 slot = shape->slot; + + ic->u.name.touched = true; + + /* Patch shape guard. */ + Repatcher repatcher(f.jit()); + repatcher.repatch(ic->shape, obj->shape()); + + /* Patch loads. */ + repatcher.patchAddressOffsetForValueStore(ic->load, slot * sizeof(Value), + ic->u.name.typeConst); + + if (ic->u.name.usePropertyCache) STRICT_VARIANT(stubs::SetGlobalName)(f, atom); else STRICT_VARIANT(stubs::SetGlobalNameNoCache)(f, atom); @@ -1281,16 +1157,6 @@ JITScript::sweepCallICs(JSContext *cx, bool purgeAll) released++; } - for (uint32 i = 0; i < nMICs; i ++) { - ic::MICInfo &ic = mics[i]; - if (!ic.extraShapeGuard) - continue; - JS_ASSERT(ic.kind == ic::MICInfo::SET); - repatcher.relink(ic.fastPathStart.jumpAtOffset(ic.inlineShapeJump), ic.slowPathStart); - ic.extraShapeGuard = 0; - released++; - } - JS_ASSERT(released == execPools.length()); for (uint32 i = 0; i < released; i++) execPools[i]->release(); diff --git a/js/src/methodjit/MonoIC.h b/js/src/methodjit/MonoIC.h index 1cbba69bc27..db3765192f7 100644 --- a/js/src/methodjit/MonoIC.h +++ b/js/src/methodjit/MonoIC.h @@ -43,7 +43,6 @@ #include "assembler/assembler/MacroAssembler.h" #include "assembler/assembler/CodeLocation.h" -#include "assembler/moco/MocoStubs.h" #include "methodjit/MethodJIT.h" #include "CodeGenIncludes.h" @@ -101,10 +100,9 @@ struct MICInfo { SET }; - typedef JSC::MacroAssembler::RegisterID RegisterID; - - JSC::CodeLocationLabel fastPathStart; - JSC::CodeLocationLabel slowPathStart; + /* Used by multiple MICs. */ + JSC::CodeLocationLabel entry; + JSC::CodeLocationLabel stubEntry; /* * - ARM and x64 always emit exactly one instruction which needs to be @@ -119,21 +117,17 @@ struct MICInfo { JSC::CodeLocationDataLabel32 shape; JSC::CodeLocationCall stubCall; - /* SET only, if we had to generate an out-of-line path. */ - Kind kind : 2; - bool usePropertyCache : 1; - int inlineShapeJump : 10; /* Offset into inline path for shape jump. */ - int extraShapeGuard : 6; /* Offset into stub for shape guard. */ - bool objConst : 1; /* True if the object is constant. */ - RegisterID objReg : 5; /* Register for object, if objConst is false. */ - RegisterID shapeReg : 5; /* Register for shape; volatile. */ - JSC::JITCode extraStub; /* Out-of-line generated stub. */ - - int fastRejoinOffset : 16; /* Offset from fastPathStart to rejoin. */ - int extraStoreOffset : 16; /* Offset into store code. */ - - /* SET only. */ - ValueRemat vr; /* RHS value. */ + /* Used by all MICs. */ + Kind kind : 3; + union { + /* Used by GET/SET. */ + struct { + bool touched : 1; + bool typeConst : 1; + bool dataConst : 1; + bool usePropertyCache : 1; + } name; + } u; }; struct TraceICInfo {