Get rid of baseStrOff

It was unnecessary book keeping, and caused us to differ
from zend's behavior
Esse commit está contido em:
mwilliams
2013-04-16 18:47:38 -07:00
commit de Sara Golemon
commit 6df0912bc0
10 arquivos alterados com 49 adições e 88 exclusões
+15 -30
Ver Arquivo
@@ -1811,16 +1811,13 @@ opcodes associated with them.
Operations can produce and consume intermediate values called "bases". A "base"
is a structure that contains either a cell or a var or a reference to a memory
location that is occupied by a cell or a var. A "base" also contains a boolean
flag "StrOff" which indicates whether the base represents a string offset.
Bases are never pushed onto the evaluation stack.
location that is occupied by a cell or a var. Bases are never pushed onto the
evaluation stack.
For operations that create a base, the operation descriptions specify whether
the base created "contains" a value or "references" a location. In the former
case, the base created contains a cell or a var. In the latter case, the base
created contains a reference to a memory location occupied by a cell or a var.
Operations that create a base set the StrOff flag to false by default unless
indicated otherwise by the operation's description.
When a base that contains a cell is destroyed, if the cell references data then
the execution engine is responsible for honoring the data's refcount logic.
@@ -1982,14 +1979,11 @@ ElemL <local variable id> [B] -> [B]
If y is an object that does not implement the ArrayAccess interface,
this operation throws a fatal error.
If y is a string, this operation checks the status of the StrOff
flag of base x. If the StrOff flag is true, this instruction throws
a fatal error. Otherwise, this operation continues to compute z =
(int)x. If z >= 0 and z < strlen(z), this operation builds a new
string consisting of the character at offset z from y and outputs a
base that contains the new string with the StrOff flag set to
true. Otherwise, this operation outputs a base that contains the
empty string with the StrOff flag set to true.
If y is a string, this operation computes z = (int)x. If z >= 0 and
z < strlen(z), this operation builds a new string consisting of the
character at offset z from y and outputs a base that contains the new
string. Otherwise, this operation outputs a base that contains the
empty string.
If y is not a string, array, or object, this operation will output a
null base.
@@ -2019,14 +2013,11 @@ ElemLW <local variable id> [B] -> [B]
If y is an object that does not implement the ArrayAccess interface,
this operation throws a fatal error.
If y is a string, this operation checks the status of the StrOff
flag of base y. If the StrOff flag is true, this instruction throws
a fatal error. Otherwise, this operation continues to compute z =
(int)x. If z >= 0 and z < strlen(z), this operation builds a new
If y is a string, this operation continues to compute z = (int)x.
If z >= 0 and z < strlen(z), this operation builds a new
string consisting of the character at offset z from y and outputs a
base that contains the new string with the StrOff flag set to
true. Otherwise, this operation raises a warning and outputs a base
that contains the empty string with the StrOff flag set to true.
base that contains the new string. Otherwise, this operation raises
a warning and outputs a base that contains the empty string.
If y is not a string, array, or object, this operation will output
a null base.
@@ -2315,10 +2306,8 @@ CGetElemL <local variable id> [B] -> [C]
If y is an object that does not implement the ArrayAccess interface, this
operation throws a fatal error.
If y is a string, this operation checks the status of the StrOff flag of
base y. If the StrOff flag is true, this operation throws a fatal error.
Otherwise this operation continues to compute z = (int)x. If z >= 0 and
z < strlen(z), this operation builds a new string consisting of the character
If y is a string, this operation continues to compute z = (int)x. If z >= 0
and z < strlen(z), this operation builds a new string consisting of the character
at offset z from y and pushes it onto the stack. Otherwise, this operation
raises a warning and pushes the empty string onto the stack.
@@ -2379,9 +2368,7 @@ IssetElemL <local variable id> [B] -> [C:Bool]
If y is an object that does not implement the ArrayAccess interface, this
operation throws a fatal error.
If y is a string, this operation first checks the status of the StrOff flag
of base y. If the StrOff flag is true, this operation pushes false.
Otherwise this operation continues to compute x = (int)x and then it pushes
If y is a string, this operation computes x = (int)x and then it pushes
(x >= 0 && x < strlen(y)) onto the stack.
If y is a not a string, array, or object, this operation pushes false onto
@@ -2409,9 +2396,7 @@ EmptyElemL <local variable id> [B] -> [C]
If y is an object that does not implement the ArrayAccess interface, this
operation throws a fatal error.
If y is a string, this operation first checks the status of the StrOff flag
of base y. If the StrOff flag is true, this operation pushes true.
Otherwise this operation computes z = (int)x, then pushes true if
If y is a string, this operation computes z = (int)x, then pushes true if
(z < 0 || z >= strlen(y)), !(y[z]) otherwise.
If y is, not an array, object, or string, this operation pushes true onto
+4 -4
Ver Arquivo
@@ -445,13 +445,13 @@ private:
template <bool setMember, bool warn, bool define, bool unset, bool reffy,
unsigned mdepth, VectorLeaveCode mleave, bool saveResult>
bool memberHelperPre(VM::PC& pc, unsigned& ndiscard, TypedValue*& base,
bool& baseStrOff, TypedValue& tvScratch,
TypedValue& tvScratch,
TypedValue& tvLiteral,
TypedValue& tvRef, TypedValue& tvRef2,
VM::MemberCode& mcode, TypedValue*& curMember);
template <bool warn, bool saveResult, VectorLeaveCode mleave>
void getHelperPre(VM::PC& pc, unsigned& ndiscard,
TypedValue*& base, bool& baseStrOff, TypedValue& tvScratch,
TypedValue*& base, TypedValue& tvScratch,
TypedValue& tvLiteral,
TypedValue& tvRef, TypedValue& tvRef2,
VM::MemberCode& mcode, TypedValue*& curMember);
@@ -460,7 +460,7 @@ private:
TypedValue& tvScratch, TypedValue& tvRef,
TypedValue& tvRef2);
void getHelper(VM::PC& pc, unsigned& ndiscard, TypedValue*& tvRet,
TypedValue*& base, bool& baseStrOff, TypedValue& tvScratch,
TypedValue*& base, TypedValue& tvScratch,
TypedValue& tvLiteral,
TypedValue& tvRef, TypedValue& tvRef2,
VM::MemberCode& mcode, TypedValue*& curMember);
@@ -468,7 +468,7 @@ private:
template <bool warn, bool define, bool unset, bool reffy, unsigned mdepth,
VectorLeaveCode mleave>
bool setHelperPre(VM::PC& pc, unsigned& ndiscard, TypedValue*& base,
bool& baseStrOff, TypedValue& tvScratch,
TypedValue& tvScratch,
TypedValue& tvLiteral,
TypedValue& tvRef, TypedValue& tvRef2,
VM::MemberCode& mcode, TypedValue*& curMember);
+8 -16
Ver Arquivo
@@ -3139,7 +3139,6 @@ static inline void ratchetRefs(TypedValue*& result, TypedValue& tvRef,
#define DECLARE_MEMBERHELPER_ARGS \
unsigned ndiscard; \
TypedValue* base; \
bool baseStrOff = false; \
TypedValue tvScratch; \
TypedValue tvLiteral; \
TypedValue tvRef; \
@@ -3152,14 +3151,13 @@ static inline void ratchetRefs(TypedValue*& result, TypedValue& tvRef,
TypedValue* tvRet;
#define MEMBERHELPERPRE_ARGS \
pc, ndiscard, base, baseStrOff, tvScratch, tvLiteral, \
pc, ndiscard, base, tvScratch, tvLiteral, \
tvRef, tvRef2, mcode, curMember
// The following arguments are outputs:
// pc: bytecode instruction after the vector instruction
// ndiscard: number of stack elements to discard
// base: ultimate result of the vector-get
// baseStrOff: StrOff flag associated with base
// tvScratch: temporary result storage
// tvRef: temporary result storage
// tvRef2: temporary result storage
@@ -3178,7 +3176,6 @@ inline void OPTBLD_INLINE VMExecutionContext::getHelperPre(
PC& pc,
unsigned& ndiscard,
TypedValue*& base,
bool& baseStrOff,
TypedValue& tvScratch,
TypedValue& tvLiteral,
TypedValue& tvRef,
@@ -3219,14 +3216,13 @@ inline void OPTBLD_INLINE VMExecutionContext::getHelperPost(
}
#define GETHELPER_ARGS \
pc, ndiscard, tvRet, base, baseStrOff, tvScratch, tvLiteral, \
pc, ndiscard, tvRet, base, tvScratch, tvLiteral, \
tvRef, tvRef2, mcode, curMember
inline void OPTBLD_INLINE
VMExecutionContext::getHelper(PC& pc,
unsigned& ndiscard,
TypedValue*& tvRet,
TypedValue*& base,
bool& baseStrOff,
TypedValue& tvScratch,
TypedValue& tvLiteral,
TypedValue& tvRef,
@@ -3241,10 +3237,9 @@ void
VMExecutionContext::getElem(TypedValue* base, TypedValue* key,
TypedValue* dest) {
assert(base->m_type != KindOfArray);
bool baseStrOff = false;
VMRegAnchor _;
tvWriteUninit(dest);
TypedValue* result = Elem<true>(*dest, *dest, base, baseStrOff, key);
TypedValue* result = Elem<true>(*dest, *dest, base, key);
if (result != dest) {
tvDup(result, dest);
}
@@ -3260,7 +3255,7 @@ template <bool setMember,
bool saveResult>
inline bool OPTBLD_INLINE VMExecutionContext::memberHelperPre(
PC& pc, unsigned& ndiscard, TypedValue*& base,
bool& baseStrOff, TypedValue& tvScratch, TypedValue& tvLiteral,
TypedValue& tvScratch, TypedValue& tvLiteral,
TypedValue& tvRef, TypedValue& tvRef2,
MemberCode& mcode, TypedValue*& curMember) {
// The caller must move pc to the vector immediate before calling
@@ -3438,7 +3433,7 @@ inline bool OPTBLD_INLINE VMExecutionContext::memberHelperPre(
} else if (define) {
result = ElemD<warn,reffy>(tvScratch, tvRef, base, curMember);
} else {
result = Elem<warn>(tvScratch, tvRef, base, baseStrOff, curMember);
result = Elem<warn>(tvScratch, tvRef, base, curMember);
}
break;
case MPL:
@@ -3500,7 +3495,6 @@ inline bool OPTBLD_INLINE VMExecutionContext::memberHelperPre(
// pc: bytecode instruction after the vector instruction
// ndiscard: number of stack elements to discard
// base: ultimate result of the vector-get
// baseStrOff: StrOff flag associated with base
// tvScratch: temporary result storage
// tvRef: temporary result storage
// tvRef2: temporary result storage
@@ -3515,7 +3509,7 @@ template <bool warn,
VMExecutionContext::VectorLeaveCode mleave>
inline bool OPTBLD_INLINE VMExecutionContext::setHelperPre(
PC& pc, unsigned& ndiscard, TypedValue*& base,
bool& baseStrOff, TypedValue& tvScratch, TypedValue& tvLiteral,
TypedValue& tvScratch, TypedValue& tvLiteral,
TypedValue& tvRef, TypedValue& tvRef2,
MemberCode& mcode, TypedValue*& curMember) {
return memberHelperPre<true, warn, define, unset,
@@ -4756,8 +4750,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopIssetM(PC& pc) {
case MEC:
case MET:
case MEI: {
issetResult = IssetEmptyElem<false>(tvScratch, tvRef, base, baseStrOff,
curMember);
issetResult = IssetEmptyElem<false>(tvScratch, tvRef, base, curMember);
break;
}
case MPL:
@@ -4885,8 +4878,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopEmptyM(PC& pc) {
case MEC:
case MET:
case MEI: {
emptyResult = IssetEmptyElem<true>(tvScratch, tvRef, base, baseStrOff,
curMember);
emptyResult = IssetEmptyElem<true>(tvScratch, tvRef, base, curMember);
break;
}
case MPL:
+11 -14
Ver Arquivo
@@ -194,7 +194,7 @@ inline TypedValue* ElemArray(ArrayData* base,
// $result = $base[$key];
template <bool warn, KeyType keyType = AnyKey>
inline TypedValue* Elem(TypedValue& tvScratch, TypedValue& tvRef,
TypedValue* base, bool& baseStrOff,
TypedValue* base,
TypedValue* key) {
TypedValue* result;
DataType type;
@@ -220,17 +220,18 @@ inline TypedValue* Elem(TypedValue& tvScratch, TypedValue& tvRef,
}
case KindOfStaticString:
case KindOfString: {
if (baseStrOff) {
raise_error("Cannot use string offset as an array");
}
int64_t x;
if (keyType == IntKey) {
x = reinterpret_cast<int64_t>(key);
} else if (keyType == StrKey) {
x = reinterpret_cast<StringData*>(key)->toInt64(10);
} else if (LIKELY(IS_INT_TYPE(key->m_type))) {
x = key->m_data.num;
} else if (LIKELY(IS_STRING_TYPE(key->m_type))) {
x = key->m_data.pstr->toInt64(10);
} else {
x = IS_INT_TYPE(key->m_type) ? key->m_data.num
: int64_t(tvCellAsCVarRef(key));
raise_warning("String offset cast occurred");
x = int64_t(tvCellAsCVarRef(key));
}
if (x < 0 || x >= base->m_data.pstr->size()) {
if (warn) {
@@ -245,7 +246,6 @@ inline TypedValue* Elem(TypedValue& tvScratch, TypedValue& tvRef,
tvScratch.m_type = KindOfStaticString;
}
result = &tvScratch;
baseStrOff = true;
break;
}
case KindOfArray: {
@@ -1358,7 +1358,7 @@ inline TypedValue* Prop(TypedValue& tvScratch, TypedValue& tvRef,
template<bool useEmpty>
inline bool IssetEmptyElemObj(TypedValue& tvRef, Instance* instance,
bool baseStrOff, TypedValue* key) {
TypedValue* key) {
if (useEmpty) {
if (LIKELY(instance->isCollection())) {
return collectionEmpty(instance, key);
@@ -1376,13 +1376,13 @@ inline bool IssetEmptyElemObj(TypedValue& tvRef, Instance* instance,
template <bool useEmpty, bool isObj = false, KeyType keyType = AnyKey>
inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef,
TypedValue* base, bool baseStrOff,
TypedValue* base,
TypedValue* key) {
TypedValue scratch;
if (isObj) {
initScratchKey<keyType>(scratch, key);
return IssetEmptyElemObj<useEmpty>(
tvRef, reinterpret_cast<Instance*>(base), baseStrOff, key);
tvRef, reinterpret_cast<Instance*>(base), key);
}
TypedValue* result;
@@ -1391,9 +1391,6 @@ inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef,
switch (type) {
case KindOfStaticString:
case KindOfString: {
if (baseStrOff) {
return useEmpty;
}
TypedValue tv;
initScratchKey<keyType>(scratch, key);
tvDup(key, &tv);
@@ -1418,7 +1415,7 @@ inline bool IssetEmptyElem(TypedValue& tvScratch, TypedValue& tvRef,
case KindOfObject: {
initScratchKey<keyType>(scratch, key);
return IssetEmptyElemObj<useEmpty>(
tvRef, static_cast<Instance*>(base->m_data.pobj), baseStrOff, key);
tvRef, static_cast<Instance*>(base->m_data.pobj), key);
break;
}
default: {
+1 -7
Ver Arquivo
@@ -1450,8 +1450,7 @@ class RawMemSlot {
enum Kind {
ContLabel, ContDone, ContShouldThrow, ContRunning, ContARPtr,
StrLen, FuncNumParams, FuncRefBitVec, ContEntry, MisBaseStrOff,
MisCtx,
StrLen, FuncNumParams, FuncRefBitVec, ContEntry, MisCtx,
MaxKind
};
@@ -1466,7 +1465,6 @@ class RawMemSlot {
case FuncNumParams: return GetFuncNumParams();
case FuncRefBitVec: return GetFuncRefBitVec();
case ContEntry: return GetContEntry();
case MisBaseStrOff: return GetMisBaseStrOff();
case MisCtx: return GetMisCtx();
default: not_reached();
}
@@ -1519,10 +1517,6 @@ class RawMemSlot {
sz::qword, Type::TCA);
return m;
}
static RawMemSlot& GetMisBaseStrOff() {
static RawMemSlot m(HHIR_MISOFF(baseStrOff), sz::byte, Type::Bool);
return m;
}
static RawMemSlot& GetMisCtx() {
static RawMemSlot m(HHIR_MISOFF(ctx), sz::qword, Type::Cls);
return m;
@@ -351,8 +351,7 @@ void HhbcTranslator::VectorTranslator::checkMIState() {
const bool badUnset = isUnsetM && baseType.not(Type::Arr | Type::Obj);
// CGetM on an array with a base that won't use MInstrState. Str
// will use tvScratch and baseStrOff and Obj will fatal or use
// tvRef.
// will use tvScratch and Obj will fatal or use tvRef.
const bool simpleArrayGet = isCGetM && singleElem &&
baseType.not(Type::Str | Type::Obj);
@@ -405,7 +404,6 @@ void HhbcTranslator::VectorTranslator::emitMPre() {
m_tb.genStMem(m_misBase, HHIR_MISOFF(tvRef), uninit, true);
m_tb.genStMem(m_misBase, HHIR_MISOFF(tvRef2), uninit, true);
}
m_tb.genStRaw(m_misBase, RawMemSlot::MisBaseStrOff, cns(false));
}
// The base location is input 0 or 1, and the location code is stored
@@ -951,8 +949,7 @@ static inline TypedValue* elemImpl(TypedValue* base, TypedValue keyVal,
} else if (define) {
return ElemD<warn, reffy, keyType>(mis->tvScratch, mis->tvRef, base, key);
} else {
return Elem<warn, keyType>(mis->tvScratch, mis->tvRef, base,
mis->baseStrOff, key);
return Elem<warn, keyType>(mis->tvScratch, mis->tvRef, base, key);
}
}
@@ -1526,7 +1523,7 @@ static inline TypedValue cGetElemImpl(TypedValue* base, TypedValue keyVal,
MInstrState* mis) {
TypedValue result;
TypedValue* key = keyPtr<keyType>(keyVal);
base = Elem<true, keyType>(result, mis->tvRef, base, mis->baseStrOff, key);
base = Elem<true, keyType>(result, mis->tvRef, base, key);
if (base != &result) {
// Save a copy of the result.
tvDup(base, &result);
@@ -1619,10 +1616,9 @@ static inline bool issetEmptyElemImpl(TypedValue* base, TypedValue keyVal,
TypedValue* key = keyPtr<keyType>(keyVal);
// mis == nullptr if we proved that it won't be used. mis->tvScratch and
// mis->tvRef are ok because those params are passed by
// reference. mis->baseStrOff is passed by value so we have to check mis
// before accessing it.
// reference.
return VM::IssetEmptyElem<isEmpty, false, keyType>(
mis->tvScratch, mis->tvRef, base, mis ? mis->baseStrOff : false, key);
mis->tvScratch, mis->tvRef, base, key);
}
#define HELPER_TABLE(m) \
@@ -40,7 +40,6 @@ struct MInstrState {
TypedValue tvRef2;
TypedValue tvResult;
TypedValue tvVal;
bool baseStrOff;
Class* ctx;
} __attribute__((aligned(16)));
static_assert(offsetof(MInstrState, tvScratch) % 16 == 0,
@@ -697,8 +697,7 @@ static inline TypedValue* elemImpl(TypedValue* base, TypedValue* key,
} else if (define) {
return ElemD<warn, reffy, keyType>(mis->tvScratch, mis->tvRef, base, key);
} else {
return Elem<warn, keyType>(mis->tvScratch, mis->tvRef, base,
mis->baseStrOff, key);
return Elem<warn, keyType>(mis->tvScratch, mis->tvRef, base, key);
}
}
@@ -1419,7 +1418,7 @@ static inline bool issetEmptyElemImpl(TypedValue* base, TypedValue* key,
MInstrState* mis) {
key = unbox<keyType, unboxKey>(key);
return IssetEmptyElem<useEmpty, false, keyType>(mis->tvScratch, mis->tvRef,
base, mis->baseStrOff, key);
base, key);
}
#define HELPER_TABLE(m) \
@@ -2528,7 +2527,6 @@ void TranslatorX64::emitMPre(const Tracelet& t,
} else if (debug) {
emitStoreInvalid(a, MISOFF(tvResult), mis_rsp);
}
a. store_imm32_disp_reg(false, MISOFF(baseStrOff), mis_rsp);
}
SKTRACE(2, ni.source, "%s\n", __func__);
@@ -2659,7 +2657,7 @@ static inline void cGetElemImpl(TypedValue* base, TypedValue* key,
TypedValue* result,
MInstrState* mis) {
key = unbox<keyType, unboxKey>(key);
base = Elem<true, keyType>(*result, mis->tvRef, base, mis->baseStrOff, key);
base = Elem<true, keyType>(*result, mis->tvRef, base, key);
if (base != result) {
// Save a copy of the result.
tvDup(base, result);
+1 -1
Ver Arquivo
@@ -16,7 +16,7 @@
::
:1:
::
:1:
::
:1:
+1 -1
Ver Arquivo
@@ -21,7 +21,7 @@
:1:
::
:1:
::
:1:
::