2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2016 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/containers.h"
18 #include "hphp/runtime/vm/jit/ir-opcode.h"
19 #include "hphp/runtime/vm/jit/trans-rec.h"
20 #include "hphp/runtime/vm/jit/vasm.h"
21 #include "hphp/runtime/vm/jit/vasm-instr.h"
22 #include "hphp/runtime/vm/jit/vasm-text.h"
23 #include "hphp/runtime/vm/jit/vasm-unit.h"
25 #include "hphp/util/data-block.h"
29 namespace HPHP
{ namespace jit
{
33 ///////////////////////////////////////////////////////////////////////////////
35 namespace vasm_detail
{
37 ///////////////////////////////////////////////////////////////////////////////
40 * Nouned verb class used to hide mostly-debug metadata updates from the main
41 * body of vasm_emit().
43 * This is invoked on every Vinstr encountered in order to accumulate mappings
44 * from higher-level representations.
46 struct IRMetadataUpdater
{
47 IRMetadataUpdater(const Venv
& env
, AsmInfo
* asm_info
);
50 * Update IR mappings for a Vinstr.
52 void register_inst(const Vinstr
& inst
);
55 * Update IR mappings at the end of a block.
57 void register_block_end();
60 * Update AsmInfo after the Vunit has been fully emitted.
62 void finish(const jit::vector
<Vlabel
>& labels
);
66 const IRInstruction
* origin
;
71 * Get HHIR mapping info for the current block in `m_env'.
73 jit::vector
<Snippet
>& block_info();
78 const IRInstruction
* m_origin
{nullptr};
79 jit::vector
<jit::vector
<jit::vector
<Snippet
>>> m_area_to_blockinfos
;
80 std::vector
<TransBCMapping
>* m_bcmap
{nullptr};
83 ///////////////////////////////////////////////////////////////////////////////
86 * Is `block' an empty catch block?
88 bool is_empty_catch(const Vblock
& block
);
91 * Register catch blocks for fixups.
93 void register_catch_block(const Venv
& env
, const Venv::LabelPatch
& p
);
96 * Emit a service request stub and register a patch point as needed.
98 void emit_svcreq_stub(Venv
& env
, const Venv::SvcReqPatch
& p
);
101 * Arch-independent emitters.
103 * Return true if the instruction was supported.
105 template<class Inst
> bool emit(Venv
& env
, const Inst
&) { return false; }
106 bool emit(Venv
& env
, const bindjmp
& i
);
107 bool emit(Venv
& env
, const bindjcc
& i
);
108 bool emit(Venv
& env
, const bindjcc1st
& i
);
109 bool emit(Venv
& env
, const bindaddr
& i
);
110 bool emit(Venv
& env
, const fallback
& i
);
111 bool emit(Venv
& env
, const fallbackcc
& i
);
112 bool emit(Venv
& env
, const retransopt
& i
);
114 ///////////////////////////////////////////////////////////////////////////////
118 ///////////////////////////////////////////////////////////////////////////////
120 template<class Vemit
>
121 void vasm_emit(const Vunit
& unit
, Vtext
& text
, CGMeta
& fixups
,
123 using namespace vasm_detail
;
125 Venv env
{ unit
, text
, fixups
};
126 env
.addrs
.resize(unit
.blocks
.size());
128 auto labels
= layoutBlocks(unit
, text
);
130 IRMetadataUpdater
irmu(env
, asm_info
);
132 auto const area_start
= [&] (Vlabel b
) {
133 auto area
= unit
.blocks
[b
].area_idx
;
134 return text
.area(area
).start
;
137 for (int i
= 0, n
= labels
.size(); i
< n
; ++i
) {
138 assertx(checkBlockEnd(unit
, labels
[i
]));
141 auto& block
= unit
.blocks
[b
];
143 env
.cb
= &text
.area(block
.area_idx
).code
;
144 env
.addrs
[b
] = env
.cb
->frontier();
146 { // Compute the next block we will emit into the current area.
147 auto const cur_start
= area_start(labels
[i
]);
149 while (j
< labels
.size() &&
150 cur_start
!= area_start(labels
[j
])) {
153 env
.next
= j
< labels
.size() ? labels
[j
] : Vlabel(unit
.blocks
.size());
157 // We'll replace exception edges to empty catch blocks with the catch
158 // helper unique stub.
159 if (is_empty_catch(block
)) continue;
161 for (auto& inst
: block
.code
) {
162 irmu
.register_inst(inst
);
165 #define O(name, imms, uses, defs) \
167 if (emit(env, inst.name##_)) break; \
168 Vemit(env).emit(inst.name##_); \
175 irmu
.register_block_end();
178 // Emit service request stubs and register patch points.
179 for (auto& p
: env
.stubs
) emit_svcreq_stub(env
, p
);
181 // Patch up jump targets and friends.
184 // Register catch blocks.
185 for (auto& p
: env
.catches
) register_catch_block(env
, p
);
187 if (unit
.padding
) Vemit::pad(text
.main().code
);
192 ///////////////////////////////////////////////////////////////////////////////