Extend the type system of the JIT (Type class) to allow for specialized Class instead of just Type::Obj

Allow RuntimeType to specify a more specific Type (by adding a Class*) and transfer that Class* to Type. Extended API to allow discovering when a Type is a subclass of Type::Obj
Esse commit está contido em:
Dario Russi
2013-05-15 17:43:01 -07:00
commit de Sara Golemon
commit e93120812a
7 arquivos alterados com 288 adições e 110 exclusões
+1
Ver Arquivo
@@ -125,6 +125,7 @@ StaticStr and CountedStr both appear as type String at the PHP level).
CountedArr ArrayData* where isStatic() == false
Arr ArrayData* {CountedArr|StaticArr}
Obj ObjectData*
Obj<Class> ObjectData* of the specific type Class
Counted {CountedStr|CountedArr|Obj|BoxedCell}
Cell {Null|Bool|Int|Dbl|Str|Arr|Obj}
+142 -71
Ver Arquivo
@@ -1653,38 +1653,68 @@ void CodeGenerator::cgOpGte(IRInstruction* inst) {
// Type check operators
///////////////////////////////////////////////////////////////////////////////
template<class OpndType>
ConditionCode CodeGenerator::emitTypeTest(Type type, OpndType src,
bool negate) {
// Overloads to put the ObjectData* into a register so emitTypeTest
// can cmp to the Class* expected by the specialized Type
// Nothing to do, return the register that contain the ObjectData already
Reg64 getObjectDataEnregistered(Asm& as, PhysReg dataSrc, Reg64 scratch) {
return dataSrc;
}
// Enregister the meoryRef so it can be used with an offset by the
// cmp instruction
Reg64 getObjectDataEnregistered(Asm& as,
MemoryRef dataSrc,
Reg64 scratch) {
as.loadq(dataSrc, scratch);
return scratch;
}
template<class Loc1, class Loc2, class JmpFn>
void CodeGenerator::emitTypeTest(Type type, Loc1 typeSrc, Loc2 dataSrc,
JmpFn doJcc) {
assert(!type.subtypeOf(Type::Cls));
ConditionCode cc;
if (type.isString()) {
emitTestTVType(m_as, KindOfStringBit, src);
emitTestTVType(m_as, KindOfStringBit, typeSrc);
cc = CC_NZ;
} else if (type.equals(Type::UncountedInit)) {
emitTestTVType(m_as, KindOfUncountedInitBit, src);
emitTestTVType(m_as, KindOfUncountedInitBit, typeSrc);
cc = CC_NZ;
} else if (type.equals(Type::Uncounted)) {
emitCmpTVType(m_as, KindOfRefCountThreshold, src);
emitCmpTVType(m_as, KindOfRefCountThreshold, typeSrc);
cc = CC_LE;
} else if (type.equals(Type::Cell)) {
emitCmpTVType(m_as, KindOfRef, src);
emitCmpTVType(m_as, KindOfRef, typeSrc);
cc = CC_L;
} else if (type.equals(Type::Gen)) {
return CC_None; // nothing to check
// nothing to check
return;
} else {
DataType dataType = type.toDataType();
assert(dataType == KindOfRef ||
(dataType >= KindOfUninit && dataType <= KindOfObject));
emitCmpTVType(m_as, dataType, src);
emitCmpTVType(m_as, dataType, typeSrc);
cc = CC_E;
}
return negate ? ccNegate(cc) : cc;
doJcc(cc);
if (type.strictSubtypeOf(Type::Obj)) {
// emit the specific class test
assert(type.getClass()->attrs() & AttrFinal);
auto reg = getObjectDataEnregistered(m_as, dataSrc, m_rScratch);
m_as.cmpq(type.getClass(), reg[ObjectData::getVMClassOffset()]);
doJcc(cc);
}
}
ConditionCode CodeGenerator::emitIsTypeTest(IRInstruction* inst, bool negate) {
template<class JmpFn>
void CodeGenerator::emitIsTypeTest(IRInstruction* inst, JmpFn doJcc) {
auto const src = inst->getSrc(0);
// punt if specialized object for now
if (inst->getTypeParam().strictSubtypeOf(Type::Obj)) {
CG_PUNT(IsType-SpecializedUnsupported);
}
if (inst->getTypeParam().equals(Type::Obj)) {
auto const srcReg = m_regs[src].getReg();
if (src->isA(Type::PtrToGen)) {
@@ -1707,57 +1737,79 @@ ConditionCode CodeGenerator::emitIsTypeTest(IRInstruction* inst, bool negate) {
srcReg[ObjectData::getVMClassOffset()]);
}
// At this point, the flags say "equal" if is_object is false.
return negate ? CC_E : CC_NE;
doJcc(CC_NE);
return;
}
if (src->isA(Type::PtrToGen)) {
PhysReg base = m_regs[src].getReg();
return emitTypeTest(inst->getTypeParam(), base[TVOFF(m_type)], negate);
emitTypeTest(inst->getTypeParam(), base[TVOFF(m_type)],
base[TVOFF(m_data)],
[&](ConditionCode cc) { doJcc(cc); });
return;
}
assert(src->isA(Type::Gen));
assert(!src->isConst());
PhysReg srcReg = m_regs[src].getReg(1); // type register
if (srcReg == InvalidReg) {
PhysReg typeSrcReg = m_regs[src].getReg(1); // type register
if (typeSrcReg == InvalidReg) {
CG_PUNT(IsType-KnownType);
}
return emitTypeTest(inst->getTypeParam(), srcReg, negate);
PhysReg dataSrcReg = m_regs[src].getReg(); // data register
emitTypeTest(inst->getTypeParam(), typeSrcReg, dataSrcReg,
[&](ConditionCode cc) { doJcc(cc); });
}
template<class MemLoc>
void CodeGenerator::emitTypeCheck(Type type, MemLoc mem, Block* taken) {
auto const negate = true;
auto const cc = emitTypeTest(type, mem, negate);
if (cc == CC_None) return;
emitFwdJcc(cc, taken);
template<class Loc>
void CodeGenerator::emitTypeCheck(Type type,
Loc typeSrc,
Loc dataSrc,
Block* taken) {
emitTypeTest(type, typeSrc, dataSrc,
[&](ConditionCode cc) {
emitFwdJcc(ccNegate(cc), taken);
});
}
template<class MemLoc>
void CodeGenerator::emitTypeGuard(Type type, MemLoc mem) {
auto const negate = true;
auto const cc = emitTypeTest(type, mem, negate);
if (cc == CC_None) return;
auto const destSK = SrcKey(getCurFunc(), m_curTrace->getBcOff());
auto const destSR = m_tx64->getSrcRec(destSK);
m_tx64->emitFallbackCondJmp(m_as, *destSR, cc);
template<class Loc>
void CodeGenerator::emitTypeGuard(Type type, Loc typeSrc, Loc dataSrc) {
emitTypeTest(type, typeSrc, dataSrc,
[&](ConditionCode cc) {
auto const destSK = SrcKey(getCurFunc(), m_curTrace->getBcOff());
auto const destSR = m_tx64->getSrcRec(destSK);
m_tx64->emitFallbackCondJmp(m_as, *destSR, ccNegate(cc));
});
}
void CodeGenerator::emitSetCc(IRInstruction* inst, ConditionCode cc) {
if (cc == CC_None) return;
m_as.setcc(cc, rbyte(m_regs[inst->getDst()].getReg()));
}
void CodeGenerator::cgIsTypeMemCommon(IRInstruction* inst, bool negate) {
emitSetCc(inst, emitIsTypeTest(inst, negate));
bool called = false; // check emitSetCc is called only once
emitIsTypeTest(inst,
[&](ConditionCode cc) {
assert(!called);
emitSetCc(inst, negate ? ccNegate(cc) : cc);
called = true;
});
}
void CodeGenerator::cgIsTypeCommon(IRInstruction* inst, bool negate) {
emitSetCc(inst, emitIsTypeTest(inst, negate));
bool called = false; // check emitSetCc is called only once
emitIsTypeTest(inst,
[&](ConditionCode cc) {
assert(!called);
emitSetCc(inst, negate ? ccNegate(cc) : cc);
called = true;
});
}
void CodeGenerator::cgJmpIsTypeCommon(IRInstruction* inst, bool negate) {
emitFwdJcc(emitIsTypeTest(inst, negate), inst->getTaken());
emitIsTypeTest(inst,
[&](ConditionCode cc) {
emitFwdJcc(negate ? ccNegate(cc) : cc, inst->getTaken());
});
}
void CodeGenerator::cgIsType(IRInstruction* inst) {
@@ -3813,11 +3865,13 @@ void CodeGenerator::cgLoadTypedValue(PhysReg base,
if (typeDstReg != InvalidReg) {
emitLoadTVType(m_as, base[off + TVOFF(m_type)], typeDstReg);
if (label) {
emitTypeCheck(inst->getTypeParam(), typeDstReg, inst->getTaken());
emitTypeCheck(inst->getTypeParam(), typeDstReg,
valueDstReg, inst->getTaken());
}
} else if (label) {
emitTypeCheck(inst->getTypeParam(),
base[off + TVOFF(m_type)],
base[off + TVOFF(m_data)],
inst->getTaken());
}
@@ -3891,6 +3945,7 @@ void CodeGenerator::cgLoad(PhysReg base,
if (label != NULL) {
emitTypeCheck(inst->getTypeParam(),
base[off + TVOFF(m_type)],
base[off + TVOFF(m_data)],
inst->getTaken());
}
if (type.isNull()) return; // these are constants
@@ -3974,38 +4029,44 @@ void CodeGenerator::cgLdStack(IRInstruction* inst) {
void CodeGenerator::cgGuardStk(IRInstruction* inst) {
auto const rSP = m_regs[inst->getSrc(0)].getReg();
auto const off = cellsToBytes(inst->getExtra<GuardStk>()->offset) +
TVOFF(m_type);
emitTypeGuard(inst->getTypeParam(), rSP[off]);
auto const baseOff = cellsToBytes(inst->getExtra<GuardStk>()->offset);
emitTypeGuard(inst->getTypeParam(),
rSP[baseOff + TVOFF(m_type)],
rSP[baseOff + TVOFF(m_data)]);
}
void CodeGenerator::cgCheckStk(IRInstruction* inst) {
auto const rbase = m_regs[inst->getSrc(0)].getReg();
auto const off = cellsToBytes(inst->getExtra<CheckStk>()->offset) +
TVOFF(m_type);
emitTypeCheck(inst->getTypeParam(), rbase[off], inst->getTaken());
auto const baseOff = cellsToBytes(inst->getExtra<CheckStk>()->offset);
emitTypeCheck(inst->getTypeParam(), rbase[baseOff + TVOFF(m_type)],
rbase[baseOff + TVOFF(m_data)], inst->getTaken());
}
void CodeGenerator::cgGuardLoc(IRInstruction* inst) {
auto const rFP = m_regs[inst->getSrc(0)].getReg();
auto const off = getLocalOffset(inst->getExtra<GuardLoc>()->locId) +
TVOFF(m_type);
emitTypeGuard(inst->getTypeParam(), rFP[off]);
auto const baseOff = getLocalOffset(inst->getExtra<GuardLoc>()->locId);
emitTypeGuard(inst->getTypeParam(),
rFP[baseOff + TVOFF(m_type)],
rFP[baseOff + TVOFF(m_data)]);
}
void CodeGenerator::cgCheckLoc(IRInstruction* inst) {
auto const rbase = m_regs[inst->getSrc(0)].getReg();
auto const off = getLocalOffset(inst->getExtra<CheckLoc>()->locId) +
TVOFF(m_type);
emitTypeCheck(inst->getTypeParam(), rbase[off], inst->getTaken());
auto const baseOff = getLocalOffset(inst->getExtra<CheckLoc>()->locId);
emitTypeCheck(inst->getTypeParam(), rbase[baseOff + TVOFF(m_type)],
rbase[baseOff + TVOFF(m_data)], inst->getTaken());
}
template<class MemLoc>
void CodeGenerator::emitSideExitGuard(Type type, MemLoc mem, Offset taken) {
auto const cc = emitTypeTest(type, mem, true /* negate */);
auto const sk = SrcKey(getCurFunc(), taken);
if (cc == CC_None) return;
m_tx64->emitBindJcc(m_as, cc, sk, REQ_BIND_SIDE_EXIT);
template<class Loc>
void CodeGenerator::emitSideExitGuard(Type type,
Loc typeSrc,
Loc dataSrc,
Offset taken) {
emitTypeTest(type, typeSrc, dataSrc,
[&](ConditionCode cc) {
auto const sk = SrcKey(getCurFunc(), taken);
m_tx64->emitBindJcc(m_as, ccNegate(cc), sk, REQ_BIND_SIDE_EXIT);
});
}
void CodeGenerator::cgSideExitGuardLoc(IRInstruction* inst) {
@@ -4013,6 +4074,7 @@ void CodeGenerator::cgSideExitGuardLoc(IRInstruction* inst) {
auto const extra = inst->getExtra<SideExitGuardLoc>();
emitSideExitGuard(inst->getTypeParam(),
fp[getLocalOffset(extra->checkedSlot) + TVOFF(m_type)],
fp[getLocalOffset(extra->checkedSlot) + TVOFF(m_data)],
extra->taken);
}
@@ -4021,6 +4083,7 @@ void CodeGenerator::cgSideExitGuardStk(IRInstruction* inst) {
auto const extra = inst->getExtra<SideExitGuardStk>();
emitSideExitGuard(inst->getTypeParam(),
sp[cellsToBytes(extra->checkedSlot) + TVOFF(m_type)],
sp[cellsToBytes(extra->checkedSlot) + TVOFF(m_data)],
extra->taken);
}
@@ -4031,22 +4094,24 @@ void CodeGenerator::cgDefMIStateBase(IRInstruction* inst) {
void CodeGenerator::cgCheckType(IRInstruction* inst) {
auto const src = inst->getSrc(0);
auto const rData = m_regs[src].getReg(0);
auto const rType = m_regs[src].getReg(1);
auto const cc = emitTypeTest(inst->getTypeParam(), rType, true);
if (cc == CC_None) return;
emitTypeTest(inst->getTypeParam(), rType, rData,
[&](ConditionCode cc) {
emitFwdJcc(ccNegate(cc), inst->getTaken());
emitFwdJcc(cc, inst->getTaken());
auto const dstReg = m_regs[inst->getDst()].getReg();
if (dstReg != InvalidReg) {
emitMovRegReg(m_as, m_regs[src].getReg(0), dstReg);
}
auto const dstReg = m_regs[inst->getDst()].getReg();
if (dstReg != InvalidReg) {
emitMovRegReg(m_as, m_regs[src].getReg(0), dstReg);
}
});
}
void CodeGenerator::cgCheckTypeMem(IRInstruction* inst) {
auto const reg = m_regs[inst->getSrc(0)].getReg();
emitTypeCheck(inst->getTypeParam(), reg[TVOFF(m_type)], inst->getTaken());
emitTypeCheck(inst->getTypeParam(), reg[TVOFF(m_type)],
reg[TVOFF(m_data)], inst->getTaken());
}
void CodeGenerator::cgGuardRefs(IRInstruction* inst) {
@@ -4810,11 +4875,14 @@ void CodeGenerator::cgBoxPtr(IRInstruction* inst) {
auto base = m_regs[addr].getReg();
auto dstReg = m_regs[dst].getReg();
emitMovRegReg(m_as, base, dstReg);
auto const cc = emitTypeTest(Type::BoxedCell, base[TVOFF(m_type)], true);
ifThen(m_as, cc, [&] {
cgCallHelper(m_as, (TCA)tvBox, dstReg, kNoSyncPoint,
ArgGroup(m_regs).ssa(addr));
});
emitTypeTest(Type::BoxedCell, base[TVOFF(m_type)],
base[TVOFF(m_data)],
[&](ConditionCode cc) {
ifThen(m_as, ccNegate(cc), [&] {
cgCallHelper(m_as, (TCA)tvBox, dstReg, kNoSyncPoint,
ArgGroup(m_regs).ssa(addr));
});
});
}
void CodeGenerator::cgDefCns(IRInstruction* inst) {
@@ -5088,9 +5156,12 @@ void traceCallback(ActRec* fp, Cell* sp, int64_t pcOff, void* rip) {
}
void CodeGenerator::cgDbgAssertType(IRInstruction* inst) {
ConditionCode cc = emitTypeTest(inst->getTypeParam(),
m_regs[inst->getSrc(0)].getReg(1), true);
ifThen(m_as, cc, [&] { m_as.ud2(); });
emitTypeTest(inst->getTypeParam(),
m_regs[inst->getSrc(0)].getReg(1),
m_regs[inst->getSrc(0)].getReg(0),
[&](ConditionCode cc) {
ifThen(m_as, ccNegate(cc), [&] { m_as.ud2(); });
});
}
void CodeGenerator::cgVerifyParamCls(IRInstruction* inst) {
+14 -9
Ver Arquivo
@@ -193,13 +193,16 @@ private:
void cgLoad(PhysReg base, int64_t off, IRInstruction* inst);
template<class OpndType>
ConditionCode emitTypeTest(Type type, OpndType src, bool negate);
template<class Loc1, class Loc2, class JmpFn>
void emitTypeTest(Type type,
Loc1 typeSrc,
Loc2 dataSrc,
JmpFn doJcc);
template<class MemLoc>
void emitTypeCheck(Type type, MemLoc src, Block* taken);
template<class MemLoc>
void emitTypeGuard(Type type, MemLoc mem);
template<class Loc>
void emitTypeCheck(Type type, Loc typeSrc, Loc dataSrc, Block* taken);
template<class Loc>
void emitTypeGuard(Type type, Loc typeLoc, Loc dataLoc);
void cgStMemWork(IRInstruction* inst, bool genStoreType);
void cgStRefWork(IRInstruction* inst, bool genStoreType);
@@ -254,8 +257,9 @@ private:
int64_t (*obj_cmp_int)(ObjectData*, int64_t),
int64_t (*arr_cmp_arr)(ArrayData*, ArrayData*));
template<class MemLoc>
void emitSideExitGuard(Type type, MemLoc mem, Offset taken);
template<class Loc>
void emitSideExitGuard(Type type, Loc typeLoc,
Loc dataLoc, Offset taken);
void emitReqBindJcc(ConditionCode cc, const ReqBindJccData*);
void emitCompare(SSATmp*, SSATmp*);
@@ -273,7 +277,8 @@ private:
const RegAllocInfo& allocInfo,
RegXMM rXMMScratch);
void emitSetCc(IRInstruction*, ConditionCode);
ConditionCode emitIsTypeTest(IRInstruction* inst, bool negate);
template<class JmpFn>
void emitIsTypeTest(IRInstruction* inst, JmpFn doJcc);
void doubleCmp(X64Assembler& a, RegXMM xmmReg0, RegXMM xmmReg1);
void cgIsTypeCommon(IRInstruction* inst, bool negate);
void cgJmpIsTypeCommon(IRInstruction* inst, bool negate);
@@ -18,6 +18,8 @@
#include "hphp/util/base.h"
#include "hphp/runtime/vm/translator/hopt/ir.h"
// for specialized object tests to get some real VM::Class
#include "hphp/system/lib/systemlib.h"
namespace std { namespace tr1 {
template<> struct hash<HPHP::JIT::Type> {
@@ -127,6 +129,47 @@ TEST(Type, Subtypes) {
EXPECT_TRUE(Type::PtrToCell.strictSubtypeOf(Type::PtrToGen));
}
TEST(Type, RuntimeType) {
HPHP::Transl::RuntimeType rt(new StringData());
Type t = Type::fromRuntimeType(rt);
EXPECT_TRUE(t.subtypeOf(Type::Str));
EXPECT_FALSE(t.subtypeOf(Type::Int));
rt = HPHP::Transl::RuntimeType(HphpArray::GetStaticEmptyArray());
t = Type::fromRuntimeType(rt);
EXPECT_TRUE(t.subtypeOf(Type::Arr));
EXPECT_FALSE(t.subtypeOf(Type::Str));
rt = HPHP::Transl::RuntimeType(true);
t = Type::fromRuntimeType(rt);
EXPECT_TRUE(t.subtypeOf(Type::Bool));
EXPECT_FALSE(t.subtypeOf(Type::Obj));
rt = HPHP::Transl::RuntimeType((int64_t) 1);
t = Type::fromRuntimeType(rt);
EXPECT_TRUE(t.subtypeOf(Type::Int));
EXPECT_FALSE(t.subtypeOf(Type::Dbl));
rt = HPHP::Transl::RuntimeType(DataType::KindOfObject,
DataType::KindOfInvalid);
rt = rt.setKnownClass(SystemLib::s_TraversableClass);
t = Type::fromRuntimeType(rt);
EXPECT_TRUE(t.subtypeOf(Type::Obj));
EXPECT_FALSE(Type::Obj.subtypeOf(t));
EXPECT_FALSE(Type::Int.subtypeOf(t));
HPHP::Transl::RuntimeType rt1 =
HPHP::Transl::RuntimeType(DataType::KindOfObject,
DataType::KindOfInvalid);
rt1 = rt1.setKnownClass(SystemLib::s_IteratorClass);
Type t1 = Type::fromRuntimeType(rt1);
EXPECT_TRUE(t1.subtypeOf(Type::Obj));
EXPECT_TRUE(t1.subtypeOf(t));
EXPECT_FALSE(Type::Obj.subtypeOf(t1));
EXPECT_FALSE(t.subtypeOf(t1));
EXPECT_FALSE(t.subtypeOf(Type::Str));
EXPECT_FALSE(Type::Int.subtypeOf(t));
}
TEST(Type, CanRunDtor) {
TypeSet types = allTypes();
auto expectTrue = [&](Type t) {
+49 -14
Ver Arquivo
@@ -117,6 +117,12 @@ class Type {
bits_t m_bits;
TypeBits m_typedBits;
};
const Class* m_class;
// private ctor to build a specialized type
explicit Type(bits_t bits, const Class* klass)
: m_bits(bits), m_class(klass)
{}
public:
# define IRT(name, ...) static const Type name;
@@ -124,15 +130,15 @@ public:
# undef IRT
explicit Type(bits_t bits = kNone)
: m_bits(bits)
: m_bits(bits), m_class(nullptr)
{}
size_t hash() const {
return hash_int64(m_bits);
return hash_int64_pair(m_bits, reinterpret_cast<uintptr_t>(m_class));
}
bool operator==(Type other) const {
return m_bits == other.m_bits;
return equals(other);
}
bool operator!=(Type other) const {
@@ -140,14 +146,23 @@ public:
}
Type operator|(Type other) const {
assert(m_class == nullptr && other.m_class == nullptr);
return Type(m_bits | other.m_bits);
}
Type operator&(Type other) const {
if (m_class != nullptr && other.m_class != nullptr) {
if (m_class->classof(other.m_class)) {
return Type(m_bits & other.m_bits).specialize(other.m_class);
} else if (other.m_class->classof(m_class)) {
return Type(m_bits & other.m_bits).specialize(m_class);
}
}
return Type(m_bits & other.m_bits);
}
Type operator-(Type other) const {
assert(m_class == nullptr && other.m_class == nullptr);
return Type(m_bits & ~other.m_bits);
}
@@ -253,14 +268,17 @@ public:
}
/*
* Returns true if this is a non-strict subtype of any of the arguments.
* Returns true if this is same type or a subtype of any of the arguments.
*/
bool subtypeOf(Type t2) const {
return (m_bits & t2.m_bits) == m_bits;
return (m_bits & t2.m_bits) == m_bits
&& (t2.m_class == nullptr
|| (m_class != nullptr
&& m_class->classof(t2.m_class)));
}
/*
* Returns true if this is a non-strict subtype of any of the arguments.
* Returns true if and only if this is the same as or a subtype of t2.
*/
template<typename... Types>
bool subtypeOfAny(Type t2, Types... ts) const {
@@ -290,7 +308,7 @@ public:
* probably mean subtypeOf.
*/
bool equals(Type t2) const {
return m_bits == t2.m_bits;
return m_bits == t2.m_bits && m_class == t2.m_class;
}
/*
@@ -331,6 +349,11 @@ public:
return subtypeOf(Str);
}
const Class* getClass() const {
assert(isObj());
return m_class;
}
Type innerType() const {
assert(isBoxed());
return Type(m_bits >> kBoxShift);
@@ -397,6 +420,11 @@ public:
return Type(m_bits << kPtrShift);
}
Type specialize(const Class* klass) const {
assert(isObj() && m_class == nullptr);
return Type(m_bits, klass);
}
bool canRunDtor() const {
return
(*this & (Obj | CountedArr | BoxedObj | BoxedCountedArr))
@@ -430,7 +458,8 @@ public:
}
static Type fromDataType(DataType outerType,
DataType innerType = KindOfInvalid) {
DataType innerType = KindOfInvalid,
const Class* klass = nullptr) {
assert(innerType != KindOfRef);
switch (outerType) {
@@ -443,7 +472,13 @@ public:
case KindOfStaticString : return StaticStr;
case KindOfString : return Str;
case KindOfArray : return Arr;
case KindOfObject : return Obj;
case KindOfObject : {
if (klass != nullptr) {
return Obj.specialize(klass);
} else {
return Obj;
}
}
case KindOfClass : return Cls;
case KindOfUncountedInit : return UncountedInit;
case KindOfUncounted : return Uncounted;
@@ -461,7 +496,7 @@ public:
// return true if this corresponds to a type that
// is passed by value in C++
bool isSimpleType() {
bool isSimpleType() const {
return subtypeOf(Type::Bool)
|| subtypeOf(Type::Int)
|| subtypeOf(Type::Dbl)
@@ -470,7 +505,7 @@ public:
// return true if this corresponds to a type that
// is passed by reference in C++
bool isReferenceType() {
bool isReferenceType() const {
return subtypeOf(Type::Str)
|| subtypeOf(Type::Arr)
|| subtypeOf(Type::Obj);
@@ -491,14 +526,14 @@ public:
}
static Type fromRuntimeType(const Transl::RuntimeType& rtt) {
return fromDataType(rtt.outerType(), rtt.innerType());
return fromDataType(rtt.outerType(), rtt.innerType(), rtt.knownClass());
}
static Type fromDynLocation(const Transl::DynLocation* dynLoc);
};
static_assert(sizeof(Type) <= sizeof(uint64_t),
"JIT::Type should fit in a register");
static_assert(sizeof(Type) <= 2 * sizeof(uint64_t),
"JIT::Type should fit in (2 * sizeof(uint64_t))");
}}
+29 -14
Ver Arquivo
@@ -42,6 +42,7 @@ RuntimeType::RuntimeType(DataType outer, DataType inner /* = KindOfInvalid */,
m_value.outerType = normalizeDataType(outer);
m_value.innerType = normalizeDataType(inner);
m_value.klass = klass;
m_value.knownClass = nullptr;
consistencyCheck();
}
@@ -50,6 +51,7 @@ RuntimeType::RuntimeType(const StringData* sd)
m_value.outerType = KindOfString;
m_value.innerType = KindOfInvalid;
m_value.string = sd;
m_value.knownClass = nullptr;
consistencyCheck();
}
@@ -58,6 +60,7 @@ RuntimeType::RuntimeType(const ArrayData* ad)
m_value.outerType = KindOfArray;
m_value.innerType = KindOfInvalid;
m_value.array = ad;
m_value.knownClass = nullptr;
consistencyCheck();
}
@@ -68,6 +71,7 @@ RuntimeType::RuntimeType(bool value)
m_value.klass = nullptr;
m_value.boolean = value;
m_value.boolValid = true;
m_value.knownClass = nullptr;
consistencyCheck();
}
@@ -76,6 +80,7 @@ RuntimeType::RuntimeType(int64_t value)
m_value.outerType = KindOfInt64;
m_value.innerType = KindOfInvalid;
m_value.intval = value;
m_value.knownClass = nullptr;
consistencyCheck();
}
@@ -84,18 +89,16 @@ RuntimeType::RuntimeType(const Class* klass)
m_value.outerType = KindOfClass;
m_value.innerType = KindOfInvalid;
m_value.klass = klass;
m_value.knownClass = nullptr;
consistencyCheck();
}
RuntimeType::RuntimeType(const RuntimeType& source) {
*this = source;
}
RuntimeType::RuntimeType() :
m_kind(VALUE) {
m_value.outerType = KindOfInvalid;
m_value.innerType = KindOfInvalid;
m_value.klass = nullptr;
m_value.knownClass = nullptr;
}
RuntimeType::RuntimeType(const Iter* it) :
@@ -195,6 +198,12 @@ RuntimeType::valueGeneric() const {
return m_value.intval;
}
const Class*
RuntimeType::knownClass() const {
consistencyCheck();
return m_value.knownClass;
}
RuntimeType
RuntimeType::setValueType(DataType newInner) const {
assert(m_kind == VALUE);
@@ -212,6 +221,18 @@ RuntimeType::setValueType(DataType newInner) const {
return rtt;
}
RuntimeType
RuntimeType::setKnownClass(const Class* klass) const {
assert(isObject());
RuntimeType rtt;
rtt.m_kind = VALUE;
rtt.m_value.outerType = outerType();
rtt.m_value.klass = m_value.klass;
rtt.m_value.knownClass = klass;
rtt.consistencyCheck();
return rtt;
}
// Accessors
DataType RuntimeType::outerType() const {
consistencyCheck();
@@ -285,6 +306,10 @@ bool RuntimeType::isClass() const {
return isValue() && outerType() == KindOfClass;
}
bool RuntimeType::hasKnownType() const {
return isObject() && m_value.knownClass != nullptr;
}
bool RuntimeType::isArray() const {
return isValue() && outerType() == KindOfArray;
}
@@ -307,16 +332,6 @@ bool RuntimeType::operator==(const RuntimeType& r) const {
}
}
RuntimeType& RuntimeType::operator=(const RuntimeType& r) {
m_kind = r.m_kind;
m_value.innerType = r.m_value.innerType;
m_value.outerType = r.m_value.outerType;
m_value.klass = r.m_value.klass;
consistencyCheck();
assert(*this == r);
return *this;
}
size_t
RuntimeType::operator()(const RuntimeType& r) const {
uint64_t p1 = HPHP::hash_int64(m_kind);
+10 -2
Ver Arquivo
@@ -188,6 +188,9 @@ class RuntimeType {
struct {
DataType outerType;
DataType innerType;
// Set when we want to transfer the type information to the
// IR type system (Type object)
const Class* knownClass;
union {
// We may have even more precise data about this set of values.
const StringData* string; // KindOfString: The exact value.
@@ -225,6 +228,8 @@ class RuntimeType {
m_value.klass == nullptr);
assert(m_value.innerType != KindOfStaticString &&
m_value.outerType != KindOfStaticString);
assert(m_value.knownClass == nullptr ||
m_value.outerType == KindOfObject);
}
}
@@ -236,7 +241,7 @@ class RuntimeType {
explicit RuntimeType(const Class*);
explicit RuntimeType(bool value);
explicit RuntimeType(int64_t value);
RuntimeType(const RuntimeType& copy);
RuntimeType(const RuntimeType& copy) = default;
RuntimeType();
explicit RuntimeType(const Iter* iter);
explicit RuntimeType(ArrayIter::Type type);
@@ -247,6 +252,7 @@ class RuntimeType {
RuntimeType box() const;
RuntimeType unbox() const;
RuntimeType setValueType(DataType vt) const;
RuntimeType setKnownClass(const Class* klass) const;
// Accessors
DataType outerType() const;
@@ -259,6 +265,7 @@ class RuntimeType {
int valueBoolean() const;
int64_t valueInt() const;
int64_t valueGeneric() const;
const Class* knownClass() const;
// Helpers for typechecking
DataType typeCheckValue() const;
@@ -279,8 +286,9 @@ class RuntimeType {
bool isString() const;
bool isObject() const;
bool isClass() const;
bool hasKnownType() const;
bool operator==(const RuntimeType& r) const;
RuntimeType &operator=(const RuntimeType& r);
RuntimeType &operator=(const RuntimeType& r) = default;
size_t operator()(const RuntimeType& r) const; // hash function
std::string pretty() const;
};