Inline object constructors

This should automatically handle the case when we had
a generated 86pinit constructor.
Esse commit está contido em:
aravind
2013-05-02 20:36:23 -07:00
commit de Sara Golemon
commit b558f6f118
13 arquivos alterados com 83 adições e 134 exclusões
+9 -14
Ver Arquivo
@@ -665,6 +665,11 @@ D:Cls = LdClsCctx S0:Cctx
Loads into D the class representing the current context. Extracts
the class from the S0, which is a context class.
D:Func = LdClsCtor S0:Cls
Loads into D the constructor of class S0. If the constructor cannot
be called from the current context, raise an error.
D:Home = LdHome S0:StkPtr S1:ConstInt
Logically packages the location of a pointer into the VM stack and
@@ -821,19 +826,9 @@ D:StkPtr = NewObj S0:ConstInt S1:Cls S2:StkPtr S3:FramePtr
S2 is the current stack pointer
S3 is the frame pointer of the current ActRec
D:StkPtr = NewObjCached S0:ConstInt S1:Str S2:StkPtr S3:FramePtr
D:Obj = AllocObj S1:Cls
Allocate a new object with class name S1, using a target cache
lookup. S1 is the string name of the class, other parameters are
the same as NewObj.
D:StkPtr = NewObjNoCtorCached S0:Str S1:StkPtr
Allocate a new object, which does not require a constructor call,
with class name S0, using a target cache lookup. Because no
constructor will be called this opcode does not allocate an ActRec.
Operand S0 is the name of the class, S1 is the current stack
pointer.
Allocate a new object of class S1.
NewArray
NewTuple
@@ -843,8 +838,8 @@ NewTuple
D:StkPtr = SpillFrame<numArgs,invName> S0:StkPtr
S1:FramePtr
S1:Func
S2:{Ctx|Class|Null}
S2:Func
S3:{Ctx|Class|Null}
Operands:
+9 -3
Ver Arquivo
@@ -143,13 +143,14 @@ void annotate(NormalizedInstruction* i) {
case OpFPushObjMethodD:
case OpFPushClsMethodD:
case OpFPushClsMethodF:
case OpFPushCtorD:
case OpFPushFuncD: {
// When we push predictable action records, we can use a simpler
// translation for their corresponding FCall.
const StringData* className = nullptr;
const StringData* funcName = nullptr;
if (i->op() == OpFPushFuncD) {
funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA);
funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA);
} else if (i->op() == OpFPushObjMethodD) {
if (i->inputs[0]->valueType() != KindOfObject) break;
const Class* cls = i->inputs[0]->rtt.valueClass();
@@ -166,10 +167,15 @@ void annotate(NormalizedInstruction* i) {
if (!cls) break;
funcName = i->inputs[1]->rtt.valueString();
className = cls->name();
} else {
assert(i->op() == OpFPushClsMethodD);
} else if (i->op() == OpFPushClsMethodD) {
funcName = curUnit()->lookupLitstrId(i->imm[1].u_SA);
className = curUnit()->lookupLitstrId(i->imm[2].u_SA);
} else {
assert(i->op() == OpFPushCtorD);
className = curUnit()->lookupLitstrId(i->imm[1].u_SA);
const Class* cls = Unit::lookupUniqueClass(className);
if (!cls) break;
funcName = cls->getCtor()->name();
}
assert(funcName->isStatic());
recordActRecPush(*i, curUnit(), funcName, className,
+17 -73
Ver Arquivo
@@ -351,6 +351,7 @@ CALL_OPCODE(FillContLocals)
CALL_OPCODE(NewArray)
CALL_OPCODE(NewTuple)
CALL_OPCODE(NewObj)
CALL_OPCODE(LdClsCtor);
CALL_OPCODE(CreateCl)
CALL_OPCODE(PrintStr)
CALL_OPCODE(PrintInt)
@@ -3228,6 +3229,17 @@ void CodeGenerator::cgSpillFrame(IRInstruction* inst) {
spOffset);
}
const Func* loadClassCtor(Class* cls) {
const Func* f = cls->getCtor();
if (UNLIKELY(!(f->attrs() & AttrPublic))) {
VMRegAnchor _;
UNUSED MethodLookup::LookupResult res =
g_vmContext->lookupCtorMethod(f, cls, true /*raise*/);
assert(res == MethodLookup::MethodFoundWithThis);
}
return f;
}
HOT_FUNC_VM ActRec*
irNewInstanceHelper(Class* cls,
int numArgs,
@@ -3243,28 +3255,6 @@ irNewInstanceHelper(Class* cls,
return ar;
}
HOT_FUNC_VM static ActRec*
irNewInstanceHelperCached(CacheHandle cacheHandle,
const StringData* clsName,
int numArgs,
Cell* sp,
ActRec* prevAr) {
Cell* obj = sp - 1; // this is where the newly allocated object will go
ActRec* ar = (ActRec*)(uintptr_t(obj) - sizeof(ActRec));
Instance* newObj = newInstanceHelperCached(
static_cast<Class**>(handleToPtr(cacheHandle)),
clsName,
numArgs,
ar,
prevAr
);
// store obj into the stack
obj->m_data.pobj = newObj;
obj->m_type = KindOfObject;
return ar;
}
static inline ALWAYS_INLINE Class* getKnownClass(Class** classCache,
const StringData* clsName) {
Class* cls = *classCache;
@@ -3283,59 +3273,13 @@ Instance* createClHelper(Class* cls, int numArgs, ActRec* ar, TypedValue* sp) {
return static_cast<c_Closure*>(newObj)->init(numArgs, ar, sp);
}
static Cell*
newInstanceHelperNoCtorCached(CacheHandle cacheHandle,
const StringData* clsName,
Cell* sp) {
Cell* obj = sp - 1; // this is where the newly allocated object will go
void CodeGenerator::cgAllocObj(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* cls = inst->getSrc(0);
Class* cls = getKnownClass((Class**)handleToPtr(cacheHandle), clsName);
Instance* newObj = newInstance(cls);
newObj->incRefCount();
// store obj into the stack
obj->m_data.pobj = newObj;
obj->m_type = KindOfObject;
return obj;
}
void CodeGenerator::cgNewObjCached(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* numParams = inst->getSrc(0);
SSATmp* clsName = inst->getSrc(1);
SSATmp* sp = inst->getSrc(2);
SSATmp* fp = inst->getSrc(3);
assert(clsName->isString());
const StringData* classNameString = clsName->getValStr();
CacheHandle ch = allocKnownClass(classNameString);
ActRec* (*helper)(CacheHandle, const StringData*, int, Cell*, ActRec*)
= irNewInstanceHelperCached;
Instance* (*helper)(Class*) = newInstance;
ArgGroup args;
args.imm(ch)
.ssa(clsName)
.ssa(numParams)
.ssa(sp)
.ssa(fp);
cgCallHelper(m_as, (TCA)helper, dst, kSyncPoint, args);
}
void CodeGenerator::cgNewObjNoCtorCached(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* clsName = inst->getSrc(0);
SSATmp* sp = inst->getSrc(1);
assert(clsName->isString());
const StringData* classNameString = clsName->getValStr();
CacheHandle ch = allocKnownClass(classNameString);
Cell* (*helper)(CacheHandle, const StringData*, Cell*) =
newInstanceHelperNoCtorCached;
ArgGroup args;
args.imm(ch)
.ssa(clsName)
.ssa(sp);
args.ssa(cls);
cgCallHelper(m_as,
(TCA)helper,
dst,
+2
Ver Arquivo
@@ -487,6 +487,8 @@ private:
std::vector<ArgDesc> m_args;
};
const Func* loadClassCtor(Class* cls);
ActRec* irNewInstanceHelper(Class* cls,
int numArgs,
Cell* sp,
+38 -18
Ver Arquivo
@@ -1499,27 +1499,43 @@ void HhbcTranslator::emitFPushCtor(int32_t numParams) {
void HhbcTranslator::emitFPushCtorD(int32_t numParams, int32_t classNameStrId) {
const StringData* className = lookupStringId(classNameStrId);
exceptionBarrier();
m_fpiStack.emplace(nullptr, 0);
// If constructor is the generated 86ctor, no need to call it.
if (RuntimeOption::RepoAuthoritative &&
numParams == 0) {
const Class* cls = Unit::lookupUniqueClass(className);
if (cls &&
(cls->attrs() & AttrUnique) &&
Func::isSpecial(cls->getCtor()->name())) {
// This optimization is only safe if the FCall is in the same
// tracelet. Luckily that is always the case: since this
// optimization only applies when numParams==0, there will be
// nothing between the FPushCtorD and the FCall.
gen(NewObjNoCtorCached, cns(className), m_tb->getSp());
push(m_tb->genDefNull());
return;
const Class* cls = Unit::lookupUniqueClass(className);
bool uniqueCls = classIsUnique(cls);
bool persistentCls = classIsPersistent(cls);
const Func* func = uniqueCls ? cls->getCtor() : nullptr;
if (func && !(func->attrs() & AttrPublic)) {
Class* ctx = arGetContextClass(curFrame());
if (!ctx) {
func = nullptr;
} else if (ctx != cls) {
if ((func->attrs() & AttrPrivate) ||
!(ctx->classof(cls) || cls->classof(ctx))) {
func = nullptr;
}
}
}
gen(
NewObjCached, cns(numParams), cns(className), m_tb->getSp(), m_tb->getFp()
);
SSATmp* clss = nullptr;
if (persistentCls) {
clss = cns(cls);
} else {
clss = gen(LdClsCached, cns(className));
}
SSATmp* obj = gen(IncRef, gen(AllocObj, clss));
push(obj);
SSATmp* fn = nullptr;
if (func) {
fn = cns(func);
} else {
fn = gen(LdClsCtor, clss);
}
SSATmp* obj2 = gen(IncRef, obj);
int32_t numArgsAndCtorFlag = numParams | (1 << 31);
emitFPushActRec(fn, obj2, numArgsAndCtorFlag, nullptr);
}
/*
@@ -1885,6 +1901,10 @@ void HhbcTranslator::emitRetFromInlined(Type type) {
* value so stack offsets are properly tracked.
*/
m_tb->endInlining();
// after end of inlining, m_stackDeficit should be set to
// 0, and eval stack should be empty
assert(m_evalStack.numCells() == 0);
m_stackDeficit = 0;
FTRACE(1, "]]] end inlining: {}\n", getCurFunc()->fullName()->data());
m_bcStateStack.pop_back();
m_fpiStack.pop();
+2 -6
Ver Arquivo
@@ -315,12 +315,8 @@ O(NewObj, D(StkPtr), S(Cls) \
C(Int) \
S(StkPtr) \
S(FramePtr), E|Mem|N|Refs|PRc|Er) \
O(NewObjCached, D(StkPtr), C(Int) \
S(Str) \
S(StkPtr) \
S(FramePtr), E|Mem|N|Refs|PRc|Er) \
O(NewObjNoCtorCached, D(StkPtr), S(Str) \
S(StkPtr), E|Mem|N|Refs|PRc|Er) \
O(AllocObj, D(Obj), S(Cls), N) \
O(LdClsCtor, D(Func), S(Cls), C|Er|N) \
O(CreateCl, D(Obj), C(Cls) \
C(Int) \
S(FramePtr) \
@@ -370,8 +370,6 @@ void LinearScan::allocRegToInstruction(InstructionList::iterator it) {
opc == ExceptionBarrier ||
opc == RetAdjustStack ||
opc == NewObj ||
opc == NewObjCached ||
opc == NewObjNoCtorCached ||
opc == InterpOne ||
opc == GenericRetDecRefs ||
opc == GuardStk ||
@@ -135,6 +135,8 @@ static CallMap s_callMap({
{{SSA, 0}, {SSA, 1}}},
{NewObj, (TCA)irNewInstanceHelper, DSSA, SSync,
{{SSA, 0}, {SSA, 1}, {SSA, 2}, {SSA, 3}}},
{LdClsCtor, (TCA)loadClassCtor, DSSA, SSync,
{{SSA, 0}}},
{PrintStr, (TCA)print_string, DNone, SNone, {{SSA, 0}}},
{PrintInt, (TCA)print_int, DNone, SNone, {{SSA, 0}}},
{PrintBool, (TCA)print_boolean, DNone, SNone, {{SSA, 0}}},
@@ -131,7 +131,6 @@ StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
index - kNumActRecCells);
case NewObj:
case NewObjCached:
if (index == kNumActRecCells) {
// newly allocated object, which we unfortunately don't have any
// kind of handle to :-(
@@ -142,12 +141,6 @@ StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
// NewObj pushes an object and an ActRec
index - (1 + kNumActRecCells));
case NewObjNoCtorCached:
if (index == 0) {
return StackValueInfo { Type::Obj };
}
return getStackValue(sp->inst()->getSrc(1), index - 1);
default:
{
// Assume it's a vector instruction. This will assert in
@@ -396,9 +389,6 @@ SSATmp* Simplifier::simplifyCall(IRInstruction* inst) {
}
SSATmp* sp = spillStack->getSrc(0);
if (sp->inst()->op() == NewObjNoCtorCached) {
inst->convertToNop();
}
int baseOffset = spillStack->getSrc(1)->getValInt() -
spillValueCells(spillStack);
auto const numSpillSrcs = spillVals.size();
@@ -478,17 +478,11 @@ void TraceBuilder::updateTrackedState(IRInstruction* inst) {
break;
case NewObj:
case NewObjCached:
m_spValue = inst->getDst();
// new obj leaves the new object and an actrec on the stack
m_spOffset += kNumActRecCells + 1;
break;
case NewObjNoCtorCached:
m_spValue = inst->getDst();
m_spOffset += 1;
break;
case InterpOne: {
m_spValue = inst->getDst();
int64_t stackAdjustment = inst->getSrc(3)->getValInt();
+1 -1
Ver Arquivo
@@ -258,7 +258,7 @@ struct IfCountNotStatic {
}
};
inline static bool
bool
classIsPersistent(const Class* cls) {
return RuntimeOption::RepoAuthoritative &&
cls &&
@@ -1199,6 +1199,7 @@ void dumpTranslationInfo(const Tracelet& t, TCA postGuards);
bool classIsUnique(const Class* cls);
bool classIsUniqueOrCtxParent(const Class* cls);
bool classIsUniqueNormalClass(const Class* cls);
bool classIsPersistent(const Class* cls);
// SpaceRecorder is used in translator-x64.cpp and in hopt/irtranslator.cpp
// RAII logger for TC space consumption.
+2 -1
Ver Arquivo
@@ -3003,7 +3003,8 @@ static bool shouldAnalyzeCallee(const NormalizedInstruction* fcall) {
// Note: the IR assumes that $this is available in all inlined object
// methods, which will need to be updated when we support
// OpFPushClsMethod here.
if (pushOp != OpFPushFuncD && pushOp != OpFPushObjMethodD) {
if (pushOp != OpFPushFuncD && pushOp != OpFPushObjMethodD
&& pushOp != OpFPushCtorD) {
FTRACE(1, "analyzeCallee: push op ({}) was not supported\n",
opcodeToName(pushOp));
return false;