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/base/coeffects-config.h"
19 #include "hphp/runtime/server/source-root-info.h"
20 #include "hphp/runtime/base/zend-string.h"
21 #include "hphp/runtime/base/mixed-array.h"
22 #include "hphp/runtime/base/builtin-functions.h"
23 #include "hphp/runtime/base/request-info.h"
24 #include "hphp/runtime/base/unit-cache.h"
25 #include "hphp/runtime/ext/std/ext_std_closure.h"
26 #include "hphp/runtime/ext/generator/ext_generator.h"
27 #include "hphp/runtime/vm/bytecode.h"
28 #include "hphp/runtime/vm/repo.h"
29 #include "hphp/util/trace.h"
30 #include "hphp/util/text-util.h"
31 #include "hphp/runtime/vm/jit/translator-inline.h"
32 #include "hphp/runtime/base/zend-functions.h"
33 #include "hphp/runtime/ext/string/ext_string.h"
35 #include <folly/tracing/StaticTracepoint.h>
39 TRACE_SET_MOD(runtime
);
42 * print_string will decRef the string
44 void print_string(StringData
* s
) {
45 g_context
->write(s
->data(), s
->size());
46 TRACE(2, "t-x64 output(str): (%p) %43s\n", s
->data(),
47 escapeStringForCPP(s
->data(), s
->size()).data());
51 void print_int(int64_t i
) {
53 auto const s
= conv_10(i
, intbuf
+ sizeof(intbuf
));
55 g_context
->write(s
.data(), s
.size());
58 void print_boolean(bool val
) {
60 g_context
->write("1", 1);
65 * concat_ss will will incRef the output string
66 * and decref its first argument
68 StringData
* concat_ss(StringData
* v1
, StringData
* v2
) {
70 FOLLY_SDT(hhvm
, hhvm_cow_concat
, v1
->size(), v2
->size());
71 StringData
* ret
= StringData::Make(v1
, v2
);
72 // Because v1 was shared, we know this won't release the string.
77 auto const rhs
= v2
->slice();
78 UNUSED
auto const lsize
= v1
->size();
79 FOLLY_SDT(hhvm
, hhvm_mut_concat
, lsize
, rhs
.size());
80 auto const ret
= v1
->append(rhs
);
81 if (UNLIKELY(ret
!= v1
)) {
82 // had to realloc even though count==1
83 assertx(v1
->hasExactlyOneRef());
90 * concat_is will incRef the output string
92 StringData
* concat_is(int64_t v1
, StringData
* v2
) {
94 // Convert the int to a string
95 auto const s1
= conv_10(v1
, intbuf
+ sizeof(intbuf
));
96 auto const s2
= v2
->slice();
97 return StringData::Make(s1
, s2
);
101 * concat_si will incRef the output string
102 * and decref its first argument
104 StringData
* concat_si(StringData
* v1
, int64_t v2
) {
106 auto const s2
= conv_10(v2
, intbuf
+ sizeof(intbuf
));
107 if (v1
->cowCheck()) {
108 auto const s1
= v1
->slice();
109 FOLLY_SDT(hhvm
, hhvm_cow_concat
, s1
.size(), s2
.size());
110 auto const ret
= StringData::Make(s1
, s2
);
111 // Because v1 was shared, we know this won't release it.
116 UNUSED
auto const lsize
= v1
->size();
117 FOLLY_SDT(hhvm
, hhvm_mut_concat
, lsize
, s2
.size());
118 auto const ret
= v1
->append(s2
);
119 if (UNLIKELY(ret
!= v1
)) {
120 // had to realloc even though count==1
121 assertx(v1
->hasExactlyOneRef());
127 StringData
* concat_s3(StringData
* v1
, StringData
* v2
, StringData
* v3
) {
128 if (v1
->cowCheck()) {
129 auto s1
= v1
->slice();
130 auto s2
= v2
->slice();
131 auto s3
= v3
->slice();
132 FOLLY_SDT(hhvm
, hhvm_cow_concat
, s1
.size(), s2
.size() + s3
.size());
133 StringData
* ret
= StringData::Make(s1
, s2
, s3
);
134 // Because v1 was shared, we know this won't release it.
139 UNUSED
auto const lsize
= v1
->size();
140 FOLLY_SDT(hhvm
, hhvm_mut_concat
, lsize
, v2
->size() + v3
->size());
141 auto const ret
= v1
->append(v2
->slice(), v3
->slice());
142 if (UNLIKELY(ret
!= v1
)) {
143 // had to realloc even though count==1
144 assertx(v1
->hasExactlyOneRef());
150 StringData
* concat_s4(StringData
* v1
, StringData
* v2
,
151 StringData
* v3
, StringData
* v4
) {
152 if (v1
->cowCheck()) {
153 auto s1
= v1
->slice();
154 auto s2
= v2
->slice();
155 auto s3
= v3
->slice();
156 auto s4
= v4
->slice();
157 FOLLY_SDT(hhvm
, hhvm_cow_concat
, s1
.size(),
158 s2
.size() + s3
.size() + s4
.size());
159 StringData
* ret
= StringData::Make(s1
, s2
, s3
, s4
);
160 // Because v1 was shared, we know this won't release it.
165 UNUSED
auto const lsize
= v1
->size();
166 FOLLY_SDT(hhvm
, hhvm_mut_concat
, lsize
,
167 v2
->size() + v3
->size() + v4
->size());
168 auto const ret
= v1
->append(v2
->slice(), v3
->slice(), v4
->slice());
169 if (UNLIKELY(ret
!= v1
)) {
170 // had to realloc even though count==1
171 assertx(v1
->hasExactlyOneRef());
177 void raiseWarning(const StringData
* sd
) {
178 raise_warning("%s", sd
->data());
181 void raiseNotice(const StringData
* sd
) {
182 raise_notice("%s", sd
->data());
185 void throwArrayIndexException(const ArrayData
* ad
, const int64_t index
) {
186 throwOOBArrayKeyException(index
, ad
);
189 void throwArrayKeyException(const ArrayData
* ad
, const StringData
* key
) {
190 assertx(ad
->isDArray() || ad
->isDictType());
191 throwOOBArrayKeyException(key
, ad
);
194 std::string
formatParamInOutMismatch(const char* fname
, uint32_t index
,
197 return folly::sformat(
198 "{}() expects parameter {} to be inout, but the call was "
199 "not annotated with 'inout'", fname
, index
+ 1
202 return folly::sformat(
203 "{}() does not expect parameter {} to be inout, but the call was "
204 "annotated with 'inout'", fname
, index
+ 1
209 void throwParamInOutMismatch(const Func
* func
, uint32_t index
) {
210 SystemLib::throwInvalidArgumentExceptionObject(formatParamInOutMismatch(
211 func
->fullName()->data(), index
, func
->isInOut(index
)));
214 void throwParamInOutMismatchRange(const Func
* func
, unsigned firstVal
,
215 uint64_t mask
, uint64_t vals
) {
216 for (auto i
= 0; i
< 64; ++i
) {
217 if (mask
& (1UL << i
)) {
218 bool isInOut
= vals
& (1UL << i
);
219 if (func
->isInOut(firstVal
+ i
) != isInOut
) {
220 throwParamInOutMismatch(func
, firstVal
+ i
);
225 // Caller guarantees at least one parameter with inout-ness mismatch.
229 void throwInvalidUnpackArgs() {
230 SystemLib::throwInvalidArgumentExceptionObject(
231 "Only containers may be unpacked");
236 std::string
formatArgumentErrMsg(const Func
* func
, const char* amount
,
237 uint32_t expected
, uint32_t got
) {
238 return folly::sformat(
239 "{}() expects {} {} parameter{}, {} given",
240 func
->fullName()->data(),
243 expected
== 1 ? "" : "s",
250 void throwMissingArgument(const Func
* func
, int got
) {
251 auto const expected
= func
->numRequiredParams();
252 assertx(got
< expected
);
253 auto const amount
= expected
< func
->numParams() ? "at least" : "exactly";
254 auto const errMsg
= formatArgumentErrMsg(func
, amount
, expected
, got
);
255 SystemLib::throwRuntimeExceptionObject(Variant(errMsg
));
258 void raiseTooManyArguments(const Func
* func
, int got
) {
259 assertx(!func
->hasVariadicCaptureParam());
261 if (!RuntimeOption::EvalWarnOnTooManyArguments
&& !func
->isCPPBuiltin()) {
265 auto const total
= func
->numNonVariadicParams();
266 assertx(got
> total
);
267 auto const amount
= func
->numRequiredParams() < total
? "at most" : "exactly";
268 auto const errMsg
= formatArgumentErrMsg(func
, amount
, total
, got
);
270 if (RuntimeOption::EvalWarnOnTooManyArguments
> 1 || func
->isCPPBuiltin()) {
271 SystemLib::throwRuntimeExceptionObject(Variant(errMsg
));
273 raise_warning(errMsg
);
277 void raiseTooManyArgumentsPrologue(const Func
* func
, ArrayData
* unpackArgs
) {
278 SCOPE_EXIT
{ decRefArr(unpackArgs
); };
279 if (unpackArgs
->empty()) return;
280 auto const got
= func
->numNonVariadicParams() + unpackArgs
->size();
281 raiseTooManyArguments(func
, got
);
284 //////////////////////////////////////////////////////////////////////
286 void raiseCoeffectsCallViolation(const Func
* callee
,
287 RuntimeCoeffects provided
,
288 RuntimeCoeffects required
) {
289 assertx(CoeffectsConfig::enabled());
290 auto const errMsg
= folly::sformat(
291 "Call to {}() requires [{}] coeffects but {}() provided [{}]",
292 callee
->fullNameWithClosureName(),
294 fromLeaf([] (const ActRec
* fp
, Offset
) {
295 return fp
->func()->fullNameWithClosureName();
300 assertx(!provided
.canCall(required
));
301 if (provided
.canCallWithWarning(required
)) {
302 raise_warning(errMsg
);
304 SystemLib::throwBadMethodCallExceptionObject(errMsg
);
308 //////////////////////////////////////////////////////////////////////
310 int64_t zero_error_level() {
311 auto& id
= RequestInfo::s_requestInfo
.getNoCheck()->m_reqInjectionData
;
312 auto level
= id
.getErrorReportingLevel();
313 id
.setErrorReportingLevel(0);
317 void restore_error_level(int64_t oldLevel
) {
318 auto& id
= RequestInfo::s_requestInfo
.getNoCheck()->m_reqInjectionData
;
319 if (id
.getErrorReportingLevel() == 0) {
320 id
.setErrorReportingLevel(oldLevel
);
324 //////////////////////////////////////////////////////////////////////