Remove dead includes in hphp/runtime/vm
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-lookup-method.cpp
blob1ad38343dd317738ce25bc2ac67e81b496b52d55
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/object-data.h"
22 #include "hphp/runtime/base/rds.h"
23 #include "hphp/runtime/base/runtime-option.h"
24 #include "hphp/runtime/base/typed-value.h"
26 #include "hphp/runtime/vm/act-rec.h"
27 #include "hphp/runtime/vm/func.h"
28 #include "hphp/runtime/vm/interp-helpers.h"
29 #include "hphp/runtime/vm/method-lookup.h"
31 #include "hphp/runtime/vm/jit/types.h"
32 #include "hphp/runtime/vm/jit/abi.h"
33 #include "hphp/runtime/vm/jit/arg-group.h"
34 #include "hphp/runtime/vm/jit/bc-marker.h"
35 #include "hphp/runtime/vm/jit/call-spec.h"
36 #include "hphp/runtime/vm/jit/code-gen-cf.h"
37 #include "hphp/runtime/vm/jit/code-gen-helpers.h"
38 #include "hphp/runtime/vm/jit/extra-data.h"
39 #include "hphp/runtime/vm/jit/ir-instruction.h"
40 #include "hphp/runtime/vm/jit/ir-opcode.h"
41 #include "hphp/runtime/vm/jit/meth-profile.h"
42 #include "hphp/runtime/vm/jit/ssa-tmp.h"
43 #include "hphp/runtime/vm/jit/target-cache.h"
44 #include "hphp/runtime/vm/jit/translator-inline.h"
45 #include "hphp/runtime/vm/jit/type.h"
46 #include "hphp/runtime/vm/jit/vasm-gen.h"
47 #include "hphp/runtime/vm/jit/vasm-instr.h"
48 #include "hphp/runtime/vm/jit/vasm-reg.h"
50 #include "hphp/util/asm-x64.h"
51 #include "hphp/util/trace.h"
53 namespace HPHP { namespace jit { namespace irlower {
55 TRACE_SET_MOD(irlower);
57 ///////////////////////////////////////////////////////////////////////////////
60 * The `mcprep' instruction here creates a smashable move, which serves as
61 * the inline cache, or "prime cache" for the method lookup.
63 * On our first time through this codepath in the TC, we "prime" this cache
64 * (which holds across /all/ requests) by smashing the mov immediate to hold
65 * a Func* in the upper 32 bits, and a Class* in the lower 32 bits. This is
66 * not always possible (see MethodCache::handleStaticCall() for details), in
67 * which case we smash an immediate with some low bits set, so that we always
68 * miss on the inline cache when comparing against our live Class*.
70 * The inline cache is set up so that we always miss initially, and take the
71 * slow path to initialize it. After initialization, the slow path uses the
72 * out-of-line method cache (allocated above). The inline cache is set only
73 * during the first call(s) (usually once), but the one-way request-local
74 * method cache is updated on each miss.
76 void cgLdSmashable(IRLS& env, const IRInstruction* inst) {
77 auto const dst = dstLoc(env, inst, 0).reg();
78 auto& v = vmain(env);
79 v << mcprep{dst};
82 void cgCheckSmashableClass(IRLS& env, const IRInstruction* inst) {
83 auto const smashable = srcLoc(env, inst, 0).reg();
84 auto const cls = srcLoc(env, inst, 1).reg();
85 auto& v = vmain(env);
87 auto const tmp = v.makeReg();
88 auto const smashableCls = v.makeReg();
89 v << movtql{smashable, tmp};
90 v << movzlq{tmp, smashableCls};
92 auto const sf = v.makeReg();
93 v << cmpq{smashableCls, cls, sf};
94 v << jcc{CC_NE, sf, {label(env, inst->next()), label(env, inst->taken())}};
97 void cgLdSmashableFunc(IRLS& env, const IRInstruction* inst) {
98 auto const smashable = srcLoc(env, inst, 0).reg();
99 auto const dst = dstLoc(env, inst, 0).reg();
100 auto& v = vmain(env);
102 v << shrqi{32, smashable, dst, v.makeReg()};
105 void cgLdObjMethodD(IRLS& env, const IRInstruction* inst) {
106 assertx(inst->taken() && inst->taken()->isCatch()); // must have catch block
108 auto const target = CallSpec::direct(MethodCache::handleDynamicCall);
109 auto const args = argGroup(env, inst)
110 .ssa(0 /* cls */)
111 .ssa(1 /* methodName */)
112 .immPtr(inst->marker().func()->cls());
114 auto& v = vmain(env);
115 cgCallHelper(v, env, target, callDest(env, inst), SyncOptions::Sync, args);
118 void cgLdObjMethodS(IRLS& env, const IRInstruction* inst) {
119 assertx(inst->taken() && inst->taken()->isCatch()); // must have catch block
120 using namespace MethodCache;
122 // Allocate the request-local one-way method cache for this lookup.
123 auto const handle =
124 rds::alloc<Entry, rds::Mode::Normal, sizeof(Entry)>().handle();
125 if (RuntimeOption::EvalPerfDataMap) {
126 rds::recordRds(handle, sizeof(TypedValue), "MethodCache",
127 inst->marker().func()->fullName()->slice());
130 auto const target = CallSpec::direct(MethodCache::handleStaticCall);
131 auto const args = argGroup(env, inst)
132 .ssa(0 /* cls */)
133 .immPtr(inst->extra<FuncNameData>()->name)
134 .immPtr(inst->marker().func()->cls())
135 .imm(safe_cast<int32_t>(handle))
136 .ssa(1 /* smashable */);
138 auto& v = vmain(env);
139 cgCallHelper(v, env, target, callDest(env, inst), SyncOptions::Sync, args);
142 ///////////////////////////////////////////////////////////////////////////////
144 IMPL_OPCODE_CALL(LdClsCtor)
145 IMPL_OPCODE_CALL(LookupClsMethod)
147 void cgProfileMethod(IRLS& env, const IRInstruction* inst) {
148 auto const extra = inst->extra<ProfileCallTargetData>();
150 auto const args = argGroup(env, inst)
151 .addr(rvmtl(), safe_cast<int32_t>(extra->handle))
152 .ssa(0)
153 .ssa(1);
155 cgCallHelper(vmain(env), env, CallSpec::method(&MethProfile::reportMeth),
156 kVoidDest, SyncOptions::None, args);
159 ///////////////////////////////////////////////////////////////////////////////
161 namespace {
163 const char* ctxName(const BCMarker& marker) {
164 auto const ctx = marker.func()->cls();
165 return ctx ? ctx->name()->data() : ":anonymous:";
170 ///////////////////////////////////////////////////////////////////////////////
172 void cgLookupClsMethodCache(IRLS& env, const IRInstruction* inst) {
173 auto const extra = inst->extra<ClsMethodData>();
174 auto const dst = dstLoc(env, inst, 0).reg();
175 auto const fp = srcLoc(env, inst, 0).reg();
176 auto& v = vmain(env);
178 auto const ch = StaticMethodCache::alloc(
179 extra->clsName,
180 extra->methodName,
181 ctxName(inst->marker())
184 if (false) { // typecheck
185 UNUSED TypedValue* fake_fp = nullptr;
186 const UNUSED Func* f = StaticMethodCache::lookup(
188 extra->namedEntity,
189 extra->clsName,
190 extra->methodName,
191 fake_fp
195 auto const args = argGroup(env, inst)
196 .imm(ch)
197 .immPtr(extra->namedEntity)
198 .immPtr(extra->clsName)
199 .immPtr(extra->methodName)
200 .reg(fp);
202 // May raise an error if the class is undefined.
203 cgCallHelper(v, env, CallSpec::direct(StaticMethodCache::lookup),
204 callDest(dst), SyncOptions::Sync, args);
207 void cgLdClsMethodCacheFunc(IRLS& env, const IRInstruction* inst) {
208 auto const extra = inst->extra<ClsMethodData>();
209 auto const dst = dstLoc(env, inst, 0).reg();
210 auto& v = vmain(env);
212 auto const ch = StaticMethodCache::alloc(
213 extra->clsName,
214 extra->methodName,
215 ctxName(inst->marker())
218 auto const sf = checkRDSHandleInitialized(v, ch);
219 fwdJcc(v, env, CC_NE, sf, inst->taken());
220 emitLdLowPtr(v, rvmtl()[ch + offsetof(StaticMethodCache, m_func)],
221 dst, sizeof(LowPtr<const Func>));
224 void cgLdClsMethodCacheCls(IRLS& env, const IRInstruction* inst) {
225 auto const extra = inst->extra<ClsMethodData>();
226 auto const dst = dstLoc(env, inst, 0).reg();
227 auto& v = vmain(env);
229 auto const ch = StaticMethodCache::alloc(
230 extra->clsName,
231 extra->methodName,
232 ctxName(inst->marker())
234 assertx(rds::isNormalHandle(ch));
236 // The StaticMethodCache here is guaranteed to already be initialized in RDS
237 // by the pre-conditions of this instruction.
238 emitLdLowPtr(v, rvmtl()[ch + offsetof(StaticMethodCache, m_cls)],
239 dst, sizeof(LowPtr<const Class>));
242 void cgLookupClsMethodFCache(IRLS& env, const IRInstruction* inst) {
243 auto const extra = inst->extra<ClsMethodData>();
244 auto const dst = dstLoc(env, inst, 0).reg(0);
245 auto const cls = inst->src(0)->clsVal();
246 auto const fp = srcLoc(env, inst, 1).reg();
247 auto& v = vmain(env);
249 auto const ch = StaticMethodFCache::alloc(
250 cls->name(),
251 extra->methodName,
252 ctxName(inst->marker())
254 assertx(rds::isNormalHandle(ch));
256 const Func* (*lookup)(rds::Handle, const Class*,
257 const StringData*, TypedValue*) =
258 StaticMethodFCache::lookup;
260 auto const args = argGroup(env, inst)
261 .imm(ch)
262 .immPtr(cls)
263 .immPtr(extra->methodName)
264 .reg(fp);
266 cgCallHelper(v, env, CallSpec::direct(lookup),
267 callDest(dst), SyncOptions::Sync, args);
270 void cgLdClsMethodFCacheFunc(IRLS& env, const IRInstruction* inst) {
271 auto const extra = inst->extra<ClsMethodData>();
272 auto const dst = dstLoc(env, inst, 0).reg();
273 auto& v = vmain(env);
275 auto const ch = StaticMethodFCache::alloc(
276 extra->clsName,
277 extra->methodName,
278 ctxName(inst->marker())
280 assertx(rds::isNormalHandle(ch));
282 auto const sf = checkRDSHandleInitialized(v, ch);
283 fwdJcc(v, env, CC_NE, sf, inst->taken());
284 emitLdLowPtr(v, rvmtl()[ch + offsetof(StaticMethodFCache, m_func)],
285 dst, sizeof(LowPtr<const Func>));
288 ///////////////////////////////////////////////////////////////////////////////