mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 578761: PIC for JSOP_GETELEM. (r=dvander)
This commit is contained in:
parent
cdeede6c82
commit
a887840fdf
@ -308,15 +308,12 @@ mjit::Compiler::finishThisUp()
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pics.length(); i++) {
|
||||
script->pics[i].kind = pics[i].kind;
|
||||
pics[i].copySimpleMembersTo(script->pics[i]);
|
||||
script->pics[i].fastPathStart = fullCode.locationOf(pics[i].hotPathBegin);
|
||||
script->pics[i].storeBack = fullCode.locationOf(pics[i].storeBack);
|
||||
script->pics[i].slowPathStart = stubCode.locationOf(pics[i].slowPathStart);
|
||||
script->pics[i].callReturn = uint16((uint8*)stubCode.locationOf(pics[i].callReturn).executableAddress() -
|
||||
(uint8*)script->pics[i].slowPathStart.executableAddress());
|
||||
script->pics[i].shapeReg = pics[i].shapeReg;
|
||||
script->pics[i].objReg = pics[i].objReg;
|
||||
script->pics[i].atom = pics[i].atom;
|
||||
script->pics[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].hotPathBegin);
|
||||
script->pics[i].shapeRegHasBaseShape = true;
|
||||
@ -324,15 +321,12 @@ mjit::Compiler::finishThisUp()
|
||||
if (pics[i].kind == ic::PICInfo::SET) {
|
||||
script->pics[i].u.vr = pics[i].vr;
|
||||
} else if (pics[i].kind != ic::PICInfo::NAME) {
|
||||
script->pics[i].u.get.typeReg = pics[i].typeReg;
|
||||
if (pics[i].hasTypeCheck) {
|
||||
int32 distance = stubcc.masm.distanceOf(pics[i].typeCheck) -
|
||||
stubcc.masm.distanceOf(pics[i].slowPathStart);
|
||||
script->pics[i].u.get.typeCheckOffset = uint16(-distance);
|
||||
JS_ASSERT(script->pics[i].u.get.typeCheckOffset == -distance);
|
||||
}
|
||||
script->pics[i].u.get.hasTypeCheck = pics[i].hasTypeCheck;
|
||||
script->pics[i].u.get.objRemat = pics[i].objRemat.offset;
|
||||
}
|
||||
new (&script->pics[i].execPools) ic::PICInfo::ExecPoolVector(SystemAllocPolicy());
|
||||
}
|
||||
@ -1961,6 +1955,56 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
|
||||
pics.append(pic);
|
||||
}
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
void
|
||||
mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
|
||||
RegisterID idReg, RegisterID shapeReg)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::GETELEM);
|
||||
|
||||
pic.objRemat = frame.dataRematInfo(obj);
|
||||
pic.idRemat = frame.dataRematInfo(id);
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.hasTypeCheck = false;
|
||||
|
||||
pic.hotPathBegin = masm.label();
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, map)), shapeReg);
|
||||
masm.load32(Address(shapeReg, offsetof(JSObjectMap, shape)), shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
Jump shapeGuard = masm.branch32(Assembler::NotEqual, shapeReg,
|
||||
Imm32(int32(JSObjectMap::INVALID_SHAPE)));
|
||||
|
||||
/* Guard on id identity. */
|
||||
static const int32 BOGUS_ATOM = 0xdeadbeef;
|
||||
// :FIXME: x64
|
||||
Jump idGuard = masm.branch32(Assembler::NotEqual, idReg, Imm32(BOGUS_ATOM));
|
||||
pic.slowPathStart = stubcc.masm.label();
|
||||
stubcc.linkExit(idGuard, Uses(2));
|
||||
stubcc.linkExitDirect(shapeGuard, pic.slowPathStart);
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.masm.move(Imm32(pics.length()), Registers::ArgReg1);
|
||||
pic.callReturn = stubcc.call(ic::GetElem);
|
||||
|
||||
/* Load dslots. */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
masm.loadTypeTag(slot, shapeReg);
|
||||
masm.loadData32(slot, objReg);
|
||||
pic.storeBack = masm.label();
|
||||
pic.objReg = objReg;
|
||||
pic.idReg = idReg;
|
||||
JS_ASSERT(pic.idReg != pic.objReg);
|
||||
JS_ASSERT(pic.idReg != pic.shapeReg);
|
||||
JS_ASSERT(pic.objReg != pic.shapeReg);
|
||||
pics.append(pic);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
||||
{
|
||||
|
@ -110,13 +110,31 @@ class Compiler
|
||||
Label slowPathStart;
|
||||
RegisterID shapeReg;
|
||||
RegisterID objReg;
|
||||
RegisterID idReg;
|
||||
RegisterID typeReg;
|
||||
Label shapeGuard;
|
||||
JSAtom *atom;
|
||||
StateRemat objRemat;
|
||||
StateRemat idRemat;
|
||||
Call callReturn;
|
||||
bool hasTypeCheck;
|
||||
ValueRemat vr;
|
||||
|
||||
void copySimpleMembersTo(ic::PICInfo &pi) const {
|
||||
pi.kind = kind;
|
||||
pi.shapeReg = shapeReg;
|
||||
pi.objReg = objReg;
|
||||
pi.atom = atom;
|
||||
if (kind == ic::PICInfo::SET) {
|
||||
pi.u.vr = vr;
|
||||
} else if (kind != ic::PICInfo::NAME) {
|
||||
pi.u.get.idReg = idReg;
|
||||
pi.u.get.typeReg = typeReg;
|
||||
pi.u.get.hasTypeCheck = hasTypeCheck;
|
||||
pi.u.get.objRemat = objRemat.offset;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -133,6 +151,10 @@ class Compiler
|
||||
: reg(Registers::ReturnReg), set(false)
|
||||
{ }
|
||||
|
||||
MaybeRegisterID(RegisterID reg)
|
||||
: reg(reg), set(true)
|
||||
{ }
|
||||
|
||||
inline RegisterID getReg() const { JS_ASSERT(set); return reg; }
|
||||
inline void setReg(const RegisterID r) { reg = r; set = true; }
|
||||
inline bool isSet() const { return set; }
|
||||
@ -276,6 +298,13 @@ class Compiler
|
||||
void jsop_localinc(JSOp op, uint32 slot, bool popped);
|
||||
void jsop_setelem();
|
||||
void jsop_getelem();
|
||||
void jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg);
|
||||
void jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg);
|
||||
void jsop_getelem_nopic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg);
|
||||
void jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg, RegisterID idReg,
|
||||
RegisterID shapeReg);
|
||||
void jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
|
||||
MaybeRegisterID &idReg, RegisterID shapeReg);
|
||||
void jsop_stricteq(JSOp op);
|
||||
void jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
void jsop_pos();
|
||||
|
@ -349,6 +349,25 @@ FrameState::predictRegForType(FrameEntry *fe)
|
||||
return reg;
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::RegisterID
|
||||
FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
|
||||
{
|
||||
JS_ASSERT(regstate[fallback].fe == NULL);
|
||||
if (fe->isCopy())
|
||||
fe = fe->copyOf();
|
||||
|
||||
JS_ASSERT(!fe->type.isConstant());
|
||||
|
||||
if (fe->type.inRegister())
|
||||
return fe->type.reg();
|
||||
|
||||
/* :XXX: X86 */
|
||||
|
||||
masm.loadTypeTag(addressOf(fe), fallback);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
|
||||
inline JSC::MacroAssembler::RegisterID
|
||||
FrameState::tempRegForType(FrameEntry *fe)
|
||||
{
|
||||
@ -542,6 +561,15 @@ FrameState::testBoolean(Assembler::Condition cond, FrameEntry *fe)
|
||||
return masm.testBoolean(cond, tempRegForType(fe));
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::Jump
|
||||
FrameState::testString(Assembler::Condition cond, FrameEntry *fe)
|
||||
{
|
||||
JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
|
||||
if (shouldAvoidTypeRemat(fe))
|
||||
return masm.testString(cond, addressOf(fe));
|
||||
return masm.testString(cond, tempRegForType(fe));
|
||||
}
|
||||
|
||||
inline FrameEntry *
|
||||
FrameState::getLocal(uint32 slot)
|
||||
{
|
||||
|
@ -255,6 +255,15 @@ class FrameState
|
||||
*/
|
||||
inline RegisterID tempRegForType(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Try to use a register already allocated for fe's type, but if one
|
||||
* is not already available, use fallback.
|
||||
*
|
||||
* Note: this does NOT change fe's type-register remat info. It's supposed
|
||||
* to be a super lightweight/transparent operation.
|
||||
*/
|
||||
inline RegisterID tempRegForType(FrameEntry *fe, RegisterID fallback);
|
||||
|
||||
/*
|
||||
* Returns a register that is guaranteed to contain the frame entry's
|
||||
* data payload. The compiler may not modify the contents of the register.
|
||||
@ -464,11 +473,17 @@ class FrameState
|
||||
inline Jump testDouble(Assembler::Condition cond, FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Helper function. Tests if a slot's type is an integer. Condition should
|
||||
* Helper function. Tests if a slot's type is a boolean. Condition should
|
||||
* be Equal or NotEqual.
|
||||
*/
|
||||
inline Jump testBoolean(Assembler::Condition cond, FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Helper function. Tests if a slot's type is a string. Condition should
|
||||
* be Equal or NotEqual.
|
||||
*/
|
||||
inline Jump testString(Assembler::Condition cond, FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Helper function. Tests if a slot's type is a non-funobj. Condition should
|
||||
* be Equal or NotEqual.
|
||||
|
@ -48,7 +48,8 @@ using namespace js;
|
||||
using namespace js::mjit;
|
||||
|
||||
#ifdef JS_METHODJIT_PROFILE_STUBS
|
||||
static uint32 StubCallsForOp[255];
|
||||
static const size_t STUB_CALLS_FOR_OP_COUNT = 255;
|
||||
static uint32 StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
|
||||
#endif
|
||||
|
||||
extern "C" void JS_FASTCALL
|
||||
@ -542,6 +543,11 @@ ThreadData::Initialize()
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT_PROFILE_STUBS
|
||||
for (size_t i = 0; i < STUB_CALLS_FOR_OP_COUNT; ++i)
|
||||
StubCallsForOp[i] = 0;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ typedef JSC::MacroAssembler::Address Address;
|
||||
typedef JSC::ReturnAddressPtr ReturnAddressPtr;
|
||||
typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr;
|
||||
|
||||
struct AutoPropertyDropper
|
||||
class AutoPropertyDropper
|
||||
{
|
||||
JSContext *cx;
|
||||
JSObject *holder;
|
||||
@ -827,7 +827,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||
JS_ASSERT(tempObj);
|
||||
JS_ASSERT(tempObj->isNative());
|
||||
|
||||
masm.loadData32(proto, pic.objReg);
|
||||
masm.loadPtr(proto, pic.objReg);
|
||||
pic.shapeRegHasBaseShape = false;
|
||||
pic.u.get.objNeedsRemat = true;
|
||||
|
||||
@ -939,10 +939,267 @@ class GetPropCompiler : public PICStubCompiler
|
||||
return patchInline(holder, sprop);
|
||||
else
|
||||
return generateStub(holder, sprop);
|
||||
}
|
||||
|
||||
bool disable(const char *reason)
|
||||
{
|
||||
return PICStubCompiler::disable(reason, stub);
|
||||
}
|
||||
};
|
||||
|
||||
class GetElemCompiler : public PICStubCompiler
|
||||
{
|
||||
JSObject *obj;
|
||||
JSString *id;
|
||||
void *stub;
|
||||
int lastStubSecondShapeGuard;
|
||||
|
||||
#ifdef JS_CPU_X86
|
||||
static const int32 DSLOTS_LOAD = -15;
|
||||
static const int32 TYPE_LOAD = -6;
|
||||
static const int32 DATA_LOAD = 0;
|
||||
static const int32 INLINE_SHAPE_OFFSET = 0x6;
|
||||
static const int32 INLINE_ATOM_OFFSET = 0x12;
|
||||
static const int32 INLINE_ATOM_JUMP = 0x18;
|
||||
static const int32 INLINE_SHAPE_JUMP = 12;
|
||||
static const int32 STUB_SHAPE_JUMP = 12;
|
||||
static const int32 STUB_ATOM_JUMP = 24;
|
||||
#endif
|
||||
|
||||
public:
|
||||
GetElemCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSString *id,
|
||||
VoidStub stub)
|
||||
: PICStubCompiler("getelem", f, script, pic), obj(obj), id(id),
|
||||
stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
|
||||
lastStubSecondShapeGuard(pic.u.get.secondShapeGuard)
|
||||
{}
|
||||
|
||||
bool patchInline(JSObject *holder, JSScopeProperty *sprop)
|
||||
{
|
||||
spew("patch", "inline");
|
||||
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
|
||||
|
||||
int32 offset;
|
||||
if (sprop->slot < JS_INITIAL_NSLOTS) {
|
||||
JSC::CodeLocationInstruction istr = pic.storeBack.instructionAtOffset(DSLOTS_LOAD);
|
||||
repatcher.repatchLoadPtrToLEA(istr);
|
||||
|
||||
//
|
||||
// We've patched | mov dslots, [obj + DSLOTS_OFFSET]
|
||||
// To: | lea fslots, [obj + DSLOTS_OFFSET]
|
||||
//
|
||||
// Because the offset is wrong, it's necessary to correct it
|
||||
// below.
|
||||
//
|
||||
int32 diff = int32(offsetof(JSObject, fslots)) - int32(offsetof(JSObject, dslots));
|
||||
JS_ASSERT(diff != 0);
|
||||
offset = (int32(sprop->slot) * sizeof(Value)) + diff;
|
||||
} else {
|
||||
offset = (sprop->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
|
||||
}
|
||||
|
||||
uint32 shapeOffset = pic.shapeGuard + INLINE_SHAPE_OFFSET;
|
||||
repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(shapeOffset), obj->shape());
|
||||
uint32 idOffset = pic.shapeGuard + INLINE_ATOM_OFFSET;
|
||||
repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(idOffset), int32(id));
|
||||
repatcher.repatch(pic.storeBack.dataLabel32AtOffset(TYPE_LOAD), offset + 4);
|
||||
repatcher.repatch(pic.storeBack.dataLabel32AtOffset(DATA_LOAD), offset);
|
||||
pic.inlinePathPatched = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void patchPreviousToHere(PICRepatchBuffer &repatcher, CodeLocationLabel cs)
|
||||
{
|
||||
// Patch either the inline fast path or a generated stub. The stub
|
||||
// omits the prefix of the inline fast path that loads the shape, so
|
||||
// the offsets are different.
|
||||
int shapeGuardJumpOffset;
|
||||
int atomGuardJumpOffset;
|
||||
if (pic.stubsGenerated) {
|
||||
shapeGuardJumpOffset = STUB_SHAPE_JUMP;
|
||||
atomGuardJumpOffset = STUB_ATOM_JUMP;
|
||||
} else {
|
||||
shapeGuardJumpOffset = pic.shapeGuard + INLINE_SHAPE_JUMP;
|
||||
atomGuardJumpOffset = pic.shapeGuard + INLINE_ATOM_JUMP;
|
||||
}
|
||||
repatcher.relink(shapeGuardJumpOffset, cs);
|
||||
repatcher.relink(atomGuardJumpOffset, cs);
|
||||
if (lastStubSecondShapeGuard)
|
||||
repatcher.relink(lastStubSecondShapeGuard, cs);
|
||||
}
|
||||
|
||||
bool generateStub(JSObject *holder, JSScopeProperty *sprop)
|
||||
{
|
||||
JS_ASSERT(pic.u.get.idReg != pic.shapeReg);
|
||||
Vector<Jump, 8> shapeMismatches(f.cx);
|
||||
|
||||
Assembler masm;
|
||||
|
||||
if (pic.objNeedsRemat()) {
|
||||
if (pic.objRemat() >= sizeof(JSStackFrame))
|
||||
masm.loadData32(Address(JSFrameReg, pic.objRemat()), pic.objReg);
|
||||
else
|
||||
masm.move(RegisterID(pic.objRemat()), pic.objReg);
|
||||
pic.u.get.objNeedsRemat = false;
|
||||
}
|
||||
|
||||
if (pic.idNeedsRemat()) {
|
||||
if (pic.idRemat() >= sizeof(JSStackFrame))
|
||||
masm.loadData32(Address(JSFrameReg, pic.idRemat()), pic.u.get.idReg);
|
||||
else
|
||||
masm.move(RegisterID(pic.idRemat()), pic.u.get.idReg);
|
||||
pic.u.get.idNeedsRemat = false;
|
||||
}
|
||||
|
||||
Label start;
|
||||
Jump shapeGuard;
|
||||
Jump atomGuard;
|
||||
if (obj->isDenseArray()) {
|
||||
start = masm.label();
|
||||
atomGuard = masm.branchPtr(Assembler::NotEqual, pic.u.get.idReg, ImmPtr(id));
|
||||
shapeGuard = masm.branchPtr(Assembler::NotEqual,
|
||||
Address(pic.objReg, offsetof(JSObject, clasp)),
|
||||
ImmPtr(obj->getClass()));
|
||||
} else {
|
||||
if (pic.shapeNeedsRemat()) {
|
||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
pic.shapeRegHasBaseShape = true;
|
||||
}
|
||||
|
||||
start = masm.label();
|
||||
atomGuard = masm.branchPtr(Assembler::NotEqual, pic.u.get.idReg, ImmPtr(id));
|
||||
shapeGuard = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
|
||||
Imm32(obj->shape()));
|
||||
}
|
||||
|
||||
if (!(shapeMismatches.append(shapeGuard) && shapeMismatches.append(atomGuard)))
|
||||
return false;
|
||||
|
||||
if (obj != holder) {
|
||||
// Emit code that walks the prototype chain.
|
||||
JSObject *tempObj = obj;
|
||||
Address proto(pic.objReg, offsetof(JSObject, proto));
|
||||
do {
|
||||
tempObj = tempObj->getProto();
|
||||
// FIXME: we should find out why this condition occurs. It is probably
|
||||
// related to PICs on globals.
|
||||
if (!tempObj)
|
||||
return false;
|
||||
JS_ASSERT(tempObj);
|
||||
|
||||
/*
|
||||
* If there is a native along the prototype chain the shape is technically
|
||||
* invalid.
|
||||
*/
|
||||
if (!tempObj->isNative())
|
||||
return false;
|
||||
|
||||
masm.loadPtr(proto, pic.objReg);
|
||||
pic.shapeRegHasBaseShape = false;
|
||||
pic.u.get.objNeedsRemat = true;
|
||||
|
||||
Jump j = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
|
||||
if (!shapeMismatches.append(j))
|
||||
return false;
|
||||
} while (tempObj != holder);
|
||||
|
||||
// Load the shape out of the holder and check it.
|
||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
Jump j = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
|
||||
Imm32(holder->shape()));
|
||||
if (!shapeMismatches.append(j))
|
||||
return false;
|
||||
pic.u.get.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start);
|
||||
} else {
|
||||
JS_ASSERT(holder->isNative()); /* Precondition: already checked. */
|
||||
pic.u.get.secondShapeGuard = 0;
|
||||
}
|
||||
|
||||
/* Load the value out of the object. */
|
||||
masm.loadSlot(pic.objReg, pic.objReg, sprop->slot, pic.shapeReg, pic.objReg);
|
||||
Jump done = masm.jump();
|
||||
|
||||
JSC::ExecutablePool *ep = getExecPool(masm.size());
|
||||
if (!ep) {
|
||||
js_ReportOutOfMemory(f.cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// :TODO: this can OOM
|
||||
JSC::LinkBuffer buffer(&masm, ep);
|
||||
|
||||
if (!pic.execPools.append(ep)) {
|
||||
ep->release();
|
||||
js_ReportOutOfMemory(f.cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The guard exit jumps to the original slow case.
|
||||
for (Jump *pj = shapeMismatches.begin(); pj != shapeMismatches.end(); ++pj)
|
||||
buffer.link(*pj, pic.slowPathStart);
|
||||
|
||||
// The final exit jumps to the store-back in the inline stub.
|
||||
buffer.link(done, pic.storeBack);
|
||||
CodeLocationLabel cs = buffer.finalizeCodeAddendum();
|
||||
#if DEBUG
|
||||
char *chars = js_DeflateString(f.cx, id->chars(), id->length());
|
||||
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n",
|
||||
type, cs.executableAddress(), id, chars, holder->shape(), script->filename,
|
||||
js_FramePCToLineNumber(f.cx, f.fp));
|
||||
f.cx->free(chars);
|
||||
#endif
|
||||
|
||||
PICRepatchBuffer repatcher(pic, pic.lastPathStart());
|
||||
patchPreviousToHere(repatcher, cs);
|
||||
|
||||
pic.stubsGenerated++;
|
||||
pic.lastStubStart = buffer.locationOf(start);
|
||||
|
||||
if (pic.stubsGenerated == MAX_STUBS)
|
||||
disable("max stubs reached");
|
||||
if (obj->isDenseArray())
|
||||
disable("dense array");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update()
|
||||
{
|
||||
if (!pic.hit) {
|
||||
spew("first hit", "nop");
|
||||
pic.hit = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSAtom *atom = js_AtomizeString(f.cx, id, 0);
|
||||
if (!atom)
|
||||
return false;
|
||||
JSObject *holder;
|
||||
JSProperty *prop;
|
||||
if (!obj->lookupProperty(f.cx, ATOM_TO_JSID(atom), &holder, &prop))
|
||||
return false;
|
||||
|
||||
if (!prop)
|
||||
return disable("lookup failed");
|
||||
|
||||
AutoPropertyDropper dropper(f.cx, holder, prop);
|
||||
|
||||
if (!holder->isNative())
|
||||
return disable("non-native holder");
|
||||
|
||||
JSScopeProperty *sprop = (JSScopeProperty *)prop;
|
||||
if (!sprop->hasDefaultGetterOrIsMethod())
|
||||
return disable("getter");
|
||||
if (!SPROP_HAS_VALID_SLOT(sprop, holder->scope()))
|
||||
return disable("invalid slot");
|
||||
|
||||
if (obj == holder && !pic.inlinePathPatched)
|
||||
return patchInline(holder, sprop);
|
||||
else
|
||||
return generateStub(holder, sprop);
|
||||
}
|
||||
|
||||
bool disable(const char *reason)
|
||||
{
|
||||
return PICStubCompiler::disable(reason, stub);
|
||||
@ -1334,6 +1591,36 @@ ic::GetProp(VMFrame &f, uint32 index)
|
||||
f.regs.sp[-1] = v;
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
ic::GetElem(VMFrame &f, uint32 picIndex)
|
||||
{
|
||||
JSScript *script = f.fp->script;
|
||||
PICInfo &pic = script->pics[picIndex];
|
||||
|
||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
||||
if (!obj)
|
||||
THROW();
|
||||
|
||||
Value idval = f.regs.sp[-1];
|
||||
JS_ASSERT(idval.isString());
|
||||
JSString *id = idval.toString();
|
||||
if (pic.shouldGenerate()) {
|
||||
GetElemCompiler cc(f, script, obj, pic, id, stubs::GetElem);
|
||||
if (!cc.update()) {
|
||||
cc.disable("error");
|
||||
THROW();
|
||||
}
|
||||
}
|
||||
|
||||
JSAtom *atom = js_AtomizeString(f.cx, id, 0);
|
||||
if (!atom)
|
||||
THROW();
|
||||
Value v;
|
||||
if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v))
|
||||
THROW();
|
||||
f.regs.sp[-2] = v;
|
||||
}
|
||||
|
||||
static void JS_FASTCALL
|
||||
SetPropDumb(VMFrame &f, uint32 index)
|
||||
{
|
||||
|
@ -69,11 +69,12 @@ struct PICInfo {
|
||||
CALL,
|
||||
SET,
|
||||
NAME,
|
||||
BIND
|
||||
BIND,
|
||||
GETELEM
|
||||
};
|
||||
|
||||
union {
|
||||
// This struct comes out to 61 bits.
|
||||
// This struct comes out to 70 bits.
|
||||
struct {
|
||||
RegisterID typeReg : 5; // reg used for checking type
|
||||
bool hasTypeCheck : 1; // type check and reg are present
|
||||
@ -82,8 +83,11 @@ struct PICInfo {
|
||||
uint16 typeCheckOffset : 9;
|
||||
|
||||
// Remat info for the object reg.
|
||||
uint32 objRemat : 20;
|
||||
bool objNeedsRemat : 1;
|
||||
uint32 objRemat : 20;
|
||||
bool objNeedsRemat : 1;
|
||||
RegisterID idReg : 5; // only used in GETELEM PICs.
|
||||
uint32 idRemat : 20;
|
||||
bool idNeedsRemat : 1;
|
||||
|
||||
// Offset from start of stub to jump target of second shape guard as Nitro
|
||||
// asm data location. This is 0 if there is only one shape guard in the
|
||||
@ -106,8 +110,20 @@ struct PICInfo {
|
||||
RegisterID shapeReg : 5; // also the out type reg
|
||||
RegisterID objReg : 5; // also the out data reg
|
||||
|
||||
// Number of stubs generated.
|
||||
uint32 stubsGenerated : 5;
|
||||
|
||||
// Offset from start of fast path to initial shape guard.
|
||||
int shapeGuard : 8;
|
||||
|
||||
// Return address of slow path call, as an offset from slowPathStart.
|
||||
uint16 callReturn : 9;
|
||||
|
||||
unsigned unused : 24;
|
||||
|
||||
|
||||
inline bool isGet() {
|
||||
return kind == GET || kind == CALL;
|
||||
return kind == GET || kind == CALL || kind == GETELEM;
|
||||
}
|
||||
inline RegisterID typeReg() {
|
||||
JS_ASSERT(isGet());
|
||||
@ -121,10 +137,18 @@ struct PICInfo {
|
||||
JS_ASSERT(isGet());
|
||||
return u.get.objRemat;
|
||||
}
|
||||
inline uint32 idRemat() {
|
||||
JS_ASSERT(isGet());
|
||||
return u.get.idRemat;
|
||||
}
|
||||
inline bool objNeedsRemat() {
|
||||
JS_ASSERT(isGet());
|
||||
return u.get.objNeedsRemat;
|
||||
}
|
||||
inline bool idNeedsRemat() {
|
||||
JS_ASSERT(isGet());
|
||||
return u.get.idNeedsRemat;
|
||||
}
|
||||
inline bool shapeNeedsRemat() {
|
||||
return !shapeRegHasBaseShape;
|
||||
}
|
||||
@ -133,12 +157,6 @@ struct PICInfo {
|
||||
return !hasTypeCheck();
|
||||
}
|
||||
|
||||
// Number of stubs generated.
|
||||
uint32 stubsGenerated : 5;
|
||||
|
||||
// Offset from start of fast path to initial shape guard.
|
||||
int shapeGuard : 8;
|
||||
|
||||
// Index into the script's atom table.
|
||||
JSAtom *atom;
|
||||
|
||||
@ -148,9 +166,6 @@ struct PICInfo {
|
||||
// Address of store back at the end of the inline fast-path.
|
||||
JSC::CodeLocationLabel storeBack;
|
||||
|
||||
// Return address of slow path call, as an offset from slowPathStart.
|
||||
uint16 callReturn : 9;
|
||||
|
||||
// Offset from callReturn to the start of the slow case.
|
||||
JSC::CodeLocationLabel slowPathStart;
|
||||
|
||||
@ -200,6 +215,7 @@ struct PICInfo {
|
||||
|
||||
void PurgePICs(JSContext *cx, JSScript *script);
|
||||
void JS_FASTCALL GetProp(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL GetElem(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL SetProp(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL CallProp(VMFrame &f, uint32 index);
|
||||
void JS_FASTCALL Name(VMFrame &f, uint32 index);
|
||||
|
@ -231,6 +231,14 @@ class Assembler : public BaseAssembler
|
||||
Jump testBoolean(Assembler::Condition cond, Address address) {
|
||||
return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
}
|
||||
|
||||
Jump testString(Assembler::Condition cond, RegisterID reg) {
|
||||
return branch32(cond, reg, ImmTag(JSVAL_TAG_STRING));
|
||||
}
|
||||
|
||||
Jump testString(Assembler::Condition cond, Address address) {
|
||||
return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_STRING));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -1144,35 +1144,13 @@ mjit::Compiler::jsop_setelem()
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getelem()
|
||||
mjit::Compiler::jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
|
||||
MaybeRegisterID &idReg, RegisterID tmpReg)
|
||||
{
|
||||
FrameEntry *obj = frame.peek(-2);
|
||||
FrameEntry *id = frame.peek(-1);
|
||||
|
||||
if ((obj->isTypeKnown() && obj->getKnownType() != JSVAL_TYPE_OBJECT) ||
|
||||
(id->isTypeKnown() && id->getKnownType() != JSVAL_TYPE_INT32) ||
|
||||
(id->isConstant() && id->getValue().toInt32() < 0)) {
|
||||
jsop_getelem_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
/* id.isInt32() */
|
||||
if (!id->isTypeKnown()) {
|
||||
Jump j = frame.testInt32(Assembler::NotEqual, id);
|
||||
stubcc.linkExit(j, Uses(2));
|
||||
}
|
||||
|
||||
/* obj.isNonFunObj() */
|
||||
if (!obj->isTypeKnown()) {
|
||||
Jump j = frame.testObject(Assembler::NotEqual, obj);
|
||||
stubcc.linkExit(j, Uses(2));
|
||||
}
|
||||
|
||||
/* obj.isDenseArray() */
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
/* Note: idReg is only valid if id is not a constant. */
|
||||
Jump guardDense = masm.branchPtr(Assembler::NotEqual,
|
||||
Address(objReg, offsetof(JSObject, clasp)),
|
||||
ImmPtr(&js_ArrayClass));
|
||||
Address(objReg, offsetof(JSObject, clasp)),
|
||||
ImmPtr(&js_ArrayClass));
|
||||
stubcc.linkExit(guardDense, Uses(2));
|
||||
|
||||
/* dslots non-NULL */
|
||||
@ -1192,37 +1170,185 @@ mjit::Compiler::jsop_getelem()
|
||||
Jump notHole = masm.branch32(Assembler::Equal, masm.tagOf(slot), ImmTag(JSVAL_TAG_MAGIC));
|
||||
stubcc.linkExit(notHole, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::GetElem);
|
||||
|
||||
frame.popn(2);
|
||||
frame.freeReg(objReg);
|
||||
frame.push(slot);
|
||||
/* Load slot address into regs. */
|
||||
masm.loadTypeTag(slot, tmpReg);
|
||||
masm.loadData32(slot, objReg);
|
||||
} else {
|
||||
RegisterID idReg = frame.copyDataIntoReg(id);
|
||||
JS_ASSERT(idReg.isSet());
|
||||
Jump inRange = masm.branch32(Assembler::AboveOrEqual,
|
||||
idReg,
|
||||
idReg.getReg(),
|
||||
masm.payloadOf(Address(objReg, -int(sizeof(Value)))));
|
||||
stubcc.linkExit(inRange, Uses(2));
|
||||
|
||||
/* guard not a hole */
|
||||
BaseIndex slot(objReg, idReg, Assembler::JSVAL_SCALE);
|
||||
BaseIndex slot(objReg, idReg.getReg(), Assembler::JSVAL_SCALE);
|
||||
Jump notHole = masm.branch32(Assembler::Equal, masm.tagOf(slot), ImmTag(JSVAL_TAG_MAGIC));
|
||||
stubcc.linkExit(notHole, Uses(2));
|
||||
|
||||
masm.loadTypeTag(slot, tmpReg);
|
||||
masm.loadData32(slot, objReg);
|
||||
}
|
||||
/* Postcondition: type must be in tmpReg, data must be in objReg. */
|
||||
|
||||
/* Note: linkExits will be hooked up to a leave() after this method completes. */
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg)
|
||||
{
|
||||
switch (id->getKnownType()) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
{
|
||||
/* Prologue. */
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
MaybeRegisterID idReg;
|
||||
if (!id->isConstant())
|
||||
idReg.setReg(frame.copyDataIntoReg(id));
|
||||
|
||||
/* Meat. */
|
||||
jsop_getelem_dense(obj, id, objReg, idReg, tmpReg);
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::GetElem);
|
||||
|
||||
/* Epilogue. */
|
||||
if (idReg.isSet())
|
||||
frame.freeReg(idReg.getReg());
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
stubcc.rejoin(Changes(1));
|
||||
return;
|
||||
}
|
||||
#ifdef JS_POLYIC
|
||||
case JSVAL_TYPE_STRING:
|
||||
{
|
||||
/* Prologue. */
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
RegisterID idReg = frame.copyDataIntoReg(id);
|
||||
|
||||
RegisterID reg = frame.allocReg();
|
||||
masm.loadTypeTag(slot, reg);
|
||||
masm.loadData32(slot, idReg);
|
||||
frame.freeReg(objReg);
|
||||
frame.pushRegs(reg, idReg);
|
||||
/* Meat. */
|
||||
jsop_getelem_pic(obj, id, objReg, idReg, tmpReg);
|
||||
|
||||
/* Epilogue. */
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
frame.freeReg(idReg);
|
||||
stubcc.rejoin(Changes(1));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
JS_NOT_REACHED("Invalid known id type.");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
void
|
||||
mjit::Compiler::jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg)
|
||||
{
|
||||
JS_ASSERT(!id->isTypeKnown());
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
MaybeRegisterID idReg(frame.copyDataIntoReg(id));
|
||||
|
||||
RegisterID typeReg = frame.tempRegForType(id, tmpReg);
|
||||
Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
|
||||
|
||||
JaegerSpew(JSpew_Insns, " ==== BEGIN DENSE ARRAY CODE ==== \n");
|
||||
|
||||
jsop_getelem_dense(obj, id, objReg, idReg, tmpReg);
|
||||
Jump performedDense = masm.jump();
|
||||
|
||||
JaegerSpew(JSpew_Insns, " ==== END DENSE ARRAY CODE ==== \n");
|
||||
|
||||
intGuard.linkTo(masm.label(), &masm);
|
||||
Jump stringGuard = masm.testString(Assembler::NotEqual, typeReg);
|
||||
stubcc.linkExit(stringGuard, Uses(2)); /* Neither int nor string at this point. */
|
||||
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::GetElem);
|
||||
Jump toFinalMerge = stubcc.masm.jump();
|
||||
|
||||
jsop_getelem_pic(obj, id, objReg, idReg.getReg(), tmpReg);
|
||||
performedDense.linkTo(masm.label(), &masm);
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
frame.freeReg(idReg.getReg());
|
||||
toFinalMerge.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getelem_nopic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg)
|
||||
{
|
||||
/* Only handle the int32 case. */
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
MaybeRegisterID idReg(frame.copyDataIntoReg(id));
|
||||
RegisterID typeReg = frame.tempRegForType(id, tmpReg);
|
||||
Jump intGuard = masm.testInt32(Assembler::NotEqual, typeReg);
|
||||
stubcc.linkExit(intGuard, Uses(2));
|
||||
|
||||
/* Meat. */
|
||||
jsop_getelem_dense(obj, id, objReg, idReg, tmpReg);
|
||||
stubcc.leave();
|
||||
stubcc.call(stubs::GetElem);
|
||||
|
||||
/* Epilogue. */
|
||||
frame.freeReg(idReg.getReg());
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getelem()
|
||||
{
|
||||
FrameEntry *obj = frame.peek(-2);
|
||||
FrameEntry *id = frame.peek(-1);
|
||||
|
||||
if (obj->isTypeKnown() && obj->getKnownType() != JSVAL_TYPE_OBJECT) {
|
||||
jsop_getelem_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
stubcc.rejoin(Changes(1));
|
||||
if (id->isTypeKnown() &&
|
||||
!(id->getKnownType() == JSVAL_TYPE_INT32
|
||||
#ifdef JS_POLYIC
|
||||
|| id->getKnownType() == JSVAL_TYPE_STRING
|
||||
#endif
|
||||
)) {
|
||||
jsop_getelem_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_INT32 && id->isConstant() &&
|
||||
id->getValue().toInt32() < 0) {
|
||||
jsop_getelem_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_STRING && id->isConstant()) {
|
||||
/* Never happens, or I'd optimize it. */
|
||||
jsop_getelem_slow();
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterID tmpReg;
|
||||
if (obj->isTypeKnown()) {
|
||||
tmpReg = frame.allocReg();
|
||||
} else {
|
||||
tmpReg = frame.copyTypeIntoReg(obj);
|
||||
Jump objGuard = masm.testObject(Assembler::NotEqual, tmpReg);
|
||||
stubcc.linkExit(objGuard, Uses(2));
|
||||
}
|
||||
|
||||
if (id->isTypeKnown())
|
||||
return jsop_getelem_known_type(obj, id, tmpReg);
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
return jsop_getelem_with_pic(obj, id, tmpReg);
|
||||
#else
|
||||
return jsop_getelem_nopic(obj, id, tmpReg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
9
js/src/trace-test/tests/jaeger/getelem-sanity-1.js
Normal file
9
js/src/trace-test/tests/jaeger/getelem-sanity-1.js
Normal file
@ -0,0 +1,9 @@
|
||||
var obj = {attr: 'value'};
|
||||
|
||||
(function() {
|
||||
var name = 'attr';
|
||||
for (var i = 0; i < 10; ++i)
|
||||
assertEq(obj[name], 'value');
|
||||
})();
|
||||
|
||||
/* Look up a string id. */
|
22
js/src/trace-test/tests/jaeger/getelem-sanity-2.js
Normal file
22
js/src/trace-test/tests/jaeger/getelem-sanity-2.js
Normal file
@ -0,0 +1,22 @@
|
||||
var obj = {firstAttr: 'value', secondAttr: 'another value'};
|
||||
|
||||
(function() {
|
||||
for (var i = 0; i < 12; ++i) {
|
||||
var name;
|
||||
if (i < 4)
|
||||
name = 'firstAttr';
|
||||
else if (i < 8)
|
||||
name = 'secondAttr';
|
||||
else
|
||||
name = 'firstAttr';
|
||||
|
||||
var result = obj[name];
|
||||
|
||||
switch (name) {
|
||||
case 'firstAttr': assertEq(result, 'value'); break;
|
||||
case 'secondAttr': assertEq(result, 'another value'); break;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
/* Toggle lookup between two ids. */
|
22
js/src/trace-test/tests/jaeger/getelem-sanity-3.js
Normal file
22
js/src/trace-test/tests/jaeger/getelem-sanity-3.js
Normal file
@ -0,0 +1,22 @@
|
||||
var obj = {firstAttr: 'value', secondAttr: 'another value', thirdAttr: 'the last value'};
|
||||
|
||||
(function() {
|
||||
for (var i = 0; i < 64; ++i) {
|
||||
var name;
|
||||
switch (~~(i / 4) % 3) {
|
||||
case 0: name = 'firstAttr'; break;
|
||||
case 1: name = 'secondAttr'; break;
|
||||
case 2: name = 'thirdAttr'; break;
|
||||
}
|
||||
|
||||
var result = obj[name];
|
||||
|
||||
switch (name) {
|
||||
case 'firstAttr': assertEq(result, 'value'); break;
|
||||
case 'secondAttr': assertEq(result, 'another value'); break;
|
||||
case 'thirdAttr': assertEq(result, 'the last value'); break;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
/* Rotate lookup between three ids. */
|
51
js/src/trace-test/tests/jaeger/getelem-sanity-4.js
Normal file
51
js/src/trace-test/tests/jaeger/getelem-sanity-4.js
Normal file
@ -0,0 +1,51 @@
|
||||
var obj = {
|
||||
attr0: 'val0',
|
||||
attr1: 'val1',
|
||||
attr2: 'val2',
|
||||
attr3: 'val3',
|
||||
attr4: 'val4',
|
||||
attr5: 'val5',
|
||||
attr6: 'val6',
|
||||
attr7: 'val7',
|
||||
attr8: 'val8',
|
||||
attr9: 'val9',
|
||||
attr10: 'val10',
|
||||
attr11: 'val11',
|
||||
attr12: 'val12',
|
||||
attr13: 'val13',
|
||||
attr14: 'val14',
|
||||
attr15: 'val15',
|
||||
attr16: 'val16',
|
||||
attr17: 'val17',
|
||||
}
|
||||
|
||||
var baseName = 'attr';
|
||||
|
||||
(function() {
|
||||
for (var i = 0; i < 128; ++i) {
|
||||
var name = baseName + (i % 18);
|
||||
var result = obj[name];
|
||||
switch (i) {
|
||||
case 0: assertEq('val0', result); break;
|
||||
case 1: assertEq('val1', result); break;
|
||||
case 2: assertEq('val2', result); break;
|
||||
case 3: assertEq('val3', result); break;
|
||||
case 4: assertEq('val4', result); break;
|
||||
case 5: assertEq('val5', result); break;
|
||||
case 6: assertEq('val6', result); break;
|
||||
case 7: assertEq('val7', result); break;
|
||||
case 8: assertEq('val8', result); break;
|
||||
case 9: assertEq('val9', result); break;
|
||||
case 10: assertEq('val10', result); break;
|
||||
case 11: assertEq('val11', result); break;
|
||||
case 12: assertEq('val12', result); break;
|
||||
case 13: assertEq('val13', result); break;
|
||||
case 14: assertEq('val14', result); break;
|
||||
case 15: assertEq('val15', result); break;
|
||||
case 16: assertEq('val16', result); break;
|
||||
case 17: assertEq('val17', result); break;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
/* Megamorphic index atom. */
|
4
js/src/trace-test/tests/jaeger/getelem-sanity-5.js
Normal file
4
js/src/trace-test/tests/jaeger/getelem-sanity-5.js
Normal file
@ -0,0 +1,4 @@
|
||||
var x = { 0: 5, 1: 5 };
|
||||
assertEq(x[0] + x[1], 10);
|
||||
|
||||
/* int32 getelem on object. */
|
4
js/src/trace-test/tests/jaeger/getelem-sanity-6.js
Normal file
4
js/src/trace-test/tests/jaeger/getelem-sanity-6.js
Normal file
@ -0,0 +1,4 @@
|
||||
var x = {1: 2, 3: 4};
|
||||
assertEq(x[1], 2);
|
||||
|
||||
/* getelem with non-dense array and known type int32. */
|
10
js/src/trace-test/tests/jaeger/getelem-sanity-7.js
Normal file
10
js/src/trace-test/tests/jaeger/getelem-sanity-7.js
Normal file
@ -0,0 +1,10 @@
|
||||
var obj = {count: 24};
|
||||
var key = 'count';
|
||||
|
||||
for (var i = 0; i < 1024; ++i) {
|
||||
var result = obj[key];
|
||||
if (i === 2)
|
||||
obj.newAttr = 42;
|
||||
}
|
||||
|
||||
/* Perform getelem across shape change. */
|
7
js/src/trace-test/tests/jaeger/getelem-sanity-int-1.js
Normal file
7
js/src/trace-test/tests/jaeger/getelem-sanity-int-1.js
Normal file
@ -0,0 +1,7 @@
|
||||
var arr = ['this', 'works', 'for', 'me'];
|
||||
assertEq('this', arr[0]);
|
||||
assertEq('works', arr[1]);
|
||||
assertEq('for', arr[2]);
|
||||
assertEq('me', arr[3]);
|
||||
|
||||
/* Multiple int32 getelem for dense array. */
|
12
js/src/trace-test/tests/jaeger/getelem-sanity-int-2.js
Normal file
12
js/src/trace-test/tests/jaeger/getelem-sanity-int-2.js
Normal file
@ -0,0 +1,12 @@
|
||||
var arr = ['this', 'works', 'for', 'me'];
|
||||
for (var i = 0; i < arr.length; ++i) {
|
||||
var result = arr[i];
|
||||
switch (i) {
|
||||
case 0: assertEq('this', result); break;
|
||||
case 1: assertEq('works', result); break;
|
||||
case 2: assertEq('for', result); break;
|
||||
case 3: assertEq('me', result); break;
|
||||
}
|
||||
}
|
||||
|
||||
/* int32 getelem for dense array. */
|
19
js/src/trace-test/tests/jaeger/getelem-sanity-int-3.js
Normal file
19
js/src/trace-test/tests/jaeger/getelem-sanity-int-3.js
Normal file
@ -0,0 +1,19 @@
|
||||
var a = [1, 2];
|
||||
a[3.1415926535] = 'value';
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var attr;
|
||||
switch (i) {
|
||||
case 0: attr = 0; break;
|
||||
case 1: attr = 1; break;
|
||||
case 2: attr = 3.1415926535; break;
|
||||
}
|
||||
var result = a[attr];
|
||||
switch (i) {
|
||||
case 0: assertEq(result, 1); break;
|
||||
case 1: assertEq(result, 2); break;
|
||||
case 2: assertEq(result, 'value'); break;
|
||||
}
|
||||
}
|
||||
|
||||
/* int32 and string getelem for non-dense array. */
|
@ -139,7 +139,7 @@ def run_test(test, lib_dir):
|
||||
cmd = valgrind_prefix + cmd
|
||||
|
||||
if OPTIONS.show_cmd:
|
||||
print(cmd)
|
||||
print(subprocess.list2cmdline(cmd))
|
||||
# close_fds is not supported on Windows and will cause a ValueError.
|
||||
close_fds = sys.platform != 'win32'
|
||||
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds, env=env)
|
||||
|
Loading…
Reference in New Issue
Block a user