Use RATs from HHBBC in init_use_vars
[hiphop-php.git] / hphp / runtime / vm / runtime.cpp
bloba1cf4679869d48a830eecb6698358550cc9c5ab2
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
34 namespace HPHP {
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;
42 /**
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());
49 decRefStr(s);
52 void print_int(int64_t i) {
53 char buf[256];
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) {
60 if (val) {
61 g_context->write("1");
65 /**
66 * concat_ss will will incRef the output string
67 * and decref its first argument
69 StringData* concat_ss(StringData* v1, StringData* v2) {
70 if (v1->cowCheck()) {
71 StringData* ret = StringData::Make(v1, v2);
72 // Because v1 was shared, we know this won't release the string.
73 v1->decRefCount();
74 return ret;
77 auto const ret = v1->append(v2->slice());
78 if (UNLIKELY(ret != v1)) {
79 assert(v1->hasExactlyOneRef());
80 v1->release();
82 return ret;
85 /**
86 * concat_is will incRef the output string
88 StringData* concat_is(int64_t v1, StringData* v2) {
89 char intbuf[21];
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);
96 /**
97 * concat_si will incRef the output string
98 * and decref its first argument
100 StringData* concat_si(StringData* v1, int64_t v2) {
101 char intbuf[21];
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.
107 v1->decRefCount();
108 return ret;
111 auto const ret = v1->append(s2);
112 if (UNLIKELY(ret != v1)) {
113 assert(v1->hasExactlyOneRef());
114 v1->release();
116 return ret;
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.
124 v1->decRefCount();
125 return ret;
128 auto const ret = v1->append(v2->slice(), v3->slice());
130 if (UNLIKELY(ret != v1)) {
131 assert(v1->hasExactlyOneRef());
132 v1->release();
134 return ret;
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.
143 v1->decRefCount();
144 return ret;
147 auto const ret = v1->append(v2->slice(), v3->slice(), v4->slice());
149 if (UNLIKELY(ret != v1)) {
150 assert(v1->hasExactlyOneRef());
151 v1->release();
153 return ret;
156 Unit* compile_file(const char* s, size_t sz, const MD5& md5,
157 const char* fname) {
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,
182 size_t sz,
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();
187 if (u != nullptr) {
188 return u;
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
192 // code errors.
193 return g_hphp_compiler_parse(s, sz, md5, fname);
196 Unit* compile_systemlib_string(const char* s, size_t sz,
197 const char* fname) {
198 if (RuntimeOption::RepoAuthoritative) {
199 String systemName = String("/:") + String(fname);
200 MD5 md5 {
201 mangleSystemMd5(string_md5(s, sz)).c_str()
203 if (Repo::get().findFile(systemName.data(),
204 SourceRootInfo::GetCurrentSourceRoot(),
205 md5)) {
206 if (auto u = Repo::get().loadUnit(fname, md5)) {
207 return u.release();
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());
225 if (ar->hasThis()) {
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);
246 return n + 1;
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);
271 return level;
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 //////////////////////////////////////////////////////////////////////