Permalink
Browse files

Encapsulate return types of NvGet*() and GetValueRef()

Summary:
This divorces the array vtable API from the actual data layout used
by the various array implementations.  In particular, it no longer
requires them to lay out TypedValues in memory (or rather... we're
pushing that dependency further out, with plans to eliminate it
completely).

We define a member_rval type analogous to the member_lval type used by
the LvalAt*() functions, which has const/read-only semantics.
member_rval::ptr_u replaces the return types for the array vtable
NvGet*() and GetValueRef() functions, while ArrayData wraps it trivially
as a member_rval.  We also add Rval*() functions to mirror the Lval*()
functions on each array type, and we rename ArrayData::nvGet() and
ArrayData::getValueRef() to ArrayData::rval*() (with ArrayData::at() as
a helper for getting a TypedValue by value).

Reviewed By: jano

Differential Revision: D4890419

fbshipit-source-id: 57c0fda93ea28eac6e02cadbb178f83fa33bd4b2
  • Loading branch information...
mxw authored and hhvm-bot committed Jun 27, 2017
1 parent 095a4b2 commit e513c6d6d4a847fd7d09e27f23e4554b6955c0f0
Showing with 752 additions and 435 deletions.
  1. +4 −4 hphp/hhbbc/type-system.cpp
  2. +12 −13 hphp/runtime/base/apc-local-array.cpp
  3. +19 −4 hphp/runtime/base/apc-local-array.h
  4. +35 −23 hphp/runtime/base/array-data-defs.h
  5. +12 −12 hphp/runtime/base/array-data.cpp
  6. +20 −17 hphp/runtime/base/array-data.h
  7. +10 −10 hphp/runtime/base/array-iterator.cpp
  8. +7 −4 hphp/runtime/base/array-iterator.h
  9. +8 −8 hphp/runtime/base/array-util.cpp
  10. +3 −2 hphp/runtime/base/empty-array.cpp
  11. +24 −5 hphp/runtime/base/empty-array.h
  12. +6 −4 hphp/runtime/base/exceptions.cpp
  13. +7 −9 hphp/runtime/base/hash-table-inl.h
  14. +13 −3 hphp/runtime/base/hash-table.h
  15. +54 −3 hphp/runtime/base/{member-lval-inl.h → member-val-inl.h}
  16. +99 −11 hphp/runtime/base/{member-lval.h → member-val.h}
  17. +1 −1 hphp/runtime/base/mixed-array-defs.h
  18. +24 −22 hphp/runtime/base/mixed-array.cpp
  19. +30 −6 hphp/runtime/base/mixed-array.h
  20. +13 −14 hphp/runtime/base/object-data.cpp
  21. +12 −12 hphp/runtime/base/packed-array.cpp
  22. +29 −6 hphp/runtime/base/packed-array.h
  23. +1 −1 hphp/runtime/base/php-globals.h
  24. +14 −12 hphp/runtime/base/proxy-array.cpp
  25. +23 −7 hphp/runtime/base/proxy-array.h
  26. +4 −4 hphp/runtime/base/repo-auth-type.cpp
  27. +8 −8 hphp/runtime/base/set-array.cpp
  28. +15 −5 hphp/runtime/base/set-array.h
  29. +10 −0 hphp/runtime/base/tv-mutate.h
  30. +5 −2 hphp/runtime/base/tv-type.h
  31. +25 −15 hphp/runtime/base/type-array.cpp
  32. +2 −2 hphp/runtime/base/type-variant.h
  33. +2 −3 hphp/runtime/base/variable-serializer.cpp
  34. +4 −4 hphp/runtime/ext/array/ext_array.cpp
  35. +3 −3 hphp/runtime/ext/collections/ext_collections-map.cpp
  36. +3 −3 hphp/runtime/ext/collections/ext_collections-set.h
  37. +1 −1 hphp/runtime/ext/collections/ext_collections-vector.cpp
  38. +5 −3 hphp/runtime/ext/factparse/ext_factparse.cpp
  39. +1 −1 hphp/runtime/ext/std/ext_std_classobj.cpp
  40. +4 −4 hphp/runtime/vm/class.cpp
  41. +5 −5 hphp/runtime/vm/globals-array.cpp
  42. +4 −4 hphp/runtime/vm/globals-array.h
  43. +2 −2 hphp/runtime/vm/jit/irgen-minstr.cpp
  44. +1 −1 hphp/runtime/vm/jit/irlower-cns.cpp
  45. +7 −7 hphp/runtime/vm/jit/irlower-lookup-cls-func.cpp
  46. +24 −21 hphp/runtime/vm/jit/minstr-helpers.h
  47. +21 −21 hphp/runtime/vm/jit/simplify.cpp
  48. +13 −13 hphp/runtime/vm/jit/translator-runtime.cpp
  49. +11 −11 hphp/runtime/vm/jit/type-array-elem.cpp
  50. +90 −77 hphp/runtime/vm/member-operations.h
  51. +2 −2 hphp/runtime/vm/unit.cpp
