Authors: Andreas Krall
Reinhard Grafl
- $Id: jit.c 638 2003-11-14 23:51:34Z stefan $
+ Changes: Edwin Steiner
+
+ $Id: jit.c 923 2004-02-24 13:28:08Z edwin $
*/
#include <stdlib.h>
#include <string.h>
#include "global.h" /* we define _GNU_SOURCE there */
+#include "main.h"
#include "tables.h"
#include "loader.h"
#include "jit.h"
/* global switches ************************************************************/
-bool compileverbose = false;
-bool showstack = false;
-bool showdisassemble = false;
-bool showddatasegment = false;
-bool showintermediate = false;
-int optimizelevel = 0;
-
-bool useinlining = false;
-bool inlinevirtuals = false;
-bool inlineexceptions = false;
-bool inlineparamopt = false;
-bool inlineoutsiders = false;
-
-bool checkbounds = true;
-bool checknull = true;
-bool opt_noieee = false;
-bool checksync = true;
-bool opt_loops = false;
-
-bool getcompilingtime = false;
-long compilingtime = 0;
-
-int has_ext_instr_set = 0;
-
-bool statistics = false;
int count_jit_calls = 0;
int count_methods = 0;
basicblock *last_block; /* points to the end of the BB list */
+bool regs_ok; /* true if registers have been allocated */
+
/* list of all classes used by the compiled method which have to be */
/* initialised (if not already done) before execution of this method */
chain *uninitializedclasses;
int stackreq[256];
+
+#if defined(__I386__)
+/* these define if a method has ICMDs which use %edx or %ecx */
+bool method_uses_ecx;
+bool method_uses_edx;
+#endif
+
int jcommandsize[256] = {
#if defined(USEBUILTINTABLE)
+#if 0
stdopdescriptor builtintable[] = {
{ ICMD_LCMP, TYPE_LONG, TYPE_LONG, TYPE_INT, ICMD_BUILTIN2,
(functionptr) builtin_lcmp , SUPPORT_LONG && SUPPORT_LONG_CMP, false },
(functionptr) builtin_lneg, SUPPORT_LONG && SUPPORT_LONG_ADD, true },
{ ICMD_LMUL, TYPE_LONG, TYPE_LONG, TYPE_LONG, ICMD_BUILTIN2,
(functionptr) builtin_lmul , SUPPORT_LONG && SUPPORT_LONG_MUL, false },
- { ICMD_FREM, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, ICMD_BUILTIN2,
- (functionptr) builtin_frem, SUPPORT_FLOAT && SUPPORT_FMOD, true },
- { ICMD_DREM, TYPE_DOUBLE, TYPE_DOUBLE, TYPE_DOUBLE, ICMD_BUILTIN2,
- (functionptr) builtin_drem, SUPPORT_DOUBLE && SUPPORT_FMOD, true },
{ ICMD_I2F, TYPE_INT, TYPE_VOID, TYPE_FLOAT, ICMD_BUILTIN1,
(functionptr) builtin_i2f, SUPPORT_FLOAT && SUPPORT_IFCVT, true },
{ ICMD_I2D, TYPE_INT, TYPE_VOID, TYPE_DOUBLE, ICMD_BUILTIN1,
{ 255, 0, 0, 0, 0, NULL, true, false },
};
+#endif
+
+static int builtintablelen;
+
#endif /* USEBUILTINTABLE */
+/*****************************************************************************
+ TABLE OF BUILTIN FUNCTIONS
+
+ This table lists the builtin functions which are used inside
+ BUILTIN* opcodes.
+
+ The first part of the table (up to the 255-marker) lists the
+ opcodes which are automatically replaced in stack.c.
+
+ The second part lists the builtin functions which are "manually"
+ used for BUILTIN* opcodes in parse.c and stack.c.
+
+*****************************************************************************/
+
+builtin_descriptor builtin_desc[] = {
+#if defined(USEBUILTINTABLE)
+ {ICMD_LCMP , BUILTIN_lcmp ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_INT ,
+ SUPPORT_LONG && SUPPORT_LONG_CMP,false,"lcmp"},
+
+ {ICMD_LAND , BUILTIN_land ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_LOG,false,"land"},
+ {ICMD_LOR , BUILTIN_lor ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_LOG,false,"lor"},
+ {ICMD_LXOR , BUILTIN_lxor ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_LOG,false,"lxor"},
+
+ {ICMD_LSHL , BUILTIN_lshl ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_INT ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_SHIFT,false,"lshl"},
+ {ICMD_LSHR , BUILTIN_lshr ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_INT ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_SHIFT,false,"lshr"},
+ {ICMD_LUSHR, BUILTIN_lushr,ICMD_BUILTIN2,TYPE_LONG ,TYPE_INT ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_SHIFT,false,"lushr"},
+
+ {ICMD_LADD , BUILTIN_ladd ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_ADD,false,"ladd"},
+ {ICMD_LSUB , BUILTIN_lsub ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_ADD,false,"lsub"},
+ {ICMD_LNEG , BUILTIN_lneg ,ICMD_BUILTIN1,TYPE_LONG ,TYPE_VOID ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_ADD,false,"lneg"},
+ {ICMD_LMUL , BUILTIN_lmul ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_LONG && SUPPORT_LONG_MUL,false,"lmul"},
+
+ {ICMD_I2F , BUILTIN_i2f ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_FLOAT ,
+ SUPPORT_FLOAT && SUPPORT_IFCVT,true ,"i2f"},
+ {ICMD_I2D , BUILTIN_i2d ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_DOUBLE,
+ SUPPORT_DOUBLE && SUPPORT_IFCVT,true ,"i2d"},
+ {ICMD_L2F , BUILTIN_l2f ,ICMD_BUILTIN1,TYPE_LONG ,TYPE_VOID ,TYPE_VOID ,TYPE_FLOAT ,
+ SUPPORT_LONG && SUPPORT_FLOAT && SUPPORT_LONG_FCVT,true ,"l2f"},
+ {ICMD_L2D , BUILTIN_l2d ,ICMD_BUILTIN1,TYPE_LONG ,TYPE_VOID ,TYPE_VOID ,TYPE_DOUBLE,
+ SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_LONG_FCVT,true ,"l2d"},
+ {ICMD_F2L , BUILTIN_f2l ,ICMD_BUILTIN1,TYPE_FLOAT ,TYPE_VOID ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_LONG_ICVT,true ,"f2l"},
+ {ICMD_D2L , BUILTIN_d2l ,ICMD_BUILTIN1,TYPE_DOUBLE,TYPE_VOID ,TYPE_VOID ,TYPE_LONG ,
+ SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_LONG_ICVT,true ,"d2l"},
+ {ICMD_F2I , BUILTIN_f2i ,ICMD_BUILTIN1,TYPE_FLOAT ,TYPE_VOID ,TYPE_VOID ,TYPE_INT ,
+ SUPPORT_FLOAT && SUPPORT_FICVT,true ,"f2i"},
+ {ICMD_D2I , BUILTIN_d2i ,ICMD_BUILTIN1,TYPE_DOUBLE,TYPE_VOID ,TYPE_VOID ,TYPE_INT ,
+ SUPPORT_DOUBLE && SUPPORT_FICVT,true ,"d2i"},
+#endif
+
+ /* this record marks the end of the automatically replaced opcodes */
+ {255,NULL,0,0,0,0,0,0,0,"<INVALID>"},
+
+ /* the following functions are not replaced automatically */
+
+#if defined(__ALPHA__)
+ {255, BUILTIN_f2l ,ICMD_BUILTIN1,TYPE_FLOAT ,TYPE_VOID ,TYPE_VOID ,TYPE_LONG ,0,0,"f2l"},
+ {255, BUILTIN_d2l ,ICMD_BUILTIN1,TYPE_DOUBLE,TYPE_VOID ,TYPE_VOID ,TYPE_LONG ,0,0,"d2l"},
+ {255, BUILTIN_f2i ,ICMD_BUILTIN1,TYPE_FLOAT ,TYPE_VOID ,TYPE_VOID ,TYPE_INT ,0,0,"f2i"},
+ {255, BUILTIN_d2i ,ICMD_BUILTIN1,TYPE_DOUBLE,TYPE_VOID ,TYPE_VOID ,TYPE_INT ,0,0,"d2i"},
+#endif
+
+ {255,BUILTIN_instanceof ,ICMD_BUILTIN2,TYPE_ADR ,TYPE_ADR ,TYPE_VOID ,TYPE_INT ,0,0,"instanceof"},
+ {255,BUILTIN_arrayinstanceof ,ICMD_BUILTIN2,TYPE_ADR ,TYPE_ADR ,TYPE_VOID ,TYPE_INT ,0,0,"arrayinstanceof"},
+ {255,BUILTIN_checkarraycast ,ICMD_BUILTIN2,TYPE_ADR ,TYPE_ADR ,TYPE_VOID ,TYPE_VOID ,0,0,"checkarraycast"},
+ {255,BUILTIN_aastore ,ICMD_BUILTIN3,TYPE_ADR ,TYPE_INT ,TYPE_ADR ,TYPE_VOID ,0,0,"aastore"},
+ {255,BUILTIN_new ,ICMD_BUILTIN1,TYPE_ADR ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"new"},
+ {255,BUILTIN_newarray ,ICMD_BUILTIN2,TYPE_INT ,TYPE_ADR ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray"},
+ {255,BUILTIN_newarray_boolean,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_boolean"},
+ {255,BUILTIN_newarray_char ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_char"},
+ {255,BUILTIN_newarray_float ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_float"},
+ {255,BUILTIN_newarray_double ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_double"},
+ {255,BUILTIN_newarray_byte ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_byte"},
+ {255,BUILTIN_newarray_short ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_short"},
+ {255,BUILTIN_newarray_int ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_int"},
+ {255,BUILTIN_newarray_long ,ICMD_BUILTIN1,TYPE_INT ,TYPE_VOID ,TYPE_VOID ,TYPE_ADR ,0,0,"newarray_long"},
+ {255,BUILTIN_monitorenter ,ICMD_BUILTIN1,TYPE_ADR ,TYPE_VOID ,TYPE_VOID ,TYPE_VOID ,0,0,"monitorenter"},
+ {255,BUILTIN_monitorexit ,ICMD_BUILTIN1,TYPE_ADR ,TYPE_VOID ,TYPE_VOID ,TYPE_VOID ,0,0,"monitorexit"},
+#if !SUPPORT_DIVISION
+ {255,BUILTIN_idiv ,ICMD_BUILTIN2,TYPE_INT ,TYPE_INT ,TYPE_VOID ,TYPE_INT ,0,0,"idiv"},
+ {255,BUILTIN_irem ,ICMD_BUILTIN2,TYPE_INT ,TYPE_INT ,TYPE_VOID ,TYPE_INT ,0,0,"irem"},
+#endif
+#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV)
+ {255,BUILTIN_ldiv ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,0,0,"ldiv"},
+ {255,BUILTIN_lrem ,ICMD_BUILTIN2,TYPE_LONG ,TYPE_LONG ,TYPE_VOID ,TYPE_LONG ,0,0,"lrem"},
+#endif
+ {255,BUILTIN_frem ,ICMD_BUILTIN2,TYPE_FLOAT ,TYPE_FLOAT ,TYPE_VOID ,TYPE_FLOAT ,0,0,"frem"},
+ {255,BUILTIN_drem ,ICMD_BUILTIN2,TYPE_DOUBLE,TYPE_DOUBLE,TYPE_VOID ,TYPE_DOUBLE,0,0,"drem"},
+
+ /* this record marks the end of the list */
+ { 0,NULL,0,0,0,0,0,0,0,"<END>"}
+};
+
/* include compiler subsystems ************************************************/
/* from codegen.inc */
*******************************************************************************/
+#if 0
+#define LOG_STEP(step) \
+ if (compileverbose) { \
+ char logtext[MAXLOGTEXT]; \
+ sprintf(logtext, "%s: ",step); \
+ utf_sprint(logtext+strlen(logtext), m->class->name); \
+ strcpy(logtext+strlen(logtext), "."); \
+ utf_sprint(logtext+strlen(logtext), m->name); \
+ utf_sprint(logtext+strlen(logtext), m->descriptor); \
+ log_text(logtext); \
+ }
+#else
+#define LOG_STEP(step)
+#endif
+
methodptr jit_compile(methodinfo *m)
{
- int dumpsize;
- long starttime = 0;
- long stoptime = 0;
+ s4 dumpsize;
+ s8 starttime = 0;
+ s8 stoptime = 0;
count_jit_calls++;
count_methods++;
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ pthread_mutex_lock(&compiler_mutex);
+#endif
+
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsDisable(); /* disable interrupts */
-
+#endif
/* mark start of dump memory area */
/* if there is no javacode print error message and return empty method */
if (!m->jcode) {
+ char logtext[MAXLOGTEXT];
sprintf(logtext, "No code given for: ");
utf_sprint(logtext+strlen(logtext), m->class->name);
strcpy(logtext+strlen(logtext), ".");
utf_sprint(logtext+strlen(logtext), m->name);
utf_sprint(logtext+strlen(logtext), m->descriptor);
- dolog();
+ log_text(logtext);
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsRestore(); /* enable interrupts again */
+#endif
return (methodptr) do_nothing_function; /* return empty method */
}
/* print log message for compiled method */
if (compileverbose) {
+ char logtext[MAXLOGTEXT];
sprintf(logtext, "Compiling: ");
utf_sprint(logtext+strlen(logtext), m->class->name);
strcpy(logtext+strlen(logtext), ".");
utf_sprint(logtext+strlen(logtext), m->name);
utf_sprint(logtext+strlen(logtext), m->descriptor);
- dolog();
+ log_text(logtext);
}
+ /* initialize the static function's class */
+ if (m->flags & ACC_STATIC && !m->class->initialized) {
+ if (initverbose) {
+ char logtext[MAXLOGTEXT];
+ sprintf(logtext, "Initialize class ");
+ utf_sprint(logtext + strlen(logtext), m->class->name);
+ log_text(logtext);
+ }
+ class_init(m->class);
+ }
/* initialisation of variables and subsystems */
jcode = m->jcode;
exceptiontablelength = m->exceptiontablelength;
raw_extable = m->exceptiontable;
+ regs_ok = false;
#ifdef STATISTICS
count_tryblocks += exceptiontablelength;
mparamcount = m->paramcount;
mparamtypes = m->paramtypes;
- /* initialize class list with class the compiled method belongs to */
-
- uninitializedclasses = chain_new();
- compiler_addinitclass(m->class);
-
+#if defined(__I386__)
+ method_uses_ecx = true;
+ method_uses_edx = false;
+#endif
/* call the compiler passes ***********************************************/
- /* must be call before reg_init, because it can change maxlocals */
+ /* must be called before reg_init, because it can change maxlocals */
if (useinlining)
inlining_init(m);
- reg_init(m);
+ reg_setup();
codegen_init();
parse();
analyse_stack();
+#ifdef CACAO_TYPECHECK
+ if (opt_verify) {
+ LOG_STEP("Typechecking");
+ typecheck();
+ LOG_STEP("Done typechecking");
+ }
+#endif
+
if (opt_loops) {
depthFirst();
analyseGraph();
preregpass();
#endif
+ LOG_STEP("Regalloc");
regalloc();
+ regs_ok = true;
+
+ LOG_STEP("Codegen");
codegen();
/* intermediate and assembly code listings ********************************/
if (getcompilingtime) {
stoptime = getcputime();
- compilingtime += (stoptime-starttime);
- }
-
- /* initialize all used classes */
- /* because of reentrant code global variables are not allowed here */
-
- {
- chain *ul = uninitializedclasses; /* list of uninitialized classes */
- classinfo *c; /* single class */
-
- while ((c = chain_first(ul)) != NULL) {
- chain_remove(ul);
- class_init(c); /* may again call the compiler */
- }
- chain_free(ul);
+ compilingtime += (stoptime - starttime);
}
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsRestore(); /* enable interrupts again */
+#endif
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ pthread_mutex_unlock(&compiler_mutex);
+#endif
/* return pointer to the methods entry point */
+ LOG_STEP("Done compiling");
return m->entrypoint;
}
static int stdopcompare(const void *a, const void *b)
{
- stdopdescriptor *o1 = (stdopdescriptor *) a;
- stdopdescriptor *o2 = (stdopdescriptor *) b;
+ builtin_descriptor *o1 = (builtin_descriptor *) a;
+ builtin_descriptor *o2 = (builtin_descriptor *) b;
+ if (!o1->supported && o2->supported)
+ return -1;
+ if (o1->supported && !o2->supported)
+ return 1;
return (o1->opcode < o2->opcode) ? -1 : (o1->opcode > o2->opcode);
}
-
static inline void sort_builtintable()
{
int len;
- len = sizeof(builtintable) / sizeof(stdopdescriptor);
- qsort(builtintable, len, sizeof(stdopdescriptor), stdopcompare);
+ len = 0;
+ while (builtin_desc[len].opcode != 255) len++;
+ qsort(builtin_desc, len, sizeof(builtin_descriptor), stdopcompare);
-#if 0
- {
- int i;
- for (i=0; i<len; i++)
- if (!builtintable[i].supported)
- printf("%s\n", icmd_names[builtintable[i].opcode]);
- }
-#endif
+ for (--len; len>=0 && builtin_desc[len].supported; len--);
+ builtintablelen = ++len;
}
-stdopdescriptor *find_builtin(int icmd)
+builtin_descriptor *find_builtin(int icmd)
{
- stdopdescriptor *first = builtintable;
- stdopdescriptor *last = builtintable + sizeof(builtintable) / sizeof(stdopdescriptor);
+ builtin_descriptor *first = builtin_desc;
+ builtin_descriptor *last = builtin_desc + builtintablelen;
int len = last - first;
int half;
- stdopdescriptor *middle;
+ builtin_descriptor *middle;
while (len > 0) {
half = len / 2;
} else
len = half;
}
- return first;
+ return first != last ? first : NULL;
}
#endif
stackreq[JAVA_DUP_X2] = 4;
stackreq[JAVA_DUP2_X1] = 3;
stackreq[JAVA_DUP2_X2] = 4;
-
+
+ reg_init();
init_exceptions();
}