зеркало из https://github.com/mozilla/pjs.git
Refactor and improve GETELEM IC (bug 602641, r=dmandelin).
This commit is contained in:
Родитель
9a59b7e436
Коммит
7dca1f9035
|
@ -50,6 +50,8 @@
|
|||
#include "methodjit/MethodJIT.h"
|
||||
#include "methodjit/MachineRegs.h"
|
||||
#include "CodeGenIncludes.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
@ -209,9 +211,9 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
|||
load32(Address(obj, offsetof(JSObject, objShape)), shape);
|
||||
}
|
||||
|
||||
Jump guardShape(RegisterID obj, uint32 shape) {
|
||||
return branch32(NotEqual, Address(obj, offsetof(JSObject, objShape)),
|
||||
Imm32(shape));
|
||||
Jump guardShape(RegisterID objReg, JSObject *obj) {
|
||||
return branch32(NotEqual, Address(objReg, offsetof(JSObject, objShape)),
|
||||
Imm32(obj->shape()));
|
||||
}
|
||||
|
||||
Jump testFunction(Condition cond, RegisterID fun) {
|
||||
|
@ -427,6 +429,24 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
|||
else
|
||||
move(remat.reg(), reg);
|
||||
}
|
||||
|
||||
void loadDynamicSlot(RegisterID objReg, uint32 slot,
|
||||
RegisterID typeReg, RegisterID dataReg) {
|
||||
loadPtr(Address(objReg, offsetof(JSObject, slots)), dataReg);
|
||||
loadValueAsComponents(Address(dataReg, slot * sizeof(Value)), typeReg, dataReg);
|
||||
}
|
||||
|
||||
void loadObjProp(JSObject *obj, RegisterID objReg,
|
||||
const js::Shape *shape,
|
||||
RegisterID typeReg, RegisterID dataReg)
|
||||
{
|
||||
if (shape->isMethod())
|
||||
loadValueAsComponents(ObjectValue(shape->methodObject()), typeReg, dataReg);
|
||||
else if (obj->hasSlotsArray())
|
||||
loadDynamicSlot(objReg, shape->slot, typeReg, dataReg);
|
||||
else
|
||||
loadInlineSlot(objReg, shape->slot, typeReg, dataReg);
|
||||
}
|
||||
};
|
||||
|
||||
/* Return f<true> if the script is strict mode code, f<false> otherwise. */
|
||||
|
|
|
@ -48,19 +48,7 @@
|
|||
namespace js {
|
||||
namespace mjit {
|
||||
|
||||
class BaseCompiler
|
||||
{
|
||||
protected:
|
||||
JSContext *cx;
|
||||
|
||||
public:
|
||||
BaseCompiler() : cx(NULL)
|
||||
{ }
|
||||
|
||||
BaseCompiler(JSContext *cx) : cx(cx)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
struct MacroAssemblerTypedefs {
|
||||
typedef JSC::MacroAssembler::Label Label;
|
||||
typedef JSC::MacroAssembler::Imm32 Imm32;
|
||||
typedef JSC::MacroAssembler::ImmPtr ImmPtr;
|
||||
|
@ -77,11 +65,25 @@ class BaseCompiler
|
|||
typedef JSC::MacroAssembler::DataLabel32 DataLabel32;
|
||||
typedef JSC::FunctionPtr FunctionPtr;
|
||||
typedef JSC::RepatchBuffer RepatchBuffer;
|
||||
typedef JSC::CodeBlock CodeBlock;
|
||||
typedef JSC::CodeLocationLabel CodeLocationLabel;
|
||||
typedef JSC::JITCode JITCode;
|
||||
typedef JSC::CodeLocationCall CodeLocationCall;
|
||||
typedef JSC::ReturnAddressPtr ReturnAddressPtr;
|
||||
typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr;
|
||||
};
|
||||
|
||||
class BaseCompiler : public MacroAssemblerTypedefs
|
||||
{
|
||||
protected:
|
||||
JSContext *cx;
|
||||
|
||||
public:
|
||||
BaseCompiler() : cx(NULL)
|
||||
{ }
|
||||
|
||||
BaseCompiler(JSContext *cx) : cx(cx)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
||||
JSC::ExecutablePool *
|
||||
getExecPool(size_t size) {
|
||||
|
@ -127,6 +129,12 @@ class LinkerHelper : public JSC::LinkBuffer
|
|||
}
|
||||
return ep;
|
||||
}
|
||||
|
||||
void maybeLink(MaybeJump jump, JSC::CodeLocationLabel label) {
|
||||
if (!jump.isSet())
|
||||
return;
|
||||
link(jump.get(), label);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -103,6 +103,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp)
|
|||
#endif
|
||||
#if defined JS_POLYIC
|
||||
pics(ContextAllocPolicy(cx)),
|
||||
getElemICs(ContextAllocPolicy(cx)),
|
||||
#endif
|
||||
callPatches(ContextAllocPolicy(cx)),
|
||||
callSites(ContextAllocPolicy(cx)),
|
||||
|
@ -390,6 +391,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
#endif
|
||||
#if defined JS_POLYIC
|
||||
sizeof(ic::PICInfo) * pics.length() +
|
||||
sizeof(ic::GetElementIC) * getElemICs.length() +
|
||||
#endif
|
||||
sizeof(CallSite) * callSites.length();
|
||||
|
||||
|
@ -586,6 +588,38 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
}
|
||||
|
||||
#if defined JS_POLYIC
|
||||
jit->nGetElems = getElemICs.length();
|
||||
if (getElemICs.length()) {
|
||||
jit->getElems = (ic::GetElementIC *)cursor;
|
||||
cursor += sizeof(ic::GetElementIC) * getElemICs.length();
|
||||
} else {
|
||||
jit->getElems = NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < getElemICs.length(); i++) {
|
||||
ic::GetElementIC &to = jit->getElems[i];
|
||||
GetElementICInfo &from = getElemICs[i];
|
||||
to.init();
|
||||
from.copyTo(to, fullCode, stubCode);
|
||||
|
||||
to.typeReg = from.typeReg;
|
||||
to.objReg = from.objReg;
|
||||
to.idRemat = from.id;
|
||||
|
||||
if (from.typeGuard.isSet()) {
|
||||
int inlineTypeGuard = fullCode.locationOf(from.typeGuard.get()) -
|
||||
fullCode.locationOf(from.fastPathStart);
|
||||
to.inlineTypeGuard = inlineTypeGuard;
|
||||
JS_ASSERT(to.inlineTypeGuard == inlineTypeGuard);
|
||||
}
|
||||
int inlineClaspGuard = fullCode.locationOf(from.claspGuard) -
|
||||
fullCode.locationOf(from.fastPathStart);
|
||||
to.inlineClaspGuard = inlineClaspGuard;
|
||||
JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard);
|
||||
|
||||
stubCode.patch(from.paramAddr, &to);
|
||||
}
|
||||
|
||||
jit->nPICs = pics.length();
|
||||
if (pics.length()) {
|
||||
jit->pics = (ic::PICInfo *)cursor;
|
||||
|
@ -596,11 +630,9 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
|
||||
if (ic::PICInfo *scriptPICs = jit->pics) {
|
||||
for (size_t i = 0; i < pics.length(); i++) {
|
||||
scriptPICs[i].init();
|
||||
pics[i].copyTo(scriptPICs[i], fullCode, stubCode);
|
||||
pics[i].copySimpleMembersTo(scriptPICs[i]);
|
||||
scriptPICs[i].fastPathStart = fullCode.locationOf(pics[i].fastPathStart);
|
||||
scriptPICs[i].fastPathRejoin = fullCode.locationOf(pics[i].fastPathRejoin);
|
||||
scriptPICs[i].slowPathStart = stubCode.locationOf(pics[i].slowPathStart);
|
||||
scriptPICs[i].slowPathCall = stubCode.locationOf(pics[i].slowPathCall);
|
||||
scriptPICs[i].shapeGuard = masm.distanceOf(pics[i].shapeGuard) -
|
||||
masm.distanceOf(pics[i].fastPathStart);
|
||||
JS_ASSERT(scriptPICs[i].shapeGuard == masm.distanceOf(pics[i].shapeGuard) -
|
||||
|
@ -623,8 +655,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
scriptPICs[i].u.get.typeCheckOffset = distance;
|
||||
}
|
||||
}
|
||||
new (&scriptPICs[i].execPools) ic::PICInfo::ExecPoolVector(SystemAllocPolicy());
|
||||
scriptPICs[i].reset();
|
||||
stubCode.patch(pics[i].paramAddr, &scriptPICs[i]);
|
||||
}
|
||||
}
|
||||
|
@ -2593,9 +2623,9 @@ mjit::Compiler::passMICAddress(MICGenInfo &mic)
|
|||
|
||||
#if defined JS_POLYIC
|
||||
void
|
||||
mjit::Compiler::passPICAddress(PICGenInfo &pic)
|
||||
mjit::Compiler::passICAddress(BaseICInfo *ic)
|
||||
{
|
||||
pic.paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||
ic->paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2623,7 +2653,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
|||
shapeReg = frame.allocReg();
|
||||
}
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::GET, usePropCache);
|
||||
PICGenInfo pic(ic::PICInfo::GET, JSOp(*PC), usePropCache);
|
||||
|
||||
/* Guard that the type is an object. */
|
||||
Jump typeCheck;
|
||||
|
@ -2654,7 +2684,6 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
|||
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.atom = atom;
|
||||
pic.objRemat = frame.dataRematInfo(top);
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
|
@ -2669,7 +2698,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
|||
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
|
||||
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::GetProp);
|
||||
|
||||
/* Load dslots. */
|
||||
|
@ -2727,113 +2756,6 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
bool
|
||||
mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
|
||||
RegisterID idReg, RegisterID shapeReg)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::GETELEM, true);
|
||||
|
||||
pic.objRemat = frame.dataRematInfo(obj);
|
||||
pic.idRemat = frame.dataRematInfo(id);
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.hasTypeCheck = false;
|
||||
|
||||
pic.fastPathStart = masm.label();
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
pic.shapeGuard = masm.label();
|
||||
|
||||
DataLabel32 inlineShapeOffsetLabel;
|
||||
Jump jmpShapeGuard = masm.branch32WithPatch(Assembler::NotEqual, shapeReg,
|
||||
Imm32(int32(JSObjectMap::INVALID_SHAPE)),
|
||||
inlineShapeOffsetLabel);
|
||||
DBGLABEL(dbgInlineShapeJump);
|
||||
|
||||
/* Guard on id identity. */
|
||||
#if defined JS_NUNBOX32
|
||||
static const void *BOGUS_ATOM = (void *)0xdeadbeef;
|
||||
#elif defined JS_PUNBOX64
|
||||
static const void *BOGUS_ATOM = (void *)0xfeedfacedeadbeef;
|
||||
#endif
|
||||
|
||||
DataLabelPtr inlineAtomOffsetLabel;
|
||||
Jump idGuard = masm.branchPtrWithPatch(Assembler::NotEqual, idReg,
|
||||
inlineAtomOffsetLabel, ImmPtr(BOGUS_ATOM));
|
||||
DBGLABEL(dbgInlineAtomJump);
|
||||
|
||||
/*
|
||||
* The state between these two exits is identical, so this safe. The
|
||||
* GETELEM PIC repatches both jumps to the slowPathStart on reset.
|
||||
*/
|
||||
stubcc.linkExit(idGuard, Uses(2));
|
||||
pic.slowPathStart = stubcc.linkExit(jmpShapeGuard, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
pic.slowPathCall = stubcc.call(ic::GetElem);
|
||||
|
||||
/* Load dslots. */
|
||||
#if defined JS_NUNBOX32
|
||||
DBGLABEL(dbgDslotsLoad);
|
||||
#elif defined JS_PUNBOX64
|
||||
Label dslotsLoadLabel = masm.label();
|
||||
#endif
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
#if defined JS_NUNBOX32
|
||||
masm.loadTypeTag(slot, shapeReg);
|
||||
DBGLABEL(dbgTypeLoad);
|
||||
masm.loadPayload(slot, objReg);
|
||||
DBGLABEL(dbgDataLoad);
|
||||
#elif defined JS_PUNBOX64
|
||||
Label inlineValueOffsetLabel =
|
||||
masm.loadValueAsComponents(slot, shapeReg, objReg);
|
||||
#endif
|
||||
pic.fastPathRejoin = masm.label();
|
||||
|
||||
pic.objReg = objReg;
|
||||
pic.idReg = idReg;
|
||||
|
||||
RETURN_IF_OOM(false);
|
||||
#if defined JS_NUNBOX32
|
||||
JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgDslotsLoad) == GETPROP_DSLOTS_LOAD);
|
||||
JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgTypeLoad) == GETPROP_TYPE_LOAD);
|
||||
JS_ASSERT(masm.differenceBetween(pic.fastPathRejoin, dbgDataLoad) == GETPROP_DATA_LOAD);
|
||||
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, inlineAtomOffsetLabel) == GETELEM_INLINE_ATOM_OFFSET);
|
||||
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineAtomJump) == GETELEM_INLINE_ATOM_JUMP);
|
||||
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, inlineShapeOffsetLabel) == GETELEM_INLINE_SHAPE_OFFSET);
|
||||
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETELEM_INLINE_SHAPE_JUMP);
|
||||
#elif defined JS_PUNBOX64
|
||||
pic.labels.getprop.dslotsLoadOffset = masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel);
|
||||
JS_ASSERT(pic.labels.getprop.dslotsLoadOffset == masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
|
||||
|
||||
pic.labels.getelem.inlineShapeOffset = masm.differenceBetween(pic.shapeGuard, inlineShapeOffsetLabel);
|
||||
JS_ASSERT(pic.labels.getelem.inlineShapeOffset == masm.differenceBetween(pic.shapeGuard, inlineShapeOffsetLabel));
|
||||
|
||||
pic.labels.getelem.inlineAtomOffset = masm.differenceBetween(pic.shapeGuard, inlineAtomOffsetLabel);
|
||||
JS_ASSERT(pic.labels.getelem.inlineAtomOffset == masm.differenceBetween(pic.shapeGuard, inlineAtomOffsetLabel));
|
||||
|
||||
pic.labels.getelem.inlineValueOffset = masm.differenceBetween(pic.fastPathRejoin, inlineValueOffsetLabel);
|
||||
JS_ASSERT(pic.labels.getelem.inlineValueOffset == masm.differenceBetween(pic.fastPathRejoin, inlineValueOffsetLabel));
|
||||
|
||||
JS_ASSERT(masm.differenceBetween(inlineShapeOffsetLabel, dbgInlineShapeJump) == GETELEM_INLINE_SHAPE_JUMP);
|
||||
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineAtomJump) ==
|
||||
pic.labels.getelem.inlineAtomOffset + GETELEM_INLINE_ATOM_JUMP);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(pic.idReg != pic.objReg);
|
||||
JS_ASSERT(pic.idReg != pic.shapeReg);
|
||||
JS_ASSERT(pic.objReg != pic.shapeReg);
|
||||
|
||||
pics.append(pic);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
||||
{
|
||||
|
@ -2847,7 +2769,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
|||
RegisterID objReg = frame.copyDataIntoReg(top);
|
||||
RegisterID shapeReg = frame.allocReg();
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::CALL, true);
|
||||
PICGenInfo pic(ic::PICInfo::CALL, JSOp(*PC), true);
|
||||
|
||||
pic.pc = PC;
|
||||
|
||||
|
@ -2871,7 +2793,6 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
|||
pic.objReg = objReg;
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.atom = atom;
|
||||
pic.objRemat = frame.dataRematInfo(top);
|
||||
|
||||
/*
|
||||
* Store the type and object back. Don't bother keeping them in registers,
|
||||
|
@ -2901,7 +2822,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
|||
|
||||
/* Slow path. */
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::CallProp);
|
||||
|
||||
/* Adjust the frame. None of this will generate code. */
|
||||
|
@ -3019,7 +2940,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
|||
{
|
||||
FrameEntry *top = frame.peek(-1);
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::CALL, true);
|
||||
PICGenInfo pic(ic::PICInfo::CALL, JSOp(*PC), true);
|
||||
|
||||
JS_ASSERT(top->isTypeKnown());
|
||||
JS_ASSERT(top->getKnownType() == JSVAL_TYPE_OBJECT);
|
||||
|
@ -3034,7 +2955,6 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
|||
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.atom = atom;
|
||||
pic.objRemat = frame.dataRematInfo(top);
|
||||
|
||||
/* Guard on shape. */
|
||||
masm.loadShape(objReg, shapeReg);
|
||||
|
@ -3049,7 +2969,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
|||
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
|
||||
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::CallProp);
|
||||
|
||||
/* Load dslots. */
|
||||
|
@ -3151,7 +3071,10 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
|||
|
||||
JSOp op = JSOp(*PC);
|
||||
|
||||
PICGenInfo pic(op == JSOP_SETMETHOD ? ic::PICInfo::SETMETHOD : ic::PICInfo::SET, usePropCache);
|
||||
ic::PICInfo::Kind kind = (op == JSOP_SETMETHOD)
|
||||
? ic::PICInfo::SETMETHOD
|
||||
: ic::PICInfo::SET;
|
||||
PICGenInfo pic(kind, op, usePropCache);
|
||||
pic.atom = atom;
|
||||
|
||||
/* Guard that the type is an object. */
|
||||
|
@ -3191,7 +3114,6 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
|||
|
||||
RegisterID shapeReg = frame.allocReg();
|
||||
pic.shapeReg = shapeReg;
|
||||
pic.objRemat = frame.dataRematInfo(lhs);
|
||||
|
||||
frame.unpinEntry(vr);
|
||||
|
||||
|
@ -3209,7 +3131,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
|||
pic.slowPathStart = stubcc.linkExit(j, Uses(2));
|
||||
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::SetProp);
|
||||
}
|
||||
|
||||
|
@ -3276,7 +3198,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
|
|||
void
|
||||
mjit::Compiler::jsop_name(JSAtom *atom)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::NAME, true);
|
||||
PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC), true);
|
||||
|
||||
pic.shapeReg = frame.allocReg();
|
||||
pic.objReg = frame.allocReg();
|
||||
|
@ -3291,7 +3213,7 @@ mjit::Compiler::jsop_name(JSAtom *atom)
|
|||
{
|
||||
pic.slowPathStart = stubcc.linkExit(j, Uses(0));
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::Name);
|
||||
}
|
||||
|
||||
|
@ -3308,7 +3230,7 @@ mjit::Compiler::jsop_name(JSAtom *atom)
|
|||
bool
|
||||
mjit::Compiler::jsop_xname(JSAtom *atom)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::XNAME, true);
|
||||
PICGenInfo pic(ic::PICInfo::XNAME, JSOp(*PC), true);
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
|
||||
|
@ -3333,7 +3255,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
|||
{
|
||||
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::XName);
|
||||
}
|
||||
|
||||
|
@ -3352,7 +3274,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
|
|||
void
|
||||
mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
|
||||
{
|
||||
PICGenInfo pic(ic::PICInfo::BIND, usePropCache);
|
||||
PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC), usePropCache);
|
||||
|
||||
// This code does not check the frame flags to see if scopeChain has been
|
||||
// set. Rather, it relies on the up-front analysis statically determining
|
||||
|
@ -3382,7 +3304,7 @@ mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
|
|||
{
|
||||
pic.slowPathStart = stubcc.linkExit(j, Uses(0));
|
||||
stubcc.leave();
|
||||
passPICAddress(pic);
|
||||
passICAddress(&pic);
|
||||
pic.slowPathCall = stubcc.call(ic::BindName);
|
||||
}
|
||||
|
||||
|
|
|
@ -160,18 +160,39 @@ class Compiler : public BaseCompiler
|
|||
bool hasSlowNcode;
|
||||
};
|
||||
|
||||
#if defined JS_POLYIC
|
||||
struct BaseICInfo {
|
||||
BaseICInfo(JSOp op) : op(op)
|
||||
{ }
|
||||
Label fastPathStart;
|
||||
Label fastPathRejoin;
|
||||
Label slowPathStart;
|
||||
Call slowPathCall;
|
||||
DataLabelPtr paramAddr;
|
||||
JSOp op;
|
||||
|
||||
void copyTo(ic::BaseIC &to, JSC::LinkBuffer &full, JSC::LinkBuffer &stub) {
|
||||
to.fastPathStart = full.locationOf(fastPathStart);
|
||||
to.fastPathRejoin = full.locationOf(fastPathRejoin);
|
||||
to.slowPathStart = stub.locationOf(slowPathStart);
|
||||
to.slowPathCall = stub.locationOf(slowPathCall);
|
||||
to.op = op;
|
||||
JS_ASSERT(to.op == op);
|
||||
}
|
||||
};
|
||||
|
||||
struct GetElementICInfo : public BaseICInfo {
|
||||
GetElementICInfo(JSOp op) : BaseICInfo(op)
|
||||
{ }
|
||||
RegisterID typeReg;
|
||||
RegisterID objReg;
|
||||
ValueRemat id;
|
||||
MaybeJump typeGuard;
|
||||
Jump claspGuard;
|
||||
};
|
||||
|
||||
struct PICGenInfo : public BaseICInfo {
|
||||
PICGenInfo(ic::PICInfo::Kind kind, bool usePropCache)
|
||||
: kind(kind), usePropCache(usePropCache)
|
||||
PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
|
||||
: BaseICInfo(op), kind(kind), usePropCache(usePropCache)
|
||||
{ }
|
||||
ic::PICInfo::Kind kind;
|
||||
Label typeCheck;
|
||||
|
@ -183,8 +204,6 @@ class Compiler : public BaseCompiler
|
|||
Label shapeGuard;
|
||||
jsbytecode *pc;
|
||||
JSAtom *atom;
|
||||
StateRemat objRemat;
|
||||
StateRemat idRemat;
|
||||
bool hasTypeCheck;
|
||||
ValueRemat vr;
|
||||
# if defined JS_CPU_X64
|
||||
|
@ -200,15 +219,12 @@ class Compiler : public BaseCompiler
|
|||
if (ic.isSet()) {
|
||||
ic.u.vr = vr;
|
||||
} else if (ic.isGet()) {
|
||||
ic.u.get.idReg = idReg;
|
||||
ic.u.get.typeReg = typeReg;
|
||||
ic.u.get.hasTypeCheck = hasTypeCheck;
|
||||
ic.setObjRemat(objRemat);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
struct Defs {
|
||||
Defs(uint32 ndefs)
|
||||
|
@ -250,6 +266,7 @@ class Compiler : public BaseCompiler
|
|||
#endif
|
||||
#if defined JS_POLYIC
|
||||
js::Vector<PICGenInfo, 16> pics;
|
||||
js::Vector<GetElementICInfo> getElemICs;
|
||||
#endif
|
||||
js::Vector<CallPatchInfo, 64> callPatches;
|
||||
js::Vector<InternalCallSite, 64> callSites;
|
||||
|
@ -298,7 +315,7 @@ class Compiler : public BaseCompiler
|
|||
void iterEnd();
|
||||
MaybeJump loadDouble(FrameEntry *fe, FPRegisterID fpReg);
|
||||
#ifdef JS_POLYIC
|
||||
void passPICAddress(PICGenInfo &pic);
|
||||
void passICAddress(BaseICInfo *ic);
|
||||
#endif
|
||||
#ifdef JS_MONOIC
|
||||
void passMICAddress(MICGenInfo &mic);
|
||||
|
@ -400,13 +417,6 @@ class Compiler : public BaseCompiler
|
|||
void jsop_localinc(JSOp op, uint32 slot, bool popped);
|
||||
void jsop_setelem();
|
||||
bool jsop_getelem();
|
||||
bool jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg);
|
||||
bool jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg);
|
||||
void jsop_getelem_nopic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg);
|
||||
bool 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_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
|
||||
|
|
|
@ -1360,135 +1360,6 @@ mjit::Compiler::jsop_setelem()
|
|||
stubcc.rejoin(Changes(0));
|
||||
}
|
||||
|
||||
void
|
||||
mjit::Compiler::jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
|
||||
MaybeRegisterID &idReg, RegisterID tmpReg)
|
||||
{
|
||||
/* Note: idReg is only valid if id is not a constant. */
|
||||
Jump guardDense = masm.testObjClass(Assembler::NotEqual, objReg, &js_ArrayClass);
|
||||
stubcc.linkExit(guardDense, Uses(2));
|
||||
|
||||
Int32Key key = idReg.isSet()
|
||||
? Int32Key::FromRegister(idReg.reg())
|
||||
: Int32Key::FromConstant(id->getValue().toInt32());
|
||||
|
||||
Assembler::FastArrayLoadFails fails =
|
||||
masm.fastArrayLoad(objReg, key, tmpReg, objReg);
|
||||
|
||||
stubcc.linkExit(fails.rangeCheck, Uses(2));
|
||||
stubcc.linkExit(fails.holeCheck, Uses(2));
|
||||
}
|
||||
|
||||
bool
|
||||
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.reg());
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
stubcc.rejoin(Changes(1));
|
||||
break;
|
||||
}
|
||||
#ifdef JS_POLYIC
|
||||
case JSVAL_TYPE_STRING:
|
||||
{
|
||||
/* Prologue. */
|
||||
RegisterID objReg = frame.copyDataIntoReg(obj);
|
||||
RegisterID idReg = frame.copyDataIntoReg(id);
|
||||
|
||||
/* Meat. */
|
||||
if (!jsop_getelem_pic(obj, id, objReg, idReg, tmpReg))
|
||||
return false;
|
||||
|
||||
/* Epilogue. */
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
frame.freeReg(idReg);
|
||||
stubcc.rejoin(Changes(1));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
JS_NOT_REACHED("Invalid known id type.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
bool
|
||||
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();
|
||||
|
||||
if (!jsop_getelem_pic(obj, id, objReg, idReg.reg(), tmpReg))
|
||||
return false;
|
||||
performedDense.linkTo(masm.label(), &masm);
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
frame.freeReg(idReg.reg());
|
||||
toFinalMerge.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
stubcc.rejoin(Changes(1));
|
||||
return true;
|
||||
}
|
||||
#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.reg());
|
||||
frame.popn(2);
|
||||
frame.pushRegs(tmpReg, objReg);
|
||||
stubcc.rejoin(Changes(1));
|
||||
}
|
||||
|
||||
bool
|
||||
mjit::Compiler::jsop_getelem()
|
||||
{
|
||||
|
@ -1516,30 +1387,107 @@ mjit::Compiler::jsop_getelem()
|
|||
return true;
|
||||
}
|
||||
|
||||
if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_STRING && id->isConstant()) {
|
||||
/* Never happens, or I'd optimize it. */
|
||||
jsop_getelem_slow();
|
||||
return true;
|
||||
GetElementICInfo ic = GetElementICInfo(JSOp(*PC));
|
||||
|
||||
// Pin the top of the stack to avoid spills, before allocating registers.
|
||||
MaybeRegisterID pinnedIdData = frame.maybePinData(id);
|
||||
MaybeRegisterID pinnedIdType = frame.maybePinType(id);
|
||||
|
||||
MaybeJump objTypeGuard;
|
||||
if (!obj->isTypeKnown()) {
|
||||
// Test the type of the object without spilling the payload.
|
||||
MaybeRegisterID pinnedObjData = frame.maybePinData(obj);
|
||||
Jump guard = frame.testObject(Assembler::NotEqual, obj);
|
||||
frame.maybeUnpinReg(pinnedObjData);
|
||||
|
||||
// Create a sync path, which we'll rejoin manually later. This is safe
|
||||
// as long as the IC does not build a stub; it won't, because |obj|
|
||||
// won't be an object. If we extend this IC to support strings, all
|
||||
// that needs to change is a little code movement.
|
||||
stubcc.linkExit(guard, Uses(2));
|
||||
objTypeGuard = stubcc.masm.jump();
|
||||
}
|
||||
|
||||
RegisterID tmpReg;
|
||||
if (obj->isTypeKnown()) {
|
||||
tmpReg = frame.allocReg();
|
||||
// Get a mutable register for the object. This will be the data reg.
|
||||
ic.objReg = frame.copyDataIntoReg(obj);
|
||||
|
||||
// Get a mutable register for pushing the result type. We kill two birds
|
||||
// with one stone by making sure, if the key type is not known, to be loaded
|
||||
// into this register. In this case it is both an input and an output.
|
||||
frame.maybeUnpinReg(pinnedIdType);
|
||||
if (id->isConstant() || id->isTypeKnown())
|
||||
ic.typeReg = frame.allocReg();
|
||||
else
|
||||
ic.typeReg = frame.copyTypeIntoReg(id);
|
||||
|
||||
// Fill in the id value.
|
||||
frame.maybeUnpinReg(pinnedIdData);
|
||||
if (id->isConstant()) {
|
||||
ic.id = ValueRemat::FromConstant(id->getValue());
|
||||
} else {
|
||||
tmpReg = frame.copyTypeIntoReg(obj);
|
||||
Jump objGuard = masm.testObject(Assembler::NotEqual, tmpReg);
|
||||
stubcc.linkExit(objGuard, Uses(2));
|
||||
RegisterID dataReg = frame.tempRegForData(id);
|
||||
if (id->isTypeKnown())
|
||||
ic.id = ValueRemat::FromKnownType(id->getKnownType(), dataReg);
|
||||
else
|
||||
ic.id = ValueRemat::FromRegisters(ic.typeReg, dataReg);
|
||||
}
|
||||
|
||||
if (id->isTypeKnown())
|
||||
return jsop_getelem_known_type(obj, id, tmpReg);
|
||||
ic.fastPathStart = masm.label();
|
||||
|
||||
// Note: slow path here is safe, since the frame will not be modified.
|
||||
ic.slowPathStart = stubcc.masm.label();
|
||||
frame.sync(stubcc.masm, Uses(2));
|
||||
|
||||
if (id->mightBeType(JSVAL_TYPE_INT32)) {
|
||||
// Always test the type first (see comment in PolyIC.h).
|
||||
if (!id->isTypeKnown()) {
|
||||
ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg);
|
||||
stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
|
||||
}
|
||||
|
||||
// Guard on the clasp.
|
||||
ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass);
|
||||
stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
|
||||
|
||||
Int32Key key = id->isConstant()
|
||||
? Int32Key::FromConstant(id->getValue().toInt32())
|
||||
: Int32Key::FromRegister(ic.id.dataReg());
|
||||
|
||||
Assembler::FastArrayLoadFails fails =
|
||||
masm.fastArrayLoad(ic.objReg, key, ic.typeReg, ic.objReg);
|
||||
|
||||
stubcc.linkExitDirect(fails.rangeCheck, ic.slowPathStart);
|
||||
stubcc.linkExitDirect(fails.holeCheck, ic.slowPathStart);
|
||||
} else {
|
||||
// The type is known to not be dense-friendly ahead of time, so always
|
||||
// fall back to a slow path.
|
||||
ic.claspGuard = masm.jump();
|
||||
stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
|
||||
}
|
||||
|
||||
stubcc.leave();
|
||||
if (objTypeGuard.isSet())
|
||||
objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
#ifdef JS_POLYIC
|
||||
passICAddress(&ic);
|
||||
ic.slowPathCall = stubcc.call(ic::GetElement);
|
||||
#else
|
||||
ic.slowPathCall = stubcc.call(stubs::GetElem);
|
||||
#endif
|
||||
|
||||
ic.fastPathRejoin = masm.label();
|
||||
|
||||
frame.popn(2);
|
||||
frame.pushRegs(ic.typeReg, ic.objReg);
|
||||
|
||||
stubcc.rejoin(Changes(2));
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
return jsop_getelem_with_pic(obj, id, tmpReg);
|
||||
#else
|
||||
jsop_getelem_nopic(obj, id, tmpReg);
|
||||
return true;
|
||||
if (!getElemICs.append(ic))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
|
|
@ -97,6 +97,12 @@ class FrameEntry
|
|||
return isTypeKnown() && getKnownType() != type_;
|
||||
}
|
||||
|
||||
// Return true if the type of this value is definitely type_, or is unknown
|
||||
// and thus potentially type_ at runtime.
|
||||
bool mightBeType(JSValueType type_) const {
|
||||
return !isNotType(type_);
|
||||
}
|
||||
|
||||
#if defined JS_NUNBOX32
|
||||
uint32 getPayload() const {
|
||||
//JS_ASSERT(!Valueify(v_.asBits).isDouble() || type.synced());
|
||||
|
|
|
@ -811,10 +811,10 @@ mjit::JITScript::release()
|
|||
code.m_executablePool->release();
|
||||
|
||||
#if defined JS_POLYIC
|
||||
for (uint32 i = 0; i < nPICs; i++) {
|
||||
pics[i].releasePools();
|
||||
Destroy(pics[i].execPools);
|
||||
}
|
||||
for (uint32 i = 0; i < nPICs; i++)
|
||||
pics[i].finish();
|
||||
for (uint32 i = 0; i < nGetElems; i++)
|
||||
getElems[i].finish();
|
||||
#endif
|
||||
|
||||
#if defined JS_MONOIC
|
||||
|
|
|
@ -143,6 +143,7 @@ namespace mjit {
|
|||
namespace ic {
|
||||
# if defined JS_POLYIC
|
||||
struct PICInfo;
|
||||
struct GetElementIC;
|
||||
# endif
|
||||
# if defined JS_MONOIC
|
||||
struct MICInfo;
|
||||
|
@ -182,6 +183,7 @@ typedef void * (JS_FASTCALL *VoidPtrStubTraceIC)(VMFrame &, js::mjit::ic::TraceI
|
|||
#endif
|
||||
#ifdef JS_POLYIC
|
||||
typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *);
|
||||
typedef void (JS_FASTCALL *VoidStubGetElemIC)(VMFrame &, js::mjit::ic::GetElementIC *);
|
||||
#endif
|
||||
|
||||
namespace mjit {
|
||||
|
@ -212,6 +214,8 @@ struct JITScript {
|
|||
#ifdef JS_POLYIC
|
||||
ic::PICInfo *pics; /* PICs in this script */
|
||||
uint32 nPICs; /* number of PolyICs */
|
||||
ic::GetElementIC *getElems;
|
||||
uint32 nGetElems;
|
||||
#endif
|
||||
void *invokeEntry; /* invoke address */
|
||||
void *fastEntry; /* cached entry, fastest */
|
||||
|
|
|
@ -90,22 +90,15 @@ class NunboxAssembler : public JSC::MacroAssembler
|
|||
return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
|
||||
}
|
||||
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, bool inlineAccess,
|
||||
RegisterID type, RegisterID data) {
|
||||
JS_ASSERT(type != data);
|
||||
Address address(obj, JSObject::getFixedSlotOffset(slot));
|
||||
RegisterID activeAddressReg = obj;
|
||||
if (!inlineAccess) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, slots)), clobber);
|
||||
address = Address(clobber, slot * sizeof(Value));
|
||||
activeAddressReg = clobber;
|
||||
}
|
||||
if (activeAddressReg == type) {
|
||||
loadPayload(address, data);
|
||||
loadTypeTag(address, type);
|
||||
void loadInlineSlot(RegisterID objReg, uint32 slot,
|
||||
RegisterID typeReg, RegisterID dataReg) {
|
||||
Address address(objReg, JSObject::getFixedSlotOffset(slot));
|
||||
if (objReg == typeReg) {
|
||||
loadPayload(address, dataReg);
|
||||
loadTypeTag(address, typeReg);
|
||||
} else {
|
||||
loadTypeTag(address, type);
|
||||
loadPayload(address, data);
|
||||
loadTypeTag(address, typeReg);
|
||||
loadPayload(address, dataReg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -37,7 +37,7 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#if !defined jsjaeger_poly_ic_h__ && defined JS_METHODJIT && defined JS_POLYIC
|
||||
#if !defined jsjaeger_poly_ic_h__ && defined JS_METHODJIT
|
||||
#define jsjaeger_poly_ic_h__
|
||||
|
||||
#include "jscntxt.h"
|
||||
|
@ -46,7 +46,9 @@
|
|||
#include "assembler/assembler/MacroAssembler.h"
|
||||
#include "assembler/assembler/CodeLocation.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
#include "BaseAssembler.h"
|
||||
#include "RematInfo.h"
|
||||
#include "BaseCompiler.h"
|
||||
|
||||
namespace js {
|
||||
namespace mjit {
|
||||
|
@ -54,6 +56,7 @@ namespace ic {
|
|||
|
||||
/* Maximum number of stubs for a given callsite. */
|
||||
static const uint32 MAX_PIC_STUBS = 16;
|
||||
static const uint32 MAX_GETELEM_IC_STUBS = 17;
|
||||
|
||||
/* SetPropCompiler */
|
||||
#if defined JS_CPU_X86
|
||||
|
@ -159,26 +162,6 @@ union PICLabels {
|
|||
int32 stubShapeJump : 8;
|
||||
} getprop;
|
||||
|
||||
/* GetElemCompiler */
|
||||
struct {
|
||||
/* Offset from storeBack to beginning of 'mov dslots, addr' */
|
||||
int32 dslotsLoadOffset : 8;
|
||||
|
||||
/* Offset from shapeGuard to end of shape comparison. */
|
||||
int32 inlineShapeOffset : 8;
|
||||
|
||||
/* Offset from shapeGuard to end of atom comparison. */
|
||||
int32 inlineAtomOffset : 8;
|
||||
|
||||
/* Offset from storeBack to end of value load. */
|
||||
int32 inlineValueOffset : 8;
|
||||
|
||||
/* Offset from lastStubStart to end of shape jump. */
|
||||
// TODO: We can redefine the location of lastStubStart to be
|
||||
// after the jump -- at which point this is always 0.
|
||||
int32 stubShapeJump : 8;
|
||||
} getelem;
|
||||
|
||||
/* BindNameCompiler */
|
||||
struct {
|
||||
/* Offset from shapeGuard to end of shape jump. */
|
||||
|
@ -187,21 +170,27 @@ union PICLabels {
|
|||
};
|
||||
#endif
|
||||
|
||||
struct BaseIC {
|
||||
enum LookupStatus {
|
||||
Lookup_Error = 0,
|
||||
Lookup_Uncacheable,
|
||||
Lookup_Cacheable
|
||||
};
|
||||
|
||||
struct BaseIC : public MacroAssemblerTypedefs {
|
||||
// Address of inline fast-path.
|
||||
JSC::CodeLocationLabel fastPathStart;
|
||||
CodeLocationLabel fastPathStart;
|
||||
|
||||
// Address to rejoin to the fast-path.
|
||||
JSC::CodeLocationLabel fastPathRejoin;
|
||||
CodeLocationLabel fastPathRejoin;
|
||||
|
||||
// Start of the slow path.
|
||||
JSC::CodeLocationLabel slowPathStart;
|
||||
CodeLocationLabel slowPathStart;
|
||||
|
||||
// Slow path stub call.
|
||||
JSC::CodeLocationCall slowPathCall;
|
||||
CodeLocationCall slowPathCall;
|
||||
|
||||
// Address of the start of the last generated stub, if any.
|
||||
JSC::CodeLocationLabel lastStubStart;
|
||||
CodeLocationLabel lastStubStart;
|
||||
|
||||
typedef Vector<JSC::ExecutablePool *, 0, SystemAllocPolicy> ExecPoolVector;
|
||||
|
||||
|
@ -210,16 +199,25 @@ struct BaseIC {
|
|||
|
||||
// Return the start address of the last path in this PIC, which is the
|
||||
// inline path if no stubs have been generated yet.
|
||||
JSC::CodeLocationLabel lastPathStart() {
|
||||
CodeLocationLabel lastPathStart() {
|
||||
return stubsGenerated > 0 ? lastStubStart : fastPathStart;
|
||||
}
|
||||
|
||||
// Whether or not the callsite has been hit at least once.
|
||||
bool hit : 1;
|
||||
bool slowCallPatched : 1;
|
||||
|
||||
// Number of stubs generated.
|
||||
uint32 stubsGenerated : 5;
|
||||
|
||||
// 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
|
||||
// last stub.
|
||||
int secondShapeGuard : 11;
|
||||
|
||||
// Opcode this was compiled for.
|
||||
JSOp op : 8;
|
||||
|
||||
// Release ExecutablePools referred to by this PIC.
|
||||
void releasePools() {
|
||||
for (JSC::ExecutablePool **pExecPool = execPools.begin();
|
||||
|
@ -229,17 +227,122 @@ struct BaseIC {
|
|||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
new (&execPools) ExecPoolVector(SystemAllocPolicy());
|
||||
}
|
||||
void finish() {
|
||||
releasePools();
|
||||
this->~BaseIC();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
hit = false;
|
||||
slowCallPatched = false;
|
||||
stubsGenerated = 0;
|
||||
secondShapeGuard = 0;
|
||||
releasePools();
|
||||
execPools.clear();
|
||||
}
|
||||
bool shouldUpdate(JSContext *cx);
|
||||
void spew(JSContext *cx, const char *event, const char *reason);
|
||||
LookupStatus disable(JSContext *cx, const char *reason, void *stub);
|
||||
bool isCallOp();
|
||||
};
|
||||
|
||||
struct GetElementIC : public BaseIC {
|
||||
// On stub entry:
|
||||
// If hasInlineTypeCheck() is true, and inlineTypeCheckPatched is false,
|
||||
// - typeReg contains the type of the |id| parameter.
|
||||
// If hasInlineTypeCheck() is true, and inlineTypeCheckPatched is true,
|
||||
// - typeReg contains the shape of |objReg| iff typeRegHasBaseShape
|
||||
// is true.
|
||||
// Otherwise, typeReg is garbage.
|
||||
//
|
||||
// On stub exit, typeReg must contain the type of the result value.
|
||||
RegisterID typeReg : 5;
|
||||
|
||||
// On stub entry, objReg contains the object pointer for the |obj| parameter.
|
||||
// On stub exit, objReg must contain the payload of the result value.
|
||||
RegisterID objReg : 5;
|
||||
|
||||
// Offset from the fast path to the inline type check.
|
||||
// This is only set if hasInlineTypeCheck() is true.
|
||||
unsigned inlineTypeGuard : 8;
|
||||
|
||||
// Offset from the fast path to the inline clasp guard. This is always
|
||||
// set; if |id| is known to not be int32, then it's an unconditional
|
||||
// jump to the slow path.
|
||||
unsigned inlineClaspGuard : 8;
|
||||
|
||||
// This is usable if hasInlineTypeGuard() returns true, which implies
|
||||
// that a dense array fast path exists. The inline type guard serves as
|
||||
// the head of the chain of all string-based element stubs.
|
||||
bool inlineTypeGuardPatched : 1;
|
||||
|
||||
// This is always usable, and specifies whether the inline clasp guard
|
||||
// has been patched. If hasInlineTypeGuard() is true, it guards against
|
||||
// a dense array, and guarantees the inline type guard has passed.
|
||||
// Otherwise, there is no inline type guard, and the clasp guard is just
|
||||
// an unconditional jump.
|
||||
bool inlineClaspGuardPatched : 1;
|
||||
|
||||
////////////////////////////////////////////
|
||||
// State for string-based property stubs. //
|
||||
////////////////////////////////////////////
|
||||
|
||||
// True if typeReg is guaranteed to have the shape of objReg.
|
||||
bool typeRegHasBaseShape : 1;
|
||||
|
||||
// These offsets are used for string-key dependent stubs, such as named
|
||||
// property accesses. They are separated from the int-key dependent stubs,
|
||||
// in order to guarantee that the id type needs only one guard per type.
|
||||
int atomGuard : 8; // optional, non-zero if present
|
||||
int firstShapeGuard : 8; // always set
|
||||
int secondShapeGuard : 8; // optional, non-zero if present
|
||||
|
||||
bool hasLastStringStub : 1;
|
||||
CodeLocationLabel lastStringStub;
|
||||
|
||||
// A limited ValueRemat instance. It may contains either:
|
||||
// 1) A constant, or
|
||||
// 2) A known type and data reg, or
|
||||
// 3) A data reg.
|
||||
// The sync bits are not set, and the type reg is never set and should not
|
||||
// be used, as it is encapsulated more accurately in |typeReg|. Also, note
|
||||
// carefully that the data reg is immutable.
|
||||
ValueRemat idRemat;
|
||||
|
||||
bool hasInlineTypeGuard() const {
|
||||
return !idRemat.isTypeKnown();
|
||||
}
|
||||
bool shouldPatchInlineTypeGuard() {
|
||||
return hasInlineTypeGuard() && !inlineTypeGuardPatched;
|
||||
}
|
||||
bool shouldPatchUnconditionalClaspGuard() {
|
||||
return !hasInlineTypeGuard() && !inlineClaspGuardPatched;
|
||||
}
|
||||
|
||||
void init() {
|
||||
BaseIC::init();
|
||||
reset();
|
||||
}
|
||||
void reset() {
|
||||
BaseIC::reset();
|
||||
inlineTypeGuardPatched = false;
|
||||
inlineClaspGuardPatched = false;
|
||||
typeRegHasBaseShape = false;
|
||||
hasLastStringStub = false;
|
||||
}
|
||||
void purge();
|
||||
LookupStatus update(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp);
|
||||
LookupStatus attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid id,
|
||||
Value *vp);
|
||||
LookupStatus disable(JSContext *cx, const char *reason);
|
||||
LookupStatus error(JSContext *cx);
|
||||
bool shouldUpdate(JSContext *cx);
|
||||
};
|
||||
|
||||
struct PICInfo : public BaseIC {
|
||||
typedef JSC::MacroAssembler::RegisterID RegisterID;
|
||||
|
||||
// Operation this is a PIC for.
|
||||
enum Kind
|
||||
#ifdef _MSC_VER
|
||||
|
@ -252,7 +355,6 @@ struct PICInfo : public BaseIC {
|
|||
SETMETHOD, // JSOP_SETMETHOD
|
||||
NAME, // JSOP_NAME
|
||||
BIND, // JSOP_BINDNAME
|
||||
GETELEM, // JSOP_GETELEM
|
||||
XNAME // JSOP_GETXPROP
|
||||
};
|
||||
|
||||
|
@ -263,20 +365,10 @@ struct PICInfo : public BaseIC {
|
|||
|
||||
// Reverse offset from slowPathStart to the type check slow path.
|
||||
int32 typeCheckOffset;
|
||||
|
||||
// Remat info for the object reg.
|
||||
int32 objRemat : MIN_STATE_REMAT_BITS;
|
||||
bool objNeedsRemat : 1;
|
||||
RegisterID idReg : 5; // only used in GETELEM PICs.
|
||||
} get;
|
||||
ValueRemat vr;
|
||||
} u;
|
||||
|
||||
// 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
|
||||
// last stub.
|
||||
int secondShapeGuard : 11;
|
||||
|
||||
Kind kind : 3;
|
||||
|
||||
// True if register R holds the base object shape along exits from the
|
||||
|
@ -299,7 +391,7 @@ struct PICInfo : public BaseIC {
|
|||
return kind == SET || kind == SETMETHOD;
|
||||
}
|
||||
inline bool isGet() const {
|
||||
return kind == GET || kind == CALL || kind == GETELEM;
|
||||
return kind == GET || kind == CALL;
|
||||
}
|
||||
inline RegisterID typeReg() {
|
||||
JS_ASSERT(isGet());
|
||||
|
@ -309,14 +401,6 @@ struct PICInfo : public BaseIC {
|
|||
JS_ASSERT(isGet());
|
||||
return u.get.hasTypeCheck;
|
||||
}
|
||||
inline const StateRemat objRemat() const {
|
||||
JS_ASSERT(isGet());
|
||||
return StateRemat::FromInt32(u.get.objRemat);
|
||||
}
|
||||
inline bool objNeedsRemat() {
|
||||
JS_ASSERT(isGet());
|
||||
return u.get.objNeedsRemat;
|
||||
}
|
||||
inline bool shapeNeedsRemat() {
|
||||
return !shapeRegHasBaseShape;
|
||||
}
|
||||
|
@ -325,12 +409,6 @@ struct PICInfo : public BaseIC {
|
|||
return !hasTypeCheck();
|
||||
}
|
||||
|
||||
inline void setObjRemat(const StateRemat &sr) {
|
||||
JS_ASSERT(isGet());
|
||||
u.get.objRemat = sr.toInt32();
|
||||
JS_ASSERT(u.get.objRemat == sr.toInt32());
|
||||
}
|
||||
|
||||
#if defined JS_CPU_X64
|
||||
// Required labels for platform-specific patching.
|
||||
PICLabels labels;
|
||||
|
@ -342,30 +420,30 @@ struct PICInfo : public BaseIC {
|
|||
// Index into the script's atom table.
|
||||
JSAtom *atom;
|
||||
|
||||
bool shouldGenerate() {
|
||||
return stubsGenerated < MAX_PIC_STUBS || !inlinePathPatched;
|
||||
void init() {
|
||||
BaseIC::init();
|
||||
reset();
|
||||
}
|
||||
|
||||
// Reset the data members to the state of a fresh PIC before any patching
|
||||
// or stub generation was done.
|
||||
void reset() {
|
||||
inlinePathPatched = false;
|
||||
if (kind == GET || kind == CALL || kind == GETELEM)
|
||||
u.get.objNeedsRemat = false;
|
||||
secondShapeGuard = 0;
|
||||
shapeRegHasBaseShape = true;
|
||||
BaseIC::reset();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef JS_POLYIC
|
||||
void PurgePICs(JSContext *cx, JSScript *script);
|
||||
void JS_FASTCALL GetProp(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL GetElem(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL SetProp(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL CallProp(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL Name(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL XName(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL BindName(VMFrame &f, ic::PICInfo *);
|
||||
void JS_FASTCALL GetElement(VMFrame &f, ic::GetElementIC *);
|
||||
#endif
|
||||
|
||||
} /* namespace ic */
|
||||
} /* namespace mjit */
|
||||
|
|
|
@ -93,16 +93,10 @@ class PunboxAssembler : public JSC::MacroAssembler
|
|||
return address;
|
||||
}
|
||||
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, bool inlineAccess,
|
||||
RegisterID type, RegisterID data) {
|
||||
JS_ASSERT(type != data);
|
||||
Address address(obj, JSObject::getFixedSlotOffset(slot));
|
||||
if (!inlineAccess) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, slots)), clobber);
|
||||
address = Address(clobber, slot * sizeof(Value));
|
||||
}
|
||||
|
||||
loadValueAsComponents(address, type, data);
|
||||
void loadInlineSlot(RegisterID objReg, uint32 slot,
|
||||
RegisterID typeReg, RegisterID dataReg) {
|
||||
Address address(objReg, JSObject::getFixedSlotOffset(slot));
|
||||
loadValueAsComponents(address, typeReg, dataReg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -127,6 +127,7 @@ class StubCompiler
|
|||
STUB_CALL_TYPE(VoidStubPC);
|
||||
#ifdef JS_POLYIC
|
||||
STUB_CALL_TYPE(VoidStubPIC);
|
||||
STUB_CALL_TYPE(VoidStubGetElemIC);
|
||||
#endif
|
||||
#ifdef JS_MONOIC
|
||||
STUB_CALL_TYPE(VoidStubMIC);
|
||||
|
|
Загрузка…
Ссылка в новой задаче