2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_MC_GENERATOR_INTERNAL_H_
17 #define incl_HPHP_MC_GENERATOR_INTERNAL_H_
19 #include <boost/filesystem.hpp>
20 #include <boost/utility/typed_in_place_factory.hpp>
22 #include "hphp/runtime/vm/jit/abi-x64.h"
23 #include "hphp/runtime/vm/jit/translator-inline.h"
24 #include "hphp/runtime/vm/jit/vasm-emit.h"
25 #include "hphp/runtime/vm/jit/vasm-instr.h"
26 #include "hphp/runtime/vm/jit/vasm-reg.h"
28 namespace HPHP
{ namespace jit
{
29 ///////////////////////////////////////////////////////////////////////////////
31 // Helper structs for jcc vs. jcc8.
33 static void branch(X64Assembler
& a
, ConditionCode cc
, TCA dest
) {
36 static void patch(X64Assembler
& a
, TCA site
, TCA newDest
) {
37 a
.patchJcc8(site
, newDest
);
42 static void branch(X64Assembler
& a
, ConditionCode cc
, TCA dest
) {
45 static void patch(X64Assembler
& a
, TCA site
, TCA newDest
) {
46 a
.patchJcc(site
, newDest
);
50 // A CondBlock is an RAII structure for emitting conditional code. It
51 // compares the source register at fieldOffset with fieldValue, and
52 // conditionally branches over the enclosing block of assembly on the
53 // passed-in condition-code.
57 // RefCountedOnly ifRefCounted(a, rdi, 0);
61 // will only execute emitIncRef if we find at runtime that rdi points at
62 // a ref-counted cell.
64 // It's ok to do reconcilable register operations in the body.
65 template<unsigned FieldOffset
, int32_t FieldValue
, ConditionCode Jcc
,
72 CondBlock(X64Assembler
& a
, PhysReg reg
, int offset
= 0)
75 int typeDisp
= m_off
+ FieldOffset
;
76 static_assert(sizeof(FieldType
) == 1 || sizeof(FieldType
) == 4,
77 "CondBlock of unimplemented field size");
78 if (sizeof(FieldType
) == 4) {
79 a
. cmpl(FieldValue
, reg
[typeDisp
]);
80 } else if (sizeof(FieldType
) == 1) {
81 a
. cmpb(FieldValue
, reg
[typeDisp
]);
83 m_jcc8
= a
.frontier();
89 m_a
.patchJcc8(m_jcc8
, m_a
.frontier());
94 // Emits if (IS_REFCOUNTED_TYPE()) { ... }
95 typedef CondBlock
<TVOFF(m_type
),
96 KindOfRefCountThreshold
,
98 DataType
> IfRefCounted
;
100 typedef CondBlock
<TVOFF(m_type
),
105 typedef CondBlock
<TVOFF(m_type
),
108 DataType
> UnlessUninit
;
113 * Helper code for stack frames. The struct is a "template" in the
114 * non-C++ sense: we don't build source-level stack frames in C++
115 * for the most part, but its offsets tell us where to find fields
118 * If we were physically pushing stack frames, we would push them
119 * in reverse order to what you see here.
122 locToRegDisp(int32_t localIndex
, PhysReg
*outbase
, int *outdisp
) {
123 *outdisp
= cellsToBytes(locPhysicalOffset(localIndex
));
124 *outbase
= x64::rVmFp
;
127 // Common code emission patterns.
129 static_assert(sizeof(DataType
) == 1,
130 "Your DataType has an unsupported size.");
131 static inline Reg8
toByte(const Reg32
& x
) { return rbyte(x
); }
132 static inline Reg8
toByte(const Reg64
& x
) { return rbyte(x
); }
133 static inline Reg8
toByte(PhysReg x
) { return rbyte(Reg64(x
)); }
135 static inline Reg32
toReg32(const Reg64
& x
) { return r32(x
); }
136 static inline Reg32
toReg32(const Reg8
& x
) { return r32(x
); }
137 static inline Reg32
toReg32(PhysReg x
) { return r32(Reg64(x
)); }
139 // For other operand types, let whatever conversions (or compile
140 // errors) exist handle it.
141 template<typename OpndType
>
142 static OpndType
toByte(const OpndType
& x
) { return x
; }
143 template<typename OpndType
>
144 static OpndType
toReg32(const OpndType
& x
) { return x
; }
146 template<typename OpndType
>
147 static inline void verifyTVOff(const OpndType
& op
) { /* nop */ }
148 static inline void verifyTVOff(MemoryRef mr
) {
149 DEBUG_ONLY
auto disp
= mr
.r
.disp
;
150 // Make sure that we're operating on the m_type field of a
152 assertx((disp
& (sizeof(TypedValue
) - 1)) == TVOFF(m_type
));
155 template<typename SrcType
, typename OpndType
>
156 void emitTestTVType(X64Assembler
& a
, SrcType src
, OpndType tvOp
) {
157 a
. testb(src
, toByte(tvOp
));
160 inline void emitTestTVType(Vout
& v
, Vreg sf
, Immed s0
, Vreg s1
) {
161 v
<< testbi
{s0
, s1
, sf
};
164 inline void emitTestTVType(Vout
& v
, Vreg sf
, Immed s0
, Vptr s1
) {
165 v
<< testbim
{s0
, s1
, sf
};
168 template<typename SrcType
, typename OpndType
>
170 emitLoadTVType(X64Assembler
& a
, SrcType src
, OpndType tvOp
) {
171 // Zero extend the type, just in case.
172 a
. loadzbl(src
, toReg32(tvOp
));
175 inline void emitLoadTVType(Vout
& v
, Vptr mem
, Vreg d
) {
176 v
<< loadzbq
{mem
, d
};
179 template<typename SrcType
, typename OpndType
>
180 void emitCmpTVType(X64Assembler
& a
, SrcType src
, OpndType tvOp
) {
181 a
. cmpb(src
, toByte(tvOp
));
184 inline void emitCmpTVType(Vout
& v
, Vreg sf
, Immed s0
, Vptr s1
) {
185 v
<< cmpbim
{s0
, s1
, sf
};
188 inline void emitCmpTVType(Vout
& v
, Vreg sf
, Immed s0
, Vreg s1
) {
189 v
<< cmpbi
{s0
, s1
, sf
};
192 template<typename DestType
, typename OpndType
>
193 void emitStoreTVType(X64Assembler
& a
, OpndType tvOp
, DestType dest
) {
194 a
. storeb(toByte(tvOp
), dest
);
197 inline void emitStoreTVType(Vout
& v
, Vreg src
, Vptr dest
) {
198 v
<< storeb
{src
, dest
};
202 emitStoreTVType(Vout
& v
, DataType src
, Vptr dest
) {
203 v
<< storebi
{src
, dest
};
207 // emitStoreTypedValue --
208 // emitStoreUninitNull --
210 // Helpers for common cell operations.
212 // Dereference the var in the cell whose address lives in src into
215 emitDeref(X64Assembler
&a
, PhysReg src
, PhysReg dest
) {
216 // src is a RefData, dest will be m_data field of inner gizmoom.
217 a
. loadq (src
[TVOFF(m_data
)], dest
);
220 // NB: leaves count field unmodified. Does not store to m_data if type
223 emitStoreTypedValue(X64Assembler
& a
, DataType type
, PhysReg val
,
224 int disp
, PhysReg dest
, bool writeType
= true) {
226 emitStoreTVType(a
, type
, dest
[disp
+ TVOFF(m_type
)]);
228 if (!IS_NULL_TYPE(type
)) {
229 assertx(val
!= InvalidReg
);
230 a
. storeq(val
, dest
[disp
+ TVOFF(m_data
)]);
235 emitStoreUninitNull(X64Assembler
& a
,
238 // OK to leave garbage in m_data, m_aux.
239 emitStoreTVType(a
, KindOfUninit
, dest
[disp
+ TVOFF(m_type
)]);
243 emitCopyTo(X64Assembler
& a
,
249 assertx(src
!= scratch
);
250 // This is roughly how gcc compiles this. Blow off m_aux.
251 a
. loadq (src
[srcOff
+ TVOFF(m_data
)], scratch
);
252 a
. storeq (scratch
, dest
[destOff
+ TVOFF(m_data
)]);
253 emitLoadTVType(a
, src
[srcOff
+ TVOFF(m_type
)], r32(scratch
));
254 emitStoreTVType(a
, r32(scratch
), dest
[destOff
+ TVOFF(m_type
)]);
257 ///////////////////////////////////////////////////////////////////////////////