Encapsulate return types of NvGet*() and GetValueRef()
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-cns.cpp
blob5ad0ba19d1fe3aed7acb5cf0601335fbc139edf9
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 +----------------------------------------------------------------------+
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);
60 auto& v = vmain(env);
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
81 // non-persistent.
82 if (!RuntimeOption::RepoAuthoritative) {
83 if (strcasecmp(cnsName->data(), "stdin") == 0 ||
84 strcasecmp(cnsName->data(), "stdout") == 0 ||
85 strcasecmp(cnsName->data(), "stderr") == 0) {
86 checkUninit();
89 return;
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]);
97 checkUninit();
98 } else {
99 // Statically known constant.
100 assertx(!dst.isFullSIMD());
101 switch (cns.m_type) {
102 case KindOfNull:
103 v << copy{v.cns(nullptr), dst.reg(0)};
104 break;
105 case KindOfBoolean:
106 v << copy{v.cns(!!cns.m_data.num), dst.reg(0)};
107 break;
108 case KindOfInt64:
109 case KindOfPersistentString:
110 case KindOfPersistentVec:
111 case KindOfPersistentDict:
112 case KindOfPersistentKeyset:
113 case KindOfPersistentArray:
114 case KindOfString:
115 case KindOfVec:
116 case KindOfDict:
117 case KindOfKeyset:
118 case KindOfArray:
119 case KindOfObject:
120 case KindOfResource:
121 case KindOfRef:
122 v << copy{v.cns(cns.m_data.num), dst.reg(0)};
123 break;
124 case KindOfDouble:
125 v << copy{v.cns(cns.m_data.dbl), dst.reg(0)};
126 break;
127 case KindOfUninit:
128 not_reached();
130 v << copy{v.cns(cns.m_type), dst.reg(1)};
134 ///////////////////////////////////////////////////////////////////////////////
136 ALWAYS_INLINE
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();
143 if (!cns) {
144 cns = Unit::loadCns(const_cast<StringData*>(nm));
146 return cns;
149 Cell lookupCnsHelper(StringData* nm, bool error) {
150 auto const cns = lookupCnsImpl(nm);
151 if (LIKELY(cns != nullptr)) {
152 Cell c1;
153 cellDup(*cns, c1);
154 return c1;
157 // Undefined constants.
158 if (error) {
159 raise_error("Undefined constant '%s'", nm->data());
160 } else {
161 raise_notice(Strings::UNDEFINED_CONSTANT, nm->data(), nm->data());
162 Cell c1;
163 c1.m_data.pstr = const_cast<StringData*>(nm);
164 c1.m_type = KindOfPersistentString;
165 return c1;
167 not_reached();
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)) {
179 Cell c1;
180 cellDup(*cns, c1);
181 return c1;
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)) {
201 Cell c1;
202 cellDup(*cns, c1);
203 return c1;
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)) {
223 Cell c1;
224 cellDup(*cns, c1);
225 return c1;
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)) {
242 cns = tv;
245 if (LIKELY(cns != nullptr)) {
246 Cell c1;
247 cellDup(*cns, c1);
248 return c1;
251 return lookupCnsHelper(fallback, false);
254 ///////////////////////////////////////////////////////////////////////////////
256 namespace {
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))
264 .immPtr(cnsName)
265 .imm(inst->is(LookupCnsE));
267 cgCallHelper(
268 vmain(env), env,
269 rds::isNormalHandle(ch)
270 ? CallSpec::direct(lookupCnsHelperNormal)
271 : CallSpec::direct(lookupCnsHelperPersistent),
272 callDestTV(env, inst),
273 SyncOptions::Sync,
274 args
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))
296 .immPtr(cnsName)
297 .immPtr(fallbackName);
299 cgCallHelper(
300 vmain(env), env,
301 rds::isNormalHandle(fallbackCh)
302 ? CallSpec::direct(lookupCnsUHelperNormal)
303 : CallSpec::direct(lookupCnsUHelperPersistent),
304 callDestTV(env, inst),
305 SyncOptions::Sync,
306 args
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);
327 return clsCns;
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 ///////////////////////////////////////////////////////////////////////////////