Bug 588021: Port GETPROP PIC for ARM. (r=dmandelin)

This commit is contained in:
Chris Leary 2011-01-13 22:40:15 -08:00
parent 9e386e7eeb
commit 8dc586ec63
9 changed files with 333 additions and 202 deletions

View File

@ -2913,6 +2913,7 @@ i?86-*)
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
ENABLE_POLYIC=1
ENABLE_POLYIC_GETPROP=1
AC_DEFINE(JS_CPU_X86)
AC_DEFINE(JS_NUNBOX32)
;;
@ -2922,6 +2923,7 @@ x86_64*-*)
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
ENABLE_POLYIC=1
ENABLE_POLYIC_GETPROP=1
AC_DEFINE(JS_CPU_X64)
AC_DEFINE(JS_PUNBOX64)
;;
@ -2930,6 +2932,8 @@ arm*-*)
NANOJIT_ARCH=ARM
ENABLE_METHODJIT=1
ENABLE_MONOIC=1
ENABLE_POLYIC=1
ENABLE_POLYIC_GETPROP=1
AC_DEFINE(JS_CPU_ARM)
AC_DEFINE(JS_NUNBOX32)
;;
@ -2975,6 +2979,26 @@ if test "$ENABLE_POLYIC"; then
AC_DEFINE(JS_POLYIC)
fi
if test "$ENABLE_POLYIC_GETPROP"; then
AC_DEFINE(JS_POLYIC_GETPROP)
fi
if test "$ENABLE_POLYIC_SETPROP"; then
AC_DEFINE(JS_POLYIC_SETPROP)
fi
if test "$ENABLE_POLYIC_NAME"; then
AC_DEFINE(JS_POLYIC_SETPROP)
fi
if test "$ENABLE_POLYIC_BIND"; then
AC_DEFINE(JS_POLYIC_SETPROP)
fi
if test "$ENABLE_POLYIC_ELEM"; then
AC_DEFINE(JS_POLYIC_ELEM)
fi
if test "$ENABLE_METHODJIT_SPEW"; then
AC_DEFINE(JS_METHODJIT_SPEW)
fi

View File

