Implement fast allocation path for objects in HHIR

Tx64 generates a fast path for allocating objects of a
persistent class that inlines a bunch of the helper work into the TC.
This diff is basically a translation of that path into HHIR codegen.
Esse commit está contido em:
Bert Maher
2013-05-09 17:28:46 -07:00
commit de Sara Golemon
commit 083b028a3d
6 arquivos alterados com 152 adições e 8 exclusões
+6
Ver Arquivo
@@ -821,6 +821,12 @@ D:Obj = AllocObj S1:Cls
Allocates a new object of class S1.
D:Obj = AllocObjFast S1:ConstCls
Allocate a new object of class S1 where S1 is persistent and able to
be instantiated (i.e., S1 is not an abstract class, interface, or
trait).
NewArray
NewTuple
+3 -3
Ver Arquivo
@@ -320,7 +320,7 @@ class PreClass : public AtomicCountable {
}
BuiltinCtorFunction instanceCtor() const { return m_InstanceCtor; }
int builtinPropSize() { return m_builtinPropSize; }
int builtinPropSize() const { return m_builtinPropSize; }
void prettyPrint(std::ostream& out) const;
@@ -734,8 +734,8 @@ public:
// ObjectData attributes, to be set during Instance initialization.
int getODAttrs() const { return m_ODAttrs; }
int builtinPropSize() { return m_builtinPropSize; }
BuiltinCtorFunction instanceCtor() { return m_InstanceCtor; }
int builtinPropSize() const { return m_builtinPropSize; }
BuiltinCtorFunction instanceCtor() const { return m_InstanceCtor; }
// Interfaces this class declares in its "implements" clause.
const std::vector<ClassPtr>& declInterfaces() const {
+117
Ver Arquivo
@@ -3286,6 +3286,123 @@ Instance* createClHelper(Class* cls, int numArgs, ActRec* ar, TypedValue* sp) {
return static_cast<c_Closure*>(newObj)->init(numArgs, ar, sp);
}
void CodeGenerator::cgAllocObjFast(IRInstruction* inst) {
const Class* cls = inst->getSrc(0)->getValClass();
auto dstReg = m_regs[inst->getDst()].getReg();
// First, make sure our property init vectors are all set up
bool props = cls->pinitVec().size() > 0;
bool sprops = cls->numStaticProperties() > 0;
assert((props || sprops) == cls->needInitialization());
if (cls->needInitialization()) {
if (props) {
cls->initPropHandle();
m_as.testq(-1, rVmTl[cls->propHandle()]);
unlikelyIfBlock(CC_Z, [&] (Asm& a) {
cgCallHelper(a,
(TCA)getMethodPtr(&Class::initProps),
InvalidReg,
kSyncPoint,
ArgGroup(m_regs).imm((uint64_t)cls));
});
}
if (sprops) {
cls->initSPropHandle();
m_as.testq(-1, rVmTl[cls->sPropHandle()]);
unlikelyIfBlock(CC_Z, [&] (Asm& a) {
cgCallHelper(a,
(TCA)getMethodPtr(&Class::initSProps),
InvalidReg,
kSyncPoint,
ArgGroup(m_regs).imm((uint64_t)cls));
});
}
}
// Next, allocate the object
if (cls->instanceCtor()) {
cgCallHelper(m_as,
(TCA)cls->instanceCtor(),
dstReg,
kSyncPoint,
ArgGroup(m_regs).imm((uint64_t)cls));
} else {
size_t size = Instance::sizeForNProps(cls->numDeclProperties());
int allocator = object_alloc_size_to_index(size);
assert(allocator != -1);
cgCallHelper(m_as,
(TCA)getMethodPtr(&Instance::newInstanceRaw),
dstReg,
kSyncPoint,
ArgGroup(m_regs).imm((uint64_t)cls).imm(allocator));
}
// Set the attributes, if any
int odAttrs = cls->getODAttrs();
if (odAttrs) {
// o_attribute is 16 bits but the fact that we're or-ing a mask makes it ok
assert(!(odAttrs & 0xffff0000));
m_as.orq(odAttrs, dstReg[ObjectData::attributeOff()]);
}
// Initialize the properties
size_t nProps = cls->numDeclProperties();
if (nProps > 0) {
m_as.push(dstReg);
m_as.subq(8, reg::rsp);
if (cls->pinitVec().size() == 0) {
// Fast case: copy from a known address in the Class
ArgGroup args = ArgGroup(m_regs)
.addr(dstReg, sizeof(ObjectData) + cls->builtinPropSize())
.imm(int64_t(&cls->declPropInit()[0]))
.imm(cellsToBytes(nProps));
cgCallHelper(m_as,
(TCA)memcpy,
InvalidReg,
kNoSyncPoint,
args);
} else {
// Slower case: we have to load the src address from the targetcache
auto rPropData = rScratch;
// Load the Class's propInitVec from the targetcache
m_as.loadq(rVmTl[cls->propHandle()], rPropData);
// propData holds the PropInitVec. We want &(*propData)[0]
m_as.loadq(rPropData[Class::PropInitVec::dataOff()], rPropData);
if (!cls->hasDeepInitProps()) {
ArgGroup args = ArgGroup(m_regs)
.addr(dstReg, sizeof(ObjectData) + cls->builtinPropSize())
.reg(rPropData)
.imm(cellsToBytes(nProps));
cgCallHelper(m_as,
(TCA)memcpy,
InvalidReg,
kNoSyncPoint,
args);
} else {
ArgGroup args = ArgGroup(m_regs)
.addr(dstReg, sizeof(ObjectData) + cls->builtinPropSize())
.reg(rPropData)
.imm(nProps);
cgCallHelper(m_as,
(TCA)deepInitHelper,
InvalidReg,
kNoSyncPoint,
args);
}
}
m_as.addq(8, reg::rsp);
m_as.pop(dstReg);
}
if (cls->callsCustomInstanceInit()) {
// callCustomInstanceInit returns the instance in rax
cgCallHelper(m_as,
(TCA)getMethodPtr(&Instance::callCustomInstanceInit),
dstReg,
kSyncPoint,
ArgGroup(m_regs).reg(dstReg));
}
}
void CodeGenerator::cgInlineCreateCont(IRInstruction* inst) {
auto const& data = *inst->getExtra<InlineCreateCont>();
auto const helper = data.origFunc->isMethod()
@@ -1488,11 +1488,10 @@ void HhbcTranslator::emitFPushActRec(SSATmp* func,
}
void HhbcTranslator::emitFPushCtorCommon(SSATmp* cls,
SSATmp* obj,
const Func* func,
int32_t numParams) {
SSATmp* obj = gen(IncRef, gen(AllocObj, cls));
push(obj);
SSATmp* fn = nullptr;
if (func) {
fn = cns(func);
@@ -1507,7 +1506,14 @@ void HhbcTranslator::emitFPushCtorCommon(SSATmp* cls,
void HhbcTranslator::emitFPushCtor(int32_t numParams) {
SSATmp* cls = popA();
exceptionBarrier();
emitFPushCtorCommon(cls, nullptr, numParams);
SSATmp* obj = gen(IncRef, gen(AllocObj, cls));
emitFPushCtorCommon(cls, obj, nullptr, numParams);
}
bool
canInstantiateClass(const Class* cls) {
return cls &&
!(cls->attrs() & (AttrAbstract | AttrInterface | AttrTrait));
}
void HhbcTranslator::emitFPushCtorD(int32_t numParams, int32_t classNameStrId) {
@@ -1517,6 +1523,9 @@ void HhbcTranslator::emitFPushCtorD(int32_t numParams, int32_t classNameStrId) {
const Class* cls = Unit::lookupUniqueClass(className);
bool uniqueCls = classIsUnique(cls);
bool persistentCls = classIsPersistent(cls);
bool canInstantiate = canInstantiateClass(cls);
bool fastAlloc = !RuntimeOption::EnableObjDestructCall &&
persistentCls && canInstantiate;
const Func* func = uniqueCls ? cls->getCtor() : nullptr;
if (func && !(func->attrs() & AttrPublic)) {
@@ -1537,7 +1546,15 @@ void HhbcTranslator::emitFPushCtorD(int32_t numParams, int32_t classNameStrId) {
} else {
clss = gen(LdClsCached, cns(className));
}
emitFPushCtorCommon(clss, func, numParams);
SSATmp* obj = nullptr;
if (fastAlloc) {
obj = gen(IncRef, gen(AllocObjFast, clss));
} else {
obj = gen(IncRef, gen(AllocObj, clss));
}
emitFPushCtorCommon(clss, obj, func, numParams);
}
/*
@@ -239,7 +239,10 @@ struct HhbcTranslator {
const StringData* methName);
void emitFPushCtorD(int32_t numParams, int32_t classNameStrId);
void emitFPushCtor(int32_t numParams);
void emitFPushCtorCommon(SSATmp* cls, const Func* func, int32_t numParams);
void emitFPushCtorCommon(SSATmp* cls,
SSATmp* obj,
const Func* func,
int32_t numParams);
void emitCreateCl(int32_t numParams, int32_t classNameStrId);
void emitFCallArray(const Offset pcOffset, const Offset after);
void emitFCall(uint32_t numParams,
+1
Ver Arquivo
@@ -312,6 +312,7 @@ O(LdSwitchStrIndex, D(Int), S(Str) S(Int) S(Int), CRc|N) \
O(LdSwitchObjIndex, D(Int), S(Obj) S(Int) S(Int), CRc|N|Er) \
O(JmpSwitchDest, ND, S(Int), T|E) \
O(AllocObj, D(Obj), S(Cls), N) \
O(AllocObjFast, D(Obj), C(Cls), N) \
O(LdClsCtor, D(Func), S(Cls), C|Er|N) \
O(CreateCl, D(Obj), C(Cls) \
C(Int) \