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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/irlower-internal.h"
19 #include "hphp/runtime/base/datatype.h"
20 #include "hphp/runtime/base/execution-context.h"
21 #include "hphp/runtime/base/rds.h"
22 #include "hphp/runtime/base/rds-util.h"
23 #include "hphp/runtime/base/runtime-error.h"
24 #include "hphp/runtime/base/static-string-table.h"
25 #include "hphp/runtime/base/string-data.h"
26 #include "hphp/runtime/base/strings.h"
27 #include "hphp/runtime/base/tv-mutate.h"
28 #include "hphp/runtime/base/tv-variant.h"
29 #include "hphp/runtime/base/type-variant.h"
30 #include "hphp/runtime/vm/named-entity.h"
31 #include "hphp/runtime/vm/unit.h"
33 #include "hphp/runtime/vm/jit/types.h"
34 #include "hphp/runtime/vm/jit/abi.h"
35 #include "hphp/runtime/vm/jit/arg-group.h"
36 #include "hphp/runtime/vm/jit/call-spec.h"
37 #include "hphp/runtime/vm/jit/extra-data.h"
38 #include "hphp/runtime/vm/jit/ir-instruction.h"
39 #include "hphp/runtime/vm/jit/ir-opcode.h"
40 #include "hphp/runtime/vm/jit/ssa-tmp.h"
41 #include "hphp/runtime/vm/jit/translator-inline.h"
42 #include "hphp/runtime/vm/jit/type.h"
43 #include "hphp/runtime/vm/jit/vasm-gen.h"
44 #include "hphp/runtime/vm/jit/vasm-instr.h"
45 #include "hphp/runtime/vm/jit/vasm-reg.h"
47 #include "hphp/util/asm-x64.h"
48 #include "hphp/util/trace.h"
50 namespace HPHP
{ namespace jit
{ namespace irlower
{
52 TRACE_SET_MOD(irlower
);
54 ///////////////////////////////////////////////////////////////////////////////
56 void cgLdCns(IRLS
& env
, const IRInstruction
* inst
) {
57 auto const cnsName
= inst
->src(0)->strVal();
58 auto const ch
= makeCnsHandle(cnsName
, false);
59 auto const dst
= dstLoc(env
, inst
, 0);
61 assertx(inst
->taken());
63 auto checkUninit
= [&] {
64 auto const sf
= v
.makeReg();
65 irlower::emitTypeTest(
66 v
, env
, TUninit
, dst
.reg(1), dst
.reg(0), sf
,
67 [&] (ConditionCode cc
, Vreg sfr
) {
68 fwdJcc(v
, env
, cc
, sfr
, inst
->taken());
73 if (rds::isNormalHandle(ch
)) {
74 auto const sf
= checkRDSHandleInitialized(v
, ch
);
75 fwdJcc(v
, env
, CC_NE
, sf
, inst
->taken());
76 loadTV(v
, inst
->dst(), dst
, rvmtl()[ch
]);
78 // When a CLIServer is active requests running in script mode will define
79 // the stdio constants which require lookup via special callbacks. To not
80 // interfere with the server these constants will be defined as
82 if (!RuntimeOption::RepoAuthoritative
) {
83 if (strcasecmp(cnsName
->data(), "stdin") == 0 ||
84 strcasecmp(cnsName
->data(), "stdout") == 0 ||
85 strcasecmp(cnsName
->data(), "stderr") == 0) {
91 assertx(rds::isPersistentHandle(ch
));
93 auto const& cns
= rds::handleToRef
<TypedValue
>(ch
);
95 if (cns
.m_type
== KindOfUninit
) {
96 loadTV(v
, inst
->dst(), dst
, rvmtl()[ch
]);
99 // Statically known constant.
100 assertx(!dst
.isFullSIMD());
101 switch (cns
.m_type
) {
103 v
<< copy
{v
.cns(nullptr), dst
.reg(0)};
106 v
<< copy
{v
.cns(!!cns
.m_data
.num
), dst
.reg(0)};
109 case KindOfPersistentString
:
110 case KindOfPersistentVec
:
111 case KindOfPersistentDict
:
112 case KindOfPersistentKeyset
:
113 case KindOfPersistentArray
:
122 v
<< copy
{v
.cns(cns
.m_data
.num
), dst
.reg(0)};
125 v
<< copy
{v
.cns(cns
.m_data
.dbl
), dst
.reg(0)};
130 v
<< copy
{v
.cns(cns
.m_type
), dst
.reg(1)};
134 ///////////////////////////////////////////////////////////////////////////////
137 const Cell
* lookupCnsImpl(StringData
* nm
) {
138 const Cell
* cns
= nullptr;
140 if (UNLIKELY(rds::s_constants().get() != nullptr)) {
141 cns
= rds::s_constants()->rval(nm
).tv_ptr();
144 cns
= Unit::loadCns(const_cast<StringData
*>(nm
));
149 Cell
lookupCnsHelper(StringData
* nm
, bool error
) {
150 auto const cns
= lookupCnsImpl(nm
);
151 if (LIKELY(cns
!= nullptr)) {
157 // Undefined constants.
159 raise_error("Undefined constant '%s'", nm
->data());
161 raise_notice(Strings::UNDEFINED_CONSTANT
, nm
->data(), nm
->data());
163 c1
.m_data
.pstr
= const_cast<StringData
*>(nm
);
164 c1
.m_type
= KindOfPersistentString
;
170 Cell
lookupCnsHelperNormal(rds::Handle tv_handle
,
171 StringData
* nm
, bool error
) {
172 assertx(rds::isNormalHandle(tv_handle
));
173 if (UNLIKELY(rds::isHandleInit(tv_handle
))) {
174 auto const tv
= &rds::handleToRef
<TypedValue
>(tv_handle
);
175 if (tv
->m_data
.pref
!= nullptr) {
176 auto callback
= (Unit::SystemConstantCallback
)(tv
->m_data
.pref
);
177 const Cell
* cns
= callback().asTypedValue();
178 if (LIKELY(cns
->m_type
!= KindOfUninit
)) {
185 assertx(!rds::isHandleInit(tv_handle
));
187 return lookupCnsHelper(nm
, error
);
190 Cell
lookupCnsHelperPersistent(rds::Handle tv_handle
,
191 StringData
* nm
, bool error
) {
192 assertx(rds::isPersistentHandle(tv_handle
));
193 auto const tv
= &rds::handleToRef
<TypedValue
>(tv_handle
);
194 assertx(tv
->m_type
== KindOfUninit
);
196 // Deferred system constants.
197 if (UNLIKELY(tv
->m_data
.pref
!= nullptr)) {
198 auto callback
= (Unit::SystemConstantCallback
)(tv
->m_data
.pref
);
199 const Cell
* cns
= callback().asTypedValue();
200 if (LIKELY(cns
->m_type
!= KindOfUninit
)) {
206 return lookupCnsHelper(nm
, error
);
209 Cell
lookupCnsUHelperNormal(rds::Handle tv_handle
,
210 StringData
* nm
, StringData
* fallback
) {
211 assertx(rds::isNormalHandle(tv_handle
));
213 // Lookup qualified name in thread-local constants.
214 auto cns
= lookupCnsImpl(nm
);
216 // Try cache handle for unqualified name.
217 if (UNLIKELY(!cns
&& rds::isHandleInit(tv_handle
, rds::NormalTag
{}))) {
218 cns
= &rds::handleToRef
<TypedValue
>(tv_handle
);
219 assertx(cns
->m_type
!= KindOfUninit
);
222 if (LIKELY(cns
!= nullptr)) {
228 // Lookup unqualified name in thread-local constants.
229 return lookupCnsHelper(fallback
, false);
232 Cell
lookupCnsUHelperPersistent(rds::Handle tv_handle
,
233 StringData
* nm
, StringData
* fallback
) {
234 assertx(rds::isPersistentHandle(tv_handle
));
236 // Lookup qualified name in thread-local constants.
237 auto cns
= lookupCnsImpl(nm
);
239 // Try cache handle for unqualified name.
240 auto const tv
= &rds::handleToRef
<TypedValue
>(tv_handle
);
241 if (UNLIKELY(!cns
&& tv
->m_type
!= KindOfUninit
)) {
245 if (LIKELY(cns
!= nullptr)) {
251 return lookupCnsHelper(fallback
, false);
254 ///////////////////////////////////////////////////////////////////////////////
258 void implLookupCns(IRLS
& env
, const IRInstruction
* inst
) {
259 auto const cnsName
= inst
->src(0)->strVal();
260 auto const ch
= makeCnsHandle(cnsName
, false);
262 auto const args
= argGroup(env
, inst
)
263 .imm(safe_cast
<int32_t>(ch
))
265 .imm(inst
->is(LookupCnsE
));
269 rds::isNormalHandle(ch
)
270 ? CallSpec::direct(lookupCnsHelperNormal
)
271 : CallSpec::direct(lookupCnsHelperPersistent
),
272 callDestTV(env
, inst
),
280 void cgLookupCns(IRLS
& env
, const IRInstruction
* inst
) {
281 implLookupCns(env
, inst
);
284 void cgLookupCnsE(IRLS
& env
, const IRInstruction
* inst
) {
285 implLookupCns(env
, inst
);
288 void cgLookupCnsU(IRLS
& env
, const IRInstruction
* inst
) {
289 auto const cnsName
= inst
->src(0)->strVal();
290 auto const fallbackName
= inst
->src(1)->strVal();
292 auto const fallbackCh
= makeCnsHandle(fallbackName
, false);
294 auto const args
= argGroup(env
, inst
)
295 .imm(safe_cast
<int32_t>(fallbackCh
))
297 .immPtr(fallbackName
);
301 rds::isNormalHandle(fallbackCh
)
302 ? CallSpec::direct(lookupCnsUHelperNormal
)
303 : CallSpec::direct(lookupCnsUHelperPersistent
),
304 callDestTV(env
, inst
),
310 ///////////////////////////////////////////////////////////////////////////////
312 void cgLdClsCns(IRLS
& env
, const IRInstruction
* inst
) {
313 auto const extra
= inst
->extra
<LdClsCns
>();
314 auto const link
= rds::bindClassConstant(extra
->clsName
, extra
->cnsName
);
315 auto const dst
= dstLoc(env
, inst
, 0).reg();
316 auto& v
= vmain(env
);
318 auto const sf
= checkRDSHandleInitialized(v
, link
.handle());
319 fwdJcc(v
, env
, CC_NE
, sf
, inst
->taken());
320 v
<< lea
{rvmtl()[link
.handle()], dst
};
323 Cell
lookupClsCnsHelper(TypedValue
* cache
, const NamedEntity
* ne
,
324 const StringData
* cls
, const StringData
* cns
) {
325 auto const clsCns
= g_context
->lookupClsCns(ne
, cls
, cns
);
326 cellDup(clsCns
, *cache
);
330 void cgInitClsCns(IRLS
& env
, const IRInstruction
* inst
) {
331 auto const extra
= inst
->extra
<InitClsCns
>();
332 auto const link
= rds::bindClassConstant(extra
->clsName
, extra
->cnsName
);
333 auto& v
= vmain(env
);
335 auto const args
= argGroup(env
, inst
)
336 .addr(rvmtl(), safe_cast
<int32_t>(link
.handle()))
337 .immPtr(NamedEntity::get(extra
->clsName
))
338 .immPtr(extra
->clsName
)
339 .immPtr(extra
->cnsName
);
341 cgCallHelper(v
, env
, CallSpec::direct(lookupClsCnsHelper
),
342 callDestTV(env
, inst
), SyncOptions::Sync
, args
);
344 markRDSHandleInitialized(v
, link
.handle());
347 ///////////////////////////////////////////////////////////////////////////////