Implement most bitwise arithmetic outside of Variant

Everything except unary bitwise not.
Esse commit está contido em:
Jordan DeLong
2013-06-28 19:56:51 -07:00
commit de Sara Golemon
commit dec333dd14
15 arquivos alterados com 184 adições e 206 exclusões
+26 -13
Ver Arquivo
@@ -524,31 +524,44 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
Variant result;
switch (m_op) {
case T_LOGICAL_XOR:
result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean()); break;
result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean());
break;
case '|':
result = bitwise_or(v1, v2); break;
*result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell());
break;
case '&':
result = bitwise_and(v1, v2); break;
*result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell());
break;
case '^':
result = bitwise_xor(v1, v2); break;
*result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
break;
case '.':
result = concat(v1.toString(), v2.toString()); break;
result = concat(v1.toString(), v2.toString());
break;
case T_IS_IDENTICAL:
result = same(v1, v2); break;
result = same(v1, v2);
break;
case T_IS_NOT_IDENTICAL:
result = !same(v1, v2); break;
result = !same(v1, v2);
break;
case T_IS_EQUAL:
result = equal(v1, v2); break;
result = equal(v1, v2);
break;
case T_IS_NOT_EQUAL:
result = !equal(v1, v2); break;
result = !equal(v1, v2);
break;
case '<':
result = less(v1, v2); break;
result = less(v1, v2);
break;
case T_IS_SMALLER_OR_EQUAL:
result = cellLessOrEqual(*v1.asCell(), *v2.asCell()); break;
result = cellLessOrEqual(*v1.asCell(), *v2.asCell());
break;
case '>':
result = more(v1, v2); break;
result = more(v1, v2);
break;
case T_IS_GREATER_OR_EQUAL:
result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell()); break;
result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell());
break;
case '+':
*result.asCell() = cellAdd(*v1.asCell(), *v2.asCell());
break;
-3
Ver Arquivo
@@ -90,9 +90,6 @@ bool empty(CVarRef v, CStrRef, bool = false) = delete;
///////////////////////////////////////////////////////////////////////////////
// operators
inline Variant bitwise_or (CVarRef v1, CVarRef v2) { return v1 | v2;}
inline Variant bitwise_and(CVarRef v1, CVarRef v2) { return v1 & v2;}
inline Variant bitwise_xor(CVarRef v1, CVarRef v2) { return v1 ^ v2;}
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; }
+4 -2
Ver Arquivo
@@ -230,10 +230,12 @@ inline ALWAYS_INLINE unsigned typeToDestrIndex(DataType t) {
// Helper macro for checking if a given type is refcounted
#define IS_REFCOUNTED_TYPE(t) ((t) > KindOfRefCountThreshold)
// Helper macro for checking if a type is KindOfString or KindOfStaticString.
// Helper function for checking if a type is KindOfString or KindOfStaticString.
static_assert(KindOfStaticString == 0x0C, "");
static_assert(KindOfString == 0x14, "");
#define IS_STRING_TYPE(t) (((t) & ~0x18) == KindOfStringBit)
inline bool IS_STRING_TYPE(DataType t) {
return (t & ~0x18) == KindOfStringBit;
}
// Check if a type is KindOfUninit or KindOfNull
#define IS_NULL_TYPE(t) (unsigned(t) <= KindOfNull)
+2 -4
Ver Arquivo
@@ -234,15 +234,13 @@ public:
Util::s_stackSize));
}
/**
* Informational.
*/
const char *data() const {
// TODO: t1800106: re-enable this assert
//assert(rawdata()[size()] == 0); // all strings must be null-terminated
return rawdata();
}
// This method should only be used internally by the String class.
char* mutableData() const { return m_data; }
int size() const { return m_len; }
static uint sizeOffset() { return offsetof(StringData, m_len); }
int capacity() const { return isSmall() ? MaxSmallSize : bigCap(); }
+79
Ver Arquivo
@@ -17,6 +17,7 @@
#include <type_traits>
#include <limits>
#include <algorithm>
#include "hphp/runtime/base/runtime_error.h"
#include "hphp/runtime/base/tv_conversions.h"
@@ -237,6 +238,51 @@ struct MulEq {
}
};
template<class SzOp, class BitOp>
StringData* stringBitOp(BitOp bop, SzOp sop, StringData* s1, StringData* s2) {
auto const newLen = sop(s1->size(), s2->size());
auto const newStr = NEW(StringData)(newLen);
auto const s1Data = s1->data();
auto const s2Data = s2->data();
auto const outData = newStr->mutableData();
for (uint32_t i = 0; i < newLen; ++i) {
outData[i] = bop(s1Data[i], s2Data[i]);
}
newStr->setSize(newLen);
newStr->setRefCount(1);
return newStr;
}
template<template<class> class BitOp, class StrLenOp>
Cell cellBitOp(StrLenOp strLenOp, Cell c1, Cell c2) {
assert(cellIsPlausible(&c1));
assert(cellIsPlausible(&c2));
if (IS_STRING_TYPE(c1.m_type) && IS_STRING_TYPE(c2.m_type)) {
return make_tv<KindOfString>(
stringBitOp(
BitOp<char>(),
strLenOp,
c1.m_data.pstr,
c2.m_data.pstr
)
);
}
return make_tv<KindOfInt64>(
BitOp<int64_t>()(cellToInt(c1), cellToInt(c2))
);
}
template<class Op>
void cellBitOpEq(Op op, Cell& c1, Cell c2) {
auto const result = op(c1, c2);
cellSet(result, c1);
}
}
//////////////////////////////////////////////////////////////////////
@@ -271,6 +317,27 @@ Cell cellMod(Cell c1, Cell c2) {
return make_tv<KindOfInt64>(i1 % i2);
}
Cell cellBitAnd(Cell c1, Cell c2) {
return cellBitOp<std::bit_and>(
[] (uint32_t a, uint32_t b) { return std::min(a, b); },
c1, c2
);
}
Cell cellBitOr(Cell c1, Cell c2) {
return cellBitOp<std::bit_or>(
[] (uint32_t a, uint32_t b) { return std::max(a, b); },
c1, c2
);
}
Cell cellBitXor(Cell c1, Cell c2) {
return cellBitOp<std::bit_xor>(
[] (uint32_t a, uint32_t b) { return std::min(a, b); },
c1, c2
);
}
void cellAddEq(Cell& c1, Cell c2) {
cellOpEq(AddEq(), c1, c2);
}
@@ -296,6 +363,18 @@ void cellModEq(Cell& c1, Cell c2) {
cellCopy(cellMod(c1, c2), c1);
}
void cellBitAndEq(Cell& c1, Cell c2) {
cellBitOpEq(cellBitAnd, c1, c2);
}
void cellBitOrEq(Cell& c1, Cell c2) {
cellBitOpEq(cellBitOr, c1, c2);
}
void cellBitXorEq(Cell& c1, Cell c2) {
cellBitOpEq(cellBitXor, c1, c2);
}
//////////////////////////////////////////////////////////////////////
}
+22
Ver Arquivo
@@ -53,6 +53,16 @@ TypedNum cellMul(Cell, Cell);
Cell cellDiv(Cell, Cell);
Cell cellMod(Cell, Cell);
/*
* PHP operators &, |, and ^.
*
* These functions return a KindOfInt64, unless both arguments are
* KindOfString, in which case they return a KindOfString.
*/
Cell cellBitAnd(Cell, Cell);
Cell cellBitOr(Cell, Cell);
Cell cellBitXor(Cell, Cell);
//////////////////////////////////////////////////////////////////////
/*
@@ -89,6 +99,18 @@ void cellMulEq(Cell& c1, Cell);
void cellDivEq(Cell& c1, Cell);
void cellModEq(Cell& c1, Cell);
/*
* PHP operators &=, |=, and ^=.
*
* Mutates the first argument in place, by combining the second
* argument with it in the sense of the appropriate operator.
*
* Post: c1.m_type == KindOfString || c1.m_type == KindOfInt64
*/
void cellBitAndEq(Cell& c1, Cell);
void cellBitOrEq(Cell& c1, Cell);
void cellBitXorEq(Cell& c1, Cell);
//////////////////////////////////////////////////////////////////////
}
-78
Ver Arquivo
@@ -401,84 +401,6 @@ String String::operator~() const {
return ret;
}
String String::operator|(CStrRef v) const {
return String(m_px).operator|=(v);
}
String String::operator&(CStrRef v) const {
return String(m_px).operator&=(v);
}
String String::operator^(CStrRef v) const {
return String(m_px).operator^=(v);
}
String &String::operator|=(CStrRef v) {
const char *s1 = data();
const char *s2 = v.data();
int len1 = size();
int len2 = v.size();
int len;
char *copy = nullptr;
if (len2 > len1) {
len = len2;
copy = string_duplicate(s2, len2);
for (int i = 0; i < len1; i++) copy[i] |= s1[i];
} else {
len = len1;
copy = string_duplicate(s1, len1);
for (int i = 0; i < len2; i++) copy[i] |= s2[i];
}
if (m_px) decRefStr(m_px);
m_px = NEW(StringData)(copy, len, AttachString);
m_px->setRefCount(1);
return *this;
}
String &String::operator&=(CStrRef v) {
const char *s1 = data();
const char *s2 = v.data();
int len1 = size();
int len2 = v.size();
int len;
char *copy = nullptr;
if (len2 < len1) {
len = len2;
copy = string_duplicate(s2, len2);
for (int i = 0; i < len2; i++) copy[i] &= s1[i];
} else {
len = len1;
copy = string_duplicate(s1, len1);
for (int i = 0; i < len1; i++) copy[i] &= s2[i];
}
if (m_px) decRefStr(m_px);
m_px = NEW(StringData)(copy, len, AttachString);
m_px->setRefCount(1);
return *this;
}
String &String::operator^=(CStrRef v) {
const char *s1 = data();
const char *s2 = v.data();
int len1 = size();
int len2 = v.size();
int len;
char *copy = nullptr;
if (len2 < len1) {
len = len2;
copy = string_duplicate(s2, len2);
for (int i = 0; i < len2; i++) copy[i] ^= s1[i];
} else {
len = len1;
copy = string_duplicate(s1, len1);
for (int i = 0; i < len1; i++) copy[i] ^= s2[i];
}
if (m_px) decRefStr(m_px);
m_px = NEW(StringData)(copy, len, AttachString);
m_px->setRefCount(1);
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// conversions
+6 -6
Ver Arquivo
@@ -311,12 +311,12 @@ public:
String &operator += (CStrRef v);
String &operator += (const StringSlice& slice);
String &operator += (const MutableSlice& slice);
String operator | (CStrRef v) const;
String operator & (CStrRef v) const;
String operator ^ (CStrRef v) const;
String &operator |= (CStrRef v);
String &operator &= (CStrRef v);
String &operator ^= (CStrRef v);
String operator | (CStrRef v) const = delete;
String operator & (CStrRef v) const = delete;
String operator ^ (CStrRef v) const = delete;
String &operator |= (CStrRef v) = delete;
String &operator &= (CStrRef v) = delete;
String &operator ^= (CStrRef v) = delete;
String operator ~ () const;
explicit operator std::string () const {
return std::string(c_str(), size());
-48
Ver Arquivo
@@ -624,54 +624,6 @@ Variant Variant::bitNot() const {
throw InvalidOperandException("only numerics and strings can be negated");
}
Variant Variant::operator|(CVarRef v) const {
if (isString() && v.isString()) {
return toString() | v.toString();
}
return toInt64() | v.toInt64();
}
Variant Variant::operator&(CVarRef v) const {
if (isString() && v.isString()) {
return toString() & v.toString();
}
return toInt64() & v.toInt64();
}
Variant Variant::operator^(CVarRef v) const {
if (isString() && v.isString()) {
return toString() ^ v.toString();
}
return toInt64() ^ v.toInt64();
}
Variant &Variant::operator|=(CVarRef v) {
if (isString() && v.isString()) {
set(toString() | v.toString());
} else {
set(toInt64() | v.toInt64());
}
return *this;
}
Variant &Variant::operator&=(CVarRef v) {
if (isString() && v.isString()) {
set(toString() & v.toString());
} else {
set(toInt64() & v.toInt64());
}
return *this;
}
Variant &Variant::operator^=(CVarRef v) {
if (isString() && v.isString()) {
set(toString() ^ v.toString());
} else {
set(toInt64() ^ v.toInt64());
}
return *this;
}
Variant &Variant::operator<<=(int64_t n) {
set(toInt64() << n);
return *this;
+6 -6
Ver Arquivo
@@ -575,12 +575,12 @@ class Variant : private TypedValue {
Variant &operator %= (int64_t n) = delete;
Variant &operator %= (double n) = delete;
Variant operator | (CVarRef v) const;
Variant &operator |= (CVarRef v);
Variant operator & (CVarRef v) const;
Variant &operator &= (CVarRef v);
Variant operator ^ (CVarRef v) const;
Variant &operator ^= (CVarRef v);
Variant operator | (CVarRef v) const = delete;
Variant &operator |= (CVarRef v) = delete;
Variant operator & (CVarRef v) const = delete;
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);
+12 -35
Ver Arquivo
@@ -3708,6 +3708,18 @@ inline void OPTBLD_INLINE VMExecutionContext::iopMod(PC& pc) {
implCellBinOp(pc, cellMod);
}
inline void OPTBLD_INLINE VMExecutionContext::iopBitAnd(PC& pc) {
implCellBinOp(pc, cellBitAnd);
}
inline void OPTBLD_INLINE VMExecutionContext::iopBitOr(PC& pc) {
implCellBinOp(pc, cellBitOr);
}
inline void OPTBLD_INLINE VMExecutionContext::iopBitXor(PC& pc) {
implCellBinOp(pc, cellBitXor);
}
template<class Op>
void OPTBLD_INLINE VMExecutionContext::implCellBinOpBool(PC& pc, Op op) {
NEXT();
@@ -3767,41 +3779,6 @@ inline void OPTBLD_INLINE VMExecutionContext::iopGte(PC& pc) {
implCellBinOpBool(pc, cellGreaterOrEqual);
}
#define MATHOP(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; \
MATHOP_DIVCHECK(0) \
c2->m_data.num = a OP b; \
m_stack.popX(); \
} \
MATHOP_DOUBLE(OP) \
else { \
tvCellAsVariant(c2) = VOP(tvCellAsVariant(c2), tvCellAsCVarRef(c1)); \
m_stack.popC(); \
} \
} while (0)
#define MATHOP_DOUBLE(OP)
#define MATHOP_DIVCHECK(x)
inline void OPTBLD_INLINE VMExecutionContext::iopBitAnd(PC& pc) {
MATHOP(&, bitwise_and);
}
inline void OPTBLD_INLINE VMExecutionContext::iopBitOr(PC& pc) {
MATHOP(|, bitwise_or);
}
inline void OPTBLD_INLINE VMExecutionContext::iopBitXor(PC& pc) {
MATHOP(^, bitwise_xor);
}
#undef MATHOP
#undef MATHOP_DOUBLE
#undef MATHOP_DIVCHECK
inline void OPTBLD_INLINE VMExecutionContext::iopBitNot(PC& pc) {
NEXT();
Cell* c1 = m_stack.topC();
+3 -3
Ver Arquivo
@@ -47,9 +47,9 @@ void SETOP_BODY(TypedValue* lhs, unsigned char op, Cell* rhs) {
case SetOpConcatEqual:
concat_assign(tvAsVariant(lhs), tvCellAsCVarRef(rhs).toString());
break;
case SetOpAndEqual: tvAsVariant(lhs) &= tvCellAsCVarRef(rhs); break;
case SetOpOrEqual: tvAsVariant(lhs) |= tvCellAsCVarRef(rhs); break;
case SetOpXorEqual: tvAsVariant(lhs) ^= tvCellAsCVarRef(rhs); break;
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) >>=
-8
Ver Arquivo
@@ -168,14 +168,6 @@ bool TestCppBase::TestString() {
s = String("c") + String("d"); VS(s.c_str(), "cd");
s += "efg"; VS(s.c_str(), "cdefg");
s += String("hij"); VS(s.c_str(), "cdefghij");
s = String("\x50\x51") | "\x51\x51"; VS(s.c_str(), "\x51\x51");
s = String("\x50\x51") & "\x51\x51"; VS(s.c_str(), "\x50\x51");
s = String("\x50\x51") ^ "\x51\x51"; VS(s.c_str(), "\x01");
s = "\x50\x51"; s |= "\x51\x51"; VS(s.c_str(), "\x51\x51");
s = "\x50\x51"; s &= "\x51\x51"; VS(s.c_str(), "\x50\x51");
s = "\x50\x51"; s ^= "\x51\x51"; VS(s.c_str(), "\x01");
s = "\x50\x51"; s = ~s; VS(s.c_str(), "\xAF\xAE");
}
// manipulations
+17
Ver Arquivo
@@ -0,0 +1,17 @@
<?php
function VS($a, $b) {
if ($a === $b) var_dump("ok");
else {
var_dump($a);
var_dump(debug_backtrace());
}
}
$s = "\x50\x51" | "\x51\x51"; VS($s, "\x51\x51");
$s = "\x50\x51" & "\x51\x51"; VS($s, "\x50\x51");
$s = "\x50\x51" ^ "\x51\x51"; VS($s, "\x01\x00");
$s = "\x50\x51"; $s |= "\x51\x51"; VS($s, "\x51\x51");
$s = "\x50\x51"; $s &= "\x51\x51"; VS($s, "\x50\x51");
$s = "\x50\x51"; $s ^= "\x51\x51"; VS($s, "\x01\x00");
$s = "\x50\x51"; $s = ~$s; VS($s, "\xAF\xAE");
+7
Ver Arquivo
@@ -0,0 +1,7 @@
string(2) "ok"
string(2) "ok"
string(2) "ok"
string(2) "ok"
string(2) "ok"
string(2) "ok"
string(2) "ok"