@ -69,10 +69,16 @@ struct MacroAssemblerTypedefs {
typedef JSC::FunctionPtr FunctionPtr;
typedef JSC::RepatchBuffer RepatchBuffer;
typedef JSC::CodeLocationLabel CodeLocationLabel;
typedef JSC::CodeLocationDataLabel32 CodeLocationDataLabel32;
typedef JSC::CodeLocationJump CodeLocationJump;
typedef JSC::CodeLocationCall CodeLocationCall;
typedef JSC::CodeLocationInstruction CodeLocationInstruction;
typedef JSC::ReturnAddressPtr ReturnAddressPtr;
typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr;
typedef JSC::JITCode JITCode;
#if defined JS_CPU_ARM
typedef JSC::ARMWord ARMWord;
#endif
};
class BaseCompiler : public MacroAssemblerTypedefs
@ -195,19 +201,22 @@ class LinkerHelper : public JSC::LinkBuffer
* up front to prevent this from happening.
*/
#ifdef JS_CPU_ARM
template <size_t reservedSpace>
class AutoReserveICSpace {
typedef Assembler::Label Label;
static const size_t reservedSpace = 68;
Assembler &masm;
#ifdef DEBUG
Label startLabel;
bool didCheck;
#endif
public:
AutoReserveICSpace(Assembler &masm) : masm(masm) {
masm.ensureSpace(reservedSpace);
#ifdef DEBUG
didCheck = false;
startLabel = masm.label();
/* Assert that the constant pool is not flushed until we reach a safe point. */
@ -217,8 +226,13 @@ class AutoReserveICSpace {
#endif
}
~AutoReserveICSpace() {
/* Allow manual IC space checks so that non-patchable code at the end of an IC section can be
* free to use constant pools. */
void check() {
#ifdef DEBUG
JS_ASSERT(!didCheck);
didCheck = true;
Label endLabel = masm.label();
int spaceUsed = masm.differenceBetween(startLabel, endLabel);
@ -233,12 +247,33 @@ class AutoReserveICSpace {
/* Allow the pool to be flushed. */
masm.allowPoolFlush(true);
#endif
}
~AutoReserveICSpace() {
#ifdef DEBUG
/* Automatically check the IC space if we didn't already do it manually. */
if (!didCheck) {
check();
}
#endif
}
};
# define RESERVE_IC_SPACE(__masm) AutoReserveICSpace arics(__masm)
# define RESERVE_IC_SPACE(__masm) AutoReserveICSpace<80> arics(__masm)
/* The OOL path can need a lot of space because we save and restore a lot of registers. The actual
* sequene varies. However, dumping the literal pool before an OOL block is probably a good idea
* anyway, as we branch directly to the start of the block from the fast path. */
# define RESERVE_OOL_SPACE(__masm) AutoReserveICSpace<256> arics_ool(__masm)
/* Allow the OOL patch to be checked before object destruction. Often, non-patchable epilogues or
* rejoining sequences are emitted, and it isn't necessary to protect these from literal pools. */
# define CHECK_OOL_SPACE() arics_ool.check()
#else
# define RESERVE_IC_SPACE(__masm) /* Nothing. */
# define RESERVE_IC_SPACE(__masm) /* Do nothing. */
# define RESERVE_OOL_SPACE(__masm) /* Do nothing. */
# define CHECK_OOL_SPACE() /* Do nothing. */
#endif
} /* namespace js */

View File

@ -2969,7 +2969,9 @@ mjit::Compiler::passICAddress(BaseICInfo *ic)
{
ic->paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
}
#endif
#if defined JS_POLYIC_GETPROP
bool
mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
{
@ -2995,10 +2997,12 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
shapeReg = frame.allocReg();
}
RESERVE_IC_SPACE(masm);
PICGenInfo pic(ic::PICInfo::GET, JSOp(*PC), usePropCache);
/* Guard that the type is an object. */
Jump typeCheck;
Label typeCheck;
if (doTypeCheck && !top->isTypeKnown()) {
RegisterID reg = frame.tempRegForType(top);
pic.typeReg = reg;
@ -3006,10 +3010,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
/* Start the hot path where it's easy to patch it. */
pic.fastPathStart = masm.label();
Jump j = masm.testObject(Assembler::NotEqual, reg);
/* GETPROP_INLINE_TYPE_GUARD is used to patch the jmp, not cmp. */
typeCheck = masm.label();
RETURN_IF_OOM(false);
JS_ASSERT(masm.differenceBetween(pic.fastPathStart, masm.label()) == GETPROP_INLINE_TYPE_GUARD);
pic.typeCheck = stubcc.linkExit(j, Uses(1));
pic.hasTypeCheck = true;
@ -3035,52 +3037,43 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
Jump j = masm.branch32WithPatch(Assembler::NotEqual, shapeReg,
Imm32(int32(JSObjectMap::INVALID_SHAPE)),
inlineShapeLabel);
DBGLABEL(dbgInlineShapeJump);
Label inlineShapeJump = masm.label();
RESERVE_OOL_SPACE(stubcc.masm);
pic.slowPathStart = stubcc.linkExit(j, Uses(1));
stubcc.leave();
passICAddress(&pic);
pic.slowPathCall = OOL_STUBCALL(ic::GetProp);
CHECK_OOL_SPACE();
/* Load dslots. */
Label dslotsLoadLabel = masm.label();
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Load the base slot address. */
Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)),
objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
frame.pop();
#if defined JS_NUNBOX32
masm.loadTypeTag(slot, shapeReg);
Label typeLoad = masm.label();
masm.loadPayload(slot, objReg);
Label dataLoad = masm.label();
#elif defined JS_PUNBOX64
Label inlineValueLoadLabel = masm.loadValueAsComponents(slot, shapeReg, objReg);
#endif
Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg);
pic.fastPathRejoin = masm.label();
RETURN_IF_OOM(false);
/* Initialize op labels. */
GetPropLabels &labels = pic.getPropLabels();
labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel));
labels.setDslotsLoad(masm, pic.fastPathRejoin, dslotsLoadLabel);
labels.setInlineShapeData(masm, pic.shapeGuard, inlineShapeLabel);
#if defined JS_NUNBOX32
labels.setTypeLoad(masm.differenceBetween(pic.fastPathRejoin, typeLoad));
labels.setDataLoad(masm.differenceBetween(pic.fastPathRejoin, dataLoad));
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
#elif defined JS_PUNBOX64
labels.setValueLoad(masm.differenceBetween(pic.fastPathRejoin, inlineValueLoadLabel));
JS_ASSERT(masm.differenceBetween(inlineShapeLabel, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad);
if (pic.hasTypeCheck)
labels.setInlineTypeJump(masm, pic.fastPathStart, typeCheck);
#ifdef JS_CPU_X64
labels.setInlineShapeJump(masm, inlineShapeLabel, inlineShapeJump);
#else
labels.setInlineShapeJump(masm, pic.shapeGuard, inlineShapeJump);
#endif
/* GETPROP_INLINE_TYPE_GUARD's validity is asserted above. */
pic.objReg = objReg;
frame.pushRegs(shapeReg, objReg);
@ -3089,7 +3082,9 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
pics.append(pic);
return true;
}
#endif /* JS_POLYIC_GETPROP */
#if defined JS_POLYIC_CALLPROP
bool
mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
{
@ -3171,15 +3166,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
#if defined JS_NUNBOX32
masm.loadTypeTag(slot, shapeReg);
Label typeLoad = masm.label();
masm.loadPayload(slot, objReg);
Label dataLoad = masm.label();
#elif defined JS_PUNBOX64
Label inlineValueLoadLabel = masm.loadValueAsComponents(slot, shapeReg, objReg);
#endif
Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg);
pic.fastPathRejoin = masm.label();
/* Assert correctness of hardcoded offsets. */
@ -3189,14 +3176,10 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
GetPropLabels &labels = pic.getPropLabels();
labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel));
labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad);
#if defined JS_NUNBOX32
labels.setTypeLoad(masm.differenceBetween(pic.fastPathRejoin, typeLoad));
labels.setDataLoad(masm.differenceBetween(pic.fastPathRejoin, dataLoad));
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
#elif defined JS_PUNBOX64
labels.setValueLoad(masm.differenceBetween(pic.fastPathRejoin, inlineValueLoadLabel));
JS_ASSERT(masm.differenceBetween(inlineShapeLabel, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
#endif
@ -3309,15 +3292,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
#if defined JS_NUNBOX32
masm.loadTypeTag(slot, shapeReg);
Label dbgTypeLoad = masm.label();
masm.loadPayload(slot, objReg);
Label dbgDataLoad = masm.label();
#elif defined JS_PUNBOX64
Label inlineValueLoadLabel = masm.loadValueAsComponents(slot, shapeReg, objReg);
#endif
Label fastValueLoad = masm.loadValueWithAddressOffsetPatch(slot, shapeReg, objReg);
pic.fastPathRejoin = masm.label();
pic.objReg = objReg;
@ -3344,14 +3319,11 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
GetPropLabels &labels = pic.getPropLabels();
labels.setDslotsLoadOffset(masm.differenceBetween(pic.fastPathRejoin, dslotsLoadLabel));
labels.setInlineShapeOffset(masm.differenceBetween(pic.shapeGuard, inlineShapeLabel));
#if defined JS_NUNBOX32
labels.setTypeLoad(masm.differenceBetween(pic.fastPathRejoin, dbgTypeLoad));
labels.setDataLoad(masm.differenceBetween(pic.fastPathRejoin, dbgDataLoad));
labels.setValueLoad(masm, pic.fastPathRejoin, fastValueLoad);
#if defined JS_NUNBOX32
JS_ASSERT(masm.differenceBetween(pic.shapeGuard, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
#elif defined JS_PUNBOX64
labels.setValueLoad(masm.differenceBetween(pic.fastPathRejoin, inlineValueLoadLabel));
JS_ASSERT(masm.differenceBetween(inlineShapeLabel, dbgInlineShapeJump) == GETPROP_INLINE_SHAPE_JUMP);
#endif
@ -3377,7 +3349,9 @@ mjit::Compiler::jsop_callprop(JSAtom *atom)
return jsop_callprop_obj(atom);
return jsop_callprop_generic(atom);
}
#endif /* JS_POLYIC_CALLPROP */
#ifdef JS_POLYIC_SETPROP
bool
mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
{
@ -3516,7 +3490,9 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
pics.append(pic);
return true;
}
#endif
#ifdef JS_POLYIC_NAME
void
mjit::Compiler::jsop_name(JSAtom *atom)
{
@ -3593,6 +3569,9 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
return true;
}
#endif /* JSOP_POLYIC_NAME */
#ifdef JS_POLYIC_BIND
void
mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
{
@ -3641,9 +3620,9 @@ mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
pics.append(pic);
}
#endif /* JS_POLYIC_BIND */
#else /* JS_POLYIC */
#if !defined JS_POLYIC_NAME
void
mjit::Compiler::jsop_name(JSAtom *atom)
{
@ -3657,27 +3636,35 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
{
return jsop_getprop(atom);
}
#endif
#if !defined JS_POLYIC_GETPROP
bool
mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck, bool usePropCache)
{
jsop_getprop_slow(atom, usePropCache);
return true;
}
#endif
#if !defined JS_POLYIC_CALLPROP
bool
mjit::Compiler::jsop_callprop(JSAtom *atom)
{
return jsop_callprop_slow(atom);
}
#endif
#if !defined JS_POLYIC_SETPROP
bool
mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
{
jsop_setprop_slow(atom, usePropCache);
return true;
}
#endif
#if !defined JS_POLYIC_BIND
void
mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
{
@ -4355,9 +4342,9 @@ mjit::Compiler::jsop_getgname(uint32 index)
Address address(objReg, slot);
/* Allocate any register other than objReg. */
RegisterID dreg = frame.allocReg();
RegisterID treg = frame.allocReg();
/* After dreg is loaded, it's safe to clobber objReg. */
RegisterID treg = objReg;
RegisterID dreg = objReg;
mic.load = masm.loadValueWithAddressOffsetPatch(address, treg, dreg);

View File

@ -1286,7 +1286,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart);
stubcc.leave();
#ifdef JS_POLYIC
#if defined JS_POLYIC && defined JS_POLYIC_SETELEM
passICAddress(&ic);
ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement));
#else
@ -1326,7 +1326,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
frame.shimmy(2);
stubcc.rejoin(Changes(2));
#ifdef JS_POLYIC
#if defined JS_POLYIC && defined JS_POLYIC_SETELEM
if (!setElemICs.append(ic))
return false;
#endif
@ -1341,7 +1341,7 @@ IsCacheableGetElem(FrameEntry *obj, FrameEntry *id)
return false;
if (id->isTypeKnown() &&
!(id->getKnownType() == JSVAL_TYPE_INT32
#ifdef JS_POLYIC
#if defined JS_POLYIC && defined JS_POLYIC_GETELEM
|| id->getKnownType() == JSVAL_TYPE_STRING
#endif
)) {
@ -1471,7 +1471,7 @@ mjit::Compiler::jsop_getelem(bool isCall)
stubcc.leave();
if (objTypeGuard.isSet())
objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
#ifdef JS_POLYIC
#if defined JS_POLYIC && defined JS_POLYIC_GETELEM
passICAddress(&ic);
if (isCall)
ic.slowPathCall = OOL_STUBCALL(ic::CallElement);
@ -1493,7 +1493,7 @@ mjit::Compiler::jsop_getelem(bool isCall)
stubcc.rejoin(Changes(2));
#ifdef JS_POLYIC
#if defined JS_POLYIC && defined JS_POLYIC_GETELEM
if (!getElemICs.append(ic))
return false;
#endif

View File

@ -48,6 +48,7 @@
#include "jsvector.h"
#include "assembler/assembler/MacroAssembler.h"
#include "assembler/assembler/CodeLocation.h"
#include "methodjit/CodeGenIncludes.h"
#include "methodjit/MethodJIT.h"
#include "BaseAssembler.h"
#include "RematInfo.h"
@ -62,20 +63,89 @@ namespace js {
namespace mjit {
namespace ic {
#if defined JS_CPU_X64 || defined JS_CPU_ARM
/*
* On x64 and ARM, we create offsets dynamically instead of using hardcoded
* offsets into the instruction stream. This is done on x64 because of
* variable-width instruction encoding when using the extended register set and
* it is done on ARM for expediency of implementation.
* On x64 and ARM, we record offsets into the labels data structures at runtime
* instead of using hardcoded offsets into the instruction stream, as we do on
* x86.
*
* This is done on x64 because of variable-width instruction encoding when
* using the extended register set. It is done on ARM for ease of
* implementation.
*/
#if defined JS_CPU_X64 || defined JS_CPU_ARM
# define JS_HAS_IC_LABELS
#endif
# define JS_POLYIC_OFFSET_BITS 8
/* GetPropCompiler */
struct GetPropLabels {
struct GetPropLabels : MacroAssemblerTypedefs {
friend class ::ICOffsetInitializer;
void setValueLoad(MacroAssembler &masm, Label fastPathRejoin, Label fastValueLoad) {
int offset = masm.differenceBetween(fastPathRejoin, fastValueLoad);
#ifdef JS_HAS_IC_LABELS
inlineValueLoadOffset = offset;
#endif
/*
* Note: the offset between the type and data loads for x86 is asserted
* in NunboxAssembler::loadValueWithAddressOffsetPatch.
*/
JS_ASSERT(offset == inlineValueLoadOffset);
}
CodeLocationLabel getValueLoad(CodeLocationLabel fastPathRejoin) {
return fastPathRejoin.labelAtOffset(inlineValueLoadOffset);
}
void setDslotsLoad(MacroAssembler &masm, Label fastPathRejoin, Label dslotsLoad) {
int offset = masm.differenceBetween(fastPathRejoin, dslotsLoad);
setDslotsLoadOffset(offset);
}
CodeLocationInstruction getDslotsLoad(CodeLocationLabel fastPathRejoin) {
return fastPathRejoin.instructionAtOffset(getDslotsLoadOffset());
}
void setInlineShapeData(MacroAssembler &masm, Label shapeGuard, DataLabel32 inlineShape) {
int offset = masm.differenceBetween(shapeGuard, inlineShape);
setInlineShapeOffset(offset);
}
CodeLocationDataLabel32 getInlineShapeData(CodeLocationLabel fastShapeGuard) {
return fastShapeGuard.dataLabel32AtOffset(getInlineShapeOffset());
}
/*
* Note: on x64, the base is the inlineShapeLabel DataLabel32, whereas on other
* platforms the base is the shapeGuard.
*/
template <typename T>
void setInlineShapeJump(MacroAssembler &masm, T base, Label afterJump) {
setInlineShapeJumpOffset(masm.differenceBetween(base, afterJump));
}
CodeLocationJump getInlineShapeJump(CodeLocationLabel fastShapeGuard) {
return fastShapeGuard.jumpAtOffset(getInlineShapeJumpOffset());
}
void setInlineTypeJump(MacroAssembler &masm, Label fastPathStart, Label afterTypeJump) {
int offset = masm.differenceBetween(fastPathStart, afterTypeJump);
setInlineTypeJumpOffset(offset);
}
CodeLocationJump getInlineTypeJump(CodeLocationLabel fastPathStart) {
#if defined JS_CPU_X86 || defined JS_CPU_X64
return fastPathStart.jumpAtOffset(getInlineTypeJumpOffset());
#elif defined JS_CPU_ARM
/* Type check is after the testObject, so offset by one instruction to get the jump. */
return fastPathStart.jumpAtOffset(getInlineTypeJumpOffset() - sizeof(ARMWord));
#endif
}
/* Offset-based interface */
void setDslotsLoadOffset(int offset) {
#ifdef JS_HAS_IC_LABELS
dslotsLoadOffset = offset;
@ -92,41 +162,41 @@ struct GetPropLabels {
void setStubShapeJump(int offset) {
#ifdef JS_HAS_IC_LABELS
stubShapeJump = offset;
stubShapeJumpOffset = offset;
#endif
JS_ASSERT(offset == stubShapeJump);
JS_ASSERT(offset == stubShapeJumpOffset);
}
#if defined JS_NUNBOX32
void setTypeLoad(int offset) {
# if defined JS_HAS_IC_LABELS
inlineTypeLoad = offset;
# endif
JS_ASSERT(offset == inlineTypeLoad);
}
void setDataLoad(int offset) {
# if defined JS_HAS_IC_LABELS
inlineDataLoad = offset;
# endif
JS_ASSERT(offset == inlineDataLoad);
}
JSC::CodeLocationDataLabel32 getTypeLoad(JSC::CodeLocationLabel start) {
return start.dataLabel32AtOffset(inlineTypeLoad);
}
JSC::CodeLocationDataLabel32 getDataLoad(JSC::CodeLocationLabel start) {
return start.dataLabel32AtOffset(inlineDataLoad);
}
#elif defined JS_PUNBOX64
void setValueLoad(int offset) {
# if defined JS_HAS_IC_LABELS
inlineValueLoad = offset;
# endif
JS_ASSERT(offset == inlineValueLoad);
}
JSC::CodeLocationDataLabel32 getValueLoad(JSC::CodeLocationLabel start) {
return start.dataLabel32AtOffset(inlineValueLoad);
}
int getInlineShapeJumpOffset() {
#if defined JS_CPU_X86
return INLINE_SHAPE_JUMP;
#elif defined JS_CPU_X64
return getInlineShapeOffset() + INLINE_SHAPE_JUMP;
#elif defined JS_CPU_ARM
return INLINE_SHAPE_JUMP - sizeof(ARMWord);
#endif
}
void setInlineShapeJumpOffset(int offset) {
JS_ASSERT(INLINE_SHAPE_JUMP == offset);
}
int getInlineTypeJumpOffset() {
#if defined JS_CPU_X86 || defined JS_CPU_X64
return INLINE_TYPE_JUMP;
#elif defined JS_CPU_ARM
return inlineTypeJumpOffset;
#endif
}
void setInlineTypeJumpOffset(int offset) {
#if defined JS_CPU_X86 || defined JS_CPU_X64
JS_ASSERT(INLINE_TYPE_JUMP == offset);
#elif defined JS_CPU_ARM
inlineTypeJumpOffset = offset;
JS_ASSERT(offset == inlineTypeJumpOffset);
#endif
}
int getInlineShapeOffset() {
return inlineShapeOffset;
@ -134,8 +204,12 @@ struct GetPropLabels {
int getDslotsLoadOffset() {
return dslotsLoadOffset;
}
int getStubShapeJump() {
return stubShapeJump;
int getStubShapeJumpOffset() {
#if defined JS_CPU_X86 || defined JS_CPU_X64
return stubShapeJumpOffset;
#elif defined JS_CPU_ARM
return stubShapeJumpOffset - sizeof(ARMWord);
#endif
}
private:
@ -146,19 +220,28 @@ struct GetPropLabels {
int32 inlineShapeOffset : 8;
/* Offset from storeBack to end of value load. */
#ifdef JS_NUNBOX32
int32 inlineTypeLoad : 8;
int32 inlineDataLoad : 8;
#elif JS_PUNBOX64
int32 inlineValueLoad : 8;
#endif
int32 inlineValueLoadOffset : 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;
int32 stubShapeJumpOffset : 8;
#if defined JS_CPU_X86
static const int32 INLINE_SHAPE_JUMP = 12;
static const int32 INLINE_TYPE_JUMP = 12;
#elif defined JS_CPU_X64
static const int32 INLINE_SHAPE_JUMP = 6;
static const int32 INLINE_TYPE_JUMP = 19;
#elif defined JS_CPU_ARM
/* Offset from the shape guard start to the shape guard jump. */
static const int32 INLINE_SHAPE_JUMP = 12;
/* Offset from the fast path to the type guard jump. */
int32 inlineTypeJumpOffset : 8;
#endif
};
/* SetPropCompiler */
@ -206,7 +289,7 @@ struct SetPropLabels {
private:
#ifdef JS_PUNBOX64
/* Offset from storeBack to beginning of 'mov dslots, addr' */
/* Offset from storeBack to beginning of 'mov dslots, addr'. */
int32 dslotsLoadOffset : 8;
#endif

View File

@ -98,14 +98,14 @@ class Repatcher : public JSC::RepatchBuffer
#if defined JS_CPU_X64 || defined JS_CPU_ARM
repatch(label.dataLabel32AtOffset(0), offset);
#elif defined JS_CPU_X86
static const unsigned LOAD_DATA_OFFSET = 6;
static const unsigned LOAD_TYPE_OFFSET = 12;
static const unsigned LOAD_TYPE_OFFSET = 6;
static const unsigned LOAD_DATA_OFFSET = 12;
/*
* We have the following sequence to patch:
*
* mov <offset+0>($base), %<data>
* mov <offset+4>($base), %<type>
* mov <offset+0>($base), %<data>
*/
repatch(label.dataLabel32AtOffset(LOAD_DATA_OFFSET), offset);
repatch(label.dataLabel32AtOffset(LOAD_TYPE_OFFSET), offset + 4);

View File

@ -166,11 +166,11 @@ class NunboxAssembler : public JSC::MacroAssembler
* ICRepatcher::patchAddressOffsetForValueLoad to patch the address'
* offset.
*
* The type register is guaranteed to be clobbered last. (This makes the
* base register for the address reusable as 'treg'.)
* The data register is guaranteed to be clobbered last. (This makes the
* base register for the address reusable as 'dreg'.)
*/
Label loadValueWithAddressOffsetPatch(Address address, RegisterID treg, RegisterID dreg) {
JS_ASSERT(address.base != dreg); /* dreg is clobbered first. */
JS_ASSERT(address.base != treg); /* treg is clobbered first. */
Label start = label();
#if defined JS_CPU_X86
@ -178,12 +178,12 @@ class NunboxAssembler : public JSC::MacroAssembler
* On x86 there are two loads to patch and they both encode the offset
* in-line.
*/
loadPayload(address, dreg);
DBGLABEL_NOMASM(endPayload);
loadTypeTag(address, treg);
DBGLABEL_NOMASM(endType);
JS_ASSERT(differenceBetween(start, endPayload) == 6);
JS_ASSERT(differenceBetween(endPayload, endType) == 6);
loadPayload(address, dreg);
DBGLABEL_NOMASM(endPayload);
JS_ASSERT(differenceBetween(start, endType) == 6);
JS_ASSERT(differenceBetween(endType, endPayload) == 6);
return start;
#elif defined JS_CPU_ARM
/*

View File

@ -77,9 +77,8 @@ ICOffsetInitializer::ICOffsetInitializer()
#if defined JS_CPU_X86
labels.dslotsLoadOffset = -15;
labels.inlineShapeOffset = 6;
labels.inlineTypeLoad = -6;
labels.inlineDataLoad = 0;
labels.stubShapeJump = 12;
labels.stubShapeJumpOffset = 12;
labels.inlineValueLoadOffset = -12;
#endif
}
{
@ -173,6 +172,7 @@ class PICStubCompiler : public BaseCompiler
}
};
#if defined JS_POLYIC_SETPROP
class SetPropCompiler : public PICStubCompiler
{
JSObject *obj;
@ -308,7 +308,7 @@ class SetPropCompiler : public PICStubCompiler
// the offsets are different.
int shapeGuardJumpOffset;
if (pic.stubsGenerated)
shapeGuardJumpOffset = pic.setPropLabels().getStubShapeJump();
shapeGuardJumpOffset = pic.setPropLabels().getStubShapeJumpOffset();
else
shapeGuardJumpOffset = pic.shapeGuard + inlineShapeJump();
repatcher.relink(label.jumpAtOffset(shapeGuardJumpOffset), cs);
@ -671,6 +671,7 @@ class SetPropCompiler : public PICStubCompiler
return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray());
}
};
#endif
static bool
IsCacheableProtoChain(JSObject *obj, JSObject *holder)
@ -755,40 +756,13 @@ struct GetPropertyHelper {
}
};
#if defined JS_POLYIC_GETPROP
class GetPropCompiler : public PICStubCompiler
{
JSObject *obj;
JSAtom *atom;
int lastStubSecondShapeGuard;
static int32 inlineShapeOffset(ic::PICInfo &pic) {
return pic.getPropLabels().getInlineShapeOffset();
}
inline int32 inlineShapeOffset() {
return inlineShapeOffset(pic);
}
static int32 inlineShapeJump(ic::PICInfo &pic) {
#if defined JS_NUNBOX32
return GETPROP_INLINE_SHAPE_JUMP;
#elif defined JS_PUNBOX64
return inlineShapeOffset(pic) + GETPROP_INLINE_SHAPE_JUMP;
#endif
}
inline int32 inlineShapeJump() {
return inlineShapeJump(pic);
}
static int32 dslotsLoad(ic::PICInfo &pic) {
return pic.getPropLabels().getDslotsLoadOffset();
}
inline int32 dslotsLoad() {
return dslotsLoad(pic);
}
public:
GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
VoidStubPIC stub)
@ -799,18 +773,26 @@ class GetPropCompiler : public PICStubCompiler
lastStubSecondShapeGuard(pic.secondShapeGuard)
{ }
int getLastStubSecondShapeGuard() const {
#if defined JS_CPU_ARM
/* Jumps on ARM point at the beginning of the instruction. */
return lastStubSecondShapeGuard ? lastStubSecondShapeGuard - sizeof(JSC::ARMWord) : 0;
#else
return lastStubSecondShapeGuard;
#endif
}
static void reset(Repatcher &repatcher, ic::PICInfo &pic)
{
repatcher.repatchLEAToLoadPtr(pic.fastPathRejoin.instructionAtOffset(dslotsLoad(pic)));
repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(
pic.shapeGuard + inlineShapeOffset(pic)),
GetPropLabels &labels = pic.getPropLabels();
repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin));
repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()),
int32(JSObjectMap::INVALID_SHAPE));
repatcher.relink(pic.fastPathStart.jumpAtOffset(pic.shapeGuard + inlineShapeJump(pic)),
pic.slowPathStart);
repatcher.relink(labels.getInlineShapeJump(pic.getFastShapeGuard()), pic.slowPathStart);
if (pic.hasTypeCheck()) {
repatcher.relink(pic.fastPathStart.jumpAtOffset(GETPROP_INLINE_TYPE_GUARD),
pic.slowPathStart.labelAtOffset(pic.u.get.typeCheckOffset));
/* TODO: combine pic.u.get into ICLabels? */
repatcher.relink(labels.getInlineTypeJump(pic.fastPathStart), pic.getSlowTypeCheck());
}
VoidStubPIC stub;
@ -1001,7 +983,7 @@ class GetPropCompiler : public PICStubCompiler
return disable("code memory is out of range");
}
buffer.link(notString, pic.slowPathStart.labelAtOffset(pic.u.get.typeCheckOffset));
buffer.link(notString, pic.getSlowTypeCheck());
buffer.link(shapeMismatch, pic.slowPathStart);
buffer.link(done, pic.fastPathRejoin);
@ -1012,7 +994,7 @@ class GetPropCompiler : public PICStubCompiler
/* Patch the type check to jump here. */
if (pic.hasTypeCheck()) {
Repatcher repatcher(f.jit());
repatcher.relink(pic.fastPathStart.jumpAtOffset(GETPROP_INLINE_TYPE_GUARD), cs);
repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), cs);
}
/* Disable the PIC so we don't keep generating stubs on the above shape mismatch. */
@ -1043,7 +1025,7 @@ class GetPropCompiler : public PICStubCompiler
return disable("code memory is out of range");
}
buffer.link(notString, pic.slowPathStart.labelAtOffset(pic.u.get.typeCheckOffset));
buffer.link(notString, pic.getSlowTypeCheck());
buffer.link(done, pic.fastPathRejoin);
CodeLocationLabel start = buffer.finalize();
@ -1052,7 +1034,7 @@ class GetPropCompiler : public PICStubCompiler
if (pic.hasTypeCheck()) {
Repatcher repatcher(f.jit());
repatcher.relink(pic.fastPathStart.jumpAtOffset(GETPROP_INLINE_TYPE_GUARD), start);
repatcher.relink(pic.getPropLabels().getInlineTypeJump(pic.fastPathStart), start);
}
disable("generated string length stub");
@ -1064,11 +1046,11 @@ class GetPropCompiler : public PICStubCompiler
{
spew("patch", "inline");
Repatcher repatcher(f.jit());
GetPropLabels &labels = pic.getPropLabels();
int32 offset;
if (!holder->hasSlotsArray()) {
JSC::CodeLocationInstruction istr;
istr = pic.fastPathRejoin.instructionAtOffset(dslotsLoad());
CodeLocationInstruction istr = labels.getDslotsLoad(pic.fastPathRejoin);
repatcher.repatchLoadPtrToLEA(istr);
//
@ -1086,15 +1068,8 @@ class GetPropCompiler : public PICStubCompiler
offset = shape->slot * sizeof(Value);
}
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(shapeOffs), obj->shape());
GetPropLabels &labels = pic.getPropLabels();
#if defined JS_NUNBOX32
repatcher.repatch(labels.getTypeLoad(pic.fastPathRejoin), offset + 4);
repatcher.repatch(labels.getDataLoad(pic.fastPathRejoin), offset);
#elif defined JS_PUNBOX64
repatcher.repatch(labels.getValueLoad(pic.fastPathRejoin), offset);
#endif
repatcher.repatch(labels.getInlineShapeData(pic.getFastShapeGuard()), obj->shape());
repatcher.patchAddressOffsetForValueLoad(labels.getValueLoad(pic.fastPathRejoin), offset);
pic.inlinePathPatched = true;
@ -1108,13 +1083,14 @@ class GetPropCompiler : public PICStubCompiler
Assembler masm;
Label start;
Jump shapeGuard;
Jump shapeGuardJump;
DataLabel32 shapeGuardData;
Jump argsLenGuard;
bool setStubShapeOffset = true;
if (obj->isDenseArray()) {
start = masm.label();
shapeGuard = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
shapeGuardJump = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
/*
* No need to assert validity of GETPROP_STUB_SHAPE_JUMP in this case:
@ -1130,13 +1106,12 @@ class GetPropCompiler : public PICStubCompiler
}
start = masm.label();
shapeGuard = masm.branch32_force32(Assembler::NotEqual, pic.shapeReg,
Imm32(obj->shape()));
shapeGuardJump = masm.branch32WithPatch(Assembler::NotEqual, pic.shapeReg,
Imm32(obj->shape()), shapeGuardData);
}
Label stubShapeJumpLabel = masm.label();
if (!shapeMismatches.append(shapeGuard))
if (!shapeMismatches.append(shapeGuardJump))
return error();
RegisterID holderReg = pic.objReg;
@ -1204,12 +1179,12 @@ class GetPropCompiler : public PICStubCompiler
// the offsets are different.
int shapeGuardJumpOffset;
if (pic.stubsGenerated)
shapeGuardJumpOffset = pic.getPropLabels().getStubShapeJump();
shapeGuardJumpOffset = pic.getPropLabels().getStubShapeJumpOffset();
else
shapeGuardJumpOffset = pic.shapeGuard + inlineShapeJump();
shapeGuardJumpOffset = pic.shapeGuard + pic.getPropLabels().getInlineShapeJumpOffset();
repatcher.relink(label.jumpAtOffset(shapeGuardJumpOffset), cs);
if (lastStubSecondShapeGuard)
repatcher.relink(label.jumpAtOffset(lastStubSecondShapeGuard), cs);
if (int secondGuardOffset = getLastStubSecondShapeGuard())
repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs);
}
LookupStatus update()
@ -1227,7 +1202,9 @@ class GetPropCompiler : public PICStubCompiler
return generateStub(getprop.holder, getprop.shape);
}
};
#endif
#if defined JS_POLYIC_NAME
class ScopeNameCompiler : public PICStubCompiler
{
JSObject *scopeChain;
@ -1543,7 +1520,9 @@ class ScopeNameCompiler : public PICStubCompiler
return true;
}
};
#endif
#if defined JS_POLYIC_BIND
class BindNameCompiler : public PICStubCompiler
{
JSObject *scopeChain;
@ -1668,7 +1647,9 @@ class BindNameCompiler : public PICStubCompiler
return obj;
}
};
#endif
#if defined JS_POLYIC_GETPROP
static void JS_FASTCALL
DisabledLengthIC(VMFrame &f, ic::PICInfo *pic)
{
@ -1750,7 +1731,9 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
THROW();
f.regs.sp[-1] = v;
}
#endif
#if defined JS_POLYIC_SETPROP
template <JSBool strict>
static void JS_FASTCALL
DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
@ -1797,7 +1780,9 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic)
Value rval = f.regs.sp[-1];
stub(f, pic);
}
#endif
#if defined JS_POLYIC_GETPROP
static void JS_FASTCALL
DisabledCallPropIC(VMFrame &f, ic::PICInfo *pic)
{
@ -1914,7 +1899,9 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
}
#endif
}
#endif
#if defined JS_POLYIC_NAME
static void JS_FASTCALL
DisabledNameIC(VMFrame &f, ic::PICInfo *pic)
{
@ -1963,7 +1950,9 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
THROW();
f.regs.sp[0] = rval;
}
#endif
#if defined JS_POLYIC_BIND
static void JS_FASTCALL
DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
{
@ -1994,6 +1983,7 @@ ic::BindName(VMFrame &f, ic::PICInfo *pic)
f.regs.sp[0].setObject(*obj);
}
#endif
bool
BaseIC::isCallOp()
@ -2032,6 +2022,7 @@ BaseIC::shouldUpdate(JSContext *cx)
return true;
}
#if defined JS_POLYIC_ELEM
static void JS_FASTCALL
DisabledGetElem(VMFrame &f, ic::GetElementIC *ic)
{
@ -2739,6 +2730,7 @@ ic::SetElement(VMFrame &f, ic::SetElementIC *ic)
template void JS_FASTCALL ic::SetElement<true>(VMFrame &f, SetElementIC *ic);
template void JS_FASTCALL ic::SetElement<false>(VMFrame &f, SetElementIC *ic);
#endif /* JS_POLYIC_ELEM */
void
JITScript::purgePICs()
@ -2751,21 +2743,29 @@ JITScript::purgePICs()
for (uint32 i = 0; i < nPICs; i++) {
ic::PICInfo &pic = pics[i];
switch (pic.kind) {
#ifdef JS_POLYIC_SETPROP
case ic::PICInfo::SET:
case ic::PICInfo::SETMETHOD:
SetPropCompiler::reset(repatcher, pic);
break;
#endif
#ifdef JS_POLYIC_NAME
case ic::PICInfo::NAME:
case ic::PICInfo::XNAME:
ScopeNameCompiler::reset(repatcher, pic);
break;
#endif
#ifdef JS_POLYIC_BIND
case ic::PICInfo::BIND:
BindNameCompiler::reset(repatcher, pic);
break;
#endif
#ifdef JS_POLYIC_GETPROP
case ic::PICInfo::CALL: /* fall-through */
case ic::PICInfo::GET:
GetPropCompiler::reset(repatcher, pic);
break;
#endif
default:
JS_NOT_REACHED("Unhandled PIC kind");
break;
@ -2773,10 +2773,12 @@ JITScript::purgePICs()
pic.reset();
}
#if defined JS_POLYIC_ELEM
for (uint32 i = 0; i < nGetElems; i++)
getElems[i].purge(repatcher);
for (uint32 i = 0; i < nSetElems; i++)
setElems[i].purge(repatcher);
#endif
}
void

View File

@ -78,15 +78,6 @@ static const int32 SETPROP_INLINE_STORE_VALUE = 0; //asserted
static const int32 SETPROP_INLINE_SHAPE_JUMP = 6; //asserted
#endif
/* GetPropCompiler */
#if defined JS_CPU_X86
static const int32 GETPROP_INLINE_TYPE_GUARD = 12; //asserted
static const int32 GETPROP_INLINE_SHAPE_JUMP = 12; //asserted
#elif defined JS_CPU_X64
static const int32 GETPROP_INLINE_TYPE_GUARD = 19; //asserted
static const int32 GETPROP_INLINE_SHAPE_JUMP = 6; //asserted
#endif
/* ScopeNameCompiler */
#if defined JS_CPU_X86
static const int32 SCOPENAME_JUMP_OFFSET = 5; //asserted
@ -450,6 +441,15 @@ struct PICInfo : public BasePolyIC {
return CodeLocationLabel(lastStubStart.start());
}
CodeLocationLabel getFastShapeGuard() {
return fastPathStart.labelAtOffset(shapeGuard);
}
CodeLocationLabel getSlowTypeCheck() {
JS_ASSERT(isGet());
return slowPathStart.labelAtOffset(u.get.typeCheckOffset);
}
// Return a JITCode block corresponding to the code memory to attach a
// new stub to.
JITCode lastCodeBlock(JITScript *jit) {