HHIR mod.
Esse commit está contido em:
@@ -374,16 +374,22 @@ GuardRefs
|
||||
|
||||
2. Arithmetic
|
||||
|
||||
D:Int = OpAdd S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpSub S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpAnd S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpOr S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpXor S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpMul S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpAdd S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpSub S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpAnd S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpOr S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpXor S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:Int = OpMul S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:{Int|Bool} = OpMod S0:{Int|Bool} S1:{Int|Bool}
|
||||
D:{Int|Bool|Dbl} = OpDiv S0:{Int|Bool} S1:{Int|Bool}
|
||||
|
||||
Integer/boolean arithmetic. Performs the operation described by the
|
||||
opcode name on S0 and S1, and puts the result in D.
|
||||
|
||||
Note that OpMod and OpDiv produce boolean false when the divisor is
|
||||
zero-like. Ints are not closed under OpDiv, as OpDiv produces doubles
|
||||
when there is a non-zero remainder.
|
||||
|
||||
|
||||
3. Type conversions
|
||||
|
||||
@@ -905,6 +911,10 @@ RaiseError S0:Str
|
||||
|
||||
Raises a fatal error with the text in S0 as its message.
|
||||
|
||||
RaiseWarning S0:Str
|
||||
|
||||
Raises a warning with the text in S0 as its message.
|
||||
|
||||
D:StkPtr = GenericRetDecRefs S0:StkPtr S1:Gen S2:ConstInt
|
||||
|
||||
Does decrefs of all the current function's locals, where S0 is a
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <runtime/base/taint/taint_observer.h>
|
||||
#include <runtime/base/variable_unserializer.h>
|
||||
#include <runtime/base/util/request_local.h>
|
||||
#include <runtime/base/strings.h>
|
||||
#include <util/case_insensitive.h>
|
||||
|
||||
#if defined(__APPLE__) || defined(__USE_BSD)
|
||||
@@ -108,7 +109,7 @@ inline Numeric minus(CVarRef v1, CVarRef v2) { return v1 - v2;}
|
||||
inline Numeric divide(CVarRef v1, CVarRef v2) { return v1 / v2; }
|
||||
inline Numeric modulo(int64_t v1, int64_t v2) {
|
||||
if (UNLIKELY(v2 == 0)) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
return false;
|
||||
}
|
||||
if (UNLIKELY(uint64_t(v2+1) <= 2u)) {
|
||||
|
||||
@@ -28,6 +28,8 @@ const char* const CONSTANTS_MUST_BE_SCALAR =
|
||||
"Constants may only evaluate to scalar values";
|
||||
const char* const CONSTANTS_CASE_SENSITIVE =
|
||||
"Case insensitive constant names are not supported in HipHop";
|
||||
const char* const DIVISION_BY_ZERO =
|
||||
"Division by zero";
|
||||
const char* const UNDEFINED_CONSTANT =
|
||||
"Use of undefined constant %s - assumed '%s'";
|
||||
const char* const UNDEFINED_VARIABLE = "Undefined variable: %s";
|
||||
|
||||
@@ -1037,7 +1037,7 @@ Variant Variant::operator/(CVarRef var) const {
|
||||
}
|
||||
|
||||
if ((int2 && lval2 == 0) || (!int2 && dval2 == 0)) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1095,7 +1095,7 @@ Variant &Variant::operator/=(CVarRef var) {
|
||||
}
|
||||
|
||||
if ((int2 && lval2 == 0) || (!int2 && dval2 == 0)) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
@@ -1121,7 +1121,7 @@ Variant &Variant::operator/=(int64_t n) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (n == 0) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
@@ -1149,7 +1149,7 @@ Variant &Variant::operator/=(double n) {
|
||||
throw BadArrayOperandException();
|
||||
}
|
||||
if (n == 0.0) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
@@ -1164,7 +1164,7 @@ int64_t Variant::operator%(CVarRef var) const {
|
||||
int64_t lval = toInt64();
|
||||
int64_t lval2 = var.toInt64();
|
||||
if (lval2 == 0) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
return false;
|
||||
}
|
||||
return lval % lval2;
|
||||
@@ -1174,7 +1174,7 @@ Variant &Variant::operator%=(CVarRef var) {
|
||||
int64_t lval = toInt64();
|
||||
int64_t lval2 = var.toInt64();
|
||||
if (lval2 == 0) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
@@ -1184,7 +1184,7 @@ Variant &Variant::operator%=(CVarRef var) {
|
||||
|
||||
Variant &Variant::operator%=(int64_t n) {
|
||||
if (n == 0) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
@@ -1194,7 +1194,7 @@ Variant &Variant::operator%=(int64_t n) {
|
||||
|
||||
Variant &Variant::operator%=(double n) {
|
||||
if ((int64_t)n == 0) {
|
||||
raise_warning("Division by zero");
|
||||
raise_warning(Strings::DIVISION_BY_ZERO);
|
||||
set(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -3952,7 +3952,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopMul(PC& pc) {
|
||||
|
||||
#define MATHOP_DIVCHECK(x) \
|
||||
if (b == x) { \
|
||||
raise_warning("Division by zero"); \
|
||||
raise_warning(Strings::DIVISION_BY_ZERO); \
|
||||
c2->m_data.num = 0; \
|
||||
c2->m_type = KindOfBoolean; \
|
||||
} else
|
||||
|
||||
@@ -519,5 +519,15 @@ int init_closure(ActRec* ar, TypedValue* sp) {
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
void raiseWarning(const StringData* sd) {
|
||||
raise_warning("%s", sd->data());
|
||||
}
|
||||
|
||||
HOT_FUNC int64_t modHelper(int64_t left, int64_t right) {
|
||||
// We already dealt with divide-by-zero up in hhbctranslator.
|
||||
assert(right != 0);
|
||||
return left % right;
|
||||
}
|
||||
|
||||
} } // HPHP::VM
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ void print_string(StringData* s);
|
||||
void print_int(int64_t i);
|
||||
void print_boolean(bool val);
|
||||
|
||||
void raiseWarning(const StringData* sd);
|
||||
int64_t modHelper(int64_t left, int64_t right);
|
||||
|
||||
inline Iter*
|
||||
frame_iter(const ActRec* fp, int i) {
|
||||
return (Iter*)(uintptr_t(fp)
|
||||
|
||||
@@ -333,9 +333,11 @@ CALL_OPCODE(WarnNonObjProp)
|
||||
CALL_OPCODE(ThrowNonObjProp)
|
||||
CALL_OPCODE(RaiseUndefProp)
|
||||
CALL_OPCODE(RaiseError)
|
||||
CALL_OPCODE(RaiseWarning)
|
||||
CALL_OPCODE(IncStatGrouped)
|
||||
CALL_OPCODE(StaticLocInit)
|
||||
CALL_OPCODE(StaticLocInitCached)
|
||||
CALL_OPCODE(OpMod)
|
||||
|
||||
// Vector instruction helpers
|
||||
CALL_OPCODE(BaseG)
|
||||
@@ -1068,6 +1070,10 @@ void CodeGenerator::cgOpOr(IRInstruction* inst) {
|
||||
Commutative);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgOpDiv(IRInstruction* inst) {
|
||||
not_implemented();
|
||||
}
|
||||
|
||||
void CodeGenerator::cgOpXor(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src1 = inst->getSrc(0);
|
||||
@@ -4940,13 +4946,9 @@ void CodeGenerator::cgDbgAssertRefCount(IRInstruction* inst) {
|
||||
}
|
||||
|
||||
void traceCallback(ActRec* fp, Cell* sp, int64_t pcOff, void* rip) {
|
||||
#if 0
|
||||
const Func* func = fp->m_func;
|
||||
std::cout << func->fullName()->data()
|
||||
<< " " << pcOff
|
||||
<< " " << rip
|
||||
<< std::endl;
|
||||
#endif
|
||||
if (HPHP::Trace::moduleEnabled(HPHP::Trace::hhirTracelets)) {
|
||||
FTRACE(0, "{} {} {}\n", fp->m_func->fullName()->data(), pcOff, rip);
|
||||
}
|
||||
checkFrame(fp, sp, /*checkLocals*/true);
|
||||
}
|
||||
|
||||
|
||||
@@ -2416,18 +2416,55 @@ void HhbcTranslator::emitNot() {
|
||||
m_tb->genDecRef(src);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitAdd() {
|
||||
TRACE(3, "%u: Add\n", m_bcOff);
|
||||
emitBinaryArith(OpAdd);
|
||||
#define BINOP(Opp) \
|
||||
void HhbcTranslator::emit ## Opp() { \
|
||||
TRACE(3, "%u: " #Opp "\n", m_bcOff); \
|
||||
emitBinaryArith(Op ## Opp); \
|
||||
}
|
||||
void HhbcTranslator::emitSub() {
|
||||
TRACE(3, "%u: Sub\n", m_bcOff);
|
||||
emitBinaryArith(OpSub);
|
||||
BINOP(Add)
|
||||
BINOP(Sub)
|
||||
BINOP(Mul)
|
||||
BINOP(BitAnd)
|
||||
BINOP(BitOr)
|
||||
BINOP(BitXor)
|
||||
#undef BINOP
|
||||
|
||||
void HhbcTranslator::emitDiv() {
|
||||
emitInterpOne(Type::Cell, 2);
|
||||
}
|
||||
void HhbcTranslator::emitMul() {
|
||||
TRACE(3, "%u: Mul\n", m_bcOff);
|
||||
emitBinaryArith(OpMul);
|
||||
|
||||
void HhbcTranslator::emitMod() {
|
||||
auto tl = topC(1)->getType();
|
||||
auto tr = topC(0)->getType();
|
||||
auto isInty = [&](Type t) {
|
||||
return t.subtypeOf(Type::Null | Type::Bool | Type::Int);
|
||||
};
|
||||
if (!(isInty(tl) && isInty(tr))) {
|
||||
emitInterpOne(Type::Cell, 2);
|
||||
return;
|
||||
}
|
||||
SSATmp* r = popC();
|
||||
SSATmp* l = popC();
|
||||
// Exit path spills an additional false
|
||||
auto exitSpillValues = getSpillValues();
|
||||
exitSpillValues.push_back(m_tb->genDefConst(false));
|
||||
// Generate an exit for the rare case that r is zero
|
||||
auto exit =
|
||||
m_tb->ifThenExit(getCurFunc(),
|
||||
m_stackDeficit,
|
||||
exitSpillValues,
|
||||
[&](IRFactory* irf, Trace* t) {
|
||||
// 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,
|
||||
cns(StringData::GetStaticString(Strings::DIVISION_BY_ZERO)));
|
||||
},
|
||||
getNextSrcKey().offset() /* exitBcOff */, m_bcOff);
|
||||
m_tb->gen(JmpZero, exit, r);
|
||||
push(m_tb->gen(OpMod, Type::Int, l, r));
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitBitNot() {
|
||||
TRACE(3, "%u: BitNot\n", m_bcOff);
|
||||
Type srcType = topC()->getType();
|
||||
@@ -2448,18 +2485,7 @@ void HhbcTranslator::emitBitNot() {
|
||||
emitInterpOne(resultType, 1);
|
||||
}
|
||||
}
|
||||
void HhbcTranslator::emitBitAnd() {
|
||||
TRACE(3, "%u: BitAnd\n", m_bcOff);
|
||||
emitBinaryArith(OpAnd);
|
||||
}
|
||||
void HhbcTranslator::emitBitOr() {
|
||||
TRACE(3, "%u: BitOr\n", m_bcOff);
|
||||
emitBinaryArith(OpOr);
|
||||
}
|
||||
void HhbcTranslator::emitBitXor() {
|
||||
TRACE(3, "%u: BitXor\n", m_bcOff);
|
||||
emitBinaryArith(OpXor);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitXor() {
|
||||
TRACE(3, "%u: Xor\n", m_bcOff);
|
||||
SSATmp* btr = popC();
|
||||
@@ -2533,13 +2559,12 @@ std::vector<SSATmp*> HhbcTranslator::getSpillValues() const {
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates an exit trace which will continue the VM execution at the given
|
||||
* nextByteCode (defaults to the current m_bcOff) without using HHIR.
|
||||
* This should be used in situations that HHIR cannot handle -- ideally only in
|
||||
* slow paths.
|
||||
* Generates an exit trace which will continue execution without HHIR.
|
||||
* This should be used in situations that HHIR cannot handle -- ideally
|
||||
* only in slow paths.
|
||||
*/
|
||||
Trace* HhbcTranslator::getExitSlowTrace() {
|
||||
std::vector<SSATmp*> stackValues = getSpillValues();
|
||||
auto stackValues = getSpillValues();
|
||||
return m_tb->getExitSlowTrace(m_bcOff,
|
||||
m_stackDeficit,
|
||||
stackValues.size(),
|
||||
@@ -2564,10 +2589,10 @@ Trace* HhbcTranslator::getExitTrace(Offset targetBcOff /* = -1 */) {
|
||||
|
||||
std::vector<SSATmp*> stackValues = getSpillValues();
|
||||
return m_tb->genExitTrace(targetBcOff,
|
||||
m_stackDeficit,
|
||||
stackValues.size(),
|
||||
stackValues.size() ? &stackValues[0] : nullptr,
|
||||
TraceExitType::Normal);
|
||||
m_stackDeficit,
|
||||
stackValues.size(),
|
||||
stackValues.size() ? &stackValues[0] : nullptr,
|
||||
TraceExitType::Normal);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -278,6 +278,8 @@ struct HhbcTranslator {
|
||||
void emitBitXor();
|
||||
void emitBitNot();
|
||||
void emitMul();
|
||||
void emitMod();
|
||||
void emitDiv();
|
||||
|
||||
// boolean ops
|
||||
void emitXor();
|
||||
|
||||
@@ -167,6 +167,8 @@ O(OpAnd, D(Int), SNumInt SNumInt, C) \
|
||||
O(OpOr, D(Int), SNum SNum, C) \
|
||||
O(OpXor, D(Int), SNumInt SNumInt, C) \
|
||||
O(OpMul, DParam, SNum SNum, C) \
|
||||
O(OpDiv, DParam, SNum SNum, C) \
|
||||
O(OpMod, D(Int), SNumInt SNumInt, C|N) \
|
||||
\
|
||||
O(ConvBoolToArr, D(Arr), S(Bool), C|N) \
|
||||
O(ConvDblToArr, D(Arr), S(Dbl), C|N) \
|
||||
@@ -240,6 +242,7 @@ O(ExitWhenSurprised, ND, NA, E) \
|
||||
O(ExitOnVarEnv, ND, S(StkPtr), E) \
|
||||
O(ReleaseVVOrExit, ND, S(StkPtr), N|E) \
|
||||
O(RaiseError, ND, S(Str), E|N|Mem|Refs|T) \
|
||||
O(RaiseWarning, ND, S(Str), E|N|Mem|Refs|Er) \
|
||||
O(CheckInit, ND, S(Gen), NF) \
|
||||
O(CheckInitMem, ND, S(PtrToGen) C(Int), NF) \
|
||||
O(Unbox, DUnbox(0), S(Gen), NF) \
|
||||
@@ -558,6 +561,12 @@ enum Opcode : uint16_t {
|
||||
#define O(name, dsts, srcs, flags) name,
|
||||
IR_OPCODES
|
||||
#undef O
|
||||
|
||||
// Agree with hhbc on the names of these, to ease macro implementations.
|
||||
OpBitAnd = OpAnd,
|
||||
OpBitOr = OpOr,
|
||||
OpBitXor = OpXor,
|
||||
|
||||
IR_NUM_OPCODES
|
||||
};
|
||||
|
||||
|
||||
@@ -145,19 +145,25 @@ TranslatorX64::irEmitLoadDeps() {
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateMod(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
HHIR_EMIT(Mod);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::irTranslateBinaryArithOp(const Tracelet& t,
|
||||
const NormalizedInstruction& i) {
|
||||
const Opcode op = i.op();
|
||||
switch (op) {
|
||||
#define CASE(OpBc, x64op) \
|
||||
#define CASE(OpBc) \
|
||||
case Op ## OpBc: HHIR_EMIT(OpBc);
|
||||
CASE(Add, add)
|
||||
CASE(Sub, sub)
|
||||
CASE(BitAnd, and)
|
||||
CASE(BitOr, or)
|
||||
CASE(BitXor, xor)
|
||||
CASE(Mul, imul)
|
||||
CASE(Add)
|
||||
CASE(Sub)
|
||||
CASE(BitAnd)
|
||||
CASE(BitOr)
|
||||
CASE(BitXor)
|
||||
CASE(Mul)
|
||||
#undef CASE
|
||||
default: {
|
||||
not_reached();
|
||||
|
||||
@@ -85,6 +85,8 @@ static CallMap s_callMap({
|
||||
{{TV, 0}, {SSA, 1}}},
|
||||
{VerifyParamFail, (TCA)VerifyParamTypeFail, DNone, SSync, {{SSA, 0}}},
|
||||
{RaiseUninitLoc, (TCA)raiseUndefVariable, DNone, SSync, {{SSA, 0}}},
|
||||
{RaiseWarning, (TCA)raiseWarning, DNone, SSync, {{SSA, 0}}},
|
||||
{OpMod, (TCA)modHelper, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
|
||||
{WarnNonObjProp, (TCA)raisePropertyOnNonObject, DNone, SSync, {}},
|
||||
{ThrowNonObjProp, (TCA)throw_null_object_prop, DNone, SSync, {}},
|
||||
{RaiseUndefProp, (TCA)raiseUndefProp, DNone, SSync,
|
||||
|
||||
@@ -251,7 +251,8 @@ Trace* TraceBuilder::genExitGuardFailure(uint32_t bcOff) {
|
||||
}
|
||||
|
||||
/*
|
||||
* genExitSlow generates a target exit trace for TraceExitType::Slow branches.
|
||||
* getExitSlowTrace generates a target exit trace for
|
||||
* TraceExitType::Slow branches.
|
||||
*/
|
||||
Trace* TraceBuilder::getExitSlowTrace(uint32_t bcOff,
|
||||
int32_t stackDeficit,
|
||||
@@ -291,9 +292,11 @@ void TraceBuilder::genTraceEnd(uint32_t nextPc,
|
||||
Trace* TraceBuilder::genExitTrace(uint32_t bcOff,
|
||||
int32_t stackDeficit,
|
||||
uint32_t numOpnds,
|
||||
SSATmp** opnds,
|
||||
SSATmp* const* opnds,
|
||||
TraceExitType::ExitType exitType,
|
||||
uint32_t notTakenBcOff) {
|
||||
uint32_t notTakenBcOff,
|
||||
std::function<void(IRFactory*, Trace*)>
|
||||
beforeExit) {
|
||||
Trace* exitTrace = makeExitTrace(bcOff);
|
||||
|
||||
MarkerData marker;
|
||||
@@ -302,6 +305,9 @@ Trace* TraceBuilder::genExitTrace(uint32_t bcOff,
|
||||
marker.func = m_curFunc->getValFunc();
|
||||
exitTrace->back()->push_back(m_irFactory.gen(Marker, &marker));
|
||||
|
||||
if (beforeExit) {
|
||||
beforeExit(&m_irFactory, exitTrace);
|
||||
}
|
||||
SSATmp* sp = m_spValue;
|
||||
if (numOpnds != 0 || stackDeficit != 0) {
|
||||
SSATmp* srcs[numOpnds + 2];
|
||||
@@ -314,25 +320,19 @@ Trace* TraceBuilder::genExitTrace(uint32_t bcOff,
|
||||
exitTrace->back()->push_back(spillInst);
|
||||
}
|
||||
SSATmp* pc = genDefConst<int64_t>(bcOff);
|
||||
IRInstruction* instr = nullptr;
|
||||
if (exitType == TraceExitType::NormalCc) {
|
||||
assert(notTakenBcOff != 0);
|
||||
SSATmp* notTakenPC = genDefConst(notTakenBcOff);
|
||||
instr = m_irFactory.gen(getExitOpcode(exitType),
|
||||
m_curFunc,
|
||||
pc,
|
||||
sp,
|
||||
m_fpValue,
|
||||
notTakenPC);
|
||||
genFor(exitTrace, getExitOpcode(exitType),
|
||||
m_curFunc,
|
||||
pc, sp, m_fpValue,
|
||||
notTakenPC);
|
||||
} else {
|
||||
assert(notTakenBcOff == 0);
|
||||
instr = m_irFactory.gen(getExitOpcode(exitType),
|
||||
m_curFunc,
|
||||
pc,
|
||||
sp,
|
||||
m_fpValue);
|
||||
genFor(exitTrace, getExitOpcode(exitType),
|
||||
m_curFunc,
|
||||
pc, sp, m_fpValue);
|
||||
}
|
||||
exitTrace->back()->push_back(instr);
|
||||
return exitTrace;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,13 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
IRInstruction* genFor(Trace* t, Args... args) {
|
||||
auto instr = m_irFactory.gen(args...);
|
||||
t->back()->push_back(instr);
|
||||
return instr;
|
||||
}
|
||||
|
||||
SSATmp* genDefCns(const StringData* cnsName, SSATmp* val);
|
||||
SSATmp* genConcat(SSATmp* tl, SSATmp* tr);
|
||||
void genDefCls(PreClass*, const HPHP::VM::Opcode* after);
|
||||
@@ -248,12 +255,14 @@ public:
|
||||
* Lifetime of the returned pointer is managed by the trace this
|
||||
* TraceBuilder is generating.
|
||||
*/
|
||||
typedef std::function<void(IRFactory*, Trace*)> ExitTraceCallback;
|
||||
Trace* genExitTrace(uint32_t bcOff,
|
||||
int32_t stackDeficit,
|
||||
uint32_t numOpnds,
|
||||
SSATmp** opnds,
|
||||
SSATmp* const* opnds,
|
||||
TraceExitType::ExitType,
|
||||
uint32_t notTakenBcOff = 0);
|
||||
uint32_t notTakenBcOff = 0,
|
||||
ExitTraceCallback beforeExit = ExitTraceCallback());
|
||||
|
||||
/*
|
||||
* Generates a target exit trace for GuardFailure exits.
|
||||
@@ -360,6 +369,22 @@ public:
|
||||
appendBlock(done_block);
|
||||
}
|
||||
|
||||
/*
|
||||
* ifThenExit produces a conditional exit with user-supplied logic
|
||||
* if the exit is taken.
|
||||
*/
|
||||
Trace* ifThenExit(const Func* func,
|
||||
int stackDeficit,
|
||||
const std::vector<SSATmp*> &stackValues,
|
||||
ExitTraceCallback exit,
|
||||
Offset exitBcOff,
|
||||
Offset bcOff) {
|
||||
return genExitTrace(exitBcOff, stackDeficit,
|
||||
stackValues.size(),
|
||||
stackValues.size() ? &stackValues[0] : nullptr,
|
||||
TraceExitType::NormalCc, bcOff /* notTakenOff */, exit);
|
||||
}
|
||||
|
||||
/*
|
||||
* ifElse generates if-then-else blocks with an empty 'then' block
|
||||
* that do not produce values. Code emitted in the next lambda will
|
||||
|
||||
@@ -6075,6 +6075,15 @@ TranslatorX64::translateXor(const Tracelet& t,
|
||||
a. xor_reg64_reg64(src, srcdest);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::analyzeMod(Tracelet& t, NormalizedInstruction& i) {
|
||||
i.m_txFlags = nativePlan(false);
|
||||
}
|
||||
|
||||
void TranslatorX64::translateMod(const Tracelet& t, const NormalizedInstruction& i) {
|
||||
not_reached();
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorX64::analyzeNot(Tracelet& t, NormalizedInstruction& i) {
|
||||
assert(i.inputs.size() == 1);
|
||||
|
||||
@@ -543,6 +543,7 @@ MINSTRS
|
||||
CASE(Add) \
|
||||
CASE(Xor) \
|
||||
CASE(Not) \
|
||||
CASE(Mod) \
|
||||
CASE(BitNot) \
|
||||
CASE(CastInt) \
|
||||
CASE(CastString) \
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?
|
||||
|
||||
function f() {
|
||||
$a = range(-3, 3);
|
||||
$a []= true;
|
||||
$a []= false;
|
||||
$a []= 3.14;
|
||||
$a []= "123";
|
||||
$a []= "0";
|
||||
foreach ($a as $l) {
|
||||
foreach ($a as $r) {
|
||||
var_dump($l % $r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
int(0)
|
||||
int(-1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(-1)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(-3)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(-2)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(-2)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(-2)
|
||||
int(-2)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(-1)
|
||||
int(-1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(-1)
|
||||
int(-1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(-1)
|
||||
int(-1)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(1)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(1)
|
||||
int(1)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(2)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(2)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(2)
|
||||
int(2)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(3)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(1)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(1)
|
||||
int(1)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(3)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(1)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
int(0)
|
||||
int(0)
|
||||
HipHop Warning: Division by zero in %s on line 12
|
||||
bool(false)
|
||||
Link simbólico
+1
@@ -0,0 +1 @@
|
||||
default.filter
|
||||
@@ -80,6 +80,7 @@ namespace Trace {
|
||||
TM(txdeps) \
|
||||
TM(typeProfile) \
|
||||
TM(hhir) \
|
||||
TM(hhirTracelets) \
|
||||
TM(gc) \
|
||||
TM(unlikely) \
|
||||
TM(jcc) \
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário