CACAO
CodeGenPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/CodeGenPass.cpp - CodeGenPass
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
33 
34 #include "toolbox/logging.hpp"
35 
36 #include "mm/codememory.hpp"
37 #include "vm/types.hpp"
39 #include "vm/jit/jit.hpp"
40 #include "vm/jit/methodtree.hpp"
41 
42 #include "vm/jit/disass.hpp"
43 
44 #include "mm/memory.hpp"
45 
46 #include "md.hpp"
47 
48 #include "vm/jit/replace.hpp"
49 
50 #define DEBUG_NAME "compiler2/CodeGen"
51 
52 STAT_DECLARE_VAR(std::size_t, compiler_last_codesize, 0)
53 STAT_DECLARE_VAR(std::size_t, num_remaining_moves,0)
54 
55 namespace cacao {
56 namespace jit {
57 namespace compiler2 {
58 
59 #ifdef ENABLE_LOGGING
60 Option<bool> CodeGenPass::print_code("PrintCodeSegment","compiler2: print code segment",false,::cacao::option::xx_root());
61 Option<bool> CodeGenPass::print_data("PrintDataSegment","compiler2: print data segment",false,::cacao::option::xx_root());
62 #endif
63 
64 bool CodeGenPass::run(JITData &JD) {
65  MachineInstructionSchedule *MIS = get_Pass<MachineInstructionSchedulingPass>();
66  CodeMemory *CM = JD.get_CodeMemory();
67  CodeSegment &CS = CM->get_CodeSegment();
69 
70  SSM->finalize();
71 
72  // NOTE reverse so we see jump targets (which are not backedges) before
73  // the jump.
74  MachineBasicBlock *MBB = NULL;
75  std::size_t bb_start = 0;
77  e = MIS->rend() ; i != e ; ++i ) {
78  MBB = *i;
79  bb_start = CS.size();
81  e = MBB->rend(); i != e ; ++i) {
82  MachineInstruction *MI = *i;
83  std::size_t start = CS.size();
84  LOG2("MInst: " << MI << " emitted instruction:" << nl);
85  MI->emit(CM);
86  std::size_t end = CS.size();
87  instruction_positions[MI] = start;
88  instruction_sizes[MI] = end - start;
89  #if defined(ENABLE_STATISTICS)
90  if (MI->is_move() && start != end) {
91  STATISTICS(++num_remaining_moves);
92  }
93  #endif
94  if (DEBUG_COND_N(2)) {
95  if ( start == end) {
96  LOG2("none" << nl);
97  } else {
99  while(start != end--) {
100  tmp.push_back(CS.at(end));
101  }
102  #if defined(ENABLE_DISASSEMBLER)
103  disassemble(&tmp.front(), &tmp.front() + tmp.size());
104  #else
105  // TODO print hex code
106  #endif
107  }
108  }
109  }
110  std::size_t bb_end = CS.size();
111  bbmap[MBB] = bb_end - bb_start;
112  }
113  assert(MBB != NULL);
114  // create stack frame
115  JD.get_Backend()->create_frame(CM,SSM);
116  // fix last block (frame start, alignment)
117  bbmap[MBB] = CS.size() - bb_start;
118  // finish
119  finish(JD);
120  return true;
121 }
122 
123 std::size_t CodeGenPass::get_block_size(MachineBasicBlock *MBB) const {
124  BasicBlockMap::const_iterator i = bbmap.find(MBB);
125  if (i == bbmap.end())
126  return 0;
127  return i->second;
128 }
129 
130 namespace {
131 
132 #ifdef ENABLE_LOGGING
133 void print_hex(OStream &OS, u1 *start, u1 *end, uint32_t num_bytes_per_line = 8) {
134  OS << hex;
135  for(u1 *ptr = start, *e = end; ptr < e; ++ptr) {
136  if ( (ptr - start) % num_bytes_per_line == 0) {
137  OS << nl << "0x" << setz(16) << (u8) ptr << ": ";
138  }
139  OS << setz(2) << *ptr << ' ';
140  }
141  OS << dec << nl;
142 }
143 #endif
144 
145 template<class OutputIt>
146 void find_all_replacement_points(MachineInstructionSchedule *MIS,
147  OutputIt outIterator) {
148  MachineBasicBlock *MBB = NULL;
149  for (MachineInstructionSchedule::const_iterator i = MIS->begin(),
150  e = MIS->end() ; i != e ; ++i ) {
151  MBB = *i;
152  for (MachineBasicBlock::const_iterator i = MBB->begin(),
153  e = MBB->end(); i != e ; ++i) {
154  MachineInstruction *MI = *i;
155  if (MI->to_MachineReplacementPointInst()) {
156  *outIterator = MI;
157  outIterator++;
158  }
159  }
160  }
161 }
162 
163 } // end anonymous namespace
164 
165 template<class ForwardIt>
166 void CodeGenPass::resolve_replacement_points(ForwardIt first, ForwardIt last, JITData &JD) {
167  codeinfo *code = JD.get_jitdata()->code;
168  CodeMemory *CM = JD.get_CodeMemory();
169  CodeSegment &CS = CM->get_CodeSegment();
170 
171  code->rplpointcount = std::distance(first, last);
172  code->rplpoints = MNEW(rplpoint, code->rplpointcount);
173 
174  rplpoint *rp = code->rplpoints;
175  for (ForwardIt i = first; i != last; i++) {
177  assert(MI);
178  std::size_t offset = CS.size() - instruction_positions[MI];
179 
180  u1 *position = code->entrypoint + offset;
181 
182  // initialize rplpoint structure
183  rp->method = JD.get_jitdata()->m;
184  rp->pc = position;
185  rp->regalloc = MNEW(rplalloc, MI->op_size());
186  rp->regalloccount = MI->op_size();
187  rp->flags = 0;
188  rp->id = MI->get_source_id();
189  rp->patch_target_addr = NULL;
190 
191  if (MI->to_MachineDeoptInst()) {
192  rp->flags |= rplpoint::FLAG_DEOPTIMIZE;
193  }
194 
196  rp->callsize = instruction_sizes[MI->to_MachineReplacementPointCallSiteInst()->get_call_inst()];
197 
199  DataSegment::IdxTy idx = MI->to_MachineReplacementPointStaticSpecialInst()->get_idx();
200  // The data and code segment were already copied,
201  // with the DataSegment directly starting at code->mcode
202  rp->patch_target_addr = code->mcode + idx.idx;
203  }
204  }
205 
206  // store allocation infos
207  rplalloc *ra = rp->regalloc;
208  int op_index = 0;
210  e = MI->end(); i != e; i++) {
211  MachineOperand *mop = i->op;
212 
213  ra->index = MI->get_javalocal_index(op_index);
214  ra->type = convert_to_type(mop->get_type());
215 
216  Register *reg = mop->to_Register();
217  if (reg) {
218  // the operand has been allocated to a register
219  MachineRegister *machine_reg = reg->to_MachineRegister();
220  assert(machine_reg);
221  ra->inmemory = false;
222 
223  // XXX The `regoff` member of the `rplalloc` structure has to
224  // store a register identifier that is compatible to those in
225  // vm/jit/TARGET/md-abi.hpp, which is part of the baseiline
226  // compiler. We somehow need to obtain such a register identifier
227  // from the compiler2's `MachineRegister`. It seems that
228  // `id_offset()` and `id_size()` can be used for this purpose,
229  // but we had to change their visibility from `protected` to
230  // `public`. Is this approach ok?
231  ra->regoff = machine_reg->id_offset() / machine_reg->id_size();
232  } else {
233  // the operand has been allocated to a stack slot
234  StackSlot *stack_slot = mop->to_StackSlot();
235  assert(stack_slot);
236  ra->inmemory = true;
237  ra->regoff = stack_slot->get_index();
238  }
239 
240  op_index++;
241  ra++;
242  }
243 
244  LOG("resolved replacement point " << rp << nl);
245 
246  rp++;
247  }
248 }
249 
250 void CodeGenPass::finish(JITData &JD) {
251  CodeMemory *CM = JD.get_CodeMemory();
252  CodeSegment &CS = CM->get_CodeSegment();
253  DataSegment &DS = CM->get_DataSegment();
254 #if 0
255  s4 alignedmcodelen;
256  jumpref *jr;
257  s4 alignedlen;
258 #endif
259  u1 *epoint;
260 
261  /* Get required compiler data. */
262 
263  codeinfo* code = JD.get_jitdata()->code;
264 #if 0
265  codegendata* cd = jd->cd;
266  registerdata* rd = jd->rd;
267 #endif
268 
269  /* Generate the method header. It simply contains a pointer to the
270  method's codeinfo structure that has to be placed at a fixed offset
271  from the end of the data segment (the offset is defined as
272  `CodeinfoPointer` in src/vm/jit/methodheader.hpp). For more info have
273  a look at the baseline compiler's `codegen_emit` function in
274  src/vm/jit/codegen-common.cpp. */
275 
276  DataFragment codeinfo_ptr = DS.get_Ref(sizeof(codeinfo *));
277  // TODO unify with `InstructionEncoding::imm`
278  for (int i = 0, e = sizeof(codeinfo *); i < e; i++) {
279  codeinfo_ptr[i] = (reinterpret_cast<u1*>(&code))[i];
280  }
281 
282  /* Link code memory */
283 
284  CM->link();
285 
286  /* calculate the code length */
287 
288  #if 0
289  s4 mcodelen = (s4) (JD.get_CodeMemory()->get_end() - JD.get_CodeMemory()->get_start());
290  s4 alignedmcodelen = MEMORY_ALIGN(mcodelen, MAX_ALIGN);
291  s4 dseglen = (s4) JD.get_CodeMemory()->data_size();
292  s4 aligneddseglen = MEMORY_ALIGN(dseglen, MAX_ALIGN);
293 
294 
295  s4 alignedlen = alignedmcodelen + aligneddseglen;
296  #endif
297 
298 #if 0
299  STATISTICS(count_code_len += mcodelen);
300  STATISTICS(count_data_len += cd->dseglen);
301 #endif
302 
303  /* allocate new memory */
304 
305  // Note that the DataSegment and the CodeSegment shall be aligned!
306  code->mcodelength = DS.size() + CS.size();
307  code->mcode = CNEW(u1, code->mcodelength);
308 
309  /* set the entrypoint of the method */
310 
311  assert(code->entrypoint == NULL);
312  code->entrypoint = epoint = (code->mcode + DS.size());
313 
314  /* fill the data segment (code->entrypoint must already be set!) */
315  MCOPY((void *) code->mcode, DS.get_start(), u1, DS.size());
316 
317  #if 0
318  size_t offset = 1;
319  /// @Cpp11 Could use vector::data()
320  for (CodeMemory::const_data_iterator i = JD.get_CodeMemory()->data_begin(),
321  e = JD.get_CodeMemory()->data_end() ; i != e; ++i) {
322  u1* ptr = epoint - offset++;
323  *ptr = *i;
324  LOG3("" << ptr
325  << ": " << hex << *i << " " << *ptr << dec << nl);
326  assert(ptr >= code->mcode);
327  }
328  #endif
329 
330  LOG2("mcode: " << code->mcode << nl);
331  LOG2("entry: " << code->entrypoint << nl);
332 
333  if (DEBUG_COND_N(2)) {
334  for(u8 *ptr = reinterpret_cast<u8*>(code->mcode),
335  *e = reinterpret_cast<u8*>(code->entrypoint); ptr < e; ++ptr) {
336  LOG2("" << setz(16) << hex << ptr
337  << ": " << setz(16) << (u8)*ptr << dec << nl);
338  }
339  }
340 
341  STATISTICS(compiler_last_codesize = code->mcodelength);
342 
343 #if 0
344  STATISTICS(count_code_len += mcodelen);
345  STATISTICS(count_data_len += cd->dseglen);
346 #endif
347 
348 
349 #if 0
350  dseg_finish(jd);
351 #endif
352 
353  /* copy code to the new location */
354 
355  CS.reverse();
356  MCOPY((void *) code->entrypoint, CS.get_start(), u1, CS.size());
357 
358  /* Fill runtime information about generated code. */
359 
360 #if 0
361  code->stackframesize = cd->stackframesize;
362  code->synchronizedoffset = rd->memuse * 8;
363  code->savedintcount = INT_SAV_CNT - rd->savintreguse;
364  code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse;
365 #else
367  code->synchronizedoffset = 0;
368  code->savedintcount = 0;
369  code->savedfltcount = 0;
370 #endif
371 #if defined(HAS_ADDRESS_REGISTER_FILE)
372  code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse;
373 #endif
374 
375 #if defined(__AARCH64__) || defined(__X86_64__)
376  // Since we use the EnterInst on method entry, the generated code saves the
377  // frame pointer (register RBP) of the calling method on the stack. We
378  // therefore have to provide an additional stack slot.
379  code->stackframesize++;
381 #endif
382 
383 #if defined(__AARCH64__)
384  // We do not handle leaf methods yet in the aarch64 compiler2 backend
385  // During replacement, assumptions are made on the stacklayout regarding
386  // leaf methods that do not hold up when using the compiler2 backend
388 
389  // On aarch64 the replacement code also assumes that the stacksize includes
390  // the return address
391  code->stackframesize++;
392 #endif
393 
394  /* Create the exception table. */
395 
396 #if 0
398 #endif
399 
400  /* Create the linenumber table. */
401 
402 #if 0
403  code->linenumbertable = new LinenumberTable(jd);
404 
405  /* jump table resolving */
406  for (jr = cd->jumpreferences; jr != NULL; jr = jr->next)
407  *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
408  (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
409 
410 #endif
411  /* patcher resolving */
412 
413  patcher_resolve(code);
414  LOG2("Patchers:" << nl);
415  #if !defined(NDEBUG)
416  DEBUG2(patcher_list_show(code));
417  #endif
418  /* replacement point resolving */
419  {
420  MInstListTy rplpoints;
421  MachineInstructionSchedule *MIS = get_Pass<MachineInstructionSchedulingPass>();
422  find_all_replacement_points(MIS, std::back_inserter(rplpoints));
423  resolve_replacement_points(rplpoints.begin(), rplpoints.end(), JD);
424  }
425 
426  /* Insert method into methodtree to find the entrypoint. */
427 
428  methodtree_insert(code->entrypoint, code->entrypoint + CS.size());
429 
430 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
431  /* resolve data segment references */
432 
433 #if 0
434  dseg_resolve_datareferences(jd);
435 #endif
436 #endif
437 
438  /* flush the instruction and data caches */
439 
440  md_cacheflush(code->mcode, code->mcodelength);
441 
442 #ifdef ENABLE_LOGGING
443  if (print_data) {
444  dbg() << nl << "Data Segment: " << *JD.get_Method() << hex;
445  print_hex(dbg(), code->mcode, code->entrypoint);
446  }
447  if (print_code) {
448  dbg() << nl << "Code Segment: " << *JD.get_Method() << hex;
449  print_hex(dbg(), code->entrypoint, code->mcode + code->mcodelength);
450  }
451 #endif
452 
453 }
454 
455 // pass usage
456 PassUsage& CodeGenPass::get_PassUsage(PassUsage &PU) const {
459  return PU;
460 }
461 
462 // registrate Pass
463 static PassRegistry<CodeGenPass> X("CodeGenPass");
464 
465 } // end namespace compiler2
466 } // end namespace jit
467 } // end namespace cacao
468 
469 
470 /*
471  * These are local overrides for various environment variables in Emacs.
472  * Please do not remove this and leave it at the end of the file, where
473  * Emacs will automagically detect them.
474  * ---------------------------------------------------------------------
475  * Local variables:
476  * mode: c++
477  * indent-tabs-mode: t
478  * c-basic-offset: 4
479  * tab-width: 4
480  * End:
481  * vim:noexpandtab:sw=4:ts=4:
482  */
basicblock * target
#define STATISTICS(x)
Wrapper for statistics only code.
Definition: statistics.hpp:975
reverse_iterator rbegin()
returns an reverse_iterator to the beginning
#define ra
Definition: md-asm.hpp:62
std::reverse_iterator< const_iterator > const_reverse_iterator
reverse_iterator rend()
returns an reverse_iterator to the end
Linenumber table of a Java method.
virtual void emit(CodeMemory *CM) const
emit machine code
uint8_t savedfltcount
Definition: code.hpp:90
void link()
Link instructions.
Definition: CodeMemory.cpp:75
int32_t stackframesize
Definition: code.hpp:87
jumpref * next
codeinfo * code
Definition: jit.hpp:128
A basic block of (scheduled) machine instructions.
u1 at(std::size_t i) const
get content
Definition: Segment.hpp:194
s4 mpc
Definition: jit.hpp:352
StackSlotManager * get_StackSlotManager()
Definition: JITData.hpp:56
int savintreguse
Definition: reg.hpp:88
void patcher_resolve(codeinfo *code)
Resolve all patchers in the current JIT run.
uint8_t u1
Definition: types.hpp:40
Represents a point in the program, where it is possible to recover the source state to perform on-sta...
static void code_unflag_leafmethod(codeinfo *code)
Definition: code.hpp:160
Hex hex
Definition: OStream.cpp:50
s4 mcodelength
Definition: code.hpp:84
std::size_t size() const
get size
Definition: Segment.hpp:153
#define DEBUG_COND_N(VERBOSE)
Definition: Debug.hpp:112
virtual MachineReplacementPointCallSiteInst * to_MachineReplacementPointCallSiteInst()
jitdata * get_jitdata() const
Definition: JITData.hpp:51
void md_cacheflush(u1 *addr, s4 nbytes)
Definition: md.c:49
const CodeSegment & get_CodeSegment() const
get CodeSegment
Definition: CodeMemory.hpp:65
void finalize()
Assigns each ManagedStackSlot a position in the virtual frame.
void(* functionptr)(void)
Definition: global.hpp:39
#define INT_SAV_CNT
Definition: md-abi.hpp:75
#define MCOPY(dest, src, type, num)
Definition: memory.hpp:103
u1 * mcode
Definition: code.hpp:82
void reverse()
reverse content
Definition: Segment.hpp:203
#define MAX_ALIGN
Definition: global.hpp:102
#define DEBUG2(STMT)
Definition: Debug.hpp:127
std::vector< MachineInstruction * > MInstListTy
Definition: CodeGenPass.hpp:58
Instruction::InstID tmp[]
Definition: Matcher.cpp:55
void patcher_list_show(codeinfo *code)
Show the content of the whole patcher reference list for debugging purposes.
CodeMemory * get_CodeMemory()
Definition: JITData.hpp:57
std::vector< T, Allocator< T > > type
Definition: vector.hpp:38
jumpref * jumpreferences
uint64_t u8
Definition: types.hpp:49
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
Simple stream class for formatted output.
Definition: OStream.hpp:141
Container::const_reverse_iterator const_reverse_iterator
virtual MachineReplacementPointInst * to_MachineReplacementPointInst()
#define MEMORY_ALIGN(pos, size)
Definition: memory.hpp:37
static void code_flag_using_frameptr(codeinfo *code)
Definition: code.hpp:199
void dseg_finish(jitdata *jd)
Definition: dseg.cpp:46
MIIterator i
#define LOG2(STMT)
Definition: logging.hpp:93
#define SIZE_OF_STACKSLOT
Definition: simplereg.cpp:80
int32_t s4
Definition: types.hpp:45
virtual MachineReplacementPointStaticSpecialInst * to_MachineReplacementPointStaticSpecialInst()
OStream & OS
virtual void create_frame(CodeMemory *CM, StackSlotManager *SSM) const =0
int savfltreguse
Definition: reg.hpp:91
#define LOG3(STMT)
Definition: logging.hpp:94
#define MNEW(type, num)
Definition: memory.hpp:96
MIIterator e
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
int convert_to_type(Type::TypeID type)
Convert a Type::TypeID to a Type.
Definition: Type.cpp:69
#define FLT_SAV_CNT
Definition: md-abi.hpp:82
Proxy to encode explicit and implicit successors.
void exceptiontable_create(jitdata *jd)
int memuse
Definition: reg.hpp:84
int32_t synchronizedoffset
Definition: code.hpp:88
methodinfo * m
Definition: jit.hpp:127
virtual MachineRegister * to_MachineRegister()
Operands that can be directly used by the machine (register, memory, stackslot)
LinenumberTable * linenumbertable
Definition: code.hpp:93
OptionPrefix & xx_root()
Definition: Option.cpp:39
reverse_iterator rbegin()
returns an reverse_iterator to the beginning
void methodtree_insert(void *startpc, void *endpc)
Definition: methodtree.cpp:148
void disassemble(u1 *start, u1 *end)
Definition: disass.cpp:403
Segment reference.
Definition: Segment.hpp:44
reverse_iterator rend()
returns an reverse_iterator to the end
u1 * get_start()
get start address
Definition: Segment.hpp:173
virtual IdentifyOffsetTy id_offset() const
uintptr_t ptrint
Definition: types.hpp:54
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
static SetZero setz(size_t w)
Definition: OStream.hpp:398
#define STAT_DECLARE_VAR(type, var, init)
Declare an external statistics variable.
Definition: statistics.hpp:963
virtual IdentifySizeTy id_size() const
Dec dec
Definition: OStream.cpp:48
Ref get_Ref(std::size_t t)
get a new reference to the segment
Definition: Segment.hpp:208
uint8_t savedintcount
Definition: code.hpp:89
OStream & dbg()
The default destination for logging messages.
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
const DataSegment & get_DataSegment() const
get DataSegment
Definition: CodeMemory.hpp:69
u1 * entrypoint
Definition: code.hpp:83
#define CNEW(type, num)
Definition: codememory.hpp:34