Merge backout.

This commit is contained in:
David Anderson 2011-02-01 13:49:38 -08:00
commit 674cddc8c2
5 changed files with 134 additions and 281 deletions

View File

@ -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. */

View File

@ -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);

View File

@ -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 {

View File

@ -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();

View File

@ -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 {