home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / kaffe-0.5p4-src.tgz / tar.out / contrib / kaffe / kaffevm / jit / machine.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  552 lines

  1. /* machine.c
  2.  * Translate the Kaffe instruction set to the native one.
  3.  *
  4.  * Copyright (c) 1996 Systems Architecture Research Centre,
  5.  *           City University, London, UK.
  6.  *
  7.  * See the file "license.terms" for information on usage and redistribution
  8.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  9.  *
  10.  * Written by Tim Wilkinson <tim@sarc.city.ac.uk>, June 1996.
  11.  */
  12.  
  13. #define    DBG(s)
  14. #define    BDBG(s)
  15. #define    MDBG(s)
  16.  
  17. #include <stdio.h>
  18. #include <assert.h>
  19. #include <stdlib.h>
  20. #include "gtypes.h"
  21. #include "bytecode.h"
  22. #include "slots.h"
  23. #include "registers.h"
  24. #include "seq.h"
  25. #include "machine.h"
  26. #include "basecode.h"
  27. #include "icode.h"
  28. #include "labels.h"
  29. #include "codeinfo.h"
  30. #include "codeproto.h"
  31. #include "checks.h"
  32. #include "access.h"
  33. #include "object.h"
  34. #include "constants.h"
  35. #include "baseClasses.h"
  36. #include "classMethod.h"
  37. #include "access.h"
  38. #include "lookup.h"
  39. #include "exception.h"
  40. #include "ops.h"
  41. #include "gc.h"
  42. #include "flags.h"
  43. #include "md.h"
  44.  
  45. int code_size;
  46. codes* code;
  47.  
  48. int stackno;
  49. int maxStack;
  50. int maxLocal;
  51. int maxTemp;
  52. int maxArgs;
  53. int isStatic;
  54. callInfo cinfo;
  55. fieldInfo flinfo;
  56. createInfo crinfo;
  57.  
  58. /* Fix to so we can reuse libraries without change */
  59. slots retarg;
  60.  
  61. int tmpslot = 0;
  62. int argcount = 0;        /* Function call argument count */
  63. uint32 pc;
  64. uint32 npc;
  65.  
  66. /* Unit in which code block is increased when overrun */
  67. #define    ALLOCCODEBLOCKSZ    8192
  68. /* Codeblock redzone - allows for safe overrun when generating instructions */
  69. #define    CODEBLOCKREDZONE    256
  70.  
  71. static nativecode* codeblock;
  72. static int codeblock_size;
  73.  
  74. nativecode* CODEPC;
  75. uintp realcodediff;
  76.  
  77. static void    findBlocks(methods*, uint32, int);
  78. static void    generateCode(methods*);
  79.  
  80. void    endBlock(sequence*);
  81. void    startBlock(sequence*);
  82.  
  83. /*
  84.  * Translate a method into native code.
  85.  */
  86. void
  87. translate(methods* meth)
  88. {
  89.     uint32 wide;
  90.     int i;
  91.  
  92.     jint low;
  93.     jint high;
  94.     int idx;
  95.     slots* cnst;
  96.     slots* tmp;
  97.     slots* tmp2;
  98.     slots* mtable;
  99.  
  100.     bytecode* base;
  101.     int len;
  102.  
  103. DBG(    printf("callinfo = 0x%x\n", &cinfo);    )
  104.  
  105.     /* If this code block is native, then just set it up and return */
  106.     if ((meth->accflags & ACC_NATIVE) != 0) {
  107.         native(meth);
  108.         return;
  109.     }
  110.  
  111.     maxLocal = meth->localsz;
  112.     maxStack = meth->stacksz;
  113.     maxArgs = meth->ins;
  114.     if (meth->accflags & ACC_STATIC) {
  115.         isStatic = 1;
  116.     }
  117.     else {
  118.         isStatic = 0;
  119.         maxArgs += 1;
  120.     }
  121.  
  122.     base = (bytecode*)meth->code;
  123.     len = meth->codelen;
  124.  
  125.     /* Make sure we have enough code space */
  126.     if (len+1 > code_size) {
  127.         if (code != 0) {
  128.             free(code);
  129.         }
  130.         code = calloc(sizeof(codes), len+1);
  131.         assert(code != 0);
  132.         code_size = len+1;
  133.     }
  134.  
  135.     /* Set locals, stack and temps */
  136.     assert(maxLocal + maxStack < MAXSLOT);
  137.     localinfo = &slotinfo[0];
  138.     stackinfo = &localinfo[maxLocal];
  139.     tempinfo = &stackinfo[maxStack];
  140.  
  141.     initSeq();
  142.     initRegisters();
  143.     initSlots();
  144.  
  145.     /* Traverse code block to mark branch and join points */
  146.     for (i = 0; i < len; i++) {
  147.         code[i].block = 0;
  148.         code[i].stackdepth = -1;
  149.         code[i].pc = (uintp)-1;
  150.     }
  151.     stackval(len) = MAXSLOT;
  152.  
  153.     /* Scan the code and determine the basic blocks */
  154.  
  155.     /* First the main body of code. */
  156.     findBlocks(meth, 0, 0);
  157.  
  158.     /* Then the exception handlers */
  159.     for (i = 0; i < meth->exception_table_len; i++) {
  160.         findBlocks(meth, meth->exception_table[i].handler_pc, 1);
  161.         BLOCKPOINT(meth->exception_table[i].handler_pc) |= IEBSTART;
  162.     }
  163.  
  164.     /* Clear temporary counter */
  165.     maxTemp = 0;
  166.  
  167.     /* Next reduce bytecode to native code */
  168.     start_function();
  169.     monitor_enter();
  170.  
  171.     npc = 0;
  172.     wide = 0;
  173.     start_basic_block();
  174.     for (pc = 0; pc < len; pc = npc) {
  175.  
  176.         /* If this is -1 then this code was unreachable - skip it */
  177.         if (stackval(pc) == -1) {
  178.             npc = pc + 1;
  179.             continue;
  180.         }
  181.  
  182.         /* Retrieve stack for new instruction and next instruction
  183.          * pointer.
  184.          */
  185.         stackno = meth->stacksz - stackval(pc);
  186.  
  187.         assert(stackno >= 0);
  188.         assert(stackno <= meth->stacksz);
  189.  
  190.         npc = pc + opcodeInfo[base[pc]].len;
  191.  
  192.         /* Note start of exception handling blocks */
  193.         if (BLOCKPOINT(pc) & IEBSTART) {
  194.             start_exception_block();
  195.         }
  196.  
  197.         start_instruction();
  198.         switch (base[pc]) {
  199.         default:
  200.             fprintf(stderr, "Unknown bytecode %d\n", base[pc]);
  201.             abort();
  202. #include "kaffe.def"
  203.         }
  204.  
  205.         /* Note maximum number of temp slots used and reset it */
  206.         if (tmpslot > maxTemp) {
  207.             maxTemp = tmpslot;
  208.         }
  209.         tmpslot = 0;
  210.  
  211.         if (BLOCKPOINT(npc) & IBBSTART) {
  212.             end_basic_block();
  213.             start_basic_block();
  214.         }
  215.     }
  216.  
  217.     assert(maxLocal + maxStack + maxTemp < MAXSLOT);
  218.  
  219.     /* Generate and link code */
  220.     generateCode(meth);
  221.     establishMethod(meth);
  222.  
  223. MDBG(    printf("Translating %s.%s%s (%s) 0x%x\n", meth->class->name, meth->pair->s1, meth->pair->s2, isStatic ? "static" : "normal", meth->ncode);    )
  224. }
  225.  
  226. /*
  227.  * Analyse code to work out basic blocks and stack depths.
  228.  */
  229. static
  230. void
  231. findBlocks(methods* meth, uint32 pc, int stk)
  232. {
  233.     uint32 destpc;
  234.     uint32 tabpc;
  235.     uint32 idx;
  236.     uint32 low;
  237.     uint32 high;
  238.     bytecode* base;
  239.  
  240.     base = (bytecode*)meth->code;
  241.  
  242.     /* Mark start of basic block */
  243.     BLOCKPOINT(pc) = IBBSTART;
  244.  
  245.     while (stackval(pc) == -1) {
  246.         assert(stk >= 0 && stk <= meth->stacksz);
  247.         stackval(pc) = stk;
  248.  
  249.         if (opcodeInfo[base[pc]].stack == 9) {
  250.             idx = (base[pc+1] << 8)|base[pc+2];
  251.  
  252.             /* Variable length ones */
  253.             switch (base[pc]) {
  254.             case INVOKEVIRTUAL:
  255.             case INVOKENONVIRTUAL:
  256.             case INVOKEINTERFACE:
  257.                 getMethodSignatureClass(idx, meth->constants, &cinfo);
  258.                 stk -= cinfo.in + 1;
  259.                 stk += cinfo.out;
  260.                 break;
  261.  
  262.             case INVOKESTATIC:
  263.                 idx = (base[pc+1] << 8)|base[pc+2];
  264.                 getMethodSignatureClass(idx, meth->constants, &cinfo);
  265.                 stk -= cinfo.in;
  266.                 stk += cinfo.out;
  267.                 break;
  268.  
  269.             case GETFIELD:
  270.                 getField(idx, false, meth->constants, &flinfo);
  271.                 stk += flinfo.size - 1;
  272.                 break;
  273.  
  274.             case PUTFIELD:
  275.                 getField(idx, false, meth->constants, &flinfo);
  276.                 stk -= flinfo.size + 1;
  277.                 break;
  278.  
  279.             case GETSTATIC:
  280.                 getField(idx, true, meth->constants, &flinfo);
  281.                 stk += flinfo.size;
  282.                 break;
  283.  
  284.             case PUTSTATIC:
  285.                 getField(idx, true, meth->constants, &flinfo);
  286.                 stk -= flinfo.size;
  287.                 break;
  288.  
  289.             case MULTIANEWARRAY:
  290.                 stk -= (uint8)base[pc+3] - 1;
  291.                 break;
  292.  
  293.             default:
  294.                 abort();
  295.             }
  296.         }
  297.         else {
  298.             stk += opcodeInfo[base[pc]].stack;
  299.         }
  300.  
  301.         switch (opcodeInfo[base[pc]].jmp) {
  302.         case 1:
  303.             switch (opcodeInfo[base[pc]].len) {
  304.             case 3:
  305.                 destpc = pc + (int16)
  306.                     (base[pc+1] * 0x00000100 +
  307.                      base[pc+2] * 0x00000001);
  308.                 findBlocks(meth, destpc, stk);
  309.                 break;
  310.             case 5:
  311.                 destpc = pc + (int32)
  312.                     (base[pc+1] * 0x01000000 +
  313.                      base[pc+2] * 0x00010000 +
  314.                      base[pc+3] * 0x00000100 +
  315.                      base[pc+4] * 0x00000001);
  316.                 findBlocks(meth, destpc, stk);
  317.                 break;
  318.             default:
  319.                 abort();
  320.                 break;
  321.             }
  322.             pc += opcodeInfo[base[pc]].len;
  323.             /* Mark start of basic block */
  324.             BLOCKPOINT(pc) = IBBSTART;
  325.             break;
  326.  
  327.         case 2: /* Returns */
  328.             return;
  329.  
  330.         case 3: /* Gotos */
  331.             switch (opcodeInfo[base[pc]].len) {
  332.             case 3:
  333.                 pc = pc + (int16)
  334.                     (base[pc+1] * 0x00000100 +
  335.                      base[pc+2] * 0x00000001);
  336.                 break;
  337.             case 5:
  338.                 pc = pc + (int32)
  339.                     (base[pc+1] * 0x01000000 +
  340.                      base[pc+2] * 0x00010000 +
  341.                      base[pc+3] * 0x00000100 +
  342.                      base[pc+4] * 0x00000001);
  343.                 break;
  344.             case 0:
  345.                 /* Table and Switch */
  346.                 tabpc = pc + 4 - (pc % 4);
  347.                 if (base[pc] == LOOKUPSWITCH) {
  348.                     idx = (uint32)
  349.                           (base[tabpc+4] * 0x01000000 +
  350.                            base[tabpc+5] * 0x00010000 +
  351.                            base[tabpc+6] * 0x00000100 +
  352.                            base[tabpc+7] * 0x00000001);
  353.                     for (; idx > 0; idx--) {
  354.                         destpc = pc + (int32)
  355.                         (base[tabpc+idx*8+4] * 0x01000000 +
  356.                              base[tabpc+idx*8+5] * 0x00010000 +
  357.                          base[tabpc+idx*8+6] * 0x00000100 +
  358.                          base[tabpc+idx*8+7] * 0x00000001);
  359.                         findBlocks(meth, destpc, stk);
  360.                     }
  361.                     pc = pc + (int32)
  362.                     (base[tabpc+0] * 0x01000000 +
  363.                      base[tabpc+1] * 0x00010000 +
  364.                      base[tabpc+2] * 0x00000100 +
  365.                      base[tabpc+3] * 0x00000001);
  366.                 }
  367.                 else {
  368.                     assert(base[pc] == TABLESWITCH);
  369.                     low = (uint32)
  370.                           (base[tabpc+4] * 0x01000000 +
  371.                            base[tabpc+5] * 0x00010000 +
  372.                            base[tabpc+6] * 0x00000100 +
  373.                            base[tabpc+7] * 0x00000001);
  374.                     high = (uint32)
  375.                           (base[tabpc+8] * 0x01000000 +
  376.                            base[tabpc+9] * 0x00010000 +
  377.                            base[tabpc+10] * 0x00000100 +
  378.                            base[tabpc+11] * 0x00000001);
  379.                     for (idx = 0; idx < high-low+1; idx++) {
  380.                         destpc = pc + (int32)
  381.                         (base[tabpc+idx*4+12] * 0x01000000 +
  382.                              base[tabpc+idx*4+13] * 0x00010000 +
  383.                          base[tabpc+idx*4+14] * 0x00000100 +
  384.                          base[tabpc+idx*4+15] * 0x00000001);
  385.                         findBlocks(meth, destpc, stk);
  386.                     }
  387.                     pc = pc + (int32)
  388.                     (base[tabpc+0] * 0x01000000 +
  389.                      base[tabpc+1] * 0x00010000 +
  390.                      base[tabpc+2] * 0x00000100 +
  391.                      base[tabpc+3] * 0x00000001);
  392.                 }
  393.                 break;
  394.             }
  395.             /* Mark start of basic block */
  396.             BLOCKPOINT(pc) = IBBSTART;
  397.             break;
  398.  
  399.         case 0:
  400.             pc += opcodeInfo[base[pc]].len;
  401.             break;
  402.         default:
  403.             abort();
  404.             break;
  405.         }
  406.     }
  407.     if (stk != stackval(pc) && stackval(pc) != MAXSLOT) {
  408.         fprintf(stderr, "Stack depths wrong at %d (code=0x%x)\n", pc, &code);
  409.         abort();
  410.     }
  411. }
  412.  
  413. /*
  414.  * Generate the code.
  415.  */
  416. static
  417. void
  418. generateCode(methods* meth)
  419. {
  420.     sequence* t;
  421.     uint32 clen;
  422.     nativecode* realcode;
  423.     int i;
  424.     jexception* e;
  425.  
  426. DBG(    printf("codeblock = 0x%x\n", codeblock);    )
  427. DBG(    printf("slotinfo = 0x%x\n", slotinfo);        )
  428.  
  429.     restart:
  430.     CODEPC = codeblock;
  431.     for (t = firstSeq; t != currSeq; t = t->next) {
  432.  
  433.         /* If we overrun the codeblock, reallocate and restart */
  434.         if (CODEPC >= &codeblock[codeblock_size]) {
  435.             if (codeblock != 0) {
  436.                 free(codeblock);
  437.             }
  438.             codeblock_size += ALLOCCODEBLOCKSZ;
  439.             codeblock = calloc(sizeof(nativecode), codeblock_size + CODEBLOCKREDZONE);
  440.             assert(codeblock != 0);
  441.             goto restart;
  442.         }
  443.  
  444.         /* Generate sequences which are actually referenced */
  445.         if (t->ref > 0) {
  446.             (*(t->func))(t);
  447.         }
  448.     }
  449.  
  450.     /* Okay, put this into malloc'ed memory */
  451.     clen = CODEPC - codeblock;
  452.     realcode = malloc(clen);
  453.     assert(realcode != 0);
  454.     memcpy(realcode, codeblock, clen);
  455.  
  456.     /* Link it */
  457.     realcodediff = realcode - codeblock;
  458.     linkLabels();
  459.  
  460.     /* Note where it all is */
  461.     meth->ncode = realcode;
  462.     meth->ncode_end = realcode + clen;
  463.  
  464.     /* Translate exception table and make it available */
  465.     if (meth->exception_table != 0) {
  466.         for (i = 0; i < meth->exception_table_len; i++) {
  467.             e = &meth->exception_table[i];
  468.             e->start_pc = code[e->start_pc].pc + realcodediff;
  469.             e->end_pc = code[e->end_pc].pc + realcodediff;
  470.             e->handler_pc = code[e->handler_pc].pc + realcodediff;
  471.         }
  472.     }
  473. }
  474.  
  475. /*
  476.  * Start a new instruction.
  477.  */
  478. void
  479. startInsn(sequence* s)
  480. {
  481.     uintp pc;
  482.  
  483.     /* Note PC value at start of this instruction */
  484.     pc = const_int(2);
  485.     code[pc].pc = (uintp)CODEPC;
  486. }
  487.  
  488. /*
  489.  * Invalidate a specific slot to avoid writeback.
  490.  */
  491. void
  492. invalSlot(sequence* s)
  493. {
  494.     seq_slot(s, 2)->modified = 0;
  495. }
  496.  
  497. /*
  498.  * Start a new basic block.
  499.  */
  500. void
  501. startBlock(sequence* s)
  502. {
  503.     int i;
  504.  
  505.     startInsn(s);
  506.  
  507.     /* Invalidate all slots - don't use clobberRegister which will
  508.      * flush them - we do not want to do that even if they are dirty.
  509.      */
  510.     for (i = MAXSLOT - 1; i >= 0; i--) {
  511.         if (slotinfo[i].regno != NOREG) {
  512.             register_invalidate(slotinfo[i].regno);
  513.             slot_invalidate(&slotinfo[i]);
  514.         }
  515.     }
  516. BDBG(    printf("-------start-------\n");            )
  517. }
  518.  
  519. /*
  520.  * End a basic block.
  521.  */
  522. void
  523. endBlock(sequence* s)
  524. {
  525.     int stkno;
  526.     int i;
  527.  
  528.     /* Spill locals */
  529.     for (i = 0; i < maxLocal; i++) {
  530.         if ((localinfo[i].modified & rwrite) != 0 && localinfo[i].regno != NOREG) {
  531.             spill(&localinfo[i]);
  532.         }
  533.     }
  534.  
  535.     /* Spill stack */
  536.     stkno = const_int(1);
  537.     for (i = stkno; i < maxStack; i++) {
  538.         if ((stackinfo[i].modified & rwrite) != 0 && stackinfo[i].regno != NOREG) {
  539.             spill(&stackinfo[i]);
  540.         }
  541.     }
  542.  
  543.     /* Spill temps currently in use */
  544.     tmpslot = const_int(2);
  545.     for (i = 0; i < tmpslot; i++) {
  546.         if ((tempinfo[i].modified & rwrite) != 0 && tempinfo[i].regno != NOREG) {
  547.             spill(&tempinfo[i]);
  548.         }
  549.     }
  550. BDBG(    printf("-------end-------\n");            )
  551. }
  552.