diff --git a/hphp/compiler/expression/binary_op_expression.cpp b/hphp/compiler/expression/binary_op_expression.cpp index c74ca6d83..e75c84755 100644 --- a/hphp/compiler/expression/binary_op_expression.cpp +++ b/hphp/compiler/expression/binary_op_expression.cpp @@ -584,9 +584,11 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) { *result.asCell() = cellMod(*v1.asCell(), *v2.asCell()); break; case T_SL: - result = shift_left(v1.toInt64(), v2.toInt64()); break; + result = v1.toInt64() << v2.toInt64(); + break; case T_SR: - result = shift_right(v1.toInt64(), v2.toInt64()); break; + result = v1.toInt64() >> v2.toInt64(); + break; case T_BOOLEAN_OR: result = v1.toBoolean() || v2.toBoolean(); break; case T_BOOLEAN_AND: diff --git a/hphp/runtime/base/builtin_functions.h b/hphp/runtime/base/builtin_functions.h index 23257c57a..2e09d3382 100644 --- a/hphp/runtime/base/builtin_functions.h +++ b/hphp/runtime/base/builtin_functions.h @@ -90,10 +90,7 @@ bool empty(CVarRef v, CStrRef, bool = false) = delete; /////////////////////////////////////////////////////////////////////////////// // operators -inline int64_t shift_left(int64_t v1, int64_t v2) { return v1 << v2; } -inline int64_t shift_right(int64_t v1, int64_t v2) { return v1 >> v2; } - -inline String concat(CStrRef s1, CStrRef s2) { +inline String concat(CStrRef s1, CStrRef s2) { return s1 + s2; } diff --git a/hphp/runtime/base/tv_helpers.h b/hphp/runtime/base/tv_helpers.h index 981db0e4c..0fbeb5778 100644 --- a/hphp/runtime/base/tv_helpers.h +++ b/hphp/runtime/base/tv_helpers.h @@ -457,6 +457,7 @@ void tvUnboxIfNeeded(TypedValue* tv); */ void tvCastToBooleanInPlace(TypedValue* tv); void tvCastToInt64InPlace(TypedValue* tv); +void cellCastToInt64InPlace(Cell*); void tvCastToDoubleInPlace(TypedValue* tv); double tvCastToDouble(TypedValue* tv); void tvCastToStringInPlace(TypedValue* tv); diff --git a/hphp/runtime/base/type_variant.cpp b/hphp/runtime/base/type_variant.cpp index 3688c1447..3f148bfca 100644 --- a/hphp/runtime/base/type_variant.cpp +++ b/hphp/runtime/base/type_variant.cpp @@ -624,16 +624,6 @@ Variant Variant::bitNot() const { throw InvalidOperandException("only numerics and strings can be negated"); } -Variant &Variant::operator<<=(int64_t n) { - set(toInt64() << n); - return *this; -} - -Variant &Variant::operator>>=(int64_t n) { - set(toInt64() >> n); - return *this; -} - /////////////////////////////////////////////////////////////////////////////// // increment/decrement diff --git a/hphp/runtime/base/type_variant.h b/hphp/runtime/base/type_variant.h index 06cc90772..d599619c0 100644 --- a/hphp/runtime/base/type_variant.h +++ b/hphp/runtime/base/type_variant.h @@ -581,8 +581,8 @@ class Variant : private TypedValue { Variant &operator &= (CVarRef v) = delete; Variant operator ^ (CVarRef v) const = delete; Variant &operator ^= (CVarRef v) = delete; - Variant &operator <<=(int64_t n); - Variant &operator >>=(int64_t n); + Variant &operator <<=(int64_t n) = delete; + Variant &operator >>=(int64_t n) = delete; Variant &operator ++ (); Variant operator ++ (int); diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 5856f8bed..634a05c86 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -3688,6 +3688,17 @@ void OPTBLD_INLINE VMExecutionContext::implCellBinOp(PC& pc, Op op) { m_stack.popC(); } +template +void OPTBLD_INLINE VMExecutionContext::implCellBinOpBool(PC& pc, Op op) { + NEXT(); + auto const c1 = m_stack.topC(); + auto const c2 = m_stack.indC(1); + bool const result = op(*c2, *c1); + tvRefcountedDecRefCell(c2); + *c2 = make_tv(result); + m_stack.popC(); +} + inline void OPTBLD_INLINE VMExecutionContext::iopAdd(PC& pc) { implCellBinOp(pc, cellAdd); } @@ -3720,17 +3731,6 @@ inline void OPTBLD_INLINE VMExecutionContext::iopBitXor(PC& pc) { implCellBinOp(pc, cellBitXor); } -template -void OPTBLD_INLINE VMExecutionContext::implCellBinOpBool(PC& pc, Op op) { - NEXT(); - auto const c1 = m_stack.topC(); - auto const c2 = m_stack.indC(1); - bool const result = op(*c2, *c1); - tvRefcountedDecRefCell(c2); - *c2 = make_tv(result); - m_stack.popC(); -} - inline void OPTBLD_INLINE VMExecutionContext::iopXor(PC& pc) { implCellBinOpBool(pc, [&] (Cell c1, Cell c2) -> bool { return cellToBool(c1) ^ cellToBool(c2); @@ -3779,6 +3779,18 @@ inline void OPTBLD_INLINE VMExecutionContext::iopGte(PC& pc) { implCellBinOpBool(pc, cellGreaterOrEqual); } +inline void OPTBLD_INLINE VMExecutionContext::iopShl(PC& pc) { + implCellBinOp(pc, [&] (Cell c1, Cell c2) { + return make_tv(cellToInt(c1) << cellToInt(c2)); + }); +} + +inline void OPTBLD_INLINE VMExecutionContext::iopShr(PC& pc) { + implCellBinOp(pc, [&] (Cell c1, Cell c2) { + return make_tv(cellToInt(c1) >> cellToInt(c2)); + }); +} + inline void OPTBLD_INLINE VMExecutionContext::iopBitNot(PC& pc) { NEXT(); Cell* c1 = m_stack.topC(); @@ -3794,30 +3806,6 @@ inline void OPTBLD_INLINE VMExecutionContext::iopBitNot(PC& pc) { } } -#define SHIFTOP(OP) do { \ - NEXT(); \ - Cell* c1 = m_stack.topC(); \ - Cell* c2 = m_stack.indC(1); \ - if (c2->m_type == KindOfInt64 && c1->m_type == KindOfInt64) { \ - int64_t a = c2->m_data.num; \ - int64_t b = c1->m_data.num; \ - c2->m_data.num = a OP b; \ - m_stack.popX(); \ - } else { \ - tvCellAsVariant(c2) = tvCellAsVariant(c2).toInt64() OP \ - tvCellAsCVarRef(c1).toInt64(); \ - m_stack.popC(); \ - } \ -} while (0) -inline void OPTBLD_INLINE VMExecutionContext::iopShl(PC& pc) { - SHIFTOP(<<); -} - -inline void OPTBLD_INLINE VMExecutionContext::iopShr(PC& pc) { - SHIFTOP(>>); -} -#undef SHIFTOP - inline void OPTBLD_INLINE VMExecutionContext::iopCastBool(PC& pc) { NEXT(); Cell* c1 = m_stack.topC(); diff --git a/hphp/runtime/vm/bytecode.h b/hphp/runtime/vm/bytecode.h index b46f0e53c..d3d475c14 100644 --- a/hphp/runtime/vm/bytecode.h +++ b/hphp/runtime/vm/bytecode.h @@ -23,6 +23,7 @@ #include "hphp/util/util.h" #include "hphp/runtime/base/complex_types.h" #include "hphp/runtime/base/tv_arith.h" +#include "hphp/runtime/base/tv_conversions.h" #include "hphp/runtime/base/class_info.h" #include "hphp/runtime/base/array/array_iterator.h" #include "hphp/runtime/vm/class.h" @@ -50,11 +51,17 @@ void SETOP_BODY(TypedValue* lhs, unsigned char op, Cell* rhs) { case SetOpAndEqual: cellBitAndEq(*lhs, *rhs); break; case SetOpOrEqual: cellBitOrEq(*lhs, *rhs); break; case SetOpXorEqual: cellBitXorEq(*lhs, *rhs); break; - case SetOpSlEqual: tvAsVariant(lhs) <<= - tvCellAsCVarRef(rhs).toInt64(); break; - case SetOpSrEqual: tvAsVariant(lhs) >>= - tvCellAsCVarRef(rhs).toInt64(); break; - default: not_reached(); + + case SetOpSlEqual: + cellCastToInt64InPlace(lhs); + lhs->m_data.num <<= cellToInt(*rhs); + break; + case SetOpSrEqual: + cellCastToInt64InPlace(lhs); + lhs->m_data.num >>= cellToInt(*rhs); + break; + default: + not_reached(); } } diff --git a/hphp/test/quick/shiftDtorOrder.php b/hphp/test/quick/shiftDtorOrder.php new file mode 100644 index 000000000..bd90f4a7c --- /dev/null +++ b/hphp/test/quick/shiftDtorOrder.php @@ -0,0 +1,16 @@ +