Store num args instead of offset in prologue and func entry SrcKeys
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-object.cpp
blob346c1637b0bdda56c0062f8a26d4e53204ac1d83
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/memory-manager.h"
20 #include "hphp/runtime/base/object-data.h"
21 #include "hphp/runtime/base/tv-layout.h"
22 #include "hphp/runtime/vm/class.h"
24 #include "hphp/runtime/vm/jit/types.h"
25 #include "hphp/runtime/vm/jit/abi.h"
26 #include "hphp/runtime/vm/jit/arg-group.h"
27 #include "hphp/runtime/vm/jit/call-spec.h"
28 #include "hphp/runtime/vm/jit/code-gen-cf.h"
29 #include "hphp/runtime/vm/jit/code-gen-helpers.h"
30 #include "hphp/runtime/vm/jit/extra-data.h"
31 #include "hphp/runtime/vm/jit/ir-instruction.h"
32 #include "hphp/runtime/vm/jit/ir-opcode.h"
33 #include "hphp/runtime/vm/jit/ssa-tmp.h"
34 #include "hphp/runtime/vm/jit/translator-inline.h"
35 #include "hphp/runtime/vm/jit/vasm-gen.h"
36 #include "hphp/runtime/vm/jit/vasm-instr.h"
37 #include "hphp/runtime/vm/jit/vasm-reg.h"
38 #include "hphp/runtime/ext/std/ext_std_closure.h"
40 #include "hphp/util/trace.h"
42 namespace HPHP::jit::irlower {
44 TRACE_SET_MOD(irlower);
46 ///////////////////////////////////////////////////////////////////////////////
48 void cgLdObjClass(IRLS& env, const IRInstruction* inst) {
49 auto dst = dstLoc(env, inst, 0).reg();
50 auto obj = srcLoc(env, inst, 0).reg();
51 emitLdObjClass(vmain(env), obj, dst);
54 IMPL_OPCODE_CALL(AllocObj)
55 IMPL_OPCODE_CALL(AllocObjReified)
57 namespace {
59 void objectPropsRawInit(Vout& v, Vreg base, size_t props) {
60 if (props == 0) return;
62 if constexpr (std::is_same_v<ObjectProps, tv_layout::Tv7Up>) {
63 // Maintain 7-up invariant
64 auto const last_type_word_offset =
65 sizeof(ObjectData) +
66 8 * sizeof(uint64_t) * ((props - 1) / 7);
68 v << storeqi{0, base[last_type_word_offset]};
74 void cgNewInstanceRaw(IRLS& env, const IRInstruction* inst) {
75 auto& v = vmain(env);
76 auto const dst = dstLoc(env, inst, 0).reg();
77 auto const cls = inst->extra<NewInstanceRaw>()->cls;
79 assertx(!cls->getNativeDataInfo());
80 auto const memoSize =
81 cls->hasMemoSlots() ? ObjectData::objOffFromMemoNode(cls) : 0;
82 auto const size =
83 ObjectData::sizeForNProps(cls->numDeclProperties()) + memoSize;
84 auto const index = MemoryManager::size2Index(size);
85 auto const size_class = MemoryManager::sizeIndex2Size(index);
87 auto const target = [&]{
88 if (memoSize > 0) {
89 return size <= kMaxSmallSize
90 ? CallSpec::direct(&ObjectData::newInstanceRawMemoSmall)
91 : CallSpec::direct(&ObjectData::newInstanceRawMemoBig);
92 } else {
93 return size <= kMaxSmallSize
94 ? CallSpec::direct(&ObjectData::newInstanceRawSmall)
95 : CallSpec::direct(&ObjectData::newInstanceRawBig);
97 }();
99 auto args = argGroup(env, inst).immPtr(cls);
100 size <= kMaxSmallSize
101 ? args.imm(size_class).imm(index)
102 : args.imm(size);
103 if (memoSize > 0) args.imm(memoSize);
105 cgCallHelper(
107 env,
108 target,
109 callDest(dst),
110 SyncOptions::None,
111 args
113 objectPropsRawInit(v, dst, cls->numDeclProperties());
117 void cgConstructInstance(IRLS& env, const IRInstruction* inst) {
118 auto const dst = dstLoc(env, inst, 0).reg();
119 auto const cls = inst->extra<ConstructInstance>()->cls;
121 auto const args = argGroup(env, inst).immPtr(cls);
122 cgCallHelper(vmain(env), env,
123 CallSpec::direct(cls->instanceCtor<true>().get()),
124 callDest(dst), SyncOptions::Sync, args);
127 void cgConstructClosure(IRLS& env, const IRInstruction* inst) {
128 auto const dst = dstLoc(env, inst, 0).reg();
129 auto const cls = inst->extra<ConstructClosure>()->cls;
130 assertx(cls);
131 auto& v = vmain(env);
133 // c_Closure is not allowed to use the fast path, as the constructor will
134 // throw immediately. No other closure's constructor is able to throw, so we
135 // are able to make some optimizations that would be unsafe if unwinding.
136 if (!RuntimeOption::RepoAuthoritative || cls == c_Closure::classof()) {
137 auto const args = argGroup(env, inst).immPtr(cls);
138 cgCallHelper(vmain(env), env, CallSpec::direct(createClosure),
139 callDest(dst), SyncOptions::None, args);
140 } else {
141 auto const size = c_Closure::size(cls);
143 auto const index = MemoryManager::size2Index(size);
144 auto const size_class = MemoryManager::sizeIndex2Size(index);
146 // We don't specialize the large allocation case since it is unlikely.
147 auto const target = index < kNumSmallSizes
148 ? CallSpec::direct(&createClosureRepoAuthRawSmall)
149 : CallSpec::direct(&createClosureRepoAuth);
151 auto args = argGroup(env, inst).immPtr(cls);
152 if (index < kNumSmallSizes) {
153 args.imm(size_class).imm(index);
156 cgCallHelper(vmain(env), env, target,
157 callDest(dst), SyncOptions::None, args);
159 objectPropsRawInit(v, dst, cls->numDeclProperties());
162 if (inst->src(0)->isA(TNullptr)) {
163 v << storeqi{0, dst[c_Closure::ctxOffset()]};
164 } else {
165 auto const ctx = srcLoc(env, inst, 0).reg();
166 v << store{ctx, dst[c_Closure::ctxOffset()]};
170 IMPL_OPCODE_CALL(Clone)
172 IMPL_OPCODE_CALL(FuncCred);
174 ///////////////////////////////////////////////////////////////////////////////
176 namespace {
178 static void initObjMemoSlots(MemoSlot* slots, size_t n) {
179 for (auto i = 0; i < n; i++) {
180 slots[i].init();
184 void implInitObjPropsFast(Vout& v, IRLS& env, const IRInstruction* inst,
185 Vreg dst, const Class* cls, size_t nprops) {
186 // memcpy the values from the class property init vec.
187 auto args = argGroup(env, inst)
188 .addr(dst, safe_cast<int32_t>(sizeof(ObjectData)))
189 .imm(reinterpret_cast<uintptr_t>(cls->declPropInit().data()))
190 .imm(ObjectProps::sizeFor(nprops));
192 cgCallHelper(v, env, CallSpec::direct(memcpy),
193 kVoidDest, SyncOptions::None, args);
196 void implInitObjMemoSlots(Vout& v, IRLS& env, const IRInstruction* inst,
197 const Class* cls, Vreg obj) {
198 assertx(cls->hasMemoSlots());
199 assertx(!cls->getNativeDataInfo());
201 auto const nslots = cls->numMemoSlots();
202 if (nslots < 8) {
203 for (Slot i = 0; i < nslots; ++i) {
204 static_assert(sizeof(MemoSlot) == 16, "");
205 auto const offset = -(sizeof(MemoSlot) * (nslots - i));
206 auto const dt = static_cast<data_type_t>(KindOfUninit);
207 emitImmStoreq(v, 0, obj[offset + TVOFF(m_data)]);
208 v << storebi{dt, obj[offset + TVOFF(m_type)]};
210 return;
213 auto const args = argGroup(env, inst)
214 .addr(obj, -safe_cast<int32_t>(sizeof(MemoSlot) * nslots))
215 .imm(nslots);
216 cgCallHelper(v, env, CallSpec::direct(initObjMemoSlots),
217 kVoidDest, SyncOptions::None, args);
222 void cgInitObjMemoSlots(IRLS& env, const IRInstruction* inst) {
223 auto const cls = inst->extra<InitObjMemoSlots>()->cls;
224 auto const obj = srcLoc(env, inst, 0).reg();
225 auto& v = vmain(env);
227 implInitObjMemoSlots(v, env, inst, cls, obj);
230 void cgInitObjProps(IRLS& env, const IRInstruction* inst) {
231 auto const cls = inst->extra<InitObjProps>()->cls;
232 auto const obj = srcLoc(env, inst, 0).reg();
233 auto& v = vmain(env);
235 if (cls->hasMemoSlots()) implInitObjMemoSlots(v, env, inst, cls, obj);
237 // Initialize the properties.
238 auto const nprops = cls->numDeclProperties();
239 if (nprops > 0) {
240 if (cls->pinitVec().size() == 0) {
241 // If the Class has no 86pinit property-initializer functions, we can
242 // just copy the initial values from a data member on the Class.
243 implInitObjPropsFast(v, env, inst, obj, cls, nprops);
244 } else {
245 // Load the Class's propInitVec from the target cache. We know it's
246 // already been initialized as a pre-condition on this op.
247 auto const propHandle = cls->propHandle();
248 assertx(rds::isNormalHandle(propHandle));
250 markRDSAccess(v, propHandle);
252 auto const propInitVec = v.makeReg();
253 auto const propData = v.makeReg();
254 v << load{Vreg(rvmtl())[propHandle], propInitVec};
256 auto args = argGroup(env, inst)
257 .addr(obj, safe_cast<int32_t>(sizeof(ObjectData)));
259 if (!cls->hasDeepInitProps()) {
260 v << load{propInitVec[Class::PropInitVec::dataOff()], propData};
261 cgCallHelper(v, env, CallSpec::direct(memcpy), kVoidDest,
262 SyncOptions::None,
263 args
264 .reg(propData)
265 .imm(ObjectProps::sizeFor(nprops)));
266 } else {
267 cgCallHelper(v, env, CallSpec::direct(deepInitHelper),
268 kVoidDest, SyncOptions::None,
269 args.reg(propInitVec).imm(nprops));
275 void cgLockObj(IRLS& env, const IRInstruction* inst) {
276 auto const obj = srcLoc(env, inst, 0).reg();
277 auto& v = vmain(env);
278 auto const mask = ~static_cast<int8_t>(ObjectData::IsBeingConstructed);
279 v << andbim{mask, obj[HeaderAuxOffset], v.makeReg()};
282 ///////////////////////////////////////////////////////////////////////////////
284 void cgClassHasReifiedGenerics(IRLS& env, const IRInstruction* inst) {
285 auto const dst = dstLoc(env, inst, 0).reg();
286 auto const cls = srcLoc(env, inst, 0).reg();
288 auto& v = vmain(env);
289 auto const sf = v.makeReg();
291 v << testbim{(int32_t)Class::reifiedGenericsMask(), cls[Class::allFlagsOff()], sf};
292 v << setcc{CC_NZ, sf, dst};
295 void cgHasReifiedParent(IRLS& env, const IRInstruction* inst) {
296 auto const dst = dstLoc(env, inst, 0).reg();
297 auto const cls = srcLoc(env, inst, 0).reg();
299 auto& v = vmain(env);
300 auto const sf = v.makeReg();
302 v << testbim{(int32_t)Class::reifiedParentMask(), cls[Class::allFlagsOff()], sf};
303 v << setcc{CC_NZ, sf, dst};
306 IMPL_OPCODE_CALL(GetClsRGProp)
308 ///////////////////////////////////////////////////////////////////////////////