@@ -2676,13 +2676,13 @@ std::pair<Type,bool> arr_val_elem(const Type& aval, const ArrKey& key) {
auto ad = aval.m_data.aval;
auto const isPhpArray = aval.subtypeOf(TOptArr);
if (key.i) {
if (auto const r = ad->nvGet(*key.i)) {
return { from_cell(*r), true };
if (auto const r = ad->rval(*key.i)) {
return { from_cell(r.tv()), true };
}
return { isPhpArray ? TInitNull : TBottom, false };
} else if (key.s) {
if (auto const r = ad->nvGet(*key.s)) {
return { from_cell(*r), true };
if (auto const r = ad->rval(*key.s)) {
return { from_cell(r.tv()), true };
}
return { isPhpArray ? TInitNull : TBottom, false };
}
@@ -21,7 +21,7 @@
#include "hphp/runtime/base/array-data-defs.h"
#include "hphp/runtime/base/array-init.h"
#include "hphp/runtime/base/array-iterator.h"
#include "hphp/runtime/base/member-lval.h"
#include "hphp/runtime/base/member-val.h"
#include "hphp/runtime/base/mixed-array-defs.h"
#include "hphp/runtime/base/runtime-option.h"
#include "hphp/runtime/base/runtime-error.h"
@@ -80,18 +80,17 @@ void APCLocalArray::sweep() {
m_arr = nullptr;
}
const Variant& APCLocalArray::GetValueRef(const ArrayData* adIn, ssize_t pos) {
member_rval::ptr_u APCLocalArray::GetValueRef(const ArrayData* adIn,
ssize_t pos) {
auto const ad = asApcArray(adIn);
assert(unsigned(pos) < ad->getSize());
auto const elms = ad->localCache();
auto const tv = &elms[pos];
if (tv->m_type != KindOfUninit) {
return tvAsCVarRef(tv);
}
if (tv->m_type != KindOfUninit) return tv;
auto const sv = ad->m_arr->getValue(pos);
tvAsVariant(tv) = sv->toLocal();
assert(tv->m_type != KindOfUninit);
return tvAsCVarRef(tv);
return tv;
}
ALWAYS_INLINE
@@ -145,13 +144,13 @@ ArrayData* APCLocalArray::loadElems() const {
if (m_arr->isPacked()) {
PackedArrayInit ai(count);
for (uint32_t i = 0; i < count; i++) {
ai.append(GetValueRef(this, i));
ai.append(RvalAtPos(this, i).tv());
}
elems = ai.create();
} else {
ArrayInit ai(count, ArrayInit::Mixed{});
for (uint32_t i = 0; i < count; i++) {
ai.add(getKey(i), GetValueRef(this, i), true);
ai.add(getKey(i), RvalAtPos(this, i).tv(), true);
}
elems = ai.create();
}
@@ -278,19 +277,19 @@ ArrayData *APCLocalArray::Escalate(const ArrayData* ad) {
return ret;
}
const TypedValue* APCLocalArray::NvGetInt(const ArrayData* ad, int64_t k) {
member_rval::ptr_u APCLocalArray::NvGetInt(const ArrayData* ad, int64_t k) {
auto a = asApcArray(ad);
auto index = a->getIndex(k);
if (index == -1) return nullptr;
return GetValueRef(a, index).asTypedValue();
return GetValueRef(a, index);
}
const TypedValue* APCLocalArray::NvGetStr(const ArrayData* ad,
const StringData* key) {
member_rval::ptr_u APCLocalArray::NvGetStr(const ArrayData* ad,
const StringData* key) {
auto a = asApcArray(ad);
auto index = a->getIndex(key);
if (index == -1) return nullptr;
return GetValueRef(a, index).asTypedValue();
return GetValueRef(a, index);
}
Cell APCLocalArray::NvGetKey(const ArrayData* ad, ssize_t pos) {
@@ -23,7 +23,7 @@
#include "hphp/runtime/base/array-data.h"
#include "hphp/runtime/base/apc-array.h"
#include "hphp/runtime/base/member-lval.h"
#include "hphp/runtime/base/member-val.h"
namespace HPHP {
@@ -46,7 +46,7 @@ struct APCLocalArray final : ArrayData,
static APCLocalArray* Make(const APCArray*);
static size_t Vsize(const ArrayData*);
static const Variant& GetValueRef(const ArrayData* ad, ssize_t pos);
static member_rval::ptr_u GetValueRef(const ArrayData* ad, ssize_t pos);
static bool ExistsInt(const ArrayData* ad, int64_t k);
static bool ExistsStr(const ArrayData* ad, const StringData* k);
static member_lval LvalInt(ArrayData*, int64_t k, bool copy);
@@ -71,10 +71,25 @@ struct APCLocalArray final : ArrayData,
static ArrayData* PlusEq(ArrayData*, const ArrayData *elems);
static ArrayData* Merge(ArrayData*, const ArrayData *elems);
static ArrayData* Prepend(ArrayData*, Cell v, bool copy);
static const TypedValue* NvGetInt(const ArrayData*, int64_t k);
static member_rval::ptr_u NvGetInt(const ArrayData*, int64_t k);
static constexpr auto NvTryGetInt = &NvGetInt;
static const TypedValue* NvGetStr(const ArrayData*, const StringData* k);
static member_rval::ptr_u NvGetStr(const ArrayData*, const StringData* k);
static constexpr auto NvTryGetStr = &NvGetStr;
static member_rval RvalInt(const ArrayData* ad, int64_t k) {
return member_rval { ad, NvGetInt(ad, k) };
}
static member_rval RvalIntStrict(const ArrayData* ad, int64_t k) {
return member_rval { ad, NvTryGetInt(ad, k) };
}
static member_rval RvalStr(const ArrayData* ad, const StringData* k) {
return member_rval { ad, NvGetStr(ad, k) };
}
static member_rval RvalStrStrict(const ArrayData* ad, const StringData* k) {
return member_rval { ad, NvTryGetStr(ad, k) };
}
static member_rval RvalAtPos(const ArrayData* ad, ssize_t pos) {
return member_rval { ad, GetValueRef(ad, pos) };
}
static Cell NvGetKey(const ArrayData*, ssize_t pos);
static bool IsVectorData(const ArrayData* ad);
static ssize_t IterBegin(const ArrayData*);
@@ -19,12 +19,12 @@
#include "hphp/runtime/base/array-data.h"
#include <algorithm>
#include "hphp/runtime/base/member-lval.h"
#include "hphp/runtime/base/member-val.h"
#include "hphp/runtime/base/string-data.h"
#include "hphp/runtime/base/type-variant.h"
#include <algorithm>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -99,20 +99,20 @@ inline const Variant& ArrayData::get(Cell k, bool error) const {
}
inline const Variant& ArrayData::get(int64_t k, bool error) const {
auto tv = error ? nvTryGet(k) : nvGet(k);
return tv ? tvAsCVarRef(tv) : getNotFound(k, error);
auto r = error ? rvalStrict(k) : rval(k);
return r ? tvAsCVarRef(r.tv_ptr()) : getNotFound(k, error);
}
inline const Variant& ArrayData::get(const StringData* k, bool error) const {
auto r = error ? rvalStrict(k) : rval(k);
return r ? tvAsCVarRef(r.tv_ptr()) : getNotFound(k, error);
}
inline const Variant& ArrayData::get(const String& k, bool error) const {
assert(IsValidKey(k));
return get(k.get(), error);
}
inline const Variant& ArrayData::get(const StringData* k, bool error) const {
auto tv = error ? nvTryGet(k) : nvGet(k);
return tv ? tvAsCVarRef(tv) : getNotFound(k, error);
}
inline const Variant& ArrayData::get(const Variant& k, bool error) const {
return get(*k.asCell(), error);
}
@@ -228,7 +228,7 @@ inline ArrayData* ArrayData::remove(const Variant& k, bool copy) {
}
inline Variant ArrayData::getValue(ssize_t pos) const {
return getValueRef(pos);
return tvAsCVarRef(rvalPos(pos).tv_ptr());
}
inline Variant ArrayData::getKey(ssize_t pos) const {
@@ -260,20 +260,36 @@ inline ArrayData* ArrayData::appendWithRef(const Variant& v, bool copy) {
return g_array_funcs.appendWithRef[kind()](this, *v.asTypedValue(), copy);
}
inline const TypedValue* ArrayData::nvGet(int64_t ikey) const {
return g_array_funcs.nvGetInt[kind()](this, ikey);
inline member_rval ArrayData::rval(int64_t k) const {
return member_rval { this, g_array_funcs.nvGetInt[kind()](this, k) };
}
inline const TypedValue* ArrayData::nvTryGet(int64_t ikey) const {
return g_array_funcs.nvTryGetInt[kind()](this, ikey);
inline member_rval ArrayData::rvalStrict(int64_t k) const {
return member_rval { this, g_array_funcs.nvTryGetInt[kind()](this, k) };
}
inline const TypedValue* ArrayData::nvGet(const StringData* skey) const {
return g_array_funcs.nvGetStr[kind()](this, skey);
inline member_rval ArrayData::rval(const StringData* k) const {
return member_rval { this, g_array_funcs.nvGetStr[kind()](this, k) };
}
inline const TypedValue* ArrayData::nvTryGet(const StringData* skey) const {
return g_array_funcs.nvTryGetStr[kind()](this, skey);
inline member_rval ArrayData::rvalStrict(const StringData* k) const {
return member_rval { this, g_array_funcs.nvTryGetStr[kind()](this, k) };
}
inline member_rval ArrayData::rvalPos(ssize_t pos) const {
return member_rval { this, g_array_funcs.nvGetPos[kind()](this, pos) };
}
inline TypedValue ArrayData::at(int64_t k) const {
return rval(k).tv();
}
inline TypedValue ArrayData::at(const StringData* k) const {
return rval(k).tv();
}
inline TypedValue ArrayData::atPos(ssize_t pos) const {
return rvalPos(pos).tv();
}
inline Cell ArrayData::nvGetKey(ssize_t pos) const {
@@ -314,10 +330,6 @@ inline size_t ArrayData::vsize() const {
return g_array_funcs.vsize[kind()](this);
}
inline const Variant& ArrayData::getValueRef(ssize_t pos) const {
return g_array_funcs.getValueRef[kind()](this, pos);
}
inline bool ArrayData::noCopyOnWrite() const {
// GlobalsArray doesn't support COW.
return kind() == kGlobalsKind;
@@ -173,35 +173,35 @@ const ArrayFunctions g_array_funcs = {
DISPATCH(Release)
/*
* const TypedValue* NvGetInt(const ArrayData*, int64_t key)
* member_rval::ptr_u NvGetInt(const ArrayData*, int64_t key)
*
* Lookup a value in an array using an integer key. Returns nullptr if the
* key is not in the array. Must not throw if key isn't present.
* key is not in the array. Must not throw if key isn't present.
*/
DISPATCH(NvGetInt)
/*
* const TypedValue* NvTryGetInt(const ArrayData*, int64_t key)
* member_rval::ptr_u NvTryGetInt(const ArrayData*, int64_t key)
*
* Lookup a value in an array using an integer key. Either throws, or
* Lookup a value in an array using an integer key. Either throws or
* returns nullptr if the key is not in the array.
*/
DISPATCH(NvTryGetInt)
/*
* const TypedValue* NvGetStr(const ArrayData*, const StringData*)
* member_rval::ptr_u NvGetStr(const ArrayData*, const StringData*)
*
* Lookup a value in an array using a string key. The string key
* must not be an integer-like string. Returns nullptr if the key
* is not in the array.
* Lookup a value in an array using a string key. The string key must not
* be an integer-like string. Returns nullptr if the key is not in the
* array.
*/
DISPATCH(NvGetStr)
/*
* const TypedValue* NvTryGetStr(const ArrayData*, const StringData*)
* member_rval::ptr_u NvTryGetStr(const ArrayData*, const StringData*)
*
* Lookup a value in an array using a string key. Either throws, or
* returns nullptr if the key is not in the array.
* Lookup a value in an array using a string key. Either throws or returns
* nullptr if the key is not in the array.
*/
DISPATCH(NvTryGetStr)
@@ -246,7 +246,7 @@ const ArrayFunctions g_array_funcs = {
DISPATCH(Vsize)
/*
* const Variant& GetValueRef(const ArrayData*, ssize_t pos)
* member_rval::ptr_u GetValueRef(const ArrayData*, ssize_t pos)
*
* Return a reference to the value at an iterator position. `pos' must be
* a valid position for this array.
@@ -23,7 +23,7 @@
#include <folly/Likely.h>
#include "hphp/runtime/base/countable.h"
#include "hphp/runtime/base/member-lval.h"
#include "hphp/runtime/base/member-val.h"
#include "hphp/runtime/base/memory-manager.h"
#include "hphp/runtime/base/sort-flags.h"
#include "hphp/runtime/base/typed-value.h"
@@ -166,12 +166,6 @@ struct ArrayData : MaybeCountable {
*/
size_t vsize() const;
/*
* getValueRef() gets a reference to value at position "pos". You
* must not change the returned Variant.
*/
const Variant& getValueRef(ssize_t pos) const;
/*
* Return true for array types that don't have COW semantics.
*/
@@ -238,6 +232,8 @@ struct ArrayData : MaybeCountable {
bool isTail() const { return m_pos == iter_last(); }
bool isInvalid() const { return m_pos == iter_end(); }
/////////////////////////////////////////////////////////////////////////////
/**
* Testing whether a key exists.
*/
@@ -249,16 +245,21 @@ struct ArrayData : MaybeCountable {
* using the other ArrayData api; subclasses may customize methods either
* by providing a custom static method in g_array_funcs.
*/
const TypedValue* nvGet(int64_t k) const;
const TypedValue* nvGet(const StringData* k) const;
const TypedValue* nvTryGet(int64_t k) const;
const TypedValue* nvTryGet(const StringData* k) const;
TypedValue at(int64_t k) const;
TypedValue at(const StringData* k) const;
TypedValue atPos(ssize_t pos) const;
Cell nvGetKey(ssize_t pos) const;
// wrappers that call getValueRef()
// wrappers that call rvalPos()
Variant getValue(ssize_t pos) const;
Variant getKey(ssize_t pos) const;
member_rval rval(int64_t k) const;
member_rval rval(const StringData* k) const;
member_rval rvalPos(ssize_t pos) const;
member_rval rvalStrict(int64_t k) const;
member_rval rvalStrict(const StringData* k) const;
/**
* Getting l-value (that Variant pointer) at specified key. Return this if
* escalation is not needed, or an escalated array data.
@@ -350,6 +351,8 @@ struct ArrayData : MaybeCountable {
ArrayData *remove(const String& k, bool copy);
ArrayData *remove(const Variant& k, bool copy);
/////////////////////////////////////////////////////////////////////////////
// See the documentation for IterEnd, IterBegin, etc. in array-data.cpp
ssize_t iter_begin() const;
ssize_t iter_last() const;
@@ -630,16 +633,16 @@ struct ArrayFunctions {
// NK stands for number of array kinds.
static auto const NK = size_t{9};
void (*release[NK])(ArrayData*);
const TypedValue* (*nvGetInt[NK])(const ArrayData*, int64_t k);
const TypedValue* (*nvTryGetInt[NK])(const ArrayData*, int64_t k);
const TypedValue* (*nvGetStr[NK])(const ArrayData*, const StringData* k);
const TypedValue* (*nvTryGetStr[NK])(const ArrayData*, const StringData* k);
member_rval::ptr_u (*nvGetInt[NK])(const ArrayData*, int64_t k);
member_rval::ptr_u (*nvTryGetInt[NK])(const ArrayData*, int64_t k);
member_rval::ptr_u (*nvGetStr[NK])(const ArrayData*, const StringData* k);
member_rval::ptr_u (*nvTryGetStr[NK])(const ArrayData*, const StringData* k);
Cell (*nvGetKey[NK])(const ArrayData*, ssize_t pos);
ArrayData* (*setInt[NK])(ArrayData*, int64_t k, Cell v, bool copy);
ArrayData* (*setStr[NK])(ArrayData*, StringData* k, Cell v,
bool copy);
size_t (*vsize[NK])(const ArrayData*);
const Variant& (*getValueRef[NK])(const ArrayData*, ssize_t pos);
member_rval::ptr_u (*nvGetPos[NK])(const ArrayData*, ssize_t pos);
bool (*isVectorData[NK])(const ArrayData*);
bool (*existsInt[NK])(const ArrayData*, int64_t k);
bool (*existsStr[NK])(const ArrayData*, const StringData* k);
Oops, something went wrong.

0 comments on commit e513c6d

Please sign in to comment.