CACAO
inline.cpp
Go to the documentation of this file.
1 /* src/vm/jit/inline/inline.cpp - method inlining
2 
3  Copyright (C) 1996-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 
25 
26 #include "config.h"
27 
28 #include <assert.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "vm/types.hpp"
34 
35 #include "mm/dumpmemory.hpp"
36 
37 #include "threads/lock.hpp"
38 #include "threads/mutex.hpp"
39 #include "threads/thread.hpp"
40 
41 #include "toolbox/logging.hpp"
42 
43 #include "vm/class.hpp"
44 #include "vm/descriptor.hpp" // for typedesc, methoddesc, etc
45 #include "vm/global.hpp"
46 #include "vm/initialize.hpp"
47 #include "vm/method.hpp"
48 #include "vm/options.hpp"
49 #include "vm/statistics.hpp"
50 
51 #include "vm/jit/builtin.hpp"
52 #include "vm/jit/code.hpp"
53 #include "vm/jit/jit.hpp"
54 #include "vm/jit/parse.hpp"
55 #include "vm/jit/reg.hpp"
56 #include "vm/jit/show.hpp"
57 #include "vm/jit/stack.hpp"
58 
59 #include "vm/jit/inline/inline.hpp"
60 #include "vm/jit/loop/loop.hpp"
61 
63 
65 
66 
67 /* algorithm tuning constants *************************************************/
68 
69 /* Algorithm Selection */
70 /* Define exactly one of the following three to select the inlining */
71 /* heuristics. */
72 
73 /*#define INLINE_DEPTH_FIRST*/
74 /*#define INLINE_BREADTH_FIRST*/
75 #define INLINE_KNAPSACK
76 
77 /* Parameters for knapsack heuristics: */
78 
79 #if defined(INLINE_KNAPSACK)
80 
81 #define INLINE_COUNTDOWN_INIT 1000
82 #define INLINE_COST_OFFSET -16
83 #define INLINE_COST_BUDGET 100
84 /*#define INLINE_WEIGHT_BUDGET 5.0*/
85 /*#define INLINE_ADD_NEGATIVE_TO_BUDGET*/
86 /*#define INLINE_MAX_DEPTH 3*/
87 /*#define INLINE_DIVIDE_COST_BY_FREQ */
88 
89 #endif
90 
91 /* Parameters for depth-first heuristics: */
92 
93 #if defined(INLINE_DEPTH_FIRST)
94 
95 #define INLINE_MAX_DEPTH 3
96 #define INLINE_MAX_BLOCK_EXPANSION 10
97 /*#define INLINE_MAX_ICMD_EXPANSION 10*/
98 /*#define INLINE_CANCEL_ON_THRESHOLD*/
99 
100 #endif
101 
102 /* Parameters for breadth-first heuristics: */
103 
104 #if defined(INLINE_BREADTH_FIRST)
105 
106 /*#define INLINE_MAX_BLOCK_EXPANSION 10*/
107 #define INLINE_MAX_ICMD_EXPANSION 5
108 
109 #endif
110 
111 
112 /* debugging ******************************************************************/
113 
114 #if !defined(NDEBUG)
115 #define INLINE_VERBOSE
116 #define DOLOG(code) do{ if (opt_TraceInlining >= 2) { code; } }while(0)
117 #define DOLOG_SHORT(code) do{ if (opt_TraceInlining >= 1) { code; } }while(0)
118 #else
119 #define DOLOG(code)
120 #endif
121 
122 #if defined(ENABLE_VERIFIER) && !defined(NDEBUG)
123 /* Define this to verify the resulting code after inlining. */
124 /* Note: This is only useful for development and may require patches to the */
125 /* verifier code. */
126 /* #define INLINE_VERIFY_RESULT */
127 #endif
128 
129 /* types **********************************************************************/
130 
131 typedef struct inline_node inline_node;
135 typedef struct inline_site inline_site;
137 
138 struct inline_node {
140 
144  inline_node *next; /* next node at this depth */
145  inline_node *prev; /* prev node at this depth */
146  int depth; /* inlining depth, 0 for root */
147 
148  /* info about the call site (if depth > 0)*/
149  inline_node *parent; /* node of the caller (NULL for root) */
150  basicblock *callerblock; /* original block containing the INVOKE* */
151  instruction *callerins; /* the original INVOKE* instruction */
155  int n_selfpassthroughcount; /* # of pass-through vars of the call itself */
157  int n_handlercount; /* # of handlers protecting this call */
159  int synclocal; /* variable used for synchr., or UNUSED */
160  bool isstatic; /* this is a static call */
161 
162  bool blockbefore; /* block boundary before inlined body? */
163  bool blockafter; /* block boundary after inlined body? */
164 
165  /* info about the callee */
167  int prolog_instructioncount; /* # of ICMDs in the inlining prolog */
168  int epilog_instructioncount; /* # of ICMDs in the inlining epilog */
170  int extra_exceptiontablelength; /* # of extra handlers to put in caller */
171  bool synchronize; /* do we have to synchronize enter/exit? */
172  basicblock *handler_monitorexit; /* handler for synchronized inlinees */
174 
175  /* cumulative values */
176  int cumul_instructioncount; /* ICMDs in this node and its children */
177  int cumul_basicblockcount; /* BBs started by this node and its children */
178  int cumul_basicblockcount_root; /* BBs that have to be added to the root */
179  /* node if this node is inlined */
183 
184  /* output */
189 
190  /* register data */
192 
193  /* temporary */
197 
198  /* XXX debug */
199  char *indent;
200  int debugnr;
201 };
202 
205  union {
207  s4 *nr;
208  } ref;
210  bool isnumber;
211 };
212 
217 };
218 
221 
223 
225 
229 
231 
232  bool stopped;
233 
234  int next_debugnr; /* XXX debug */
235 };
236 
237 struct inline_site {
238  bool speculative; /* true, if inlining would be speculative */
239  bool inlined; /* true, if this site has been inlined */
240 
241  basicblock *bptr; /* basic block containing the call site */
242  instruction *iptr; /* the invocation instruction */
243  exception_entry **handlers; /* active handlers at the call site */
244  s4 nhandlers; /* number of active handlers */
245  s4 pc; /* PC of the invocation instruction */
246 };
247 
250  int freq;
251  int cost;
252  double weight;
256 };
257 
258 
259 /* prototypes *****************************************************************/
260 
261 static bool inline_analyse_code(inline_node *iln);
262 static void inline_post_process(jitdata *jd);
263 
264 
265 /* debug helpers **************************************************************/
266 
267 #if !defined(NDEBUG)
268 #include "inline_debug.inc"
269 #endif
270 
271 
272 /* statistics *****************************************************************/
273 
274 /*#define INLINE_STATISTICS*/
275 
276 #if !defined(NDEBUG)
277 #define INLINE_STATISTICS
278 #endif
279 
280 #if defined(INLINE_STATISTICS)
285 
287 {
288  printf("inlining statistics:\n");
289  printf(" roots analysed : %d\n", inline_stat_roots);
290  printf(" roots transformed: %d\n", inline_stat_roots_transformed);
291  printf(" inlined nodes : %d\n", inline_stat_inlined_nodes);
292  printf(" max depth : %d\n", inline_stat_max_depth);
293 }
294 #endif
295 
296 
297 /* compilation of callees *****************************************************/
298 
300 {
301  methodinfo *m;
302 
303  /* XXX should share code with jit.c */
304 
305  assert(jd);
306 
307  /* XXX initialize the static function's class */
308 
309  m = jd->m;
310 
311  /* call the compiler passes ***********************************************/
312 
313  /* call parse pass */
314 
315  DOLOG( log_message_class("Parsing ", m->clazz) );
316  if (!parse(jd)) {
317  return false;
318  }
319 
320  /* call stack analysis pass */
321 
322  if (!stack_analyse(jd)) {
323  return false;
324  }
325 
326  return true;
327 }
328 
329 
331 {
332  bool r;
333  methodinfo *m;
334  jitdata *jd;
335 
336  /* XXX should share code with jit.c */
337 
338  assert(iln);
339  m = iln->m;
340  assert(m);
341 
342  /* enter a monitor on the method */
343 
344  m->mutex->lock();
345 
346  /* allocate jitdata structure and fill it */
347 
348  jd = jit_jitdata_new(m);
349  iln->jd = jd;
350 
351  jd->flags = 0; /* XXX */
352 
353  /* initialize the register allocator */
354 
355  reg_setup(jd);
356 
357  /* setup the codegendata memory */
358 
359  /* XXX do a pseudo setup */
361  MZERO(jd->cd, codegendata, 1);
362  jd->cd->method = m;
363  /* XXX uses too much dump memory codegen_setup(jd); */
364 
365  /* now call internal compile function */
366 
368 
369  if (r) {
370  iln->regdata = jd->rd;
371  }
372 
373  /* free some memory */
374 #if 0
375 
376 #if defined(ENABLE_JIT)
377 # if defined(ENABLE_INTRP)
378  if (!opt_intrp)
379 # endif
380  codegen_free(jd);
381 #endif
382 
383 #endif
384 
385  /* leave the monitor */
386 
387  m->mutex->unlock();
388 
389  return r;
390 }
391 
392 
393 /* inlining tree handling *****************************************************/
394 
396 {
397  inline_node *first;
398  inline_node *succ;
399 
400  assert(parent && child);
401 
402  child->parent = parent;
403 
404  child->debugnr = parent->ctx->next_debugnr++; /* XXX debug */
405 
406  first = parent->children;
407  if (!first) {
408  /* insert as only node */
409  parent->children = child;
410  child->next = child;
411  child->prev = child;
412  return;
413  }
414 
415  /* {there is at least one child already there} */
416 
417  /* XXX is this search necessary, or could we always add at the end? */
418 
419  succ = first;
420  while (succ->callerpc < child->callerpc) {
421  succ = succ->next;
422  if (succ == first) {
423  /* insert as last node */
424  child->prev = first->prev;
425  child->next = first;
426  child->prev->next = child;
427  child->next->prev = child;
428  return;
429  }
430  }
431 
432  assert(succ->callerpc > child->callerpc);
433 
434  /* insert before succ */
435 
436  child->prev = succ->prev;
437  child->next = succ;
438  child->prev->next = child;
439  child->next->prev = child;
440 
441  if (parent->children == succ)
442  parent->children = child;
443 }
444 
445 
447 {
448  assert(parent);
449  assert(child);
450  assert(child->parent == parent);
451 
452  if (child->prev == child) {
453  /* remove the only child node */
454  parent->children = NULL;
455  }
456  else {
457  child->prev->next = child->next;
458  child->next->prev = child->prev;
459 
460  if (parent->children == child)
461  parent->children = child->next;
462  }
463 }
464 
465 
466 /* inlining candidate handling ************************************************/
467 
468 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
470  inline_node *caller,
471  methodinfo *callee,
472  inline_site *site)
473 {
475  inline_candidate *cand;
476 
478 #if defined(INLINE_DIVIDE_COST_BY_FREQ)
479  cand->freq = INLINE_COUNTDOWN_INIT - callee->hitcountdown;
480  if (cand->freq < 1)
481 #endif
482  cand->freq = 1;
483 #if defined(INLINE_KNAPSACK)
484  cand->cost = callee->jcodelength + INLINE_COST_OFFSET;
485 #endif
486 #if defined(INLINE_BREADTH_FIRST)
487  cand->cost = caller->depth;
488 #endif
489  cand->caller = caller;
490  cand->callee = callee;
491  cand->site = *site;
492 
493  cand->weight = (double)cand->cost / cand->freq;
494 
495  for (link = &(ctx->candidates); ; link = &((*link)->next)) {
496  if (!*link || (*link)->weight > cand->weight) {
497  cand->next = *link;
498  *link = cand;
499  break;
500  }
501  }
502 }
503 #endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
504 
505 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
507 {
508  inline_candidate *cand;
509 
510  cand = ctx->candidates;
511 
512  if (cand)
513  ctx->candidates = cand->next;
514 
515  return cand;
516 }
517 #endif /* defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST) */
518 
519 #if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
521 {
522  printf("%10g (%5d / %5d) depth %2d ",
523  cand->weight, cand->cost, cand->freq, cand->caller->depth + 1);
524  method_println(cand->callee);
525 }
526 #endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
527 
528 
529 #if !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST))
531 {
532  inline_candidate *cand;
533 
534  for (cand = ctx->candidates; cand != NULL; cand = cand->next) {
535  printf(" ");
537  }
538 }
539 #endif /* !defined(NDEBUG) && (defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)) */
540 
541 
542 /* variable handling **********************************************************/
543 
544 static s4 inline_new_variable(jitdata *jd, Type type, s4 flags)
545 {
546  s4 index;
547  s4 newcount;
548 
549  index = jd->vartop++;
550  if (index >= jd->varcount) {
551  newcount = jd->vartop * 2; /* XXX */
552  jd->var = (varinfo*) DumpMemory::reallocate(jd->var, sizeof(varinfo) * jd->varcount, sizeof(varinfo) * newcount);
553  MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
554  jd->varcount = newcount;
555  }
556 
557  jd->var[index].type = type;
558  jd->var[index].flags = flags;
559 
560  return index;
561 }
562 
563 
564 static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
565 {
566  varinfo *v;
567  s4 newidx;
568 
569  v = &(origjd->var[origidx]);
570 
571  newidx = inline_new_variable(jd, v->type, v->flags);
572 
573  jd->var[newidx].vv = v->vv;
574 
575  return newidx;
576 }
577 
578 
580 {
581  return inline_new_variable(jd, type, 0);
582 }
583 
584 
585 static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
586 {
587  s4 idx;
588 
589  idx = varmap[index];
590 
591  if (idx < 0) {
592  idx = inline_new_variable_clone(jd, origjd, index);
593  varmap[index] = idx;
594  }
595 
596  return idx;
597 }
598 
599 
601 {
602  s4 *varmap;
603  s4 i, t;
604  s4 varindex;
605  s4 n_javaindex;
606  s4 avail;
607  varinfo *v;
608 
609  /* create the variable mapping */
610 
611  varmap = (s4*) DumpMemory::allocate(sizeof(s4) * callee->jd->varcount);
612  for (i=0; i<callee->jd->varcount; ++i)
613  varmap[i] = -1;
614 
615  /* translate local variables */
616 
617  for (i=0; i<callee->m->maxlocals; ++i) {
618  for (t=0; t<5; ++t) {
619  varindex = callee->jd->local_map[5*i + t];
620  if (varindex == jitdata::UNUSED)
621  continue;
622 
623  v = &(callee->jd->var[varindex]);
624  assert(v->type == t || v->type == TYPE_VOID); /* XXX stack leaves VOID */
625  v->type = (Type) t; /* XXX restore if it is TYPE_VOID */
626 
627  avail = callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t];
628 
629  if (avail == jitdata::UNUSED) {
630  avail = inline_new_variable_clone(callee->ctx->resultjd, callee->jd, varindex);
631  callee->ctx->resultjd->local_map[5*(callee->localsoffset + i) + t] = avail;
632  }
633 
634  varmap[varindex] = avail;
635  }
636  }
637 
638  /* for synchronized instance methods we need an extra local */
639 
640  if (callee->synchronize && !(callee->m->flags & ACC_STATIC)) {
641  n_javaindex = callee->localsoffset - 1;
642  assert(n_javaindex >= 0);
643  assert(callee->parent);
644  assert(n_javaindex == callee->parent->localsoffset + callee->parent->m->maxlocals);
645 
646  avail = callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR];
647 
648  if (avail == jitdata::UNUSED) {
649  avail = inline_new_variable(callee->ctx->resultjd, TYPE_ADR, 0);
650  callee->ctx->resultjd->local_map[5*n_javaindex + TYPE_ADR] = avail;
651  }
652 
653  callee->synclocal = avail;
654  }
655  else {
656  callee->synclocal = jitdata::UNUSED;
657  }
658 
659  return varmap;
660 }
661 
662 
663 /* basic block translation ****************************************************/
664 
665 #define INLINE_RETURN_REFERENCE(callee) \
666  ( (basicblock *) (ptrint) (0x333 + (callee)->depth) )
667 
668 
670 {
671  inline_target_ref *ref;
672 
674  ref->ref.block = blockp;
675  ref->isnumber = false;
676  ref->next = iln->refs;
677  iln->refs = ref;
678 }
679 
680 
681 #if 0
682 static void inline_add_blocknr_reference(inline_node *iln, s4 *nrp)
683 {
684  inline_target_ref *ref;
685 
687  ref->ref.nr = nrp;
688  ref->isnumber = true;
689  ref->next = iln->refs;
690  iln->refs = ref;
691 }
692 #endif
693 
694 
695 static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
696 {
697  inline_context *ctx;
698 
699  ctx = iln->ctx;
700  assert(ctx->blockmap_index < ctx->master->cumul_blockmapcount);
701 
702  ctx->blockmap[ctx->blockmap_index].iln = iln;
703  ctx->blockmap[ctx->blockmap_index].o_block = o_bptr;
704  ctx->blockmap[ctx->blockmap_index].n_block = n_bptr;
705 
706  ctx->blockmap_index++;
707 }
708 
709 
711  basicblock *o_block,
712  inline_node *targetiln)
713 {
714  inline_block_map *bm;
715  inline_block_map *bmend;
716 
717  assert(iln);
718  assert(targetiln);
719 
720  if (!o_block)
721  return NULL;
722 
723  bm = iln->ctx->blockmap;
724  bmend = bm + iln->ctx->blockmap_index;
725 
726  while (bm < bmend) {
727  assert(bm->iln && bm->o_block && bm->n_block);
728  if (bm->o_block == o_block && bm->iln == targetiln)
729  return bm->n_block;
730  bm++;
731  }
732 
733  assert(false);
734  return NULL; /* not reached */
735 }
736 
737 
739  basicblock *o_bptr,
740  basicblock *n_bptr,
741  bool returnref)
742 {
743  inline_target_ref *ref;
744  inline_target_ref *prev;
745 
746  prev = NULL;
747  for (ref = *refs; ref != NULL; ref = ref->next) {
748  if (ref->isnumber && !returnref) {
749  if (*(ref->ref.nr) == JAVALOCAL_FROM_RETADDR(o_bptr->nr)) {
750  *(ref->ref.nr) = JAVALOCAL_FROM_RETADDR(n_bptr->nr);
751  goto remove_ref;
752  }
753  }
754  else {
755  if (*(ref->ref.block) == o_bptr) {
756  *(ref->ref.block) = n_bptr;
757  goto remove_ref;
758  }
759  }
760 
761  /* skip this ref */
762 
763  prev = ref;
764  continue;
765 
766 remove_ref:
767  /* remove this ref */
768 
769  if (prev) {
770  prev->next = ref->next;
771  }
772  else {
773  *refs = ref->next;
774  }
775  }
776 }
777 
778 
779 /* basic block creation *******************************************************/
780 
781 static basicblock * create_block(inline_node *container,
782  inline_node *iln,
783  inline_node *inner,
784  int indepth)
785 {
786  basicblock *n_bptr;
787  inline_node *outer;
788  s4 i;
789  s4 depth;
790  s4 varidx;
791  s4 newvaridx;
792 
793  assert(container);
794  assert(iln);
795  assert(inner);
796  assert(indepth >= 0);
797 
798  n_bptr = container->inlined_basicblocks_cursor++;
799  assert(n_bptr);
800  assert((n_bptr - container->inlined_basicblocks) < container->cumul_basicblockcount);
801 
802  BASICBLOCK_INIT(n_bptr, iln->m);
803 
804  n_bptr->iinstr = container->inlined_iinstr_cursor;
805  n_bptr->next = n_bptr + 1;
806  n_bptr->nr = container->ctx->next_block_number++;
807  n_bptr->indepth = indepth;
808  n_bptr->state = basicblock::FINISHED; /* XXX */
809 
810  /* set the inlineinfo of the new block */
811 
812  if (iln->inline_start_instruction)
813  n_bptr->inlineinfo = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
814 
815  if (indepth > container->ctx->maxinoutdepth)
816  container->ctx->maxinoutdepth = indepth;
817 
818  if (indepth) {
819  n_bptr->invars = (s4*) DumpMemory::allocate(sizeof(s4) * indepth);
820 
821 
822  for (i=0; i<indepth; ++i)
823  n_bptr->invars[i] = -1; /* XXX debug */
824 
825  /* pass-through variables enter the block */
826 
827  outer = inner->parent;
828  while (outer != NULL) {
829  depth = outer->n_passthroughcount;
830 
831  assert(depth + inner->n_selfpassthroughcount <= indepth);
832 
833  for (i=0; i<inner->n_selfpassthroughcount; ++i) {
834  varidx = inner->n_passthroughvars[i];
835  newvaridx =
837  outer->jd,
838  varidx);
839  n_bptr->invars[depth + i] = newvaridx;
840  outer->varmap[varidx] = newvaridx;
841  }
842  inner = outer;
843  outer = outer->parent;
844  }
845  }
846  else {
847  n_bptr->invars = NULL;
848  }
849 
850  /* XXX for the verifier. should not be here */
851 
852  {
853  varinfo *dv;
854 
857  n_bptr->inlocals = dv;
858  }
859 
860  return n_bptr;
861 }
862 
863 
864 static s4 *translate_javalocals(inline_node *iln, s4 *javalocals)
865 {
866  s4 *jl;
867  s4 i, j;
868 
869  jl = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
870 
871  for (i=0; i<iln->jd->maxlocals; ++i) {
872  j = javalocals[i];
873  if (j > jitdata::UNUSED)
874  j = inline_translate_variable(iln->ctx->resultjd, iln->jd, iln->varmap, j);
875  jl[i] = j;
876 
877 #if 0
878  if (j < jitdata::UNUSED) {
879  /* an encoded returnAddress value - must be relocated */
880  inline_add_blocknr_reference(iln, &(jl[i]));
881  }
882 #endif
883  }
884 
885  return jl;
886 }
887 
888 
890  basicblock *o_bptr, s4 *varmap)
891 {
892  basicblock *n_bptr;
893  s4 i;
894 
895  n_bptr = create_block(iln, iln, iln,
896  o_bptr->indepth + iln->n_passthroughcount);
897 
898  n_bptr->type = o_bptr->type;
899  n_bptr->state = o_bptr->state;
900  n_bptr->bitflags = o_bptr->bitflags;
901 
902  /* resolve references to this block */
903 
904  inline_resolve_block_refs(&(iln->refs), o_bptr, n_bptr, false);
905 
906  /* translate the invars of the original block */
907 
908  for (i=0; i<o_bptr->indepth; ++i) {
909  n_bptr->invars[iln->n_passthroughcount + i] =
911  varmap,
912  o_bptr->invars[i]);
913  }
914 
915  /* translate javalocals info (not for dead code) */
916 
917  if (n_bptr->state >= basicblock::REACHED)
918  n_bptr->javalocals = translate_javalocals(iln, o_bptr->javalocals);
919 
920  return n_bptr;
921 }
922 
923 
924 static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
925 {
926  basicblock *n_bptr;
927  s4 retcount;
928  s4 idx;
929 
930  /* number of return variables */
931 
932  retcount = (callee->n_resultlocal == -1
933  && callee->m->parseddesc->returntype.type != TYPE_VOID) ? 1 : 0;
934 
935  /* start the epilog block */
936 
937  n_bptr = create_block(caller, caller, callee,
938  callee->n_passthroughcount + retcount);
939 
940  /* resolve references to the return block */
941 
942  inline_resolve_block_refs(&(callee->refs),
943  INLINE_RETURN_REFERENCE(callee),
944  n_bptr,
945  true);
946 
947  /* return variable */
948 
949  if (retcount) {
950  idx = inline_new_variable(caller->ctx->resultjd,
951  callee->m->parseddesc->returntype.type, 0 /* XXX */);
952  n_bptr->invars[callee->n_passthroughcount] = idx;
953  varmap[callee->callerins->dst.varindex] = idx;
954  }
955 
956  /* set javalocals */
957 
958  n_bptr->javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * caller->jd->maxlocals);
959  MCOPY(n_bptr->javalocals, caller->javalocals, s4, caller->jd->maxlocals);
960 
961  /* set block flags & type */
962 
963  n_bptr->state = basicblock::FINISHED; // XXX original block flags
964  n_bptr->type = basicblock::TYPE_STD;
965 
966  return n_bptr;
967 }
968 
969 
970 static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
971 {
972  inline_node *outer;
973  s4 i;
974  s4 depth;
975  s4 varidx;
976 
977  n_bptr->outdepth = outdepth;
978  n_bptr->outvars = (s4*) DumpMemory::allocate(sizeof(s4) * outdepth);
979 
980  for (i=0; i<outdepth; ++i)
981  n_bptr->outvars[i] = 0; /* XXX debug */
982 
983  if (outdepth > iln->ctx->maxinoutdepth)
984  iln->ctx->maxinoutdepth = outdepth;
985 
986  /* pass-through variables leave the block */
987 
988  outer = inner->parent;
989  while (outer != NULL) {
990  depth = outer->n_passthroughcount;
991 
992  assert(depth + inner->n_selfpassthroughcount <= outdepth);
993 
994  for (i=0; i<inner->n_selfpassthroughcount; ++i) {
995  varidx = inner->n_passthroughvars[i];
996  n_bptr->outvars[depth + i] =
998  outer->jd,
999  outer->varmap,
1000  varidx);
1001  }
1002  inner = outer;
1003  outer = outer->parent;
1004  }
1005 }
1006 
1007 
1009  basicblock *n_bptr,
1010  inline_node *nextcall)
1011 {
1012  /* XXX add original outvars! */
1013  close_block(iln, nextcall, n_bptr, nextcall->n_passthroughcount);
1014 
1015  /* pass-through variables */
1016 
1017  DOLOG( printf("closed prolog block:\n");
1018  show_basicblock(iln->ctx->resultjd, n_bptr, SHOW_STACK); );
1019 }
1020 
1021 
1023  basicblock *n_bptr,
1024  basicblock *o_bptr,
1025  s4 *varmap,
1026  s4 retcount,
1027  s4 retidx)
1028 {
1029  s4 i;
1030 
1031  close_block(iln, iln, n_bptr, iln->n_passthroughcount + o_bptr->outdepth + retcount);
1032 
1033  /* translate the outvars of the original block */
1034 
1035  /* XXX reuse code */
1036  for (i=0; i<o_bptr->outdepth; ++i) {
1037  n_bptr->outvars[iln->n_passthroughcount + i] =
1038  inline_translate_variable(iln->ctx->resultjd, iln->jd, varmap,
1039  o_bptr->outvars[i]);
1040  }
1041 
1042  /* set the return variable, if any */
1043 
1044  if (retcount) {
1045  assert(retidx >= 0);
1046  n_bptr->outvars[iln->n_passthroughcount + o_bptr->outdepth] = retidx;
1047  }
1048 }
1049 
1050 
1051 /* inlined code generation ****************************************************/
1052 
1054  ICMD opcode,
1055  instruction *o_iptr)
1056 {
1057  instruction *n_iptr;
1058 
1059  n_iptr = (iln->inlined_iinstr_cursor++);
1060  assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1061 
1062  n_iptr->opc = opcode;
1063  n_iptr->flags.bits = o_iptr->flags.bits & INS_FLAG_ID_MASK;
1064  n_iptr->line = o_iptr->line;
1065 
1066  return n_iptr;
1067 }
1068 
1070  inline_node *callee,
1071  instruction *o_iptr,
1072  s4 instancevar,
1073  functionptr func)
1074 {
1075  int syncvar;
1076  instruction *n_ins;
1077 
1078  if (callee->m->flags & ACC_STATIC) {
1079  /* ACONST */
1080  syncvar = inline_new_temp_variable(iln->ctx->resultjd, TYPE_ADR);
1081 
1082  n_ins = inline_instruction(iln, ICMD_ACONST, o_iptr);
1083  n_ins->sx.val.c.cls = callee->m->clazz;
1084  n_ins->dst.varindex = syncvar;
1085  n_ins->flags.bits |= INS_FLAG_CLASS;
1086  }
1087  else {
1088  syncvar = instancevar;
1089  }
1090 
1091  assert(syncvar != jitdata::UNUSED);
1092 
1093  /* MONITORENTER / MONITOREXIT */
1094 
1095  n_ins = inline_instruction(iln, ICMD_BUILTIN, o_iptr);
1096  n_ins->sx.s23.s3.bte = builtintable_get_internal(func);
1097  n_ins->s1.argcount = 1; /* XXX add through-vars */
1098  n_ins->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4));
1099  n_ins->sx.s23.s2.args[0] = syncvar;
1100 }
1101 
1103  inline_node *callee,
1104  instruction *o_iptr,
1105  s4 *varmap)
1106 {
1107  methodinfo *calleem;
1108  methoddesc *md;
1109  int i;
1110  int localindex;
1111  int type;
1112  instruction *n_ins;
1113  insinfo_inline *insinfo;
1114  s4 varindex;
1115 
1116  assert(iln && callee && o_iptr);
1117 
1118  calleem = callee->m;
1119  md = calleem->parseddesc;
1120 
1121  /* INLINE_START instruction */
1122 
1123  n_ins = inline_instruction(iln, ICMD_INLINE_START, o_iptr);
1124 
1125  insinfo = (insinfo_inline*) DumpMemory::allocate(sizeof(insinfo_inline));
1126  insinfo->method = callee->m;
1127  insinfo->outer = iln->m;
1128  insinfo->synclocal = callee->synclocal;
1129  insinfo->synchronize = callee->synchronize;
1130  insinfo->javalocals_start = NULL;
1131  insinfo->javalocals_end = NULL;
1132 
1133  /* info about stack vars live at the INLINE_START */
1134 
1135  insinfo->throughcount = callee->n_passthroughcount;
1136  insinfo->paramcount = md->paramcount;
1137  insinfo->stackvarscount = o_iptr->s1.argcount;
1138  insinfo->stackvars = (s4*) DumpMemory::allocate(sizeof(s4) * insinfo->stackvarscount);
1139  for (i=0; i<insinfo->stackvarscount; ++i)
1140  insinfo->stackvars[i] = iln->varmap[o_iptr->sx.s23.s2.args[i]];
1141 
1142  /* info about the surrounding inlining */
1143 
1144  if (iln->inline_start_instruction)
1145  insinfo->parent = iln->inline_start_instruction->sx.s23.s3.inlineinfo;
1146  else
1147  insinfo->parent = NULL;
1148 
1149  /* finish the INLINE_START instruction */
1150 
1151  n_ins->sx.s23.s3.inlineinfo = insinfo;
1152  callee->inline_start_instruction = n_ins;
1153 
1154  DOLOG( printf("%sprolog: ", iln->indent);
1155  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1156 
1157  /* handle parameters for the inlined callee */
1158 
1159  localindex = callee->localsoffset + md->paramslots;
1160 
1161  for (i=md->paramcount-1; i>=0; --i) {
1162  assert(iln);
1163 
1164  type = md->paramtypes[i].type;
1165 
1166  localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
1167  assert(callee->regdata);
1168 
1169  /* translate the argument variable */
1170 
1171  varindex = varmap[o_iptr->sx.s23.s2.args[i]];
1172  assert(varindex != jitdata::UNUSED);
1173 
1174  /* remove preallocation from the argument variable */
1175 
1176  iln->ctx->resultjd->var[varindex].flags &= ~(PREALLOC | INMEMORY);
1177 
1178  /* check the instance slot against NULL */
1179  /* we don't need that for <init> methods, as the verifier */
1180  /* ensures that they are only called for an uninit. object */
1181  /* (which may not be NULL). */
1182 
1183  if (!callee->isstatic && i == 0 && calleem->name != utf8::init) {
1184  assert(type == TYPE_ADR);
1185  n_ins = inline_instruction(iln, ICMD_CHECKNULL, o_iptr);
1186  n_ins->s1.varindex = varindex;
1187  n_ins->dst.varindex = n_ins->s1.varindex;
1188  }
1189 
1190  /* store argument into local variable of inlined callee */
1191 
1192  if (callee->jd->local_map[5*(localindex - callee->localsoffset) + type] != jitdata::UNUSED)
1193  {
1194  /* this value is used in the callee */
1195 
1196  if (i == 0 && callee->synclocal != jitdata::UNUSED) {
1197  /* we also need it for synchronization, so copy it */
1198  assert(type == TYPE_ADR);
1199  n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1200  }
1201  else {
1202  n_ins = inline_instruction(iln, ICMD(ICMD_ISTORE + type), o_iptr);
1203  n_ins->sx.s23.s3.javaindex = jitdata::UNUSED;
1204  }
1205  n_ins->s1.varindex = varindex;
1206  n_ins->dst.varindex = iln->ctx->resultjd->local_map[5*localindex + type];
1207  assert(n_ins->dst.varindex != jitdata::UNUSED);
1208  }
1209  else if (i == 0 && callee->synclocal != jitdata::UNUSED) {
1210  /* the value is not used inside the callee, but we need it for */
1211  /* synchronization */
1212  /* XXX In this case it actually makes no sense to create a */
1213  /* separate synchronization variable. */
1214 
1215  n_ins = inline_instruction(iln, ICMD_NOP, o_iptr);
1216  }
1217  else {
1218  /* this value is not used, pop it */
1219 
1220  n_ins = inline_instruction(iln, ICMD_POP, o_iptr);
1221  n_ins->s1.varindex = varindex;
1222  }
1223 
1224  DOLOG( printf("%sprolog: ", iln->indent);
1225  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1226  }
1227 
1228  /* COPY for synchronized instance methods */
1229 
1230  if (callee->synclocal != jitdata::UNUSED) {
1231  n_ins = inline_instruction(iln, ICMD_COPY, o_iptr);
1232  n_ins->s1.varindex = varmap[o_iptr->sx.s23.s2.args[0]];
1233  n_ins->dst.varindex = callee->synclocal;
1234 
1235  assert(n_ins->s1.varindex != jitdata::UNUSED);
1236  }
1237 
1238  if (callee->synchronize) {
1239  inline_generate_sync_builtin(iln, callee, o_iptr,
1240  (callee->isstatic) ? jitdata::UNUSED : varmap[o_iptr->sx.s23.s2.args[0]],
1242  }
1243 
1244  /* INLINE_BODY instruction */
1245 
1246  n_ins = inline_instruction(iln, ICMD_INLINE_BODY, callee->jd->basicblocks[0].iinstr);
1247  n_ins->sx.s23.s3.inlineinfo = insinfo;
1248 
1249  return 0; /* XXX */
1250 }
1251 
1252 
1253 static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
1254 {
1255  instruction *n_ins;
1256  s4 *jl;
1257 
1258  assert(iln && callee && o_iptr);
1259  assert(callee->inline_start_instruction);
1260 
1261  if (callee->synchronize) {
1262  inline_generate_sync_builtin(iln, callee, o_iptr,
1263  callee->synclocal,
1265  }
1266 
1267  /* INLINE_END instruction */
1268 
1269  n_ins = inline_instruction(iln, ICMD_INLINE_END, o_iptr);
1270  n_ins->sx.s23.s3.inlineinfo = callee->inline_start_instruction->sx.s23.s3.inlineinfo;
1271 
1272  /* set the javalocals */
1273 
1274  jl = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
1275  MCOPY(jl, iln->javalocals, s4, iln->jd->maxlocals);
1276  n_ins->sx.s23.s3.inlineinfo->javalocals_end = jl;
1277 
1278  DOLOG( printf("%sepilog: ", iln->indent);
1279  show_icmd(iln->ctx->resultjd, n_ins, false, SHOW_STACK); printf("\n"); );
1280 }
1281 
1282 
1283 #define TRANSLATE_VAROP(vo) \
1284  n_iptr->vo.varindex = inline_translate_variable(jd, origjd, varmap, n_iptr->vo.varindex)
1285 
1286 
1288  jitdata *jd,
1289  jitdata *origjd,
1290  s4 *varmap,
1291  instruction *o_iptr,
1292  instruction *n_iptr)
1293 {
1294  icmdtable_entry_t *icmdt;
1295  builtintable_entry *bte;
1296  methoddesc *md;
1297  s4 i, j;
1298  branch_target_t *table;
1299  lookup_target_t *lookup;
1300  inline_node *scope;
1301 
1302  *n_iptr = *o_iptr;
1303 
1304  icmdt = &(icmd_table[o_iptr->opc]);
1305 
1306  switch (icmdt->dataflow) {
1307  case DF_0_TO_0:
1308  break;
1309 
1310  case DF_3_TO_0:
1311  TRANSLATE_VAROP(sx.s23.s3);
1312  case DF_2_TO_0:
1313  TRANSLATE_VAROP(sx.s23.s2);
1314  case DF_1_TO_0:
1316  break;
1317 
1318  case DF_2_TO_1:
1319  TRANSLATE_VAROP(sx.s23.s2);
1320  case DF_1_TO_1:
1321  case DF_COPY:
1322  case DF_MOVE:
1324  case DF_0_TO_1:
1325  TRANSLATE_VAROP(dst);
1326  break;
1327 
1328  case DF_N_TO_1:
1329  n_iptr->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_iptr->s1.argcount);
1330  for (i=0; i<n_iptr->s1.argcount; ++i) {
1331  n_iptr->sx.s23.s2.args[i] =
1332  inline_translate_variable(jd, origjd, varmap,
1333  o_iptr->sx.s23.s2.args[i]);
1334  }
1335  TRANSLATE_VAROP(dst);
1336  break;
1337 
1338  case DF_INVOKE:
1339  INSTRUCTION_GET_METHODDESC(n_iptr, md);
1340 clone_call:
1341  n_iptr->s1.argcount += iln->n_passthroughcount;
1342  n_iptr->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_iptr->s1.argcount);
1343  for (i=0; i<o_iptr->s1.argcount; ++i) {
1344  n_iptr->sx.s23.s2.args[i] =
1345  inline_translate_variable(jd, origjd, varmap,
1346  o_iptr->sx.s23.s2.args[i]);
1347  }
1348  for (scope = iln; scope != NULL; scope = scope->parent) {
1349  for (j = 0; j < scope->n_selfpassthroughcount; ++j) {
1350  n_iptr->sx.s23.s2.args[i++] =
1351  scope->parent->varmap[scope->n_passthroughvars[j]];
1352  }
1353  }
1354  if (md->returntype.type != TYPE_VOID)
1355  TRANSLATE_VAROP(dst);
1356  break;
1357 
1358  case DF_BUILTIN:
1359  bte = n_iptr->sx.s23.s3.bte;
1360  md = bte->md;
1361  goto clone_call;
1362 
1363  default:
1364  assert(0);
1365  }
1366 
1367  switch (icmdt->controlflow) {
1368  case CF_RET:
1369  TRANSLATE_VAROP(s1); /* XXX should be handled by data-flow */
1370  /* FALLTHROUGH */
1371  case CF_IF:
1372  case CF_GOTO:
1373  inline_add_block_reference(iln, &(n_iptr->dst.block));
1374  break;
1375 
1376  case CF_JSR:
1377  inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.jsrtarget.block));
1378  break;
1379 
1380  case CF_TABLE:
1381  i = n_iptr->sx.s23.s3.tablehigh - n_iptr->sx.s23.s2.tablelow + 1 + 1 /* default */;
1382 
1383  table = (branch_target_t*) DumpMemory::allocate(sizeof(branch_target_t) * i);
1384  MCOPY(table, o_iptr->dst.table, branch_target_t, i);
1385  n_iptr->dst.table = table;
1386 
1387  while (--i >= 0) {
1388  inline_add_block_reference(iln, &(table->block));
1389  table++;
1390  }
1391  break;
1392 
1393  case CF_LOOKUP:
1394  inline_add_block_reference(iln, &(n_iptr->sx.s23.s3.lookupdefault.block));
1395 
1396  i = n_iptr->sx.s23.s2.lookupcount;
1397  lookup = (lookup_target_t*) DumpMemory::allocate(sizeof(lookup_target_t) * i);
1398  MCOPY(lookup, o_iptr->dst.lookup, lookup_target_t, i);
1399  n_iptr->dst.lookup = lookup;
1400 
1401  while (--i >= 0) {
1402  inline_add_block_reference(iln, &(lookup->target.block));
1403  lookup++;
1404  }
1405  break;
1406  }
1407 
1408  /* XXX move this to dataflow section? */
1409 
1410  switch (n_iptr->opc) {
1411  case ICMD_ASTORE:
1412 #if 0
1413  if (n_iptr->flags.bits & INS_FLAG_RETADDR)
1414  inline_add_blocknr_reference(iln, &(n_iptr->sx.s23.s2.retaddrnr));
1415 #endif
1416  /* FALLTHROUGH! */
1417  case ICMD_ISTORE:
1418  case ICMD_LSTORE:
1419  case ICMD_FSTORE:
1420  case ICMD_DSTORE:
1421  stack_javalocals_store(n_iptr, iln->javalocals);
1422  break;
1423  default:
1424  break;
1425  }
1426 }
1427 
1428 
1430 {
1431  basicblock *o_bptr;
1432  s4 len;
1433  instruction *o_iptr;
1434  instruction *n_iptr;
1435  inline_node *nextcall;
1436  basicblock *n_bptr;
1437  inline_block_map *bm;
1438  int i;
1439  int icount;
1440  jitdata *resultjd;
1441  jitdata *origjd;
1442  char indent[100]; /* XXX debug */
1443  s4 retcount;
1444  s4 retidx;
1445 
1446  assert(iln);
1447 
1448  resultjd = iln->ctx->resultjd;
1449  origjd = iln->jd;
1450 
1451  n_bptr = NULL;
1452  nextcall = iln->children;
1453 
1454  /* XXX debug */
1455  for (i=0; i<iln->depth; ++i)
1456  indent[i] = '\t';
1457  indent[i] = 0;
1458  iln->indent = indent;
1459 
1460  DOLOG( printf("%srewriting: ", indent); method_println(iln->m);
1461  printf("%s(passthrough: %d+%d)\n",
1462  indent, iln->n_passthroughcount - iln->n_selfpassthroughcount,
1463  iln->n_passthroughcount); );
1464 
1465  /* set memory cursors */
1466 
1469 
1470  /* allocate temporary buffers */
1471 
1472  iln->javalocals = (s4*) DumpMemory::allocate(sizeof(s4) * iln->jd->maxlocals);
1473 
1474  /* loop over basic blocks */
1475 
1476  o_bptr = iln->jd->basicblocks;
1477  for (; o_bptr; o_bptr = o_bptr->next) {
1478 
1479  if (o_bptr->state < basicblock::REACHED) {
1480 
1481  /* ignore the dummy end block */
1482 
1483  if (o_bptr->icount == 0 && o_bptr->next == NULL) {
1484  /* enter the following block as translation, for exception handler ranges */
1486  continue;
1487  }
1488 
1489  DOLOG(
1490  printf("%s* skipping old L%03d (flags=%d, type=%d, oid=%d) of ",
1491  indent,
1492  o_bptr->nr, o_bptr->state, o_bptr->type,
1493  o_bptr->indepth);
1494  method_println(iln->m);
1495  );
1496 
1497  n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1498 
1499  /* enter it in the blockmap */
1500 
1501  inline_block_translation(iln, o_bptr, n_bptr);
1502 
1503  close_body_block(iln, n_bptr, o_bptr, iln->varmap, 0, -1);
1504  continue;
1505  }
1506 
1507  len = o_bptr->icount;
1508  o_iptr = o_bptr->iinstr;
1509 
1510  DOLOG(
1511  printf("%s* rewriting old L%03d (flags=%d, type=%d, oid=%d) of ",
1512  indent,
1513  o_bptr->nr, o_bptr->state, o_bptr->type,
1514  o_bptr->indepth);
1515  method_println(iln->m);
1516  show_basicblock(iln->jd, o_bptr, SHOW_STACK);
1517  );
1518 
1519  if (iln->blockbefore || o_bptr != iln->jd->basicblocks) {
1520  /* create an inlined clone of this block */
1521 
1522  n_bptr = create_body_block(iln, o_bptr, iln->varmap);
1523  icount = 0;
1524 
1525  /* enter it in the blockmap */
1526 
1527  inline_block_translation(iln, o_bptr, n_bptr);
1528 
1529  /* initialize the javalocals */
1530 
1531  MCOPY(iln->javalocals, n_bptr->javalocals, s4, iln->jd->maxlocals);
1532  }
1533  else {
1534  s4 *jl;
1535 
1536  /* continue caller block */
1537 
1538  n_bptr = iln->inlined_basicblocks_cursor - 1;
1539  icount = n_bptr->icount;
1540 
1541  /* translate the javalocals */
1542 
1543  jl = translate_javalocals(iln, o_bptr->javalocals);
1544  iln->inline_start_instruction->sx.s23.s3.inlineinfo->javalocals_start = jl;
1545 
1546  MCOPY(iln->javalocals, jl, s4, iln->jd->maxlocals);
1547  }
1548 
1549  /* iterate over the ICMDs of this block */
1550 
1551  retcount = 0;
1552  retidx = jitdata::UNUSED;
1553 
1554  while (--len >= 0) {
1555 
1556  DOLOG( fputs(indent, stdout); show_icmd(iln->jd, o_iptr, false, SHOW_STACK);
1557  printf("\n") );
1558 
1559  /* handle calls that will be inlined */
1560 
1561  if (nextcall && o_iptr == nextcall->callerins) {
1562 
1563  /* write the inlining prolog */
1564 
1565  (void) emit_inlining_prolog(iln, nextcall, o_iptr, iln->varmap);
1566  icount += nextcall->prolog_instructioncount;
1567 
1568  /* end current block, or glue blocks together */
1569 
1570  n_bptr->icount = icount;
1571 
1572  if (nextcall->blockbefore) {
1573  close_prolog_block(iln, n_bptr, nextcall);
1574  }
1575  else {
1576  /* XXX */
1577  }
1578 
1579  /* check if the result is a local variable */
1580 
1581  if (nextcall->m->parseddesc->returntype.type != TYPE_VOID
1582  && o_iptr->dst.varindex < iln->jd->localcount)
1583  {
1584  nextcall->n_resultlocal = iln->varmap[o_iptr->dst.varindex];
1585  }
1586  else
1587  nextcall->n_resultlocal = -1;
1588 
1589  /* set memory pointers in the callee */
1590 
1591  nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
1593 
1594  /* recurse */
1595 
1596  DOLOG( printf("%sentering inline ", indent);
1597  show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1598 
1599  inline_rewrite_method(nextcall);
1600 
1601  DOLOG( printf("%sleaving inline ", indent);
1602  show_icmd(origjd, o_iptr, false, SHOW_STACK); printf("\n") );
1603 
1604  /* update memory cursors */
1605 
1606  assert(nextcall->inlined_iinstr_cursor
1607  <= iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
1608  assert(nextcall->inlined_basicblocks_cursor
1612 
1613  /* start new block, or glue blocks together */
1614 
1615  if (nextcall->blockafter) {
1616  n_bptr = create_epilog_block(iln, nextcall, iln->varmap);
1617  icount = 0;
1618  }
1619  else {
1620  n_bptr = iln->inlined_basicblocks_cursor - 1;
1621  icount = n_bptr->icount;
1622  /* XXX */
1623  }
1624 
1625  /* emit inlining epilog */
1626 
1627  emit_inlining_epilog(iln, nextcall, o_iptr);
1628  icount += nextcall->epilog_instructioncount;
1629 
1630  /* proceed to next call */
1631 
1632  nextcall = nextcall->next;
1633  }
1634  else {
1635  n_iptr = (iln->inlined_iinstr_cursor++);
1636  assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1637 
1638  switch (o_iptr->opc) {
1639  case ICMD_RETURN:
1640  if (iln->depth == 0)
1641  goto default_clone;
1642  goto return_tail;
1643 
1644  case ICMD_IRETURN:
1645  case ICMD_ARETURN:
1646  case ICMD_LRETURN:
1647  case ICMD_FRETURN:
1648  case ICMD_DRETURN:
1649  if (iln->depth == 0)
1650  goto default_clone;
1651  retcount = 1;
1652  retidx = iln->varmap[o_iptr->s1.varindex];
1653  if (iln->n_resultlocal != -1) {
1654  /* store result in a local variable */
1655 
1656  DOLOG( printf("USING RESULTLOCAL %d\n", iln->n_resultlocal); );
1657  /* This relies on the same sequence of types for */
1658  /* ?STORE and ?RETURN opcodes. */
1659  n_iptr->opc = ICMD(ICMD_ISTORE + (o_iptr->opc - ICMD_IRETURN));
1660  n_iptr->s1.varindex = retidx;
1661  n_iptr->dst.varindex = iln->n_resultlocal;
1662  n_iptr->sx.s23.s3.javaindex = jitdata::UNUSED; /* XXX set real javaindex? */
1663 
1664  retcount = 0;
1665  retidx = jitdata::UNUSED;
1666 
1667  n_iptr = (iln->inlined_iinstr_cursor++);
1668  assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1669  icount++;
1670  }
1671  else if ((retidx < resultjd->localcount && iln->blockafter)
1672  || !iln->blockafter) /* XXX do we really always need the MOVE? */
1673  {
1674  /* local must not become outvar, insert a MOVE */
1675 
1676  n_iptr->opc = ICMD_MOVE;
1677  n_iptr->s1.varindex = retidx;
1678  retidx = inline_new_temp_variable(resultjd,
1679  resultjd->var[retidx].type);
1680  n_iptr->dst.varindex = retidx;
1681 
1682  n_iptr = (iln->inlined_iinstr_cursor++);
1683  assert((n_iptr - iln->inlined_iinstr) < iln->cumul_instructioncount);
1684  icount++;
1685  }
1686 return_tail:
1687  if (iln->blockafter) {
1688  n_iptr->opc = ICMD_GOTO;
1689  n_iptr->dst.block = INLINE_RETURN_REFERENCE(iln);
1690  inline_add_block_reference(iln, &(n_iptr->dst.block));
1691  }
1692  else {
1693  n_iptr->opc = ICMD_NOP;
1694  }
1695  break;
1696 #if 0
1697  if (o_bptr->next == NULL || (o_bptr->next->icount==0 && o_bptr->next->next == NULL)) {
1698  n_iptr->opc = ICMD_NOP;
1699  break;
1700  }
1701  goto default_clone;
1702  break;
1703 #endif
1704 
1705  default:
1706 default_clone:
1707  inline_clone_instruction(iln, resultjd, iln->jd, iln->varmap, o_iptr, n_iptr);
1708  }
1709 
1710  DOLOG( fputs(indent, stdout); show_icmd(resultjd, n_iptr, false, SHOW_STACK);
1711  printf("\n"););
1712 
1713  icount++;
1714  }
1715 
1716  o_iptr++;
1717  }
1718 
1719  /* end of basic block */
1720 
1721  if (iln->blockafter || (o_bptr->next && o_bptr->next->next)) {
1722  close_body_block(iln, n_bptr, o_bptr, iln->varmap, retcount, retidx);
1723  n_bptr->icount = icount;
1724 
1725  DOLOG( printf("closed body block:\n");
1726  show_basicblock(resultjd, n_bptr, SHOW_STACK); );
1727  }
1728  else {
1729  n_bptr->icount = icount;
1730  assert(iln->parent);
1731  if (retidx != jitdata::UNUSED)
1732  iln->parent->varmap[iln->callerins->dst.varindex] = retidx;
1733  }
1734  }
1735 
1736  bm = iln->ctx->blockmap;
1737  for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1738  assert(bm->iln && bm->o_block && bm->n_block);
1739  if (bm->iln == iln)
1740  inline_resolve_block_refs(&(iln->refs), bm->o_block, bm->n_block, false);
1741  }
1742 
1743 #if !defined(NDEBUG)
1744  if (iln->refs) {
1745  inline_target_ref *ref;
1746  ref = iln->refs;
1747  while (ref) {
1748  if (!iln->depth || ref->isnumber || *(ref->ref.block) != INLINE_RETURN_REFERENCE(iln)) {
1749  DOLOG( printf("XXX REMAINING REF at depth %d: %p\n", iln->depth,
1750  (void*)*(ref->ref.block)) );
1751  assert(false);
1752  }
1753  ref = ref->next;
1754  }
1755  }
1756 #endif
1757 }
1758 
1759 
1761  exception_entry *n_extable,
1762  exception_entry **prevextable)
1763 {
1764  inline_node *child;
1765  inline_node *scope;
1766  exception_entry *et;
1767 
1768  assert(iln);
1769  assert(n_extable);
1770  assert(prevextable);
1771 
1772  child = iln->children;
1773  if (child) {
1774  do {
1775  n_extable = inline_exception_tables(child, n_extable, prevextable);
1776  child = child->next;
1777  } while (child != iln->children);
1778  }
1779 
1780  et = iln->jd->exceptiontable;
1781  for (; et != NULL; et = et->down) {
1782  assert(et);
1783  MZERO(n_extable, exception_entry, 1);
1784  n_extable->start = inline_map_block(iln, et->start , iln);
1785  n_extable->end = inline_map_block(iln, et->end , iln);
1786  n_extable->handler = inline_map_block(iln, et->handler, iln);
1787  n_extable->catchtype = et->catchtype;
1788 
1789  if (*prevextable) {
1790  (*prevextable)->down = n_extable;
1791  }
1792  *prevextable = n_extable;
1793 
1794  n_extable++;
1795  }
1796 
1797  if (iln->handler_monitorexit) {
1798  exception_entry **activehandlers;
1799 
1800  MZERO(n_extable, exception_entry, 1);
1801  n_extable->start = iln->inlined_basicblocks;
1802  n_extable->end = iln->inlined_basicblocks_cursor;
1803  n_extable->handler = iln->handler_monitorexit;
1804  n_extable->catchtype.any = NULL; /* finally */
1805 
1806  if (*prevextable) {
1807  (*prevextable)->down = n_extable;
1808  }
1809  *prevextable = n_extable;
1810 
1811  n_extable++;
1812 
1813  /* We have to protect the created handler with the same handlers */
1814  /* that protect the method body itself. */
1815 
1816  for (scope = iln; scope->parent != NULL; scope = scope->parent) {
1817 
1818  activehandlers = scope->o_handlers;
1819  assert(activehandlers);
1820 
1821  while (*activehandlers) {
1822 
1823  assert(scope->parent);
1824 
1825  MZERO(n_extable, exception_entry, 1);
1826  n_extable->start = iln->handler_monitorexit;
1827  n_extable->end = iln->handler_monitorexit + 1; /* XXX ok in this case? */
1828  n_extable->handler = inline_map_block(scope->parent,
1829  (*activehandlers)->handler,
1830  scope->parent);
1831  n_extable->catchtype = (*activehandlers)->catchtype;
1832 
1833  if (*prevextable) {
1834  (*prevextable)->down = n_extable;
1835  }
1836  *prevextable = n_extable;
1837 
1838  n_extable++;
1839  activehandlers++;
1840  }
1841  }
1842  }
1843 
1844  return n_extable;
1845 }
1846 
1847 
1848 static void inline_locals(inline_node *iln)
1849 {
1850  inline_node *child;
1851 
1852  assert(iln);
1853 
1854  iln->varmap = create_variable_map(iln);
1855 
1856  child = iln->children;
1857  if (child) {
1858  do {
1859  inline_locals(child);
1860  child = child->next;
1861  } while (child != iln->children);
1862  }
1863 
1864  if (iln->regdata->memuse > iln->ctx->resultjd->rd->memuse)
1865  iln->ctx->resultjd->rd->memuse = iln->regdata->memuse;
1866  if (iln->regdata->argintreguse > iln->ctx->resultjd->rd->argintreguse)
1867  iln->ctx->resultjd->rd->argintreguse = iln->regdata->argintreguse;
1868  if (iln->regdata->argfltreguse > iln->ctx->resultjd->rd->argfltreguse)
1869  iln->ctx->resultjd->rd->argfltreguse = iln->regdata->argfltreguse;
1870 }
1871 
1872 
1874 {
1875  basicblock *bptr;
1876  jitdata *resultjd;
1877  s4 i;
1878  varinfo *v;
1879 
1880  resultjd = iln->ctx->resultjd;
1881 
1883  for (i=0; i<5*iln->ctx->maxinoutdepth; ++i)
1884  resultjd->interface_map[i].flags = jitdata::UNUSED;
1885 
1886  for (bptr = resultjd->basicblocks; bptr != NULL; bptr = bptr->next) {
1887  assert(bptr->indepth <= iln->ctx->maxinoutdepth);
1888  assert(bptr->outdepth <= iln->ctx->maxinoutdepth);
1889 
1890  for (i=0; i<bptr->indepth; ++i) {
1891  v = &(resultjd->var[bptr->invars[i]]);
1892  v->flags |= INOUT;
1893  if (v->type == TYPE_RET)
1894  v->flags |= PREALLOC;
1895  else
1896  v->flags &= ~PREALLOC;
1897  v->flags &= ~INMEMORY;
1898  assert(bptr->invars[i] >= resultjd->localcount);
1899 
1900  if (resultjd->interface_map[5*i + v->type].flags == jitdata::UNUSED) {
1901  resultjd->interface_map[5*i + v->type].flags = v->flags;
1902  }
1903  else {
1904  resultjd->interface_map[5*i + v->type].flags |= v->flags;
1905  }
1906  }
1907 
1908  for (i=0; i<bptr->outdepth; ++i) {
1909  v = &(resultjd->var[bptr->outvars[i]]);
1910  v->flags |= INOUT;
1911  if (v->type == TYPE_RET)
1912  v->flags |= PREALLOC;
1913  else
1914  v->flags &= ~PREALLOC;
1915  v->flags &= ~INMEMORY;
1916  assert(bptr->outvars[i] >= resultjd->localcount);
1917 
1918  if (resultjd->interface_map[5*i + v->type].flags == jitdata::UNUSED) {
1919  resultjd->interface_map[5*i + v->type].flags = v->flags;
1920  }
1921  else {
1922  resultjd->interface_map[5*i + v->type].flags |= v->flags;
1923  }
1924  }
1925  }
1926 }
1927 
1928 
1930 {
1931  basicblock *n_bptr;
1932  instruction *n_ins;
1933  inline_node *child;
1934  builtintable_entry *bte;
1935  s4 exvar;
1936  s4 syncvar;
1937  s4 i;
1938 
1939  child = iln->children;
1940  if (child) {
1941  do {
1942  inline_write_exception_handlers(master, child);
1943  child = child->next;
1944  } while (child != iln->children);
1945  }
1946 
1947  if (iln->synchronize) {
1948  /* create the monitorexit handler */
1949  n_bptr = create_block(master, iln, iln,
1950  iln->n_passthroughcount + 1);
1951  n_bptr->type = basicblock::TYPE_EXH;
1952  n_bptr->state = basicblock::FINISHED;
1953 
1954  exvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1955  n_bptr->invars[iln->n_passthroughcount] = exvar;
1956 
1957  iln->handler_monitorexit = n_bptr;
1958 
1959  /* ACONST / ALOAD */
1960 
1961  n_ins = master->inlined_iinstr_cursor++;
1962  if (iln->m->flags & ACC_STATIC) {
1963  n_ins->opc = ICMD_ACONST;
1964  n_ins->sx.val.c.cls = iln->m->clazz;
1965  n_ins->flags.bits = INS_FLAG_CLASS;
1966  }
1967  else {
1968  n_ins->opc = ICMD_ALOAD;
1969  n_ins->s1.varindex = iln->synclocal;
1970  assert(n_ins->s1.varindex != jitdata::UNUSED);
1971  }
1972  /* XXX could be PREALLOCed for builtin call */
1973  syncvar = inline_new_variable(master->ctx->resultjd, TYPE_ADR, 0);
1974  n_ins->dst.varindex = syncvar;
1975  n_ins->line = 0;
1976 
1977  /* MONITOREXIT */
1978 
1980 
1981  n_ins = master->inlined_iinstr_cursor++;
1982  n_ins->opc = ICMD_BUILTIN;
1983  n_ins->s1.argcount = 1 + iln->n_passthroughcount + 1;
1984  n_ins->sx.s23.s2.args = (s4*) DumpMemory::allocate(sizeof(s4) * n_ins->s1.argcount);
1985  n_ins->sx.s23.s2.args[0] = syncvar;
1986  for (i=0; i < iln->n_passthroughcount + 1; ++i) {
1987  n_ins->sx.s23.s2.args[1 + i] = n_bptr->invars[i];
1988  }
1989  n_ins->sx.s23.s3.bte = bte;
1990  n_ins->line = 0;
1991 
1992  /* ATHROW */
1993 
1994  n_ins = master->inlined_iinstr_cursor++;
1995  n_ins->opc = ICMD_ATHROW;
1996  n_ins->flags.bits = 0;
1997  n_ins->s1.varindex = exvar;
1998  n_ins->line = 0;
1999 
2000  /* close basic block */
2001 
2002  close_block(iln, iln, n_bptr, iln->n_passthroughcount);
2003  n_bptr->icount = 3;
2004  }
2005 }
2006 
2007 
2008 /* second pass driver *********************************************************/
2009 
2010 static bool inline_transform(inline_node *iln, jitdata *jd)
2011 {
2012  instruction *n_ins;
2013  basicblock *n_bb;
2014  basicblock *n_bptr;
2015  exception_entry *n_ext;
2016  exception_entry *prevext;
2017  codegendata *n_cd;
2018  jitdata *n_jd;
2019  s4 i;
2020 #if defined(INLINE_VERIFY_RESULT)
2021  static int debug_verify_inlined_code = 1;
2022 #endif
2023 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2024  static int debug_counter = 0;
2025 #endif
2026 
2027  DOLOG( dump_inline_tree(iln, 0); );
2028 
2029  assert(iln && jd);
2030 
2033  iln->inlined_iinstr = n_ins;
2034 
2036  MZERO(n_bb, basicblock, iln->cumul_basicblockcount);
2037  iln->inlined_basicblocks = n_bb;
2038 
2040 
2041  n_jd = jit_jitdata_new(iln->m);
2042  n_jd->flags = jd->flags;
2043  n_jd->code->optlevel = jd->code->optlevel;
2044  iln->ctx->resultjd = n_jd;
2045 
2046  reg_setup(n_jd);
2047 
2048  /* create the local_map */
2049 
2050  n_jd->local_map = (s4*) DumpMemory::allocate(sizeof(s4) * 5 * iln->cumul_maxlocals);
2051  for (i=0; i<5*iln->cumul_maxlocals; ++i)
2052  n_jd->local_map[i] = jitdata::UNUSED;
2053 
2054  /* create / coalesce local variables */
2055 
2056  n_jd->varcount = 0;
2057  n_jd->vartop = 0;
2058  n_jd->var = NULL;
2059 
2060  inline_locals(iln);
2061 
2062  n_jd->localcount = n_jd->vartop;
2063 
2064  /* extra variables for verification (debugging) */
2065 
2066 #if defined(INLINE_VERIFY_RESULT)
2067  if (debug_verify_inlined_code) {
2068  n_jd->vartop += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + 100 /* XXX m->maxstack */;
2069  if (n_jd->vartop > n_jd->varcount) {
2070  /* XXX why? */
2071  n_jd->var = (varinfo*) DumpMemory::realloc(n_jd->var, sizeof(varinfo) * n_jd->varcount, sizeof(varinfo) * n_jd->vartop);
2072  n_jd->varcount = n_jd->vartop;
2073  }
2074  }
2075 #endif /* defined(INLINE_VERIFY_RESULT) */
2076 
2077  /* write inlined code */
2078 
2079  inline_rewrite_method(iln);
2080 
2081  /* create exception handlers */
2082 
2084 
2085  /* write the dummy end block */
2086 
2087  n_bptr = create_block(iln, iln, iln, 0);
2088  n_bptr->state = basicblock::UNDEF;
2089  n_bptr->type = basicblock::TYPE_STD;
2090 
2091  /* store created code in jitdata */
2092 
2093  n_jd->basicblocks = iln->inlined_basicblocks;
2095  n_jd->instructions = iln->inlined_iinstr;
2096 
2097  /* link the basic blocks (dummy end block is not counted) */
2098 
2100  for (i=0; i<n_jd->basicblockcount + 1; ++i)
2101  n_jd->basicblocks[i].next = &(n_jd->basicblocks[i+1]);
2102  if (i)
2103  n_jd->basicblocks[i-1].next = NULL;
2104 
2105  /* check basicblock numbers */
2106 
2107 #if !defined(NDEBUG)
2109 #endif
2110 
2111  /* create the exception table */
2112 
2113  if (iln->cumul_exceptiontablelength) {
2114  exception_entry *tableend;
2115 
2117  prevext = NULL;
2118  tableend = inline_exception_tables(iln, n_ext, &prevext);
2119  assert(tableend == n_ext + iln->cumul_exceptiontablelength);
2120  if (prevext)
2121  prevext->down = NULL;
2122 
2124  n_jd->exceptiontable = n_ext;
2125  }
2126  else {
2127  n_ext = NULL;
2128  }
2129 
2130  /*******************************************************************************/
2131 
2132  n_cd = n_jd->cd;
2133  memcpy(n_cd, jd->cd, sizeof(codegendata));
2134 
2135  n_cd->method = NULL; /* XXX */
2136  n_jd->maxlocals = iln->cumul_maxlocals;
2137  n_jd->maxinterfaces = iln->ctx->maxinoutdepth;
2138 
2139  inline_post_process(n_jd);
2140 
2142 
2143  /* for debugging, verify the inlined result */
2144 
2145 #if defined(INLINE_VERIFY_RESULT)
2146  if (debug_verify_inlined_code) {
2147  debug_verify_inlined_code = 0;
2148  DOLOG( printf("VERIFYING INLINED RESULT...\n"); fflush(stdout); );
2149  if (!typecheck(n_jd)) {
2151  DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
2152  return false;
2153  }
2154  else {
2155  DOLOG( printf("VERIFICATION PASSED.\n") );
2156  }
2157  debug_verify_inlined_code = 1;
2158  }
2159 #endif /* defined(INLINE_VERIFY_RESULT) */
2160 
2161  /* we need bigger free memory stacks (XXX these should not be allocated in reg_setup) */
2162 
2163  n_jd->rd->freemem = (s4*) DumpMemory::allocate(sizeof(s4) * (iln->ctx->maxinoutdepth + 1000)) /* XXX max vars/block */;
2164 
2165 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2166  if ( (n_jd->instructioncount >= opt_InlineMinSize)
2167  && (n_jd->instructioncount <= opt_InlineMaxSize))
2168  {
2169  if (debug_counter < opt_InlineCount)
2170 #endif /* defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG) */
2171  {
2172  /* install the inlined result */
2173 
2174  *jd->code = *n_jd->code;
2175  n_jd->code = jd->code;
2176  *jd = *n_jd;
2177 
2178  /* statistics and logging */
2179 
2180 #if !defined(NDEBUG)
2182 
2183  DOLOG_SHORT(
2184  printf("==== %d.INLINE ==================================================================\n",
2185  debug_counter);
2186  printf("\ninline tree:\n");
2187  dump_inline_tree(iln, 0);
2189  /* debug_dump_inlined_code(iln, n_method, n_cd, n_rd); */
2190  printf("-------- DONE -----------------------------------------------------------\n");
2191  fflush(stdout);
2192  );
2193 #endif
2194  }
2195 
2196 #if defined(ENABLE_INLINING_DEBUG) || !defined(NDEBUG)
2197  debug_counter++;
2198  }
2199 #endif
2200  return true;
2201 }
2202 
2203 
2204 /******************************************************************************/
2205 /* FIRST PASS: build inlining tree */
2206 /******************************************************************************/
2207 
2208 
2209 /* inline_pre_parse_heuristics *************************************************
2210 
2211  Perform heuristic checks whether a call site should be inlined.
2212  These checks are evaluated before the callee has been parsed and analysed.
2213 
2214  IN:
2215  caller...........inlining node of the caller
2216  callee...........the called method
2217  site.............information on the call site
2218 
2219  RETURN VALUE:
2220  true........consider for inlining
2221  false.......don't inline
2222 
2223 *******************************************************************************/
2224 
2225 static bool inline_pre_parse_heuristics(const inline_node *caller,
2226  const methodinfo *callee,
2227  inline_site *site)
2228 {
2229 #if defined(INLINE_MAX_DEPTH)
2230  if (caller->depth >= INLINE_MAX_DEPTH)
2231  return false;
2232 #endif
2233 
2234  return true;
2235 }
2236 
2237 
2238 /* inline_post_parse_heuristics ************************************************
2239 
2240  Perform heuristic checks whether a call site should be inlined.
2241  These checks are evaluated after the callee has been parsed and analysed.
2242 
2243  IN:
2244  caller...........inlining node of the caller (const)
2245  callee...........the called method (const)
2246 
2247  RETURN VALUE:
2248  true........consider for inlining
2249  false.......don't inline
2250 
2251 *******************************************************************************/
2252 
2253 static bool inline_post_parse_heuristics(const inline_node *caller,
2254  const inline_node *callee)
2255 {
2256  return true;
2257 }
2258 
2259 
2260 /* inline_afterwards_heuristics ************************************************
2261 
2262  Perform heuristic checks whether a call site should be inlined.
2263  These checks are evaluated after the inlining plan for the callee has
2264  been made.
2265 
2266  IN:
2267  caller...........inlining node of the caller (const)
2268  callee...........the called method (const)
2269 
2270  RETURN VALUE:
2271  true........consider for inlining
2272  false.......don't inline
2273 
2274 *******************************************************************************/
2275 
2276 static bool inline_afterwards_heuristics(const inline_node *caller,
2277  const inline_node *callee)
2278 {
2279 #if defined(INLINE_MAX_ICMD_EXPANSION) || defined(INLINE_MAX_BLOCK_EXPANSION)
2280  inline_node *cumulator;
2281 
2282 #if defined(INLINE_DEPTH_FIRST)
2283  cumulator = caller;
2284 #else
2285  cumulator = caller->ctx->master;
2286 #endif
2287 #endif
2288 
2289  if (0
2290 #if defined(INLINE_MAX_BLOCK_EXPANSION)
2291  || (cumulator->cumul_basicblockcount + callee->cumul_basicblockcount
2292  > INLINE_MAX_BLOCK_EXPANSION*caller->ctx->master->jd->basicblockcount)
2293 #endif
2294 #if defined(INLINE_MAX_ICMD_EXPANSION)
2295  || (cumulator->cumul_instructioncount + callee->cumul_instructioncount
2296  > INLINE_MAX_ICMD_EXPANSION*caller->ctx->master->jd->instructioncount)
2297 #endif
2298  )
2299  {
2300  return false;
2301  }
2302 
2303  return true;
2304 }
2305 
2306 
2307 /* inline_is_monomorphic *******************************************************
2308 
2309  Check if the given call site can be proven to be monomorphic.
2310 
2311  IN:
2312  callee...........the called method
2313  call.............the invocation instruction
2314 
2315  OUT:
2316  site->speculative.....flags whether the inlining is speculative
2317  (only defined if return value is true)
2318 
2319  RETURN VALUE:
2320  true if the call site is (currently) monomorphic,
2321  false if not or unknown
2322 
2323 *******************************************************************************/
2324 
2325 static bool inline_is_monomorphic(const methodinfo *callee,
2326  const instruction *call,
2327  inline_site *site)
2328 {
2329  if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)
2330  || call->opc == ICMD_INVOKESPECIAL))
2331  {
2332  site->speculative = false;
2333  return true;
2334  }
2335 
2336  /* XXX search single implementation for abstract monomorphics */
2337 
2339  | ACC_ABSTRACT))
2341  {
2342  if (1) {
2343  DOLOG( printf("SPECULATIVE INLINE: "); method_println((methodinfo*)callee); );
2344  site->speculative = true;
2345 
2346  return true;
2347  }
2348  }
2349 
2350  /* possibly polymorphic call site */
2351 
2352  return false;
2353 }
2354 
2355 
2356 /* inline_can_inline ***********************************************************
2357 
2358  Check if inlining of the given call site is possible.
2359 
2360  IN:
2361  caller...........inlining node of the caller
2362  callee...........the called method
2363  call.............the invocation instruction
2364 
2365  OUT:
2366  site->speculative.....flags whether the inlining is speculative
2367  (only defined if return value is true)
2368 
2369  RETURN VALUE:
2370  true if inlining is possible, false if not
2371 
2372 *******************************************************************************/
2373 
2374 static bool inline_can_inline(const inline_node *caller,
2375  const methodinfo *callee,
2376  const instruction *call,
2377  inline_site *site)
2378 {
2379  const inline_node *active;
2380 
2381  /* cannot inline native methods */
2382 
2383  if (callee->flags & ACC_NATIVE)
2384  return false;
2385 
2386  /* cannot inline possibly polymorphic calls */
2387 
2388  if (!inline_is_monomorphic(callee, call, site))
2389  return false;
2390 
2391  /* cannot inline recursive calls */
2392 
2393  for (active = caller; active; active = active->parent) {
2394  if (callee == active->m) {
2395  DOLOG( printf("RECURSIVE!\n") );
2396  return false;
2397  }
2398  }
2399 
2400  /* inlining is possible */
2401 
2402  return true;
2403 }
2404 
2405 
2406 /* inline_create_callee_node ***************************************************
2407 
2408  Create an inlining node for the given callee.
2409 
2410  IN:
2411  caller...........inlining node of the caller (const)
2412  callee...........the called method
2413 
2414  RETURN VALUE:
2415  the new inlining node
2416 
2417 *******************************************************************************/
2418 
2420  methodinfo *callee)
2421 {
2422  inline_node *cn; /* the callee inline_node */
2423 
2424  cn = (inline_node*) DumpMemory::allocate(sizeof(inline_node));
2425  MZERO(cn, inline_node, 1);
2426 
2427  cn->depth = caller->depth + 1;
2428  cn->ctx = caller->ctx;
2429  cn->m = callee;
2430  cn->synchronize = (callee->flags & ACC_SYNCHRONIZED);
2431  cn->isstatic = (callee->flags & ACC_STATIC);
2432 
2433  return cn;
2434 }
2435 
2436 
2437 /* inline_set_callee_properties ************************************************
2438 
2439  Set properties of the inlined call site.
2440 
2441  IN:
2442  caller...........inlining node of the caller (const)
2443  cn...............the called method
2444  site.............info about the call site (const)
2445 
2446  OUT:
2447  *cn..............has the properties set
2448 
2449 *******************************************************************************/
2450 
2451 static void inline_set_callee_properties(const inline_node *caller,
2452  inline_node *cn,
2453  const inline_site *site)
2454 {
2455  s4 argi;
2456  s4 i, j;
2457  basicblock *bptr;
2458 
2459  /* set info about the call site */
2460 
2461  cn->callerblock = site->bptr;
2462  cn->callerins = site->iptr;
2463  cn->callerpc = site->pc;
2464  cn->o_handlers = site->handlers;
2465  cn->n_handlercount = caller->n_handlercount + site->nhandlers;
2466 
2467  /* determine if we need basic block boundaries before/after */
2468 
2469  cn->blockbefore = false;
2470  cn->blockafter = false;
2471 
2472  if (cn->jd->branchtoentry)
2473  cn->blockbefore = true;
2474 
2475  if (cn->jd->branchtoend)
2476  cn->blockafter = true;
2477 
2478  if (cn->jd->returncount > 1)
2479  cn->blockafter = true;
2480 
2481  /* XXX make safer and reusable (maybe store last real block) */
2482  for (bptr = cn->jd->basicblocks; bptr && bptr->next && bptr->next->next; bptr = bptr->next)
2483  ;
2484 
2485  if (cn->jd->returnblock != bptr)
2486  cn->blockafter = true;
2487 
2488  /* info about the callee */
2489 
2490  cn->localsoffset = caller->localsoffset + caller->m->maxlocals;
2492  cn->epilog_instructioncount = 1; /* INLINE_END */
2493  cn->extra_instructioncount = 0;
2494 
2495  /* we need a CHECKNULL for instance methods, except for <init> */
2496 
2497  if (!cn->isstatic && cn->m->name != utf8::init)
2498  cn->prolog_instructioncount += 1;
2499 
2500  /* deal with synchronized callees */
2501 
2502  if (cn->synchronize) {
2503  methoddesc *md;
2504  builtintable_entry *bte;
2505 
2506  /* we need basic block boundaries because of the handler */
2507 
2508  cn->blockbefore = true;
2509  cn->blockafter = true;
2510 
2511  /* for synchronized static methods */
2512  /* we need an ACONST, MONITORENTER in the prolog */
2513  /* and ACONST, MONITOREXIT in the epilog */
2514 
2515  /* for synchronized instance methods */
2516  /* we need an COPY, MONITORENTER in the prolog */
2517  /* and MONITOREXIT in the epilog */
2518 
2519  if (cn->isstatic) {
2520  cn->prolog_instructioncount += 2;
2521  cn->epilog_instructioncount += 2;
2522  }
2523  else {
2524  cn->prolog_instructioncount += 2;
2525  cn->epilog_instructioncount += 1;
2526  cn->localsoffset += 1;
2527  }
2528 
2529  /* and exception handler */
2530  /* ALOAD, builtin_monitorexit, ATHROW */
2531 
2532  cn->extra_instructioncount += 3;
2533 
2534  /* exception table entries */
2535 
2537 
2538  /* add exception handler block */
2539 
2541 
2542  /* we must call the builtins */
2543 
2545  md = bte->md;
2546  if (md->memuse > cn->regdata->memuse)
2547  cn->regdata->memuse = md->memuse;
2548  if (md->argintreguse > cn->regdata->argintreguse)
2549  cn->regdata->argintreguse = md->argintreguse;
2550 
2552  md = bte->md;
2553  if (md->memuse > cn->regdata->memuse)
2554  cn->regdata->memuse = md->memuse;
2555  if (md->argintreguse > cn->regdata->argintreguse)
2556  cn->regdata->argintreguse = md->argintreguse;
2557  }
2558 
2559  /* determine pass-through variables */
2560 
2561  i = site->iptr->s1.argcount - cn->m->parseddesc->paramcount; /* max # of pass-though vars */
2562 
2563  cn->n_passthroughvars = (s4*) DumpMemory::allocate(sizeof(s4) * i);
2564  j = 0;
2565  for (argi = site->iptr->s1.argcount - 1; argi >= cn->m->parseddesc->paramcount; --argi) {
2566  s4 idx = site->iptr->sx.s23.s2.args[argi];
2567  if (idx >= caller->jd->localcount) {
2568  cn->n_passthroughvars[j] = idx;
2569  j++;
2570  }
2571  else {
2572  DOLOG( printf("PASSING THROUGH LOCAL VARIABLE %d\n", idx); );
2573  }
2574  }
2575  assert(j <= i);
2576  cn->n_selfpassthroughcount = j;
2578 }
2579 
2580 
2581 /* inline_cumulate_counters ****************************************************
2582 
2583  Cumulate counters after a node has been decided to become inlined.
2584 
2585  IN:
2586  caller...........inlining node of the caller
2587  callee...........inlining node of the callee (const)
2588 
2589  OUT:
2590  *caller..........gets cumulated values added
2591 
2592 *******************************************************************************/
2593 
2595  const inline_node *cn)
2596 {
2600  caller->cumul_instructioncount += cn->cumul_instructioncount - 1 /*invoke*/;
2601 
2607 
2608  if (cn->cumul_maxlocals > caller->cumul_maxlocals)
2609  caller->cumul_maxlocals = cn->cumul_maxlocals;
2610 
2611  /* XXX extra block after inlined call */
2612  if (cn->blockafter) {
2613  caller->cumul_basicblockcount += 1;
2614  caller->cumul_blockmapcount += 1;
2615  }
2616 }
2617 
2618 
2619 /* inline_analyse_callee *******************************************************
2620 
2621  Analyse an inlining candidate callee.
2622 
2623  IN:
2624  caller...........inlining node of the caller
2625  callee...........the called method
2626  site.............info about the call site
2627 
2628  OUT:
2629  site->inlined....true if the callee has been selected for inlining
2630 
2631  RETURN VALUE:
2632  the inline node of the callee, or
2633  NULL if an error has occurred (don't use the inlining plan in this case)
2634 
2635 *******************************************************************************/
2636 
2638  methodinfo *callee,
2639  inline_site *site)
2640 {
2641  inline_node *cn; /* the callee inline_node */
2642 
2643  /* create an inline tree node */
2644 
2645  cn = inline_create_callee_node(caller, callee);
2646 
2647  /* get the intermediate representation of the callee */
2648 
2649  if (!inline_jit_compile(cn))
2650  return NULL;
2651 
2652  /* evaluate heuristics after parsing the callee */
2653 
2654  if (!inline_post_parse_heuristics(caller, cn))
2655  return cn;
2656 
2657  /* the call site will be inlined */
2658 
2659  site->inlined = true;
2660 
2661  /* set info about the call site */
2662 
2663  inline_set_callee_properties(caller, cn, site);
2664 
2665  /* insert the node into the inline tree */
2666 
2667  inline_insert_inline_node(caller, cn);
2668 
2669  /* analyse recursively */
2670 
2671  if (!inline_analyse_code(cn))
2672  return NULL;
2673 
2674  if (!inline_afterwards_heuristics(caller, cn)) {
2675 #if defined(INLINE_CANCEL_ON_THRESHOLD)
2676  return NULL;
2677 #else
2678  inline_remove_inline_node(caller, cn);
2679  caller->ctx->stopped = true;
2680  site->inlined = false;
2681  return cn;
2682 #endif
2683  }
2684 
2685  /* cumulate counters */
2686 
2687 #if defined(INLINE_DEPTH_FIRST)
2688  inline_cumulate_counters(caller, cn);
2689 #endif
2690 
2691 #if defined(INLINE_BREADTH_FIRST)
2692  while (caller) {
2693  inline_cumulate_counters(caller, cn);
2694  caller = caller->parent;
2695  }
2696 #endif
2697 
2698  return cn;
2699 }
2700 
2701 
2702 /* inline_process_candidate ****************************************************
2703 
2704  Process a selected inlining candidate.
2705 
2706  IN:
2707  cand.............the candidate
2708 
2709  RETURN VALUE:
2710  true........everything ok
2711  false.......an error has occurred, don't use the plan
2712 
2713 *******************************************************************************/
2714 
2716 {
2717  inline_node *cn;
2718 
2719  cn = inline_analyse_callee(cand->caller,
2720  cand->callee,
2721  &(cand->site));
2722 
2723  if (!cn)
2724  return false;
2725 
2726  if (!cand->site.inlined)
2727  return true;
2728 
2729  /* store assumptions */
2730 
2731  if (cand->site.speculative)
2733 
2734  return true;
2735 }
2736 
2737 
2738 /* inline_analyse_code *********************************************************
2739 
2740  Analyse the intermediate code of the given inlining node.
2741 
2742  IN:
2743  iln..............the inlining node
2744 
2745  OUT:
2746  *iln.............the inlining plan
2747 
2748  RETURN VALUE:
2749  true........everything ok
2750  false.......an error has occurred, don't use the plan
2751 
2752 *******************************************************************************/
2753 
2755 {
2756  methodinfo *m;
2757  basicblock *bptr;
2758  s4 len;
2759  instruction *iptr;
2760  methodinfo *callee;
2761  exception_entry **handlers;
2762  exception_entry *ex;
2763  s4 nhandlers;
2764  s4 blockendpc;
2765  jitdata *mjd;
2766  inline_site site;
2767 
2768  assert(iln);
2769 
2770  m = iln->m;
2771  mjd = iln->jd;
2772 
2773  /* initialize cumulative counters */
2774 
2775  iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
2777 
2778  /* iterate over basic blocks */
2779 
2780  blockendpc = 0;
2781 
2782  for (bptr = mjd->basicblocks; bptr; bptr = bptr->next) {
2783 
2784  /* count the block */
2785  /* ignore dummy end blocks (but count them for the blockmap) */
2786 
2787  iln->cumul_blockmapcount++;
2788  if ((bptr != mjd->basicblocks || iln->blockbefore)
2789  &&
2790  (bptr->icount > 0 || bptr->next != NULL))
2791  iln->cumul_basicblockcount++;
2792 
2793  /* skip dead code */
2794 
2795  if (bptr->state < basicblock::REACHED)
2796  continue;
2797 
2798  /* allocate the buffer of active exception handlers */
2799  /* XXX this wastes some memory, but probably it does not matter */
2800 
2801  handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (mjd->exceptiontablelength + 1));
2802 
2803  /* determine the active exception handlers for this block */
2804  /* XXX maybe the handlers of a block should be part of our IR */
2805  /* XXX this should share code with the type checkers */
2806  nhandlers = 0;
2807  for (ex = mjd->exceptiontable; ex ; ex = ex->down) {
2808  if ((ex->start->nr <= bptr->nr) && (ex->end->nr > bptr->nr)) {
2809  handlers[nhandlers++] = ex;
2810  }
2811  }
2812  handlers[nhandlers] = NULL;
2813 
2814  len = bptr->icount;
2815  iptr = bptr->iinstr;
2816 
2817  blockendpc += len;
2818  iln->cumul_instructioncount += len;
2819 
2820  /* iterate over the instructions of the block */
2821 
2822  for (; --len >= 0; ++iptr) {
2823 
2824  switch (iptr->opc) {
2825  case ICMD_INVOKEVIRTUAL:
2826  case ICMD_INVOKESPECIAL:
2827  case ICMD_INVOKESTATIC:
2828  case ICMD_INVOKEINTERFACE:
2829 
2830  if (!INSTRUCTION_IS_UNRESOLVED(iptr) && !iln->ctx->stopped) {
2831  callee = iptr->sx.s23.s3.fmiref->p.method;
2832 
2833  if (inline_can_inline(iln, callee, iptr, &site)) {
2834  site.inlined = false;
2835  site.bptr = bptr;
2836  site.iptr = iptr;
2837  site.pc = blockendpc - len - 1;
2838  site.handlers = handlers;
2839  site.nhandlers = nhandlers;
2840 
2841  if (inline_pre_parse_heuristics(iln, callee, &site)) {
2842 #if defined(INLINE_KNAPSACK) || defined(INLINE_BREADTH_FIRST)
2843  inline_add_candidate(iln->ctx, iln, callee, &site);
2844 #else
2845  inline_candidate cand;
2846  cand.caller = iln;
2847  cand.callee = callee;
2848  cand.site = site;
2849 
2850  if (!inline_process_candidate(&cand))
2851  return false;
2852 #endif
2853  }
2854  }
2855  }
2856  break;
2857 
2858  case ICMD_RETURN:
2859  case ICMD_IRETURN:
2860  case ICMD_ARETURN:
2861  case ICMD_LRETURN:
2862  case ICMD_FRETURN:
2863  case ICMD_DRETURN:
2864  /* extra ICMD_MOVE may be necessary */
2865  iln->cumul_instructioncount++;
2866  break;
2867  default:
2868  break;
2869  }
2870  }
2871 
2872  /* end of basic block */
2873  }
2874 
2875  return true;
2876 }
2877 
2878 
2880 {
2881  inline_node *child;
2882 
2883  child = iln->children;
2884  if (child) {
2885  do {
2887  inline_cumulate_counters(iln, child);
2888  child = child->next;
2889  } while (child != iln->children);
2890  }
2891 }
2892 
2893 
2894 /* inline_make_inlining_plan ***************************************************
2895 
2896  Make an inlining plan for the given root node
2897 
2898  IN:
2899  iln..............the root node
2900 
2901  OUT:
2902  *iln.............the inlining plan
2903 
2904  RETURN VALUE:
2905  true........everything ok
2906  false.......an error has occurred, don't use the plan
2907 
2908 *******************************************************************************/
2909 
2910 #if defined(INLINE_KNAPSACK)
2912 {
2913  inline_candidate *cand;
2914 #if defined(INLINE_COST_BUDGET)
2915  s4 budget = INLINE_COST_BUDGET;
2916 # define BUDGETMEMBER cost
2917 #endif
2918 #if defined(INLINE_WEIGHT_BUDGET)
2919  double budget = INLINE_WEIGHT_BUDGET;
2920 # define BUDGETMEMBER weight
2921 #endif
2922 
2923  inline_analyse_code(iln);
2924 
2925  DOLOG( printf("candidates in "); method_println(iln->m);
2926  inline_candidates_println(iln->ctx); );
2927 
2928  while ((cand = inline_pick_best_candidate(iln->ctx)) != NULL)
2929  {
2930  if (cand->BUDGETMEMBER <= budget) {
2931  DOLOG( printf(" picking: "); inline_candidate_println(cand); );
2932 
2933  if (!inline_process_candidate(cand))
2934  return false;
2935 
2936 #if !defined(INLINE_ADD_NEGATIVE_TO_BUDGET)
2937  if (cand->BUDGETMEMBER > 0)
2938 #endif
2939  budget -= cand->BUDGETMEMBER;
2940  }
2941  }
2942 
2944 
2945  return true;
2946 }
2947 #endif /* defined(INLINE_KNAPSACK) */
2948 
2949 
2950 #if defined(INLINE_DEPTH_FIRST)
2951 static bool inline_make_inlining_plan(inline_node *iln)
2952 {
2953  return inline_analyse_code(iln);
2954 }
2955 #endif /* defined(INLINE_DEPTH_FIRST) */
2956 
2957 
2958 #if defined(INLINE_BREADTH_FIRST)
2959 static bool inline_make_inlining_plan(inline_node *iln)
2960 {
2961  inline_candidate *cand;
2962 
2963  inline_analyse_code(iln);
2964 
2965  DOLOG( printf("candidates in "); method_println(iln->m);
2966  inline_candidates_println(iln->ctx); );
2967 
2968  while (!iln->ctx->stopped
2969  && (cand = inline_pick_best_candidate(iln->ctx)) != NULL)
2970  {
2971  DOLOG( printf(" picking: "); inline_candidate_println(cand); );
2972 
2973  if (!inline_process_candidate(cand))
2974  return false;
2975  }
2976 
2977  return true;
2978 }
2979 #endif /* defined(INLINE_BREADTH_FIRST) */
2980 
2981 
2982 /* statistics *****************************************************************/
2983 
2984 #if defined(INLINE_STATISTICS)
2986 {
2987  inline_node *child;
2988 
2990 
2991  if (iln->depth > inline_stat_max_depth)
2993 
2994  child = iln->children;
2995  if (child) {
2996  do {
2998  child = child->next;
2999  } while (child != iln->children);
3000  }
3001 }
3002 #endif /* defined(INLINE_STATISTICS) */
3003 
3004 
3005 #if defined(INLINE_STATISTICS)
3007 {
3009 
3011 }
3012 #endif /* defined(INLINE_STATISTICS) */
3013 
3014 
3015 /* post processing ************************************************************/
3016 
3017 #define POSTPROCESS_SRC(varindex) live[varindex]--
3018 #define POSTPROCESS_DST(varindex) live[varindex]++
3019 
3020 #define POSTPROCESS_SRCOP(s) POSTPROCESS_SRC(iptr->s.varindex)
3021 #define POSTPROCESS_DSTOP(d) POSTPROCESS_DST(iptr->d.varindex)
3022 
3023 #define MARKSAVED(varindex) jd->var[varindex].flags |= SAVEDVAR
3024 
3025 #define MARK_ALL_SAVED \
3026  do { \
3027  for (i=0; i<jd->vartop; ++i) \
3028  if (live[i]) \
3029  MARKSAVED(i); \
3030  } while (0)
3031 
3033 {
3034  codeinfo *code;
3035  basicblock *bptr;
3036  instruction *iptr;
3037  instruction *iend;
3038  s4 i;
3039  icmdtable_entry_t *icmdt;
3040  s4 *live;
3041  methoddesc *md;
3042  builtintable_entry *bte;
3043 
3044  /* Get required compiler data. */
3045 
3046  code = jd->code;
3047 
3048  /* reset the SAVEDVAR flag of all variables */
3049 
3050  for (i=0; i<jd->vartop; ++i)
3051  jd->var[i].flags &= ~SAVEDVAR;
3052 
3053  /* allocate the life counters */
3054 
3055  live = (s4*) DumpMemory::allocate(sizeof(s4) * jd->vartop);
3056  MZERO(live, s4, jd->vartop);
3057 
3058  /* iterate over all basic blocks */
3059 
3060  for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
3061  if (bptr->state < basicblock::REACHED)
3062  continue;
3063 
3064  /* make invars live */
3065 
3066  for (i=0; i<bptr->indepth; ++i)
3067  POSTPROCESS_DST(bptr->invars[i]);
3068 
3069  iptr = bptr->iinstr;
3070  iend = iptr + bptr->icount;
3071 
3072  for (; iptr < iend; ++iptr) {
3073 
3074  icmdt = &(icmd_table[iptr->opc]);
3075 
3076  switch (icmdt->dataflow) {
3077  case DF_3_TO_0:
3078  POSTPROCESS_SRCOP(sx.s23.s3);
3079  case DF_2_TO_0:
3080  POSTPROCESS_SRCOP(sx.s23.s2);
3081  case DF_1_TO_0:
3083  case DF_0_TO_0:
3084  if (icmdt->flags & ICMDTABLE_CALLS) {
3085  code_unflag_leafmethod(code);
3087  }
3088  break;
3089 
3090  case DF_2_TO_1:
3091  POSTPROCESS_SRCOP(sx.s23.s2);
3092  case DF_1_TO_1:
3093  case DF_MOVE:
3095  case DF_0_TO_1:
3096  if (icmdt->flags & ICMDTABLE_CALLS) {
3097  code_unflag_leafmethod(code);
3099  }
3100  case DF_COPY:
3101  POSTPROCESS_DSTOP(dst);
3102  break;
3103 
3104  case DF_N_TO_1:
3105  for (i=0; i<iptr->s1.argcount; ++i) {
3106  POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
3107  }
3108  if (icmdt->flags & ICMDTABLE_CALLS) {
3109  code_unflag_leafmethod(code);
3111  }
3112  POSTPROCESS_DSTOP(dst);
3113  break;
3114 
3115  case DF_INVOKE:
3116  INSTRUCTION_GET_METHODDESC(iptr, md);
3117  post_process_call:
3118  code_unflag_leafmethod(code);
3119  for (i=0; i<md->paramcount; ++i) {
3120  POSTPROCESS_SRC(iptr->sx.s23.s2.args[i]);
3121  }
3122  for (; i<iptr->s1.argcount; ++i) {
3123  MARKSAVED(iptr->sx.s23.s2.args[i]);
3124  }
3125  if (md->returntype.type != TYPE_VOID)
3126  POSTPROCESS_DSTOP(dst);
3127  break;
3128 
3129  case DF_BUILTIN:
3130  bte = iptr->sx.s23.s3.bte;
3131  md = bte->md;
3132  goto post_process_call;
3133 
3134  default:
3135  assert(0);
3136  }
3137 
3138  } /* end instruction loop */
3139 
3140  /* consume outvars */
3141 
3142  for (i=0; i<bptr->outdepth; ++i)
3143  POSTPROCESS_SRC(bptr->outvars[i]);
3144 
3145 #if !defined(NDEBUG)
3146  for (i=jd->localcount; i < jd->vartop; ++i)
3147  assert(live[i] == 0);
3148 #endif
3149 
3150  } /* end basic block loop */
3151 }
3152 
3153 
3154 /* inline_create_root_node *****************************************************
3155 
3156  Create the root node of the inlining tree.
3157 
3158  IN:
3159  jd...............the current jitdata of the root method
3160 
3161  RETURN VALUE:
3162  the root node of the inlining tree
3163 
3164 *******************************************************************************/
3165 
3167 {
3168  inline_node *iln;
3169 
3170  iln = (inline_node*) DumpMemory::allocate(sizeof(inline_node));
3171  MZERO(iln, inline_node, 1);
3172 
3173  iln->m = jd->m;
3174  iln->jd = jd;
3175  iln->regdata = jd->rd;
3176 
3177  iln->blockbefore = true;
3178  iln->blockafter = true;
3179 
3180  iln->cumul_instructioncount = 0;
3181  iln->cumul_basicblockcount = 1 /* dummy end block */;
3182 
3183  /* create inlining context */
3184 
3186  MZERO(iln->ctx, inline_context, 1);
3187  iln->ctx->master = iln;
3188  iln->ctx->next_debugnr = 1; /* XXX debug */
3189 
3190  return iln;
3191 }
3192 
3193 
3194 /******************************************************************************/
3195 /* MAIN DRIVER FUNCTION */
3196 /******************************************************************************/
3197 
3199 {
3200  inline_node *iln;
3201 
3202  DOLOG( printf("==== INLINE ==================================================================\n");
3203  show_method(jd, SHOW_STACK); );
3204 
3205 #if defined(INLINE_STATISTICS)
3207 #endif
3208 
3209  iln = inline_create_root_node(jd);
3210 
3211  if (inline_make_inlining_plan(iln)) {
3212 
3213  /* add blocks to the root node */
3214 
3217 
3218  DOLOG( printf("==== INLINE TRANSFORM ========================================================\n"); );
3219 
3220  if (iln->children)
3221  inline_transform(iln, jd);
3222 
3223 #if defined(INLINE_STATISTICS)
3225 #endif
3226  }
3227 
3228  DOLOG( printf("-------- DONE -----------------------------------------------------------\n");
3229  fflush(stdout); );
3230 
3231  return true;
3232 }
3233 
3234 
3235 /*
3236  * These are local overrides for various environment variables in Emacs.
3237  * Please do not remove this and leave it at the end of the file, where
3238  * Emacs will automagically detect them.
3239  * ---------------------------------------------------------------------
3240  * Local variables:
3241  * mode: c++
3242  * indent-tabs-mode: t
3243  * c-basic-offset: 4
3244  * tab-width: 4
3245  * End:
3246  * vim:noexpandtab:sw=4:ts=4:
3247  */
val_operand_t val
static void close_body_block(inline_node *iln, basicblock *n_bptr, basicblock *o_bptr, s4 *varmap, s4 retcount, s4 retidx)
Definition: inline.cpp:1022
Utf8String name
Definition: method.hpp:71
inline_node * prev
Definition: inline.cpp:145
int maxinoutdepth
Definition: inline.cpp:230
std::size_t index
methodinfo * outer
int n_resultlocal
Definition: inline.cpp:158
basicblock * block
union varinfo::@19 vv
int argintreguse
Definition: reg.hpp:86
static void inline_cumulate_counters(inline_node *caller, const inline_node *cn)
Definition: inline.cpp:2594
LiveInSetTy & live
s4 exceptiontablelength
Definition: jit.hpp:167
basicblock * handler_monitorexit
Definition: inline.cpp:172
#define DF_1_TO_0
Definition: icmd.hpp:335
inline_block_map * blockmap
Definition: inline.cpp:227
#define CF_GOTO
Definition: icmd.hpp:376
basicblock * basicblocks
Definition: jit.hpp:141
Definition: lsra.hpp:67
insinfo_inline * parent
union inline_target_ref::@10 ref
Definition: jit.hpp:126
int * freemem
Definition: reg.hpp:81
#define DF_2_TO_0
Definition: icmd.hpp:336
#define BASICBLOCK_INIT(bptr, m)
Definition: jit.hpp:423
Definition: stack.hpp:46
s4 jcodelength
Definition: method.hpp:85
#define DF_1_TO_1
Definition: icmd.hpp:342
methoddesc * md
Definition: builtin.hpp:71
basicblock * returnblock
Definition: jit.hpp:170
static bool inline_make_inlining_plan(inline_node *iln)
Definition: inline.cpp:2911
int epilog_instructioncount
Definition: inline.cpp:168
static bool inline_afterwards_heuristics(const inline_node *caller, const inline_node *callee)
Definition: inline.cpp:2276
exception_entry ** handlers
Definition: inline.cpp:243
s4 localcount
Definition: jit.hpp:152
exception_entry * exceptiontable
Definition: jit.hpp:168
#define INLINE_COST_OFFSET
Definition: inline.cpp:82
bool blockbefore
Definition: inline.cpp:162
#define CF_RET
Definition: icmd.hpp:380
static void inline_block_translation(inline_node *iln, basicblock *o_bptr, basicblock *n_bptr)
Definition: inline.cpp:695
int cumul_exceptiontablelength
Definition: inline.cpp:182
s4 bitflags
Definition: jit.hpp:314
inline_site site
Definition: inline.cpp:255
State state
Definition: jit.hpp:313
bool inline_inline(jitdata *jd)
Definition: inline.cpp:3198
bool inlined
Definition: inline.cpp:239
s4 maxlocals
Definition: jit.hpp:162
s4 * invars
Definition: jit.hpp:323
inline_node * master
Definition: inline.cpp:220
basicblock * next
Definition: jit.hpp:337
#define POSTPROCESS_DST(varindex)
Definition: inline.cpp:3018
static bool inline_jit_compile(inline_node *iln)
Definition: inline.cpp:330
int localsoffset
Definition: inline.cpp:166
methodinfo * callee
Definition: inline.cpp:254
static exception_entry * inline_exception_tables(inline_node *iln, exception_entry *n_extable, exception_entry **prevextable)
Definition: inline.cpp:1760
#define ICMDTABLE_CALLS
Definition: icmd.hpp:385
static void inline_candidates_println(inline_context *ctx)
Definition: inline.cpp:530
codeinfo * code
Definition: jit.hpp:128
static inline_candidate * inline_pick_best_candidate(inline_context *ctx)
Definition: inline.cpp:506
insinfo_inline * inlineinfo
Definition: jit.hpp:343
s4 outdepth
Definition: jit.hpp:326
int32_t * stackvars
static void inline_insert_inline_node(inline_node *parent, inline_node *child)
Definition: inline.cpp:395
u1 optlevel
Definition: code.hpp:80
static void inline_write_exception_handlers(inline_node *master, inline_node *iln)
Definition: inline.cpp:1929
int32_t argcount
Definition: instruction.hpp:64
varinfo * var
Definition: jit.hpp:148
static basicblock * inline_map_block(inline_node *iln, basicblock *o_block, inline_node *targetiln)
Definition: inline.cpp:710
bool typecheck(jitdata *jd)
Definition: typecheck.cpp:684
#define show_method(...)
Definition: ssa2.cpp:41
#define CF_JSR
Definition: icmd.hpp:379
#define DF_0_TO_0
Definition: icmd.hpp:334
bool opt_intrp
Definition: options.cpp:55
codegendata * cd
Definition: jit.hpp:129
int32_t varindex
Definition: instruction.hpp:63
u4 flags
Definition: jit.hpp:138
jitdata * jd
Definition: inline.cpp:141
typedef void(JNICALL *jvmtiEventSingleStep)(jvmtiEnv *jvmti_env
static void close_prolog_block(inline_node *iln, basicblock *n_bptr, inline_node *nextcall)
Definition: inline.cpp:1008
s4 vartop
Definition: jit.hpp:149
int extra_exceptiontablelength
Definition: inline.cpp:170
methodinfo * m
Definition: inline.cpp:142
static s4 inline_new_temp_variable(jitdata *jd, Type type)
Definition: inline.cpp:579
#define CF_TABLE
Definition: icmd.hpp:377
inline_node * parent
Definition: inline.cpp:149
basicblock * target
Definition: inline.cpp:209
inline_candidate * next
Definition: inline.cpp:249
inline_node * children
Definition: inline.cpp:143
registerdata * regdata
Definition: inline.cpp:191
basicblock * o_block
Definition: inline.cpp:215
#define DF_3_TO_0
Definition: icmd.hpp:337
static bool inline_jit_compile_intern(jitdata *jd)
Definition: inline.cpp:299
static void code_unflag_leafmethod(codeinfo *code)
Definition: code.hpp:161
static void inline_post_process(jitdata *jd)
Definition: inline.cpp:3032
Type type
Definition: reg.hpp:44
static void inline_set_callee_properties(const inline_node *caller, inline_node *cn, const inline_site *site)
Definition: inline.cpp:2451
int cumul_blockmapcount
Definition: inline.cpp:180
static inline_node * inline_create_callee_node(const inline_node *caller, methodinfo *callee)
Definition: inline.cpp:2419
varinfo * inlocals
Definition: jit.hpp:321
instruction * callerins
Definition: inline.cpp:151
lookup_target_t * lookup
instruction * iinstr
Definition: jit.hpp:319
static bool inline_post_parse_heuristics(const inline_node *caller, const inline_node *callee)
Definition: inline.cpp:2253
Definition: reg.hpp:43
s4 icount
Definition: jit.hpp:318
void inline_print_stats()
Definition: inline.cpp:286
inline_target_ref * next
Definition: inline.cpp:204
s4 * varmap
Definition: inline.cpp:173
#define MZERO(ptr, type, num)
Definition: memory.hpp:105
instruction * iptr
Definition: inline.cpp:242
static s4 inline_new_variable_clone(jitdata *jd, jitdata *origjd, s4 origidx)
Definition: inline.cpp:564
s4 * javalocals
Definition: inline.cpp:196
void(* functionptr)(void)
Definition: global.hpp:39
s4 varcount
Definition: jit.hpp:151
s4 * javalocals
Definition: jit.hpp:322
typedesc paramtypes[1]
Definition: descriptor.hpp:167
void link(basicblock *v, basicblock *w)
Definition: dominator.cpp:178
#define IS_2_WORD_TYPE(a)
Definition: global.hpp:132
int next_debugnr
Definition: inline.cpp:234
int prolog_instructioncount
Definition: inline.cpp:167
#define MARK_ALL_SAVED
Definition: inline.cpp:3025
#define JITDATA_FLAG_SHOWINTERMEDIATE
Definition: jit.hpp:195
static bool inline_is_monomorphic(const methodinfo *callee, const instruction *call, inline_site *site)
Definition: inline.cpp:2325
static inline_node * inline_analyse_callee(inline_node *caller, methodinfo *callee, inline_site *site)
Definition: inline.cpp:2637
Indent indent
Definition: OStream.cpp:54
jlong jlong jlong jlong jint depth
Definition: jvmti.h:497
void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
Definition: show.cpp:449
#define INLINE_RETURN_REFERENCE(callee)
Definition: inline.cpp:665
int synclocal
Definition: inline.cpp:159
#define MARKSAVED(varindex)
Definition: inline.cpp:3023
classref_or_classinfo c
#define DF_N_TO_1
Definition: icmd.hpp:345
inline_candidate * candidates
Definition: inline.cpp:224
builtintable_entry * builtintable_get_internal(functionptr fp)
Definition: builtin.cpp:275
basicblock * inlined_basicblocks_cursor
Definition: inline.cpp:188
int cumul_basicblockcount_root
Definition: inline.cpp:178
static bool inline_analyse_code(inline_node *iln)
Definition: inline.cpp:2754
static void emit_inlining_epilog(inline_node *iln, inline_node *callee, instruction *o_iptr)
Definition: inline.cpp:1253
#define POSTPROCESS_DSTOP(d)
Definition: inline.cpp:3021
bool isstatic
Definition: inline.cpp:160
#define DOLOG_SHORT(code)
Definition: inline.cpp:117
static void inline_generate_sync_builtin(inline_node *iln, inline_node *callee, instruction *o_iptr, s4 instancevar, functionptr func)
Definition: inline.cpp:1069
branch_target_t target
Definition: instruction.hpp:57
dst_operand_t dst
flags_operand_t flags
#define SHOW_STACK
Definition: show.hpp:41
instruction * inlined_iinstr
Definition: inline.cpp:185
methodinfo * method
jitdata * jit_jitdata_new(methodinfo *m)
Definition: jit.cpp:217
#define LOCK_monitor_enter
Definition: builtin.hpp:124
#define INLINE_COUNTDOWN_INIT
Definition: inline.cpp:81
void method_println(methodinfo *m)
Definition: method.cpp:1218
bool stack_analyse(jitdata *jd)
Definition: stack.cpp:2144
classinfo * clazz
Definition: method.hpp:80
int inline_stat_inlined_nodes
Definition: inline.cpp:283
int32_t dataflow
Definition: icmd.hpp:395
static basicblock * create_epilog_block(inline_node *caller, inline_node *callee, s4 *varmap)
Definition: inline.cpp:924
basicblock * start
Definition: jit.hpp:234
This file contains the statistics framework.
int inline_stat_roots_transformed
Definition: inline.cpp:282
basicblock ** block
Definition: inline.cpp:206
basicblock * handler
Definition: jit.hpp:236
s4 returncount
Definition: jit.hpp:172
static void * reallocate(void *src, size_t len1, size_t len2)
Stupid realloc implementation for dump memory.
Definition: dumpmemory.cpp:57
void reg_setup(jitdata *jd)
Definition: reg.cpp:42
int32_t paramcount
#define CF_IF
Definition: icmd.hpp:371
#define DF_COPY
Definition: icmd.hpp:350
#define POSTPROCESS_SRC(varindex)
Definition: inline.cpp:3017
int extra_instructioncount
Definition: inline.cpp:169
Type
Types used internally by JITTED code.
Definition: global.hpp:117
static bool inline_can_inline(const inline_node *caller, const methodinfo *callee, const instruction *call, inline_site *site)
Definition: inline.cpp:2374
instruction * inlined_iinstr_cursor
Definition: inline.cpp:186
classref_or_classinfo catchtype
Definition: jit.hpp:237
s4 indepth
Definition: jit.hpp:325
basicblock * n_block
Definition: inline.cpp:216
static basicblock * create_body_block(inline_node *iln, basicblock *o_bptr, s4 *varmap)
Definition: inline.cpp:889
#define DF_0_TO_1
Definition: icmd.hpp:341
static void inline_candidate_println(inline_candidate *cand)
Definition: inline.cpp:520
s4 * local_map
Definition: jit.hpp:153
int cumul_instructioncount
Definition: inline.cpp:176
int inline_stat_max_depth
Definition: inline.cpp:284
#define INLINE_COST_BUDGET
Definition: inline.cpp:83
#define VERIFIER_EXTRA_LOCALS
Definition: global.hpp:373
MIIterator i
typedesc returntype
Definition: descriptor.hpp:166
bool branchtoentry
Definition: jit.hpp:173
int32_t s4
Definition: types.hpp:45
int argfltreguse
Definition: reg.hpp:89
s4 * n_passthroughvars
Definition: inline.cpp:153
int32_t * javalocals_start
ICMD
Definition: icmd.hpp:37
registerdata * rd
Definition: jit.hpp:130
#define DF_MOVE
Definition: icmd.hpp:351
s4 maxlocals
Definition: method.hpp:84
int next_block_number
Definition: inline.cpp:226
s4 * outvars
Definition: jit.hpp:324
int blockmap_index
Definition: inline.cpp:228
int n_selfpassthroughcount
Definition: inline.cpp:155
union instruction::@12 sx
bool synchronize
Definition: inline.cpp:171
static void inline_rewrite_method(inline_node *iln)
Definition: inline.cpp:1429
s4 instructioncount
Definition: jit.hpp:143
Mutex * mutex
Definition: method.hpp:69
exception_entry * down
Definition: jit.hpp:240
s4 nhandlers
Definition: inline.cpp:244
#define CF_LOOKUP
Definition: icmd.hpp:378
#define LOCK_monitor_exit
Definition: builtin.hpp:132
static void inline_gather_statistics(inline_node *iln)
Definition: inline.cpp:3006
bool blockafter
Definition: inline.cpp:163
void stack_javalocals_store(instruction *iptr, s4 *javalocals)
Definition: stack.cpp:4692
int32_t varindex
icmdtable_entry_t icmd_table[256]
Definition: icmd.cpp:60
#define INSTRUCTION_GET_METHODDESC(iptr, md)
#define DOLOG(code)
Definition: inline.cpp:116
static void inline_remove_inline_node(inline_node *parent, inline_node *child)
Definition: inline.cpp:446
s1_operand_t s1
exception_entry ** o_handlers
Definition: inline.cpp:156
basicblock * block
Definition: instruction.hpp:50
inline_node * next
Definition: inline.cpp:144
int32_t controlflow
Definition: icmd.hpp:396
static inline_node * inline_create_root_node(jitdata *jd)
Definition: inline.cpp:3166
int inline_stat_roots
Definition: inline.cpp:281
static void inline_add_candidate(inline_context *ctx, inline_node *caller, methodinfo *callee, inline_site *site)
Definition: inline.cpp:469
static bool inline_transform(inline_node *iln, jitdata *jd)
Definition: inline.cpp:2010
void show_icmd(jitdata *jd, instruction *iptr, bool deadcode, int stage)
Definition: show.cpp:917
methoddesc * parseddesc
Definition: method.hpp:78
inline_node * iln
Definition: inline.cpp:214
int memuse
Definition: reg.hpp:84
static void inline_interface_variables(inline_node *iln)
Definition: inline.cpp:1873
Definition: builtin.hpp:60
methodinfo * m
Definition: jit.hpp:127
static s4 inline_translate_variable(jitdata *jd, jitdata *origjd, s4 *varmap, s4 index)
Definition: inline.cpp:585
int cumul_maxlocals
Definition: inline.cpp:181
s4 maxinterfaces
Definition: jit.hpp:165
basicblock * end
Definition: jit.hpp:235
static bool inline_pre_parse_heuristics(const inline_node *caller, const methodinfo *callee, inline_site *site)
Definition: inline.cpp:2225
interface_info * interface_map
Definition: jit.hpp:164
static basicblock * create_block(inline_node *container, inline_node *iln, inline_node *inner, int indepth)
Definition: inline.cpp:781
int cumul_basicblockcount
Definition: inline.cpp:177
bool parse(jitdata *jd)
Definition: parse.cpp:604
s4 flags
Definition: reg.hpp:45
#define TRANSLATE_VAROP(vo)
Definition: inline.cpp:1283
#define DF_INVOKE
Definition: icmd.hpp:347
static void * allocate(size_t size)
Definition: dumpmemory.hpp:251
bool speculative
Definition: inline.cpp:238
s4 nr
Definition: jit.hpp:312
static void inline_cumulate_counters_recursive(inline_node *iln)
Definition: inline.cpp:2879
void exceptions_clear_exception(void)
Definition: exceptions.cpp:127
int8_t s1
Definition: types.hpp:39
s4 basicblockcount
Definition: jit.hpp:144
int n_handlercount
Definition: inline.cpp:157
#define INSTRUCTION_IS_UNRESOLVED(iptr)
bool branchtoend
Definition: jit.hpp:174
Definition: icmd.hpp:391
struct instruction::@12::@13 s23
jitdata * resultjd
Definition: inline.cpp:222
void unlock()
Unlocks the given mutex object and checks for errors.
Definition: mutex-none.hpp:36
void jit_check_basicblock_numbers(jitdata *jd)
Definition: jit.cpp:1177
#define POSTPROCESS_SRCOP(s)
Definition: inline.cpp:3020
#define JAVALOCAL_FROM_RETADDR(nr)
Definition: jit.hpp:416
#define JITDATA_FLAG_SHOWDISASSEMBLE
Definition: jit.hpp:196
basicblock * callerblock
Definition: inline.cpp:150
int debugnr
Definition: inline.cpp:200
basicblock * inlined_basicblocks
Definition: inline.cpp:187
int32_t throughcount
void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
Definition: method.cpp:1085
static void inline_add_block_reference(inline_node *iln, basicblock **blockp)
Definition: inline.cpp:669
static s4 emit_inlining_prolog(inline_node *iln, inline_node *callee, instruction *o_iptr, s4 *varmap)
Definition: inline.cpp:1102
Definition: jit.hpp:233
#define MCOPY(dest, src, type, num)
Definition: memory.hpp:103
s4 flags
Definition: method.hpp:70
int32_t stackvarscount
inline_target_ref * refs
Definition: inline.cpp:194
static instruction * inline_instruction(inline_node *iln, ICMD opcode, instruction *o_iptr)
Definition: inline.cpp:1053
#define INS_FLAG_ID_MASK
#define DF_BUILTIN
Definition: icmd.hpp:348
instruction * inline_start_instruction
Definition: inline.cpp:195
char * indent
Definition: inline.cpp:199
static s4 * translate_javalocals(inline_node *iln, s4 *javalocals)
Definition: inline.cpp:864
basicblock * bptr
Definition: inline.cpp:241
static void inline_gather_statistics_recursive(inline_node *iln)
Definition: inline.cpp:2985
instruction * instructions
Definition: jit.hpp:140
Type type
Definition: jit.hpp:315
#define printf(...)
Definition: ssa2.cpp:40
LoopTreeGraph * parent
static bool inline_process_candidate(inline_candidate *cand)
Definition: inline.cpp:2715
#define DF_2_TO_1
Definition: icmd.hpp:343
branch_target_t * table
static s4 inline_new_variable(jitdata *jd, Type type, s4 flags)
Definition: inline.cpp:544
void log_message_class(const char *msg, classinfo *c)
Definition: logging.cpp:237
void lock()
Locks the given mutex object and checks for errors.
Definition: mutex-none.hpp:35
static void inline_locals(inline_node *iln)
Definition: inline.cpp:1848
int n_passthroughcount
Definition: inline.cpp:154
inline_context * ctx
Definition: inline.cpp:139
int32_t flags
Definition: icmd.hpp:397
inline_node * caller
Definition: inline.cpp:253
int32_t * javalocals_end
static void inline_clone_instruction(inline_node *iln, jitdata *jd, jitdata *origjd, s4 *varmap, instruction *o_iptr, instruction *n_iptr)
Definition: inline.cpp:1287
#define VERIFIER_EXTRA_VARS
Definition: global.hpp:374
static s4 * create_variable_map(inline_node *callee)
Definition: inline.cpp:600
methodinfo * method
static void close_block(inline_node *iln, inline_node *inner, basicblock *n_bptr, s4 outdepth)
Definition: inline.cpp:970
static void inline_resolve_block_refs(inline_target_ref **refs, basicblock *o_bptr, basicblock *n_bptr, bool returnref)
Definition: inline.cpp:738