diff --git a/hphp/compiler/expression/binary_op_expression.cpp b/hphp/compiler/expression/binary_op_expression.cpp index 2556b3ef7..3d796c286 100644 --- a/hphp/compiler/expression/binary_op_expression.cpp +++ b/hphp/compiler/expression/binary_op_expression.cpp @@ -543,11 +543,11 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) { case '<': result = less(v1, v2); break; case T_IS_SMALLER_OR_EQUAL: - result = less_or_equal(v1, v2); break; + result = cellLessOrEqual(v1.asCell(), v2.asCell()); break; case '>': result = more(v1, v2); break; case T_IS_GREATER_OR_EQUAL: - result = more_or_equal(v1, v2); break; + result = cellGreaterOrEqual(v1.asCell(), v2.asCell()); break; case '+': result = plus(v1, v2); break; case '-': diff --git a/hphp/runtime/base/comparisons.cpp b/hphp/runtime/base/comparisons.cpp index db4613702..8adb5d2da 100644 --- a/hphp/runtime/base/comparisons.cpp +++ b/hphp/runtime/base/comparisons.cpp @@ -85,38 +85,6 @@ bool same(CVarRef v1, CObjRef v2) { ////////////////////////////////////////////////////////////////////// -bool less_or_equal(CVarRef v1, CVarRef v2) { - // To be PHP-compatible, when comparing two arrays or two objects we - // cannot assume that "($x <= $y)" is equivalent to "!($x > $y)". - if (v1.is(KindOfArray) && v2.is(KindOfArray)) { - Array a1 = v1.toArray(); - Array a2 = v2.toArray(); - return a1.less(a2) || a1.equal(a2); - } - if (v1.is(KindOfObject) && v2.is(KindOfObject)) { - Object o1 = v1.toObject(); - Object o2 = v2.toObject(); - return o1.less(o2) || o1.equal(o2); - } - return !more(v1, v2); -} - -bool more_or_equal(CVarRef v1, CVarRef v2) { - // To be PHP-compatible, when comparing two arrays or two objects we - // cannot assume that "($x >= $y)" is equivalent to "!($x < $y)". - if (v1.is(KindOfArray) && v2.is(KindOfArray)) { - Array a1 = v1.toArray(); - Array a2 = v2.toArray(); - return a1.more(a2) || a1.equal(a2); - } - if (v1.is(KindOfObject) && v2.is(KindOfObject)) { - Object o1 = v1.toObject(); - Object o2 = v2.toObject(); - return o1.more(o2) || o1.equal(o2); - } - return !less(v1, v2); -} - bool equal(int v1, const StringData *v2) { return equal((int64_t)v1, v2); } diff --git a/hphp/runtime/base/comparisons.h b/hphp/runtime/base/comparisons.h index 6041f8d86..4c91fbfc0 100644 --- a/hphp/runtime/base/comparisons.h +++ b/hphp/runtime/base/comparisons.h @@ -687,15 +687,6 @@ inline bool more(CObjRef v1, CArrRef v2) { return less(v2, v1);} inline bool more(CObjRef v1, CObjRef v2) { return v1.more(v2);} inline bool more(CObjRef v1, CVarRef v2) { return less(v2, v1);} -/////////////////////////////////////////////////////////////////////////////// -/** - * Special-casing comparisons between arrays to get the same results from - * comparisons between uncomparable arrays. - */ -bool less_or_equal(CVarRef v1, CVarRef v2); - -bool more_or_equal(CVarRef v1, CVarRef v2); - /////////////////////////////////////////////////////////////////////////////// } diff --git a/hphp/runtime/base/execution_context.h b/hphp/runtime/base/execution_context.h index 97177a64d..db8791b59 100644 --- a/hphp/runtime/base/execution_context.h +++ b/hphp/runtime/base/execution_context.h @@ -483,6 +483,7 @@ private: template void setHelperPost(unsigned ndiscard, Variant& tvRef, Variant& tvRef2); + template void implCellBinOpBool(PC&, Op op); bool cellInstanceOf(TypedValue* c, const HPHP::NamedEntity* s); bool initIterator(PC& pc, PC& origPc, Iter* it, Offset offset, Cell* c1); diff --git a/hphp/runtime/base/hphp_value.h b/hphp/runtime/base/hphp_value.h index 1702a670c..f1be2b7eb 100644 --- a/hphp/runtime/base/hphp_value.h +++ b/hphp/runtime/base/hphp_value.h @@ -13,21 +13,22 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ +#ifndef incl_HPHP_HPHPVALUE_H_ +#define incl_HPHP_HPHPVALUE_H_ #ifndef incl_HPHP_INSIDE_HPHP_COMPLEX_TYPES_H_ #error Directly including 'hphp_value.h' is prohibited. \ Include 'complex_types.h' instead. #endif -#ifndef incl_HPHP_HPHPVALUE_H_ -#define incl_HPHP_HPHPVALUE_H_ +#include #include "hphp/runtime/base/types.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// - class Class; +class Class; struct TypedValue; @@ -138,6 +139,72 @@ private: typedef TypedValue Cell; typedef TypedValue Var; +////////////////////////////////////////////////////////////////////// + +/* + * make_value and make_tv are helpers for creating TypedValues and + * Values as temporaries, without messing up the conversions. + */ + +template +typename std::enable_if< + std::is_integral::value, + Value +>::type make_value(T t) { Value v; v.num = t; return v; } + +template +typename std::enable_if< + std::is_pointer::value, + Value +>::type make_value(T t) { + Value v; + v.num = reinterpret_cast(t); + return v; +} + +inline Value make_value(double d) { Value v; v.dbl = d; return v; } + +namespace detail { + + template struct DataTypeCPPType; +#define X(dt, cpp) \ + template<> struct DataTypeCPPType
{ typedef cpp type; } + + X(KindOfNull, void); + X(KindOfBoolean, bool); + X(KindOfInt64, int64_t); + X(KindOfDouble, double); + X(KindOfArray, ArrayData*); + X(KindOfObject, ObjectData*); + X(KindOfRef, RefData*); + X(KindOfString, StringData*); + X(KindOfStaticString, StringData*); + +#undef X + +} + +template +typename std::enable_if< + !std::is_same::type,void>::value, + TypedValue +>::type make_tv(typename detail::DataTypeCPPType::type val) { + TypedValue ret; + ret.m_data = make_value(val); + ret.m_type = DType; + return ret; +} + +template +typename std::enable_if< + std::is_same::type,void>::value, + TypedValue +>::type make_tv() { + TypedValue ret; + ret.m_type = DType; + return ret; +} + /////////////////////////////////////////////////////////////////////////////// } diff --git a/hphp/runtime/base/tv_comparisons.cpp b/hphp/runtime/base/tv_comparisons.cpp index 72b8123d0..d1fd89e2b 100644 --- a/hphp/runtime/base/tv_comparisons.cpp +++ b/hphp/runtime/base/tv_comparisons.cpp @@ -32,28 +32,6 @@ namespace { ////////////////////////////////////////////////////////////////////// -bool cellToBool(const Cell* cell) { - assert(tvIsPlausible(cell)); - assert(cell->m_type != KindOfRef); - - switch (cell->m_type) { - case KindOfUninit: - case KindOfNull: return false; - case KindOfInt64: return cell->m_data.num != 0; - case KindOfBoolean: return cell->m_data.num; - case KindOfDouble: return cell->m_data.dbl != 0; - case KindOfStaticString: - case KindOfString: return cell->m_data.pstr->toBoolean(); - case KindOfArray: return !cell->m_data.parr->empty(); - case KindOfObject: // TODO: should handle o_toBoolean? - return true; - default: break; - } - not_reached(); -} - -////////////////////////////////////////////////////////////////////// - /* * Family of relative op functions. * @@ -247,31 +225,36 @@ bool cellRelOp(Op op, const Cell* cell, const ObjectData* od) { } template -bool tvRelOp(Op op, const TypedValue* tv1, const TypedValue* tv2) { - assert(tvIsPlausible(tv1)); - assert(tvIsPlausible(tv2)); - tv1 = tvToCell(tv1); - tv2 = tvToCell(tv2); +bool cellRelOp(Op op, const Cell* c1, const Cell* c2) { + assert(c1->m_type != KindOfRef); + assert(c2->m_type != KindOfRef); - switch (tv2->m_type) { + switch (c2->m_type) { case KindOfUninit: case KindOfNull: - return IS_STRING_TYPE(tv1->m_type) - ? op(tv1->m_data.pstr, empty_string.get()) - : cellRelOp(op, tv1, false); - case KindOfInt64: return cellRelOp(op, tv1, tv2->m_data.num); - case KindOfBoolean: return cellRelOp(op, tv1, !!tv2->m_data.num); - case KindOfDouble: return cellRelOp(op, tv1, tv2->m_data.dbl); + return IS_STRING_TYPE(c1->m_type) + ? op(c1->m_data.pstr, empty_string.get()) + : cellRelOp(op, c1, false); + case KindOfInt64: return cellRelOp(op, c1, c2->m_data.num); + case KindOfBoolean: return cellRelOp(op, c1, !!c2->m_data.num); + case KindOfDouble: return cellRelOp(op, c1, c2->m_data.dbl); case KindOfStaticString: - case KindOfString: return cellRelOp(op, tv1, tv2->m_data.pstr); - case KindOfArray: return cellRelOp(op, tv1, tv2->m_data.parr); - case KindOfObject: return cellRelOp(op, tv1, tv2->m_data.pobj); + case KindOfString: return cellRelOp(op, c1, c2->m_data.pstr); + case KindOfArray: return cellRelOp(op, c1, c2->m_data.parr); + case KindOfObject: return cellRelOp(op, c1, c2->m_data.pobj); default: break; } not_reached(); } +template +bool tvRelOp(Op op, const TypedValue* tv1, const TypedValue* tv2) { + assert(tvIsPlausible(tv1)); + assert(tvIsPlausible(tv2)); + return cellRelOp(op, tvToCell(tv1), tvToCell(tv2)); +} + /* * These relative ops helper function objects define operator() for * each primitive type, and for the case of a complex type being @@ -387,39 +370,36 @@ struct Gt { } -bool tvSame(const TypedValue* tv1, const TypedValue* tv2) { - assert(tvIsPlausible(tv1)); - assert(tvIsPlausible(tv2)); +bool cellSame(const Cell* c1, const Cell* c2) { + assert(c1->m_type != KindOfRef); + assert(c2->m_type != KindOfRef); - tv1 = tvToCell(tv1); - tv2 = tvToCell(tv2); - - bool const null1 = IS_NULL_TYPE(tv1->m_type); - bool const null2 = IS_NULL_TYPE(tv2->m_type); + bool const null1 = IS_NULL_TYPE(c1->m_type); + bool const null2 = IS_NULL_TYPE(c2->m_type); if (null1 && null2) return true; if (null1 || null2) return false; - switch (tv1->m_type) { + switch (c1->m_type) { case KindOfInt64: case KindOfBoolean: - if (tv2->m_type != tv1->m_type) return false; - return tv1->m_data.num == tv2->m_data.num; + if (c2->m_type != c1->m_type) return false; + return c1->m_data.num == c2->m_data.num; case KindOfDouble: - if (tv2->m_type != tv1->m_type) return false; - return tv1->m_data.dbl == tv2->m_data.dbl; + if (c2->m_type != c1->m_type) return false; + return c1->m_data.dbl == c2->m_data.dbl; case KindOfStaticString: case KindOfString: - if (!IS_STRING_TYPE(tv2->m_type)) return false; - return tv1->m_data.pstr->same(tv2->m_data.pstr); + if (!IS_STRING_TYPE(c2->m_type)) return false; + return c1->m_data.pstr->same(c2->m_data.pstr); case KindOfArray: - if (tv2->m_type != KindOfArray) return false; - return tv1->m_data.parr->equal(tv2->m_data.parr, true); + if (c2->m_type != KindOfArray) return false; + return c1->m_data.parr->equal(c2->m_data.parr, true); case KindOfObject: - return tv2->m_type == KindOfObject && - tv1->m_data.pobj == tv2->m_data.pobj; + return c2->m_type == KindOfObject && + c1->m_data.pobj == c2->m_data.pobj; default: break; @@ -427,6 +407,12 @@ bool tvSame(const TypedValue* tv1, const TypedValue* tv2) { not_reached(); } +bool tvSame(const TypedValue* tv1, const TypedValue* tv2) { + assert(tvIsPlausible(tv1)); + assert(tvIsPlausible(tv2)); + return cellSame(tvToCell(tv1), tvToCell(tv2)); +} + ////////////////////////////////////////////////////////////////////// /* @@ -459,6 +445,10 @@ bool cellEqual(const Cell* cell, const ObjectData* val) { return cellRelOp(Eq(), cell, val); } +bool cellEqual(const Cell* c1, const Cell* c2) { + return cellRelOp(Eq(), c1, c2); +} + HOT_FUNC bool tvEqual(const TypedValue* tv1, const TypedValue* tv2) { return tvRelOp(Eq(), tv1, tv2); @@ -488,6 +478,10 @@ bool cellLess(const Cell* cell, const ObjectData* val) { return cellRelOp(Lt(), cell, val); } +bool cellLess(const Cell* c1, const Cell* c2) { + return cellRelOp(Lt(), c1, c2); +} + HOT_FUNC bool tvLess(const TypedValue* tv1, const TypedValue* tv2) { return tvRelOp(Lt(), tv1, tv2); @@ -518,11 +512,39 @@ bool cellGreater(const Cell* cell, const ObjectData* val) { return cellRelOp(Gt(), cell, val); } +bool cellGreater(const Cell* c1, const Cell* c2) { + return cellRelOp(Gt(), c1, c2); +} + bool tvGreater(const TypedValue* tv1, const TypedValue* tv2) { return tvRelOp(Gt(), tv1, tv2); } ////////////////////////////////////////////////////////////////////// +bool cellLessOrEqual(const Cell* c1, const Cell* c2) { + assert(c1->m_type != KindOfRef); + assert(c2->m_type != KindOfRef); + + if ((c1->m_type == KindOfArray && c2->m_type == KindOfArray) || + (c1->m_type == KindOfObject && c2->m_type == KindOfObject)) { + return cellLess(c1, c2) || cellEqual(c1, c2); + } + return !cellGreater(c1, c2); +} + +bool cellGreaterOrEqual(const Cell* c1, const Cell* c2) { + assert(c1->m_type != KindOfRef); + assert(c2->m_type != KindOfRef); + + if ((c1->m_type == KindOfArray && c2->m_type == KindOfArray) || + (c1->m_type == KindOfObject && c2->m_type == KindOfObject)) { + return cellGreater(c1, c2) || cellEqual(c1, c2); + } + return !cellLess(c1, c2); +} + +////////////////////////////////////////////////////////////////////// + } diff --git a/hphp/runtime/base/tv_comparisons.h b/hphp/runtime/base/tv_comparisons.h index 3b867a166..977cf2bf8 100644 --- a/hphp/runtime/base/tv_comparisons.h +++ b/hphp/runtime/base/tv_comparisons.h @@ -23,6 +23,12 @@ namespace HPHP { ////////////////////////////////////////////////////////////////////// // Php's operator === +/* + * Returns whether two Cells have the same value, in the sense of + * php's === operator. + */ +bool cellSame(const Cell*, const Cell*); + /* * Returns whether two TypedValues have the same value, in sense of * php's === operator. @@ -44,6 +50,12 @@ bool cellEqual(const Cell*, const StringData*); bool cellEqual(const Cell*, const ArrayData*); bool cellEqual(const Cell*, const ObjectData*); +/* + * Returns whether two Cells have the same value, in the same of php's + * == operator. + */ +bool cellEqual(const Cell*, const Cell*); + /* * Returns whether two TypedValues have the same value, in the sense * of php's == operator. @@ -65,6 +77,12 @@ bool cellLess(const Cell*, const StringData*); bool cellLess(const Cell*, const ArrayData*); bool cellLess(const Cell*, const ObjectData*); +/* + * Returns whether a Cell is greater than another Cell, in the sense + * of php's < operator. + */ +bool cellLess(const Cell*, const Cell*); + /* * Returns whether tv1 is less than tv2, as in php's < operator. */ @@ -85,6 +103,12 @@ bool cellGreater(const Cell*, const StringData*); bool cellGreater(const Cell*, const ArrayData*); bool cellGreater(const Cell*, const ObjectData*); +/* + * Returns whether a Cell is greater than another Cell, in the sense + * of php's > operator. + */ +bool cellGreater(const Cell*, const Cell*); + /* * Returns whether tv1 is greather than tv2, as in php's > operator. */ @@ -92,6 +116,19 @@ bool tvGreater(const TypedValue*, const TypedValue*); ////////////////////////////////////////////////////////////////////// +/* + * Php operator >= and <= + * + * Note that in php $x <= $y is not equivalent to !($x > $y) for + * objects and arrays. + * + * These functions are necessary to handle those cases specially. + */ +bool cellLessOrEqual(const Cell*, const Cell*); +bool cellGreaterOrEqual(const Cell*, const Cell*); + +////////////////////////////////////////////////////////////////////// + } #include "hphp/runtime/base/tv_comparisons-inl.h" diff --git a/hphp/runtime/base/tv_helpers-inl.h b/hphp/runtime/base/tv_helpers-inl.h new file mode 100644 index 000000000..3a5e9ed73 --- /dev/null +++ b/hphp/runtime/base/tv_helpers-inl.h @@ -0,0 +1,43 @@ +/* + +----------------------------------------------------------------------+ + | HipHop for PHP | + +----------------------------------------------------------------------+ + | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +namespace HPHP { + +////////////////////////////////////////////////////////////////////// + +inline bool cellToBool(const Cell* cell) { + assert(tvIsPlausible(cell)); + assert(cell->m_type != KindOfRef); + + switch (cell->m_type) { + case KindOfUninit: + case KindOfNull: return false; + case KindOfInt64: return cell->m_data.num != 0; + case KindOfBoolean: return cell->m_data.num; + case KindOfDouble: return cell->m_data.dbl != 0; + case KindOfStaticString: + case KindOfString: return cell->m_data.pstr->toBoolean(); + case KindOfArray: return !cell->m_data.parr->empty(); + case KindOfObject: // TODO: should handle o_toBoolean? + return true; + default: break; + } + not_reached(); +} + +////////////////////////////////////////////////////////////////////// + +} diff --git a/hphp/runtime/base/tv_helpers.h b/hphp/runtime/base/tv_helpers.h index 7605f7ca6..170767096 100644 --- a/hphp/runtime/base/tv_helpers.h +++ b/hphp/runtime/base/tv_helpers.h @@ -29,16 +29,6 @@ namespace HPHP { class Variant; -template -inline TypedValue tv(DataType type, Data data) { - static_assert(sizeof(Data) == sizeof(int64_t), - "Data type in tv() not proper size"); - TypedValue v; - v.m_data.num = (int64_t)data; - v.m_type = type; - return v; -} - // Assumes 'data' is live // Assumes 'IS_REFCOUNTED_TYPE(type)' void tvDecRefHelper(DataType type, uint64_t datum); @@ -448,6 +438,15 @@ inline bool tvIsString(const TypedValue* tv) { void tvUnboxIfNeeded(TypedValue* tv); +/* + * Convert a cell to a boolean, without changing the Cell. + */ +bool cellToBool(const Cell*); + +/* + * TypedValue conversions that update the tv in place (decrefing and + * old value, if necessary). + */ void tvCastToBooleanInPlace(TypedValue* tv); void tvCastToInt64InPlace(TypedValue* tv, int base = 10); int64_t tvCastToInt64(TypedValue* tv, int base = 10); @@ -471,4 +470,6 @@ extern const RawDestructor g_destructors[kDestrTableSize]; /////////////////////////////////////////////////////////////////////////////// } +#include "hphp/runtime/base/tv_helpers-inl.h" + #endif // incl_HPHP_TV_HELPERS_H_ diff --git a/hphp/runtime/base/type_string.cpp b/hphp/runtime/base/type_string.cpp index d6f67d7c4..b3950a807 100644 --- a/hphp/runtime/base/type_string.cpp +++ b/hphp/runtime/base/type_string.cpp @@ -587,14 +587,6 @@ bool String::operator!=(litstr v) const { return !HPHP::equal(m_px, v); } -bool String::operator>=(litstr v) const { - return more_or_equal(m_px, v); -} - -bool String::operator<=(litstr v) const { - return less_or_equal(m_px, v); -} - bool String::operator>(litstr v) const { return HPHP::more(m_px, v); } @@ -611,14 +603,6 @@ bool String::operator!=(CStrRef v) const { return !HPHP::equal(m_px, v); } -bool String::operator>=(CStrRef v) const { - return more_or_equal(m_px, v); -} - -bool String::operator<=(CStrRef v) const { - return less_or_equal(m_px, v); -} - bool String::operator>(CStrRef v) const { return HPHP::more(m_px, v); } @@ -635,14 +619,6 @@ bool String::operator!=(CVarRef v) const { return !HPHP::equal(m_px, v); } -bool String::operator>=(CVarRef v) const { - return more_or_equal(m_px, v); -} - -bool String::operator<=(CVarRef v) const { - return less_or_equal(m_px, v); -} - bool String::operator>(CVarRef v) const { return HPHP::more(m_px, v); } diff --git a/hphp/runtime/base/type_string.h b/hphp/runtime/base/type_string.h index ab53fc97f..fcf2e8fbb 100644 --- a/hphp/runtime/base/type_string.h +++ b/hphp/runtime/base/type_string.h @@ -332,20 +332,20 @@ public: */ bool operator == (litstr v) const; bool operator != (litstr v) const; - bool operator >= (litstr v) const; - bool operator <= (litstr v) const; + bool operator >= (litstr v) const = delete; + bool operator <= (litstr v) const = delete; bool operator > (litstr v) const; bool operator < (litstr v) const; bool operator == (CStrRef v) const; bool operator != (CStrRef v) const; - bool operator >= (CStrRef v) const; - bool operator <= (CStrRef v) const; + bool operator >= (CStrRef v) const = delete; + bool operator <= (CStrRef v) const = delete; bool operator > (CStrRef v) const; bool operator < (CStrRef v) const; bool operator == (CVarRef v) const; bool operator != (CVarRef v) const; - bool operator >= (CVarRef v) const; - bool operator <= (CVarRef v) const; + bool operator >= (CVarRef v) const = delete; + bool operator <= (CVarRef v) const = delete; bool operator > (CVarRef v) const; bool operator < (CVarRef v) const; diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 5caab9100..d2021b7cc 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -3780,79 +3780,70 @@ inline void OPTBLD_INLINE VMExecutionContext::iopMod(PC& pc) { #undef MATHOP_DOUBLE #undef MATHOP_DIVCHECK -#define LOGICOP(OP) do { \ - NEXT(); \ - Cell* c1 = m_stack.topC(); \ - Cell* c2 = m_stack.indC(1); \ - { \ - tvCellAsVariant(c2) = \ - bool(tvCellAsVariant(c2).toBoolean() OP tvCellAsVariant(c1).toBoolean()); \ - } \ - m_stack.popC(); \ -} while (0) - -inline void OPTBLD_INLINE VMExecutionContext::iopXor(PC& pc) { - LOGICOP(^); -} -#undef LOGICOP - inline void OPTBLD_INLINE VMExecutionContext::iopNot(PC& pc) { NEXT(); Cell* c1 = m_stack.topC(); tvCellAsVariant(c1) = !tvCellAsVariant(c1).toBoolean(); } -#define CMPOP(OP, VOP) 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); \ - c2->m_type = KindOfBoolean; \ - m_stack.popX(); \ - } else { \ - int64_t result = VOP(tvCellAsVariant(c2), tvCellAsCVarRef(c1)); \ - tvRefcountedDecRefCell(c2); \ - c2->m_data.num = result; \ - c2->m_type = KindOfBoolean; \ - m_stack.popC(); \ - } \ -} while (0) +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, [&] (const Cell* c1, const Cell* c2) -> bool { + return cellToBool(c1) ^ cellToBool(c2); + }); +} inline void OPTBLD_INLINE VMExecutionContext::iopSame(PC& pc) { - CMPOP(==, same); + implCellBinOpBool(pc, cellSame); } inline void OPTBLD_INLINE VMExecutionContext::iopNSame(PC& pc) { - CMPOP(!=, !same); + implCellBinOpBool(pc, [&] (const Cell* c1, const Cell* c2) { + return !cellSame(c1, c2); + }); } inline void OPTBLD_INLINE VMExecutionContext::iopEq(PC& pc) { - CMPOP(==, equal); + implCellBinOpBool(pc, [&] (const Cell* c1, const Cell* c2) { + return cellEqual(c1, c2); + }); } inline void OPTBLD_INLINE VMExecutionContext::iopNeq(PC& pc) { - CMPOP(!=, !equal); + implCellBinOpBool(pc, [&] (const Cell* c1, const Cell* c2) { + return !cellEqual(c1, c2); + }); } inline void OPTBLD_INLINE VMExecutionContext::iopLt(PC& pc) { - CMPOP(<, less); + implCellBinOpBool(pc, [&] (const Cell* c1, const Cell* c2) { + return cellLess(c1, c2); + }); } inline void OPTBLD_INLINE VMExecutionContext::iopLte(PC& pc) { - CMPOP(<=, less_or_equal); + implCellBinOpBool(pc, cellLessOrEqual); } inline void OPTBLD_INLINE VMExecutionContext::iopGt(PC& pc) { - CMPOP(>, more); + implCellBinOpBool(pc, [&] (const Cell* c1, const Cell* c2) { + return cellGreater(c1, c2); + }); } inline void OPTBLD_INLINE VMExecutionContext::iopGte(PC& pc) { - CMPOP(>=, more_or_equal); + implCellBinOpBool(pc, cellGreaterOrEqual); } -#undef CMPOP #define MATHOP_DOUBLE(OP) #define MATHOP_DIVCHECK(x) diff --git a/hphp/runtime/vm/member_operations.h b/hphp/runtime/vm/member_operations.h index ba56e24d6..dcda48022 100644 --- a/hphp/runtime/vm/member_operations.h +++ b/hphp/runtime/vm/member_operations.h @@ -31,7 +31,7 @@ class InvalidSetMException : public std::runtime_error { public: InvalidSetMException() : std::runtime_error("Empty InvalidSetMException") - , m_tv(HPHP::tv(KindOfNull, 0LL)) + , m_tv(make_tv()) {} explicit InvalidSetMException(const TypedValue& value) @@ -543,7 +543,7 @@ inline void SetElemNumberish(Cell* value) { tvRefcountedDecRefCell((TypedValue*)value); tvWriteNull((TypedValue*)value); } else { - throw InvalidSetMException(tv(KindOfNull, 0LL)); + throw InvalidSetMException(make_tv()); } } @@ -631,7 +631,7 @@ inline void SetElemArray(TypedValue* base, TypedValue* key, tvRefcountedDecRef(value); tvWriteNull(value); } else { - throw InvalidSetMException(tv(KindOfNull, 0LL)); + throw InvalidSetMException(make_tv()); } } @@ -788,7 +788,7 @@ inline void SetNewElemNumberish(Cell* value) { tvRefcountedDecRefCell((TypedValue*)value); tvWriteNull((TypedValue*)value); } else { - throw InvalidSetMException(tv(KindOfNull, 0LL)); + throw InvalidSetMException(make_tv()); } } template @@ -1519,7 +1519,7 @@ inline void SetPropNull(Cell* val) { tvRefcountedDecRefCell(val); tvWriteNull(val); } else { - throw InvalidSetMException(tv(KindOfNull, 0LL)); + throw InvalidSetMException(make_tv()); } } inline void SetPropStdclass(TypedValue* base, TypedValue* key,