diff --git a/hphp/runtime/base/tv_helpers.cpp b/hphp/runtime/base/tv_helpers.cpp index 267158f21..a545b0c28 100644 --- a/hphp/runtime/base/tv_helpers.cpp +++ b/hphp/runtime/base/tv_helpers.cpp @@ -85,6 +85,34 @@ void tvCastToInt64InPlace(TypedValue* tv, int base /* = 10 */) { tv->m_type = KindOfInt64; } +int64_t tvCastToInt64(TypedValue* tv, int base /* = 10 */) { + if (tv->m_type == KindOfRef) { + tv = tv->m_data.pref->tv(); + } + + switch (tv->m_type) { + case KindOfUninit: + case KindOfNull: + return 0; + case KindOfBoolean: + assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL); + // Fall through + case KindOfInt64: + return tv->m_data.num; + case KindOfDouble: + return toInt64(tv->m_data.dbl); + case KindOfStaticString: + case KindOfString: + return tv->m_data.pstr->toInt64(base); + case KindOfArray: + return tv->m_data.parr->empty() ? 0 : 1; + case KindOfObject: + return tv->m_data.pobj->o_toInt64(); + default: + not_reached(); + } +} + void tvCastToDoubleInPlace(TypedValue* tv) { if (tv->m_type == KindOfRef) { tvUnbox(tv); @@ -133,13 +161,36 @@ void tvCastToStringInPlace(TypedValue* tv) { tvAsVariant(tv) = tv->m_data.pobj->t___tostring(); return; } - default: assert(false); s = buildStringData(""); break; + default: not_reached(); } tv->m_data.pstr = s; tv->m_type = KindOfString; tv->m_data.pstr->incRefCount(); } +StringData* tvCastToString(TypedValue* tv) { + if (tv->m_type == KindOfRef) { + tv = tv->m_data.pref->tv(); + } + + StringData* s; + switch (tv->m_type) { + case KindOfUninit: + case KindOfNull: s = buildStringData(""); break; + case KindOfBoolean: s = buildStringData(tv->m_data.num ? "1" : ""); break; + case KindOfInt64: s = buildStringData(tv->m_data.num); break; + case KindOfDouble: s = buildStringData(tv->m_data.dbl); break; + case KindOfStaticString: + case KindOfString: s = tv->m_data.pstr; break; + case KindOfArray: return StringData::GetStaticString("Array"); + case KindOfObject: return tv->m_data.pobj->t___tostring().detach(); + default: not_reached(); + } + + s->incRefCount(); + return s; +} + void tvCastToArrayInPlace(TypedValue* tv) { if (tv->m_type == KindOfRef) { tvUnbox(tv); diff --git a/hphp/runtime/base/tv_helpers.h b/hphp/runtime/base/tv_helpers.h index 532e8616d..6c6b56650 100644 --- a/hphp/runtime/base/tv_helpers.h +++ b/hphp/runtime/base/tv_helpers.h @@ -447,8 +447,10 @@ inline bool tvIsString(const TypedValue* tv) { void tvCastToBooleanInPlace(TypedValue* tv); void tvCastToInt64InPlace(TypedValue* tv, int base = 10); +int64_t tvCastToInt64(TypedValue* tv, int base = 10); void tvCastToDoubleInPlace(TypedValue* tv); void tvCastToStringInPlace(TypedValue* tv); +StringData* tvCastToString(TypedValue* tv); void tvCastToArrayInPlace(TypedValue* tv); void tvCastToObjectInPlace(TypedValue* tv); diff --git a/hphp/runtime/vm/member_operations.h b/hphp/runtime/vm/member_operations.h index 8f14bf633..4d5bad406 100644 --- a/hphp/runtime/vm/member_operations.h +++ b/hphp/runtime/vm/member_operations.h @@ -650,11 +650,10 @@ inline void SetElem(TypedValue* base, TypedValue* key, Cell* value) { } else { // Convert key to string offset. int64_t x; - { - TypedValue tv; - tvDup(key, &tv); - tvCastToInt64InPlace(&tv); - x = tv.m_data.num; + if (LIKELY(key->m_type == KindOfInt64)) { + x = key->m_data.num; + } else { + x = tvCastToInt64(key); } if (x < 0 || x >= StringData::MaxSize) { // Andrei: can't use PRId64 here because of order of inclusion @@ -673,16 +672,21 @@ inline void SetElem(TypedValue* base, TypedValue* key, Cell* value) { // Extract the first character of (string)value. char y[2]; { - TypedValue tv; - tvDup(value, &tv); - tvCastToStringInPlace(&tv); - if (tv.m_data.pstr->size() > 0) { - y[0] = tv.m_data.pstr->data()[0]; + StringData* valStr; + if (LIKELY(IS_STRING_TYPE(value->m_type))) { + valStr = value->m_data.pstr; + valStr->incRefCount(); + } else { + valStr = tvCastToString(value); + } + + if (valStr->size() > 0) { + y[0] = valStr->data()[0]; y[1] = '\0'; } else { y[0] = '\0'; } - tvRefcountedDecRef(&tv); + decRefStr(valStr); } // Create and save the result. if (x >= 0 && x < baseLen && base->m_data.pstr->getCount() <= 1) {