Atomically assign and set persistent rds handles
[hiphop-php.git] / hphp / runtime / vm / native.h
blob9ed79f8c0ed5191d8328ae88b0e6a82853d78e39
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_RUNTIME_VM_NATIVE_H
17 #define incl_HPHP_RUNTIME_VM_NATIVE_H
19 #include "hphp/runtime/base/type-string.h"
20 #include "hphp/runtime/base/typed-value.h"
21 #include "hphp/runtime/base/tv-mutate.h"
22 #include "hphp/runtime/base/tv-variant.h"
24 #include "hphp/runtime/vm/func.h"
25 #include "hphp/util/abi-cxx.h"
27 #include <type_traits>
29 namespace HPHP {
30 struct ActRec;
31 struct Class;
32 struct FuncEmitter;
33 struct Object;
36 /* Macros related to declaring/registering internal implementations
37 * of <<__Native>> global functions.
39 * Declare a function in ext_foo.h using:
40 * ReturnType HHVM_FUNCTION(functionName, parameterList...)
41 * For example:
42 * int64_t HHVM_FUNCTION(sum, int64_t a, int64_t b) {
43 * return a + b;
44 * }
46 * Then register it from your Extension's moduleLoad() hook:
47 * void moduleLoad(const IniSetting::Map& ini, Hdf config) override {
48 * HHVM_FE(sum);
49 * }
51 * To finish exposing it to PHP, add an entry to Systemlib
52 * using matching hack typehints:
53 * <?php
54 * <<__Native>>
55 * function sum(int $a, int $b): int;
57 ****************************************************************************
59 * For functions with variadic args or other "special" handling,
60 * declare the prototype as a BuiltinFuncPtr:
61 * TypedValue* HHVM_FN(sum)(ActRec* ar) { ... }
62 * And declare it in Systemlib with the "ActRec" subattribute
63 * <?php
64 * <<__Native("ActRec")>>
65 * function sum(int $a, int $b): int;
66 * Registering the function in moduleLoad() remains the same.
68 ****************************************************************************
70 * If, for whatever reason, the standard declaration doesn't work,
71 * you may declare the function directly as:
72 * ReturnType localSymbolName(parameterList...)
73 * For example:
74 * int64_t my_sum_function(int64_t a, int64_t b) {
75 * return a + b;
76 * }
78 * In which case you will need to use a different macro in moduleLoad()
79 * virtual moduleLoad(const IniSetting::Map& ini, Hdf config) {
80 * HHVM_NAME_FE(sum, my_sum_function)
81 * }
82 * Or an explicit call to registerBuildinFunction()
83 * static const StaticString s_sum("sum");
84 * virtual moduleLoad(const IniSetting::Map& ini, Hdf config) {
85 * Native::registerBuiltinFunction(s_sum, (void*)my_sum_function);
86 * }
88 ****************************************************************************
90 * The macros HHVM_FALIAS, HHVM_MALIAS, and HHVM_STATIC_MALIAS allow
91 * giving different names to the C++ implementation and the exported
92 * C++ function. This ca be useful for creating multiple names for one
93 * function or for registering functions that live in a namespace.
96 #define HHVM_FN(fn) f_ ## fn
97 #define HHVM_FUNCTION(fn, ...) \
98 HHVM_FN(fn)(__VA_ARGS__)
99 #define HHVM_NAMED_FE_STR(fn, fimpl) \
100 do { \
101 /* This calls Extension::registerExtensionFunction() on the */ \
102 /* local 'this' at the call site. */ \
103 String name{makeStaticString(fn)}; \
104 registerExtensionFunction(name); \
105 Native::registerBuiltinFunction(name, fimpl); \
106 } while(0)
107 #define HHVM_NAMED_FE(fn, fimpl) HHVM_NAMED_FE_STR(#fn, fimpl)
108 #define HHVM_FE(fn) HHVM_NAMED_FE_STR(#fn, HHVM_FN(fn))
109 #define HHVM_FALIAS(fn, falias) HHVM_NAMED_FE_STR(#fn, HHVM_FN(falias))
111 /* Macros related to declaring/registering internal implementations
112 * of <<__Native>> class instance methods.
114 * See the definition of function macros above for general explanation.
115 * These macros only differ in the following ways:
116 * - They accept a classname in addition to the function name
117 * - The registered name of the function is "ClassName->FunctionName"
118 * - Prototypes include a prepended ObjectData* const parameter (named this_)
120 #define HHVM_MN(cn,fn) c_ ## cn ## _ni_ ## fn
121 #define HHVM_METHOD(cn, fn, ...) \
122 HHVM_MN(cn,fn)(ObjectData* const this_, ##__VA_ARGS__)
123 #define HHVM_NAMED_ME(cn,fn,mimpl) \
124 Native::registerBuiltinFunction(#cn "->" #fn, mimpl)
125 #define HHVM_ME(cn,fn) HHVM_NAMED_ME(cn,fn, HHVM_MN(cn,fn))
126 #define HHVM_MALIAS(cn,fn,calias,falias) \
127 HHVM_NAMED_ME(cn,fn,HHVM_MN(calias,falias))
129 /* Macros related to declaring/registering internal implementations
130 * of <<__Native>> class static methods.
132 * See the definition of function macros above for general explanation.
133 * These macros only differ in the following ways:
134 * - They accept a classname in addition to the function name
135 * - The registered name of the function is "ClassName::FunctionName"
136 * - Prototypes include a prepended const Class* parameter (named self_)
138 #define HHVM_STATIC_MN(cn,fn) c_ ## cn ## _ns_ ## fn
139 #define HHVM_STATIC_METHOD(cn, fn, ...) \
140 HHVM_STATIC_MN(cn,fn)(const Class *self_, ##__VA_ARGS__)
141 #define HHVM_NAMED_STATIC_ME(cn,fn,mimpl) \
142 Native::registerBuiltinFunction(#cn "::" #fn, mimpl)
143 #define HHVM_STATIC_ME(cn,fn) HHVM_NAMED_STATIC_ME(cn,fn,HHVM_STATIC_MN(cn,fn))
144 #define HHVM_STATIC_MALIAS(cn,fn,calias,falias) \
145 HHVM_NAMED_STATIC_ME(cn,fn,HHVM_STATIC_MN(calias,falias))
147 /* Macros related to declaring/registering constants. Note that the
148 * HHVM_RCC_* macros expect a StaticString to be present via s_##class_name.
150 #define HHVM_RC_STR(const_name, const_value) \
151 Native::registerConstant<KindOfString>( \
152 makeStaticString(#const_name), makeStaticString(const_value));
153 #define HHVM_RC_INT(const_name, const_value) \
154 Native::registerConstant<KindOfInt64>( \
155 makeStaticString(#const_name), int64_t{const_value});
156 #define HHVM_RC_DBL(const_name, const_value) \
157 Native::registerConstant<KindOfDouble>( \
158 makeStaticString(#const_name), double{const_value});
159 #define HHVM_RC_BOOL(const_name, const_value) \
160 Native::registerConstant<KindOfBoolean>( \
161 makeStaticString(#const_name), bool{const_value});
163 #define HHVM_RC_STR_SAME(const_name) \
164 Native::registerConstant<KindOfString>( \
165 makeStaticString(#const_name), makeStaticString(const_name));
166 #define HHVM_RC_INT_SAME(const_name) \
167 Native::registerConstant<KindOfInt64>( \
168 makeStaticString(#const_name), int64_t{const_name});
169 #define HHVM_RC_DBL_SAME(const_name) \
170 Native::registerConstant<KindOfDouble>( \
171 makeStaticString(#const_name), double{const_name});
172 #define HHVM_RC_BOOL_SAME(const_name) \
173 Native::registerConstant<KindOfBoolean>( \
174 makeStaticString(#const_name), bool{const_name});
176 #define HHVM_RCC_STR(class_name, const_name, const_value) \
177 Native::registerClassConstant<KindOfString>(s_##class_name.get(), \
178 makeStaticString(#const_name), makeStaticString(const_value));
179 #define HHVM_RCC_INT(class_name, const_name, const_value) \
180 Native::registerClassConstant<KindOfInt64>(s_##class_name.get(), \
181 makeStaticString(#const_name), int64_t{const_value});
182 #define HHVM_RCC_DBL(class_name, const_name, const_value) \
183 Native::registerClassConstant<KindOfDouble>(s_##class_name.get(), \
184 makeStaticString(#const_name), double{const_value});
185 #define HHVM_RCC_BOOL(class_name, const_name, const_value) \
186 Native::registerClassConstant<KindOfBoolean>(s_##class_name.get(), \
187 makeStaticString(#const_name), bool{const_value});
189 // Register a dynamic constant. This will not be optimized by hhbbc
190 #define HHVM_RC_DYNAMIC(const_name, const_value_cell) \
191 Native::registerConstant(makeStaticString(#const_name), \
192 const_value_cell, true);
194 namespace HPHP { namespace Native {
195 //////////////////////////////////////////////////////////////////////////////
197 // Maximum number of args for a native function call
198 // Beyond this number, a function/method will have to
199 // take a raw ActRec (using <<__Native("ActRec")>>) and
200 // deal with the args using getArg<KindOf*>(ar, argNum)
202 // To paraphrase you-know-who, "32 args should be enough for anybody"
204 // Note: If changing this number, update native-func-caller.h
205 // using make_native-func-caller.php
206 const int kMaxBuiltinArgs = 32;
208 inline int maxFCallBuiltinArgs() {
209 return kMaxBuiltinArgs;
212 inline bool allowFCallBuiltinDoubles() {
213 return true;
216 enum Attr {
217 AttrNone = 0,
218 AttrActRec = 1 << 0,
219 AttrZendCompat = 1 << 1,
220 AttrOpCodeImpl = 1 << 2, //Methods whose implementation is in the emitter
224 * Prepare function call arguments to match their expected
225 * types on a native function/method call.
227 * Uses typehints in Func and tvCast*InPlace
229 bool coerceFCallArgs(TypedValue* args,
230 int32_t numArgs, int32_t numNonDefault,
231 const Func* func, bool useStrictTypes);
234 * Dispatches a call to the native function bound to <func>
235 * If <ctx> is not nullptr, it is prepended to <args> when
236 * calling.
238 template<bool usesDoubles>
239 void callFunc(const Func* func, void* ctx,
240 TypedValue* args, int32_t numNonDefault,
241 TypedValue& ret);
244 * Extract the name used to invoke the function from the ActRec where name
245 * maybe be stored in invName, or may include the classname (e.g. Class::func)
247 const StringData* getInvokeName(ActRec* ar);
249 #define NATIVE_TYPES \
250 /* kind arg type return type */ \
251 X(Int32, int32_t, int32_t) \
252 X(Int64, int64_t, int64_t) \
253 X(Double, double, double) \
254 X(Bool, bool, bool) \
255 X(Object, const Object&, Object) \
256 X(String, const String&, String) \
257 X(Array, const Array&, Array) \
258 X(Resource, const Resource&, Resource) \
259 X(Mixed, const Variant&, Variant) \
260 X(ObjectArg, ObjectArg, ObjectArg) \
261 X(StringArg, StringArg, StringArg) \
262 X(ArrayArg, ArrayArg, ArrayArg) \
263 X(ResourceArg,ResourceArg, ResourceArg) \
264 X(OutputArg, OutputArg, OutputArg) \
265 X(ARReturn, TypedValue*, TypedValue*) \
266 X(MixedTV, TypedValue, TypedValue) \
267 X(MixedRef, const VRefParamValue&,VRefParamValue) \
268 X(VarArgs, ActRec*, ActRec*) \
269 X(This, ObjectData*, ObjectData*) \
270 X(Class, const Class*, const Class*) \
271 X(Void, void, void) \
272 X(Zend, ZendFuncType, ZendFuncType) \
273 /**/
275 enum class ZendFuncType {};
277 template <class T>
278 struct NativeArg {
280 * Delete move assignment operator to make this non-copyable.
282 NativeArg& operator=(NativeArg&&) = delete;
283 T* operator->() { return m_px; }
284 T* get() { return m_px; }
285 bool operator!() const { return m_px == nullptr; }
286 bool isNull() const { return m_px == nullptr; }
287 private:
289 * To be able to pass the values of this class as function parameters
290 * by value, define default copy constructor (See Itanium C++ ABI p3.1.1).
291 * Make it private to satisfy the non-copyable requirement.
293 NativeArg(const NativeArg&) = default;
294 T* m_px;
298 using ObjectArg = Native::NativeArg<ObjectData>;
299 using StringArg = Native::NativeArg<StringData>;
300 using ArrayArg = Native::NativeArg<ArrayData>;
301 using ResourceArg = Native::NativeArg<ResourceData>;
302 using OutputArg = Native::NativeArg<RefData>;
304 namespace Native {
306 struct NativeSig {
307 enum class Type : uint8_t {
308 #define X(name, ...) name,
309 NATIVE_TYPES
310 #undef X
313 explicit NativeSig(ZendFuncType) : ret(Type::Zend) {}
314 NativeSig() : ret(Type::Void) {}
316 NativeSig(Type _ret, const std::vector<Type>& _args)
317 : ret(_ret), args(_args) {
320 template<class Ret>
321 explicit NativeSig(Ret (*ptr)());
323 template<class Ret, class... Args>
324 explicit NativeSig(Ret (*ptr)(Args...));
326 std::string toString(const char* classname, const char* fname) const;
328 Type ret;
329 std::vector<Type> args;
332 namespace detail {
334 template<class T> struct native_arg_type {};
335 template<class T> struct native_ret_type {};
336 template<class T> struct known_native_arg : std::false_type {};
338 #define X(name, argTy, retTy) \
339 template<> struct native_ret_type<retTy> \
340 : std::integral_constant<NativeSig::Type,NativeSig::Type::name> \
341 {}; \
342 template<> struct native_arg_type<argTy> \
343 : std::integral_constant<NativeSig::Type,NativeSig::Type::name> \
344 {}; \
345 template<> struct known_native_arg<argTy> : std::true_type {};
347 NATIVE_TYPES
349 #undef X
351 template<class... Args> struct all_known_arg_type {};
352 template<class A> struct all_known_arg_type<A> : known_native_arg<A> {};
354 template<class A, class... Rest>
355 struct all_known_arg_type<A,Rest...>
356 : std::integral_constant<
357 bool,
358 known_native_arg<A>::value && all_known_arg_type<Rest...>::value
362 template<class T> struct understandable_sig : std::false_type {};
363 template<class R> struct understandable_sig<R (*)()> : std::true_type {};
364 template<class R, class... Args>
365 struct understandable_sig<R (*)(Args...)>
366 : all_known_arg_type<Args...>
369 template<class... Args>
370 std::vector<NativeSig::Type> build_args() {
371 return {
372 native_arg_type<Args>::value...
378 template <class Ret>
379 NativeSig::NativeSig(Ret (*/*ptr*/)())
380 : ret(detail::native_ret_type<Ret>::value) {}
382 template <class Ret, class... Args>
383 NativeSig::NativeSig(Ret (*/*ptr*/)(Args...))
384 : ret(detail::native_ret_type<Ret>::value),
385 args(detail::build_args<Args...>()) {}
387 #undef NATIVE_TYPES
389 struct BuiltinFunctionInfo {
390 BuiltinFunctionInfo() : ptr(nullptr) {}
392 template<typename Func>
393 explicit BuiltinFunctionInfo(Func f)
394 : sig(f)
395 , ptr((BuiltinFunction)f)
398 BuiltinFunctionInfo(NativeSig _sig, BuiltinFunction _ptr)
399 : sig(_sig), ptr(_ptr) {
402 NativeSig sig;
403 BuiltinFunction ptr;
406 /////////////////////////////////////////////////////////////////////////////
409 * Returns a specialization of either functionWrapper or methodWrapper
411 * functionWrapper() Unpacks args and coerces types according
412 * to Func typehints. Calls C++ function in the form:
413 * ret f_foo(type arg1, type arg2, ...)
414 * Marshalls return into TypedValue.
416 * methodWrapper() behaves the same as functionWrapper(),
417 * but also prepends either an ObjectData* (instance) or Class* (static)
418 * argument to the signature. i.e.:
419 * ret c_class_ni_method(ObjectData* this_, type arg1, type arg2, ...)
420 * ret c_class_ns_method(Class* self_, type arg1, type arg2, ...)
422 void getFunctionPointers(const BuiltinFunctionInfo& info,
423 int nativeAttrs,
424 BuiltinFunction& bif,
425 BuiltinFunction& nif);
428 * Fallback method bound to declared methods with no matching
429 * internal implementation.
431 TypedValue* unimplementedWrapper(ActRec* ar);
433 /////////////////////////////////////////////////////////////////////////////
436 * Case insensitive map of "name" to function pointer
438 * Extensions should generally add items to this map using
439 * the HHVM_FE/ME macros above. The function name (key) must
440 * be a static string because this table is shared and outlives
441 * individual requests.
443 typedef hphp_hash_map<const StringData*, BuiltinFunctionInfo,
444 string_data_hash, string_data_isame> BuiltinFunctionMap;
446 extern BuiltinFunctionMap s_builtinFunctions;
448 template <class Fun> typename
449 std::enable_if<!std::is_member_function_pointer<Fun>::value, void>::type
450 registerBuiltinFunction(const char* name, Fun func) {
451 static_assert(
452 std::is_pointer<Fun>::value &&
453 std::is_function<typename std::remove_pointer<Fun>::type>::value,
454 "You can only register pointers to functions."
456 static_assert(
457 detail::understandable_sig<Fun>::value,
458 "Arguments on builtin function were not understood types"
460 s_builtinFunctions[makeStaticString(name)] = BuiltinFunctionInfo(func);
463 template <class Fun> typename
464 std::enable_if<!std::is_member_function_pointer<Fun>::value, void>::type
465 registerBuiltinFunction(const String& name, Fun func) {
466 static_assert(
467 std::is_pointer<Fun>::value &&
468 std::is_function<typename std::remove_pointer<Fun>::type>::value,
469 "You can only register pointers to functions."
471 static_assert(
472 detail::understandable_sig<Fun>::value,
473 "Arguments on builtin function were not understood types"
475 s_builtinFunctions[makeStaticString(name)] = BuiltinFunctionInfo(func);
478 template <class Fun> typename
479 std::enable_if<!std::is_member_function_pointer<Fun>::value, void>::type
480 registerBuiltinZendFunction(const char* name, Fun func) {
481 static_assert(
482 std::is_pointer<Fun>::value &&
483 std::is_function<typename std::remove_pointer<Fun>::type>::value,
484 "You can only register pointers to functions."
486 auto bfi = BuiltinFunctionInfo();
487 bfi.ptr = (BuiltinFunction)func;
488 bfi.sig = NativeSig(ZendFuncType{});
489 s_builtinFunctions[makeStaticString(name)] = bfi;
492 template <class Fun> typename
493 std::enable_if<!std::is_member_function_pointer<Fun>::value, void>::type
494 registerBuiltinZendFunction(const String& name, Fun func) {
495 static_assert(
496 std::is_pointer<Fun>::value &&
497 std::is_function<typename std::remove_pointer<Fun>::type>::value,
498 "You can only register pointers to function."
500 auto bfi = BuiltinFunctionInfo();
501 bfi.ptr = (BuiltinFunction)func;
502 bfi.sig = NativeSig(ZendFuncType{});
503 s_builtinFunctions[makeStaticString(name)] = bfi;
506 // Specializations of registerBuiltinFunction for taking
507 // Pointers to Member Functions and making them look like HNI wrapper funcs
509 // This allows invoking object method calls directly,
510 // but ONLY for specialized subclasses of ObjectData.
512 // This API is limited to: Closure, Asio, and Collections
513 // Do not use it if you are not implementing one of these
514 template<class Ret, class Cls> typename
515 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
516 registerBuiltinFunction(const char* name, Ret (Cls::*func)()) {
517 registerBuiltinFunction(name,
518 (Ret (*)(ObjectData*))getMethodPtr(func));
521 template<class Ret, class Cls, class... Args> typename
522 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
523 registerBuiltinFunction(const char* name, Ret (Cls::*func)(Args...)) {
524 registerBuiltinFunction(name,
525 (Ret (*)(ObjectData*, Args...))getMethodPtr(func));
528 template<class Ret, class Cls> typename
529 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
530 registerBuiltinFunction(const char* name, Ret (Cls::*func)() const) {
531 registerBuiltinFunction(name,
532 (Ret (*)(ObjectData*))getMethodPtr(func));
534 template<class Ret, class Cls, class... Args> typename
535 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
536 registerBuiltinFunction(const char* name, Ret (Cls::*func)(Args...) const) {
537 registerBuiltinFunction(name,
538 (Ret (*)(ObjectData*, Args...))getMethodPtr(func));
541 /////////////////////////////////////////////////////////////////////////////
543 const char* checkTypeFunc(const NativeSig& sig,
544 const TypeConstraint& retType,
545 const Func* func);
547 inline BuiltinFunctionInfo GetBuiltinFunction(const StringData* fname,
548 const StringData* cname = nullptr,
549 bool isStatic = false) {
550 auto it = s_builtinFunctions.find((cname == nullptr) ? fname :
551 (String(const_cast<StringData*>(cname)) +
552 (isStatic ? "::" : "->") +
553 String(const_cast<StringData*>(fname))).get());
554 return (it == s_builtinFunctions.end()) ? BuiltinFunctionInfo() : it->second;
557 inline BuiltinFunctionInfo GetBuiltinFunction(const char* fname,
558 const char* cname = nullptr,
559 bool isStatic = false) {
560 return GetBuiltinFunction(makeStaticString(fname),
561 cname ? makeStaticString(cname) : nullptr,
562 isStatic);
565 //////////////////////////////////////////////////////////////////////////////
566 // Global constants
568 typedef std::map<const StringData*,TypedValueAux> ConstantMap;
569 extern ConstantMap s_constant_map;
571 inline
572 bool registerConstant(const StringData* cnsName, Cell cns,
573 bool dynamic = false) {
574 assert(cellIsPlausible(cns) && cns.m_type != KindOfUninit);
575 auto& dst = s_constant_map[cnsName];
576 *static_cast<Cell*>(&dst) = cns;
577 dst.dynamic() = dynamic;
578 return bindPersistentCns(cnsName, cns);
581 template<DataType DType>
582 typename std::enable_if<
583 !std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
584 bool>::type
585 registerConstant(const StringData* cnsName,
586 typename DataTypeCPPType<DType>::type val) {
587 return registerConstant(cnsName, make_tv<DType>(val));
590 template<DataType DType>
591 typename std::enable_if<
592 std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
593 bool>::type
594 registerConstant(const StringData* cnsName) {
595 return registerConstant(cnsName, make_tv<DType>());
598 inline
599 const ConstantMap& getConstants() {
600 return s_constant_map;
603 using ConstantCallback = const Variant& (*)();
604 bool registerConstant(const StringData*, ConstantCallback);
606 //////////////////////////////////////////////////////////////////////////////
607 // Class Constants
609 typedef hphp_hash_map<const StringData*, ConstantMap,
610 string_data_hash, string_data_isame> ClassConstantMapMap;
611 extern ClassConstantMapMap s_class_constant_map;
613 inline
614 bool registerClassConstant(const StringData *clsName,
615 const StringData *cnsName,
616 Cell cns) {
617 assert(cellIsPlausible(cns));
618 auto &cls = s_class_constant_map[clsName];
619 assert(cls.find(cnsName) == cls.end());
620 *static_cast<Cell*>(&cls[cnsName]) = cns;
621 return true;
624 template<DataType DType>
625 typename std::enable_if<
626 !std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
627 bool>::type
628 registerClassConstant(const StringData* clsName,
629 const StringData* cnsName,
630 typename DataTypeCPPType<DType>::type val) {
631 return registerClassConstant(clsName, cnsName, make_tv<DType>(val));
634 template<DataType DType>
635 typename std::enable_if<
636 std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
637 bool>::type
638 registerClassConstant(const StringData* clsName,
639 const StringData* cnsName) {
640 return registerClassConstant(clsName, cnsName, make_tv<DType>());
643 inline
644 const ConstantMap* getClassConstants(const StringData* clsName) {
645 auto clsit = s_class_constant_map.find(const_cast<StringData*>(clsName));
646 if (clsit == s_class_constant_map.end()) {
647 return nullptr;
649 return &clsit->second;
652 //////////////////////////////////////////////////////////////////////////////
653 }} // namespace HPHP::Native
655 #endif