port emit_iter
[hiphop-php.git] / hphp / system / systemlib.cpp
blob5b89fbbac5b2fac748336e78abe3076a3e2c4acb
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 #include "hphp/system/systemlib.h"
18 #include "hphp/runtime/base/array-init.h"
19 #include "hphp/runtime/base/builtin-functions.h"
20 #include "hphp/runtime/base/execution-context.h"
21 #include "hphp/runtime/base/init-fini-node.h"
22 #include "hphp/runtime/base/object-data.h"
23 #include "hphp/runtime/base/type-object.h"
24 #include "hphp/runtime/base/type-string.h"
25 #include "hphp/runtime/base/type-variant.h"
26 #include "hphp/runtime/base/types.h"
27 #include "hphp/runtime/vm/class.h"
28 #include "hphp/runtime/vm/unit.h"
29 #include "hphp/runtime/vm/rx.h"
31 #include <vector>
33 namespace HPHP { namespace SystemLib {
34 /////////////////////////////////////////////////////////////////////////////
36 namespace {
38 const StaticString s_message("message");
39 const StaticString s_code("code");
40 const Slot s_messageIdx{0};
41 const Slot s_codeIdx{2};
43 DEBUG_ONLY bool throwable_has_expected_props() {
44 auto const erCls = s_ErrorClass;
45 auto const exCls = s_ExceptionClass;
46 if (erCls->lookupDeclProp(s_message.get()) != s_messageIdx ||
47 exCls->lookupDeclProp(s_message.get()) != s_messageIdx ||
48 erCls->lookupDeclProp(s_code.get()) != s_codeIdx ||
49 exCls->lookupDeclProp(s_code.get()) != s_codeIdx) {
50 return false;
52 // Check that we have the expected type-hints on these props so we don't need
53 // to verify anything.
54 return
55 erCls->declPropTypeConstraint(s_messageIdx).isString() &&
56 exCls->declPropTypeConstraint(s_messageIdx).isString() &&
57 erCls->declPropTypeConstraint(s_codeIdx).isInt() &&
58 exCls->declPropTypeConstraint(s_codeIdx).isInt();
61 ALWAYS_INLINE
62 Object createAndConstruct(Class* cls, const Array& args) {
63 Object inst{cls};
64 tvDecRefGen(g_context->invokeFunc(cls->getCtor(), args, inst.get()));
65 return inst;
68 /**
69 * Fast path for Errors and Exceptions that do not override the default
70 * constructor or message property initializer. Does not reenter VM.
72 ALWAYS_INLINE
73 Object createAndConstructThrowable(Class* cls, const Variant& message) {
74 assertx(throwable_has_expected_props());
75 assertx(cls->getCtor() == s_ErrorClass->getCtor() ||
76 cls->getCtor() == s_ExceptionClass->getCtor());
78 Object inst{cls};
79 if (debug) {
80 DEBUG_ONLY auto const code_prop = inst->propRvalAtOffset(s_codeIdx);
81 assertx(isIntType(code_prop.type()));
82 assertx(code_prop.val().num == 0);
84 auto const message_prop = inst->propLvalAtOffset(s_messageIdx);
85 assertx(isStringType(message_prop.type()));
86 assertx(message_prop.val().pstr == staticEmptyString());
87 tvDup(*message.asTypedValue(), message_prop);
88 return inst;
93 bool s_inited = false;
94 bool s_anyNonPersistentBuiltins = false;
95 std::string s_source;
96 Unit* s_unit = nullptr;
97 Unit* s_hhas_unit = nullptr;
98 Func* s_nullFunc = nullptr;
99 Func* s_singleArgNullFunc = nullptr;
100 Func* s_nullCtor = nullptr;
102 /////////////////////////////////////////////////////////////////////////////
104 #define DEFINE_SYSTEMLIB_CLASS(cls) \
105 Class* s_ ## cls ## Class = nullptr;
106 SYSTEMLIB_CLASSES(DEFINE_SYSTEMLIB_CLASS)
107 #undef DEFINE_SYSTEMLIB_CLASS
109 #define DEFINE_SYSTEMLIB_HH_CLASS(cls) \
110 Class* s_HH_ ## cls ## Class = nullptr;
111 SYSTEMLIB_HH_CLASSES(DEFINE_SYSTEMLIB_HH_CLASS)
112 #undef DEFINE_SYSTEMLIB_HH_CLASS
114 Class* s_ThrowableClass;
115 Class* s_BaseExceptionClass;
116 Class* s_ErrorClass;
117 Class* s_ArithmeticErrorClass;
118 Class* s_ArgumentCountErrorClass;
119 Class* s_AssertionErrorClass;
120 Class* s_DivisionByZeroErrorClass;
121 Class* s_ParseErrorClass;
122 Class* s_TypeErrorClass;
124 Object AllocStdClassObject() {
125 return Object{s_stdclassClass};
128 Object AllocPinitSentinel() {
129 return Object{s_pinitSentinelClass};
132 Object AllocExceptionObject(const Variant& message) {
133 return createAndConstructThrowable(s_ExceptionClass, message);
136 Object AllocErrorObject(const Variant& message) {
137 return createAndConstructThrowable(s_ErrorClass, message);
140 Object AllocArithmeticErrorObject(const Variant& message) {
141 return createAndConstructThrowable(s_ArithmeticErrorClass, message);
144 Object AllocArgumentCountErrorObject(const Variant& message) {
145 return createAndConstructThrowable(s_ArgumentCountErrorClass, message);
148 Object AllocDivisionByZeroErrorObject(const Variant& message) {
149 return createAndConstructThrowable(s_DivisionByZeroErrorClass, message);
152 Object AllocParseErrorObject(const Variant& message) {
153 return createAndConstructThrowable(s_ParseErrorClass, message);
156 Object AllocTypeErrorObject(const Variant& message) {
157 return createAndConstructThrowable(s_TypeErrorClass, message);
160 Object AllocBadMethodCallExceptionObject(const Variant& message) {
161 return createAndConstructThrowable(s_BadMethodCallExceptionClass, message);
164 Object AllocInvalidArgumentExceptionObject(const Variant& message) {
165 return createAndConstructThrowable(s_InvalidArgumentExceptionClass, message);
168 Object AllocTypeAssertionExceptionObject(const Variant& message) {
169 return createAndConstructThrowable(s_TypeAssertionExceptionClass, message);
172 Object AllocRuntimeExceptionObject(const Variant& message) {
173 return createAndConstructThrowable(s_RuntimeExceptionClass, message);
176 Object AllocOutOfBoundsExceptionObject(const Variant& message) {
177 return createAndConstructThrowable(s_OutOfBoundsExceptionClass, message);
180 Object AllocInvalidOperationExceptionObject(const Variant& message) {
181 return createAndConstructThrowable(s_InvalidOperationExceptionClass, message);
184 Object AllocDOMExceptionObject(const Variant& message) {
185 return createAndConstructThrowable(s_DOMExceptionClass, message);
188 Object AllocDivisionByZeroExceptionObject() {
189 return createAndConstructThrowable(s_DivisionByZeroExceptionClass,
190 Strings::DIVISION_BY_ZERO);
193 Object AllocSoapFaultObject(const Variant& code,
194 const Variant& message,
195 const Variant& actor /* = uninit_variant */,
196 const Variant& detail /* = uninit_variant */,
197 const Variant& name /* = uninit_variant */,
198 const Variant& header /* = uninit_variant */) {
199 return createAndConstruct(
200 s_SoapFaultClass,
201 make_varray(code, message, actor, detail, name, header)
205 Object AllocLazyKVZipIterableObject(const Variant& mp) {
206 return createAndConstruct(s_LazyKVZipIterableClass,
207 make_varray(mp));
210 Object AllocLazyIterableViewObject(const Variant& iterable) {
211 return createAndConstruct(s_LazyIterableViewClass,
212 make_varray(iterable));
215 Object AllocLazyKeyedIterableViewObject(const Variant& iterable) {
216 return createAndConstruct(s_LazyKeyedIterableViewClass,
217 make_varray(iterable));
220 void throwExceptionObject(const Variant& message) {
221 throw_object(AllocExceptionObject(message));
224 void throwErrorObject(const Variant& message) {
225 throw_object(AllocErrorObject(message));
228 void throwArithmeticErrorObject(const Variant& message) {
229 throw_object(AllocArithmeticErrorObject(message));
232 void throwArgumentCountErrorObject(const Variant& message) {
233 throw_object(AllocArgumentCountErrorObject(message));
236 void throwDivisionByZeroErrorObject(const Variant& message) {
237 throw_object(AllocDivisionByZeroErrorObject(message));
240 void throwParseErrorObject(const Variant& message) {
241 throw_object(AllocParseErrorObject(message));
244 void throwTypeErrorObject(const Variant& message) {
245 throw_object(AllocTypeErrorObject(message));
248 void throwBadMethodCallExceptionObject(const Variant& message) {
249 throw_object(AllocBadMethodCallExceptionObject(message));
252 void throwInvalidArgumentExceptionObject(const Variant& message) {
253 throw_object(AllocInvalidArgumentExceptionObject(message));
256 void throwTypeAssertionExceptionObject(const Variant& message) {
257 throw_object(AllocTypeAssertionExceptionObject(message));
260 void throwRuntimeExceptionObject(const Variant& message) {
261 throw_object(AllocRuntimeExceptionObject(message));
264 void throwOutOfBoundsExceptionObject(const Variant& message) {
265 throw_object(AllocOutOfBoundsExceptionObject(message));
268 void throwInvalidOperationExceptionObject(const Variant& message) {
269 throw_object(AllocInvalidOperationExceptionObject(message));
272 void throwDOMExceptionObject(const Variant& message) {
273 throw_object(AllocDOMExceptionObject(message));
276 void throwDivisionByZeroExceptionObject() {
277 throw_object(AllocDivisionByZeroExceptionObject());
280 void throwSoapFaultObject(const Variant& code,
281 const Variant& message,
282 const Variant& actor /* = uninit_variant */,
283 const Variant& detail /* = uninit_variant */,
284 const Variant& name /* = uninit_variant */,
285 const Variant& header /* = uninit_variant */) {
286 throw_object(Object{AllocSoapFaultObject(code, message,
287 actor, detail,
288 name, header)});
291 #define ALLOC_OBJECT_STUB(name) \
292 Object Alloc##name##Object() { \
293 return Object{s_##name##Class}; \
296 ALLOC_OBJECT_STUB(Directory);
297 ALLOC_OBJECT_STUB(PDOException);
299 #undef ALLOC_OBJECT_STUB
301 /////////////////////////////////////////////////////////////////////////////
303 static std::vector<Unit*> s_persistent_units;
305 /* To be called during process startup ONLY, before threads are spun up.
306 * Typically this will be called by HPHP::Extension::moduleInit to load an
307 * extension-specific systemlib file, or to load the main systemlib.
309 void addPersistentUnit(Unit* unit) {
310 s_persistent_units.push_back(unit);
313 /* Typically called between requests in non-RepoAuthoritative mode
314 * when function renaming is enabled.
316 void mergePersistentUnits() {
317 for (auto unit : s_persistent_units) {
318 unit->merge();
322 namespace {
324 Func* setupNullClsMethod(Func* f, Class* cls, StringData* name) {
325 assertx(f && f->isPhpLeafFn());
326 auto clone = f->clone(cls, name);
327 clone->setNewFuncId();
328 clone->setAttrs(static_cast<Attr>(
329 AttrPublic | AttrNoInjection | AttrDynamicallyCallable) |
330 rxMakeAttr(RxLevel::Rx, false));
331 return clone;
334 Func* setup86ctorMethod(Class* cls) {
335 if (!s_nullFunc) {
336 s_nullFunc =
337 Unit::lookupFunc(makeStaticString("__SystemLib\\__86null"));
339 return setupNullClsMethod(s_nullFunc, cls, s_86ctor.get());
342 Func* setup86ReifiedInitMethod(Class* cls) {
343 if (!s_singleArgNullFunc) {
344 s_singleArgNullFunc =
345 Unit::lookupFunc(makeStaticString("__SystemLib\\__86single_arg_null"));
347 return setupNullClsMethod(s_singleArgNullFunc, cls, s_86reifiedinit.get());
350 } // namespace
352 void setupNullCtor(Class* cls) {
353 assertx(!s_nullCtor);
354 s_nullCtor = setup86ctorMethod(cls);
355 s_nullCtor->setHasForeignThis(true);
358 Func* getNull86reifiedinit(Class* cls) {
359 auto f = setup86ReifiedInitMethod(cls);
360 f->setBaseCls(cls);
361 f->setGenerated(true);
362 return f;
365 /////////////////////////////////////////////////////////////////////////////
366 }} // namespace HPHP::SystemLib