Conversions in IR
Rolls up all previous diffs into a single diff and uses the CALL_OPCODE macro.
Esse commit está contido em:
@@ -398,21 +398,34 @@ D:Arr = ConvDblToArr S0:Dbl
|
||||
D:Arr = ConvIntToArr S0:Int
|
||||
D:Arr = ConvObjToArr S0:Obj
|
||||
D:Arr = ConvStrToArr S0:Str
|
||||
D:Arr = ConvGenToArr S0:Gen
|
||||
D:Bool = ConvToBool S0:Gen
|
||||
D:Arr = ConvCellToArr S0:Cell
|
||||
|
||||
D:Bool = ConvArrToBool S0:Arr
|
||||
D:Bool = ConvDblToBool S0:Dbl
|
||||
D:Bool = ConvIntToBool S0:Int
|
||||
D:Bool = ConvStrToBool S0:Str
|
||||
D:Bool = ConvCellToBool S0:Cell
|
||||
|
||||
D:Dbl = ConvArrToDbl S0:Arr
|
||||
D:Dbl = ConvBoolToDbl S0:Bool
|
||||
D:Dbl = ConvIntToDbl S0:Int
|
||||
D:Dbl = ConvObjToDbl S0:Obj
|
||||
D:Dbl = ConvStrToDbl S0:Str
|
||||
D:Dbl = ConvGenToDbl S0:Gen
|
||||
D:Dbl = ConvCellToDbl S0:Cell
|
||||
|
||||
D:Int = ConvArrToInt S0:Arr
|
||||
D:Int = ConvDblToInt S0:Dbl
|
||||
D:Int = ConvObjToInt S0:Obj
|
||||
D:Int = ConvStrToInt S0:Str
|
||||
D:Int = ConvGenToInt S0:Gen
|
||||
D:Obj = ConvoObj S0:Gen
|
||||
D:Str = ConvToStr S0:Gen
|
||||
D:Int = ConvCellToInt S0:Cell
|
||||
|
||||
D:Obj = ConvCellToObj S0:Cell
|
||||
|
||||
D:StaticStr = ConvBoolToStr S0:Bool
|
||||
D:Str = ConvDblToStr S0:Dbl
|
||||
D:Str = ConvIntToStr S0:Int
|
||||
D:Str = ConvObjToStr S0:Obj
|
||||
D:Str = ConvCellToStr S0:Cell
|
||||
|
||||
Convert S0 from its current type to the destination type, according to the PHP
|
||||
semantics of such a conversion.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <runtime/base/util/exceptions.h>
|
||||
#include <util/alloc.h>
|
||||
#include <math.h>
|
||||
#include <runtime/base/zend/zend_printf.h>
|
||||
#include <runtime/base/zend/zend_string.h>
|
||||
#include <runtime/base/zend/zend_strtod.h>
|
||||
#include <runtime/base/complex_types.h>
|
||||
@@ -42,6 +43,28 @@ typedef tbb::concurrent_unordered_map<const StringData *, uint32_t,
|
||||
string_data_same> StringDataMap;
|
||||
static StringDataMap *s_stringDataMap;
|
||||
|
||||
const StringData* StringData::convert_double_helper(double n) {
|
||||
char *buf;
|
||||
StringData* result;
|
||||
|
||||
if (n == 0.0) n = 0.0; // so to avoid "-0" output
|
||||
vspprintf(&buf, 0, "%.*G", 14, n);
|
||||
result = StringData::GetStaticString(buf);
|
||||
free(buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
const StringData* StringData::convert_integer_helper(int64_t n) {
|
||||
char tmpbuf[21];
|
||||
char *p;
|
||||
int is_negative;
|
||||
int len;
|
||||
|
||||
tmpbuf[20] = '\0';
|
||||
p = conv_10(n, &is_negative, &tmpbuf[20], &len);
|
||||
return StringData::GetStaticString(p);
|
||||
}
|
||||
|
||||
size_t StringData::GetStaticStringCount() {
|
||||
if (!s_stringDataMap) return 0;
|
||||
return s_stringDataMap->size();
|
||||
|
||||
@@ -215,6 +215,8 @@ class StringData {
|
||||
public:
|
||||
void append(StringSlice r) { append(r.ptr, r.len); }
|
||||
void append(const char *s, int len);
|
||||
static const StringData* convert_double_helper(double n);
|
||||
static const StringData* convert_integer_helper(int64_t n);
|
||||
StringData *copy(bool sharedMemory = false) const;
|
||||
MutableSlice reserve(int capacity);
|
||||
MutableSlice mutableSlice() {
|
||||
|
||||
@@ -40,27 +40,16 @@ StringData const **String::converted_integers;
|
||||
|
||||
String::IntegerStringDataMap String::integer_string_data_map;
|
||||
|
||||
static const StringData *convert_integer_helper(int64_t n) {
|
||||
char tmpbuf[21];
|
||||
char *p;
|
||||
int is_negative;
|
||||
int len;
|
||||
|
||||
tmpbuf[20] = '\0';
|
||||
p = conv_10(n, &is_negative, &tmpbuf[20], &len);
|
||||
return StringData::GetStaticString(p);
|
||||
}
|
||||
|
||||
void String::PreConvertInteger(int64_t n) {
|
||||
IntegerStringDataMap::const_iterator it =
|
||||
integer_string_data_map.find(n);
|
||||
if (it != integer_string_data_map.end()) return;
|
||||
integer_string_data_map[n] = convert_integer_helper(n);
|
||||
integer_string_data_map[n] = StringData::convert_integer_helper(n);
|
||||
}
|
||||
|
||||
const StringData *String::ConvertInteger(int64_t n) {
|
||||
StringData const **psd = converted_integers + n;
|
||||
const StringData *sd = convert_integer_helper(n);
|
||||
const StringData *sd = StringData::convert_integer_helper(n);
|
||||
*psd = sd;
|
||||
return sd;
|
||||
}
|
||||
|
||||
@@ -315,6 +315,36 @@ CALL_OPCODE(AddElemIntKey)
|
||||
CALL_OPCODE(AddNewElem)
|
||||
CALL_OPCODE(ArrayAdd)
|
||||
CALL_OPCODE(Box)
|
||||
|
||||
CALL_OPCODE(ConvBoolToArr);
|
||||
CALL_OPCODE(ConvDblToArr);
|
||||
CALL_OPCODE(ConvIntToArr);
|
||||
CALL_OPCODE(ConvObjToArr);
|
||||
CALL_OPCODE(ConvStrToArr);
|
||||
CALL_OPCODE(ConvCellToArr);
|
||||
|
||||
CALL_OPCODE(ConvArrToBool);
|
||||
CALL_OPCODE(ConvStrToBool);
|
||||
CALL_OPCODE(ConvCellToBool);
|
||||
|
||||
CALL_OPCODE(ConvArrToDbl);
|
||||
CALL_OPCODE(ConvObjToDbl);
|
||||
CALL_OPCODE(ConvStrToDbl);
|
||||
CALL_OPCODE(ConvCellToDbl);
|
||||
|
||||
CALL_OPCODE(ConvArrToInt);
|
||||
CALL_OPCODE(ConvDblToInt);
|
||||
CALL_OPCODE(ConvObjToInt);
|
||||
CALL_OPCODE(ConvStrToInt);
|
||||
CALL_OPCODE(ConvCellToInt);
|
||||
|
||||
CALL_OPCODE(ConvCellToObj);
|
||||
|
||||
CALL_OPCODE(ConvDblToStr);
|
||||
CALL_OPCODE(ConvIntToStr);
|
||||
CALL_OPCODE(ConvObjToStr);
|
||||
CALL_OPCODE(ConvCellToStr);
|
||||
|
||||
CALL_OPCODE(CreateCont)
|
||||
CALL_OPCODE(FillContLocals)
|
||||
CALL_OPCODE(NewArray)
|
||||
@@ -1101,34 +1131,6 @@ void CodeGenerator::cgOpMul(IRInstruction* inst) {
|
||||
Commutative);
|
||||
}
|
||||
|
||||
// Runtime helpers
|
||||
|
||||
HOT_FUNC_VM static int64_t arrToBoolHelper(const ArrayData *a) {
|
||||
return a->size() != 0;
|
||||
}
|
||||
|
||||
HOT_FUNC_VM static int64_t cellToBoolHelper(TypedValue tv) {
|
||||
if (IS_NULL_TYPE(tv.m_type)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tv.m_type <= KindOfInt64) {
|
||||
return tv.m_data.num ? 1 : 0;
|
||||
}
|
||||
|
||||
switch (tv.m_type) {
|
||||
case KindOfDouble: return tv.m_data.dbl != 0;
|
||||
case KindOfStaticString:
|
||||
case KindOfString: return tv.m_data.pstr->toBoolean();
|
||||
case KindOfArray: return tv.m_data.parr->size() != 0;
|
||||
case KindOfObject: return tv.m_data.pobj->o_toBoolean();
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Comparison Operators
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1612,138 +1614,48 @@ asm_label(a, falseLabel);
|
||||
asm_label(a, out);
|
||||
}
|
||||
|
||||
// The assumption here is that the overall cost of allocating
|
||||
// the array swamps the cost of putting a simple value in to
|
||||
// a typed value, so there is no need for further type specialization.
|
||||
|
||||
void CodeGenerator::cgConvBoolToArr(IRInstruction* inst) {
|
||||
cgConvGenToArr(inst);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvDblToArr(IRInstruction* inst) {
|
||||
cgConvGenToArr(inst);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvIntToArr(IRInstruction* inst) {
|
||||
cgConvGenToArr(inst);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvObjToArr(IRInstruction* inst) {
|
||||
cgConvGenToArr(inst);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvStrToArr(IRInstruction* inst) {
|
||||
cgConvGenToArr(inst);
|
||||
}
|
||||
|
||||
// So why have all of these different IR instructions instead
|
||||
// of just ConvGenToArr? Because we need at least two variants
|
||||
// and we don't want to overload opcodes and we want consistency.
|
||||
|
||||
ArrayData* convGenToArrHelper(TypedValue value) {
|
||||
// Note: the call sites of this function all assume that
|
||||
// no user code will run and no recoverable exceptions will
|
||||
// occur while running this code. This seems trivially true
|
||||
// in all cases but converting objects to arrays. It also
|
||||
// seems true for that case as well, since the resulting array
|
||||
// is essentially metadata for the object. If that is not true,
|
||||
// you might end up looking at this code in a debugger and now
|
||||
// you know why.
|
||||
tvCastToArrayInPlace(&value); // consumes a ref on counted values
|
||||
return value.m_data.parr;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvGenToArr(IRInstruction* inst) {
|
||||
void CodeGenerator::cgConvDblToBool(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
ArgGroup args;
|
||||
args.typedValue(src);
|
||||
ArrayData*(*fPtr)(TypedValue) = convGenToArrHelper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToBool(IRInstruction* inst) {
|
||||
Type fromType = inst->getSrc(0)->getType();
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
auto dstReg = dst->getReg();
|
||||
assert(dstReg != InvalidReg);
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
auto srcReg = src->getReg();
|
||||
|
||||
bool srcIsConst = src->isConst();
|
||||
|
||||
if (fromType.isNull()) {
|
||||
// Uninit/Null -> Bool (false)
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else if (fromType == Type::Bool) {
|
||||
// Bool -> Bool (nop!)
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValRawInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
if (srcReg == InvalidReg) {
|
||||
assert(src->isConst());
|
||||
double constVal = src->getValDbl();
|
||||
if (constVal == 0.0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
emitMovRegReg(m_as, srcReg, dstReg);
|
||||
}
|
||||
} else if (fromType == Type::Int) {
|
||||
// Int -> Bool
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
m_as.test_reg64_reg64(srcReg, srcReg);
|
||||
m_as.setne(rbyte(dstReg));
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
Transl::Call helper(nullptr);
|
||||
ArgGroup args;
|
||||
if (fromType == Type::Cell) {
|
||||
// Cell -> Bool
|
||||
args.typedValue(src);
|
||||
helper = Transl::Call((TCA)cellToBoolHelper);
|
||||
} else if (fromType.isString()) {
|
||||
// Str -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call(getMethodPtr(&StringData::toBoolean));
|
||||
} else if (fromType.isArray()) {
|
||||
// Arr -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call((TCA)arrToBoolHelper);
|
||||
} else if (fromType == Type::Obj) {
|
||||
// Obj -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call(getMethodPtr(&ObjectData::o_toBoolean));
|
||||
} else {
|
||||
// Dbl -> Bool
|
||||
CG_PUNT(Conv_Dbl_Bool);
|
||||
}
|
||||
cgCallHelper(m_as, helper, dstReg, kNoSyncPoint, args);
|
||||
m_as.movq(srcReg, dstReg);
|
||||
m_as.shlq(1, dstReg); // 0.0 stays zero and -0.0 is now 0.0
|
||||
m_as.setne(rbyte(dstReg)); // lower byte becomes 1 if dstReg != 0
|
||||
m_as.movzbl(rbyte(dstReg), r32(dstReg));
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t arrayToDoubleHelper(ArrayData* value) {
|
||||
union {
|
||||
int64_t intval;
|
||||
double dblval;
|
||||
} u;
|
||||
u.dblval = value->empty() ? 0 : 1;
|
||||
return u.intval;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvArrToDbl(IRInstruction* inst) {
|
||||
void CodeGenerator::cgConvIntToBool(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
auto dstReg = dst->getReg();
|
||||
assert(dstReg != InvalidReg);
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
ArgGroup args;
|
||||
args.ssa(src);
|
||||
int64_t (*fPtr)(ArrayData*) = arrayToDoubleHelper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
|
||||
auto srcReg = src->getReg();
|
||||
|
||||
if (srcReg == InvalidReg) {
|
||||
assert(src->isConst());
|
||||
int64_t constVal = src->getValInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
m_as.test_reg64_reg64(srcReg, srcReg);
|
||||
m_as.setne(rbyte(dstReg));
|
||||
m_as.movzbl(rbyte(dstReg), r32(dstReg));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvBoolToDbl(IRInstruction* inst) {
|
||||
@@ -1796,42 +1708,6 @@ void CodeGenerator::cgConvIntToDbl(IRInstruction* inst) {
|
||||
m_as.mov_xmm_reg64(xmm0, dstReg);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvObjToDbl(IRInstruction* inst) {
|
||||
cgConvGenToDbl(inst);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvStrToDbl(IRInstruction* inst) {
|
||||
cgConvGenToDbl(inst);
|
||||
}
|
||||
|
||||
HOT_FUNC_VM static int64_t genToDblHelper(TypedValue value) {
|
||||
tvCastToDoubleInPlace(&value); // this will decrease the ref count
|
||||
// of the current object in value.
|
||||
return value.m_data.num;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvGenToDbl(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
ArgGroup args;
|
||||
args.typedValue(src);
|
||||
int64_t (*fPtr)(TypedValue) = genToDblHelper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kSyncPoint, args);
|
||||
}
|
||||
|
||||
static int64_t arrayToIntHelper(ArrayData* value) {
|
||||
return value->empty() ? 0 : 1;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvArrToInt(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
ArgGroup args;
|
||||
args.ssa(src);
|
||||
int64_t (*fPtr)(ArrayData*) = arrayToIntHelper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvBoolToInt(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
auto dstReg = dst->getReg();
|
||||
@@ -1851,92 +1727,25 @@ void CodeGenerator::cgConvBoolToInt(IRInstruction* inst) {
|
||||
}
|
||||
}
|
||||
|
||||
HOT_FUNC_VM static int64_t doubleToIntHelper(int64_t value) {
|
||||
union {
|
||||
int64_t intval;
|
||||
double dblval;
|
||||
} u;
|
||||
u.intval = value;
|
||||
double d = u.dblval;
|
||||
return (d >= 0 ? d > std::numeric_limits<uint64_t>::max() ? 0u :
|
||||
(uint64_t)d : (int64_t)d);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvDblToInt(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
ArgGroup args;
|
||||
args.typedValue(src);
|
||||
int64_t (*fPtr)(int64_t) = doubleToIntHelper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvObjToInt(IRInstruction* inst) {
|
||||
// Never cheap, so just use the general logic.
|
||||
cgConvGenToInt(inst);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvStrToInt(IRInstruction* inst) {
|
||||
void CodeGenerator::cgConvBoolToStr(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
auto dstReg = dst->getReg();
|
||||
assert(dstReg != InvalidReg);
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
if (src->isConst()) {
|
||||
auto val = src->getValStr()->toInt64();
|
||||
m_as.mov_imm64_reg(val, dstReg);
|
||||
} else {
|
||||
ArgGroup args;
|
||||
args.ssa(src).imm(10);
|
||||
cgCallHelper(m_as,
|
||||
Transl::Call(getMethodPtr(&StringData::toInt64)),
|
||||
dstReg, kNoSyncPoint, args);
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t genToIntHelper(TypedValue value) {
|
||||
tvCastToInt64InPlace(&value); // this will decrease the ref count
|
||||
// of the current object in value.
|
||||
return value.m_data.num;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvGenToInt(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
ArgGroup args;
|
||||
args.typedValue(src);
|
||||
int64_t (*fPtr)(TypedValue) = genToIntHelper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kSyncPoint, args);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToObj(IRInstruction* inst) {
|
||||
CG_PUNT(ConvToObj);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToStr(IRInstruction* inst) {
|
||||
Type fromType = inst->getSrc(0)->getType();
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
auto dstReg = dst->getReg();
|
||||
auto srcReg = src->getReg();
|
||||
|
||||
if (fromType == Type::Int) {
|
||||
// Int -> Str
|
||||
ArgGroup args;
|
||||
args.ssa(src);
|
||||
StringData*(*fPtr)(int64_t) = buildStringData;
|
||||
cgCallHelper(m_as, (TCA)fPtr,
|
||||
dst, kNoSyncPoint, args);
|
||||
} else if (fromType == Type::Bool) {
|
||||
// Bool -> Str
|
||||
m_as.testb(Reg8(int(srcReg)), Reg8(int(srcReg)));
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString(""),
|
||||
dstReg);
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString("1"),
|
||||
rScratch);
|
||||
m_as.cmov_reg64_reg64(CC_NZ, rScratch, dstReg);
|
||||
assert(src->isConst() == (srcReg == InvalidReg));
|
||||
if (srcReg == InvalidReg) {
|
||||
auto constVal = src->getValBool();
|
||||
if (!constVal) {
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString(""), dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString("1"), dstReg);
|
||||
}
|
||||
} else {
|
||||
CG_PUNT(ConvToString);
|
||||
m_as.testb(Reg8(int(srcReg)), Reg8(int(srcReg)));
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString(""), dstReg);
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString("1"), rScratch);
|
||||
m_as.cmov_reg64_reg64(CC_NZ, rScratch, dstReg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| HipHop for PHP |
|
||||
+----------------------------------------------------------------------+
|
||||
@@ -2153,7 +2153,7 @@ void HhbcTranslator::emitCastArray() {
|
||||
} else if (fromType.isObj()) {
|
||||
push(m_tb->gen(ConvObjToArr, src));
|
||||
} else {
|
||||
push(m_tb->gen(ConvGenToArr, src));
|
||||
push(m_tb->gen(ConvCellToArr, src));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2184,7 +2184,7 @@ void HhbcTranslator::emitCastDouble() {
|
||||
push(m_tb->gen(ConvObjToDbl, src));
|
||||
} else {
|
||||
spillStack(); // may throw
|
||||
push(m_tb->gen(ConvGenToDbl, src));
|
||||
push(m_tb->gen(ConvCellToDbl, src));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2210,28 +2210,43 @@ void HhbcTranslator::emitCastInt() {
|
||||
push(m_tb->gen(ConvObjToInt, src));
|
||||
} else {
|
||||
spillStack(); // may throw
|
||||
push(m_tb->gen(ConvGenToInt, src));
|
||||
push(m_tb->gen(ConvCellToInt, src));
|
||||
}
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitCastObject() {
|
||||
SSATmp* src = popC();
|
||||
Type srcType = src->getType();
|
||||
if (srcType.isObj()) {
|
||||
push(src);
|
||||
} else {
|
||||
push(m_tb->gen(ConvCellToObj, src));
|
||||
}
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitCastString() {
|
||||
SSATmp* src = popC();
|
||||
Type fromType = src->getType();
|
||||
if (fromType == Type::Cell) {
|
||||
PUNT(CastString_Cell);
|
||||
} else if (fromType == Type::Obj) {
|
||||
// call the toString helper on object
|
||||
PUNT(CastString_Obj);
|
||||
if (fromType.isString()) {
|
||||
push(src);
|
||||
} else if (fromType.isNull()) {
|
||||
push(m_tb->genDefConst(StringData::GetStaticString("")));
|
||||
} else if (fromType.isArray()) {
|
||||
push(m_tb->genDefConst(StringData::GetStaticString("Array")));
|
||||
m_tb->genDecRef(src);
|
||||
} else if (fromType.isBool()) {
|
||||
push(m_tb->gen(ConvBoolToStr, src));
|
||||
} else if (fromType.isDbl()) {
|
||||
push(m_tb->gen(ConvDblToStr, src));
|
||||
} else if (fromType.isInt()) {
|
||||
push(m_tb->gen(ConvIntToStr, src));
|
||||
} else if (fromType.isObj()) {
|
||||
spillStack(); // may throw
|
||||
push(m_tb->gen(ConvObjToStr, src));
|
||||
} else {
|
||||
// for int to string conversion, this calls a helper that returns
|
||||
// a string with ref count of 0.
|
||||
pushIncRef(m_tb->genConvToStr(src));
|
||||
spillStack(); // may throw
|
||||
push(m_tb->gen(ConvCellToStr, src));
|
||||
}
|
||||
m_tb->genDecRef(src);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitCastObject() {
|
||||
emitInterpOneOrPunt(Type::Obj, 1);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -2538,7 +2553,7 @@ void HhbcTranslator::emitMod() {
|
||||
m_stackDeficit,
|
||||
exitSpillValues,
|
||||
[&](IRFactory* irf, Trace* t) {
|
||||
// Dividing by zero. Interpreting will raise a notice and
|
||||
// Dividing by zero. Interpreting will raise a notice and
|
||||
// produce the boolean false. Punch out here and resume after
|
||||
// the Mod instruction; this should be rare.
|
||||
m_tb->genFor(t, RaiseWarning,
|
||||
|
||||
@@ -466,12 +466,16 @@ bool IRInstruction::killsSource(int idx) const {
|
||||
switch (m_op) {
|
||||
case DecRef:
|
||||
case ConvObjToArr:
|
||||
case ConvGenToArr:
|
||||
case ConvCellToArr:
|
||||
case ConvCellToBool:
|
||||
case ConvObjToDbl:
|
||||
case ConvStrToDbl:
|
||||
case ConvGenToDbl:
|
||||
case ConvCellToDbl:
|
||||
case ConvObjToInt:
|
||||
case ConvGenToInt:
|
||||
case ConvCellToInt:
|
||||
case ConvCellToObj:
|
||||
case ConvObjToStr:
|
||||
case ConvCellToStr:
|
||||
assert(idx == 0);
|
||||
return true;
|
||||
case ArraySet:
|
||||
|
||||
@@ -175,27 +175,35 @@ O(ConvDblToArr, D(Arr), S(Dbl), C|N) \
|
||||
O(ConvIntToArr, D(Arr), S(Int), C|N) \
|
||||
O(ConvObjToArr, D(Arr), S(Obj), N|CRc|K) \
|
||||
O(ConvStrToArr, D(Arr), S(Str), N|CRc) \
|
||||
O(ConvGenToArr, D(Arr), S(Gen), N|CRc|K) \
|
||||
O(ConvCellToArr, D(Arr), S(Cell), N|CRc|K) \
|
||||
\
|
||||
O(ConvToBool, D(Bool), S(Gen), C|N) \
|
||||
O(ConvArrToBool, D(Bool), S(Arr), C|N) \
|
||||
O(ConvDblToBool, D(Bool), S(Dbl), C) \
|
||||
O(ConvIntToBool, D(Bool), S(Int), C) \
|
||||
O(ConvStrToBool, D(Bool), S(Str), N) \
|
||||
O(ConvCellToBool, D(Bool), S(Cell), N) \
|
||||
\
|
||||
O(ConvArrToDbl, D(Dbl), S(Arr), N) \
|
||||
O(ConvArrToDbl, D(Dbl), S(Arr), C|N) \
|
||||
O(ConvBoolToDbl, D(Dbl), S(Bool), C|Rm) \
|
||||
O(ConvIntToDbl, D(Dbl), S(Int), C|Rm) \
|
||||
O(ConvObjToDbl, D(Dbl), S(Obj), N|Er|CRc|K) \
|
||||
O(ConvStrToDbl, D(Dbl), S(Str), N|CRc|K) \
|
||||
O(ConvGenToDbl, D(Dbl), S(Gen), N|Er|CRc|K) \
|
||||
O(ConvCellToDbl, D(Dbl), S(Cell), N|Er|CRc|K) \
|
||||
\
|
||||
O(ConvArrToInt, D(Int), S(Arr), N) \
|
||||
O(ConvArrToInt, D(Int), S(Arr), C|N) \
|
||||
O(ConvBoolToInt, D(Int), S(Bool), C|Rm) \
|
||||
O(ConvDblToInt, D(Int), S(Dbl), C|N|Rm) \
|
||||
O(ConvObjToInt, D(Int), S(Obj), N|Er|CRc|K) \
|
||||
O(ConvStrToInt, D(Int), S(Str), N) \
|
||||
O(ConvGenToInt, D(Int), S(Gen), N|Er|CRc|K) \
|
||||
O(ConvCellToInt, D(Int), S(Cell), N|Er|CRc|K) \
|
||||
\
|
||||
O(ConvToObj, D(Obj), S(Gen), C|N) \
|
||||
O(ConvCellToObj, D(Obj), S(Cell), N|CRc|K) \
|
||||
\
|
||||
O(ConvToStr, D(Str), S(Gen), C|N) \
|
||||
O(ConvBoolToStr, D(StaticStr), S(Bool), C|Rm) \
|
||||
O(ConvDblToStr, D(Str), S(Dbl), N) \
|
||||
O(ConvIntToStr, D(Str), S(Int), N) \
|
||||
O(ConvObjToStr, D(Str), S(Obj), N|Er|CRc|K) \
|
||||
O(ConvCellToStr, D(Str), S(Cell), N|Er|CRc|K) \
|
||||
\
|
||||
O(ExtendsClass, D(Bool), S(Cls) C(Cls), C) \
|
||||
O(IsTypeMem, D(Bool), S(PtrToGen), NA) \
|
||||
@@ -2384,13 +2392,15 @@ int32_t spillValueCells(IRInstruction* spillStack);
|
||||
constexpr int kSpillStackActRecExtraArgs = 5;
|
||||
|
||||
inline bool isConvIntOrPtrToBool(IRInstruction* instr) {
|
||||
if (instr->getOpcode() != ConvToBool) {
|
||||
return false;
|
||||
switch (instr->getOpcode()) {
|
||||
case ConvIntToBool:
|
||||
return true;
|
||||
case ConvCellToBool:
|
||||
return instr->getSrc(0)->getType().subtypeOfAny(
|
||||
Type::Func, Type::Cls, Type::FuncCls, Type::VarEnv, Type::TCA);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return instr->getSrc(0)->isA(
|
||||
Type::Int | Type::Func | Type::Cls | Type::FuncCls |
|
||||
Type::VarEnv | Type::TCA);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -649,51 +649,6 @@ void LinearScan::computePreColoringHint() {
|
||||
m_preColoringHint.add(inst->getSrc(0), 0, 1);
|
||||
}
|
||||
break;
|
||||
case ConvBoolToArr:
|
||||
case ConvDblToArr:
|
||||
case ConvIntToArr:
|
||||
case ConvObjToArr:
|
||||
case ConvStrToArr:
|
||||
case ConvGenToArr:
|
||||
break;
|
||||
case ConvToBool:
|
||||
{
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type fromType = src->getType();
|
||||
if (fromType == Type::Cell) {
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
m_preColoringHint.add(src, 1, 1);
|
||||
} else if (fromType == Type::Str ||
|
||||
fromType == Type::StaticStr ||
|
||||
fromType.isArray() ||
|
||||
fromType == Type::Obj) {
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConvArrToDbl:
|
||||
case ConvBoolToDbl:
|
||||
case ConvIntToDbl:
|
||||
case ConvObjToDbl:
|
||||
case ConvStrToDbl:
|
||||
case ConvGenToDbl:
|
||||
break;
|
||||
case ConvBoolToInt:
|
||||
case ConvDblToInt:
|
||||
case ConvObjToInt:
|
||||
break;
|
||||
case ConvStrToInt:
|
||||
{
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
break;
|
||||
}
|
||||
case ConvGenToInt:
|
||||
break;
|
||||
case ConvToObj:
|
||||
break;
|
||||
case ConvToStr:
|
||||
break;
|
||||
case InstanceOf:
|
||||
case NInstanceOf:
|
||||
case JmpInstanceOf:
|
||||
|
||||
@@ -64,6 +64,58 @@ static const DestType DNone = DestType::None;
|
||||
*/
|
||||
static CallMap s_callMap({
|
||||
/* Opcode, Func, Dest, SyncPoint, Args */
|
||||
{ConvBoolToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
{ConvDblToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
{ConvIntToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
{ConvObjToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
{ConvStrToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
{ConvCellToArr, (TCA)convCellToArrHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
|
||||
{ConvArrToBool, (TCA)convArrToBoolHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvStrToBool, (TCA)convStrToBoolHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvCellToBool, (TCA)convCellToBoolHelper, DSSA, SNone,
|
||||
{{TV, 0}}},
|
||||
|
||||
{ConvArrToDbl, (TCA)convArrToDblHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvObjToDbl, (TCA)convCellToDblHelper, DSSA, SSync,
|
||||
{{TV, 0}}},
|
||||
{ConvStrToDbl, (TCA)convStrToDblHelper, DSSA, SSync,
|
||||
{{SSA, 0}}},
|
||||
{ConvCellToDbl, (TCA)convCellToDblHelper, DSSA, SSync,
|
||||
{{TV, 0}}},
|
||||
|
||||
{ConvArrToInt, (TCA)convArrToIntHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvDblToInt, (TCA)convDblToIntHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvObjToInt, (TCA)convCellToIntHelper, DSSA, SSync,
|
||||
{{TV, 0}}},
|
||||
{ConvStrToInt, (TCA)convStrToIntHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvCellToInt, (TCA)convCellToIntHelper, DSSA, SSync,
|
||||
{{TV, 0}}},
|
||||
|
||||
{ConvCellToObj, (TCA)convCellToObjHelper, DSSA, SSync,
|
||||
{{TV, 0}}},
|
||||
|
||||
{ConvDblToStr, (TCA)convDblToStrHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvIntToStr, (TCA)convIntToStrHelper, DSSA, SNone,
|
||||
{{SSA, 0}}},
|
||||
{ConvObjToStr, (TCA)convObjToStrHelper, DSSA, SSync,
|
||||
{{SSA, 0}}},
|
||||
{ConvCellToStr, (TCA)convCellToStrHelper, DSSA, SSync,
|
||||
{{TV, 0}}},
|
||||
|
||||
{AddElemStrKey, (TCA)addElemStringKeyHelper, DSSA, SNone,
|
||||
{{SSA, 0}, {SSA, 1}, {TV, 2}}},
|
||||
{AddElemIntKey, (TCA)addElemIntKeyHelper, DSSA, SNone,
|
||||
|
||||
@@ -100,7 +100,10 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
|
||||
case ConvDblToArr: return simplifyConvToArr(inst);
|
||||
case ConvIntToArr: return simplifyConvToArr(inst);
|
||||
case ConvStrToArr: return simplifyConvToArr(inst);
|
||||
case ConvToBool: return simplifyConvToBool(inst);
|
||||
case ConvArrToBool: return simplifyConvArrToBool(inst);
|
||||
case ConvDblToBool: return simplifyConvDblToBool(inst);
|
||||
case ConvIntToBool: return simplifyConvIntToBool(inst);
|
||||
case ConvStrToBool: return simplifyConvStrToBool(inst);
|
||||
case ConvArrToDbl: return simplifyConvArrToDbl(inst);
|
||||
case ConvBoolToDbl: return simplifyConvBoolToDbl(inst);
|
||||
case ConvIntToDbl: return simplifyConvIntToDbl(inst);
|
||||
@@ -109,8 +112,9 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
|
||||
case ConvBoolToInt: return simplifyConvBoolToInt(inst);
|
||||
case ConvDblToInt: return simplifyConvDblToInt(inst);
|
||||
case ConvStrToInt: return simplifyConvStrToInt(inst);
|
||||
case ConvToObj: return simplifyConvToObj(inst);
|
||||
case ConvToStr: return simplifyConvToStr(inst);
|
||||
case ConvBoolToStr: return simplifyConvBoolToStr(inst);
|
||||
case ConvDblToStr: return simplifyConvDblToStr(inst);
|
||||
case ConvIntToStr: return simplifyConvIntToStr(inst);
|
||||
case Unbox: return simplifyUnbox(inst);
|
||||
case UnboxPtr: return simplifyUnboxPtr(inst);
|
||||
case IsType:
|
||||
@@ -396,7 +400,10 @@ SSATmp* Simplifier::simplifyNot(SSATmp* src) {
|
||||
|
||||
// TODO: Add more algebraic simplification rules for NOT
|
||||
switch (op) {
|
||||
case ConvToBool:
|
||||
case ConvArrToBool:
|
||||
case ConvDblToBool:
|
||||
case ConvIntToBool:
|
||||
case ConvStrToBool:
|
||||
return simplifyNot(inst->getSrc(0));
|
||||
case OpXor: {
|
||||
// !!X --> bool(X)
|
||||
@@ -1069,34 +1076,40 @@ SSATmp* Simplifier::simplifyConvToArr(IRInstruction* inst) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToBool(IRInstruction* inst) {
|
||||
SSATmp* Simplifier::simplifyConvArrToBool(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType == Type::Bool) {
|
||||
return src;
|
||||
}
|
||||
if (srcType.isNull()) {
|
||||
return genDefBool(false);
|
||||
}
|
||||
if (srcType == Type::Obj) {
|
||||
if (src->isConst()) {
|
||||
if (src->getValArr()->empty()) {
|
||||
return genDefBool(false);
|
||||
}
|
||||
return genDefBool(true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvDblToBool(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
if (src->isConst()) {
|
||||
if (srcType == Type::Int) {
|
||||
return genDefBool(bool(src->getValInt()));
|
||||
}
|
||||
if (srcType == Type::StaticStr) {
|
||||
// only the strings "", and "0" convert to false, all other strings
|
||||
// are converted to true
|
||||
const StringData* str = src->getValStr();
|
||||
return genDefBool(!str->empty() && !str->isZero());
|
||||
}
|
||||
if (srcType.isArray()) {
|
||||
if (src->getValArr()->empty()) {
|
||||
return genDefBool(false);
|
||||
}
|
||||
return genDefBool(true);
|
||||
}
|
||||
return genDefBool(bool(src->getValDbl()));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvIntToBool(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
if (src->isConst()) {
|
||||
return genDefBool(bool(src->getValInt()));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvStrToBool(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
if (src->isConst()) {
|
||||
// only the strings "", and "0" convert to false, all other strings
|
||||
// are converted to true
|
||||
const StringData* str = src->getValStr();
|
||||
return genDefBool(!str->empty() && !str->isZero());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1178,43 +1191,31 @@ SSATmp* Simplifier::simplifyConvStrToInt(IRInstruction* inst) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToObj(IRInstruction* inst) {
|
||||
SSATmp* Simplifier::simplifyConvBoolToStr(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType == Type::Obj) {
|
||||
return src;
|
||||
if (src->isConst()) {
|
||||
if (src->getValBool()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("1"));
|
||||
}
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToStr(IRInstruction* inst) {
|
||||
SSATmp* Simplifier::simplifyConvDblToStr(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType.isString()) {
|
||||
return src;
|
||||
}
|
||||
// arrays always get converted to the string "Array"
|
||||
if (srcType.isArray()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("Array"));
|
||||
}
|
||||
if (srcType.isNull()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (srcType == Type::Bool) {
|
||||
if (src->getValBool()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("1"));
|
||||
}
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
if (srcType == Type::Int) {
|
||||
std::stringstream ss;
|
||||
ss << src->getValInt();
|
||||
return m_tb->genDefConst(StringData::GetStaticString(ss.str()));
|
||||
}
|
||||
if (srcType == Type::Dbl) {
|
||||
// TODO constant dbl to string
|
||||
}
|
||||
return m_tb->genDefConst(
|
||||
StringData::convert_double_helper(src->getValDbl()));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvIntToStr(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
if (src->isConst()) {
|
||||
return m_tb->genDefConst(
|
||||
StringData::convert_integer_helper(src->getValInt()));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,11 @@ private:
|
||||
SSATmp* simplifyJmpIsType(IRInstruction*);
|
||||
SSATmp* simplifyConcat(SSATmp* src1, SSATmp* src2);
|
||||
SSATmp* simplifyConvToArr(IRInstruction*);
|
||||
SSATmp* simplifyConvToBool(IRInstruction*);
|
||||
SSATmp* simplifyConvArrToBool(IRInstruction*);
|
||||
SSATmp* simplifyConvDblToBool(IRInstruction*);
|
||||
SSATmp* simplifyConvIntToBool(IRInstruction*);
|
||||
SSATmp* simplifyConvStrToBool(IRInstruction*);
|
||||
SSATmp* simplifyConvToDbl(IRInstruction*);
|
||||
SSATmp* simplifyConvArrToDbl(IRInstruction*);
|
||||
SSATmp* simplifyConvBoolToDbl(IRInstruction*);
|
||||
SSATmp* simplifyConvIntToDbl(IRInstruction*);
|
||||
@@ -73,8 +77,9 @@ private:
|
||||
SSATmp* simplifyConvDblToInt(IRInstruction*);
|
||||
SSATmp* simplifyConvObjToInt(IRInstruction*);
|
||||
SSATmp* simplifyConvStrToInt(IRInstruction*);
|
||||
SSATmp* simplifyConvToObj(IRInstruction*);
|
||||
SSATmp* simplifyConvToStr(IRInstruction*);
|
||||
SSATmp* simplifyConvBoolToStr(IRInstruction*);
|
||||
SSATmp* simplifyConvDblToStr(IRInstruction*);
|
||||
SSATmp* simplifyConvIntToStr(IRInstruction*);
|
||||
SSATmp* simplifyUnbox(IRInstruction*);
|
||||
SSATmp* simplifyUnboxPtr(IRInstruction*);
|
||||
SSATmp* simplifyCheckInit(IRInstruction* inst);
|
||||
|
||||
@@ -396,21 +396,26 @@ SSATmp* TraceBuilder::genDefNone() {
|
||||
return gen(DefConst, Type::None, &cdata);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToStr(SSATmp* src) {
|
||||
if (src->getType() == Type::Bool) {
|
||||
// Bool to string code sequence loads static strings
|
||||
return gen(ConvToStr, Type::StaticStr, src);
|
||||
} else {
|
||||
return gen(ConvToStr, Type::Str, src);
|
||||
}
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToObj(SSATmp* src) {
|
||||
return gen(ConvToObj, Type::Obj, src);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToBool(SSATmp* src) {
|
||||
return gen(ConvToBool, Type::Bool, src);
|
||||
Type fromType = src->getType();
|
||||
if (fromType.isBool()) {
|
||||
return src;
|
||||
} else if (fromType.isNull()) {
|
||||
return genDefConst(false);
|
||||
} else if (fromType.isArray()) {
|
||||
return gen(ConvArrToBool, src);
|
||||
} else if (fromType.isDbl()) {
|
||||
return gen(ConvDblToBool, src);
|
||||
} else if (fromType.isInt()) {
|
||||
return gen(ConvIntToBool, src);
|
||||
} else if (fromType.isString()) {
|
||||
return gen(ConvStrToBool, src);
|
||||
} else if (fromType.isObj()) {
|
||||
// If a value is known to be an object, it is known to be non null.
|
||||
return genDefConst(true);
|
||||
} else {
|
||||
return gen(ConvCellToBool, src);
|
||||
}
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genCmp(Opcode opc, SSATmp* src1, SSATmp* src2) {
|
||||
|
||||
@@ -187,10 +187,6 @@ public:
|
||||
SSATmp* genCmp(Opcode opc, SSATmp* src1, SSATmp* src2);
|
||||
SSATmp* genCastStk(uint32_t id, Type type);
|
||||
SSATmp* genConvToBool(SSATmp* src);
|
||||
SSATmp* genConvToDbl(SSATmp* src);
|
||||
SSATmp* genConvToStr(SSATmp* src);
|
||||
SSATmp* genConvToArr(SSATmp* src);
|
||||
SSATmp* genConvToObj(SSATmp* src);
|
||||
SSATmp* genLdPropAddr(SSATmp* obj, SSATmp* prop);
|
||||
SSATmp* genLdClsMethod(SSATmp* cls, uint32_t methodSlot);
|
||||
SSATmp* genLdClsMethodCache(SSATmp* className,
|
||||
|
||||
@@ -53,6 +53,134 @@ HOT_FUNC_VM RefData* box_value(TypedValue tv) {
|
||||
return tvBoxHelper(tv.m_type, tv.m_data.num);
|
||||
}
|
||||
|
||||
ArrayData* convCellToArrHelper(TypedValue tv) {
|
||||
// Note: the call sites of this function all assume that
|
||||
// no user code will run and no recoverable exceptions will
|
||||
// occur while running this code. This seems trivially true
|
||||
// in all cases but converting objects to arrays. It also
|
||||
// seems true for that case as well, since the resulting array
|
||||
// is essentially metadata for the object. If that is not true,
|
||||
// you might end up looking at this code in a debugger and now
|
||||
// you know why.
|
||||
tvCastToArrayInPlace(&tv); // consumes a ref on counted values
|
||||
return tv.m_data.parr;
|
||||
}
|
||||
|
||||
int64_t convArrToBoolHelper(const ArrayData* a) {
|
||||
return a->size() != 0;
|
||||
}
|
||||
|
||||
int64_t convStrToBoolHelper(const StringData* s) {
|
||||
return s->toBoolean();
|
||||
}
|
||||
|
||||
int64_t convCellToBoolHelper(TypedValue tv) {
|
||||
// Cannot call tvCastToBooleanInPlace here because some of the
|
||||
// call sites will not be increasing the ref count on tv before
|
||||
// calling, the ref count must be left alone.
|
||||
|
||||
switch (tv.m_type) {
|
||||
case KindOfUninit:
|
||||
case KindOfNull: return false;
|
||||
case KindOfBoolean: return tv.m_data.num;
|
||||
case KindOfInt64: return tv.m_data.num != 0;
|
||||
case KindOfDouble: return tv.m_data.dbl != 0;
|
||||
case KindOfStaticString:
|
||||
case KindOfString: return tv.m_data.pstr->toBoolean();
|
||||
case KindOfArray: return !tv.m_data.parr->empty();
|
||||
case KindOfObject: return tv.m_data.pobj != nullptr;
|
||||
default: not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t convArrToDblHelper(ArrayData* a) {
|
||||
return reinterpretDblAsInt(a->empty() ? 0 : 1);
|
||||
}
|
||||
|
||||
int64_t convStrToDblHelper(const StringData* s) {
|
||||
return reinterpretDblAsInt(s->toDouble());
|
||||
}
|
||||
|
||||
int64_t convCellToDblHelper(TypedValue tv) {
|
||||
tvCastToDoubleInPlace(&tv); // consumes a ref on counted values
|
||||
// but not if an exception happens. (REVIEW)
|
||||
return tv.m_data.num;
|
||||
}
|
||||
|
||||
int64_t convArrToIntHelper(ArrayData* a) {
|
||||
return a->empty() ? 0 : 1;
|
||||
}
|
||||
|
||||
int64_t convDblToIntHelper(int64_t i) {
|
||||
double d = reinterpretIntAsDbl(i);
|
||||
return (d >= 0 ? d > std::numeric_limits<uint64_t>::max() ? 0u :
|
||||
(uint64_t)d : (int64_t)d);
|
||||
}
|
||||
|
||||
int64_t convStrToIntHelper(const StringData* s) {
|
||||
return s->toInt64(10);
|
||||
}
|
||||
|
||||
int64_t convCellToIntHelper(TypedValue tv) {
|
||||
tvCastToInt64InPlace(&tv); // consumes a ref on counted values
|
||||
// but not if an exception happens. (REVIEW)
|
||||
return tv.m_data.num;
|
||||
}
|
||||
|
||||
ObjectData* convCellToObjHelper(TypedValue tv) {
|
||||
// Note: the call sites of this function all assume that
|
||||
// no user code will run and no recoverable exceptions will
|
||||
// occur while running this code. This seems trivially true
|
||||
// in all cases but converting arrays to objects. It also
|
||||
// seems true for that case as well, since the source array
|
||||
// is essentially metadata for the object. If that is not true,
|
||||
// you might end up looking at this code in a debugger and now
|
||||
// you know why.
|
||||
tvCastToObjectInPlace(&tv); // consumes a ref on counted values
|
||||
return tv.m_data.pobj;
|
||||
}
|
||||
|
||||
StringData* convDblToStrHelper(int64_t i) {
|
||||
double d = reinterpretIntAsDbl(i);
|
||||
auto r = buildStringData(d);
|
||||
r->incRefCount();
|
||||
return r;
|
||||
}
|
||||
|
||||
StringData* convIntToStrHelper(int64_t i) {
|
||||
auto r = buildStringData(i);
|
||||
r->incRefCount();
|
||||
return r;
|
||||
}
|
||||
|
||||
StringData* convObjToStrHelper(ObjectData* o) {
|
||||
try {
|
||||
auto s = o->t___tostring();
|
||||
auto r = s.get();
|
||||
o->decRefCount();
|
||||
if (!r->isStatic()) r->incRefCount();
|
||||
return r;
|
||||
} catch (...) {
|
||||
o->decRefCount();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
StringData* convCellToStrHelper(TypedValue tv) {
|
||||
switch (tv.m_type) {
|
||||
case KindOfUninit:
|
||||
case KindOfNull: return buildStringData("");
|
||||
case KindOfBoolean: return buildStringData(tv.m_data.num ? "1" : "");
|
||||
case KindOfInt64: return convIntToStrHelper(tv.m_data.num);
|
||||
case KindOfDouble: return convDblToStrHelper(tv.m_data.num);
|
||||
case KindOfStaticString:
|
||||
case KindOfString: return tv.m_data.pstr;
|
||||
case KindOfArray: tvDecRefArr(&tv); return buildStringData("Array");
|
||||
case KindOfObject: return convObjToStrHelper(tv.m_data.pobj);
|
||||
default: not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
void raisePropertyOnNonObject() {
|
||||
raise_warning("Cannot access property on non-object");
|
||||
}
|
||||
|
||||
@@ -57,6 +57,45 @@ ArrayData* addElemStringKeyHelper(ArrayData* ad, StringData* key,
|
||||
TypedValue setNewElem(TypedValue* base, Cell val);
|
||||
void bindNewElemIR(TypedValue* base, RefData* val, MInstrState* mis);
|
||||
RefData* box_value(TypedValue tv);
|
||||
ArrayData* convCellToArrHelper(TypedValue tv);
|
||||
|
||||
/* Helper functions for conversion instructions that are too
|
||||
complicated to inline */
|
||||
|
||||
inline int64_t reinterpretDblAsInt(double d) {
|
||||
union {
|
||||
int64_t intval;
|
||||
double dblval;
|
||||
} u;
|
||||
u.dblval = d;
|
||||
return u.intval;
|
||||
}
|
||||
|
||||
inline double reinterpretIntAsDbl(int64_t i) {
|
||||
union {
|
||||
int64_t intval;
|
||||
double dblval;
|
||||
} u;
|
||||
u.intval = i;
|
||||
return u.dblval;
|
||||
}
|
||||
|
||||
int64_t convArrToBoolHelper(const ArrayData* a);
|
||||
int64_t convStrToBoolHelper(const StringData* s);
|
||||
int64_t convCellToBoolHelper(TypedValue tv);
|
||||
int64_t convArrToDblHelper(ArrayData* a);
|
||||
int64_t convStrToDblHelper(const StringData* s);
|
||||
int64_t convCellToDblHelper(TypedValue tv);
|
||||
int64_t convArrToIntHelper(ArrayData* a);
|
||||
int64_t convDblToIntHelper(int64_t i);
|
||||
int64_t convStrToIntHelper(const StringData* s);
|
||||
int64_t convCellToIntHelper(TypedValue tv);
|
||||
ObjectData* convCellToObjHelper(TypedValue tv);
|
||||
StringData* convDblToStrHelper(int64_t i);
|
||||
StringData* convIntToStrHelper(int64_t i);
|
||||
StringData* convObjToStrHelper(ObjectData* o);
|
||||
StringData* convCellToStrHelper(TypedValue tv);
|
||||
|
||||
void raisePropertyOnNonObject();
|
||||
void raiseUndefProp(ObjectData* base, const StringData* name);
|
||||
void VerifyParamTypeFail(int param);
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário