Add mode to EndCatch
[hiphop-php.git] / hphp / runtime / vm / runtime.cpp
blob6cbe6f512fcda88312a16267f95d1ab8c7d916de
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 +----------------------------------------------------------------------+
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/request-info.h"
23 #include "hphp/runtime/base/unit-cache.h"
24 #include "hphp/runtime/ext/std/ext_std_closure.h"
25 #include "hphp/runtime/ext/generator/ext_generator.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 #include <folly/tracing/StaticTracepoint.h>
36 namespace HPHP {
38 TRACE_SET_MOD(runtime);
40 /**
41 * print_string will decRef the string
43 void print_string(StringData* s) {
44 g_context->write(s->data(), s->size());
45 TRACE(1, "t-x64 output(str): (%p) %43s\n", s->data(),
46 escapeStringForCPP(s->data(), s->size()).data());
47 decRefStr(s);
50 void print_int(int64_t i) {
51 char intbuf[21];
52 auto const s = conv_10(i, intbuf + sizeof(intbuf));
54 g_context->write(s.data(), s.size());
57 void print_boolean(bool val) {
58 if (val) {
59 g_context->write("1", 1);
63 /**
64 * concat_ss will will incRef the output string
65 * and decref its first argument
67 StringData* concat_ss(StringData* v1, StringData* v2) {
68 if (v1->cowCheck()) {
69 FOLLY_SDT(hhvm, hhvm_cow_concat, v1->size(), v2->size());
70 StringData* ret = StringData::Make(v1, v2);
71 // Because v1 was shared, we know this won't release the string.
72 v1->decRefCount();
73 return ret;
76 auto const rhs = v2->slice();
77 UNUSED auto const lsize = v1->size();
78 FOLLY_SDT(hhvm, hhvm_mut_concat, lsize, rhs.size());
79 auto const ret = v1->append(rhs);
80 if (UNLIKELY(ret != v1)) {
81 // had to realloc even though count==1
82 assertx(v1->hasExactlyOneRef());
83 v1->release();
85 return ret;
88 /**
89 * concat_is will incRef the output string
91 StringData* concat_is(int64_t v1, StringData* v2) {
92 char intbuf[21];
93 // Convert the int to a string
94 auto const s1 = conv_10(v1, intbuf + sizeof(intbuf));
95 auto const s2 = v2->slice();
96 return StringData::Make(s1, s2);
99 /**
100 * concat_si will incRef the output string
101 * and decref its first argument
103 StringData* concat_si(StringData* v1, int64_t v2) {
104 char intbuf[21];
105 auto const s2 = conv_10(v2, intbuf + sizeof(intbuf));
106 if (v1->cowCheck()) {
107 auto const s1 = v1->slice();
108 FOLLY_SDT(hhvm, hhvm_cow_concat, s1.size(), s2.size());
109 auto const ret = StringData::Make(s1, s2);
110 // Because v1 was shared, we know this won't release it.
111 v1->decRefCount();
112 return ret;
115 UNUSED auto const lsize = v1->size();
116 FOLLY_SDT(hhvm, hhvm_mut_concat, lsize, s2.size());
117 auto const ret = v1->append(s2);
118 if (UNLIKELY(ret != v1)) {
119 // had to realloc even though count==1
120 assertx(v1->hasExactlyOneRef());
121 v1->release();
123 return ret;
126 StringData* concat_s3(StringData* v1, StringData* v2, StringData* v3) {
127 if (v1->cowCheck()) {
128 auto s1 = v1->slice();
129 auto s2 = v2->slice();
130 auto s3 = v3->slice();
131 FOLLY_SDT(hhvm, hhvm_cow_concat, s1.size(), s2.size() + s3.size());
132 StringData* ret = StringData::Make(s1, s2, s3);
133 // Because v1 was shared, we know this won't release it.
134 v1->decRefCount();
135 return ret;
138 UNUSED auto const lsize = v1->size();
139 FOLLY_SDT(hhvm, hhvm_mut_concat, lsize, v2->size() + v3->size());
140 auto const ret = v1->append(v2->slice(), v3->slice());
141 if (UNLIKELY(ret != v1)) {
142 // had to realloc even though count==1
143 assertx(v1->hasExactlyOneRef());
144 v1->release();
146 return ret;
149 StringData* concat_s4(StringData* v1, StringData* v2,
150 StringData* v3, StringData* v4) {
151 if (v1->cowCheck()) {
152 auto s1 = v1->slice();
153 auto s2 = v2->slice();
154 auto s3 = v3->slice();
155 auto s4 = v4->slice();
156 FOLLY_SDT(hhvm, hhvm_cow_concat, s1.size(),
157 s2.size() + s3.size() + s4.size());
158 StringData* ret = StringData::Make(s1, s2, s3, s4);
159 // Because v1 was shared, we know this won't release it.
160 v1->decRefCount();
161 return ret;
164 UNUSED auto const lsize = v1->size();
165 FOLLY_SDT(hhvm, hhvm_mut_concat, lsize,
166 v2->size() + v3->size() + v4->size());
167 auto const ret = v1->append(v2->slice(), v3->slice(), v4->slice());
168 if (UNLIKELY(ret != v1)) {
169 // had to realloc even though count==1
170 assertx(v1->hasExactlyOneRef());
171 v1->release();
173 return ret;
176 int init_closure(ActRec* ar, TypedValue* sp) {
177 auto closure = c_Closure::fromObject(ar->getThis());
179 // Put in the correct context
180 ar->m_func = closure->getInvokeFunc();
182 if (ar->func()->cls()) {
183 // Swap in the $this or late bound class or null if it is ony from a plain
184 // function or pseudomain
185 ar->setThisOrClass(closure->getThisOrClass());
187 if (ar->hasThis()) {
188 ar->getThis()->incRefCount();
190 } else {
191 ar->trashThis();
194 // The closure is the first local.
195 // Similar to tvWriteObject() but we don't incref because it used to be $this
196 // and now it is a local, so they cancel out
197 TypedValue* firstLocal = --sp;
198 firstLocal->m_type = KindOfObject;
199 firstLocal->m_data.pobj = closure;
201 // Copy in all the use vars
202 Cell* prop = closure->getUseVars();
203 int n = closure->getNumUseVars();
204 for (int i = 0; i < n; i++) {
205 cellDup(*prop++, *--sp);
208 return n + 1;
211 void raiseWarning(const StringData* sd) {
212 raise_warning("%s", sd->data());
215 void raiseNotice(const StringData* sd) {
216 raise_notice("%s", sd->data());
219 void raiseArrayIndexNotice(const int64_t index, bool isInOut) {
220 raise_notice("Undefined index%s: %" PRId64,
221 isInOut ? " on inout parameter" : "", index);
224 void raiseArrayKeyNotice(const StringData* key, bool isInOut) {
225 raise_notice("Undefined index%s: %s",
226 isInOut ? " on inout parameter" : "", key->data());
229 std::string formatParamRefMismatch(const char* fname, uint32_t index,
230 bool funcByRef) {
231 if (funcByRef) {
232 return folly::sformat(
233 "{}() expects parameter {} by reference, but the call was "
234 "not annotated with '&'", fname, index + 1
236 } else {
237 return folly::sformat(
238 "{}() expects parameter {} by value, but the call was "
239 "annotated with '&'", fname, index + 1
244 void throwParamRefMismatch(const Func* func, uint32_t index) {
245 SystemLib::throwInvalidArgumentExceptionObject(formatParamRefMismatch(
246 func->fullDisplayName()->data(), index, func->byRef(index)));
249 void throwParamRefMismatchRange(const Func* func, unsigned firstVal,
250 uint64_t mask, uint64_t vals) {
251 for (auto i = 0; i < 64; ++i) {
252 if (mask & (1UL << i)) {
253 bool byRef = vals & (1UL << i);
254 if (func->byRef(firstVal + i) != byRef) {
255 throwParamRefMismatch(func, firstVal + i);
260 // Caller guarantees at least one parameter with reffiness mismatch.
261 not_reached();
264 void raiseRxCallViolation(const ActRec* caller, const Func* callee) {
265 assertx(RuntimeOption::EvalRxEnforceCalls > 0);
266 auto const errMsg = folly::sformat(
267 "Call to {} '{}' from {} '{}' violates reactivity constraints.",
268 rxLevelToString(callee->rxLevel()),
269 callee->fullName()->data(),
270 rxLevelToString(caller->rxMinLevel()),
271 caller->func()->fullName()->data()
274 if (RuntimeOption::EvalRxEnforceCalls >= 2) {
275 SystemLib::throwBadMethodCallExceptionObject(errMsg);
276 } else {
277 raise_warning(errMsg);
281 //////////////////////////////////////////////////////////////////////
283 int64_t zero_error_level() {
284 auto& id = RequestInfo::s_requestInfo.getNoCheck()->m_reqInjectionData;
285 auto level = id.getErrorReportingLevel();
286 id.setErrorReportingLevel(0);
287 return level;
290 void restore_error_level(int64_t oldLevel) {
291 auto& id = RequestInfo::s_requestInfo.getNoCheck()->m_reqInjectionData;
292 if (id.getErrorReportingLevel() == 0) {
293 id.setErrorReportingLevel(oldLevel);
297 //////////////////////////////////////////////////////////////////////