1 /* srcontainsc/vm/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
24 #include "vm/jit/jit.h"
25 #include "vmcore/class.h"
26 #include "vmcore/classcache.h"
27 #include "vm/jit/optimizing/escape.h"
29 /*** escape_state *************************************************************/
31 const char *escape_state_to_string(escape_state_t escape_state) {
32 # define str(x) case x: return #x;
33 switch (escape_state) {
37 str(ESCAPE_METHOD_RETURN)
39 default: return "???";
44 /*** instruction **************************************************************/
46 static inline s2 instruction_get_opcode(const instruction *iptr) {
47 if (iptr->opc == ICMD_BUILTIN) {
48 return iptr->sx.s23.s3.bte->opcode;
54 static inline bool instruction_is_unresolved(const instruction *iptr) {
55 return iptr->flags.bits & INS_FLAG_UNRESOLVED;
58 static inline s4 instruction_field_type(const instruction *iptr) {
59 if (instruction_is_unresolved(iptr)) {
60 return iptr->sx.s23.s3.uf->fieldref->parseddesc.fd->type;
62 return iptr->sx.s23.s3.fmiref->p.field->type;
66 static inline s4 instruction_s1(const instruction *iptr) {
67 return iptr->s1.varindex;
70 static inline s4 instruction_s2(const instruction *iptr) {
71 return iptr->sx.s23.s2.varindex;
74 static inline s4 instruction_s3(const instruction *iptr) {
75 return iptr->sx.s23.s3.varindex;
78 static inline s4 instruction_dst(const instruction *iptr) {
79 return iptr->dst.varindex;
82 static inline s4 instruction_arg(const instruction *iptr, int arg) {
83 return iptr->sx.s23.s2.args[arg];
86 static inline bool instruction_is_class_constant(const instruction *iptr) {
87 return iptr->flags.bits & INS_FLAG_CLASS;
90 static inline classinfo *instruction_classinfo(const instruction *iptr) {
91 return iptr->sx.val.c.cls;
94 static inline methodinfo *instruction_local_methodinfo(const instruction *iptr) {
95 if (instruction_is_unresolved(iptr)) {
98 return iptr->sx.s23.s3.fmiref->p.method;
102 static inline int instruction_dst_type(const instruction *iptr, jitdata *jd) {
103 return VAROP(iptr->dst)->type;
106 static inline int instruction_return_type(const instruction *iptr) {
107 return instruction_call_site(iptr)->returntype.type;
110 static inline s4 instruction_arg_type(const instruction *iptr, int arg) {
111 methoddesc *md = instruction_call_site(iptr);
112 assert(0 <= arg && arg < md->paramcount);
113 return md->paramtypes[arg].type;
116 static inline int instruction_arg_count(const instruction *iptr) {
117 return instruction_call_site(iptr)->paramcount;
120 /*** instruction_list ********************************************************/
122 typedef struct instruction_list_item {
124 struct instruction_list_item *next;
125 } instruction_list_item_t;
128 instruction_list_item_t *first;
129 } instruction_list_t;
131 void instruction_list_init(instruction_list_t *list) {
135 void instruction_list_add(instruction_list_t *list, instruction *instr) {
136 instruction_list_item_t *item = DNEW(instruction_list_item_t);
138 item->next = list->first;
142 #define FOR_EACH_INSTRUCTION_LIST(list, it) \
143 for ((it) = (list)->first; (it) != NULL; (it) = (it)->next)
145 /*** escape_analysis *********************************************************/
152 instruction_list_t *allocations;
153 instruction_list_t *getfields;
154 instruction_list_t *monitors;
155 instruction_list_t *returns;
157 struct var_extra **var;
159 unsigned adr_args_count;
165 /*** dependency_list_item ****************************************************/
167 typedef struct dependency_list_item {
169 struct dependency_list_item *next;
170 } dependency_list_item_t;
172 bool dependency_list_item_compare(const dependency_list_item_t *item, const instruction *load) {
174 instruction *store = item->store;
178 if (load->opc == ICMD_AALOAD) {
180 if (store->opc != ICMD_AASTORE) {
188 if (store->opc != ICMD_PUTFIELD) {
193 instruction_is_unresolved(store) !=
194 instruction_is_unresolved(load)
199 if (instruction_is_unresolved(store)) {
200 storen = store->sx.s23.s3.uf->fieldref->name;
201 loadn = load->sx.s23.s3.uf->fieldref->name;
203 storen = store->sx.s23.s3.fmiref->name;
204 loadn = load->sx.s23.s3.fmiref->name;
207 /* TODO pointer equality ? */
209 if (storen->blength != loadn->blength) {
213 return (strcmp(storen->text, loadn->text) == 0);
218 s4 dependency_list_item_get_dependency(const dependency_list_item_t *item) {
219 switch (item->store->opc) {
221 return instruction_s3(item->store);
223 return instruction_s2(item->store);
230 /*** dependency_list *********************************************************/
233 dependency_list_item_t *first;
234 dependency_list_item_t *last;
237 void dependency_list_init(dependency_list_t *dl) {
242 void dependency_list_add(dependency_list_t *dl, instruction *store) {
243 dependency_list_item_t *item = DNEW(dependency_list_item_t);
248 if (dl->first == NULL) {
252 dl->last->next = item;
257 void dependenCy_list_import(dependency_list_t *dl, dependency_list_t *other) {
263 if (dl->first == NULL) {
266 dl->last->next = other->first;
267 dl->last = other->last;
275 #define FOR_EACH_DEPENDENCY_LIST(dl, it) \
276 for ((it) = (dl)->first; (it) != NULL; (it) = (it)->next)
278 /*** var_extra ***************************************************************/
280 typedef struct var_extra {
281 instruction *allocation;
282 escape_state_t escape_state;
284 dependency_list_t *dependency_list;
285 unsigned contains_arg:1;
286 unsigned contains_only_args:1;
287 /*signed adr_arg_num:30;*/
290 static void var_extra_init(var_extra_t *ve) {
291 ve->allocation = NULL;
292 ve->escape_state = ESCAPE_NONE;
293 ve->representant = -1;
294 ve->dependency_list = NULL;
295 ve->contains_arg = false;
296 ve->contains_only_args = false;
297 /*ve->adr_arg_num = -1;*/
300 static inline var_extra_t *var_extra_get_no_alloc(const escape_analysis_t *e, s4 var) {
304 static var_extra_t* var_extra_get(escape_analysis_t *e, s4 var) {
307 assert(0 <= var && var <= e->jd->vartop);
309 ve = var_extra_get_no_alloc(e, var);
312 ve = DNEW(var_extra_t);
320 static s4 var_extra_get_representant(escape_analysis_t *e, s4 var) {
326 ve = var_extra_get(e, var);
328 while (ve->representant != -1) {
329 assert(ctr++ < 10000);
330 var = ve->representant;
331 ve = var_extra_get_no_alloc(e, var);
338 static escape_state_t var_extra_get_escape_state(escape_analysis_t *e, s4 var) {
341 var = var_extra_get_representant(e, var);
342 ve = var_extra_get(e, var);
344 return ve->escape_state;
347 static void var_extra_set_escape_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
350 var = var_extra_get_representant(e, var);
351 ve = var_extra_get(e, var);
353 ve->escape_state = escape_state;
356 static dependency_list_t *var_extra_get_dependency_list(escape_analysis_t *e, s4 var) {
359 var = var_extra_get_representant(e, var);
360 ve = var_extra_get(e, var);
362 if (ve->dependency_list == NULL) {
363 ve->dependency_list = DNEW(dependency_list_t);
364 dependency_list_init(ve->dependency_list);
367 return ve->dependency_list;
370 /*** escape_analysis *********************************************************/
372 static void escape_analysis_init(escape_analysis_t *e, jitdata *jd) {
375 e->allocations = DNEW(instruction_list_t);
376 instruction_list_init(e->allocations);
378 e->getfields = DNEW(instruction_list_t);
379 instruction_list_init(e->getfields);
381 e->monitors = DNEW(instruction_list_t);
382 instruction_list_init(e->monitors);
384 e->returns = DNEW(instruction_list_t);
385 instruction_list_init(e->returns);
387 e->var = DMNEW(var_extra_t *, jd->vartop);
388 MZERO(e->var, var_extra_t *, jd->vartop);
390 e->adr_args_count = 0;
393 strcmp(e->jd->m->clazz->name->text, "gnu/java/util/regex/RESyntax") == 0
394 && strcmp(e->jd->m->name->text, "<clinit>") == 0
399 static void escape_analysis_set_allocation(escape_analysis_t *e, s4 var, instruction *iptr) {
400 var_extra_get(e, var)->allocation = iptr;
403 static instruction *escape_analysis_get_allocation(const escape_analysis_t *e, s4 var) {
404 var_extra_t *ve = var_extra_get_no_alloc(e, var);
407 assert(ve->allocation != NULL);
409 return ve->allocation;
412 static void escape_analysis_set_contains_argument(escape_analysis_t *e, s4 var) {
413 var_extra_get(e, var)->contains_arg = true;
416 static bool escape_analysis_get_contains_argument(escape_analysis_t *e, s4 var) {
417 return var_extra_get(e, var)->contains_arg;
420 static void escape_analysis_set_contains_only_arguments(escape_analysis_t *e, s4 var) {
421 var_extra_get(e, var)->contains_only_args = true;
424 static bool escape_analysis_get_contains_only_arguments(escape_analysis_t *e, s4 var) {
425 return var_extra_get(e, var)->contains_only_args;
429 static void escape_analysis_set_adr_arg_num(escape_analysis_t *e, s4 var, s4 num) {
430 var_extra_get(e, var)->adr_arg_num = num;
433 static s4 escape_analysis_get_adr_arg_num(escape_analysis_t *e, s4 var) {
434 return var_extra_get(e, var)->adr_arg_num;
438 static bool escape_analysis_in_same_set(escape_analysis_t *e, s4 var1, s4 var2) {
439 return var_extra_get_representant(e, var1) == var_extra_get_representant(e, var2);
442 static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
445 dependency_list_item_t *it;
447 var = var_extra_get_representant(e, var);
448 ve = var_extra_get(e, var);
450 if (ve->escape_state < escape_state) {
453 "escape state of %d %s => %s\n",
455 escape_state_to_string(ve->escape_state),
456 escape_state_to_string(escape_state)
459 ve->escape_state = escape_state;
460 if (ve->dependency_list != NULL) {
461 FOR_EACH_DEPENDENCY_LIST(ve->dependency_list, it) {
463 printf("propagating to %s@%d\n", icmd_table[it->store->opc].name, it->store->line);
465 escape_analysis_ensure_state(
467 dependency_list_item_get_dependency(it),
475 static escape_state_t escape_analysis_get_state(escape_analysis_t *e, s4 var) {
476 return var_extra_get_escape_state(e, var);
479 static classinfo *escape_analysis_classinfo_in_var(escape_analysis_t *e, s4 var) {
480 instruction *iptr = escape_analysis_get_allocation(e, var);
486 if (! instruction_is_class_constant(iptr)) {
490 if (instruction_dst(iptr) != var) {
494 if (instruction_is_unresolved(iptr)) {
498 return instruction_classinfo(iptr);
501 static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
503 var_extra_t *ve1, *ve2;
504 dependency_list_item_t *itd;
507 var1 = var_extra_get_representant(e, var1);
508 var2 = var_extra_get_representant(e, var2);
510 /* Don't merge the same escape sets. */
516 ve1 = var_extra_get(e, var1);
517 ve2 = var_extra_get(e, var2);
519 /* Adjust escape state to maximal escape state. */
521 escape_analysis_ensure_state(e, var1, ve2->escape_state);
522 escape_analysis_ensure_state(e, var2, ve1->escape_state);
524 /* Representant of var1 becomes the representant of var2. */
526 ve2->representant = var1;
528 /* Adjust is_arg to logical or. */
530 has_become_arg = ve1->contains_arg != ve2->contains_arg;
531 ve1->contains_arg = ve1->contains_arg || ve2->contains_arg;
533 if (e->verbose && has_become_arg) printf("(%d,%d) has become arg.\n", var1, var2);
535 /* Merge list of dependencies. */
537 if (ve1->dependency_list == NULL) {
538 ve1->dependency_list = ve2->dependency_list;
540 dependenCy_list_import(ve1->dependency_list, ve2->dependency_list);
543 /* If one of the merged values is an argument but the other not,
544 all dependencies of the newly created value escape globally. */
546 if (has_become_arg && ve1->dependency_list != NULL) {
547 FOR_EACH_DEPENDENCY_LIST(ve1->dependency_list, itd) {
548 escape_analysis_ensure_state(
550 dependency_list_item_get_dependency(itd),
556 /* Adjust contains_only_args to logical and. */
558 ve1->contains_only_args = ve1->contains_only_args && ve2->contains_only_args;
560 /* Adjust address argument number contained in this var. */
563 if (ve1->adr_arg_num != ve2->adr_arg_num) {
564 ve1->adr_arg_num = -1;
569 static void escape_analysis_add_dependency(escape_analysis_t *e, instruction *store) {
570 s4 obj = instruction_s1(store);
571 dependency_list_t *dl = var_extra_get_dependency_list(e, obj);
573 assert(store->opc == ICMD_PUTFIELD || store->opc == ICMD_AASTORE);
575 dependency_list_add(dl, store);
578 printf("dependency_list_add\n");
582 static void escape_analysis_process_instruction(escape_analysis_t *e, instruction *iptr) {
593 printf("processing %s@%d\n", icmd_table[iptr->opc].name, iptr->line);
596 switch (instruction_get_opcode(iptr)) {
599 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
600 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
605 c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
607 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
610 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
611 } else if (c->finalizer != NULL) {
612 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
614 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
617 instruction_list_add(e->allocations, iptr);
621 case ICMD_MONITORENTER:
622 case ICMD_MONITOREXIT:
624 instruction_list_add(e->monitors, iptr);
631 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
632 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
633 instruction_list_add(e->allocations, iptr);
638 if (instruction_field_type(iptr) == TYPE_ADR) {
639 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
644 if (instruction_field_type(iptr) == TYPE_ADR) {
645 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
646 escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_GLOBAL);
647 /* If s1 is currently not an argument, but can contain one later because
648 of a phi function, the merge function takes care to make all
649 dependencies escape globally. */
651 escape_analysis_ensure_state(e, instruction_s2(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
652 escape_analysis_add_dependency(e, iptr);
658 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
659 escape_analysis_ensure_state(e, instruction_s3(iptr), ESCAPE_GLOBAL);
661 escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
662 escape_analysis_add_dependency(e, iptr);
667 if (instruction_field_type(iptr) == TYPE_ADR) {
668 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
669 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
674 if (instruction_field_type(iptr) == TYPE_ADR) {
676 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
677 /* Fields loaded from arguments escape globally.
680 => y escapes globally. */
681 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
683 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
686 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
688 instruction_list_add(e->getfields, iptr);
692 case ICMD_ARRAYLENGTH:
698 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
699 /* If store into argument, escapes globally. See ICMD_GETFIELD. */
700 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
702 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
705 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
707 instruction_list_add(e->getfields, iptr);
712 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
713 escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_METHOD);
719 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
723 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
724 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
725 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
728 case ICMD_INSTANCEOF:
729 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
732 case ICMD_INVOKESPECIAL:
733 case ICMD_INVOKEVIRTUAL:
734 case ICMD_INVOKEINTERFACE:
735 case ICMD_INVOKESTATIC:
736 count = instruction_arg_count(iptr);
737 mi = instruction_local_methodinfo(iptr);
741 /* If the method could be resolved, it already is. */
742 paramescape = mi->paramescape;
744 if (paramescape == NULL) {
746 printf("BC escape analyzing callee %s/%s.\n", mi->clazz->name->text, mi->name->text);
748 bc_escape_analysis_perform(mi);
749 paramescape = mi->paramescape;
753 printf("Unresolved callee.\n");
757 if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
758 if (mi != NULL && !method_profile_is_monomorphic(mi)) {
763 /* Set the escape state of the return value.
764 This is: global if we down have information of the callee, or the callee
765 supplied escape state. */
767 if (instruction_return_type(iptr) == TYPE_ADR) {
768 if (paramescape == NULL) {
769 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
771 es = escape_state_from_u1(paramescape[-1]);
772 escape_analysis_ensure_state(e, instruction_dst(iptr), es);
774 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
777 for (i = 0; i < count; ++i) {
778 if (instruction_arg_type(iptr, i) == TYPE_ADR) {
780 if (paramescape == NULL) {
781 escape_analysis_ensure_state(
783 instruction_arg(iptr, i),
786 } else if (escape_state_from_u1(*paramescape) < ESCAPE_METHOD) {
787 es = escape_state_from_u1(*paramescape);
789 if (es < ESCAPE_METHOD) {
793 escape_analysis_ensure_state(e, instruction_arg(iptr, i), es);
795 if (*paramescape & 0x80) {
796 /* Parameter can be returned from method.
797 This creates an alias to the retur value.
798 If the return value escapes, the ES of the parameter needs
800 escape_analysis_merge(e, instruction_arg(iptr, i), instruction_dst(iptr));
804 if (paramescape != NULL) {
813 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
817 /* If we return only arguments, the return value escapes only the method.
818 ESCAPE_METHOD for now, and check later, if a different value than an
819 argument is possibly returned. */
820 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD_RETURN);
821 instruction_list_add(e->returns, iptr);
828 if (instruction_dst_type(iptr, jd) == TYPE_ADR) {
829 escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
830 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
836 iarg = iptr->sx.s23.s2.iargs;
837 iarg != iptr->sx.s23.s2.iargs + iptr->s1.argcount;
840 escape_analysis_merge(e, instruction_dst(iptr), instruction_dst(*iarg));
844 case ICMD_GETEXCEPTION:
845 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
850 static void escape_analysis_process_instructions(escape_analysis_t *e) {
854 FOR_EACH_BASICBLOCK(e->jd, bptr) {
856 for (iptr = bptr->phis; iptr != bptr->phis + bptr->phicount; ++iptr) {
857 escape_analysis_process_instruction(e, iptr);
860 FOR_EACH_INSTRUCTION(bptr, iptr) {
861 escape_analysis_process_instruction(e, iptr);
867 static void escape_analysis_post_process_returns(escape_analysis_t *e) {
868 instruction_list_item_t *iti;
871 FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
874 if (! escape_analysis_get_contains_only_arguments(e, instruction_s1(iptr))) {
875 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
880 static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
881 instruction_list_item_t *iti;
882 dependency_list_item_t *itd;
884 dependency_list_t *dl;
886 FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
890 /* Get the object the field/element is loaded from. */
892 dl = var_extra_get_dependency_list(e, instruction_s1(iptr));
894 /* Adjust escape state of all objects in the dependency list,
895 referenced via the field of this getfield/arraystore. */
898 FOR_EACH_DEPENDENCY_LIST(dl, itd) {
899 if (dependency_list_item_compare(itd, iptr)) {
901 /* Fields match. Adjust escape state. */
903 escape_analysis_ensure_state(
905 dependency_list_item_get_dependency(itd),
906 escape_analysis_get_state(e, instruction_dst(iptr))
915 static void escape_analysis_mark_monitors(escape_analysis_t *e) {
916 instruction_list_item_t *iti;
919 FOR_EACH_INSTRUCTION_LIST(e->monitors, iti) {
922 /* TODO if argument does not escape, mark. */
923 if (escape_analysis_get_state(e, instruction_arg(iptr, 0)) != ESCAPE_GLOBAL) {
924 printf("Monitor on thread local object!\n");
929 static void display_allocation(escape_analysis_t *e, const char *prefix, const instruction *iptr, escape_state_t es) {
930 const char *cl = "WTF";
933 if (instruction_get_opcode(iptr) == ICMD_NEW) {
934 c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
942 " %s %s %s: %s %s @%d %s\n",
944 e->jd->m->clazz->name->text,
945 e->jd->m->name->text,
946 icmd_table[iptr->opc].name,
949 escape_state_to_string(es)
953 static void escape_analysis_mark_allocations(escape_analysis_t *e) {
954 instruction_list_item_t *iti;
957 FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
958 es = escape_analysis_get_state(e, instruction_dst(iti->instr));
959 if (es < ESCAPE_GLOBAL_THROUGH_METHOD) {
960 display_allocation(e, "****", iti->instr, es);
962 if (es == ESCAPE_GLOBAL_THROUGH_METHOD) {
963 display_allocation(e, "!!!!", iti->instr, es);
969 static void escape_analysis_process_arguments(escape_analysis_t *e) {
976 md = e->jd->m->parseddesc;
978 for (p = 0, l = 0; p < md->paramcount; ++p) {
979 t = md->paramtypes[p].type;
980 varindex = e->jd->local_map[l * 5 + t];
982 if (varindex != UNUSED) {
983 escape_analysis_ensure_state(e, varindex, ESCAPE_NONE);
984 escape_analysis_set_contains_argument(e, varindex);
985 escape_analysis_set_contains_only_arguments(e, varindex);
986 /*escape_analysis_set_adr_arg_num(e, varindex, e->adr_args_count);*/
988 e->adr_args_count += 1;
990 l += IS_2_WORD_TYPE(t) ? 2 : 1;
994 static void escape_analysis_export_arguments(escape_analysis_t *e) {
1001 instruction_list_item_t *iti;
1003 escape_state_t es, re;
1006 md = e->jd->m->parseddesc;
1008 ret_val_is_adr = (md->returntype.type == TYPE_ADR) ? 1 : 0;
1010 paramescape = MNEW(u1, e->adr_args_count + ret_val_is_adr);
1012 e->jd->m->paramescape = paramescape + ret_val_is_adr;
1014 for (p = 0, l = 0; p < md->paramcount; ++p) {
1015 t = md->paramtypes[p].type;
1016 varindex = e->jd->local_map[l * 5 + t];
1017 if (t == TYPE_ADR) {
1018 if (varindex == UNUSED) {
1019 *paramescape = (u1)ESCAPE_NONE;
1021 es = escape_analysis_get_state(e, varindex);
1023 if (es == ESCAPE_METHOD_RETURN) {
1024 *paramescape = escape_state_to_u1(ESCAPE_METHOD) | 0x80;
1026 printf("non-escaping adr parameter returned: %d\n", p);
1029 *paramescape = escape_state_to_u1(es);
1035 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1038 if (ret_val_is_adr) {
1039 /* Calculate escape state of return value as maximum escape state of all
1044 FOR_EACH_INSTRUCTION_LIST(e->returns, iti) {
1046 es = escape_analysis_get_state(e, instruction_s1(iptr));
1053 e->jd->m->paramescape[-1] = escape_state_to_u1(re);
1057 static void escape_analysis_display(escape_analysis_t *e) {
1058 instruction_list_item_t *iti;
1062 FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1064 ve = var_extra_get(e, instruction_dst(iptr));
1067 icmd_table[iptr->opc].name,
1069 escape_state_to_string(ve->escape_state)
1074 void escape_analysis_perform(jitdata *jd) {
1075 escape_analysis_t *e;
1077 jd->m->flags |= ACC_METHOD_EA;
1079 e = DNEW(escape_analysis_t);
1080 escape_analysis_init(e, jd);
1083 printf("==== %s/%s ====\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
1085 escape_analysis_process_arguments(e);
1086 escape_analysis_process_instructions(e);
1087 escape_analysis_post_process_getfields(e);
1088 escape_analysis_post_process_returns(e);
1090 escape_analysis_export_arguments(e);
1091 if (e->verbose) escape_analysis_display(e);
1093 escape_analysis_mark_allocations(e);
1094 escape_analysis_mark_monitors(e);
1096 jd->m->flags &= ~ACC_METHOD_EA;
1099 void escape_analysis_escape_check(void *vp) {
1102 /*** monomorphic *************************************************************/
1104 monomorphic_t monomorphic_get(methodinfo *caller, methodinfo *callee) {
1105 monomorphic_t res = { 0, 0 };
1108 bool method_profile_is_monomorphic(methodinfo *m) {
1114 /*** HACK to store method monomorphy information upon shutdown ****************/
1116 #include <sqlite3.h>
1118 bool method_profile_is_monomorphic(methodinfo *m) {
1119 static sqlite3 *db = NULL;
1120 static sqlite3_stmt *stmt = NULL;
1124 assert(sqlite3_open("/home/peter/cacao-dev/profile.sqlite", &db) == SQLITE_OK);
1125 assert(sqlite3_prepare(db, "SELECT count(*) FROM monomorphic where class=? and method=? and descriptor=?", -1, &stmt, 0) == SQLITE_OK);
1128 assert(sqlite3_bind_text(stmt, 1, m->clazz->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
1129 assert(sqlite3_bind_text(stmt, 2, m->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
1130 assert(sqlite3_bind_text(stmt, 3, m->descriptor->text, -1, SQLITE_STATIC) == SQLITE_OK);
1132 assert(sqlite3_step(stmt) == SQLITE_ROW);
1133 ret = sqlite3_column_int(stmt, 0);
1134 assert(sqlite3_reset(stmt) == SQLITE_OK);
1138 void func(classinfo *c, void *arg) {
1140 sqlite3_stmt *stmt = (sqlite3_stmt *)arg;
1142 for (it = c->methods; it != c->methods + c->methodscount; ++it) {
1144 if (flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
1147 if ((flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED | ACC_ABSTRACT)) ==
1148 (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)) {
1149 assert(sqlite3_bind_text(stmt, 1, c->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
1150 assert(sqlite3_bind_text(stmt, 2, it->name->text, -1, SQLITE_STATIC) == SQLITE_OK);
1151 assert(sqlite3_bind_text(stmt, 3, it->descriptor->text, -1, SQLITE_STATIC) == SQLITE_OK);
1153 assert(sqlite3_step(stmt) == SQLITE_DONE);
1154 assert(sqlite3_reset(stmt) == SQLITE_OK);
1160 void method_profile_store() {
1163 assert(sqlite3_open("/home/peter/cacao-dev/profile.sqlite", &db) == SQLITE_OK);
1164 assert(sqlite3_exec(db, "DELETE FROM monomorphic", NULL, NULL, NULL) == SQLITE_OK);
1165 assert(sqlite3_prepare(db, "INSERT INTO monomorphic (class, method, descriptor) VALUES (?,?,?)", -1, &stmt, 0) == SQLITE_OK);
1166 classcache_foreach_loaded_class(func, stmt);
1167 assert(sqlite3_finalize(stmt) == SQLITE_OK);
1168 assert(sqlite3_close(db) == SQLITE_OK);
1171 void iterate_classes() {
1173 method_profile_store();
1179 #if defined(ENABLE_TLH)
1180 /*** TLH (Thread local heap) hack ********************************************/
1182 #include <sys/mman.h>
1183 #include "threads/thread.h"
1185 #define TLH_MAX_SIZE (20 * 1024 * 1024)
1187 void tlh_init(threadobject *t) {
1188 uint8_t *heap = (uint8_t *)mmap(
1191 PROT_READ|PROT_WRITE,
1192 MAP_ANONYMOUS|MAP_PRIVATE,
1196 uint8_t *red = (uint8_t *)mmap(
1197 heap + TLH_MAX_SIZE - getpagesize(),
1200 MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED,
1211 void tlh_reset(threadobject *t) {
1212 t->tlhtop = t->tlhstart;
1213 t->tlhbase = t->tlhstart;
1216 void tlh_destroy(threadobject *t) {
1217 int res = munmap(t->tlhstart, TLH_MAX_SIZE - getpagesize());
1218 int res2 = munmap(t->tlhstart + TLH_MAX_SIZE - getpagesize(), getpagesize());
1223 bool tlh_sigsegv_handler(void *addr) {