From cc37fe637a945bace3f0f6f7bbe32e33add2024c Mon Sep 17 00:00:00 2001 From: ptarjan Date: Wed, 20 Mar 2013 02:21:16 -0700 Subject: [PATCH] add Callable typehint php-5.4 has it http://www.php.net/manual/en/language.types.callable.php --- hphp/runtime/vm/translator/translator-x64.cpp | 22 ++++++++++++--- hphp/runtime/vm/type_constraint.cpp | 28 +++++++++++-------- hphp/runtime/vm/type_constraint.h | 11 +++++++- hphp/test/vm/typehint_callable.php | 12 ++++++++ hphp/test/vm/typehint_callable.php.exp | 2 ++ hphp/test/vm/typehint_callable.php.filter | 1 + 6 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 hphp/test/vm/typehint_callable.php create mode 100644 hphp/test/vm/typehint_callable.php.exp create mode 120000 hphp/test/vm/typehint_callable.php.filter diff --git a/hphp/runtime/vm/translator/translator-x64.cpp b/hphp/runtime/vm/translator/translator-x64.cpp index c2c0c4538..95e2a34de 100644 --- a/hphp/runtime/vm/translator/translator-x64.cpp +++ b/hphp/runtime/vm/translator/translator-x64.cpp @@ -66,6 +66,7 @@ typedef __sighandler_t *sighandler_t; #include "runtime/base/runtime_option.h" #include "runtime/base/server/source_root_info.h" #include "runtime/ext/ext_continuation.h" +#include "runtime/ext/ext_function.h" #include "runtime/vm/debug/debug.h" #include "runtime/vm/translator/targetcache.h" #include "runtime/vm/translator/translator-deps.h" @@ -10258,6 +10259,16 @@ VerifyParamTypeSlow(const Class* cls, const Class* constraint, int param) { } } +static void +VerifyParamCallable(ObjectData* obj, int param) { + TypedValue tv; + tvWriteObject(obj, &tv); + if (!UNLIKELY(f_is_callable(tvAsCVarRef(&tv)))) { + VerifyParamTypeFail(param); + } + tvDecRef(&tv); +} + void TranslatorX64::translateVerifyParamType(const Tracelet& t, const NormalizedInstruction& i) { @@ -10283,18 +10294,21 @@ TranslatorX64::translateVerifyParamType(const Tracelet& t, ScratchReg cls(m_regMap); // Constraint may not be in the class-hierarchy of the method being traced, // look up the class handle and emit code to put the Class* into a reg. - bool isSelfOrParent = tc.isSelf() || tc.isParent(); + bool isSpecial = tc.isSelf() || tc.isParent() || tc.isCallable(); const Class* constraint = nullptr; const StringData* clsName; - if (!isSelfOrParent) { + if (!isSpecial) { clsName = tc.typeName(); constraint = Unit::lookupUniqueClass(clsName); } else { if (tc.isSelf()) { tc.selfToClass(curFunc(), &constraint); - } else { - assert(tc.isParent()); + } else if (tc.isParent()) { tc.parentToClass(curFunc(), &constraint); + } else { + assert(tc.isCallable()); + EMIT_RCALL(a, i, VerifyParamCallable, R(src), IMM(param)); + return; } clsName = constraint ? constraint->preClass()->name() : nullptr; } diff --git a/hphp/runtime/vm/type_constraint.cpp b/hphp/runtime/vm/type_constraint.cpp index f39a7b3c8..3930d5233 100644 --- a/hphp/runtime/vm/type_constraint.cpp +++ b/hphp/runtime/vm/type_constraint.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -39,22 +40,23 @@ TypeConstraint::TypeConstraint(const StringData* typeName /* = NULL */, const StringData* name; Type type; } pairs[] = { - { StringData::GetStaticString("bool"), { KindOfBoolean, Precise }}, - { StringData::GetStaticString("boolean"), { KindOfBoolean, Precise }}, + { StringData::GetStaticString("bool"), { KindOfBoolean, Precise }}, + { StringData::GetStaticString("boolean"), { KindOfBoolean, Precise }}, - { StringData::GetStaticString("int"), { KindOfInt64, Precise }}, - { StringData::GetStaticString("integer"), { KindOfInt64, Precise }}, + { StringData::GetStaticString("int"), { KindOfInt64, Precise }}, + { StringData::GetStaticString("integer"), { KindOfInt64, Precise }}, - { StringData::GetStaticString("real"), { KindOfDouble, Precise }}, - { StringData::GetStaticString("double"), { KindOfDouble, Precise }}, - { StringData::GetStaticString("float"), { KindOfDouble, Precise }}, + { StringData::GetStaticString("real"), { KindOfDouble, Precise }}, + { StringData::GetStaticString("double"), { KindOfDouble, Precise }}, + { StringData::GetStaticString("float"), { KindOfDouble, Precise }}, - { StringData::GetStaticString("string"), { KindOfString, Precise }}, + { StringData::GetStaticString("string"), { KindOfString, Precise }}, - { StringData::GetStaticString("array"), { KindOfArray, Precise }}, + { StringData::GetStaticString("array"), { KindOfArray, Precise }}, - { StringData::GetStaticString("self"), { KindOfObject, Self }}, - { StringData::GetStaticString("parent"), { KindOfObject, Parent }}, + { StringData::GetStaticString("self"), { KindOfObject, Self }}, + { StringData::GetStaticString("parent"), { KindOfObject, Parent }}, + { StringData::GetStaticString("callable"), { KindOfObject, Callable }}, }; for (unsigned i = 0; i < sizeof(pairs) / sizeof(Pair); ++i) { s_typeNamesToTypes[pairs[i].name] = pairs[i].type; @@ -107,11 +109,13 @@ TypeConstraint::check(const TypedValue* tv, const Func* func) const { return true; } const Class *c = nullptr; - if (isSelf() || isParent()) { + if (isSelf() || isParent() || isCallable()) { if (isSelf()) { selfToClass(func, &c); } else if (isParent()) { parentToClass(func, &c); + } else if (isCallable()) { + return f_is_callable(tvAsCVarRef(tv)); } } else { // We can't save the Class* since it moves around from request diff --git a/hphp/runtime/vm/type_constraint.h b/hphp/runtime/vm/type_constraint.h index 13b755dfd..221e0bae7 100644 --- a/hphp/runtime/vm/type_constraint.h +++ b/hphp/runtime/vm/type_constraint.h @@ -34,7 +34,8 @@ protected: enum MetaType { Precise, Self, - Parent + Parent, + Callable }; struct Type { @@ -46,6 +47,9 @@ protected: constexpr bool isSelf() const { return m_metatype == Self; } + constexpr bool isCallable() const { + return m_metatype == Callable; + } }; Type m_type; @@ -74,10 +78,15 @@ public: bool isParent() const { return m_type.isParent(); } + + bool isCallable() const { + return m_type.isCallable(); + } bool isObject() const { assert(IMPLIES(isParent(), m_type.m_dt == KindOfObject)); assert(IMPLIES(isSelf(), m_type.m_dt == KindOfObject)); + assert(IMPLIES(isCallable(), m_type.m_dt == KindOfObject)); return m_type.m_dt == KindOfObject; } diff --git a/hphp/test/vm/typehint_callable.php b/hphp/test/vm/typehint_callable.php new file mode 100644 index 000000000..990ec79f4 --- /dev/null +++ b/hphp/test/vm/typehint_callable.php @@ -0,0 +1,12 @@ +