Merged with tip.
[cacao.git] / src / vm / jit / optimizing / escape.c
1 /* src/vm/optimizing/e&scape.c
2
3    Copyright (C) 2008
4    CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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 #include "vm/jit/jit.h"
25 #include "vmcore/class.h"
26 #include "vmcore/classcache.h"
27 #include "vm/jit/optimizing/escape.h"
28
29 #include <stdarg.h>
30
31 #if defined(ENABLE_ESCAPE_REASON)
32 #define ENABLE_REASON
33 #endif
34
35 #if defined(ENABLE_REASON)
36 #define I2(why, tov, es) escape_analysis_record_reason(e, why, iptr, tov, es);
37 #else
38 #define I2(why, tov, es)
39 #endif
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))
43
44 typedef enum {
45         RED = 31,
46         GREEN,
47         YELLOW,
48         BLUE,
49         MAGENTA,
50         CYAN,
51         WHITE,
52         COLOR_END
53 } color_t;
54
55 #define ENABLE_COLOR
56
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);
61         }
62 #endif
63 }
64
65 static void color_end() {
66 #if defined(ENABLE_COLOR)
67         printf("\033[m");
68         fflush(stdout);
69 #endif
70 }
71
72 static void color_printf(color_t color, const char *fmt, ...) {
73         va_list ap;
74         color_start(color);
75         va_start(ap, fmt);
76         vprintf(fmt, ap);
77         va_end(ap);
78         color_end();
79 }
80
81
82 /*** escape_state *************************************************************/
83
84 const char *escape_state_to_string(escape_state_t escape_state) {
85 #       define str(x) case x: return #x;
86         switch (escape_state) {
87                 str(ESCAPE_UNKNOWN)
88                 str(ESCAPE_NONE)
89                 str(ESCAPE_METHOD)
90                 str(ESCAPE_METHOD_RETURN)
91                 str(ESCAPE_GLOBAL)
92                 default: return "???";
93         }
94 #       undef str
95 }
96
97 /*** instruction **************************************************************/
98
99 static inline s2 instruction_get_opcode(const instruction *iptr) {
100         if (iptr->opc == ICMD_BUILTIN) {
101                 return iptr->sx.s23.s3.bte->opcode;
102         } else {
103                 return iptr->opc;
104         }
105 }
106
107 static inline bool instruction_is_unresolved(const instruction *iptr) {
108         return iptr->flags.bits & INS_FLAG_UNRESOLVED;
109 }
110
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;
114         } else {
115                 return iptr->sx.s23.s3.fmiref->p.field->type;
116         }
117 }
118
119 static inline s4 instruction_s1(const instruction *iptr) {
120         return iptr->s1.varindex;
121 }
122
123 static inline s4 instruction_s2(const instruction *iptr) {
124         return iptr->sx.s23.s2.varindex;
125 }
126
127 static inline s4 instruction_s3(const instruction *iptr) {
128         return iptr->sx.s23.s3.varindex;
129 }
130
131 static inline s4 instruction_dst(const instruction *iptr) {
132         return iptr->dst.varindex;
133 }
134
135 static inline s4 instruction_arg(const instruction *iptr, int arg) {
136         return iptr->sx.s23.s2.args[arg];
137 }
138
139 static inline bool instruction_is_class_constant(const instruction *iptr) {
140         return iptr->flags.bits & INS_FLAG_CLASS;
141 }
142
143 static inline classinfo *instruction_classinfo(const instruction *iptr) {
144         return iptr->sx.val.c.cls;
145 }
146
147 static inline methodinfo *instruction_local_methodinfo(const instruction *iptr) {
148         if (instruction_is_unresolved(iptr)) {
149                 return NULL;
150         } else {
151                 return iptr->sx.s23.s3.fmiref->p.method;
152         }
153 }
154
155 static inline int instruction_dst_type(const instruction *iptr, jitdata *jd) {
156         return VAROP(iptr->dst)->type;
157 }
158
159 static inline int instruction_return_type(const instruction *iptr) {
160         return instruction_call_site(iptr)->returntype.type;
161 }
162
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;
167 }
168
169 static inline int instruction_arg_count(const instruction *iptr) {
170         return instruction_call_site(iptr)->paramcount;
171 }
172
173 /*** instruction_list ********************************************************/
174
175 typedef struct instruction_list_item {
176         instruction *instr;
177         struct instruction_list_item *next;
178 } instruction_list_item_t;
179
180 typedef struct {
181         instruction_list_item_t *first;
182 } instruction_list_t;
183
184 void instruction_list_init(instruction_list_t *list) {
185         list->first = NULL;
186 }
187
188 void instruction_list_add(instruction_list_t *list, instruction *instr) {
189         instruction_list_item_t *item = DNEW(instruction_list_item_t);
190         item->instr = instr;
191         item->next = list->first;
192         list->first = item;
193 }
194
195 #define FOR_EACH_INSTRUCTION_LIST(list, it) \
196         for ((it) = (list)->first; (it) != NULL; (it) = (it)->next)
197
198 /*** escape_analysis *********************************************************/
199
200 struct var_extra;
201
202 typedef struct {
203         jitdata *jd;
204
205         instruction_list_t *allocations;
206         instruction_list_t *getfields;
207         instruction_list_t *monitors;
208         instruction_list_t *returns;
209
210         struct var_extra **var;
211
212         unsigned adr_args_count;
213
214         bool verbose;
215
216 } escape_analysis_t;
217
218 /*** dependency_list_item ****************************************************/
219
220 typedef struct dependency_list_item {
221         instruction *store;
222         struct dependency_list_item *next;
223 } dependency_list_item_t;
224
225 bool dependency_list_item_compare(const dependency_list_item_t *item, const instruction *load) {
226
227         instruction *store = item->store;
228         utf *storen;
229         const utf *loadn;
230
231         if (load->opc == ICMD_AALOAD) {
232
233                 if (store->opc != ICMD_AASTORE) {
234                         return false;
235                 }
236
237                 return true;
238
239         } else {
240
241                 if (store->opc != ICMD_PUTFIELD) {
242                         return false;
243                 }
244
245                 if (
246                         instruction_is_unresolved(store) !=
247                         instruction_is_unresolved(load)
248                 ) {
249                         return false;
250                 }
251
252                 if (instruction_is_unresolved(store)) {
253                         storen = store->sx.s23.s3.uf->fieldref->name;
254                         loadn = load->sx.s23.s3.uf->fieldref->name;
255                 } else {
256                         storen = store->sx.s23.s3.fmiref->name;
257                         loadn = load->sx.s23.s3.fmiref->name;
258                 }
259
260                 /* TODO pointer equality ? */   
261
262                 if (storen->blength != loadn->blength) {
263                         return false;
264                 }
265
266                 return (strcmp(storen->text, loadn->text) == 0);
267         }
268 }
269
270 /* TODO rename */
271 s4 dependency_list_item_get_dependency(const dependency_list_item_t *item) {
272         switch (item->store->opc) {
273                 case ICMD_AASTORE:
274                         return instruction_s3(item->store);
275                 case ICMD_PUTFIELD:
276                         return instruction_s2(item->store);
277                 default:
278                         assert(0);
279                         return 0;
280         }
281 }
282
283 /*** dependency_list *********************************************************/
284
285 typedef struct {
286         dependency_list_item_t *first;
287         dependency_list_item_t *last;
288 } dependency_list_t;
289
290 void dependency_list_init(dependency_list_t *dl) {
291         dl->first = NULL;
292         dl->last = NULL;
293 }
294
295 void dependency_list_add(dependency_list_t *dl, instruction *store) {
296         dependency_list_item_t *item = DNEW(dependency_list_item_t);
297
298         item->store = store;
299         item->next = NULL;
300         
301         if (dl->first == NULL) {
302                 dl->first = item;
303                 dl->last = item;
304         } else {
305                 dl->last->next = item;
306                 dl->last = item;
307         }
308 }
309
310 void dependenCy_list_import(dependency_list_t *dl, dependency_list_t *other) {
311
312         if (other == NULL) {
313                 return;
314         }
315
316         if (dl->first == NULL) {
317                 *dl = *other;
318         } else {
319                 dl->last->next = other->first;
320                 dl->last = other->last;
321         }
322
323         other->first = NULL;
324         other->last = NULL;
325         
326 }
327
328 #define FOR_EACH_DEPENDENCY_LIST(dl, it) \
329         for ((it) = (dl)->first; (it) != NULL; (it) = (it)->next)
330
331 /*** var_extra ***************************************************************/
332
333 #if defined(ENABLE_REASON)
334 typedef struct reason {
335         const char *why;
336         instruction *iptr;
337         struct reason *next;
338 } reason_t;
339 #endif
340
341 typedef struct var_extra {
342         instruction *allocation;
343         escape_state_t escape_state;
344         s4 representant;
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)
350         reason_t *reasons;
351 #endif
352 } var_extra_t;
353
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)
363         ve->reasons = NULL;
364 #endif
365 }
366
367 static inline var_extra_t *var_extra_get_no_alloc(const escape_analysis_t *e, s4 var) {
368         return e->var[var];
369 }
370
371 static var_extra_t* var_extra_get(escape_analysis_t *e, s4 var) {
372         var_extra_t *ve;
373
374         assert(0 <= var && var <= e->jd->vartop);
375
376         ve = var_extra_get_no_alloc(e, var);
377
378         if (ve == NULL) {
379                 ve = DNEW(var_extra_t);
380                 var_extra_init(ve);
381                 e->var[var] = ve;
382         }
383
384         return ve;
385 }
386
387 static s4 var_extra_get_representant(escape_analysis_t *e, s4 var) {
388         var_extra_t *ve;
389 #if !defined(NDEBUG)
390         int ctr = 0;
391 #endif
392
393         ve = var_extra_get(e, var);
394
395         while (ve->representant != -1) {
396                 assert(ctr++ < 10000);
397                 var = ve->representant;
398                 ve = var_extra_get_no_alloc(e, var);
399                 assert(ve);
400         }
401
402         return var;
403 }
404
405 static escape_state_t var_extra_get_escape_state(escape_analysis_t *e, s4 var) {
406         var_extra_t *ve;
407         
408         var = var_extra_get_representant(e, var);
409         ve = var_extra_get(e, var);
410
411         return ve->escape_state;
412 }
413
414 static void var_extra_set_escape_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
415         var_extra_t *ve;
416         
417         var = var_extra_get_representant(e, var);
418         ve = var_extra_get(e, var);
419
420         ve->escape_state = escape_state;
421 }
422
423 static dependency_list_t *var_extra_get_dependency_list(escape_analysis_t *e, s4 var) {
424         var_extra_t *ve;
425         
426         var = var_extra_get_representant(e, var);
427         ve = var_extra_get(e, var);
428
429         if (ve->dependency_list == NULL) {
430                 ve->dependency_list = DNEW(dependency_list_t);
431                 dependency_list_init(ve->dependency_list);
432         }
433
434         return ve->dependency_list;
435 }
436
437 /*** escape_analysis *********************************************************/
438
439 static void escape_analysis_init(escape_analysis_t *e, jitdata *jd) {
440         e->jd = jd;
441
442         e->allocations = DNEW(instruction_list_t);
443         instruction_list_init(e->allocations);
444
445         e->getfields = DNEW(instruction_list_t);
446         instruction_list_init(e->getfields);
447
448         e->monitors = DNEW(instruction_list_t);
449         instruction_list_init(e->monitors);
450
451         e->returns = DNEW(instruction_list_t);
452         instruction_list_init(e->returns);
453
454         e->var = DMNEW(var_extra_t *, jd->vartop);
455         MZERO(e->var, var_extra_t *, jd->vartop);
456
457         e->adr_args_count = 0;
458
459         e->verbose = 1;
460         e->verbose = strcmp(jd->m->name->text, "<init>") == 0;
461         e->verbose = getenv("EV") != NULL;
462 }
463
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) {
466         var_extra_t *ve;
467         reason_t *re;
468         if (es == ESCAPE_GLOBAL || es == ESCAPE_METHOD_RETURN) {
469                 var = var_extra_get_representant(e, var);
470                 ve = var_extra_get(e, var);
471                 re = NEW(reason_t);
472                 re->why = why;
473                 re->iptr= iptr;
474                 re->next = ve->reasons;
475                 ve->reasons = re;
476                 if (e->verbose) {
477                         printf("%d escapes because %s\n", var, why);
478                 }
479         }
480 }
481 #endif
482
483 static void escape_analysis_set_allocation(escape_analysis_t *e, s4 var, instruction *iptr) {
484         var_extra_get(e, var)->allocation = iptr;
485 }
486
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);
489
490         assert(ve != NULL);
491         assert(ve->allocation != NULL);
492
493         return ve->allocation;
494 }
495
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;
499 }
500
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;
504 }
505
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;
509 }
510
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;
514 }
515
516 /*
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;
519 }
520
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;
523 }
524 */
525
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);
528 }
529
530 static void escape_analysis_ensure_state(escape_analysis_t *e, s4 var, escape_state_t escape_state) {
531         
532         var_extra_t *ve;
533         dependency_list_item_t *it;
534
535         var = var_extra_get_representant(e, var);
536         ve = var_extra_get(e, var);
537
538         if (ve->escape_state < escape_state) {
539                 if (e->verbose) {
540                         printf(
541                                 "escape state of %d %s => %s\n", 
542                                 var, 
543                                 escape_state_to_string(ve->escape_state), 
544                                 escape_state_to_string(escape_state)
545                         );
546                 }
547                 ve->escape_state = escape_state;
548                 if (ve->dependency_list != NULL) {
549                         FOR_EACH_DEPENDENCY_LIST(ve->dependency_list, it) {
550                                 if (e->verbose) {
551                                         printf("propagating to %s@%d\n", icmd_table[it->store->opc].name, it->store->line);
552                                 }
553                                 escape_analysis_ensure_state(
554                                         e, 
555                                         dependency_list_item_get_dependency(it),
556                                         escape_state
557                                 );
558                                 {
559                                 instruction *iptr = NULL;
560                                 I2("propagated by dependency", dependency_list_item_get_dependency(it), escape_state);
561                                 }
562                         }
563                 }
564         }
565 }
566
567 static escape_state_t escape_analysis_get_state(escape_analysis_t *e, s4 var) {
568         return var_extra_get_escape_state(e, var);
569 }
570
571 static classinfo *escape_analysis_classinfo_in_var(escape_analysis_t *e, s4 var) {
572         instruction *iptr = escape_analysis_get_allocation(e, var);
573
574         if (iptr == NULL) {
575                 return NULL;
576         }
577
578         if (! instruction_is_class_constant(iptr)) {
579                 return NULL;
580         }
581
582         if (instruction_dst(iptr) != var) {
583                 return NULL;
584         }
585
586         if (instruction_is_unresolved(iptr)) {
587                 return NULL;
588         }
589
590         return instruction_classinfo(iptr);
591 }
592
593 static void escape_analysis_merge(escape_analysis_t *e, s4 var1, s4 var2) {
594
595         var_extra_t *ve1, *ve2;
596         dependency_list_item_t *itd;
597         bool has_become_arg;
598
599         var1 = var_extra_get_representant(e, var1);
600         var2 = var_extra_get_representant(e, var2);
601
602         /* Don't merge the same escape sets. */
603
604         if (var1 == var2) {
605                 return;
606         }
607
608         if (e->verbose) printf("Merging (%d,%d)\n", var1, var2);
609
610         ve1 = var_extra_get(e, var1);
611         ve2 = var_extra_get(e, var2);
612
613         /* Adjust escape state to maximal escape state. */
614
615         escape_analysis_ensure_state(e, var1, ve2->escape_state);
616         escape_analysis_ensure_state(e, var2, ve1->escape_state);
617
618         /* Representant of var1 becomes the representant of var2. */
619
620         ve2->representant = var1;
621
622         /* Adjust is_arg to logical or. */
623         
624         has_become_arg = ve1->contains_arg != ve2->contains_arg;
625         ve1->contains_arg = ve1->contains_arg || ve2->contains_arg;
626
627         if (e->verbose && has_become_arg) printf("(%d,%d) has become arg.\n", var1, var2);
628
629         /* Merge list of dependencies. */
630
631         if (ve1->dependency_list == NULL) {
632                 ve1->dependency_list = ve2->dependency_list;
633         } else {
634                 dependenCy_list_import(ve1->dependency_list, ve2->dependency_list);
635         }
636
637         /* If one of the merged values is an argument but the other not,
638            all dependencies of the newly created value escape globally. */
639
640         if (has_become_arg && ve1->dependency_list != NULL) {
641                 FOR_EACH_DEPENDENCY_LIST(ve1->dependency_list, itd) {
642                         escape_analysis_ensure_state(
643                                 e,
644                                 dependency_list_item_get_dependency(itd),
645                                 ESCAPE_GLOBAL
646                         );
647                         {
648                         instruction *iptr = NULL;
649                         E2("has become arg", dependency_list_item_get_dependency(itd));
650                         }
651                 }
652         }
653
654         /* Adjust contains_only_args to logical and. */
655
656         ve1->contains_only_args = ve1->contains_only_args && ve2->contains_only_args;
657
658         /* Adjust address argument number contained in this var. */
659
660         /*
661         if (ve1->adr_arg_num != ve2->adr_arg_num) {
662                 ve1->adr_arg_num = -1;
663         }
664         */
665 #if defined(ENABLE_REASON)
666         if (ve1->reasons) {
667                 reason_t *re = ve1->reasons;
668                 while (re->next != NULL) {
669                         re = re->next;
670                 }
671                 re->next = ve2->reasons;
672         } else {
673                 ve1->reasons = ve2->reasons;
674         }
675 #endif
676 }
677
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);
681
682         assert(store->opc == ICMD_PUTFIELD || store->opc == ICMD_AASTORE);
683
684         dependency_list_add(dl, store);
685
686         if (e->verbose) {
687                 printf("dependency_list_add: %d.dependency_list.add( { ", obj);
688                 show_icmd(e->jd, store, 0, 3);
689                 printf(" } )\n"); 
690         }
691 }
692
693 static void escape_analysis_process_instruction(escape_analysis_t *e, instruction *iptr) {
694         jitdata *jd = e->jd;
695         classinfo *c;
696         s4 count;
697         u1 *paramescape;
698         unsigned i;
699         instruction **iarg;
700         methodinfo *mi;
701         escape_state_t es;
702         const char *why;
703
704         if (e->verbose) {
705                 color_start(CYAN);
706                 printf("%d: ", iptr->line);
707                 show_icmd(e->jd, iptr, 0, 3);
708                 color_end();
709                 printf("\n");
710         }
711
712         switch (instruction_get_opcode(iptr)) {
713                 case ICMD_ACONST:
714
715                         escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
716                         escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
717
718                         break;
719
720                 case ICMD_NEW:
721                         c = escape_analysis_classinfo_in_var(e, instruction_arg(iptr, 0));
722
723                         escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
724
725                         if (c == NULL) {
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);
730                                 E("finalizer", dst)
731                         } else {
732                                 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
733                         }
734
735                         instruction_list_add(e->allocations, iptr);
736
737                         break;
738
739                 case ICMD_MONITORENTER:
740                 case ICMD_MONITOREXIT:
741                 
742                         instruction_list_add(e->monitors, iptr);
743
744                         break;
745
746                 case ICMD_NEWARRAY:
747                 case ICMD_ANEWARRAY:
748                         
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)
753                         break;
754
755                 case ICMD_PUTSTATIC:
756                         if (instruction_field_type(iptr) == TYPE_ADR) {
757                                 escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
758                                 E("putstatic", s1)
759                         }
760                         break;
761
762                 case ICMD_PUTFIELD:
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)
770                                 } else {
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);
774                                 }
775                         }
776                         break;
777
778                 case ICMD_AASTORE:
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)
783                         } else {
784                                 if (e->verbose) printf("Contains no argument.\n");
785                                 I("aastore", s3, s1)
786                                 escape_analysis_ensure_state(e, instruction_s3(iptr), escape_analysis_get_state(e, instruction_s1(iptr)));
787                                 escape_analysis_add_dependency(e, iptr);
788                         }
789                         break;
790
791                 case ICMD_GETSTATIC:
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);
796                         }
797                         break;
798
799                 case ICMD_GETFIELD:
800                         if (instruction_field_type(iptr) == TYPE_ADR) {
801
802                                 if (escape_analysis_get_contains_argument(e, instruction_s1(iptr))) {
803                                         /* Fields loaded from arguments escape globally.
804                                            x = arg.foo;
805                                            x.bar = y;
806                                            => y escapes globally. */
807                                         escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
808                                         E("loaded from arg", dst)
809                                 } else {
810                                         escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
811                                 }
812
813                                 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
814
815                                 instruction_list_add(e->getfields, iptr);
816                         }
817                         break;
818
819                 case ICMD_ARRAYLENGTH:
820                         escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
821                         break;
822
823                 case ICMD_AALOAD:
824
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)
829                         } else {
830                                 escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
831                         }
832
833                         escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
834
835                         instruction_list_add(e->getfields, iptr);
836                         break;
837
838                 case ICMD_IF_ACMPEQ:
839                 case ICMD_IF_ACMPNE:
840                         escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
841                         escape_analysis_ensure_state(e, instruction_s2(iptr), ESCAPE_METHOD);
842                         break;
843
844                 case ICMD_IFNULL:
845                 case ICMD_IFNONNULL:
846                         escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
847                         break;
848
849                 case ICMD_CHECKNULL:
850                         escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
851                         escape_analysis_merge(e, instruction_s1(iptr), instruction_dst(iptr));
852                         break;
853
854                 case ICMD_CHECKCAST:
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);
858                         break;
859
860                 case ICMD_INSTANCEOF:
861                         escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_METHOD);
862                         break;
863
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);
870                         paramescape = NULL;
871                         why = "???";
872
873                         if (mi != NULL) {
874                                 /* If the method could be resolved, it already is. */
875                                 paramescape = mi->paramescape;
876
877                                 if (e->verbose) {
878                                         if (paramescape) {
879                                                 printf("Paramescape for callee available.\n");
880                                         }
881                                 }
882
883                                 if (paramescape) why = "Available param escape";
884
885                                 if (paramescape == NULL) {
886                                         if (e->verbose) {
887                                                 printf("BC escape analyzing callee.\n");
888                                         }
889                                         why = "BC param escape";
890                                         bc_escape_analysis_perform(mi);
891                                         paramescape = mi->paramescape;
892                                 }
893                         } else {
894                                 if (e->verbose) {
895                                         printf("Unresolved callee.\n");
896                                 }
897                                 why = "Unresolved callee";
898                         }
899
900                         if (iptr->opc == ICMD_INVOKEVIRTUAL || iptr->opc == ICMD_INVOKEINTERFACE) {
901                                 if (mi != NULL && !escape_is_monomorphic(e->jd->m, mi)) {
902                                         if (e->verbose) {
903                                                 printf("Not monomorphic.\n");
904                                         }
905                                         why = "Polymorphic";
906                                         paramescape = NULL;
907                                 }
908                         }
909
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. */
913
914                         if (instruction_return_type(iptr) == TYPE_ADR) {
915                                 if (paramescape == NULL) {
916                                         escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_GLOBAL);
917                                         E(why, dst);
918                                 } else {
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);
922                                 }
923                                 escape_analysis_set_allocation(e, instruction_dst(iptr), iptr);
924                         }
925                         
926                         for (i = 0; i < count; ++i) {
927                                 if (instruction_arg_type(iptr, i) == TYPE_ADR) {
928
929                                         if (paramescape == NULL) {
930                                                 escape_analysis_ensure_state(
931                                                         e, 
932                                                         instruction_arg(iptr, i), 
933                                                         ESCAPE_GLOBAL
934                                                 );
935                                                 E2(why, instruction_arg(iptr, i));
936                                         } else if (escape_state_from_u1(*paramescape) <= ESCAPE_METHOD) {
937                                                 es = escape_state_from_u1(*paramescape);
938
939                                                 if (es < ESCAPE_METHOD) {
940                                                         es = ESCAPE_METHOD;
941                                                 }
942
943                                                 I2(why, instruction_arg(iptr, i), es);
944                                                 escape_analysis_ensure_state(e, instruction_arg(iptr, i), es);
945
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 
950                                                            to be adjusted. */
951                                                         escape_analysis_merge(e, instruction_arg(iptr, i), instruction_dst(iptr));
952                                                         I2("return alias", instruction_arg(iptr, i), instruction_dst(iptr));
953                                                 }
954                                         } else {
955                                                 escape_analysis_ensure_state(e, instruction_arg(iptr, i), ESCAPE_GLOBAL);
956                                                 E2(why, instruction_arg(iptr, i));
957                                         }
958
959                                         if (paramescape != NULL) {
960                                                 ++paramescape;
961                                         }
962                                 }
963                         }
964
965                         break;
966
967                 case ICMD_ATHROW:
968                         escape_analysis_ensure_state(e, instruction_s1(iptr), ESCAPE_GLOBAL);
969                         E("throw", s1)
970                         break;
971
972                 case ICMD_ARETURN:
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);
977                         E("return", s1)
978                         instruction_list_add(e->returns, iptr);
979                         break;
980
981                 case ICMD_ALOAD:
982                 case ICMD_ASTORE:
983                 case ICMD_MOVE:
984                 case ICMD_COPY:
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);
988                         }
989                         break;
990
991                 case ICMD_PHI:
992                         for (
993                                 iarg = iptr->sx.s23.s2.iargs;
994                                 iarg != iptr->sx.s23.s2.iargs + iptr->s1.argcount;
995                                 ++iarg
996                         ) {
997                                 escape_analysis_merge(e, instruction_dst(iptr), instruction_dst(*iarg));
998                         }
999                         break;
1000
1001                 case ICMD_GETEXCEPTION:
1002                         escape_analysis_ensure_state(e, instruction_dst(iptr), ESCAPE_NONE);
1003                         break;
1004         }
1005 }
1006
1007 static void escape_analysis_process_instructions(escape_analysis_t *e) {
1008         basicblock *bptr;
1009         instruction *iptr;
1010
1011         FOR_EACH_BASICBLOCK(e->jd, bptr) {
1012
1013                 if (e->verbose) {
1014                         color_printf(CYAN, "=== BB %d ===\n", bptr->nr);        
1015                 }
1016
1017                 for (iptr = bptr->phis; iptr != bptr->phis + bptr->phicount; ++iptr) {
1018                         escape_analysis_process_instruction(e, iptr);
1019                 }
1020
1021                 FOR_EACH_INSTRUCTION(bptr, iptr) {
1022                         escape_analysis_process_instruction(e, iptr);
1023                 }
1024
1025         }
1026 }
1027
1028 static void escape_analysis_post_process_returns(escape_analysis_t *e) {
1029         instruction_list_item_t *iti;
1030         instruction *iptr;
1031
1032         if (e->verbose) printf("Post processing returns:\n");
1033
1034         FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
1035                 iptr = iti->instr;
1036
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)
1040                 }
1041         }
1042 }
1043
1044 static void escape_analysis_post_process_getfields(escape_analysis_t *e) {
1045         instruction_list_item_t *iti;
1046         dependency_list_item_t *itd;
1047         instruction *iptr;
1048         dependency_list_t *dl;
1049
1050         if (e->verbose) printf("Post processing getfields:\n");
1051
1052         FOR_EACH_INSTRUCTION_LIST(e->getfields, iti) {
1053
1054                 iptr = iti->instr;
1055
1056                 /* Get the object the field/element is loaded from. */
1057
1058                 dl = var_extra_get_dependency_list(e, instruction_s1(iptr));
1059
1060                 /* Adjust escape state of all objects in the dependency list,
1061                    referenced via the field of this getfield/arraystore. */
1062
1063                 if (dl != NULL) {
1064                         FOR_EACH_DEPENDENCY_LIST(dl, itd) {
1065                                 if (dependency_list_item_compare(itd, iptr)) {
1066
1067                                         /* Fields match. Adjust escape state. */
1068
1069                                         escape_analysis_ensure_state(
1070                                                 e, 
1071                                                 dependency_list_item_get_dependency(itd),
1072                                                 escape_analysis_get_state(e, instruction_dst(iptr))
1073                                         );
1074                                         I2("post process getfield", dependency_list_item_get_dependency(itd), escape_analysis_get_state(e, instruction_dst(iptr)));
1075                                 }
1076                         }
1077                 }
1078
1079         }
1080 }
1081
1082 static void escape_analysis_mark_monitors(escape_analysis_t *e) {
1083         instruction_list_item_t *iti;
1084         instruction *iptr;
1085
1086         FOR_EACH_INSTRUCTION_LIST(e->monitors, iti) {
1087                 iptr = iti->instr;
1088
1089                 /* TODO if argument does not escape, mark. */
1090                 if (escape_analysis_get_state(e, instruction_arg(iptr, 0)) != ESCAPE_GLOBAL) {
1091                         if (e->verbose) {
1092                                 printf("Monitor on thread local object!\n");
1093                         }
1094                 }
1095         }
1096 }
1097
1098 static void escape_analysis_mark_allocations(escape_analysis_t *e) {
1099         instruction_list_item_t *iti;
1100         instruction *iptr;
1101         escape_state_t es;
1102         FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1103                 iptr = iti->instr;
1104                 es = escape_analysis_get_state(e, instruction_dst(iptr));
1105
1106 #if defined(ENABLE_REASON)
1107                 if (instruction_get_opcode(iptr) == ICMD_NEW) {
1108                         var_extra_t *ve;
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";
1116                                 r->iptr = NULL;
1117                                 r->next = NULL;
1118                                 iptr->escape_reasons = r;
1119                         } else {
1120                                 assert(iptr->escape_reasons);
1121                         }
1122                 }
1123 #endif
1124
1125 /*
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;
1131                         }
1132                 }
1133 */
1134         }
1135 }
1136
1137 static void escape_analysis_process_arguments(escape_analysis_t *e) {
1138         s4 p;
1139         s4 t;
1140         s4 l;
1141         s4 varindex;
1142         methoddesc *md;
1143         
1144         md = e->jd->m->parseddesc;
1145
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);*/
1155                         }
1156                         e->adr_args_count += 1;
1157                 }
1158                 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1159         }
1160 }
1161
1162 static void escape_analysis_export_arguments(escape_analysis_t *e) {
1163         s4 p;
1164         s4 t;
1165         s4 l;
1166         s4 varindex;
1167         methoddesc *md;
1168         u1 *paramescape;
1169         instruction_list_item_t *iti;
1170         instruction *iptr;
1171         escape_state_t es, re;
1172         int ret_val_is_adr;
1173         
1174         md = e->jd->m->parseddesc;
1175
1176         ret_val_is_adr = (md->returntype.type == TYPE_ADR) ? 1 : 0;
1177
1178         paramescape = MNEW(u1, e->adr_args_count + ret_val_is_adr);
1179
1180         e->jd->m->paramescape = paramescape + ret_val_is_adr;
1181
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;
1188                         } else {
1189                                 es = escape_analysis_get_state(e, varindex);
1190
1191                                 if (es == ESCAPE_METHOD_RETURN) {
1192                                         *paramescape = escape_state_to_u1(ESCAPE_METHOD) | 0x80;
1193                                         if (e->verbose) {
1194                                                 printf("non-escaping adr parameter returned: %d\n", p);
1195                                         }
1196                                 } else {
1197                                         *paramescape = escape_state_to_u1(es);
1198                                 }
1199
1200                         }
1201                         paramescape += 1;
1202                 }
1203                 l += IS_2_WORD_TYPE(t) ? 2 : 1;
1204         }
1205
1206         if (ret_val_is_adr) {
1207                 /* Calculate escape state of return value as maximum escape state of all
1208                    values returned. */
1209
1210                 re = ESCAPE_NONE;
1211
1212                 FOR_EACH_INSTRUCTION_LIST(e->returns, iti) {
1213                         iptr = iti->instr;
1214                         es = escape_analysis_get_state(e, instruction_s1(iptr));
1215
1216                         if (es > re) {
1217                                 re = es;
1218                         }
1219                 }
1220
1221                 e->jd->m->paramescape[-1] = escape_state_to_u1(re);
1222         }
1223 }
1224
1225 #if defined(ENABLE_REASON)
1226 void print_escape_reasons() {
1227         reason_t *re = THREADOBJECT->escape_reasons;
1228
1229         fprintf(stderr, "DYN_REASON");
1230         
1231         for (; re; re = re->next) {
1232                 fprintf(stderr,":%s", re->why);
1233         }
1234
1235         fprintf(stderr, "\n");
1236 }
1237
1238 void set_escape_reasons(void *vp) {
1239         THREADOBJECT->escape_reasons = vp;
1240 }
1241 #endif
1242
1243 static void escape_analysis_display(escape_analysis_t *e) {
1244         instruction_list_item_t *iti;
1245         var_extra_t *ve;
1246         instruction *iptr;
1247
1248         FOR_EACH_INSTRUCTION_LIST(e->allocations, iti) {
1249                 iptr = iti->instr;
1250                 ve = var_extra_get(e, var_extra_get_representant(e, instruction_dst(iptr)));
1251                 show_icmd(e->jd, iptr-1, 0, 3);
1252                 printf("\n");
1253                 show_icmd(e->jd, iptr, 0, 3);
1254                 printf("\n");
1255                 printf(
1256                         "%s@%d: --%s-- %d\n\n", 
1257                         icmd_table[iptr->opc].name, 
1258                         iptr->line, 
1259                         escape_state_to_string(ve->escape_state),
1260                         ve->representant
1261                 );
1262 #if defined(ENABLE_REASON)
1263                 {
1264                         reason_t *re;
1265                         for (re = ve->reasons; re; re = re->next) {
1266                                 printf("ESCAPE_REASON: %s\n", re->why);
1267                         }
1268                 }
1269 #endif
1270         }
1271 }
1272
1273 void escape_analysis_perform(jitdata *jd) {
1274         escape_analysis_t *e;
1275
1276         jd->m->flags |= ACC_METHOD_EA;
1277
1278         e = DNEW(escape_analysis_t);
1279         escape_analysis_init(e, jd);
1280
1281         if (e->verbose) 
1282                 color_printf(RED, "\n\n==== %s/%s ====\n\n", e->jd->m->clazz->name->text, e->jd->m->name->text);
1283                 
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);
1288
1289         escape_analysis_export_arguments(e);
1290         if (e->verbose) escape_analysis_display(e);
1291
1292         if (e->verbose) {
1293                 int i, j, r;
1294                 for (i = 0; i < jd->vartop; ++i) {
1295                         r = var_extra_get_representant(e, i);
1296                         if (i == r) {
1297                                 printf("EES of %d: ", i);
1298                                 for (j = 0; j < jd->vartop; ++j) {
1299                                         if (var_extra_get_representant(e, j) == r) {
1300                                                 printf("%d, ", j);
1301                                         }
1302                                 }
1303                                 printf("\n");
1304                         }
1305                 }
1306                 printf("\n");
1307         }
1308
1309         escape_analysis_mark_allocations(e);
1310         escape_analysis_mark_monitors(e);
1311
1312         jd->m->flags &= ~ACC_METHOD_EA;
1313 }
1314
1315 void escape_analysis_escape_check(void *vp) {
1316 }
1317
1318 /*** monomorphic *************************************************************/
1319
1320 bool escape_is_monomorphic(methodinfo *caller, methodinfo *callee) {
1321
1322         /* Non-speculative case */
1323
1324         if (callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE)) {
1325                 return true;
1326         }
1327
1328         if (
1329                 (callee->flags & (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED| ACC_ABSTRACT))
1330                 == (ACC_METHOD_MONOMORPHIC | ACC_METHOD_IMPLEMENTED)
1331         ) {
1332
1333                 /* Mark that we have used the information about monomorphy. */
1334
1335                 callee->flags |= ACC_METHOD_MONOMORPHY_USED;
1336
1337                 /* We assume the callee is monomorphic. */
1338
1339                 method_add_assumption_monomorphic(caller, callee);
1340
1341                 return true;
1342         }
1343
1344         return false;
1345 }
1346