convert init_closure into assembly

I got to do a few optimizations:

* burn in the number of use vars
* not write out uninitialized use vars
* use the staticness of the method as a hint for the incRef
Esse commit está contido em:
ptarjan
2013-03-25 01:12:33 -07:00
commit de Sara Golemon
commit 6e8eb46729
4 arquivos alterados com 68 adições e 13 exclusões
+4
Ver Arquivo
@@ -99,6 +99,10 @@ public:
HphpArray* getStaticLocals();
TypedValue* getUseVars() { return propVec(); }
int getNumUseVars() { return m_cls->numDeclProperties(); }
static size_t funcOffset() { return offsetof(c_Closure, m_func); }
static size_t thisOffset() { return offsetof(c_Closure, m_thisOrClass); }
protected:
virtual bool php_sleep(Variant &ret);
private:
+4
Ver Arquivo
@@ -49,6 +49,10 @@ public:
HphpArray* getStaticLocals();
TypedValue* getUseVars() { return propVec(); }
int getNumUseVars() { return m_cls->numDeclProperties(); }
static size_t funcOffset() { return offsetof(c_Closure, m_func); }
static size_t thisOffset() { return offsetof(c_Closure, m_thisOrClass); }
protected:
virtual bool php_sleep(Variant &ret);
private:
+59 -13
Ver Arquivo
@@ -897,6 +897,11 @@ void TranslatorX64::prepareCallSaveRegs() {
void
TranslatorX64::emitIncRef(PhysReg base, DataType dtype) {
emitIncRef(a, base, dtype);
}
void
TranslatorX64::emitIncRef(X64Assembler &a, PhysReg base, DataType dtype) {
if (!IS_REFCOUNTED_TYPE(dtype) && dtype != KindOfInvalid) {
return;
}
@@ -2294,12 +2299,62 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
// Args are kosher. Frame linkage: set fp = ar.
a. mov_reg64_reg64(rStashedAR, rVmFp);
int numLocals = numParams;
if (func->isClosureBody()) {
int numUseVars = func->cls()->numDeclProperties();
emitLea(a, rVmFp, -cellsToBytes(numParams), rVmSp);
PhysReg rClosure = rcx;
a. loadq(rVmFp[AROFF(m_this)], rClosure);
// Swap in the $this or late bound class
a. loadq(rClosure[c_Closure::thisOffset()], rScratch);
a. storeq(rScratch, rVmFp[AROFF(m_this)]);
a. shrq(1, rScratch);
if (func->attrs() & AttrStatic) {
UnlikelyIfBlock ifRealThis(CC_NBE, a, astubs);
astubs.shlq(1, rScratch);
emitIncRef(astubs, rScratch, KindOfObject);
} else {
JccBlock<CC_BE> ifRealThis(a);
a.shlq(1, rScratch);
emitIncRef(rScratch, KindOfObject);
}
// Put in the correct context
a. loadq(rClosure[c_Closure::funcOffset()], rScratch);
a. storeq(rScratch, rVmFp[AROFF(m_func)]);
// Copy in all the use vars
int baseUVOffset = sizeof(ObjectData) + func->cls()->builtinPropSize();
for (int i = 0; i < numUseVars + 1; i++) {
int spOffset = -cellsToBytes(i+1);
if (i == 0) {
// The closure is the first local.
// We don't incref because it used to be $this
// and now it is a local, so they cancel out
emitStoreTypedValue(a, KindOfObject, rClosure, spOffset, rVmSp);
continue;
}
int uvOffset = baseUVOffset + cellsToBytes(i-1);
emitCopyTo(a, rClosure, uvOffset, rVmSp, spOffset, rScratch);
emitIncRefGenericRegSafe(rVmSp, spOffset, rScratch);
}
numLocals += numUseVars + 1;
}
// We're in the callee frame; initialize locals. Unroll the loop all
// the way if there are a modest number of locals to update;
// otherwise, do it in a compact loop. If we're in a generator body,
// named locals will be initialized by UnpackCont so we can leave
// them alone here.
int numUninitLocals = func->numLocals() - numParams;
int numUninitLocals = func->numLocals() - numLocals;
assert(numUninitLocals >= 0);
if (numUninitLocals > 0 && !func->isGenerator()) {
SpaceRecorder sr("_InitializeLocals", a);
@@ -2312,7 +2367,7 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
// rVmFp + rcx points to the count/type fields of the TypedValue we're
// about to write to.
int loopStart = -func->numLocals() * sizeof(TypedValue) + TVOFF(m_type);
int loopEnd = -numParams * sizeof(TypedValue) + TVOFF(m_type);
int loopEnd = -numLocals * sizeof(TypedValue) + TVOFF(m_type);
emitImmReg(a, loopStart, loopReg);
emitImmReg(a, KindOfUninit, rdx);
@@ -2329,10 +2384,10 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
} else {
PhysReg base;
int disp, k;
if (numParams < func->numLocals()) {
if (numLocals < func->numLocals()) {
a.xorl (eax, eax);
}
for (k = numParams; k < func->numLocals(); ++k) {
for (k = numLocals; k < func->numLocals(); ++k) {
locToRegDisp(Location(Location::Local, k), &base, &disp);
emitStoreTVType(a, eax, base[disp + TVOFF(m_type)]);
}
@@ -2346,15 +2401,6 @@ TranslatorX64::emitPrologue(Func* func, int nPassed) {
}
SrcKey funcBody(func, destPC);
if (UNLIKELY(func->isClosureBody())) {
// It is a bit of a waste having the use_vars being emitted as
// uninitialized first then overwritten here, but knowing how to change
// numParams at translation time is hard
a. mov_reg64_reg64(rVmFp, argNumToRegName[0]);
emitLea(a, rVmFp, -cellsToBytes(numParams), argNumToRegName[1]);
emitCall(a, TCA(init_closure));
}
// Move rVmSp to the right place: just past all locals
int frameCells = func->numSlotsInFrame();
if (func->isGenerator()) {
@@ -226,6 +226,7 @@ private:
}
Asm& getAsmFor(TCA addr) { return asmChoose(addr, a, astubs); }
void emitIncRef(X64Assembler &a, PhysReg base, DataType dtype);
void emitIncRef(PhysReg base, DataType);
void emitIncRefGenericRegSafe(PhysReg base, int disp, PhysReg tmp);
void emitIncRefGeneric(PhysReg base, int disp = 0);