diff --git a/hphp/runtime/base/array/array_init.h b/hphp/runtime/base/array/array_init.h index 0b24e1fbd..4aeeab1ef 100644 --- a/hphp/runtime/base/array/array_init.h +++ b/hphp/runtime/base/array/array_init.h @@ -276,12 +276,26 @@ public: return *this; } + // Prefer toArray() in new code---it can save a null check when the + // compiler can't prove m_data hasn't changed. ArrayData *create() { ArrayData *ret = m_data; m_data = nullptr; return ret; } + Array toArray() { + auto ptr = m_data; + m_data = nullptr; + return Array(ptr, Array::ArrayInitCtor::Tag); + } + + Variant toVariant() { + auto ptr = m_data; + m_data = nullptr; + return Variant(ptr, Variant::ArrayInitCtor::Tag); + } + static ArrayData *CreateParams(int count, ...); private: diff --git a/hphp/runtime/base/type_array.h b/hphp/runtime/base/type_array.h index 27ffe54b6..22cc6da8d 100644 --- a/hphp/runtime/base/type_array.h +++ b/hphp/runtime/base/type_array.h @@ -82,6 +82,15 @@ class Array : protected SmartPtr { /* implicit */ Array(ArrayData *data) : ArrayBase(data) { } /* implicit */ Array(CArrRef arr) : ArrayBase(arr.m_px) { } + /* + * Special constructor for use from ArrayInit that creates an Array + * without a null check. + */ + enum class ArrayInitCtor { Tag }; + explicit Array(ArrayData* ad, ArrayInitCtor) + : ArrayBase(ad, ArrayBase::NonNull::Tag) + {} + // Move ctor Array(Array&& src) : ArrayBase(std::move(src)) { static_assert(sizeof(Array) == sizeof(ArrayBase), "Fix this."); diff --git a/hphp/runtime/base/type_variant.h b/hphp/runtime/base/type_variant.h index 00f6091bd..1a4eba1e0 100644 --- a/hphp/runtime/base/type_variant.h +++ b/hphp/runtime/base/type_variant.h @@ -188,6 +188,16 @@ class Variant : private TypedValue { Variant(const Variant *v) = delete; Variant(Variant *v) = delete; + /* + * Creation constructor from ArrayInit that avoids a null check. + */ + enum class ArrayInitCtor { Tag }; + explicit Variant(ArrayData* ad, ArrayInitCtor) { + m_type = KindOfArray; + m_data.parr = ad; + ad->incRefCount(); + } + #ifdef INLINE_VARIANT_HELPER inline ALWAYS_INLINE Variant(CVarRef v) { constructValHelper(v); } inline ALWAYS_INLINE diff --git a/hphp/runtime/base/util/smart_ptr.h b/hphp/runtime/base/util/smart_ptr.h index 3443a4e7a..a39f745bb 100644 --- a/hphp/runtime/base/util/smart_ptr.h +++ b/hphp/runtime/base/util/smart_ptr.h @@ -53,6 +53,12 @@ public: if (m_px) m_px->incRefCount(); } + enum class NonNull { Tag }; + explicit SmartPtr(T* px, NonNull) : m_px(px) { + assert(px); + m_px->incRefCount(); + } + // Move ctor SmartPtr(SmartPtr&& src) : m_px(src.get()) { src.m_px = nullptr; diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 762b2d451..be2d1578d 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -2309,12 +2309,10 @@ Array VMExecutionContext::debugBacktrace(bool skip /* = false */, // the backtrace if (parserFrame) { bt.append( - Array( - ArrayInit(2) - .set(s_file, parserFrame->filename, true) - .set(s_line, parserFrame->lineNumber, true) - .create() - ) + ArrayInit(2) + .set(s_file, parserFrame->filename, true) + .set(s_line, parserFrame->lineNumber, true) + .toVariant() ); } @@ -2360,7 +2358,7 @@ Array VMExecutionContext::debugBacktrace(bool skip /* = false */, frame.set(s_function, s_include, true); frame.set(s_args, Array::Create(parserFrame->filename), true); } - bt.append(Array(frame.create())); + bt.append(frame.toVariant()); depth++; } } @@ -2479,7 +2477,7 @@ Array VMExecutionContext::debugBacktrace(bool skip /* = false */, frame.set(s_args, args, true); } - bt.append(Array(frame.create())); + bt.append(frame.toVariant()); depth++; } return bt;