2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 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 #include "hphp/runtime/vm/runtime.h"
17 #include "hphp/runtime/base/execution-context.h"
18 #include "hphp/runtime/server/source-root-info.h"
19 #include "hphp/runtime/base/zend-string.h"
20 #include "hphp/runtime/base/mixed-array.h"
21 #include "hphp/runtime/base/builtin-functions.h"
22 #include "hphp/runtime/base/thread-info.h"
23 #include "hphp/runtime/ext/closure/ext_closure.h"
24 #include "hphp/runtime/ext/generator/ext_generator.h"
25 #include "hphp/runtime/ext/collections/ext_collections-idl.h"
26 #include "hphp/runtime/vm/bytecode.h"
27 #include "hphp/runtime/vm/repo.h"
28 #include "hphp/util/trace.h"
29 #include "hphp/util/text-util.h"
30 #include "hphp/runtime/vm/jit/translator-inline.h"
31 #include "hphp/runtime/base/zend-functions.h"
32 #include "hphp/runtime/ext/string/ext_string.h"
36 TRACE_SET_MOD(runtime
);
38 CompileStringFn g_hphp_compiler_parse
;
39 BuildNativeFuncUnitFn g_hphp_build_native_func_unit
;
40 BuildNativeClassUnitFn g_hphp_build_native_class_unit
;
43 * print_string will decRef the string
45 void print_string(StringData
* s
) {
46 g_context
->write(s
->data(), s
->size());
47 TRACE(1, "t-x64 output(str): (%p) %43s\n", s
->data(),
48 escapeStringForCPP(s
->data(), s
->size()).data());
52 void print_int(int64_t i
) {
54 snprintf(buf
, 256, "%" PRId64
, i
);
55 g_context
->write(buf
);
56 TRACE(1, "t-x64 output(int): %" PRId64
"\n", i
);
59 void print_boolean(bool val
) {
61 g_context
->write("1");
66 * concat_ss will will incRef the output string
67 * and decref its first argument
69 StringData
* concat_ss(StringData
* v1
, StringData
* v2
) {
71 StringData
* ret
= StringData::Make(v1
, v2
);
72 // Because v1 was shared, we know this won't release the string.
77 auto const ret
= v1
->append(v2
->slice());
78 if (UNLIKELY(ret
!= v1
)) {
79 assert(v1
->hasExactlyOneRef());
86 * concat_is will incRef the output string
88 StringData
* concat_is(int64_t v1
, StringData
* v2
) {
90 // Convert the int to a string
91 auto const s1
= conv_10(v1
, intbuf
+ sizeof(intbuf
));
92 auto const s2
= v2
->slice();
93 return StringData::Make(s1
, s2
);
97 * concat_si will incRef the output string
98 * and decref its first argument
100 StringData
* concat_si(StringData
* v1
, int64_t v2
) {
102 auto const s2
= conv_10(v2
, intbuf
+ sizeof(intbuf
));
103 if (v1
->cowCheck()) {
104 auto const s1
= v1
->slice();
105 auto const ret
= StringData::Make(s1
, s2
);
106 // Because v1 was shared, we know this won't release it.
111 auto const ret
= v1
->append(s2
);
112 if (UNLIKELY(ret
!= v1
)) {
113 assert(v1
->hasExactlyOneRef());
119 StringData
* concat_s3(StringData
* v1
, StringData
* v2
, StringData
* v3
) {
120 if (v1
->cowCheck()) {
121 StringData
* ret
= StringData::Make(
122 v1
->slice(), v2
->slice(), v3
->slice());
123 // Because v1 was shared, we know this won't release it.
128 auto const ret
= v1
->append(v2
->slice(), v3
->slice());
130 if (UNLIKELY(ret
!= v1
)) {
131 assert(v1
->hasExactlyOneRef());
137 StringData
* concat_s4(StringData
* v1
, StringData
* v2
,
138 StringData
* v3
, StringData
* v4
) {
139 if (v1
->cowCheck()) {
140 StringData
* ret
= StringData::Make(
141 v1
->slice(), v2
->slice(), v3
->slice(), v4
->slice());
142 // Because v1 was shared, we know this won't release it.
147 auto const ret
= v1
->append(v2
->slice(), v3
->slice(), v4
->slice());
149 if (UNLIKELY(ret
!= v1
)) {
150 assert(v1
->hasExactlyOneRef());
156 Unit
* compile_file(const char* s
, size_t sz
, const MD5
& md5
,
158 return g_hphp_compiler_parse(s
, sz
, md5
, fname
);
161 Unit
* build_native_func_unit(const HhbcExtFuncInfo
* builtinFuncs
,
162 ssize_t numBuiltinFuncs
) {
163 return g_hphp_build_native_func_unit(builtinFuncs
, numBuiltinFuncs
);
166 Unit
* build_native_class_unit(const HhbcExtClassInfo
* builtinClasses
,
167 ssize_t numBuiltinClasses
) {
168 return g_hphp_build_native_class_unit(builtinClasses
, numBuiltinClasses
);
171 std::string
mangleSystemMd5(const std::string
& fileMd5
) {
172 // This resembles mangleUnitMd5(...), however, only settings that HHBBC is
173 // aware of may be used here or it will be unable to load systemlib!
174 std::string t
= fileMd5
+ '\0'
175 + (RuntimeOption::PHP7_IntSemantics
? '1' : '0')
176 + (RuntimeOption::AutoprimeGenerators
? '1' : '0')
178 return string_md5(t
.c_str(), t
.size());
181 Unit
* compile_string(const char* s
,
183 const char* fname
/* = nullptr */) {
184 auto md5string
= mangleSystemMd5(string_md5(s
, sz
));
185 MD5
md5(md5string
.c_str());
186 Unit
* u
= Repo::get().loadUnit(fname
? fname
: "", md5
).release();
190 // NB: fname needs to be long-lived if generating a bytecode repo because it
191 // can be cached via a Location ultimately contained by ErrorInfo for printing
193 return g_hphp_compiler_parse(s
, sz
, md5
, fname
);
196 Unit
* compile_systemlib_string(const char* s
, size_t sz
,
198 if (RuntimeOption::RepoAuthoritative
) {
199 String systemName
= String("/:") + String(fname
);
201 mangleSystemMd5(string_md5(s
, sz
)).c_str()
203 if (Repo::get().findFile(systemName
.data(),
204 SourceRootInfo::GetCurrentSourceRoot(),
206 if (auto u
= Repo::get().loadUnit(fname
, md5
)) {
211 return compile_string(s
, sz
, fname
);
214 void assertTv(const TypedValue
* tv
) {
215 always_assert(tvIsPlausible(*tv
));
218 int init_closure(ActRec
* ar
, TypedValue
* sp
) {
219 c_Closure
* closure
= static_cast<c_Closure
*>(ar
->getThis());
221 // Swap in the $this or late bound class or null if it is ony from a plain
222 // function or pseudomain
223 ar
->setThisOrClassAllowNull(closure
->getThisOrClass());
226 ar
->getThis()->incRefCount();
229 // Put in the correct context
230 ar
->m_func
= closure
->getInvokeFunc();
232 // The closure is the first local.
233 // Similar to tvWriteObject() but we don't incref because it used to be $this
234 // and now it is a local, so they cancel out
235 TypedValue
* firstLocal
= --sp
;
236 firstLocal
->m_type
= KindOfObject
;
237 firstLocal
->m_data
.pobj
= closure
;
239 // Copy in all the use vars
240 TypedValue
* prop
= closure
->getUseVars();
241 int n
= closure
->getNumUseVars();
242 for (int i
=0; i
< n
; i
++) {
243 tvDup(*prop
++, *--sp
);
249 void raiseWarning(const StringData
* sd
) {
250 raise_warning("%s", sd
->data());
253 void raiseNotice(const StringData
* sd
) {
254 raise_notice("%s", sd
->data());
257 void raiseArrayIndexNotice(const int64_t index
) {
258 raise_notice("Undefined index: %" PRId64
, index
);
261 void raiseArrayKeyNotice(const StringData
* key
) {
262 raise_notice("Undefined key: %s", key
->data());
265 //////////////////////////////////////////////////////////////////////
267 int64_t zero_error_level() {
268 auto& id
= ThreadInfo::s_threadInfo
.getNoCheck()->m_reqInjectionData
;
269 auto level
= id
.getErrorReportingLevel();
270 id
.setErrorReportingLevel(0);
274 void restore_error_level(int64_t oldLevel
) {
275 auto& id
= ThreadInfo::s_threadInfo
.getNoCheck()->m_reqInjectionData
;
276 if (id
.getErrorReportingLevel() == 0) {
277 id
.setErrorReportingLevel(oldLevel
);
281 //////////////////////////////////////////////////////////////////////