Remove dead includes in hphp/runtime/vm
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-cns.cpp
blob641b0e97d2ca8114be54814d87779383bb9fa88d
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/tv-mutate.h"
27 #include "hphp/runtime/base/tv-variant.h"
28 #include "hphp/runtime/base/type-variant.h"
29 #include "hphp/runtime/vm/named-entity.h"
30 #include "hphp/runtime/vm/unit.h"
32 #include "hphp/runtime/vm/jit/types.h"
33 #include "hphp/runtime/vm/jit/abi.h"
34 #include "hphp/runtime/vm/jit/arg-group.h"
35 #include "hphp/runtime/vm/jit/call-spec.h"
36 #include "hphp/runtime/vm/jit/cls-cns-profile.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);
59 assertx(rds::isHandleBound(ch));
60 auto const dst = dstLoc(env, inst, 0);
61 auto& v = vmain(env);
62 assertx(inst->taken());
64 auto checkUninit = [&] {
65 auto const sf = v.makeReg();
66 irlower::emitTypeTest(
67 v, env, TUninit, dst.reg(1), dst.reg(0), sf,
68 [&] (ConditionCode cc, Vreg sfr) {
69 fwdJcc(v, env, cc, sfr, inst->taken());
74 if (rds::isNormalHandle(ch)) {
75 auto const sf = checkRDSHandleInitialized(v, ch);
76 fwdJcc(v, env, CC_NE, sf, inst->taken());
77 loadTV(v, inst->dst(), dst, rvmtl()[ch]);
79 // When a CLIServer is active requests running in script mode will define
80 // the stdio constants which require lookup via special callbacks. To not
81 // interfere with the server these constants will be defined as
82 // non-persistent.
83 if (!RuntimeOption::RepoAuthoritative) {
84 if (strcasecmp(cnsName->data(), "stdin") == 0 ||
85 strcasecmp(cnsName->data(), "stdout") == 0 ||
86 strcasecmp(cnsName->data(), "stderr") == 0) {
87 checkUninit();
90 return;
93 auto const pcns = rds::handleToPtr<TypedValue, rds::Mode::Persistent>(ch);
95 if (pcns->m_type == KindOfUninit) {
96 loadTV(v, inst->dst(), dst, *v.cns(pcns));
97 checkUninit();
98 } else {
99 // Statically known constant.
100 assertx(!dst.isFullSIMD());
101 switch (pcns->m_type) {
102 case KindOfNull:
103 v << copy{v.cns(nullptr), dst.reg(0)};
104 break;
105 case KindOfBoolean:
106 v << copy{v.cns(!!pcns->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 KindOfFunc:
122 case KindOfClass:
123 case KindOfClsMeth:
124 case KindOfRecord:
125 v << copy{v.cns(pcns->m_data.num), dst.reg(0)};
126 break;
127 case KindOfDouble:
128 v << copy{v.cns(pcns->m_data.dbl), dst.reg(0)};
129 break;
130 case KindOfUninit:
131 not_reached();
133 v << copy{v.cns(pcns->m_type), dst.reg(1)};
137 ///////////////////////////////////////////////////////////////////////////////
139 ALWAYS_INLINE
140 tv_rval lookupCnsImpl(StringData* nm) {
141 tv_rval cns;
143 if (UNLIKELY(rds::s_constants().get() != nullptr)) {
144 cns = rds::s_constants()->rval(nm);
146 if (!cns) {
147 cns = Unit::loadCns(const_cast<StringData*>(nm));
149 return cns;
152 Cell lookupCnsEHelper(StringData* nm) {
153 auto const cns = lookupCnsImpl(nm);
154 if (LIKELY(cns != nullptr)) {
155 Cell c1;
156 cellDup(*cns, c1);
157 return c1;
159 raise_error("Undefined constant '%s'", nm->data());
162 Cell lookupCnsEHelperNormal(rds::Handle tv_handle,
163 StringData* nm) {
164 assertx(rds::isNormalHandle(tv_handle));
165 if (UNLIKELY(rds::isHandleInit(tv_handle))) {
166 auto const tv = rds::handleToPtr<TypedValue, rds::Mode::Normal>(tv_handle);
167 if (tv->m_data.pcnt != nullptr) {
168 auto callback = (Native::ConstantCallback)(tv->m_data.pcnt);
169 const Cell* cns = callback().asTypedValue();
170 if (LIKELY(cns->m_type != KindOfUninit)) {
171 Cell c1;
172 cellDup(*cns, c1);
173 return c1;
177 assertx(!rds::isHandleInit(tv_handle));
179 return lookupCnsEHelper(nm);
182 Cell lookupCnsEHelperPersistent(rds::Handle tv_handle,
183 StringData* nm) {
184 assertx(rds::isPersistentHandle(tv_handle));
185 auto tv = rds::handleToPtr<TypedValue, rds::Mode::Persistent>(tv_handle);
186 assertx(tv->m_type == KindOfUninit);
188 // Deferred system constants.
189 if (UNLIKELY(tv->m_data.pcnt != nullptr)) {
190 auto callback = (Native::ConstantCallback)(tv->m_data.pcnt);
191 const Cell* cns = callback().asTypedValue();
192 if (LIKELY(cns->m_type != KindOfUninit)) {
193 Cell c1;
194 cellDup(*cns, c1);
195 return c1;
198 return lookupCnsEHelper(nm);
201 ///////////////////////////////////////////////////////////////////////////////
203 void cgLookupCnsE(IRLS& env, const IRInstruction* inst) {
204 auto const cnsName = inst->src(0)->strVal();
205 auto const ch = makeCnsHandle(cnsName);
206 assertx(rds::isHandleBound(ch));
208 auto const args = argGroup(env, inst)
209 .imm(ch)
210 .immPtr(cnsName);
212 cgCallHelper(
213 vmain(env), env,
214 rds::isNormalHandle(ch)
215 ? CallSpec::direct(lookupCnsEHelperNormal)
216 : CallSpec::direct(lookupCnsEHelperPersistent),
217 callDestTV(env, inst),
218 SyncOptions::Sync,
219 args
223 ///////////////////////////////////////////////////////////////////////////////
225 void cgLdClsCns(IRLS& env, const IRInstruction* inst) {
226 auto const extra = inst->extra<LdClsCns>();
227 auto const link = rds::bindClassConstant(extra->clsName, extra->cnsName);
228 auto const dst = dstLoc(env, inst, 0).reg();
229 auto& v = vmain(env);
231 auto const sf = checkRDSHandleInitialized(v, link.handle());
232 fwdJcc(v, env, CC_NE, sf, inst->taken());
233 v << lea{rvmtl()[link.handle()], dst};
236 void cgLdSubClsCns(IRLS& env, const IRInstruction* inst) {
237 auto const extra = inst->extra<LdSubClsCns>();
238 auto const dst = dstLoc(env, inst, 0).reg();
239 auto& v = vmain(env);
241 auto const slot = extra->slot;
242 auto const tmp = v.makeReg();
243 v << load{srcLoc(env, inst, 0).reg()[Class::constantsVecOff()], tmp};
244 v << lea{tmp[slot * sizeof(Class::Const) + offsetof(Class::Const, val)], dst};
247 void cgLdSubClsCnsClsName(IRLS& env, const IRInstruction* inst) {
248 auto const extra = inst->extra<LdSubClsCnsClsName>();
249 auto const dst = dstLoc(env, inst, 0).reg();
250 auto& v = vmain(env);
252 auto const slot = extra->slot;
253 auto const tmp = v.makeReg();
254 v << load{srcLoc(env, inst, 0).reg()[Class::constantsVecOff()], tmp};
255 #ifndef USE_LOWPTR
256 auto const offset = tmp[slot * sizeof(Class::Const) +
257 offsetof(Class::Const, pointedClsName)];
258 v << load{offset, dst};
259 #else
260 auto const rawData = v.makeReg();
261 auto const offset = tmp[slot * sizeof(Class::Const) +
262 offsetof(Class::Const, val) +
263 offsetof(TypedValue, m_aux)];
264 v << loadzlq{offset, rawData};
265 v << andqi{static_cast<int32_t>(ConstModifiers::kMask), rawData,
266 dst, v.makeReg()};
267 #endif
270 void cgCheckSubClsCns(IRLS& env, const IRInstruction* inst) {
271 auto const extra = inst->extra<CheckSubClsCns>();
272 auto& v = vmain(env);
274 auto const slot = extra->slot;
275 auto const tmp = v.makeReg();
276 auto const sf = v.makeReg();
277 v << load{srcLoc(env, inst, 0).reg()[Class::constantsVecOff()], tmp};
278 emitCmpLowPtr<StringData>(v, sf, v.cns(extra->cnsName),
279 tmp[slot * sizeof(Class::Const) +
280 offsetof(Class::Const, name)]);
281 fwdJcc(v, env, CC_NE, sf, inst->taken());
284 void cgLdClsCnsVecLen(IRLS& env, const IRInstruction* inst) {
285 auto const dst = dstLoc(env, inst, 0).reg();
286 auto const cls = srcLoc(env, inst, 0).reg();
287 auto& v = vmain(env);
289 auto const off = Class::constantsVecLenOff();
291 static_assert(
292 Class::constantsVecLenSize() == 4,
293 "Class::constantsVecLenSize() must be 4 bytes "
294 "(if you changed it, fix the following code)");
296 v << loadzlq{cls[off], dst};
299 void cgProfileSubClsCns(IRLS& env, const IRInstruction* inst) {
300 auto const extra = inst->extra<ProfileSubClsCns>();
302 auto const args = argGroup(env, inst)
303 .addr(rvmtl(), safe_cast<int32_t>(extra->handle))
304 .ssa(0)
305 .imm(extra->cnsName);
307 auto const dst = dstLoc(env, inst, 0).reg();
309 cgCallHelper(vmain(env), env, CallSpec::method(&ClsCnsProfile::reportClsCns),
310 callDest(dst), SyncOptions::None, args);
314 Cell lookupClsCnsHelper(TypedValue* cache, const NamedEntity* ne,
315 const StringData* cls, const StringData* cns) {
316 auto const clsCns = g_context->lookupClsCns(ne, cls, cns);
317 cellDup(clsCns, *cache);
318 return clsCns;
321 void cgInitClsCns(IRLS& env, const IRInstruction* inst) {
322 auto const extra = inst->extra<InitClsCns>();
323 auto const link = rds::bindClassConstant(extra->clsName, extra->cnsName);
324 assertx(link.isNormal());
325 auto& v = vmain(env);
327 auto const args = argGroup(env, inst)
328 .addr(rvmtl(), safe_cast<int32_t>(link.handle()))
329 .immPtr(NamedEntity::get(extra->clsName))
330 .immPtr(extra->clsName)
331 .immPtr(extra->cnsName);
333 cgCallHelper(v, env, CallSpec::direct(lookupClsCnsHelper),
334 callDestTV(env, inst), SyncOptions::Sync, args);
336 markRDSHandleInitialized(v, link.handle());
339 void cgLdTypeCns(IRLS& env, const IRInstruction* inst) {
340 auto const cns = srcLoc(env, inst, 0).reg();
341 auto const ret = dstLoc(env, inst, 0).reg();
343 auto& v = vmain(env);
344 auto const sf = v.makeReg();
345 v << testqi{0x1, cns, sf};
346 fwdJcc(v, env, CC_Z, sf, inst->taken());
347 v << xorqi{0x1, cns, ret, v.makeReg()};
350 static ArrayData* loadClsTypeCnsHelper(
351 const Class* cls, const StringData* name
353 auto typeCns = cls->clsCnsGet(name, ClsCnsLookup::IncludeTypes);
354 if (typeCns.m_type == KindOfUninit) {
355 if (cls->hasTypeConstant(name, true)) {
356 raise_error("Type constant %s::%s is abstract",
357 cls->name()->data(), name->data());
358 } else {
359 raise_error("Non-existent type constant %s::%s",
360 cls->name()->data(), name->data());
364 assertx(isArrayLikeType(typeCns.m_type));
365 assertx(typeCns.m_data.parr->isDictOrDArray());
366 assertx(typeCns.m_data.parr->isStatic());
367 return typeCns.m_data.parr;
370 const StaticString s_classname("classname");
372 static StringData* loadClsTypeCnsClsNameHelper(const Class* cls,
373 const StringData* name) {
374 auto const ts = loadClsTypeCnsHelper(cls, name);
375 if (auto const classname_field = ts->rval(s_classname.get())) {
376 assertx(isStringType(classname_field.type()));
377 return classname_field.val().pstr;
379 raise_error("Type constant %s::%s does not have a 'classname' field",
380 cls->name()->data(), name->data());
383 void cgLdClsTypeCns(IRLS& env, const IRInstruction* inst) {
384 auto const args = argGroup(env, inst).ssa(0).ssa(1);
385 cgCallHelper(vmain(env), env, CallSpec::direct(loadClsTypeCnsHelper),
386 callDest(env, inst), SyncOptions::Sync, args);
389 void cgLdClsTypeCnsClsName(IRLS& env, const IRInstruction* inst) {
390 auto const args = argGroup(env, inst).ssa(0).ssa(1);
391 cgCallHelper(vmain(env), env, CallSpec::direct(loadClsTypeCnsClsNameHelper),
392 callDest(env, inst), SyncOptions::Sync, args);
395 ///////////////////////////////////////////////////////////////////////////////