Optimize struct element initialization
[hiphop-php.git] / hphp / runtime / vm / native.h
blob0344fd3b98b47289a0ba5fdc5ae8dd54502ff297
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 #pragma once
18 #include "hphp/runtime/base/type-string.h"
19 #include "hphp/runtime/base/typed-value.h"
20 #include "hphp/runtime/base/tv-mutate.h"
21 #include "hphp/runtime/base/tv-variant.h"
23 #include "hphp/runtime/vm/func.h"
24 #include "hphp/runtime/vm/class-meth-data-ref.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;
34 struct Extension;
37 /* Macros related to declaring/registering internal implementations
38 * of <<__Native>> global functions.
40 * Declare a function in ext_foo.h using:
41 * ReturnType HHVM_FUNCTION(functionName, parameterList...)
42 * For example:
43 * int64_t HHVM_FUNCTION(sum, int64_t a, int64_t b) {
44 * return a + b;
45 * }
47 * Then register it from your Extension's moduleLoad() hook:
48 * void moduleLoad(const IniSetting::Map& ini, Hdf config) override {
49 * HHVM_FE(sum);
50 * }
52 * To finish exposing it to PHP, add an entry to Systemlib
53 * using matching hack typehints:
54 * <?hh
55 * <<__Native>>
56 * function sum(int $a, int $b): int;
58 ****************************************************************************
60 * If, for whatever reason, the standard declaration doesn't work,
61 * you may declare the function directly as:
62 * ReturnType localSymbolName(parameterList...)
63 * For example:
64 * int64_t my_sum_function(int64_t a, int64_t b) {
65 * return a + b;
66 * }
68 * In which case you will need to use a different macro in moduleLoad()
69 * virtual moduleLoad(const IniSetting::Map& ini, Hdf config) {
70 * HHVM_NAME_FE(sum, my_sum_function)
71 * }
72 * Or an explicit call to registerNativeFunc()
73 * static const StaticString s_sum("sum");
74 * virtual moduleLoad(const IniSetting::Map& ini, Hdf config) {
75 * Native::registerNativeFunc(s_sum, (void*)my_sum_function);
76 * }
78 ****************************************************************************
80 * The macros HHVM_FALIAS, HHVM_MALIAS, and HHVM_STATIC_MALIAS allow
81 * giving different names to the C++ implementation and the exported
82 * C++ function. This ca be useful for creating multiple names for one
83 * function or for registering functions that live in a namespace.
86 #define HHVM_FN(fn) f_ ## fn
87 #define HHVM_FUNCTION(fn, ...) \
88 HHVM_FN(fn)(__VA_ARGS__)
89 #define HHVM_NAMED_FE_STR(fn, fimpl, functable) \
90 do { \
91 String name{makeStaticString(fn)}; \
92 registerExtensionFunction(name); \
93 Native::registerNativeFunc(functable, name, fimpl); \
94 } while(0)
95 #define HHVM_NAMED_FE(fn, fimpl)\
96 HHVM_NAMED_FE_STR(#fn, fimpl, nativeFuncs())
97 #define HHVM_FE(fn) \
98 HHVM_NAMED_FE_STR(#fn, HHVM_FN(fn), nativeFuncs())
99 #define HHVM_FALIAS(fn, falias)\
100 HHVM_NAMED_FE_STR(#fn, HHVM_FN(falias), nativeFuncs())
102 /* Macros related to declaring/registering internal implementations
103 * of <<__Native>> class instance methods.
105 * See the definition of function macros above for general explanation.
106 * These macros only differ in the following ways:
107 * - They accept a classname in addition to the function name
108 * - The registered name of the function is "ClassName->FunctionName"
109 * - Prototypes include a prepended ObjectData* const parameter (named this_)
111 #define HHVM_MN(cn,fn) c_ ## cn ## _ni_ ## fn
112 #define HHVM_METHOD(cn, fn, ...) \
113 HHVM_MN(cn,fn)(ObjectData* const this_, ##__VA_ARGS__)
114 #define HHVM_NAMED_ME(cn,fn,mimpl) \
115 Native::registerNativeFunc(nativeFuncs(), #cn "->" #fn, mimpl)
116 #define HHVM_ME(cn,fn) HHVM_NAMED_ME(cn,fn, HHVM_MN(cn,fn))
117 #define HHVM_MALIAS(cn,fn,calias,falias) \
118 HHVM_NAMED_ME(cn,fn,HHVM_MN(calias,falias))
120 /* special case when we're registering info for a method defined in
121 * s_systemNativeFuncs, instead of the current Extension
123 #define HHVM_SYS_FE(fn)\
124 HHVM_NAMED_FE_STR(#fn, HHVM_FN(fn), Native::s_systemNativeFuncs)
125 #define HHVM_NAMED_SYS_ME(cn,fn,mimpl) Native::registerNativeFunc(\
126 Native::s_systemNativeFuncs, #cn "->" #fn, mimpl)
127 #define HHVM_SYS_ME(cn,fn) HHVM_NAMED_SYS_ME(cn,fn, HHVM_MN(cn,fn))
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::registerNativeFunc(nativeFuncs(), #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
199 // To paraphrase you-know-who, "32 args should be enough for anybody"
201 // Note: If changing this number, update native-func-caller.h
202 // using make_native-func-caller.php
203 const int kMaxBuiltinArgs = 32;
205 inline int maxFCallBuiltinArgs() {
206 return kMaxBuiltinArgs;
209 enum Attr {
210 AttrNone = 0,
212 // Methods whose implementation is generated by HackC.
213 AttrOpCodeImpl = (1u << 0),
217 * Prepare function call arguments to match their expected
218 * types on a native function/method call.
220 * Uses typehints in Func and tvCast*InPlace
222 void coerceFCallArgsFromLocals(const ActRec* fp,
223 int32_t numArgs,
224 const Func* func);
226 #define NATIVE_TYPES \
227 /* kind arg type return type */ \
228 X(Int32, int32_t, int32_t) \
229 X(Int64, int64_t, int64_t) \
230 X(Double, double, double) \
231 X(Bool, bool, bool) \
232 X(Object, const Object&, Object) \
233 X(String, const String&, String) \
234 X(Array, const Array&, Array) \
235 X(Resource, const Resource&, Resource) \
236 X(Func, Func*, Func*) \
237 X(Class, const Class*, const Class*) \
238 X(ClsMeth, ClsMethDataRef, ClsMethDataRef) \
239 X(Mixed, const Variant&, Variant) \
240 X(ObjectArg, ObjectArg, ObjectArg) \
241 X(StringArg, StringArg, StringArg) \
242 X(ArrayArg, ArrayArg, ArrayArg) \
243 X(ResourceArg,ResourceArg, ResourceArg) \
244 X(MixedTV, TypedValue, TypedValue) \
245 X(This, ObjectData*, ObjectData*) \
246 X(Void, void, void) \
247 X(IntIO, int64_t&, int64_t&) \
248 X(DoubleIO, double&, double&) \
249 X(BoolIO, bool&, bool&) \
250 X(ObjectIO, Object&, Object&) \
251 X(StringIO, String&, String&) \
252 X(ArrayIO, Array&, Array&) \
253 X(ResourceIO, Resource&, Resource&) \
254 X(FuncIO, Func*&, Func*&) \
255 X(ClassIO, Class*&, Class*&) \
256 X(ClsMethIO, ClsMethDataRef&, ClsMethDataRef&)\
257 X(MixedIO, Variant&, Variant&) \
258 /**/
260 template <class T>
261 struct NativeArg {
263 * Delete move assignment operator to make this non-copyable.
265 NativeArg& operator=(NativeArg&&) = delete;
266 T* operator->() { return m_px; }
267 T* get() { return m_px; }
268 bool operator!() const { return m_px == nullptr; }
269 bool isNull() const { return m_px == nullptr; }
270 private:
272 * To be able to pass the values of this class as function parameters
273 * by value, define default copy constructor (See Itanium C++ ABI p3.1.1).
274 * Make it private to satisfy the non-copyable requirement.
276 NativeArg(const NativeArg&) = default;
277 T* m_px;
281 using ObjectArg = Native::NativeArg<ObjectData>;
282 using StringArg = Native::NativeArg<StringData>;
283 using ArrayArg = Native::NativeArg<ArrayData>;
284 using ResourceArg = Native::NativeArg<ResourceData>;
286 namespace Native {
288 struct NativeSig {
289 enum class Type : uint8_t {
290 #define X(name, ...) name,
291 NATIVE_TYPES
292 #undef X
295 NativeSig() : ret(Type::Void) {}
297 NativeSig(Type ret, const std::vector<Type>& args)
298 : ret(ret), args(args)
301 NativeSig(Type ret, std::vector<Type>&& args)
302 : ret(ret), args(std::move(args))
305 NativeSig(NativeSig&&) = default;
306 NativeSig(const NativeSig&) = default;
308 NativeSig& operator=(const NativeSig&) = default;
309 NativeSig& operator=(NativeSig&&) = default;
311 template<class Ret>
312 explicit NativeSig(Ret (*ptr)());
314 template<class Ret, class... Args>
315 explicit NativeSig(Ret (*ptr)(Args...));
317 bool operator==(const NativeSig& other) const {
318 return ret == other.ret && args == other.args;
321 std::string toString(const char* classname, const char* fname) const;
323 Type ret;
324 std::vector<Type> args;
327 namespace detail {
329 template<class T> struct native_arg_type {};
330 template<class T> struct native_ret_type {};
331 template<class T> struct known_native_arg : std::false_type {};
333 #define X(name, argTy, retTy) \
334 template<> struct native_ret_type<retTy> \
335 : std::integral_constant<NativeSig::Type,NativeSig::Type::name> \
336 {}; \
337 template<> struct native_arg_type<argTy> \
338 : std::integral_constant<NativeSig::Type,NativeSig::Type::name> \
339 {}; \
340 template<> struct known_native_arg<argTy> : std::true_type {};
342 NATIVE_TYPES
344 #undef X
346 template<class... Args> struct all_known_arg_type {};
347 template<class A> struct all_known_arg_type<A> : known_native_arg<A> {};
349 template<class A, class... Rest>
350 struct all_known_arg_type<A,Rest...>
351 : std::integral_constant<
352 bool,
353 known_native_arg<A>::value && all_known_arg_type<Rest...>::value
357 template<class T> struct understandable_sig : std::false_type {};
358 template<class R> struct understandable_sig<R (*)()> : std::true_type {};
359 template<class R, class... Args>
360 struct understandable_sig<R (*)(Args...)>
361 : all_known_arg_type<Args...>
364 template<class... Args>
365 std::vector<NativeSig::Type> build_args() {
366 return {
367 native_arg_type<Args>::value...
373 template <class Ret>
374 NativeSig::NativeSig(Ret (*/*ptr*/)())
375 : ret(detail::native_ret_type<Ret>::value) {}
377 template <class Ret, class... Args>
378 NativeSig::NativeSig(Ret (*/*ptr*/)(Args...))
379 : ret(detail::native_ret_type<Ret>::value),
380 args(detail::build_args<Args...>()) {}
382 #undef NATIVE_TYPES
384 // NativeFunctionInfo carries around a NativeSig describing the real signature,
385 // and a type-erased NativeFunction ptr.
386 struct NativeFunctionInfo {
387 NativeFunctionInfo() : ptr(nullptr) {}
389 // generate the signature using template magic
390 template<typename Func>
391 explicit NativeFunctionInfo(Func f)
392 : sig(f)
393 , ptr(reinterpret_cast<NativeFunction>(f))
396 // trust the given signature
397 template<typename Func>
398 NativeFunctionInfo(NativeSig sig, Func f)
399 : sig(sig)
400 , ptr(reinterpret_cast<NativeFunction>(f))
403 explicit operator bool() const { return ptr != nullptr; }
405 bool operator==(const NativeFunctionInfo& other) const {
406 return ptr == other.ptr && sig == other.sig;
409 NativeSig sig;
410 NativeFunction ptr;
414 * Known output types for inout parameters on builtins and optional default
415 * values to be passed to builtins which use inout paramaters purely as out
416 * values, ignoring their inputs.
418 MaybeDataType builtinOutType(const TypeConstraint&, const UserAttributeMap&);
419 folly::Optional<TypedValue> builtinInValue(const Func* builtin, uint32_t i);
421 /////////////////////////////////////////////////////////////////////////////
424 * Returns a specialization of either functionWrapper or methodWrapper
426 * functionWrapper() Unpacks args and coerces types according
427 * to Func typehints. Calls C++ function in the form:
428 * ret f_foo(type arg1, type arg2, ...)
429 * Marshalls return into TypedValue.
431 * methodWrapper() behaves the same as functionWrapper(),
432 * but also prepends either an ObjectData* (instance) or Class* (static)
433 * argument to the signature. i.e.:
434 * ret c_class_ni_method(ObjectData* this_, type arg1, type arg2, ...)
435 * ret c_class_ns_method(Class* self_, type arg1, type arg2, ...)
437 void getFunctionPointers(const NativeFunctionInfo& info,
438 int nativeAttrs,
439 ArFunction& bif,
440 NativeFunction& nif);
443 * Fallback method bound to declared methods with no matching
444 * internal implementation.
446 [[noreturn]] TypedValue* unimplementedWrapper(ActRec* ar);
448 /////////////////////////////////////////////////////////////////////////////
451 * registerNativeFunc() and getNativeFunction() use a provided
452 * FuncTable that is a case insensitive map of "name" to function pointer.
454 * Extensions should generally add items to this map using the HHVM_FE/ME
455 * macros above. The function name (key) must be a static string.
458 struct FuncTable;
459 void registerNativeFunc(FuncTable&, const StringData*,
460 const NativeFunctionInfo&);
462 // Helper accepting a C-string name
463 template <class Fun> typename
464 std::enable_if<!std::is_member_function_pointer<Fun>::value, void>::type
465 registerNativeFunc(FuncTable& nativeFuncs, const char* 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 registerNativeFunc(nativeFuncs, makeStaticString(name),
476 NativeFunctionInfo(func));
479 // Helper accepting a possibly nonstatic HPHP::String name
480 template <class Fun> typename
481 std::enable_if<!std::is_member_function_pointer<Fun>::value, void>::type
482 registerNativeFunc(FuncTable& nativeFuncs, const String& name, Fun func) {
483 static_assert(
484 std::is_pointer<Fun>::value &&
485 std::is_function<typename std::remove_pointer<Fun>::type>::value,
486 "You can only register pointers to functions."
488 static_assert(
489 detail::understandable_sig<Fun>::value,
490 "Arguments on builtin function were not understood types"
492 registerNativeFunc(nativeFuncs, makeStaticString(name),
493 NativeFunctionInfo(func));
496 // Specializations of registerNativeFunc for taking pointers to member
497 // functions and making them look like HNI wrapper funcs.
499 // This allows invoking object method calls directly, but ONLY for specialized
500 // subclasses of ObjectData.
502 // This API is limited to: Closure, Asio, and Collections. Do not use it if
503 // you are not implementing one of these
504 template<class Ret, class Cls> typename
505 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
506 registerNativeFunc(FuncTable& nativeFuncs, const char* name,
507 Ret (Cls::*func)()) {
508 registerNativeFunc(nativeFuncs, name,
509 (Ret (*)(ObjectData*))getMethodPtr(func));
512 template<class Ret, class Cls, class... Args> typename
513 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
514 registerNativeFunc(FuncTable& nativeFuncs, const char* name,
515 Ret (Cls::*func)(Args...)) {
516 registerNativeFunc(
517 nativeFuncs, name, (Ret (*)(ObjectData*, Args...))getMethodPtr(func)
521 template<class Ret, class Cls> typename
522 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
523 registerNativeFunc(FuncTable& nativeFuncs, const char* name,
524 Ret (Cls::*func)() const) {
525 registerNativeFunc(nativeFuncs, name,
526 (Ret (*)(ObjectData*))getMethodPtr(func));
529 template<class Ret, class Cls, class... Args> typename
530 std::enable_if<std::is_base_of<ObjectData, Cls>::value, void>::type
531 registerNativeFunc(FuncTable& nativeFuncs, const char* name,
532 Ret (Cls::*func)(Args...) const) {
533 registerNativeFunc(
534 nativeFuncs, name, (Ret (*)(ObjectData*, Args...))getMethodPtr(func)
538 /////////////////////////////////////////////////////////////////////////////
540 const char* checkTypeFunc(const NativeSig& sig,
541 const TypeConstraint& retType,
542 const FuncEmitter* func);
544 // NativeFunctionInfo for native funcs and methods defined under
545 // system/php, separate from normal extensions.
546 extern FuncTable s_systemNativeFuncs;
548 // A permanently empty table, used in contexts were no native bindings
549 // are possible (most ordinary code).
550 extern const FuncTable s_noNativeFuncs;
552 String fullName(const StringData* fname, const StringData* cname,
553 bool isStatic);
555 NativeFunctionInfo getNativeFunction(const FuncTable& nativeFuncs,
556 const StringData* fname,
557 const StringData* cname = nullptr,
558 bool isStatic = false);
560 NativeFunctionInfo getNativeFunction(const FuncTable& nativeFuncs,
561 const char* fname,
562 const char* cname = nullptr,
563 bool isStatic = false);
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, TypedValue cns,
573 bool dynamic = false) {
574 assertx(tvIsPlausible(cns) && cns.m_type != KindOfUninit);
575 auto& dst = s_constant_map[cnsName];
576 *static_cast<TypedValue*>(&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 = Variant (*)(const StringData*);
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 TypedValue cns) {
617 assertx(tvIsPlausible(cns));
618 auto &cls = s_class_constant_map[clsName];
619 assertx(cls.find(cnsName) == cls.end());
620 *static_cast<TypedValue*>(&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