From 197305cc45247c2b6d860cd1faca8269792ed943 Mon Sep 17 00:00:00 2001 From: kma Date: Thu, 11 Apr 2013 23:40:38 -0700 Subject: [PATCH] HHIR mod. --- hphp/doc/ir.specification | 22 ++- hphp/runtime/base/builtin_functions.h | 3 +- hphp/runtime/base/strings.h | 2 + hphp/runtime/base/type_variant.cpp | 16 +- hphp/runtime/vm/bytecode.cpp | 2 +- hphp/runtime/vm/runtime.cpp | 10 + hphp/runtime/vm/runtime.h | 3 + hphp/runtime/vm/translator/hopt/codegen.cpp | 16 +- .../vm/translator/hopt/hhbctranslator.cpp | 85 ++++++--- .../vm/translator/hopt/hhbctranslator.h | 2 + hphp/runtime/vm/translator/hopt/ir.h | 9 + .../vm/translator/hopt/irtranslator.cpp | 20 +- .../vm/translator/hopt/nativecalls.cpp | 2 + .../vm/translator/hopt/tracebuilder.cpp | 32 ++-- .../runtime/vm/translator/hopt/tracebuilder.h | 29 ++- hphp/runtime/vm/translator/translator-x64.cpp | 9 + hphp/runtime/vm/translator/translator-x64.h | 1 + hphp/test/vm/mod.php | 18 ++ hphp/test/vm/mod.php.expectf | 180 ++++++++++++++++++ hphp/test/vm/mod.php.filter | 1 + hphp/util/trace.h | 1 + 21 files changed, 385 insertions(+), 78 deletions(-) create mode 100644 hphp/test/vm/mod.php create mode 100644 hphp/test/vm/mod.php.expectf create mode 120000 hphp/test/vm/mod.php.filter diff --git a/hphp/doc/ir.specification b/hphp/doc/ir.specification index 1252c8ede..379915b29 100644 --- a/hphp/doc/ir.specification +++ b/hphp/doc/ir.specification @@ -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 diff --git a/hphp/runtime/base/builtin_functions.h b/hphp/runtime/base/builtin_functions.h index 78ec5da27..2548fd1e8 100644 --- a/hphp/runtime/base/builtin_functions.h +++ b/hphp/runtime/base/builtin_functions.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #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)) { diff --git a/hphp/runtime/base/strings.h b/hphp/runtime/base/strings.h index d8cd67372..3e0f3d06c 100644 --- a/hphp/runtime/base/strings.h +++ b/hphp/runtime/base/strings.h @@ -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"; diff --git a/hphp/runtime/base/type_variant.cpp b/hphp/runtime/base/type_variant.cpp index bf27a34a8..5da4cddcf 100644 --- a/hphp/runtime/base/type_variant.cpp +++ b/hphp/runtime/base/type_variant.cpp @@ -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; } diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 4da3c8c5f..3e4098771 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -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 diff --git a/hphp/runtime/vm/runtime.cpp b/hphp/runtime/vm/runtime.cpp index 972e62951..3baf54388 100644 --- a/hphp/runtime/vm/runtime.cpp +++ b/hphp/runtime/vm/runtime.cpp @@ -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 diff --git a/hphp/runtime/vm/runtime.h b/hphp/runtime/vm/runtime.h index 9aeb89273..feac2fac8 100644 --- a/hphp/runtime/vm/runtime.h +++ b/hphp/runtime/vm/runtime.h @@ -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) diff --git a/hphp/runtime/vm/translator/hopt/codegen.cpp b/hphp/runtime/vm/translator/hopt/codegen.cpp index 726f0f720..aee409912 100644 --- a/hphp/runtime/vm/translator/hopt/codegen.cpp +++ b/hphp/runtime/vm/translator/hopt/codegen.cpp @@ -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); } diff --git a/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp b/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp index b7633894e..2ac9e5640 100644 --- a/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp +++ b/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp @@ -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 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 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 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); } /* diff --git a/hphp/runtime/vm/translator/hopt/hhbctranslator.h b/hphp/runtime/vm/translator/hopt/hhbctranslator.h index dfc766531..990f13605 100644 --- a/hphp/runtime/vm/translator/hopt/hhbctranslator.h +++ b/hphp/runtime/vm/translator/hopt/hhbctranslator.h @@ -278,6 +278,8 @@ struct HhbcTranslator { void emitBitXor(); void emitBitNot(); void emitMul(); + void emitMod(); + void emitDiv(); // boolean ops void emitXor(); diff --git a/hphp/runtime/vm/translator/hopt/ir.h b/hphp/runtime/vm/translator/hopt/ir.h index bfdfd1359..f1b4a98d1 100644 --- a/hphp/runtime/vm/translator/hopt/ir.h +++ b/hphp/runtime/vm/translator/hopt/ir.h @@ -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 }; diff --git a/hphp/runtime/vm/translator/hopt/irtranslator.cpp b/hphp/runtime/vm/translator/hopt/irtranslator.cpp index 92d2fdd6e..91179cd6c 100644 --- a/hphp/runtime/vm/translator/hopt/irtranslator.cpp +++ b/hphp/runtime/vm/translator/hopt/irtranslator.cpp @@ -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(); diff --git a/hphp/runtime/vm/translator/hopt/nativecalls.cpp b/hphp/runtime/vm/translator/hopt/nativecalls.cpp index 10832bdf5..91ecbb8cc 100644 --- a/hphp/runtime/vm/translator/hopt/nativecalls.cpp +++ b/hphp/runtime/vm/translator/hopt/nativecalls.cpp @@ -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, diff --git a/hphp/runtime/vm/translator/hopt/tracebuilder.cpp b/hphp/runtime/vm/translator/hopt/tracebuilder.cpp index 27917342a..23767b457 100644 --- a/hphp/runtime/vm/translator/hopt/tracebuilder.cpp +++ b/hphp/runtime/vm/translator/hopt/tracebuilder.cpp @@ -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 + 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(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; } diff --git a/hphp/runtime/vm/translator/hopt/tracebuilder.h b/hphp/runtime/vm/translator/hopt/tracebuilder.h index 1ad22b395..e06c8075a 100644 --- a/hphp/runtime/vm/translator/hopt/tracebuilder.h +++ b/hphp/runtime/vm/translator/hopt/tracebuilder.h @@ -73,6 +73,13 @@ public: ); } + template + 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 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 &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 diff --git a/hphp/runtime/vm/translator/translator-x64.cpp b/hphp/runtime/vm/translator/translator-x64.cpp index 37df3df9f..d69499ac7 100644 --- a/hphp/runtime/vm/translator/translator-x64.cpp +++ b/hphp/runtime/vm/translator/translator-x64.cpp @@ -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); diff --git a/hphp/runtime/vm/translator/translator-x64.h b/hphp/runtime/vm/translator/translator-x64.h index efeb8b253..f127ecac7 100644 --- a/hphp/runtime/vm/translator/translator-x64.h +++ b/hphp/runtime/vm/translator/translator-x64.h @@ -543,6 +543,7 @@ MINSTRS CASE(Add) \ CASE(Xor) \ CASE(Not) \ + CASE(Mod) \ CASE(BitNot) \ CASE(CastInt) \ CASE(CastString) \ diff --git a/hphp/test/vm/mod.php b/hphp/test/vm/mod.php new file mode 100644 index 000000000..41ae01676 --- /dev/null +++ b/hphp/test/vm/mod.php @@ -0,0 +1,18 @@ +