1 /* src/vm/jit/inline/inline.c - code inliner
3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Edwin Steiner
31 $Id: inline.c 4921 2006-05-15 14:24:36Z twisti $
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/builtin.h"
47 #include "vm/global.h"
48 #include "vm/options.h"
49 #include "vm/statistics.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/parse.h"
52 #include "vm/jit/inline/inline.h"
53 #include "vm/jit/loop/loop.h"
56 #include "vm/initialize.h"
57 #include "vm/method.h"
58 #include "vm/jit/jit.h"
60 #include "vm/jit/reg.h"
61 #include "vm/jit/stack.h"
63 #include "vm/jit/verify/typecheck.h"
65 #if defined(ENABLE_THREADS)
66 # include "threads/native/threads.h"
70 bool inline_debug_log = 0;
71 bool inline_debug_log_names = 0;
72 int inline_debug_start_counter = 0;
73 int inline_debug_max_size = INT_MAX;
74 int inline_debug_min_size = 0;
75 int inline_debug_end_counter = INT_MAX;
76 int inline_count_methods = 0;
77 #define DOLOG(code) do{ if (inline_debug_log) { code; } }while(0)
82 typedef struct inline_node inline_node;
83 typedef struct inline_target_ref inline_target_ref;
84 typedef struct inline_context inline_context;
85 typedef struct inline_stack_translation inline_stack_translation;
86 typedef struct inline_block_map inline_block_map;
92 inline_node *children;
97 /* info about the call site (if depth > 0)*/
99 basicblock *callerblock;
100 instruction *callerins;
102 stackptr n_callerstack;
103 int n_callerstackdepth;
104 stackptr o_callerstack;
105 exceptiontable **o_handlers;
107 /* info about the callee */
109 int prolog_instructioncount;
110 int epilog_instructioncount;
111 int extra_instructioncount;
112 int instructioncount;
115 basicblock *handler_monitorexit;
117 /* cumulative values */
118 int cumul_instructioncount;
119 int cumul_stackcount;
120 int cumul_basicblockcount;
123 int cumul_exceptiontablelength;
126 instruction *inlined_iinstr;
127 instruction *inlined_iinstr_cursor;
128 stackptr n_inlined_stack;
129 stackptr n_inlined_stack_cursor;
130 basicblock *inlined_basicblocks;
131 basicblock *inlined_basicblocks_cursor;
134 registerdata *regdata;
137 inline_target_ref *refs;
138 instruction *inline_start_instruction;
141 struct inline_target_ref {
142 inline_target_ref *next;
147 struct inline_stack_translation {
152 struct inline_block_map {
158 struct inline_context {
161 int next_block_number;
162 inline_block_map *blockmap;
167 stackptr o_translationlimit; /* if a stackptr is smaller than this, look it up in the table */
168 stackptr n_debug_stackbase;
169 inline_stack_translation *stacktranslationstart;
171 inline_stack_translation stacktranslation[1]; /* XXX VARIABLE LENGTH! */
174 static int stack_depth(stackptr sp)
185 #include "inline_debug.c"
187 void inline_print_stats()
189 printf("inlined callers: %d\n",inline_count_methods);
193 static bool inline_jit_compile_intern(jitdata *jd)
199 /* XXX initialize the static function's class */
202 m->isleafmethod = true;
204 /* call the compiler passes ***********************************************/
206 /* call parse pass */
208 DOLOG( log_message_class("Parsing ", m->class) );
213 /* call stack analysis pass */
215 if (!stack_analyse(jd)) {
222 static bool inline_jit_compile(inline_node *iln)
233 #if defined(ENABLE_THREADS)
234 /* enter a monitor on the method */
235 builtin_monitorenter((java_objectheader *) m);
238 /* XXX dont parse these a second time because parse is not idempotent */
239 for (i=0; i<m->jcodelength; ++i) {
240 if (m->jcode[i] == JAVA_TABLESWITCH || m->jcode[i] == JAVA_LOOKUPSWITCH) {
246 /* allocate jitdata structure and fill it */
251 jd->cd = DNEW(codegendata);
252 jd->rd = DNEW(registerdata);
253 #if defined(ENABLE_LOOP)
254 jd->ld = DNEW(loopdata);
258 /* Allocate codeinfo memory from the heap as we need to keep them. */
260 jd->code = code_codeinfo_new(m); /* XXX check allocation */
262 #if defined(ENABLE_JIT)
263 # if defined(ENABLE_INTRP)
266 /* initialize the register allocator */
270 /* setup the codegendata memory */
274 /* now call internal compile function */
276 r = inline_jit_compile_intern(jd);
279 iln->regdata = jd->rd;
282 /* free some memory */
286 #if defined(ENABLE_JIT)
287 # if defined(ENABLE_INTRP)
296 #if defined(ENABLE_THREADS)
297 /* leave the monitor */
298 builtin_monitorexit((java_objectheader *) m );
302 stack_show_method(jd);
308 static void insert_inline_node(inline_node *parent,inline_node *child)
313 assert(parent && child);
315 child->parent = parent;
317 first = parent->children;
319 /* insert as only node */
320 parent->children = child;
326 /* {there is at least one child already there} */
329 while (succ->callerpc < child->callerpc) {
332 /* insert as last node */
333 child->prev = first->prev;
335 child->prev->next = child;
336 child->next->prev = child;
341 assert(succ->callerpc > child->callerpc);
343 /* insert before succ */
345 child->prev = succ->prev;
347 child->prev->next = child;
348 child->next->prev = child;
351 static stackptr relocate_stack_ptr_intern(inline_node *iln,stackptr o_link,ptrint curreloc)
353 inline_stack_translation *tr;
356 /* XXX should limit range in both directions */
357 if (o_link < iln->ctx->o_translationlimit) {
358 /* this stack slot is from an earlier chunk, we must look it up */
359 tr = iln->ctx->stacktranslationstart;
360 while (tr >= iln->ctx->stacktranslation) {
361 if (o_link == tr->o_sp) {
362 DOLOG(printf("\t\t\ttable lookup %p -> %d\n",(void*)o_link,DEBUG_SLOT(tr->n_sp)));
367 DOLOG(debug_dump_inline_context(iln));
368 DOLOG(printf("\t\tFAILED TO TRANSLATE: %p\n",(void*)o_link));
372 /* this stack slot it in the most recent chunk */
374 DOLOG( printf("\t\t\toffset %d\n",(int)curreloc) );
375 return (stackptr) ((u1*)o_link + curreloc);
378 return iln->n_callerstack;
381 /* XXX for debugging */
382 static stackptr relocate_stack_ptr(inline_node *iln,stackptr o_link,ptrint curreloc)
386 new = relocate_stack_ptr_intern(iln,o_link,curreloc);
388 printf("\t\treloc %p -> %d (%p)\t(translimit=%p)\n",
389 (void*)o_link,DEBUG_SLOT(new),(void*)new,(void*)iln->ctx->o_translationlimit)
394 static void emit_instruction(inline_node *iln,instruction *ins,ptrint curreloc,stackptr o_curstack)
399 inline_target_ref *ref;
403 for (i=0; i<iln->depth; ++i)
407 n_ins = (iln->inlined_iinstr_cursor++);
408 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
412 switch (n_ins[0].opc) {
413 /****************************************/
414 /* VARIABLE ACCESS */
428 n_ins[0].op1 += iln->localsoffset;
461 ref = DNEW(inline_target_ref);
462 ref->ref = (basicblock **) &(n_ins[0].target);
463 ref->next = iln->refs;
467 /****************************************/
472 n_ins[0].opc = ICMD_GOTO;
484 n_ins[0].opc = ICMD_INLINE_GOTO;
485 n_ins[0].dst = o_curstack;
487 n_ins[0].target = (void *) (ptrint) (iln->depth + 0x333); /* XXX */
488 ref = DNEW(inline_target_ref);
489 ref->ref = (basicblock **) &(n_ins[0].target);
490 ref->next = iln->refs;
496 n_ins[0].dst = relocate_stack_ptr(iln,n_ins[0].dst,curreloc);
499 static stackptr inline_new_stackslot(inline_node *iln,stackptr n_curstack,s4 type)
503 n_sp = iln->n_inlined_stack_cursor++;
504 assert((n_sp - iln->n_inlined_stack) < iln->cumul_stackcount);
506 n_sp->prev = n_curstack;
508 n_sp->varkind = TEMPVAR;
509 n_sp->varnum = stack_depth(n_curstack); /* XXX inefficient */
512 n_sp->regoff = (IS_FLT_DBL_TYPE(type)) ? -1 : INT_ARG_CNT;
518 static stackptr emit_inlining_prolog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
528 insinfo_inline *insinfo;
530 assert(iln && callee && o_iptr);
533 md = calleem->parseddesc;
534 isstatic = (calleem->flags & ACC_STATIC);
536 localindex = callee->localsoffset + md->paramslots;
537 depth = stack_depth(n_curstack) - 1; /* XXX inefficient */
538 for (i=md->paramcount-1; i>=0; --i) {
541 n_ins = (iln->inlined_iinstr_cursor++);
542 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
544 type = md->paramtypes[i].type;
546 localindex -= IS_2_WORD_TYPE(type) ? 2 : 1;
547 assert(callee->regdata);
549 DOLOG( printf("prologlocal %d type=%d lofs=%d in ",
550 localindex - callee->localsoffset,
551 callee->regdata->locals[localindex - callee->localsoffset][type].type,callee->localsoffset);
552 method_println(callee->m); );
554 if ((callee->regdata->locals[localindex - callee->localsoffset][type].type >= 0)
556 (i==0 && callee->synchronize && !isstatic))
558 n_ins->opc = ICMD_ISTORE + type;
559 n_ins->op1 = localindex;
562 n_ins->opc = IS_2_WORD_TYPE(type) ? ICMD_POP2 : ICMD_POP; /* XXX is POP2 correct? */
564 n_ins->line = o_iptr->line;
566 if (n_curstack->varkind == ARGVAR) {
567 n_curstack->varkind = TEMPVAR;
568 n_curstack->varnum = depth;
569 n_curstack->flags &= ~INMEMORY;
571 n_curstack = n_curstack->prev;
572 n_ins->dst = n_curstack;
576 /* INLINE_START instruction */
578 n_ins = (iln->inlined_iinstr_cursor++);
579 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
581 insinfo = DNEW(insinfo_inline);
582 insinfo->method = callee->m;
583 insinfo->outer = iln->m;
584 /* XXX using local 0 only works if it is read-only!! */
585 insinfo->synclocal = callee->localsoffset;
586 insinfo->synchronize = callee->synchronize;
588 n_ins->opc = ICMD_INLINE_START;
589 n_ins->dst = n_curstack;
590 n_ins->target = insinfo;
591 n_ins->line = o_iptr->line;
592 iln->inline_start_instruction = n_ins;
597 static void emit_inlining_epilog(inline_node *iln,inline_node *callee,stackptr n_curstack,instruction *o_iptr)
601 assert(iln && callee && o_iptr);
602 assert(iln->inline_start_instruction);
604 n_ins = (iln->inlined_iinstr_cursor++);
605 assert((n_ins - iln->inlined_iinstr) < iln->cumul_instructioncount);
607 n_ins->opc = ICMD_INLINE_END;
608 n_ins->dst = n_curstack;
609 n_ins->target = iln->inline_start_instruction->target; /* insinfo_inline * */
610 n_ins->line = o_iptr->line;
613 static void rewrite_stack(inline_node *iln,stackptr o_first,stackptr o_last,ptrint curreloc)
623 DOLOG(printf("rewrite_stack: no stack slots\n"));
629 assert(o_first <= o_last);
631 n = o_last - o_first + 1;
635 n_sp = iln->n_inlined_stack_cursor;
638 printf("rewrite_stack: rewriting %d stack slots (%p,%p) -> (%d,%d)\n",
639 n,(void*)o_first,(void*)o_last,DEBUG_SLOT(n_sp),
640 DEBUG_SLOT(n_sp+n-1))
643 DOLOG( printf("o_first = "); debug_dump_stack(o_first); printf("\n") );
644 DOLOG( printf("o_last = "); debug_dump_stack(o_last); printf("\n") );
646 while (o_sp <= o_last) {
649 n_sp->prev = relocate_stack_ptr(iln,n_sp->prev,curreloc);
650 switch (n_sp->varkind) {
651 case STACKVAR: n_sp->varnum += iln->n_callerstackdepth; break;
652 case LOCALVAR: n_sp->varnum += iln->localsoffset; break;
658 DOLOG( printf("n_sp = "); debug_dump_stack(n_sp-1); printf("\n") );
660 iln->n_inlined_stack_cursor = n_sp;
661 assert((n_sp - iln->n_inlined_stack) <= iln->cumul_stackcount);
664 static void inline_resolve_block_refs(inline_target_ref **refs,basicblock *o_bptr,basicblock *n_bptr)
666 inline_target_ref *ref;
667 inline_target_ref *prev;
672 if (*(ref->ref) == o_bptr) {
674 if ((ptrint) o_bptr < (0x333+100)) { /* XXX */
675 printf("resolving RETURN block reference %p -> new L%03d (%p)\n",
676 (void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
679 printf("resolving block reference old L%03d (%p) -> new L%03d (%p)\n",
680 o_bptr->debug_nr,(void*)o_bptr,n_bptr->debug_nr,(void*)n_bptr);
684 *(ref->ref) = n_bptr;
686 prev->next = ref->next;
699 static basicblock * create_block(inline_node *iln,basicblock *o_bptr,inline_target_ref **refs,int indepth)
708 n_bptr = iln->inlined_basicblocks_cursor++;
710 assert((n_bptr - iln->inlined_basicblocks) < iln->cumul_basicblockcount);
713 temp = iln->m->c_debug_nr;
714 BASICBLOCK_INIT(n_bptr,iln->m);
715 iln->m->c_debug_nr = temp;
717 n_bptr->iinstr = iln->inlined_iinstr_cursor;
718 n_bptr->next = n_bptr+1;
719 n_bptr->debug_nr = iln->ctx->next_block_number++;
720 n_bptr->indepth = indepth;
723 /* allocate stackslots */
724 iln->n_inlined_stack_cursor += indepth;
725 n_sp = iln->n_inlined_stack_cursor - 1;
726 n_bptr->instack = n_sp;
728 assert((n_sp - iln->n_inlined_stack) < iln->cumul_stackcount);
730 /* link the stack elements */
731 for (i=indepth-1; i>=0; --i) {
732 n_sp->varkind = STACKVAR;
734 n_sp->prev = (i) ? n_sp-1 : NULL;
735 n_sp->flags = 0; /* XXX */
742 inline_resolve_block_refs(refs,o_bptr,n_bptr);
748 static void fill_translation_table(inline_node *iln,stackptr o_sp,stackptr n_sp,int n_depth)
753 printf("fill_translation_table (newdepth=%d):\n",n_depth);
754 printf("\tos_sp = "); debug_dump_stack(o_sp); printf("\n");
755 printf("\tns_sp = "); debug_dump_stack(n_sp); printf("\n");
758 /* we must translate all stack slots that were present before the call XXX */
759 /* and the instack of the block */
760 iln->ctx->stacktranslationstart = iln->ctx->stacktranslation + (n_depth - 1);
762 /* fill the translation table */
769 iln->ctx->stacktranslation[i].o_sp = o_sp;
770 iln->ctx->stacktranslation[i].n_sp = n_sp;
771 n_sp->flags |= (o_sp->flags & SAVEDVAR); /* XXX correct? */
772 n_sp->type = o_sp->type; /* XXX we overwrite this anyway with STACKVAR, right? */
780 assert(iln->ctx->stacktranslation[i].o_sp);
781 iln->ctx->stacktranslation[i].n_sp = n_sp;
782 n_sp->flags |= SAVEDVAR; /* XXX this is too conservative */
791 static void rewrite_method(inline_node *iln)
801 stackptr o_nexttorewrite;
802 stackptr o_lasttorewrite;
803 inline_node *nextcall;
806 inline_block_map *bm;
813 nextcall = iln->children;
815 /* set memory cursors */
816 iln->inlined_iinstr_cursor = iln->inlined_iinstr;
817 iln->n_inlined_stack_cursor = iln->n_inlined_stack;
818 iln->inlined_basicblocks_cursor = iln->inlined_basicblocks;
820 /* loop over basic blocks */
821 o_bptr = iln->m->basicblocks;
822 for (; o_bptr; o_bptr = o_bptr->next) {
824 if (o_bptr->flags < BBREACHED) {
826 printf("skipping old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
827 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
828 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
829 DEBUG_SLOT(iln->n_inlined_stack_cursor),
830 DEBUG_SLOT(iln->n_callerstack));
831 method_println(iln->m);
834 n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
835 n_bptr->type = o_bptr->type;
836 /* enter it in the blockmap */
837 iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
838 iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
839 iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
840 n_bptr->flags = o_bptr->flags;
844 assert(o_bptr->stack);
846 len = o_bptr->icount;
847 o_iptr = o_bptr->iinstr;
850 printf("rewriting old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,callerstack=%d) of ",
851 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
852 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
853 DEBUG_SLOT(iln->n_inlined_stack_cursor),
854 DEBUG_SLOT(iln->n_callerstack));
855 method_println(iln->m);
856 printf("o_instack: ");debug_dump_stack(o_bptr->instack);printf("\n");
857 printf("o_callerstack: ");debug_dump_stack(iln->o_callerstack);printf("\n");
860 o_curstack = o_bptr->instack;
862 /* create an inlined clone of this block */
863 n_bptr = create_block(iln,o_bptr,&(iln->refs),o_bptr->indepth + iln->n_callerstackdepth);
864 n_bptr->type = o_bptr->type;
865 n_bptr->flags = o_bptr->flags;
867 /* enter it in the blockmap */
868 iln->ctx->blockmap[iln->ctx->blockmap_index].iln = iln;
869 iln->ctx->blockmap[iln->ctx->blockmap_index].o_block = o_bptr;
870 iln->ctx->blockmap[iln->ctx->blockmap_index++].n_block = n_bptr;
872 DOLOG( debug_dump_inline_context(iln) );
874 if (iln->n_callerstackdepth)
875 iln->n_callerstack = n_bptr->instack-o_bptr->indepth;
877 iln->n_callerstack = NULL;
878 fill_translation_table(iln,iln->o_callerstack,iln->n_callerstack,iln->n_callerstackdepth);
879 fill_translation_table(iln,o_bptr->instack,n_bptr->instack,n_bptr->indepth);
880 iln->ctx->o_translationlimit = o_bptr->stack;
882 DOLOG( debug_dump_inline_context(iln) );
884 /* calculate the stack element relocation */
885 curreloc = (u1*)iln->n_inlined_stack_cursor - (u1*)o_bptr->stack;
886 DOLOG( printf("curreloc <- %d = %p - %p\n",(int)curreloc,(void*)iln->n_inlined_stack_cursor,(void*)(u1*)o_bptr->stack) );
888 o_nexttorewrite = o_bptr->stack;
889 o_lasttorewrite = o_bptr->stack-1;
890 assert(o_nexttorewrite);
897 DOLOG( printf("o_curstack = "); debug_dump_stack(o_curstack); stack_show_icmd(o_iptr,false); printf(", dst = "); debug_dump_stack(o_dst); printf("\n") );
899 if (nextcall && o_iptr == nextcall->callerins) {
901 /* rewrite stack elements produced so far in this block */
902 if (o_nexttorewrite <= o_lasttorewrite) {
903 rewrite_stack(iln, o_nexttorewrite, o_lasttorewrite, curreloc);
906 /* write the inlining prolog */
907 n_sp = emit_inlining_prolog(iln,nextcall,relocate_stack_ptr(iln,o_curstack,curreloc),o_iptr);
908 icount += nextcall->m->parseddesc->paramcount + 1; /* XXX prolog instructions */
910 /* find the first stack slot under the arguments of the invocation */
912 for (i=0; i < nextcall->m->parseddesc->paramcount; ++i) {
916 nextcall->o_callerstack = o_sp;
918 /* see how deep the new stack is after the arguments have been removed */
919 i = stack_depth(n_sp);
920 assert(i == stack_depth(nextcall->o_callerstack) + iln->n_callerstackdepth);
922 /* end current block */
923 n_bptr->icount = icount;
924 n_bptr->outstack = n_sp;
925 n_bptr->outdepth = i;
927 /* caller stack depth for the callee */
928 assert(nextcall->n_callerstackdepth == i);
930 /* set memory pointers in the callee */
931 nextcall->inlined_iinstr = iln->inlined_iinstr_cursor;
932 nextcall->n_inlined_stack = iln->n_inlined_stack_cursor;
933 nextcall->inlined_basicblocks = iln->inlined_basicblocks_cursor;
936 DOLOG( printf("entering inline "); stack_show_icmd(o_iptr,false); printf("\n") );
937 rewrite_method(nextcall);
938 DOLOG( printf("leaving inline "); stack_show_icmd(o_iptr,false); printf("\n") );
940 /* skip stack slots used by the inlined callee */
941 curreloc += (u1*)nextcall->n_inlined_stack_cursor - (u1*)iln->n_inlined_stack_cursor;
943 /* update memory cursors */
944 assert(nextcall->inlined_iinstr_cursor == iln->inlined_iinstr_cursor + nextcall->cumul_instructioncount);
945 /* XXX m->stackcount seems to be a conservative estimate */
946 assert(nextcall->n_inlined_stack_cursor <= iln->n_inlined_stack_cursor + nextcall->cumul_stackcount);
947 assert(nextcall->inlined_basicblocks_cursor == iln->inlined_basicblocks_cursor + nextcall->cumul_basicblockcount);
948 iln->inlined_iinstr_cursor = nextcall->inlined_iinstr_cursor;
949 iln->n_inlined_stack_cursor = nextcall->n_inlined_stack_cursor;
950 iln->inlined_basicblocks_cursor = nextcall->inlined_basicblocks_cursor;
952 /* start new block */
953 i = (nextcall->m->parseddesc->returntype.type == TYPE_VOID) ? 0 : 1; /* number of return slots */
954 assert(i == 0 || i == 1);
955 n_bptr = create_block(iln,(void*) (ptrint) (nextcall->depth + 0x333) /*XXX*/,
956 &(nextcall->refs),nextcall->n_callerstackdepth + i);
957 n_bptr->flags = o_bptr->flags;
960 /* skip allocated stack slots */
961 curreloc += sizeof(stackelement) * (n_bptr->indepth - i);
963 /* fill the translation table for the slots present before the call */
964 n_sp = n_bptr->instack;
965 fill_translation_table(iln,nextcall->o_callerstack,(i) ? n_sp->prev : n_sp,nextcall->n_callerstackdepth);
967 /* the return slot */
971 fill_translation_table(iln,o_dst,n_sp,nextcall->n_callerstackdepth + 1);
973 o_nexttorewrite = o_dst + 1;
974 o_lasttorewrite = o_dst;
977 /* the next chunk of stack slots start with (including) the slots produced */
978 /* by the invocation */
979 o_nexttorewrite = o_lasttorewrite + 1;
980 o_lasttorewrite = o_nexttorewrite - 1;
983 DOLOG( debug_dump_inline_context(iln) );
984 iln->ctx->o_translationlimit = o_nexttorewrite;
986 /* emit inlining epilog */
987 emit_inlining_epilog(iln,nextcall,n_sp,o_iptr);
988 icount++; /* XXX epilog instructions */
990 /* proceed to next call */
991 nextcall = nextcall->next;
994 printf("resuming old L%03d (flags=%d,type=%d,os=%p,oid=%d,ois=%p,cursor=%d,curreloc=%d,callerstack=%d) of ",
995 o_bptr->debug_nr,o_bptr->flags,o_bptr->type,
996 (void*)o_bptr->stack,o_bptr->indepth,(void*)o_bptr->instack,
997 DEBUG_SLOT(iln->n_inlined_stack_cursor),(int)curreloc,
998 DEBUG_SLOT(iln->n_callerstack));
999 method_println(iln->m);
1003 emit_instruction(iln,o_iptr,curreloc,o_curstack);
1006 if (o_dst > o_lasttorewrite)
1007 o_lasttorewrite = o_dst;
1010 DOLOG( printf("o_dst = %p\n",(void*)o_dst) );
1015 /* end of basic block */
1016 /* rewrite stack after last call */
1017 if (o_nexttorewrite <= o_lasttorewrite) {
1018 rewrite_stack(iln,o_nexttorewrite,o_lasttorewrite,curreloc);
1020 n_bptr->outstack = relocate_stack_ptr(iln,o_bptr->outstack,curreloc);
1021 n_bptr->outdepth = iln->n_callerstackdepth + o_bptr->outdepth;
1022 assert(n_bptr->outdepth == stack_depth(n_bptr->outstack));
1024 if (n_bptr->outstack) {
1026 n_bptr->outstack += curreloc;
1029 n_bptr->icount = icount;
1031 n_iptr = iln->inlined_iinstr_cursor - 1;
1032 if (n_iptr->opc == ICMD_INLINE_GOTO) {
1033 DOLOG( printf("creating stack slot for ICMD_INLINE_GOTO\n") );
1034 n_sp = iln->n_inlined_stack_cursor++;
1035 assert(n_iptr->dst);
1036 *n_sp = *n_iptr->dst;
1037 n_sp->prev = iln->n_callerstack;
1040 n_bptr->outdepth = iln->n_callerstackdepth + 1;
1041 n_bptr->outstack = n_sp;
1045 bm = iln->ctx->blockmap;
1046 for (i=0; i<iln->ctx->blockmap_index; ++i, ++bm) {
1047 assert(bm->iln && bm->o_block && bm->n_block);
1050 inline_resolve_block_refs(&(iln->refs),iln->ctx->blockmap[i].o_block,iln->ctx->blockmap[i].n_block);
1055 inline_target_ref *ref;
1058 if (!iln->depth || *(ref->ref) != (void*) (ptrint) (0x333 + iln->depth) /* XXX */) {
1059 DOLOG( printf("XXX REMAINING REF at depth %d: %p\n",iln->depth,(void*)*(ref->ref)) );
1068 static basicblock * inline_map_block(inline_node *iln,basicblock *o_block,inline_node *targetiln)
1070 inline_block_map *bm;
1071 inline_block_map *bmend;
1079 bm = iln->ctx->blockmap;
1080 bmend = bm + iln->ctx->blockmap_index;
1082 while (bm < bmend) {
1083 assert(bm->iln && bm->o_block && bm->n_block);
1084 if (bm->o_block == o_block && bm->iln == targetiln)
1090 return NULL; /* not reached */
1093 static exceptiontable * inline_exception_tables(inline_node *iln,exceptiontable *n_extable,exceptiontable **prevextable)
1101 assert(prevextable);
1103 child = iln->children;
1106 n_extable = inline_exception_tables(child,n_extable,prevextable);
1107 child = child->next;
1108 } while (child != iln->children);
1111 et = iln->m->exceptiontable;
1112 for (i=0; i<iln->m->exceptiontablelength; ++i) {
1114 memset(n_extable,0,sizeof(exceptiontable));
1115 n_extable->startpc = et->startpc;
1116 n_extable->endpc = et->endpc;
1117 n_extable->handlerpc = et->handlerpc;
1118 n_extable->start = inline_map_block(iln,et->start,iln);
1119 n_extable->end = inline_map_block(iln,et->end,iln);
1120 n_extable->handler = inline_map_block(iln,et->handler,iln);
1121 n_extable->catchtype = et->catchtype;
1124 (*prevextable)->down = n_extable;
1126 *prevextable = n_extable;
1132 if (iln->handler_monitorexit) {
1133 exceptiontable **activehandlers;
1135 memset(n_extable,0,sizeof(exceptiontable));
1136 n_extable->startpc = 0; /* XXX */
1137 n_extable->endpc = 0; /* XXX */
1138 n_extable->handlerpc = 0; /* XXX */
1139 n_extable->start = iln->inlined_basicblocks;
1140 n_extable->end = iln->inlined_basicblocks_cursor;
1141 n_extable->handler = iln->handler_monitorexit;
1142 n_extable->catchtype.any = NULL; /* finally */
1145 (*prevextable)->down = n_extable;
1147 *prevextable = n_extable;
1151 activehandlers = iln->o_handlers;
1152 while (*activehandlers) {
1154 assert(iln->parent);
1156 memset(n_extable,0,sizeof(exceptiontable));
1157 n_extable->startpc = 0; /* XXX */
1158 n_extable->endpc = 0; /* XXX */
1159 n_extable->handlerpc = 0; /* XXX */
1160 n_extable->start = iln->handler_monitorexit;
1161 n_extable->end = iln->handler_monitorexit + 1;
1162 n_extable->handler = inline_map_block(iln->parent,(*activehandlers)->handler,iln->parent);
1163 n_extable->catchtype = (*activehandlers)->catchtype;
1166 (*prevextable)->down = n_extable;
1168 *prevextable = n_extable;
1179 static void inline_locals(inline_node *iln,registerdata *rd)
1188 child = iln->children;
1191 inline_locals(child,rd);
1192 child = child->next;
1193 } while (child != iln->children);
1196 assert(iln->regdata);
1198 for (i=0; i<iln->m->maxlocals; ++i) {
1199 for (t=TYPE_INT; t<=TYPE_ADR; ++t) {
1200 DOLOG( printf("local %d type=%d in ",i,iln->regdata->locals[i][t].type); method_println(iln->m); );
1201 if (iln->regdata->locals[i][t].type >= 0) {
1202 rd->locals[iln->localsoffset + i][t].type = iln->regdata->locals[i][t].type;
1203 rd->locals[iln->localsoffset + i][t].flags |= iln->regdata->locals[i][t].flags;
1208 if (iln->regdata->memuse > rd->memuse)
1209 rd->memuse = iln->regdata->memuse;
1210 if (iln->regdata->argintreguse > rd->argintreguse)
1211 rd->argintreguse = iln->regdata->argintreguse;
1212 if (iln->regdata->argfltreguse > rd->argfltreguse)
1213 rd->argfltreguse = iln->regdata->argfltreguse;
1216 static void inline_stack_interfaces(inline_node *iln,registerdata *rd)
1225 assert(rd->interfaces);
1227 bptr = iln->inlined_basicblocks;
1228 for (i=0; i<iln->cumul_basicblockcount; ++i, ++bptr) {
1229 DOLOG( printf("INLINE STACK INTERFACE block L%03d\n",bptr->debug_nr) );
1230 DOLOG( printf("\toutstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
1231 DOLOG( printf("\tinstack = ");debug_dump_stack(bptr->outstack);printf("\n") );
1233 assert(bptr->outdepth == stack_depth(bptr->outstack));
1234 assert(bptr->indepth == stack_depth(bptr->instack));
1236 sp = bptr->outstack;
1237 d = bptr->outdepth - 1;
1239 if ((sp->varkind == STACKVAR) && (sp->varnum > d)) {
1240 sp->varkind = TEMPVAR;
1243 sp->varkind = STACKVAR;
1246 DOLOG( printf("INLINE STACK INTERFACE L%03d outstack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
1247 bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
1248 rd->interfaces[d][sp->type].type = sp->type;
1249 rd->interfaces[d][sp->type].flags |= sp->flags;
1255 d = bptr->indepth - 1;
1257 rd->interfaces[d][sp->type].type = sp->type;
1258 if (sp->varkind == STACKVAR && (sp->flags & SAVEDVAR)) {
1259 rd->interfaces[d][sp->type].flags |= SAVEDVAR;
1261 DOLOG( printf("INLINE STACK INTERFACE L%03d instack d=%d varkind=%d varnum=%d type=%d flags=%01x\n",
1262 bptr->debug_nr,d,sp->varkind,sp->varnum,sp->type,sp->flags) );
1269 static bool inline_inline_intern(methodinfo *m,jitdata *jd, inline_node *iln)
1275 stackptr o_curstack;
1276 int opcode; /* invocation opcode */
1278 inline_node *calleenode;
1279 inline_node *active;
1283 exceptiontable **handlers;
1289 /* initialize cumulative counters */
1291 iln->cumul_maxstack = iln->n_callerstackdepth + m->maxstack + 1 /* XXX builtins */;
1292 iln->cumul_maxlocals = iln->localsoffset + m->maxlocals;
1293 iln->cumul_exceptiontablelength += m->exceptiontablelength;
1295 /* iterate over basic blocks */
1297 bptr = m->basicblocks;
1298 for (; bptr; bptr = bptr->next) {
1300 iln->cumul_basicblockcount++;
1302 /* extra stackslots */
1303 iln->cumul_stackcount += iln->n_callerstackdepth;
1305 if (bptr->flags < BBREACHED)
1308 /* allocate the buffer of active exception handlers */
1309 /* XXX this wastes some memory, but probably it does not matter */
1311 handlers = DMNEW(exceptiontable*, m->exceptiontablelength + 1);
1313 /* determine the active exception handlers for this block */
1314 /* XXX maybe the handlers of a block should be part of our IR */
1316 for (i = 0; i < m->exceptiontablelength; ++i) {
1317 if ((m->exceptiontable[i].start <= bptr) && (m->exceptiontable[i].end > bptr)) {
1318 handlers[nhandlers++] = m->exceptiontable + i;
1321 handlers[nhandlers] = NULL;
1323 assert(bptr->stack);
1326 iptr = bptr->iinstr;
1327 o_curstack = bptr->instack;
1329 iln->instructioncount += len;
1330 iln->cumul_instructioncount += len;
1333 printf("ADD INSTRUCTIONS [%d]: %d, count=%d, cumulcount=%d\n",
1334 iln->depth,len,iln->instructioncount,iln->cumul_instructioncount);
1337 while (--len >= 0) {
1344 /* XXX we cannot deal with IINC's stack hacking */
1347 case ICMD_LOOKUPSWITCH:
1348 case ICMD_TABLESWITCH:
1349 /* XXX these are not implemented, yet. */
1352 /****************************************/
1355 case ICMD_INVOKEVIRTUAL:
1356 case ICMD_INVOKESPECIAL:
1357 case ICMD_INVOKESTATIC:
1358 case ICMD_INVOKEINTERFACE:
1359 callee = (methodinfo *) iptr[0].val.a;
1362 if ((callee->flags & (ACC_STATIC | ACC_FINAL | ACC_PRIVATE) || opcode == ICMD_INVOKESPECIAL)
1363 && !(callee->flags & (ACC_NATIVE)))
1365 if (iln->depth < 3) {
1366 for (active = iln; active; active = active->parent) {
1367 if (callee == active->m) {
1368 DOLOG( printf("RECURSIVE!\n") );
1373 calleenode = DNEW(inline_node);
1374 memset(calleenode,0,sizeof(inline_node));
1376 calleenode->ctx = iln->ctx;
1377 calleenode->m = callee;
1378 calleenode->synchronize = (callee->flags & ACC_SYNCHRONIZED);
1379 isstatic = (callee->flags & ACC_STATIC);
1381 if (!inline_jit_compile(calleenode))
1384 /* info about the call site */
1385 calleenode->depth = iln->depth+1;
1386 calleenode->callerblock = bptr;
1387 calleenode->callerins = iptr;
1388 calleenode->callerpc = iptr - m->basicblocks->iinstr;
1389 calleenode->o_handlers = handlers;
1391 /* info about the callee */
1392 calleenode->localsoffset = iln->localsoffset + m->maxlocals;
1393 calleenode->prolog_instructioncount = callee->parseddesc->paramcount;
1394 calleenode->epilog_instructioncount = 0;
1395 calleenode->extra_instructioncount = 0;
1397 if (calleenode->synchronize) {
1399 builtintable_entry *bte;
1401 /* and exception handler */
1402 /* ALOAD, builtin_monitorexit, ATHROW */
1403 calleenode->extra_instructioncount += 3;
1404 /* stack elements used in handler */
1405 iln->cumul_stackcount += 2;
1407 /* exception table entries */
1408 iln->cumul_exceptiontablelength += 1 + nhandlers;
1410 bte = builtintable_get_internal(BUILTIN_monitorenter);
1412 if (md->memuse > calleenode->regdata->memuse)
1413 calleenode->regdata->memuse = md->memuse;
1414 if (md->argintreguse > calleenode->regdata->argintreguse)
1415 calleenode->regdata->argintreguse = md->argintreguse;
1418 bte = builtintable_get_internal(BUILTIN_staticmonitorenter);
1420 if (md->memuse > calleenode->regdata->memuse)
1421 calleenode->regdata->memuse = md->memuse;
1422 if (md->argintreguse > calleenode->regdata->argintreguse)
1423 calleenode->regdata->argintreguse = md->argintreguse;
1426 bte = builtintable_get_internal(BUILTIN_monitorexit);
1428 if (md->memuse > calleenode->regdata->memuse)
1429 calleenode->regdata->memuse = md->memuse;
1430 if (md->argintreguse > calleenode->regdata->argintreguse)
1431 calleenode->regdata->argintreguse = md->argintreguse;
1433 iln->ctx->calls_others = true;
1436 calleenode->stackcount = callee->stackcount;
1437 calleenode->cumul_stackcount = callee->stackcount;
1439 /* see how deep the stack is below the arguments */
1441 for (i=0; sp; sp = sp->prev)
1443 calleenode->n_callerstackdepth = iln->n_callerstackdepth + i - callee->parseddesc->paramcount;
1445 insert_inline_node(iln,calleenode);
1447 if (!inline_inline_intern(callee,jd,calleenode))
1450 if (calleenode->synchronize) {
1451 /* add exception handler block */
1452 iln->ctx->master->cumul_basicblockcount++;
1455 iln->cumul_instructioncount += calleenode->prolog_instructioncount;
1456 iln->cumul_instructioncount += calleenode->epilog_instructioncount;
1457 iln->cumul_instructioncount += calleenode->extra_instructioncount;
1458 iln->cumul_instructioncount += calleenode->cumul_instructioncount - 1/*invoke*/ + 2 /*INLINE_START|END*/;
1459 iln->cumul_stackcount += calleenode->cumul_stackcount;
1461 /* XXX extra block after inlined call */
1462 iln->cumul_stackcount += calleenode->n_callerstackdepth;
1463 iln->cumul_basicblockcount += 1;
1465 iln->cumul_basicblockcount += calleenode->cumul_basicblockcount;
1466 iln->cumul_exceptiontablelength += calleenode->cumul_exceptiontablelength;
1467 if (calleenode->cumul_maxstack > iln->cumul_maxstack)
1468 iln->cumul_maxstack = calleenode->cumul_maxstack;
1469 if (calleenode->cumul_maxlocals > iln->cumul_maxlocals)
1470 iln->cumul_maxlocals = calleenode->cumul_maxlocals;
1483 /* end of basic block */
1489 static void inline_write_exception_handlers(inline_node *master,inline_node *iln)
1492 stackptr n_curstack;
1495 builtintable_entry *bte;
1497 child = iln->children;
1500 inline_write_exception_handlers(master,child);
1501 child = child->next;
1502 } while (child != iln->children);
1505 if (iln->synchronize) {
1506 /* create the monitorexit handler */
1507 n_bptr = create_block(master,NULL,NULL,1 /*XXX*/);
1508 n_bptr->type = BBTYPE_EXH;
1509 n_bptr->flags = BBFINISHED;
1511 iln->handler_monitorexit = n_bptr;
1513 n_curstack = n_bptr->instack;
1515 /* ACONST / ALOAD */
1517 n_curstack = inline_new_stackslot(master,n_curstack,TYPE_ADR);
1519 n_ins = master->inlined_iinstr_cursor++;
1520 if (iln->m->flags & ACC_STATIC) {
1521 n_ins->opc = ICMD_ACONST;
1522 n_ins->val.a = iln->m->class;
1523 n_ins->target = (void *) 0x02; /* XXX target used temporarily as flag */
1526 n_ins->opc = ICMD_ALOAD;
1527 n_ins->op1 = iln->localsoffset; /* XXX */
1529 n_ins->dst = n_curstack;
1534 n_curstack = n_curstack->prev;
1536 bte = builtintable_get_internal(BUILTIN_monitorexit);
1538 n_ins = master->inlined_iinstr_cursor++;
1539 n_ins->opc = ICMD_BUILTIN;
1541 n_ins->dst = n_curstack;
1546 n_curstack = n_curstack->prev;
1548 n_ins = master->inlined_iinstr_cursor++;
1549 n_ins->opc = ICMD_ATHROW;
1550 n_ins->dst = n_curstack;
1553 /* close basic block */
1555 n_bptr->outstack = n_curstack;
1556 n_bptr->outdepth = stack_depth(n_curstack); /* XXX */
1561 static bool test_inlining(inline_node *iln,jitdata *jd,
1562 methodinfo **resultmethod, jitdata **resultjd)
1567 methodinfo *n_method;
1568 exceptiontable *n_ext;
1569 exceptiontable *prevext;
1575 static int debug_verify_inlined_code = 1;
1577 static int debug_compile_inlined_code_counter = 0;
1580 assert(iln && jd && resultmethod && resultjd);
1582 *resultmethod = iln->m;
1586 if (debug_compile_inlined_code_counter >5)
1590 n_ins = DMNEW(instruction,iln->cumul_instructioncount);
1591 iln->inlined_iinstr = n_ins;
1593 n_stack = DMNEW(stackelement,iln->cumul_stackcount);
1594 iln->n_inlined_stack = n_stack;
1595 iln->ctx->n_debug_stackbase = n_stack;
1597 n_bb = DMNEW(basicblock,iln->cumul_basicblockcount);
1598 iln->inlined_basicblocks = n_bb;
1600 iln->ctx->blockmap = DMNEW(inline_block_map,iln->cumul_basicblockcount);
1602 rewrite_method(iln);
1603 inline_write_exception_handlers(iln,iln);
1605 /* end of basic blocks */
1606 if (iln->inlined_basicblocks_cursor > iln->inlined_basicblocks) {
1607 iln->inlined_basicblocks_cursor[-1].next = NULL;
1610 if (iln->cumul_exceptiontablelength) {
1611 exceptiontable *tableend;
1613 n_ext = DMNEW(exceptiontable,iln->cumul_exceptiontablelength);
1615 tableend = inline_exception_tables(iln,n_ext,&prevext);
1616 assert(tableend == n_ext + iln->cumul_exceptiontablelength);
1618 prevext->down = NULL;
1624 /*******************************************************************************/
1626 n_method = NEW(methodinfo);
1627 memcpy(n_method,iln->m,sizeof(methodinfo));
1628 n_method->maxstack = iln->cumul_maxstack; /* XXX put into cd,rd */
1629 n_method->maxlocals = iln->cumul_maxlocals;
1630 n_method->basicblockcount = iln->cumul_basicblockcount;
1631 n_method->basicblocks = iln->inlined_basicblocks;
1632 n_method->basicblockindex = NULL;
1633 n_method->instructioncount = iln->cumul_instructioncount;
1634 n_method->instructions = iln->inlined_iinstr;
1635 n_method->stackcount = iln->cumul_stackcount;
1636 n_method->stack = iln->n_inlined_stack;
1638 n_method->exceptiontablelength = iln->cumul_exceptiontablelength;
1639 n_method->exceptiontable = n_ext;
1640 n_method->linenumbercount = 0;
1642 n_jd = DNEW(jitdata);
1646 if (iln->ctx->calls_others) {
1647 n_method->isleafmethod = false;
1650 n_jd->code = code_codeinfo_new(n_method);
1652 n_cd = DNEW(codegendata);
1654 memcpy(n_cd,jd->cd,sizeof(codegendata));
1655 n_cd->method = n_method;
1656 n_cd->maxstack = n_method->maxstack;
1657 n_cd->maxlocals = n_method->maxlocals;
1658 n_cd->exceptiontablelength = n_method->exceptiontablelength;
1659 n_cd->exceptiontable = n_method->exceptiontable;
1661 n_rd = DNEW(registerdata);
1665 iln->regdata = jd->rd;
1666 inline_locals(iln,n_rd);
1667 DOLOG( printf("INLINING STACK INTERFACES FOR "); method_println(iln->m) );
1668 inline_stack_interfaces(iln,n_rd);
1670 #if defined(ENABLE_VERIFIER)
1671 if (debug_verify_inlined_code) {
1672 debug_verify_inlined_code = 0;
1673 DOLOG( printf("VERIFYING INLINED RESULT...\n") );
1674 if (!typecheck(n_jd)) {
1675 *exceptionptr = NULL;
1676 DOLOG( printf("XXX INLINED RESULT DID NOT PASS VERIFIER XXX\n") );
1680 DOLOG( printf("VERIFICATION PASSED.\n") );
1682 debug_verify_inlined_code = 1;
1684 #endif /* defined(ENABLE_VERIFIER) */
1688 if (n_method->instructioncount >= inline_debug_min_size && n_method->instructioncount <= inline_debug_max_size) {
1689 if (debug_compile_inlined_code_counter >= inline_debug_start_counter
1690 && debug_compile_inlined_code_counter <= inline_debug_end_counter)
1693 (strcmp(n_method->class->name->text,"java/lang/reflect/Array") == 0 &&
1694 strcmp(n_method->name->text,"<clinit>") == 0 &&
1695 strcmp(n_method->descriptor->text,"()V") == 0)
1697 (strcmp(n_method->class->name->text,"java/lang/VMClassLoader") == 0 &&
1698 strcmp(n_method->name->text,"getSystemClassLoader") == 0 &&
1699 strcmp(n_method->descriptor->text,"()Ljava/lang/ClassLoader;") == 0)
1706 *resultmethod = n_method;
1710 inline_count_methods++;
1711 if (inline_debug_log_names)
1712 method_println(n_method);
1715 printf("==== %d.INLINE ==================================================================\n",debug_compile_inlined_code_counter);
1716 method_println(n_method);
1717 stack_show_method(jd);
1718 dump_inline_tree(iln);
1719 stack_show_method(n_jd);
1720 debug_dump_inlined_code(iln,n_method,n_cd,n_rd);
1721 printf("-------- DONE -----------------------------------------------------------\n");
1728 debug_compile_inlined_code_counter++;
1734 bool inline_inline(jitdata *jd, methodinfo **resultmethod,
1746 printf("==== INLINE ==================================================================\n");
1748 stack_show_method(jd);
1751 iln = DNEW(inline_node);
1752 memset(iln,0,sizeof(inline_node));
1754 iln->ctx = (inline_context *) DMNEW(u1,sizeof(inline_context) + sizeof(inline_stack_translation) * 1000 /* XXX */);
1755 memset(iln->ctx,0,sizeof(inline_context));
1756 iln->ctx->master = iln;
1757 iln->ctx->stacktranslationstart = iln->ctx->stacktranslation - 1;
1758 iln->ctx->calls_others = false;
1761 /* we cannot use m->instructioncount because it may be greater than
1762 * the actual number of instructions in the basic blocks. */
1763 iln->instructioncount = 0;
1764 iln->cumul_instructioncount = 0;
1766 iln->stackcount = m->stackcount;
1767 iln->cumul_stackcount = m->stackcount;
1769 if (inline_inline_intern(m,jd,iln)) {
1772 printf("==== TEST INLINE =============================================================\n");
1777 test_inlining(iln,jd,resultmethod,resultjd);
1781 printf("-------- DONE -----------------------------------------------------------\n");
1789 * These are local overrides for various environment variables in Emacs.
1790 * Please do not remove this and leave it at the end of the file, where
1791 * Emacs will automagically detect them.
1792 * ---------------------------------------------------------------------
1795 * indent-tabs-mode: t
1799 * vim:noexpandtab:sw=4:ts=4: