Get rid of baseStrOff
It was unnecessary book keeping, and caused us to differ from zend's behavior
Esse commit está contido em:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
::
|
||||
:1:
|
||||
::
|
||||
:1:
|
||||
::
|
||||
|
||||
:1:
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
:1:
|
||||
::
|
||||
:1:
|
||||
::
|
||||
:1:
|
||||
|
||||
::
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário