1 /* src/vm/optimizing/e&scape.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
24 #include "vm/jit/jit.h"
25 #include "vmcore/class.h"
26 #include "vmcore/classcache.h"
27 #include "vm/jit/optimizing/escape.h"
31 #if defined(ENABLE_ESCAPE_REASON)
35 #if defined(ENABLE_REASON)
36 #define I2(why, tov, es) escape_analysis_record_reason(e, why, iptr, tov, es);
38 #define I2(why, tov, es)
40 #define I(why, to, from) I2(why, instruction_ ## to (iptr), escape_analysis_get_state(e, instruction_ ## from (iptr)))
41 #define E2(why, var) I2(why, var, ESCAPE_GLOBAL)
42 #define E(why, which) E2(why, instruction_ ## which (iptr))
57 static void color_start(color_t color) {
58 #if defined(ENABLE_COLOR)
59 if (RED <= color && color < COLOR_END) {
60 printf("\033[%dm", color);
65 static void color_end() {
66 #if defined(ENABLE_COLOR)
72 static void color_printf(color_t color, const char *fmt, ...) {
82 /*** escape_state *************************************************************/
84 const char *escape_state_to_string(escape_state_t escape_state) {
85 # define str(x) case x: return #x;
86 switch (escape_state) {
90 str(ESCAPE_METHOD_RETURN)
92 default: return "???";
97 /*** instruction **************************************************************/
99 static inline s2 instruction_get_opcode(const instruction *iptr) {
100 if (iptr->opc == ICMD_BUILTIN) {
101 return iptr->sx.s23.s3.bte->opcode;
107 static inline bool instruction_is_unresolved(const instruction *iptr) {
108 return iptr->flags.bits & INS_FLAG_UNRESOLVED;
111 static inline s4 instruction_field_type(const instruction *iptr) {
112 if (instruction_is_unresolved(iptr)) {
113 return iptr->sx.s23.s3.uf->fieldref->parseddesc.fd->type;
115 return iptr->sx.s23.s3.fmiref->p.field->type;
119 static inline s4 instruction_s1(const instruction *iptr) {
120 return iptr->s1.varindex;
123 static inline s4 instruction_s2(const instruction *iptr) {
124 return iptr->sx.s23.s2.varindex;
127 static inline s4 instruction_s3(const instruction *iptr) {
128 return iptr->sx.s23.s3.varindex;
131 static inline s4 instruction_dst(const instruction *iptr) {
132 return iptr->dst.varindex;
135 static inline s4 instruction_arg(const instruction *iptr, int arg) {
136 return iptr->sx.s23.s2.args[arg];
139 static inline bool instruction_is_class_constant(const instruction *iptr) {
140 return iptr->flags.bits & INS_FLAG_CLASS;
143 static inline classinfo *instruction_classinfo(const instruction *iptr) {
144 return iptr->sx.val.c.cls;
147 static inline methodinfo *instruction_local_methodinfo(const instruction *iptr) {
148 if (instruction_is_unresolved(iptr)) {
151 return iptr->sx.s23.s3.fmiref->p.method;
155 static inline int instruction_dst_type(const instruction *iptr, jitdata *jd) {
156 return VAROP(iptr->dst)->type;
159 static inline int instruction_return_type(const instruction *iptr) {
160 return instruction_call_site(iptr)->returntype.type;
163 static inline s4 instruction_arg_type(const instruction *iptr, int arg) {
164 methoddesc *md = instruction_call_site(iptr);
165 assert(0 <= arg && arg < md->paramcount);
166 return md->paramtypes[arg].type;
169 static inline int instruction_arg_count(const instruction *iptr) {
170 return instruction_call_site(iptr)->paramcount;
173 /*** instruction_list ********************************************************/
175 typedef struct instruction_list_item {
177 struct instruction_list_item *next;
178 } instruction_list_item_t;
181 instruction_list_item_t *first;
182 } instruction_list_t;
184 void instruction_list_init(instruction_list_t *list) {
188 void instruction_list_add(instruction_list_t *list, instruction *instr) {
189 instruction_list_item_t *item = DNEW(instruction_list_item_t);
191 item->next = list->first;
195 #define FOR_EACH_INSTRUCTION_LIST(list, it) \
196 for ((it) = (list)->first; (it) != NULL; (it) = (it)->next)
198 /*** escape_analysis *********************************************************/
205 instruction_list_t *allocations;
206 instruction_list_t *getfields;
207 instruction_list_t *monitors;
208 instruction_list_t *returns;
210 struct var_extra **var;
212 unsigned adr_args_count;
218 /*** dependency_list_item ****************************************************/
220 typedef struct dependency_list_item {
222 struct dependency_list_item *next;
223 } dependency_list_item_t;
225 bool dependency_list_item_compare(const dependency_list_item_t *item, const instruction *load) {
227 instruction *store = item->store;
231 if (load->opc == ICMD_AALOAD) {
233 if (store->opc != ICMD_AASTORE) {
241 if (store->opc != ICMD_PUTFIELD) {
246 instruction_is_unresolved(store) !=
247 instruction_is_unresolved(load)
252 if (instruction_is_unresolved(store)) {
253 storen = store->sx.s23.s3.uf->fieldref->name;
254 loadn = load->sx.s23.s3.uf->fieldref->name;
256 storen = store->sx.s23.s3.fmiref->name;
257 loadn = load->sx.s23.s3.fmiref->name;
260 /* TODO pointer equality ? */
262 if (storen->blength != loadn->blength) {
266 return (strcmp(storen->text, loadn->text) == 0);
271 s4 dependency_list_item_get_dependency(const dependency_list_item_t *item) {
272 switch (item->store->opc) {
274 return instruction_s3(item->store);
276 return instruction_s2(item->store);
283 /*** dependency_list *********************************************************/
286 dependency_list_item_t *first;
287 dependency_list_item_t *last;
290 void dependency_list_init(dependency_list_t *dl) {
295 void dependency_list_add(dependency_list_t *dl, instruction *store) {
296 dependency_list_item_t *item = DNEW(dependency_list_item_t);
301 if (dl->first == NULL) {
305 dl->last->next = item;
310 void dependenCy_list_import(dependency_list_t *dl, dependency_list_t *other) {
316 if (dl->first == NULL) {
319 dl->last->next = other->first;
320 dl->last = other->last;
328 #define FOR_EACH_DEPENDENCY_LIST(dl, it) \
329 for ((it) = (dl)->first; (it) != NULL; (it) = (it)->next)
331 /*** var_extra ***************************************************************/
333 #if defined(ENABLE_REASON)
334 typedef struct reason {
341 typedef struct var_extra {
342 instruction *allocation;
343 escape_state_t escape_state;
345 dependency_list_t *dependency_list;
346 unsigned contains_arg:1;
347 unsigned contains_only_args:1;
348 /*signed adr_arg_num:30;*/
349 #if defined(ENABLE_REASON)
354 static void var_extra_init(var_extra_t *ve) {
355 ve->allocation = NULL;
356 ve->escape_state = ESCAPE_NONE;
357 ve->representant = -1;
358 ve->dependency_list = NULL;
359 ve->contains_arg = false;
360 ve->contains_only_args = false;
361 /*ve->adr_arg_num = -1;*/
362 #if defined(ENABLE_REASON)
367 static inline var_extra_t *var_extra_get_no_alloc(const escape_analysis_t *e, s4 var) {
371 static var_extra_t* var_extra_get(escape_analysis_t *e, s4 var) {
374 assert(0 <= var && var <= e->jd->vartop);
376 ve = var_extra_get_no_alloc(e, var);
379 ve = DNEW(var_extra_t);
387 static s4 var_extra_get_representant(escape_analysis_t *e, s4 var) {
393 ve = var_extra_get(e, var);
395 while (ve->representant != -1) {
396 assert(ctr++ < 10000);
397 var = ve->representant;
398 ve = var_extra_get_no_alloc(e, var);
405 static escape_state_t var_extra_get_escape_state(escape_analysis_t *e, s4 var) {
408 var = var_extra_get_representant(e, var);
409 ve = var_extra_get(e, var);
411 return ve->escape_state;
414 static void var_extra_set_escape_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
417 var = var_extra_get_representant(e, var);
418 ve = var_extra_get(e, var);
420 ve->escape_state = escape_state;
423 static dependency_list_t *var_extra_get_dependency_list(escape_analysis_t *e, s4 var) {
426 var = var_extra_get_representant(e, var);
427 ve = var_extra_get(e, var);
429 if (ve->dependency_list == NULL) {
430 ve->dependency_list = DNEW(dependency_list_t);
431 dependency_list_init(ve->dependency_list);
434 return ve->dependency_list;
437 /*** escape_analysis *********************************************************/
439 static void escape_analysis_init(escape_analysis_t *e, jitdata *jd) {
442 e->allocations = DNEW(instruction_list_t);
443 instruction_list_init(e->allocations);
445 e->getfields = DNEW(instruction_list_t);
446 instruction_list_init(e->getfields);
448 e->monitors = DNEW(instruction_list_t);
449 instruction_list_init(e->monitors);
451 e->returns = DNEW(instruction_list_t);
452 instruction_list_init(e->returns);
454 e->var = DMNEW(var_extra_t *, jd->vartop);
455 MZERO(e->var, var_extra_t *, jd->vartop);
457 e->adr_args_count = 0;
460 e->verbose = strcmp(jd->m->name->text, "<init>") == 0;
461 e->verbose = getenv("EV") != NULL;
464 #if defined(ENABLE_REASON)
465 static void escape_analysis_record_reason(escape_analysis_t *e, const char *why, instruction *iptr, s4 var, escape_state_t es) {
468 if (es == ESCAPE_GLOBAL || es == ESCAPE_METHOD_RETURN) {
469 var = var_extra_get_representant(e, var);
470 ve = var_extra_get(e, var);
474 re->next = ve->reasons;
477 printf("%d escapes because %s\n", var, why);
483 static void escape_analysis_set_allocation(escape_analysis_t *e, s4 var, instruction *iptr) {
484 var_extra_get(e, var)->allocation = iptr;
487 static instruction *escape_analysis_get_allocation(const escape_analysis_t *e, s4 var) {
488 var_extra_t *ve = var_extra_get_no_alloc(e, var);
491 assert(ve->allocation != NULL);
493 return ve->allocation;
496 static void escape_analysis_set_contains_argument(escape_analysis_t *e, s4 var) {
497 var = var_extra_get_representant(e, var);
498 var_extra_get(e, var)->contains_arg = true;
501 static bool escape_analysis_get_contains_argument(escape_analysis_t *e, s4 var) {
502 var = var_extra_get_representant(e, var);
503 return var_extra_get(e, var)->contains_arg;
506 static void escape_analysis_set_contains_only_arguments(escape_analysis_t *e, s4 var) {
507 var = var_extra_get_representant(e, var);
508 var_extra_get(e, var)->contains_only_args = true;
511 static bool escape_analysis_get_contains_only_arguments(escape_analysis_t *e, s4 var) {
512 var = var_extra_get_representant(e, var);
513 return var_extra_get(e, var)->contains_only_args;
517 static void escape_analysis_set_adr_arg_num(escape_analysis_t *e, s4 var, s4 num) {
518 var_extra_get(e, var)->adr_arg_num = num;
521 static s4 escape_analysis_get_adr_arg_num(escape_analysis_t *e, s4 var) {
522 return var_extra_get(e, var)->adr_arg_num;
526 static bool escape_analysis_in_same_set(escape_analysis_t *e, s4 var1, s4 var2) {
527 return var_extra_get_representant(e, var1) == var_extra_get_representant(e, var2);
530 static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
533 dependency_list_item_t *it;
535 var = var_extra_get_representant(e, var);
536 ve = var_extra_get(e, var);
538 if (ve->escape_state < escape_state) {
541 "escape state of %d %s => %s\n",
543 escape_state_to_string(ve->escape_state),
544 escape_state_to_string(escape_state)
547 ve->escape_state = escape_state;
548 if (ve->dependency_list != NULL) {
549 FOR_EACH_DEPENDENCY_LIST(ve->dependency_list, it) {
551 printf("propagating to %s@%d\n", icmd_table[it->store->opc].name, it->store->line);
553 escape_analysis_ensure_state(
555 dependency_list_item_get_dependency(it),
559 instruction *iptr = NULL;
560 I2("propagated by dependency", dependency_list_item_get_dependency(it), escape_state);
567 static escape_state_t escape_analysis_get_state(escape_analysis_t *e, s4 var) {
568 return var_extra_get_escape_state(e, var);
571 static classinfo *escape_analysis_classinfo_in_var(escape_analysis_t *e, s4 var) {
572 instruction *iptr = escape_analysis_get_allocation(e, var);
578 if (! instruction_is_class_constant(iptr)) {
582 if (instruction_dst(iptr) != var) {
586 if (instruction_is_unresolved(iptr)) {
590 return instruction_classinfo(iptr);
593 static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
595 var_extra_t *ve1, *ve2;
596 dependency_list_item_t *itd;
599 var1 = var_extra_get_representant(e, var1);
600 var2 = var_extra_get_representant(e, var2);
602 /* Don't merge the same escape sets. */
608 if (e->verbose) printf("Merging (%d,%d)\n", var1, var2);
610 ve1 = var_extra_get(e, var1);
611 ve2 = var_extra_get(e, var2);
613 /* Adjust escape state to maximal escape state. */
615 escape_analysis_ensure_state(e, var1, ve2->escape_state);
616 escape_analysis_ensure_state(e, var2, ve1->escape_state);
618 /* Representant of var1 becomes the representant of var2. */
620 ve2->representant = var1;
622 /* Adjust is_arg to logical or. */
624 has_become_arg = ve1->contains_arg != ve2->contains_arg;
625 ve1->contains_arg = ve1->contains_arg || ve2->contains_arg;
627 if (e->verbose && has_become_arg) printf("(%d,%d) has become arg.\n", var1, var2);
629 /* Merge list of dependencies. */
631 if (ve1->dependency_list == NULL) {
632 ve1->dependency_list = ve2->dependency_list;
634 dependenCy_list_import(ve1->dependency_list, ve2->dependency_list);
637 /* If one of the merged values is an argument but the other not,
638 all dependencies of the newly created value escape globally. */
640 if (has_become_arg && ve1->dependency_list != NULL) {
641 FOR_EACH_DEPENDENCY_LIST(ve1->dependency_list, itd) {
642 escape_analysis_ensure_state(
644 dependency_list_item_get_dependency(itd),
648 instruction *iptr = NULL;
649 E2("has become arg", dependency_list_item_get_dependency(itd));
654 /* Adjust contains_only_args to logical and. */
656 ve1->contains_only_args = ve1->contains_only_args && ve2->contains_only_args;
658 /* Adjust address argument number contained in this var. */
661 if (ve1->adr_arg_num != ve2->adr_arg_num) {
662 ve1->adr_arg_num = -1;
665 #if defined(ENABLE_REASON)
667 reason_t *re = ve1->reasons;
668 while (re->next != NULL) {
671 re->next = ve2->reasons;
673 ve1->reasons = ve2->reasons;
678 static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *store) {
679 s4 obj = instruction_s1(store);
680 dependency_list_t *dl = var_extra_get_dependency_list(e, obj);
682 assert(store->opc == ICMD_PUTFIELD || store->opc == ICMD_AASTORE);
684 dependency_list_add(dl, store);
687 printf("dependency_list_add: %d.dependency_list.add( { ", obj);
688 show_icmd(e->jd, store, 0, 3);
693 static void escape_analysis_process_instruction(escape_analysis_t *e, instruction *iptr) {
706 printf("%d: ", iptr->line);
707 show_icmd(e->jd, iptr, 0, 3);
712 switch (instruction_get_opcode(iptr)) {
715 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
716 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
721 c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
723 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
726 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
727 E("unresolved class", dst)
728 } else if (c->finalizer != NULL) {
729 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
732 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
735 instruction_list_add(e->allocations, iptr);
739 case ICMD_MONITORENTER:
740 case ICMD_MONITOREXIT:
742 instruction_list_add(e->monitors, iptr);
749 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
750 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
751 instruction_list_add(e->allocations, iptr);
752 E("untracked array", dst)
756 if (instruction_field_type(iptr) == TYPE_ADR) {
757 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
763 if (instruction_field_type(iptr) == TYPE_ADR) {
764 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
765 escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_GLOBAL);
766 /* If s1 is currently not an argument, but can contain one later because
767 of a phi function, the merge function takes care to make all
768 dependencies escape globally. */
769 E("putfield into argument", s2)
771 I("putfield inherit", s2, s1);
772 escape_analysis_ensure_state(e, instruction_s2(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
773 escape_analysis_add_dependency(e, iptr);
779 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
780 if (e->verbose) printf("Contains argument.\n");
781 escape_analysis_ensure_state(e, instruction_s3(iptr), ESCAPE_GLOBAL);
782 E("aastore into argument", s3)
784 if (e->verbose) printf("Contains no argument.\n");
786 escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
787 escape_analysis_add_dependency(e, iptr);
792 if (instruction_field_type(iptr) == TYPE_ADR) {
793 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
794 E("loaded from static var", dst)
795 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
800 if (instruction_field_type(iptr) == TYPE_ADR) {
802 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
803 /* Fields loaded from arguments escape globally.
806 => y escapes globally. */
807 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
808 E("loaded from arg", dst)
810 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
813 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
815 instruction_list_add(e->getfields, iptr);
819 case ICMD_ARRAYLENGTH:
820 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
825 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
826 /* If store into argument, escapes globally. See ICMD_GETFIELD. */
827 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
828 E("aaload from argument", dst)
830 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
833 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
835 instruction_list_add(e->getfields, iptr);
840 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
841 escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_METHOD);
846 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
850 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
851 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
855 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
856 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
857 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
860 case ICMD_INSTANCEOF:
861 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
864 case ICMD_INVOKESPECIAL:
865 case ICMD_INVOKEVIRTUAL:
866 case ICMD_INVOKEINTERFACE:
867 case ICMD_INVOKESTATIC:
868 count = instruction_arg_count(iptr);
869 mi = instruction_local_methodinfo(iptr);
874 /* If the method could be resolved, it already is. */
875 paramescape = mi->paramescape;
879 printf("Paramescape for callee available.\n");
883 if (paramescape) why = "Available param escape";
885 if (paramescape == NULL) {
887 printf("BC escape analyzing callee.\n");
889 why = "BC param escape";
890 bc_escape_analysis_perform(mi);
891 paramescape = mi->paramescape;
895 printf("Unresolved callee.\n");
897 why = "Unresolved callee";
900 if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
901 if (mi != NULL && !escape_is_monomorphic(e->jd->m, mi)) {
903 printf("Not monomorphic.\n");
910 /* Set the escape state of the return value.
911 This is: global if we down have information of the callee, or the callee
912 supplied escape state. */
914 if (instruction_return_type(iptr) == TYPE_ADR) {
915 if (paramescape == NULL) {
916 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
919 es = escape_state_from_u1(paramescape[-1]);
920 I2(why, instruction_dst(iptr), es)
921 escape_analysis_ensure_state(e, instruction_dst(iptr), es);
923 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
926 for (i = 0; i < count; ++i) {
927 if (instruction_arg_type(iptr, i) == TYPE_ADR) {
929 if (paramescape == NULL) {
930 escape_analysis_ensure_state(
932 instruction_arg(iptr, i),
935 E2(why, instruction_arg(iptr, i));
936 } else if (escape_state_from_u1(*paramescape) <= ESCAPE_METHOD) {
937 es = escape_state_from_u1(*paramescape);
939 if (es < ESCAPE_METHOD) {
943 I2(why, instruction_arg(iptr, i), es);
944 escape_analysis_ensure_state(e, instruction_arg(iptr, i), es);
946 if (*paramescape & 0x80) {
947 /* Parameter can be returned from method.
948 This creates an alias to the retur value.
949 If the return value escapes, the ES of the parameter needs
951 escape_analysis_merge(e, instruction_arg(iptr, i), instruction_dst(iptr));
952 I2("return alias", instruction_arg(iptr, i), instruction_dst(iptr));
955 escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_GLOBAL);
956 E2(why, instruction_arg(iptr, i));
959 if (paramescape != NULL) {
968 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
973 /* If we return only arguments, the return value escapes only the method.
974 ESCAPE_METHOD for now, and check later, if a different value than an
975 argument is possibly returned. */
976 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD_RETURN);
978 instruction_list_add(e->returns, iptr);
985 if (instruction_dst_type(iptr, jd) == TYPE_ADR) {
986 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
987 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
993 iarg = iptr->sx.s23.s2.iargs;
994 iarg != iptr->sx.s23.s2.iargs + iptr->s1.argcount;
997 escape_analysis_merge(e, instruction_dst(iptr), instruction_dst(*iarg));
1001 case ICMD_GETEXCEPTION:
1002 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
1007 static void escape_analysis_process_instructions(escape_analysis_t *e) {
1011 FOR_EACH_BASICBLOCK(e->jd, bptr) {
1014 color_printf(CYAN, "=== BB %d ===\n", bptr->nr);
1017 for (iptr = bptr->phis; iptr != bptr->phis + bptr->phicount; ++iptr) {
1018 escape_analysis_process_instruction(e, iptr);
1021 FOR_EACH_INSTRUCTION(bptr, iptr) {
1022 escape_analysis_process_instruction(e, iptr);
1028 static void escape_analysis_post_process_returns(escape_analysis_t *e) {
1029 instruction_list_item_t *iti;
1032 if (e->verbose) printf("Post processing returns:\n");
1034 FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
1037 if (! escape_analysis_get_contains_only_arguments(e, instruction_s1(iptr))) {
1038 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
1039 E("return of not argument", s1)
1044 static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
1045 instruction_list_item_t *iti;
1046 dependency_list_item_t *itd;
1048 dependency_list_t *dl;
1050 if (e->verbose) printf("Post processing getfields:\n");
1052 FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
1056 /* Get the object the field/element is loaded from. */
1058 dl = var_extra_get_dependency_list(e, instruction_s1(iptr));
1060 /* Adjust escape state of all objects in the dependency list,
1061 referenced via the field of this getfield/arraystore. */
1064 FOR_EACH_DEPENDENCY_LIST(dl, itd) {
1065 if (dependency_list_item_compare(itd, iptr)) {
1067 /* Fields match. Adjust escape state. */
1069 escape_analysis_ensure_state(
1071 dependency_list_item_get_dependency(itd),
1072 escape_analysis_get_state(e, instruction_dst(iptr))
1074 I2("post process getfield", dependency_list_item_get_dependency(itd), escape_analysis_get_state(e, instruction_dst(iptr)));
1082 static void escape_analysis_mark_monitors(escape_analysis_t *e) {
1083 instruction_list_item_t *iti;
1086 FOR_EACH_INSTRUCTION_LIST(e->monitors, iti) {
1089 /* TODO if argument does not escape, mark. */
1090 if (escape_analysis_get_state(e, instruction_arg(iptr, 0)) != ESCAPE_GLOBAL) {
1092 printf("Monitor on thread local object!\n");
1098 static void escape_analysis_mark_allocations(escape_analysis_t *e) {
1099 instruction_list_item_t *iti;
1102 FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1104 es = escape_analysis_get_state(e, instruction_dst(iptr));
1106 #if defined(ENABLE_REASON)
1107 if (instruction_get_opcode(iptr) == ICMD_NEW) {
1109 iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_escape_reason_new);
1110 ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
1111 iptr->escape_reasons = ve->reasons;
1112 if (es < ESCAPE_METHOD_RETURN) {
1113 assert(!ve->reasons);
1114 reason_t *r = NEW(reason_t);
1115 r->why = "No escape\n";
1118 iptr->escape_reasons = r;
1120 assert(iptr->escape_reasons);
1126 if (instruction_get_opcode(iptr) == ICMD_NEW) {
1127 es = escape_analysis_get_state(e, instruction_dst(iptr));
1128 if (es < ESCAPE_METHOD_RETURN) {
1129 iptr->sx.s23.s3.bte = builtintable_get_internal(BUILTIN_tlh_new);
1130 e->jd->code->flags |= CODE_FLAG_TLH;
1137 static void escape_analysis_process_arguments(escape_analysis_t *e) {
1144 md = e->jd->m->parseddesc;
1146 for (p = 0, l = 0; p < md->paramcount; ++p) {
1147 t = md->paramtypes[p].type;
1148 varindex = e->jd->local_map[l * 5 + t];
1149 if (t == TYPE_ADR) {
1150 if (varindex != UNUSED) {
1151 escape_analysis_ensure_state(e, varindex, ESCAPE_NONE);
1152 escape_analysis_set_contains_argument(e, varindex);
1153 escape_analysis_set_contains_only_arguments(e, varindex);
1154 /*escape_analysis_set_adr_arg_num(e, varindex, e->adr_args_count);*/
1156 e->adr_args_count += 1;
1158 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1162 static void escape_analysis_export_arguments(escape_analysis_t *e) {
1169 instruction_list_item_t *iti;
1171 escape_state_t es, re;
1174 md = e->jd->m->parseddesc;
1176 ret_val_is_adr = (md->returntype.type == TYPE_ADR) ? 1 : 0;
1178 paramescape = MNEW(u1, e->adr_args_count + ret_val_is_adr);
1180 e->jd->m->paramescape = paramescape + ret_val_is_adr;
1182 for (p = 0, l = 0; p < md->paramcount; ++p) {
1183 t = md->paramtypes[p].type;
1184 varindex = e->jd->local_map[l * 5 + t];
1185 if (t == TYPE_ADR) {
1186 if (varindex == UNUSED) {
1187 *paramescape = (u1)ESCAPE_NONE;
1189 es = escape_analysis_get_state(e, varindex);
1191 if (es == ESCAPE_METHOD_RETURN) {
1192 *paramescape = escape_state_to_u1(ESCAPE_METHOD) | 0x80;
1194 printf("non-escaping adr parameter returned: %d\n", p);
1197 *paramescape = escape_state_to_u1(es);
1203 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1206 if (ret_val_is_adr) {
1207 /* Calculate escape state of return value as maximum escape state of all
1212 FOR_EACH_INSTRUCTION_LIST(e->returns, iti) {
1214 es = escape_analysis_get_state(e, instruction_s1(iptr));
1221 e->jd->m->paramescape[-1] = escape_state_to_u1(re);
1225 #if defined(ENABLE_REASON)
1226 void print_escape_reasons() {
1227 reason_t *re = THREADOBJECT->escape_reasons;
1229 fprintf(stderr, "DYN_REASON");
1231 for (; re; re = re->next) {
1232 fprintf(stderr,":%s", re->why);
1235 fprintf(stderr, "\n");
1238 void set_escape_reasons(void *vp) {
1239 THREADOBJECT->escape_reasons = vp;
1243 static void escape_analysis_display(escape_analysis_t *e) {
1244 instruction_list_item_t *iti;
1248 FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1250 ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
1251 show_icmd(e->jd, iptr-1, 0, 3);
1253 show_icmd(e->jd, iptr, 0, 3);
1256 "%s@%d: --%s-- %d\n\n",
1257 icmd_table[iptr->opc].name,
1259 escape_state_to_string(ve->escape_state),
1262 #if defined(ENABLE_REASON)
1265 for (re = ve->reasons; re; re = re->next) {
1266 printf("ESCAPE_REASON: %s\n", re->why);
1273 void escape_analysis_perform(jitdata *jd) {
1274 escape_analysis_t *e;
1276 jd->m->flags |= ACC_METHOD_EA;
1278 e = DNEW(escape_analysis_t);
1279 escape_analysis_init(e, jd);
1282 color_printf(RED, "\n\n==== %s/%s ====\n\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
1284 escape_analysis_process_arguments(e);
1285 escape_analysis_process_instructions(e);
1286 escape_analysis_post_process_getfields(e);
1287 escape_analysis_post_process_returns(e);
1289 escape_analysis_export_arguments(e);
1290 if (e->verbose) escape_analysis_display(e);
1294 for (i = 0; i < jd->vartop; ++i) {
1295 r = var_extra_get_representant(e, i);
1297 printf("EES of %d: ", i);
1298 for (j = 0; j < jd->vartop; ++j) {
1299 if (var_extra_get_representant(e, j) == r) {
1309 escape_analysis_mark_allocations(e);
1310 escape_analysis_mark_monitors(e);
1312 jd->m->flags &= ~ACC_METHOD_EA;
1315 void escape_analysis_escape_check(void *vp) {
1318 /*** monomorphic *************************************************************/
1320 bool escape_is_monomorphic(methodinfo *caller, methodinfo *callee) {
1322 /* Non-speculative case */
1324 if (callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
1329 (callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED| ACC_ABSTRACT))
1330 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)
1333 /* Mark that we have used the information about monomorphy. */
1335 callee->flags |= ACC_METHOD_MONOMORPHY_USED;
1337 /* We assume the callee is monomorphic. */
1339 method_add_assumption_monomorphic(caller, callee);