1 /* src/vm/jit/optimizing/escape.c
4 CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
6 This file is part of CACAO.
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.
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.
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
28 #include "vm/class.hpp"
29 #include "vm/classcache.hpp"
31 #include "vm/jit/jit.hpp"
32 #include "vm/jit/optimizing/escape.h"
36 #if defined(ENABLE_ESCAPE_REASON)
40 #if defined(ENABLE_REASON)
41 #define I2(why, tov, es) escape_analysis_record_reason(e, why, iptr, tov, es);
43 #define I2(why, tov, es)
45 #define I(why, to, from) I2(why, instruction_ ## to (iptr), escape_analysis_get_state(e, instruction_ ## from (iptr)))
46 #define E2(why, var) I2(why, var, ESCAPE_GLOBAL)
47 #define E(why, which) E2(why, instruction_ ## which (iptr))
62 static void color_start(color_t color) {
63 #if defined(ENABLE_COLOR)
64 if (RED <= color && color < COLOR_END) {
65 printf("\033[%dm", color);
70 static void color_end() {
71 #if defined(ENABLE_COLOR)
77 static void color_printf(color_t color, const char *fmt, ...) {
87 /*** escape_state *************************************************************/
89 const char *escape_state_to_string(escape_state_t escape_state) {
90 # define str(x) case x: return #x;
91 switch (escape_state) {
95 str(ESCAPE_METHOD_RETURN)
97 default: return "???";
102 /*** instruction **************************************************************/
104 static inline s2 instruction_get_opcode(const instruction *iptr) {
105 if (iptr->opc == ICMD_BUILTIN) {
106 return iptr->sx.s23.s3.bte->opcode;
112 static inline bool instruction_is_unresolved(const instruction *iptr) {
113 return iptr->flags.bits & INS_FLAG_UNRESOLVED;
116 static inline s4 instruction_field_type(const instruction *iptr) {
117 if (instruction_is_unresolved(iptr)) {
118 return iptr->sx.s23.s3.uf->fieldref->parseddesc.fd->type;
120 return iptr->sx.s23.s3.fmiref->p.field->type;
124 static inline s4 instruction_s1(const instruction *iptr) {
125 return iptr->s1.varindex;
128 static inline s4 instruction_s2(const instruction *iptr) {
129 return iptr->sx.s23.s2.varindex;
132 static inline s4 instruction_s3(const instruction *iptr) {
133 return iptr->sx.s23.s3.varindex;
136 static inline s4 instruction_dst(const instruction *iptr) {
137 return iptr->dst.varindex;
140 static inline s4 instruction_arg(const instruction *iptr, int arg) {
141 return iptr->sx.s23.s2.args[arg];
144 static inline bool instruction_is_class_constant(const instruction *iptr) {
145 return iptr->flags.bits & INS_FLAG_CLASS;
148 static inline classinfo *instruction_classinfo(const instruction *iptr) {
149 return iptr->sx.val.c.cls;
152 static inline methodinfo *instruction_local_methodinfo(const instruction *iptr) {
153 if (instruction_is_unresolved(iptr)) {
156 return iptr->sx.s23.s3.fmiref->p.method;
160 static inline int instruction_dst_type(const instruction *iptr, jitdata *jd) {
161 return VAROP(iptr->dst)->type;
164 static inline int instruction_return_type(const instruction *iptr) {
165 return instruction_call_site(iptr)->returntype.type;
168 static inline s4 instruction_arg_type(const instruction *iptr, int arg) {
169 methoddesc *md = instruction_call_site(iptr);
170 assert(0 <= arg && arg < md->paramcount);
171 return md->paramtypes[arg].type;
174 static inline int instruction_arg_count(const instruction *iptr) {
175 return instruction_call_site(iptr)->paramcount;
178 /*** instruction_list ********************************************************/
180 typedef struct instruction_list_item {
182 struct instruction_list_item *next;
183 } instruction_list_item_t;
186 instruction_list_item_t *first;
187 } instruction_list_t;
189 void instruction_list_init(instruction_list_t *list) {
193 void instruction_list_add(instruction_list_t *list, instruction *instr) {
194 instruction_list_item_t *item = DNEW(instruction_list_item_t);
196 item->next = list->first;
200 #define FOR_EACH_INSTRUCTION_LIST(list, it) \
201 for ((it) = (list)->first; (it) != NULL; (it) = (it)->next)
203 /*** escape_analysis *********************************************************/
210 instruction_list_t *allocations;
211 instruction_list_t *getfields;
212 instruction_list_t *monitors;
213 instruction_list_t *returns;
215 struct var_extra **var;
217 unsigned adr_args_count;
223 /*** dependency_list_item ****************************************************/
225 typedef struct dependency_list_item {
227 struct dependency_list_item *next;
228 } dependency_list_item_t;
230 bool dependency_list_item_compare(const dependency_list_item_t *item, const instruction *load) {
232 instruction *store = item->store;
236 if (load->opc == ICMD_AALOAD) {
238 if (store->opc != ICMD_AASTORE) {
246 if (store->opc != ICMD_PUTFIELD) {
251 instruction_is_unresolved(store) !=
252 instruction_is_unresolved(load)
257 if (instruction_is_unresolved(store)) {
258 storen = store->sx.s23.s3.uf->fieldref->name;
259 loadn = load->sx.s23.s3.uf->fieldref->name;
261 storen = store->sx.s23.s3.fmiref->name;
262 loadn = load->sx.s23.s3.fmiref->name;
265 /* TODO pointer equality ? */
267 if (storen->blength != loadn->blength) {
271 return (strcmp(storen->text, loadn->text) == 0);
276 s4 dependency_list_item_get_dependency(const dependency_list_item_t *item) {
277 switch (item->store->opc) {
279 return instruction_s3(item->store);
281 return instruction_s2(item->store);
288 /*** dependency_list *********************************************************/
291 dependency_list_item_t *first;
292 dependency_list_item_t *last;
295 void dependency_list_init(dependency_list_t *dl) {
300 void dependency_list_add(dependency_list_t *dl, instruction *store) {
301 dependency_list_item_t *item = DNEW(dependency_list_item_t);
306 if (dl->first == NULL) {
310 dl->last->next = item;
315 void dependenCy_list_import(dependency_list_t *dl, dependency_list_t *other) {
321 if (dl->first == NULL) {
324 dl->last->next = other->first;
325 dl->last = other->last;
333 #define FOR_EACH_DEPENDENCY_LIST(dl, it) \
334 for ((it) = (dl)->first; (it) != NULL; (it) = (it)->next)
336 /*** var_extra ***************************************************************/
338 #if defined(ENABLE_REASON)
339 typedef struct reason {
346 typedef struct var_extra {
347 instruction *allocation;
348 escape_state_t escape_state;
350 dependency_list_t *dependency_list;
351 unsigned contains_arg:1;
352 unsigned contains_only_args:1;
353 /*signed adr_arg_num:30;*/
354 #if defined(ENABLE_REASON)
359 static void var_extra_init(var_extra_t *ve) {
360 ve->allocation = NULL;
361 ve->escape_state = ESCAPE_NONE;
362 ve->representant = -1;
363 ve->dependency_list = NULL;
364 ve->contains_arg = false;
365 ve->contains_only_args = false;
366 /*ve->adr_arg_num = -1;*/
367 #if defined(ENABLE_REASON)
372 static inline var_extra_t *var_extra_get_no_alloc(const escape_analysis_t *e, s4 var) {
376 static var_extra_t* var_extra_get(escape_analysis_t *e, s4 var) {
379 assert(0 <= var && var <= e->jd->vartop);
381 ve = var_extra_get_no_alloc(e, var);
384 ve = DNEW(var_extra_t);
392 static s4 var_extra_get_representant(escape_analysis_t *e, s4 var) {
398 ve = var_extra_get(e, var);
400 while (ve->representant != -1) {
401 assert(ctr++ < 10000);
402 var = ve->representant;
403 ve = var_extra_get_no_alloc(e, var);
410 static escape_state_t var_extra_get_escape_state(escape_analysis_t *e, s4 var) {
413 var = var_extra_get_representant(e, var);
414 ve = var_extra_get(e, var);
416 return ve->escape_state;
419 static void var_extra_set_escape_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
422 var = var_extra_get_representant(e, var);
423 ve = var_extra_get(e, var);
425 ve->escape_state = escape_state;
428 static dependency_list_t *var_extra_get_dependency_list(escape_analysis_t *e, s4 var) {
431 var = var_extra_get_representant(e, var);
432 ve = var_extra_get(e, var);
434 if (ve->dependency_list == NULL) {
435 ve->dependency_list = DNEW(dependency_list_t);
436 dependency_list_init(ve->dependency_list);
439 return ve->dependency_list;
442 /*** escape_analysis *********************************************************/
444 static void escape_analysis_init(escape_analysis_t *e, jitdata *jd) {
447 e->allocations = DNEW(instruction_list_t);
448 instruction_list_init(e->allocations);
450 e->getfields = DNEW(instruction_list_t);
451 instruction_list_init(e->getfields);
453 e->monitors = DNEW(instruction_list_t);
454 instruction_list_init(e->monitors);
456 e->returns = DNEW(instruction_list_t);
457 instruction_list_init(e->returns);
459 e->var = DMNEW(var_extra_t *, jd->vartop);
460 MZERO(e->var, var_extra_t *, jd->vartop);
462 e->adr_args_count = 0;
465 e->verbose = strcmp(jd->m->name->text, "<init>") == 0;
466 e->verbose = getenv("EV") != NULL;
469 #if defined(ENABLE_REASON)
470 static void escape_analysis_record_reason(escape_analysis_t *e, const char *why, instruction *iptr, s4 var, escape_state_t es) {
473 if (es == ESCAPE_GLOBAL || es == ESCAPE_METHOD_RETURN) {
474 var = var_extra_get_representant(e, var);
475 ve = var_extra_get(e, var);
479 re->next = ve->reasons;
482 printf("%d escapes because %s\n", var, why);
488 static void escape_analysis_set_allocation(escape_analysis_t *e, s4 var, instruction *iptr) {
489 var_extra_get(e, var)->allocation = iptr;
492 static instruction *escape_analysis_get_allocation(const escape_analysis_t *e, s4 var) {
493 var_extra_t *ve = var_extra_get_no_alloc(e, var);
496 assert(ve->allocation != NULL);
498 return ve->allocation;
501 static void escape_analysis_set_contains_argument(escape_analysis_t *e, s4 var) {
502 var = var_extra_get_representant(e, var);
503 var_extra_get(e, var)->contains_arg = true;
506 static bool escape_analysis_get_contains_argument(escape_analysis_t *e, s4 var) {
507 var = var_extra_get_representant(e, var);
508 return var_extra_get(e, var)->contains_arg;
511 static void escape_analysis_set_contains_only_arguments(escape_analysis_t *e, s4 var) {
512 var = var_extra_get_representant(e, var);
513 var_extra_get(e, var)->contains_only_args = true;
516 static bool escape_analysis_get_contains_only_arguments(escape_analysis_t *e, s4 var) {
517 var = var_extra_get_representant(e, var);
518 return var_extra_get(e, var)->contains_only_args;
522 static void escape_analysis_set_adr_arg_num(escape_analysis_t *e, s4 var, s4 num) {
523 var_extra_get(e, var)->adr_arg_num = num;
526 static s4 escape_analysis_get_adr_arg_num(escape_analysis_t *e, s4 var) {
527 return var_extra_get(e, var)->adr_arg_num;
531 static bool escape_analysis_in_same_set(escape_analysis_t *e, s4 var1, s4 var2) {
532 return var_extra_get_representant(e, var1) == var_extra_get_representant(e, var2);
535 static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
538 dependency_list_item_t *it;
540 var = var_extra_get_representant(e, var);
541 ve = var_extra_get(e, var);
543 if (ve->escape_state < escape_state) {
546 "escape state of %d %s => %s\n",
548 escape_state_to_string(ve->escape_state),
549 escape_state_to_string(escape_state)
552 ve->escape_state = escape_state;
553 if (ve->dependency_list != NULL) {
554 FOR_EACH_DEPENDENCY_LIST(ve->dependency_list, it) {
556 printf("propagating to %s@%d\n", icmd_table[it->store->opc].name, it->store->line);
558 escape_analysis_ensure_state(
560 dependency_list_item_get_dependency(it),
564 instruction *iptr = NULL;
565 I2("propagated by dependency", dependency_list_item_get_dependency(it), escape_state);
572 static escape_state_t escape_analysis_get_state(escape_analysis_t *e, s4 var) {
573 return var_extra_get_escape_state(e, var);
576 static classinfo *escape_analysis_classinfo_in_var(escape_analysis_t *e, s4 var) {
577 instruction *iptr = escape_analysis_get_allocation(e, var);
583 if (! instruction_is_class_constant(iptr)) {
587 if (instruction_dst(iptr) != var) {
591 if (instruction_is_unresolved(iptr)) {
595 return instruction_classinfo(iptr);
598 static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
600 var_extra_t *ve1, *ve2;
601 dependency_list_item_t *itd;
604 var1 = var_extra_get_representant(e, var1);
605 var2 = var_extra_get_representant(e, var2);
607 /* Don't merge the same escape sets. */
613 if (e->verbose) printf("Merging (%d,%d)\n", var1, var2);
615 ve1 = var_extra_get(e, var1);
616 ve2 = var_extra_get(e, var2);
618 /* Adjust escape state to maximal escape state. */
620 escape_analysis_ensure_state(e, var1, ve2->escape_state);
621 escape_analysis_ensure_state(e, var2, ve1->escape_state);
623 /* Representant of var1 becomes the representant of var2. */
625 ve2->representant = var1;
627 /* Adjust is_arg to logical or. */
629 has_become_arg = ve1->contains_arg != ve2->contains_arg;
630 ve1->contains_arg = ve1->contains_arg || ve2->contains_arg;
632 if (e->verbose && has_become_arg) printf("(%d,%d) has become arg.\n", var1, var2);
634 /* Merge list of dependencies. */
636 if (ve1->dependency_list == NULL) {
637 ve1->dependency_list = ve2->dependency_list;
639 dependenCy_list_import(ve1->dependency_list, ve2->dependency_list);
642 /* If one of the merged values is an argument but the other not,
643 all dependencies of the newly created value escape globally. */
645 if (has_become_arg && ve1->dependency_list != NULL) {
646 FOR_EACH_DEPENDENCY_LIST(ve1->dependency_list, itd) {
647 escape_analysis_ensure_state(
649 dependency_list_item_get_dependency(itd),
653 instruction *iptr = NULL;
654 E2("has become arg", dependency_list_item_get_dependency(itd));
659 /* Adjust contains_only_args to logical and. */
661 ve1->contains_only_args = ve1->contains_only_args && ve2->contains_only_args;
663 /* Adjust address argument number contained in this var. */
666 if (ve1->adr_arg_num != ve2->adr_arg_num) {
667 ve1->adr_arg_num = -1;
670 #if defined(ENABLE_REASON)
672 reason_t *re = ve1->reasons;
673 while (re->next != NULL) {
676 re->next = ve2->reasons;
678 ve1->reasons = ve2->reasons;
683 static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *store) {
684 s4 obj = instruction_s1(store);
685 dependency_list_t *dl = var_extra_get_dependency_list(e, obj);
687 assert(store->opc == ICMD_PUTFIELD || store->opc == ICMD_AASTORE);
689 dependency_list_add(dl, store);
692 printf("dependency_list_add: %d.dependency_list.add( { ", obj);
693 show_icmd(e->jd, store, 0, 3);
698 static void escape_analysis_process_instruction(escape_analysis_t *e, instruction *iptr) {
711 printf("%d: ", iptr->line);
712 show_icmd(e->jd, iptr, 0, 3);
717 switch (instruction_get_opcode(iptr)) {
720 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
721 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
726 c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
728 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
731 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
732 E("unresolved class", dst)
733 } else if (c->finalizer != NULL) {
734 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
737 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
740 instruction_list_add(e->allocations, iptr);
744 case ICMD_MONITORENTER:
745 case ICMD_MONITOREXIT:
747 instruction_list_add(e->monitors, iptr);
754 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
755 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
756 instruction_list_add(e->allocations, iptr);
757 E("untracked array", dst)
761 if (instruction_field_type(iptr) == TYPE_ADR) {
762 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
768 if (instruction_field_type(iptr) == TYPE_ADR) {
769 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
770 escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_GLOBAL);
771 /* If s1 is currently not an argument, but can contain one later because
772 of a phi function, the merge function takes care to make all
773 dependencies escape globally. */
774 E("putfield into argument", s2)
776 I("putfield inherit", s2, s1);
777 escape_analysis_ensure_state(e, instruction_s2(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
778 escape_analysis_add_dependency(e, iptr);
784 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
785 if (e->verbose) printf("Contains argument.\n");
786 escape_analysis_ensure_state(e, instruction_s3(iptr), ESCAPE_GLOBAL);
787 E("aastore into argument", s3)
789 if (e->verbose) printf("Contains no argument.\n");
791 escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
792 escape_analysis_add_dependency(e, iptr);
797 if (instruction_field_type(iptr) == TYPE_ADR) {
798 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
799 E("loaded from static var", dst)
800 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
805 if (instruction_field_type(iptr) == TYPE_ADR) {
807 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
808 /* Fields loaded from arguments escape globally.
811 => y escapes globally. */
812 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
813 E("loaded from arg", dst)
815 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
818 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
820 instruction_list_add(e->getfields, iptr);
824 case ICMD_ARRAYLENGTH:
825 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
830 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
831 /* If store into argument, escapes globally. See ICMD_GETFIELD. */
832 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
833 E("aaload from argument", dst)
835 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
838 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
840 instruction_list_add(e->getfields, iptr);
845 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
846 escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_METHOD);
851 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
855 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
856 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
860 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
861 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
862 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
865 case ICMD_INSTANCEOF:
866 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
869 case ICMD_INVOKESPECIAL:
870 case ICMD_INVOKEVIRTUAL:
871 case ICMD_INVOKEINTERFACE:
872 case ICMD_INVOKESTATIC:
873 count = instruction_arg_count(iptr);
874 mi = instruction_local_methodinfo(iptr);
879 /* If the method could be resolved, it already is. */
880 paramescape = mi->paramescape;
884 printf("Paramescape for callee available.\n");
888 if (paramescape) why = "Available param escape";
890 if (paramescape == NULL) {
892 printf("BC escape analyzing callee.\n");
894 why = "BC param escape";
895 bc_escape_analysis_perform(mi);
896 paramescape = mi->paramescape;
900 printf("Unresolved callee.\n");
902 why = "Unresolved callee";
905 if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
906 if (mi != NULL && !escape_is_monomorphic(e->jd->m, mi)) {
908 printf("Not monomorphic.\n");
915 /* Set the escape state of the return value.
916 This is: global if we down have information of the callee, or the callee
917 supplied escape state. */
919 if (instruction_return_type(iptr) == TYPE_ADR) {
920 if (paramescape == NULL) {
921 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
924 es = escape_state_from_u1(paramescape[-1]);
925 I2(why, instruction_dst(iptr), es)
926 escape_analysis_ensure_state(e, instruction_dst(iptr), es);
928 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
931 for (i = 0; i < count; ++i) {
932 if (instruction_arg_type(iptr, i) == TYPE_ADR) {
934 if (paramescape == NULL) {
935 escape_analysis_ensure_state(
937 instruction_arg(iptr, i),
940 E2(why, instruction_arg(iptr, i));
941 } else if (escape_state_from_u1(*paramescape) <= ESCAPE_METHOD) {
942 es = escape_state_from_u1(*paramescape);
944 if (es < ESCAPE_METHOD) {
948 I2(why, instruction_arg(iptr, i), es);
949 escape_analysis_ensure_state(e, instruction_arg(iptr, i), es);
951 if (*paramescape & 0x80) {
952 /* Parameter can be returned from method.
953 This creates an alias to the retur value.
954 If the return value escapes, the ES of the parameter needs
956 escape_analysis_merge(e, instruction_arg(iptr, i), instruction_dst(iptr));
957 I2("return alias", instruction_arg(iptr, i), instruction_dst(iptr));
960 escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_GLOBAL);
961 E2(why, instruction_arg(iptr, i));
964 if (paramescape != NULL) {
973 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
978 /* If we return only arguments, the return value escapes only the method.
979 ESCAPE_METHOD for now, and check later, if a different value than an
980 argument is possibly returned. */
981 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD_RETURN);
983 instruction_list_add(e->returns, iptr);
990 if (instruction_dst_type(iptr, jd) == TYPE_ADR) {
991 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
992 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
998 iarg = iptr->sx.s23.s2.iargs;
999 iarg != iptr->sx.s23.s2.iargs + iptr->s1.argcount;
1002 escape_analysis_merge(e, instruction_dst(iptr), instruction_dst(*iarg));
1006 case ICMD_GETEXCEPTION:
1007 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
1012 static void escape_analysis_process_instructions(escape_analysis_t *e) {
1016 FOR_EACH_BASICBLOCK(e->jd, bptr) {
1019 color_printf(CYAN, "=== BB %d ===\n", bptr->nr);
1022 for (iptr = bptr->phis; iptr != bptr->phis + bptr->phicount; ++iptr) {
1023 escape_analysis_process_instruction(e, iptr);
1026 FOR_EACH_INSTRUCTION(bptr, iptr) {
1027 escape_analysis_process_instruction(e, iptr);
1033 static void escape_analysis_post_process_returns(escape_analysis_t *e) {
1034 instruction_list_item_t *iti;
1037 if (e->verbose) printf("Post processing returns:\n");
1039 FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
1042 if (! escape_analysis_get_contains_only_arguments(e, instruction_s1(iptr))) {
1043 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
1044 E("return of not argument", s1)
1049 static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
1050 instruction_list_item_t *iti;
1051 dependency_list_item_t *itd;
1053 dependency_list_t *dl;
1055 if (e->verbose) printf("Post processing getfields:\n");
1057 FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
1061 /* Get the object the field/element is loaded from. */
1063 dl = var_extra_get_dependency_list(e, instruction_s1(iptr));
1065 /* Adjust escape state of all objects in the dependency list,
1066 referenced via the field of this getfield/arraystore. */
1069 FOR_EACH_DEPENDENCY_LIST(dl, itd) {
1070 if (dependency_list_item_compare(itd, iptr)) {
1072 /* Fields match. Adjust escape state. */
1074 escape_analysis_ensure_state(
1076 dependency_list_item_get_dependency(itd),
1077 escape_analysis_get_state(e, instruction_dst(iptr))
1079 I2("post process getfield", dependency_list_item_get_dependency(itd), escape_analysis_get_state(e, instruction_dst(iptr)));
1087 static void escape_analysis_mark_monitors(escape_analysis_t *e) {
1088 instruction_list_item_t *iti;
1091 FOR_EACH_INSTRUCTION_LIST(e->monitors, iti) {
1094 /* TODO if argument does not escape, mark. */
1095 if (escape_analysis_get_state(e, instruction_arg(iptr, 0)) != ESCAPE_GLOBAL) {
1097 printf("Monitor on thread local object!\n");
1103 static void escape_analysis_mark_allocations(escape_analysis_t *e) {
1104 instruction_list_item_t *iti;
1107 FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1109 es = escape_analysis_get_state(e, instruction_dst(iptr));
1111 #if defined(ENABLE_REASON)
1112 if (instruction_get_opcode(iptr) == ICMD_NEW) {
1114 iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_escape_reason_new);
1115 ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
1116 iptr->escape_reasons = ve->reasons;
1117 if (es < ESCAPE_METHOD_RETURN) {
1118 assert(!ve->reasons);
1119 reason_t *r = NEW(reason_t);
1120 r->why = "No escape\n";
1123 iptr->escape_reasons = r;
1125 assert(iptr->escape_reasons);
1131 if (instruction_get_opcode(iptr) == ICMD_NEW) {
1132 es = escape_analysis_get_state(e, instruction_dst(iptr));
1133 if (es < ESCAPE_METHOD_RETURN) {
1134 iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_tlh_new);
1135 e->jd->code->flags |= CODE_FLAG_TLH;
1142 static void escape_analysis_process_arguments(escape_analysis_t *e) {
1149 md = e->jd->m->parseddesc;
1151 for (p = 0, l = 0; p < md->paramcount; ++p) {
1152 t = md->paramtypes[p].type;
1153 varindex = e->jd->local_map[l * 5 + t];
1154 if (t == TYPE_ADR) {
1155 if (varindex != UNUSED) {
1156 escape_analysis_ensure_state(e, varindex, ESCAPE_NONE);
1157 escape_analysis_set_contains_argument(e, varindex);
1158 escape_analysis_set_contains_only_arguments(e, varindex);
1159 /*escape_analysis_set_adr_arg_num(e, varindex, e->adr_args_count);*/
1161 e->adr_args_count += 1;
1163 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1167 static void escape_analysis_export_arguments(escape_analysis_t *e) {
1174 instruction_list_item_t *iti;
1176 escape_state_t es, re;
1179 md = e->jd->m->parseddesc;
1181 ret_val_is_adr = (md->returntype.type == TYPE_ADR) ? 1 : 0;
1183 paramescape = MNEW(u1, e->adr_args_count + ret_val_is_adr);
1185 e->jd->m->paramescape = paramescape + ret_val_is_adr;
1187 for (p = 0, l = 0; p < md->paramcount; ++p) {
1188 t = md->paramtypes[p].type;
1189 varindex = e->jd->local_map[l * 5 + t];
1190 if (t == TYPE_ADR) {
1191 if (varindex == UNUSED) {
1192 *paramescape = (u1)ESCAPE_NONE;
1194 es = escape_analysis_get_state(e, varindex);
1196 if (es == ESCAPE_METHOD_RETURN) {
1197 *paramescape = escape_state_to_u1(ESCAPE_METHOD) | 0x80;
1199 printf("non-escaping adr parameter returned: %d\n", p);
1202 *paramescape = escape_state_to_u1(es);
1208 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1211 if (ret_val_is_adr) {
1212 /* Calculate escape state of return value as maximum escape state of all
1217 FOR_EACH_INSTRUCTION_LIST(e->returns, iti) {
1219 es = escape_analysis_get_state(e, instruction_s1(iptr));
1226 e->jd->m->paramescape[-1] = escape_state_to_u1(re);
1230 #if defined(ENABLE_REASON)
1231 void print_escape_reasons() {
1232 reason_t *re = THREADOBJECT->escape_reasons;
1234 fprintf(stderr, "DYN_REASON");
1236 for (; re; re = re->next) {
1237 fprintf(stderr,":%s", re->why);
1240 fprintf(stderr, "\n");
1243 void set_escape_reasons(void *vp) {
1244 THREADOBJECT->escape_reasons = vp;
1248 static void escape_analysis_display(escape_analysis_t *e) {
1249 instruction_list_item_t *iti;
1253 FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1255 ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
1256 show_icmd(e->jd, iptr-1, 0, 3);
1258 show_icmd(e->jd, iptr, 0, 3);
1261 "%s@%d: --%s-- %d\n\n",
1262 icmd_table[iptr->opc].name,
1264 escape_state_to_string(ve->escape_state),
1267 #if defined(ENABLE_REASON)
1270 for (re = ve->reasons; re; re = re->next) {
1271 printf("ESCAPE_REASON: %s\n", re->why);
1278 void escape_analysis_perform(jitdata *jd) {
1279 escape_analysis_t *e;
1281 jd->m->flags |= ACC_METHOD_EA;
1283 e = DNEW(escape_analysis_t);
1284 escape_analysis_init(e, jd);
1287 color_printf(RED, "\n\n==== %s/%s ====\n\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
1289 escape_analysis_process_arguments(e);
1290 escape_analysis_process_instructions(e);
1291 escape_analysis_post_process_getfields(e);
1292 escape_analysis_post_process_returns(e);
1294 escape_analysis_export_arguments(e);
1295 if (e->verbose) escape_analysis_display(e);
1299 for (i = 0; i < jd->vartop; ++i) {
1300 r = var_extra_get_representant(e, i);
1302 printf("EES of %d: ", i);
1303 for (j = 0; j < jd->vartop; ++j) {
1304 if (var_extra_get_representant(e, j) == r) {
1314 escape_analysis_mark_allocations(e);
1315 escape_analysis_mark_monitors(e);
1317 jd->m->flags &= ~ACC_METHOD_EA;
1320 void escape_analysis_escape_check(void *vp) {
1323 /*** monomorphic *************************************************************/
1325 bool escape_is_monomorphic(methodinfo *caller, methodinfo *callee) {
1327 /* Non-speculative case */
1329 if (callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
1334 (callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED| ACC_ABSTRACT))
1335 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)
1338 /* Mark that we have used the information about monomorphy. */
1340 callee->flags |= ACC_METHOD_MONOMORPHY_USED;
1342 /* We assume the callee is monomorphic. */
1344 method_add_assumption_monomorphic(caller, callee);