From c5db7e39aba94ce03426a0d85c3c587fca4e97e4 Mon Sep 17 00:00:00 2001 From: jdelong Date: Mon, 1 Apr 2013 17:50:19 -0700 Subject: [PATCH] Fix a bug with boxed static/counted types When we box things, we need to forget whether we knew it was static or not because we don't track when that might change. --- hphp/runtime/base/tv_helpers.cpp | 2 ++ hphp/runtime/vm/translator/hopt/ir.h | 2 +- hphp/runtime/vm/translator/hopt/type.cpp | 17 +++++++++++++---- hphp/test/vm/boxed_static_string.php | 17 +++++++++++++++++ hphp/test/vm/boxed_static_string.php.exp | 1 + hphp/test/vm/boxed_static_string.php.filter | 2 ++ 6 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 hphp/test/vm/boxed_static_string.php create mode 100644 hphp/test/vm/boxed_static_string.php.exp create mode 100755 hphp/test/vm/boxed_static_string.php.filter diff --git a/hphp/runtime/base/tv_helpers.cpp b/hphp/runtime/base/tv_helpers.cpp index c71ff622a..267158f21 100644 --- a/hphp/runtime/base/tv_helpers.cpp +++ b/hphp/runtime/base/tv_helpers.cpp @@ -222,6 +222,8 @@ bool tvIsPlausible(const TypedValue* tv) { case KindOfStaticString: return okPtr(tv->m_data.pstr) && tv->m_data.pstr->isStatic(); case KindOfString: + return okPtr(tv->m_data.pstr) && + is_refcount_realistic(tv->m_data.pstr->getCount()); case KindOfArray: return okPtr(tv->m_data.parr) && is_refcount_realistic(tv->m_data.parr->getCount()); diff --git a/hphp/runtime/vm/translator/hopt/ir.h b/hphp/runtime/vm/translator/hopt/ir.h index 6a108708e..c12b41329 100644 --- a/hphp/runtime/vm/translator/hopt/ir.h +++ b/hphp/runtime/vm/translator/hopt/ir.h @@ -972,7 +972,7 @@ public: explicit Type(bits_t bits = kNone) : m_bits(bits) - {} + {} size_t hash() const { return hash_int64(m_bits); diff --git a/hphp/runtime/vm/translator/hopt/type.cpp b/hphp/runtime/vm/translator/hopt/type.cpp index dc0cf5040..b16edd022 100644 --- a/hphp/runtime/vm/translator/hopt/type.cpp +++ b/hphp/runtime/vm/translator/hopt/type.cpp @@ -48,14 +48,21 @@ Type builtinReturn(const IRInstruction* inst) { Type boxReturn(const IRInstruction* inst, int srcId) { auto t = inst->getSrc(srcId)->getType(); - // If t contains Uninit, replace it with InitNull. Otherwise, leave - // the type alone. + // If t contains Uninit, replace it with InitNull. t = t.maybe(Type::Uninit) ? (t - Type::Uninit) | Type::InitNull : t; + // We don't try to track when a BoxedStaticStr might be converted to + // a BoxedStr, and we never guard on staticness for strings, so + // boxing a string needs to forget this detail. Same thing for + // arrays. + if (t.subtypeOf(Type::Str)) { + t = Type::Str; + } else if (t.subtypeOf(Type::Arr)) { + t = Type::Arr; + } + // Everything else is just a pure type-system boxing operation. return t.box(); } -} - Type stkReturn(const IRInstruction* inst, int dstId, std::function inner) { assert(inst->modifiesStack()); @@ -68,6 +75,8 @@ Type stkReturn(const IRInstruction* inst, int dstId, return Type::StkPtr; } +} + Type outputType(const IRInstruction* inst, int dstId) { #define D(type) return Type::type; diff --git a/hphp/test/vm/boxed_static_string.php b/hphp/test/vm/boxed_static_string.php new file mode 100644 index 000000000..3ebf165b2 --- /dev/null +++ b/hphp/test/vm/boxed_static_string.php @@ -0,0 +1,17 @@ +