2 +----------------------------------------------------------------------+
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>
38 TRACE_SET_MOD(runtime
);
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());
50 void print_int(int64_t i
) {
52 auto const s
= conv_10(i
, intbuf
+ sizeof(intbuf
));
54 g_context
->write(s
.data(), s
.size());
57 void print_boolean(bool val
) {
59 g_context
->write("1", 1);
64 * concat_ss will will incRef the output string
65 * and decref its first argument
67 StringData
* concat_ss(StringData
* v1
, StringData
* v2
) {
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.
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());
89 * concat_is will incRef the output string
91 StringData
* concat_is(int64_t v1
, StringData
* v2
) {
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
);
100 * concat_si will incRef the output string
101 * and decref its first argument
103 StringData
* concat_si(StringData
* v1
, int64_t v2
) {
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.
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());
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.
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());
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.
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());
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());
188 ar
->getThis()->incRefCount();
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
);
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
,
232 return folly::sformat(
233 "{}() expects parameter {} by reference, but the call was "
234 "not annotated with '&'", fname
, index
+ 1
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.
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
);
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);
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 //////////////////////////////////////////////////////////////////////