Support "num args" extra parameter to HNI builtins
[hiphop-php.git] / hphp / runtime / vm / native.h
blob294645d5e49b51f3d91e642d556cf4de918d2f74
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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"
22 #include "hphp/runtime/vm/func.h"
24 #include <type_traits>
26 namespace HPHP {
27 struct ActRec;
28 struct Class;
29 struct FuncEmitter;
30 class Object;
33 /* Macros related to declaring/registering internal implementations
34 * of <<__Native>> global functions.
36 * Declare a function in ext_foo.h using:
37 * ReturnType HHVM_FUNCTION(functionName, parameterList...)
38 * For example:
39 * int64_t HHVM_FUNCTION(sum, int64_t a, int64_t b) {
40 * return a + b;
41 * }
43 * Then register it from your Extension's moduleLoad() hook:
44 * void moduleLoad(const IniSetting::Map& ini, Hdf config) override {
45 * HHVM_FE(sum);
46 * }
48 * To finish exposing it to PHP, add an entry to Systemlib
49 * using matching hack typehints:
50 * <?php
51 * <<__Native>>
52 * function sum(int $a, int $b): int;
54 ****************************************************************************
56 * For functions with variadic args or other "special" handling,
57 * declare the prototype as a BuiltinFuncPtr:
58 * TypedValue* HHVM_FN(sum)(ActRec* ar) { ... }
59 * And declare it in Systemlib with the "ActRec" subattribute
60 * <?php
61 * <<__Native("ActRec")>>
62 * function sum(int $a, int $b): int;
63 * Registering the function in moduleLoad() remains the same.
65 ****************************************************************************
67 * If, for whatever reason, the standard declaration doesn't work,
68 * you may declare the function directly as:
69 * ReturnType localSymbolName(parameterList...)
70 * For example:
71 * int64_t my_sum_function(int64_t a, int64_t b) {
72 * return a + b;
73 * }
75 * In which case you will need to use a different macro in moduleLoad()
76 * virtual moduleLoad(const IniSetting::Map& ini, Hdf config) {
77 * HHVM_NAME_FE(sum, my_sum_function)
78 * }
79 * Or an explicit call to registerBuildinFunction()
80 * static const StaticString s_sum("sum");
81 * virtual moduleLoad(const IniSetting::Map& ini, Hdf config) {
82 * Native::registerBuiltinFunction(s_sum, (void*)my_sum_function);
83 * }
85 ****************************************************************************
87 * The macros HHVM_FALIAS, HHVM_MALIAS, and HHVM_STATIC_MALIAS allow
88 * giving different names to the C++ implementation and the exported
89 * C++ function. This ca be useful for creating multiple names for one
90 * function or for registering functions that live in a namespace.
93 #define HHVM_FN(fn) f_ ## fn
94 #define HHVM_FUNCTION(fn, ...) \
95 HHVM_FN(fn)(__VA_ARGS__)
96 #define HHVM_NAMED_FE_STR(fn, fimpl) \
97 Native::registerBuiltinFunction(fn, fimpl)
98 #define HHVM_NAMED_FE(fn, fimpl) HHVM_NAMED_FE_STR(#fn, fimpl)
99 #define HHVM_FE(fn) HHVM_NAMED_FE_STR(#fn, HHVM_FN(fn))
100 #define HHVM_FALIAS(fn, falias) HHVM_NAMED_FE_STR(#fn, HHVM_FN(falias))
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::registerBuiltinFunction(#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 /* Macros related to declaring/registering internal implementations
121 * of <<__Native>> class static methods.
123 * See the definition of function macros above for general explanation.
124 * These macros only differ in the following ways:
125 * - They accept a classname in addition to the function name
126 * - The registered name of the function is "ClassName::FunctionName"
127 * - Prototypes include a prepended const Class* parameter (named self_)
129 #define HHVM_STATIC_MN(cn,fn) c_ ## cn ## _ns_ ## fn
130 #define HHVM_STATIC_METHOD(cn, fn, ...) \
131 HHVM_STATIC_MN(cn,fn)(const Class *self_, ##__VA_ARGS__)
132 #define HHVM_NAMED_STATIC_ME(cn,fn,mimpl) \
133 Native::registerBuiltinFunction(#cn "::" #fn, mimpl)
134 #define HHVM_STATIC_ME(cn,fn) HHVM_NAMED_STATIC_ME(cn,fn,HHVM_STATIC_MN(cn,fn))
135 #define HHVM_STATIC_MALIAS(cn,fn,calias,falias) \
136 HHVM_NAMED_STATIC_ME(cn,fn,HHVM_STATIC_MN(calias,falias))
138 namespace HPHP { namespace Native {
139 //////////////////////////////////////////////////////////////////////////////
141 // Maximum number of args for a native function call
142 // Beyond this number, a function/method will have to
143 // take a raw ActRec (using <<__Native("ActRec")>>) and
144 // deal with the args using getArg<KindOf*>(ar, argNum)
146 // To paraphrase you-know-who, "32 args should be enough for anybody"
148 // Note: If changing this number, update native-func-caller.h
149 // using make_native-func-caller.php
150 const int kMaxBuiltinArgs = 32;
152 // t#3982283 - Our ARM code gen doesn't support stack args yet.
153 // In fact, it only supports six of the eight register args.
154 // Put a hard limit of five to account for the return register for now.
155 constexpr int kMaxFCallBuiltinArgsARM = 5;
157 inline int maxFCallBuiltinArgs() {
158 #ifdef __AARCH64EL__
159 return kMaxFCallBuiltinArgsARM;
160 #else
161 if (UNLIKELY(RuntimeOption::EvalSimulateARM)) {
162 return kMaxFCallBuiltinArgsARM;
164 return kMaxBuiltinArgs;
165 #endif
168 // t#3982283 - Our ARM code gen doesn't support FP args/returns yet.
169 inline bool allowFCallBuiltinDoubles() {
170 #ifdef __AARCH64EL__
171 return false;
172 #else
173 if (UNLIKELY(RuntimeOption::EvalSimulateARM)) {
174 return false;
176 return true;
177 #endif
180 enum Attr {
181 AttrNone = 0,
182 AttrActRec = 1 << 0,
183 AttrZendCompat = 1 << 1,
187 * Prepare function call arguments to match their expected
188 * types on a native function/method call.
190 * Uses typehints in Func and tvCast*InPlace
192 bool coerceFCallArgs(TypedValue* args,
193 int32_t numArgs, int32_t numNonDefault,
194 const Func* func);
197 * Dispatches a call to the native function bound to <func>
198 * If <ctx> is not nullptr, it is prepended to <args> when
199 * calling.
201 template<bool usesDoubles, bool variadic>
202 void callFunc(const Func* func, void* ctx,
203 TypedValue* args, int32_t numNonDefault,
204 TypedValue& ret);
207 * Extract the name used to invoke the function from the ActRec where name
208 * maybe be stored in invName, or may include the classname (e.g. Class::func)
210 const StringData* getInvokeName(ActRec* ar);
213 * Returns a specialization of either functionWrapper or methodWrapper
215 * functionWrapper() Unpacks args and coerces types according
216 * to Func typehints. Calls C++ function in the form:
217 * ret f_foo(type arg1, type arg2, ...)
218 * Marshalls return into TypedValue.
220 * methodWrapper() behaves the same as functionWrapper(),
221 * but also prepends either an ObjectData* (instance) or Class* (static)
222 * argument to the signature. i.e.:
223 * ret c_class_ni_method(ObjectData* this_, type arg1, type arg2, ...)
224 * ret c_class_ns_method(Class* self_, type arg1, type arg2, ...)
226 BuiltinFunction getWrapper(bool method, bool usesDoubles, bool variadic);
229 * Fallback method bound to declared methods with no matching
230 * internal implementation.
232 TypedValue* unimplementedWrapper(ActRec* ar);
234 #define NATIVE_TYPES \
235 /* kind arg type return type */ \
236 X(Int32, int32_t, int32_t) \
237 X(Int64, int64_t, int64_t) \
238 X(Double, double, double) \
239 X(Bool, bool, bool) \
240 X(Object, const Object&, Object) \
241 X(String, const String&, String) \
242 X(Array, const Array&, Array) \
243 X(Resource, const Resource&, Resource) \
244 X(Mixed, const Variant&, Variant) \
245 X(ARReturn, TypedValue*, TypedValue*) \
246 X(MixedRef, const VRefParamValue&,VRefParamValue) \
247 X(VarArgs, ActRec*, ActRec*) \
248 X(This, ObjectData*, ObjectData*) \
249 X(Class, const Class*, const Class*) \
250 X(Void, void, void) \
251 X(Zend, ZendFuncType, ZendFuncType) \
252 /**/
254 enum class ZendFuncType {};
256 struct NativeSig {
257 enum class Type : uint8_t {
258 #define X(name, ...) name,
259 NATIVE_TYPES
260 #undef X
263 explicit NativeSig(ZendFuncType) : ret(Type::Zend) {}
264 NativeSig() : ret(Type::Void) {}
266 template<class Ret>
267 explicit NativeSig(Ret (*ptr)());
269 template<class Ret, class... Args>
270 explicit NativeSig(Ret (*ptr)(Args...));
272 std::string toString(const char* classname, const char* fname) const;
274 Type ret;
275 std::vector<Type> args;
278 namespace detail {
280 template<class T> struct native_arg_type {};
281 template<class T> struct native_ret_type {};
282 template<class T> struct known_native_arg : std::false_type {};
284 #define X(name, argTy, retTy) \
285 template<> struct native_ret_type<retTy> \
286 : std::integral_constant<NativeSig::Type,NativeSig::Type::name> \
287 {}; \
288 template<> struct native_arg_type<argTy> \
289 : std::integral_constant<NativeSig::Type,NativeSig::Type::name> \
290 {}; \
291 template<> struct known_native_arg<argTy> : std::true_type {};
293 NATIVE_TYPES
295 #undef X
297 template<class... Args> struct all_known_arg_type {};
298 template<class A> struct all_known_arg_type<A> : known_native_arg<A> {};
300 template<class A, class... Rest>
301 struct all_known_arg_type<A,Rest...>
302 : std::integral_constant<
303 bool,
304 known_native_arg<A>::value && all_known_arg_type<Rest...>::value
308 template<class T> struct understandable_sig : std::false_type {};
309 template<class R> struct understandable_sig<R (*)()> : std::true_type {};
310 template<class R, class... Args>
311 struct understandable_sig<R (*)(Args...)>
312 : all_known_arg_type<Args...>
315 template<class... Args>
316 std::vector<NativeSig::Type> build_args() {
317 return {
318 native_arg_type<Args>::value...
324 template<class Ret>
325 NativeSig::NativeSig(Ret (*ptr)())
326 : ret(detail::native_ret_type<Ret>::value)
329 template<class Ret, class... Args>
330 NativeSig::NativeSig(Ret (*ptr)(Args...))
331 : ret(detail::native_ret_type<Ret>::value)
332 , args(detail::build_args<Args...>())
335 #undef NATIVE_TYPES
337 struct BuiltinFunctionInfo {
338 BuiltinFunctionInfo() : ptr(nullptr) {}
340 template<typename Func>
341 explicit BuiltinFunctionInfo(Func f)
342 : sig(f)
343 , ptr((BuiltinFunction)f)
346 NativeSig sig;
347 BuiltinFunction ptr;
351 * Case insensitive map of "name" to function pointer
353 * Extensions should generally add items to this map using
354 * the HHVM_FE/ME macros above. The function name (key) must
355 * be a static string because this table is shared and outlives
356 * individual requests.
358 typedef hphp_hash_map<const StringData*, BuiltinFunctionInfo,
359 string_data_hash, string_data_isame> BuiltinFunctionMap;
361 extern BuiltinFunctionMap s_builtinFunctions;
363 template <class Fun>
364 inline void registerBuiltinFunction(const char* name, Fun func) {
365 static_assert(
366 std::is_pointer<Fun>::value &&
367 std::is_function<typename std::remove_pointer<Fun>::type>::value,
368 "You can only register pointers to functions."
370 static_assert(
371 detail::understandable_sig<Fun>::value,
372 "Arguments on builtin function were not understood types"
374 s_builtinFunctions[makeStaticString(name)] = BuiltinFunctionInfo(func);
377 template <class Fun>
378 inline void registerBuiltinFunction(const String& name, Fun func) {
379 static_assert(
380 std::is_pointer<Fun>::value &&
381 std::is_function<typename std::remove_pointer<Fun>::type>::value,
382 "You can only register pointers to functions."
384 static_assert(
385 detail::understandable_sig<Fun>::value,
386 "Arguments on builtin function were not understood types"
388 s_builtinFunctions[makeStaticString(name)] = BuiltinFunctionInfo(func);
391 template <class Fun>
392 inline void registerBuiltinZendFunction(const char* name, Fun func) {
393 static_assert(
394 std::is_pointer<Fun>::value &&
395 std::is_function<typename std::remove_pointer<Fun>::type>::value,
396 "You can only register pointers to functions."
398 auto bfi = BuiltinFunctionInfo();
399 bfi.ptr = (BuiltinFunction)func;
400 bfi.sig = NativeSig(ZendFuncType{});
401 s_builtinFunctions[makeStaticString(name)] = bfi;
404 template <class Fun>
405 inline void registerBuiltinZendFunction(const String& name, Fun func) {
406 static_assert(
407 std::is_pointer<Fun>::value &&
408 std::is_function<typename std::remove_pointer<Fun>::type>::value,
409 "You can only register pointers to function."
411 auto bfi = BuiltinFunctionInfo();
412 bfi.ptr = (BuiltinFunction)func;
413 bfi.sig = NativeSig(ZendFuncType{});
414 s_builtinFunctions[makeStaticString(name)] = bfi;
417 const char* checkTypeFunc(const NativeSig& sig,
418 const TypeConstraint& retType,
419 const Func* func);
421 inline BuiltinFunctionInfo GetBuiltinFunction(const StringData* fname,
422 const StringData* cname = nullptr,
423 bool isStatic = false) {
424 auto it = s_builtinFunctions.find((cname == nullptr) ? fname :
425 (String(const_cast<StringData*>(cname)) +
426 (isStatic ? "::" : "->") +
427 String(const_cast<StringData*>(fname))).get());
428 return (it == s_builtinFunctions.end()) ? BuiltinFunctionInfo() : it->second;
431 inline BuiltinFunctionInfo GetBuiltinFunction(const char* fname,
432 const char* cname = nullptr,
433 bool isStatic = false) {
434 return GetBuiltinFunction(makeStaticString(fname),
435 cname ? makeStaticString(cname) : nullptr,
436 isStatic);
439 //////////////////////////////////////////////////////////////////////////////
440 // Global constants
442 typedef std::map<const StringData*,TypedValue> ConstantMap;
443 extern ConstantMap s_constant_map;
445 inline
446 bool registerConstant(const StringData* cnsName, Cell cns) {
447 assert(cellIsPlausible(cns));
448 s_constant_map[cnsName] = cns;
449 return Unit::defCns(cnsName, &cns, true);
452 template<DataType DType>
453 typename std::enable_if<
454 !std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
455 bool>::type
456 registerConstant(const StringData* cnsName,
457 typename DataTypeCPPType<DType>::type val) {
458 return registerConstant(cnsName, make_tv<DType>(val));
461 template<DataType DType>
462 typename std::enable_if<
463 std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
464 bool>::type
465 registerConstant(const StringData* cnsName) {
466 return registerConstant(cnsName, make_tv<DType>());
469 inline
470 const ConstantMap& getConstants() {
471 return s_constant_map;
474 using NativeConstantCallback = const Variant& (*)();
475 bool registerConstant(const StringData*, NativeConstantCallback);
477 //////////////////////////////////////////////////////////////////////////////
478 // Class Constants
480 typedef hphp_hash_map<const StringData*, ConstantMap,
481 string_data_hash, string_data_isame> ClassConstantMapMap;
482 extern ClassConstantMapMap s_class_constant_map;
484 inline
485 bool registerClassConstant(const StringData *clsName,
486 const StringData *cnsName,
487 Cell cns) {
488 assert(cellIsPlausible(cns));
489 auto &cls = s_class_constant_map[clsName];
490 assert(cls.find(cnsName) == cls.end());
491 cls[cnsName] = cns;
492 return true;
495 template<DataType DType>
496 typename std::enable_if<
497 !std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
498 bool>::type
499 registerClassConstant(const StringData* clsName,
500 const StringData* cnsName,
501 typename DataTypeCPPType<DType>::type val) {
502 return registerClassConstant(clsName, cnsName, make_tv<DType>(val));
505 template<DataType DType>
506 typename std::enable_if<
507 std::is_same<typename DataTypeCPPType<DType>::type,void>::value,
508 bool>::type
509 registerClassConstant(const StringData* clsName,
510 const StringData* cnsName) {
511 return registerClassConstant(clsName, cnsName, make_tv<DType>());
514 inline
515 const ConstantMap* getClassConstants(const StringData* clsName) {
516 auto clsit = s_class_constant_map.find(const_cast<StringData*>(clsName));
517 if (clsit == s_class_constant_map.end()) {
518 return nullptr;
520 return &clsit->second;
523 //////////////////////////////////////////////////////////////////////////////
524 }} // namespace HPHP::Native
526 #endif