EvalEmitDVArray: varray
[hiphop-php.git] / hphp / runtime / base / builtin-functions.h
blob22f539ff82d0ccb742cf69c54d6cbc114a8ede7a
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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_BUILTIN_FUNCTIONS_H_
18 #define incl_HPHP_BUILTIN_FUNCTIONS_H_
20 #include "hphp/runtime/base/type-variant.h"
21 #include "hphp/runtime/base/variable-unserializer.h"
22 #include "hphp/runtime/vm/bytecode.h"
23 #include "hphp/util/functional.h"
24 #include "hphp/util/portability.h"
25 #include "hphp/runtime/base/req-root.h"
27 namespace HPHP {
28 ///////////////////////////////////////////////////////////////////////////////
29 extern const StaticString s_self;
30 extern const StaticString s_parent;
31 extern const StaticString s_static;
33 extern const StaticString s_cmpWithCollection;
34 extern const StaticString s_cmpWithVec;
35 extern const StaticString s_cmpWithDict;
36 extern const StaticString s_cmpWithKeyset;
37 extern const StaticString s_cmpWithClsMeth;
38 extern const StaticString s_cmpWithRecord;
40 ///////////////////////////////////////////////////////////////////////////////
41 // operators
43 inline String concat(const String& s1, const String& s2) {
44 return s1 + s2;
47 String concat3(const String& s1, const String& s2, const String& s3);
48 String concat4(const String& s1, const String& s2, const String& s3,
49 const String& s4);
51 ///////////////////////////////////////////////////////////////////////////////
53 [[noreturn]] void NEVER_INLINE throw_missing_this(const Func* f);
54 [[noreturn]] void NEVER_INLINE throw_has_this_need_static(const Func* f);
55 void NEVER_INLINE throw_invalid_property_name(const String& name);
57 [[noreturn]]
58 void NEVER_INLINE throw_call_reified_func_without_generics(const Func* f);
60 [[noreturn]]
61 void throw_exception(const Object& e);
63 ///////////////////////////////////////////////////////////////////////////////
64 // type testing
66 inline bool is_null(const TypedValue* c) {
67 assertx(tvIsPlausible(*c));
68 return tvIsNull(c);
71 inline bool is_bool(const TypedValue* c) {
72 assertx(tvIsPlausible(*c));
73 return tvIsBool(c);
76 inline bool is_int(const TypedValue* c) {
77 assertx(tvIsPlausible(*c));
78 return tvIsInt(c);
81 inline bool is_double(const TypedValue* c) {
82 assertx(tvIsPlausible(*c));
83 return tvIsDouble(c);
86 inline bool is_string(const TypedValue* c) {
87 if (tvIsString(c)) return true;
88 if (tvIsFunc(c)) {
89 if (RuntimeOption::EvalIsStringNotices) {
90 raise_notice("Func used in is_string");
92 return true;
94 if (tvIsClass(c)) {
95 if (RuntimeOption::EvalIsStringNotices) {
96 raise_notice("Class used in is_string");
98 return true;
100 return false;
103 // This function behaves how most callers of raise_array_serialization_notice
104 // should behave: it checks if `tv` *should* have a provenance tag and then
105 // logs a serialization notice of some kind if so.
107 // If we trace through call sites of the bare function, we'll find a number of
108 // places where we're incorrectly losing provenance logs. Clean this up soon.
109 inline void maybe_raise_array_serialization_notice(
110 SerializationSite site, const TypedValue* tv) {
111 assertx(isArrayLikeType(tv->m_type));
112 auto const ad = tv->m_data.parr;
113 if (RuntimeOption::EvalLogArrayProvenance && arrprov::arrayWantsTag(ad)) {
114 raise_array_serialization_notice(site, ad);
118 inline bool is_array(const TypedValue* c, bool logOnHackArrays) {
119 assertx(tvIsPlausible(*c));
121 if (tvIsArray(c)) {
122 maybe_raise_array_serialization_notice(SerializationSite::IsArray, c);
123 return true;
126 if (tvIsClsMeth(c)) {
127 if (!RO::EvalHackArrDVArrs && RO::EvalIsCompatibleClsMethType) {
128 if (RO::EvalIsVecNotices) raise_notice(Strings::CLSMETH_COMPAT_IS_ARR);
129 return true;
131 return false;
134 auto const hacLogging = [&](const char* msg) {
135 if (RO::EvalHackArrCompatIsArrayNotices) raise_hackarr_compat_notice(msg);
137 if (logOnHackArrays /* let's get rid of this condition if we can */) {
138 if (tvIsVec(c)) {
139 hacLogging(Strings::HACKARR_COMPAT_VEC_IS_ARR);
140 maybe_raise_array_serialization_notice(SerializationSite::IsArray, c);
141 } else if (tvIsDict(c)) {
142 hacLogging(Strings::HACKARR_COMPAT_DICT_IS_ARR);
143 maybe_raise_array_serialization_notice(SerializationSite::IsArray, c);
144 } else if (tvIsKeyset(c)) {
145 hacLogging(Strings::HACKARR_COMPAT_KEYSET_IS_ARR);
146 assertx(!arrprov::arrayWantsTag(c->m_data.parr));
149 return false;
152 inline bool is_vec(const TypedValue* c) {
153 assertx(tvIsPlausible(*c));
155 if (tvIsVec(c)) {
156 maybe_raise_array_serialization_notice(SerializationSite::IsVec, c);
157 return true;
160 auto const hacLogging = [&](const char* msg) {
161 if (RO::EvalHackArrCompatIsVecDictNotices) raise_hackarr_compat_notice(msg);
163 if (tvIsClsMeth(c)) {
164 if (RO::EvalHackArrDVArrs && RO::EvalIsCompatibleClsMethType) {
165 if (RO::EvalIsVecNotices) raise_notice(Strings::CLSMETH_COMPAT_IS_VEC);
166 return true;
169 if (!RO::EvalHackArrDVArrs) {
170 hacLogging(Strings::HACKARR_COMPAT_VARR_IS_VEC);
172 return false;
175 if (tvIsArray(c) && c->m_data.parr->isVArray()) {
176 hacLogging(Strings::HACKARR_COMPAT_VARR_IS_VEC);
177 maybe_raise_array_serialization_notice(SerializationSite::IsVec, c);
179 return false;
182 inline bool is_dict(const TypedValue* c) {
183 assertx(tvIsPlausible(*c));
185 if (tvIsDict(c)) {
186 maybe_raise_array_serialization_notice(SerializationSite::IsDict, c);
187 return true;
190 auto const hacLogging = [&](const char* msg) {
191 if (RO::EvalHackArrCompatIsVecDictNotices) raise_hackarr_compat_notice(msg);
193 if (tvIsArray(c) && c->m_data.parr->isDArray()) {
194 hacLogging(Strings::HACKARR_COMPAT_DARR_IS_DICT);
195 maybe_raise_array_serialization_notice(SerializationSite::IsDict, c);
197 return false;
200 inline bool is_keyset(const TypedValue* c) {
201 assertx(tvIsPlausible(*c));
202 return tvIsKeyset(c);
205 inline bool is_varray(const TypedValue* c) {
206 assertx(tvIsPlausible(*c));
208 // Is this line safe? It returns the correct result, but if it logs a notice,
209 // it'll be for is_vec, not is_varray. That may be fine, post-HAM, because
210 // only dynamic calls to is_varray will remain at that point.
211 if (RuntimeOption::EvalHackArrDVArrs) return is_vec(c);
213 if (tvIsVArray(c) || (tvIsArray(c) && c->m_data.parr->isVArray())) {
214 maybe_raise_array_serialization_notice(SerializationSite::IsVArray, c);
215 return true;
218 if (tvIsClsMeth(c) && RO::EvalIsCompatibleClsMethType) {
219 if (RO::EvalIsVecNotices) raise_notice(Strings::CLSMETH_COMPAT_IS_VARR);
220 return true;
223 auto const hacLogging = [&](const char* msg) {
224 if (RO::EvalHackArrCompatIsVecDictNotices) raise_hackarr_compat_notice(msg);
226 if (tvIsVec(c)) {
227 hacLogging(Strings::HACKARR_COMPAT_VEC_IS_VARR);
228 maybe_raise_array_serialization_notice(SerializationSite::IsVArray, c);
230 return false;
233 inline bool is_darray(const TypedValue* c) {
234 assertx(tvIsPlausible(*c));
236 // Is this line safe? It returns the correct result, but if it logs a notice,
237 // it'll be for is_dict, not is_darray. That may be fine, post-HAM, because
238 // only dynamic calls to is_darray will remain at that point.
239 if (RuntimeOption::EvalHackArrDVArrs) return is_dict(c);
241 if (tvIsDArray(c) || (tvIsArray(c) && c->m_data.parr->isDArray())) {
242 maybe_raise_array_serialization_notice(SerializationSite::IsDArray, c);
243 return true;
246 auto const hacLogging = [&](const char* msg) {
247 if (RO::EvalHackArrCompatIsVecDictNotices) raise_hackarr_compat_notice(msg);
249 if (tvIsDict(c)) {
250 hacLogging(Strings::HACKARR_COMPAT_DICT_IS_DARR);
251 maybe_raise_array_serialization_notice(SerializationSite::IsDArray, c);
253 return false;
256 inline bool is_object(const TypedValue* c) {
257 assertx(tvIsPlausible(*c));
258 return tvIsObject(c) &&
259 c->m_data.pobj->getVMClass() != SystemLib::s___PHP_Incomplete_ClassClass;
262 inline bool is_clsmeth(const TypedValue* c) {
263 assertx(tvIsPlausible(*c));
264 return tvIsClsMeth(c);
267 inline bool is_fun(const TypedValue* c) {
268 assertx(tvIsPlausible(*c));
269 return tvIsFunc(c);
272 inline bool is_empty_string(const TypedValue* c) {
273 return tvIsString(c) && c->m_data.pstr->empty();
276 ///////////////////////////////////////////////////////////////////////////////
277 // misc functions
280 * Semantics of is_callable defined here:
281 * http://php.net/manual/en/function.is-callable.php
283 bool is_callable(const Variant& v, bool syntax_only, Variant* name);
285 * Equivalent to is_callable(v, false, nullptr)
287 bool is_callable(const Variant& v);
288 bool array_is_valid_callback(const Array& arr);
290 enum class DecodeFlags { Warn, NoWarn, LookupOnly };
291 const HPHP::Func*
292 vm_decode_function(const_variant_ref function,
293 ActRec* ar,
294 ObjectData*& this_,
295 HPHP::Class*& cls,
296 StringData*& invName,
297 bool& dynamic,
298 DecodeFlags flags = DecodeFlags::Warn,
299 bool genericsAlreadyGiven = false);
301 inline void
302 vm_decode_function(const_variant_ref function,
303 CallCtx& ctx,
304 DecodeFlags flags = DecodeFlags::Warn,
305 bool genericsAlreadyGiven = false) {
306 ctx.func = vm_decode_function(function, nullptr, ctx.this_, ctx.cls,
307 ctx.invName, ctx.dynamic, flags,
308 genericsAlreadyGiven);
311 Variant vm_call_user_func(const_variant_ref function, const Variant& params,
312 bool checkRef = false,
313 bool allowDynCallNoPointer = false);
314 template<typename T>
315 Variant vm_call_user_func(T&& t, const Variant& params, bool checkRef = false,
316 bool allowDynCallNoPointer = false) {
317 const Variant function{std::forward<T>(t)};
318 return vm_call_user_func(
319 const_variant_ref{function}, params, checkRef, allowDynCallNoPointer
323 // Invoke an arbitrary user-defined function.
324 // If you're considering calling this function for some new code, don't.
325 Variant invoke(const String& function, const Variant& params,
326 bool allowDynCallNoPointer = false);
328 Variant invoke_static_method(const String& s, const String& method,
329 const Variant& params, bool fatal = true);
331 Variant o_invoke_failed(const char *cls, const char *meth,
332 bool fatal = true);
334 bool is_constructor_name(const char* func);
335 [[noreturn]] void throw_instance_method_fatal(const char *name);
337 [[noreturn]] void throw_invalid_collection_parameter();
338 [[noreturn]] void throw_invalid_operation_exception(StringData*);
339 [[noreturn]] void throw_division_by_zero_exception();
340 [[noreturn]] void throw_iterator_not_valid();
341 [[noreturn]] void throw_collection_property_exception();
342 [[noreturn]] void throw_collection_compare_exception();
343 [[noreturn]] void throw_vec_compare_exception();
344 [[noreturn]] void throw_dict_compare_exception();
345 [[noreturn]] void throw_keyset_compare_exception();
346 [[noreturn]] void throw_clsmeth_compare_exception();
347 [[noreturn]] void throw_record_compare_exception();
348 [[noreturn]] void throw_rec_non_rec_compare_exception();
349 [[noreturn]] void throw_param_is_not_container();
350 [[noreturn]] void throw_invalid_inout_base();
351 [[noreturn]] void throw_cannot_modify_immutable_object(const char* className);
352 [[noreturn]] void throw_cannot_modify_const_object(const char* className);
353 [[noreturn]] void throw_object_forbids_dynamic_props(const char* className);
354 [[noreturn]] void throw_cannot_modify_const_prop(const char* className,
355 const char* propName);
356 [[noreturn]] void throw_cannot_modify_static_const_prop(const char* className,
357 const char* propName);
358 [[noreturn]] void throw_late_init_prop(const Class* cls,
359 const StringData* propName,
360 bool isSProp);
361 [[noreturn]] void throw_parameter_wrong_type(TypedValue tv,
362 const Func* callee,
363 unsigned int arg_num,
364 DataType type);
366 void check_collection_cast_to_array();
368 Object create_object_only(const String& s);
369 Object create_object(const String& s, const Array &params, bool init = true);
370 Object init_object(const String& s, const Array &params, ObjectData* o);
372 [[noreturn]] void throw_object(const Object& e);
373 #if ((__GNUC__ != 4) || (__GNUC_MINOR__ != 8))
374 // gcc-4.8 has a bug that causes incorrect code if we
375 // define this function.
376 [[noreturn]] void throw_object(Object&& e);
377 #endif
379 [[noreturn]] inline
380 void throw_object(const String& s, const Array& params, bool init = true) {
381 throw_object(create_object(s, params, init));
384 void throw_missing_arguments_nr(const char *fn, int expected, int got)
386 __attribute__((__cold__));
389 * Handler for exceptions thrown from user functions that we don't
390 * allow exception propagation from. E.g., object destructors or
391 * certain callback hooks (user profiler). Implemented in
392 * program-functions.cpp.
394 void handle_destructor_exception(const char* situation = "Destructor");
397 * Deprecated wrappers for raising certain types of warnings.
399 * Don't use in new code.
401 void raise_bad_type_warning(ATTRIBUTE_PRINTF_STRING const char *fmt, ...)
402 ATTRIBUTE_PRINTF(1,2);
403 void raise_expected_array_warning(const char* fn = nullptr);
404 void raise_expected_array_or_collection_warning(const char* fn = nullptr);
405 void raise_invalid_argument_warning(ATTRIBUTE_PRINTF_STRING const char *fmt, ...)
406 ATTRIBUTE_PRINTF(1,2) __attribute__((__cold__));
409 * Unsetting ClassName::StaticProperty.
411 Variant throw_fatal_unset_static_property(const char *s, const char *prop);
413 // unserializable default value arguments such as TimeStamp::Current()
414 // are serialized as "\x01"
415 char const kUnserializableString[] = "\x01";
418 * Serialize/unserialize a variant into/from a string. We need these
419 * two functions in runtime/base, as there are functions in
420 * runtime/base that depend on these two functions.
422 String f_serialize(const Variant& value);
423 String serialize_keep_dvarrays(const Variant& value);
424 Variant unserialize_ex(const String& str,
425 VariableUnserializer::Type type,
426 const Array& options = null_array);
427 Variant unserialize_ex(const char* str, int len,
428 VariableUnserializer::Type type,
429 const Array& options = null_array);
431 inline Variant unserialize_from_buffer(const char* str, int len,
432 VariableUnserializer::Type type,
433 const Array& options = null_array) {
434 return unserialize_ex(str, len, type, options);
437 inline Variant unserialize_from_string(const String& str,
438 VariableUnserializer::Type type,
439 const Array& options = null_array) {
440 return unserialize_from_buffer(str.data(), str.size(), type, options);
443 String resolve_include(const String& file, const char* currentDir,
444 bool (*tryFile)(const String& file, void* ctx),
445 void* ctx);
446 Variant include_impl_invoke(const String& file, bool once = false,
447 const char *currentDir = "",
448 bool callByHPHPInvoke = false);
449 Variant require(const String& file, bool once, const char* currentDir,
450 bool raiseNotice);
452 bool function_exists(const String& function_name);
454 ///////////////////////////////////////////////////////////////////////////////
457 #endif