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/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
)
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
=
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
) {
76 auto const dst
= dstLoc(env
, inst
, 0).reg();
77 auto const cls
= inst
->extra
<NewInstanceRaw
>()->cls
;
79 assertx(!cls
->getNativeDataInfo());
81 cls
->hasMemoSlots() ? ObjectData::objOffFromMemoNode(cls
) : 0;
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
= [&]{
89 return size
<= kMaxSmallSize
90 ? CallSpec::direct(&ObjectData::newInstanceRawMemoSmall
)
91 : CallSpec::direct(&ObjectData::newInstanceRawMemoBig
);
93 return size
<= kMaxSmallSize
94 ? CallSpec::direct(&ObjectData::newInstanceRawSmall
)
95 : CallSpec::direct(&ObjectData::newInstanceRawBig
);
99 auto args
= argGroup(env
, inst
).immPtr(cls
);
100 size
<= kMaxSmallSize
101 ? args
.imm(size_class
).imm(index
)
103 if (memoSize
> 0) args
.imm(memoSize
);
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
;
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
);
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()]};
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 ///////////////////////////////////////////////////////////////////////////////
178 static void initObjMemoSlots(MemoSlot
* slots
, size_t n
) {
179 for (auto i
= 0; i
< n
; i
++) {
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();
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
)]};
213 auto const args
= argGroup(env
, inst
)
214 .addr(obj
, -safe_cast
<int32_t>(sizeof(MemoSlot
) * 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();
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
);
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
,
265 .imm(ObjectProps::sizeFor(nprops
)));
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 ///////////////////////////////////////////////////////////////////////////////