Implement shift operators outside of Variant
Esse commit está contido em:
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3688,6 +3688,17 @@ void OPTBLD_INLINE VMExecutionContext::implCellBinOp(PC& pc, Op op) {
|
||||
m_stack.popC();
|
||||
}
|
||||
|
||||
template<class Op>
|
||||
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<KindOfBoolean>(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<class Op>
|
||||
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<KindOfBoolean>(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<KindOfInt64>(cellToInt(c1) << cellToInt(c2));
|
||||
});
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopShr(PC& pc) {
|
||||
implCellBinOp(pc, [&] (Cell c1, Cell c2) {
|
||||
return make_tv<KindOfInt64>(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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public function __destruct() { echo "~A\n"; }
|
||||
}
|
||||
|
||||
class B {
|
||||
public function __destruct() { echo "~B\n"; }
|
||||
}
|
||||
|
||||
function main() {
|
||||
$k = (new A) << (new B);
|
||||
var_dump($k);
|
||||
}
|
||||
main();
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
HipHop Notice: Object of class A could not be converted to int in %s on line 12
|
||||
HipHop Notice: Object of class B could not be converted to int in %s on line 12
|
||||
~A
|
||||
~B
|
||||
int(2)
|
||||
Referência em uma Nova Issue
Bloquear um usuário