Authors: Andreas Krall
Reinhard Grafl
- $Id: jit.c 624 2003-11-13 14:06:52Z twisti $
+ Changes: Edwin Steiner
+
+ $Id: jit.c 789 2003-12-16 14:46:55Z edwin $
*/
/* 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;
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,
{ ICMD_L2D, TYPE_LONG, TYPE_VOID, TYPE_DOUBLE, ICMD_BUILTIN1,
(functionptr) builtin_l2d, SUPPORT_LONG && SUPPORT_DOUBLE && SUPPORT_LONG_FCVT, true },
{ ICMD_F2L, TYPE_FLOAT, TYPE_VOID, TYPE_LONG, ICMD_BUILTIN1,
- (functionptr) builtin_f2l, SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_LONG_FCVT, true },
+ (functionptr) builtin_f2l, SUPPORT_FLOAT && SUPPORT_LONG && SUPPORT_LONG_ICVT, true },
{ ICMD_D2L, TYPE_DOUBLE, TYPE_VOID, TYPE_LONG, ICMD_BUILTIN1,
- (functionptr) builtin_d2l, SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_LONG_FCVT, true },
+ (functionptr) builtin_d2l, SUPPORT_DOUBLE && SUPPORT_LONG && SUPPORT_LONG_ICVT, true },
{ ICMD_F2I, TYPE_FLOAT, TYPE_VOID, TYPE_INT, ICMD_BUILTIN1,
(functionptr) builtin_f2i, SUPPORT_FLOAT && SUPPORT_FICVT, true },
{ ICMD_D2I, TYPE_DOUBLE, TYPE_VOID, TYPE_INT, ICMD_BUILTIN1,
(functionptr) builtin_d2i, SUPPORT_DOUBLE && SUPPORT_FICVT, true },
-/* { 0, 0, 0, 0, 0, NULL, false, false }, */
+ { 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 ,
+ true ,false,"<INVALID>"},
+
+#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
+
+ /* the following functions are not replaced automatically */
+ {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_BUILTIN1,TYPE_ADR ,TYPE_VOID ,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 */
count_methods++;
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ pthread_mutex_lock(&compiler_mutex);
+#endif
+
intsDisable(); /* disable interrupts */
-
+
+ regs_ok = false;
/* 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);
intsRestore(); /* enable interrupts again */
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 class list with class the compiled method belongs to */
- uninitializedclasses = chain_new();
+ 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
+ /* print log message for compiled method */
+
+ if (compileverbose) {
+ char logtext[MAXLOGTEXT];
+ sprintf(logtext, "Typechecking: ");
+ 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);
+ }
+
+ typecheck();
+
+ if (compileverbose) {
+ dolog("Typechecking done.");
+ }
+#endif
+
if (opt_loops) {
depthFirst();
analyseGraph();
#endif
regalloc();
+ regs_ok = true;
codegen();
/* intermediate and assembly code listings ********************************/
if (getcompilingtime) {
stoptime = getcputime();
- compilingtime += (stoptime-starttime);
+ compilingtime += (stoptime - starttime);
}
/* initialize all used classes */
intsRestore(); /* enable interrupts again */
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ pthread_mutex_unlock(&compiler_mutex);
+#endif
+
/* return pointer to the methods entry point */
return m->entrypoint;
#ifdef USEBUILTINTABLE
+/* XXX delete */
+#if 0
static int stdopcompare(const void *a, const void *b)
{
stdopdescriptor *o1 = (stdopdescriptor *) a;
stdopdescriptor *o2 = (stdopdescriptor *) 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);
+}
+#endif
+static int stdopcompare(const void *a, const void *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);
}
-
+/* XXX delete */
+#if 0
static inline void sort_builtintable()
{
int len;
len = sizeof(builtintable) / sizeof(stdopdescriptor);
- qsort(builtintable, len, sizeof(stdopdescriptor), stdopcompare);
+ qsort(builtintable, len, sizeof(builtin_descriptor), stdopcompare);
+
+ for (--len; len>=0 && builtintable[len].supported; len--);
+ builtintablelen = ++len;
+
+#if 0
+ {
+ int i;
+ for (i=0; i<len; i++)
+ if (!builtintable[i].supported)
+ printf("%s\n", icmd_names[builtintable[i].opcode]);
+ }
+#endif
+}
+#endif
+
+static inline void sort_builtintable()
+{
+ int len;
+
+ len = 0;
+ while (builtin_desc[len].opcode != 255) len++;
+ qsort(builtin_desc, len, sizeof(builtin_descriptor), stdopcompare);
+
+ for (--len; len>=0 && builtin_desc[len].supported; len--);
+ builtintablelen = ++len;
}
+#if 0
stdopdescriptor *find_builtin(int icmd)
{
- stdopdescriptor *first = builtintable;
- stdopdescriptor *last = builtintable + sizeof(builtintable) / sizeof(stdopdescriptor);
+ builtin_descriptor *first = builtintable;
+ builtin_descriptor *last = builtintable + builtintablelen;
+#endif
+builtin_descriptor *find_builtin(int icmd)
+{
+ 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();
}