📄 jit3-i386.def
字号:
/* jit3-i386.def * i386 instruction definition. * * Copyright (c) 1996, 1997 * Transvirtual Technologies, Inc. All rights reserved. * * Cross-language profiling changes contributed by * the Flux Research Group, Department of Computer Science, * University of Utah, http://www.cs.utah.edu/flux/ * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "debug.h"#include "classMethod.h"#include "md.h"#include "xprofiler.h"#if defined(TRACE_METHOD_END) && defined(__GNUC__)asm(".globl tStore\ntStore: .long 0,0");#endif#ifdef KAFFE_VMDEBUGint jit_debug;#define debug(x) (jit_debug ? dprintf("%x:\t", CODEPC), dprintf x : 0)#else#define debug(x)#endif#define do_move_int(t, f) \ if ((t) != (f)) { \ OUT = 0x89; \ OUT = 0xC0|(f<<3)|t; \ debug(("movl %s,%s\n", regname(f), regname(t)));\ }#define check_reg_01() \ { \ int _r_ = rreg_int(1); \ int _w_ = wreg_int(0); \ do_move_int(_w_, _r_); \ }#define set_slot_register(S,R,T) \ forceRegister(S, R, T)#define force_move_int(S, T, F) \ if ((T) != (F)) { \ set_slot_register(S, (T), Rint); \ do_move_int((T), (F)); \ F = (T); \ }#define safe_move_int(T, F) \ if ((T) != (F)) { \ clobberRegister(T); \ do_move_int((T), (F)); \ F = (T); \ }char* rnames[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "flt0/dbl0" };#define regname(n) rnames[n]#define REG_eax 0#define REG_ecx 1#define REG_edx 2#define REG_ebx 3#define REG_esp 4#define REG_ebp 5#define REG_esi 6#define REG_edi 7#define REG_flt0 8#define REG_dbl0 REG_flt0/* IEEE mode setup */#define IEEE_INVAL 0x0001#define IEEE_DENORM 0x0002#define IEEE_DIVZ 0x0004#define IEEE_OVERF 0x0008#define IEEE_UNDERF 0x0010#define IEEE_LOS 0x0020#define IEEE_NEAREST 0x0000#define IEEE_DOWN 0x0400#define IEEE_UP 0x0800#define IEEE_CHOP 0x0C00#define IEEE_EXTRA 0x1200#define IEEE_MODE (IEEE_DENORM|IEEE_UNDERF|IEEE_LOS|IEEE_DIVZ|IEEE_NEAREST|IEEE_EXTRA)extern bool used_ieee_division;#if defined(KAFFE_PROFILER)/* This code reads the timestamp register, and substracts it * from COUNTER. As this will scratch EDX and EAX, the second * parameter said if they must be saved. */#define profiler_start(COUNTER, SAVE_EDX_EAX) do { \ int *__counter = (int *)&(COUNTER); \ if (SAVE_EDX_EAX) { \ /* Save EAX and EDX */ \ OUT = 0x50|REG_edx; \ OUT = 0x50|REG_eax; \ debug(("pushl edx\n")); \ debug(("pushl eax\n")); \ } \ \ OUT = 0x0F; \ OUT = 0x31; \ debug(("rdtsc\n")); \ \ OUT = 0x29; \ OUT = 0x05; \ LOUT = (int)(__counter); \ debug(("sub eax, 0x%x\n", (int)(__counter))); \ \ OUT = 0x19; \ OUT = 0x15; \ LOUT = (int)(__counter + 1); \ debug(("sbb edx, 0x%x\n", (int)(__counter + 1))); \ \ if (SAVE_EDX_EAX) { \ /* Restore EAX and EDX */ \ OUT = 0x58|REG_eax; \ OUT = 0x58|REG_edx; \ debug(("popl eax\n")); \ debug(("popl edx\n")); \ } \} while(0)/* This code reads the timestamp register, and add it to COUNTER. * As this will scratch EDX and EAX, the second parameter said if * they must be saved. */#define profiler_end(COUNTER, SAVE_EDX_EAX) do { \ int *__counter = (int *)&(COUNTER); \ if (SAVE_EDX_EAX) { \ /* Save EAX and EDX */ \ OUT = 0x50|REG_edx; \ OUT = 0x50|REG_eax; \ debug(("pushl edx\n")); \ debug(("pushl eax\n")); \ } \ \ OUT = 0x0F; \ OUT = 0x31; \ debug(("rdtsc\n")); \ \ OUT = 0x01; \ OUT = 0x05; \ LOUT = (int)(__counter); \ debug(("add eax, 0x%x\n", (int)(__counter))); \ \ OUT = 0x11; \ OUT = 0x15; \ LOUT = (int)(__counter + 1); \ debug(("adc edx, 0x%x\n", (int)(__counter + 1))); \ \ if (SAVE_EDX_EAX) { \ /* Restore EAX and EDX */ \ OUT = 0x58|REG_eax; \ OUT = 0x58|REG_edx; \ debug(("popl eax\n")); \ debug(("popl edx\n")); \ } \} while(0)#endif/* --------------------------------------------------------------------- */define_insn(unimplemented, unimplemented){ ABORT();}define_insn(nop, nop){ OUT = 0x90;}/* --------------------------------------------------------------------- */define_insn(prologue, prologue_xxx){ label* l; if (profFlag) { debug(("Method: %s\n", globalMethod->name->data)); }#if defined(KAFFE_XPROFILER) if (xProfFlag) { /* Store the pointer to this function in eax */ OUT = 0xB8|REG_eax; l = (label*)newLabel(); l->type = Llong|Linternal|Labsolute; l->to = 0; l->at = (uintp)CODEPC; LOUT = 0; debug(("movl #?,eax\n")); /* Push second arg to profileArcHit */ OUT = 0x50|REG_eax; debug(("pushl eax\n")); /* Get return address from the stack */ OUT = 0x8B; OUT = (REG_eax<<3)|0x44; OUT = 0x24; OUT = 0x04; debug(("movl eax,4(esp)\n")); /* Push first arg to profileArcHit */ OUT = 0x50|REG_eax; debug(("pushl eax\n")); /* Load the address to profileArcHit */ OUT = 0xB8|REG_eax; LOUT = (int)profileArcHit; debug(("movl profileArcHit,eax\n")); /* Make the call */ OUT = 0xFF; OUT = 0xD0|REG_eax; debug(("call profileArcHit\n")); /* Pop the args off */ OUT = 0x58|REG_eax; debug(("popl eax\n")); OUT = 0x58|REG_eax; debug(("popl eax\n")); }#endif OUT = 0x50|REG_ebp; OUT = 0x89; OUT = 0xC0|(REG_esp<<3)|REG_ebp; OUT = 0x81; OUT = 0xE8|REG_esp; l = (label*)const_int(1); l->type = Lframe|Labsolute|Lgeneral; l->at = (uintp)CODEPC; LOUT = 0; OUT = 0x50|REG_edi; OUT = 0x50|REG_esi; OUT = 0x50|REG_ebx; debug(("pushl ebp\n")); debug(("movl esp,ebp\n")); debug(("subl #?,esp\n")); debug(("pushl edi\n")); debug(("pushl esi\n")); debug(("pushl ebx\n"));#if defined(KAFFE_PROFILER) if (profFlag) { profiler_start(globalMethod->totalClicks, 0); OUT = 0xFF; OUT = 0x05; LOUT = (int)&(globalMethod->callsCount); debug(("incl 0x%x\n",(int)&(globalMethod->callsCount))); }#endif#if 0 /* If this method uses IEEE, set up the mode here */ if (used_ieee_division == true) { OUT = 0x68; LOUT = 0; OUT = 0x68; LOUT = 0; debug(("pushl #0\n")); debug(("pushl #0\n")); OUT = 0xD9; OUT = 0x3C; OUT = 0x24; debug(("fnstcw (esp)\n")); OUT = 0x8B; OUT = (REG_eax<<3)|0x04; OUT = 0x24; debug(("movl (esp),eax\n")); OUT = 0xB8|REG_eax; LOUT = IEEE_MODE; debug(("movl %d,eax\n", IEEE_MODE)); OUT = 0x89; OUT = (REG_eax<<3)|0x44; OUT = 0x24; OUT = 0x04; debug(("movl eax,4(esp)\n")); OUT = 0xD9; OUT = 0x6C; OUT = 0x24; OUT = 0x04; debug(("fldcw 4(esp)\n")); }#endif}#if defined (HAVE_GCJ_SUPPORT)#include "gcj/gcj.h"/* * Establish JIT3 callee-saved register information for i386 * We must tell gcj where esi, edi, and ebx have been stored * on this frame, as an offset from the CFA. * In addition, we must tell it where the caller's esp was stored * * This depends on prologue_xxx so I put it here (XXX?). */voidarch_get_frame_description(int framesize, struct kaffe_frame_descriptor frame_desc[], int *n){ int i = 0; int rsave_area_offset = CFA_OFFSET + framesize; frame_desc[i].idx = DWARF_FRAME_RETURN_COLUMN; frame_desc[i].offset = RETADDR_SAVED_OFFSET; i++; frame_desc[i].idx = CFA_REGISTER; /* gcc_esp */ frame_desc[i].offset = CFA_SAVED_OFFSET; i++; if (framesize == -1) { /* -1 indicates trampoline frame */ *n = i; return; } /* NB: since CFA is pointing at caller's ret pc + 4, * subtracting CFA_OFFSET + framesize points at the last * slot. The callee-saved registers are stored one word * below, hence the 1 * 4 */ frame_desc[i].idx = DBX_REGISTER_NUMBER(/* gcc_edi */ 5); frame_desc[i].offset = - (rsave_area_offset + 1 * 4); i++; frame_desc[i].idx = DBX_REGISTER_NUMBER(/* gcc_esi */ 4); frame_desc[i].offset = - (rsave_area_offset + 2 * 4); i++; frame_desc[i].idx = DBX_REGISTER_NUMBER(/* gcc_ebx */ 3); frame_desc[i].offset = - (rsave_area_offset + 3 * 4); i++; *n = i;}#endif /* HAVE_GCJ_SUPPORT */define_insn(check_stack_limit, check_stack_limit_xRC){ int r = rreg_int(1); label* l = const_label(2); OUT = 0x39; OUT = 0xC0|(r<<3)|REG_esp; debug(("cmpl esp,%s\n", regname(r))); OUT = 0x0F; OUT = 0x87; LOUT = 5; debug(("jugt +5\n")); OUT = 0xE8; l->type |= Llong|Lrelative; l->at = CODEPC; LOUT = 0; l->from = CODEPC; debug(("call soft_stackoverflow\n"));}define_insn(exception_prologue, eprologue_xLx){ label* l; OUT = 0x89; OUT = 0xC0|(REG_ebp<<3)|REG_ecx; OUT = 0x81; OUT = 0xE8|REG_ecx; /* Remember where the framesize is to go */ l = (label*)const_int(1); l->type = Lframe|Labsolute|Lgeneral; l->at = (uintp)CODEPC; LOUT = 0; OUT = 0x81; OUT = 0xE8|REG_ecx; LOUT = 3*SLOTSIZE; OUT = 0x89; OUT = 0xC0|(REG_ecx<<3)|REG_esp; debug(("movl ebp,ecx\n")); debug(("subl #?,ecx\n")); debug(("subl #3*SLOTSIZE,ecx\n")); debug(("movl ecx,esp\n"));#if 0 if (used_ieee_division == true) { OUT = 0x81; OUT = 0xE8|REG_esp; LOUT = SLOTSIZE; debug(("subl #%d,esp\n", SLOTSIZE)); OUT = 0x8B; OUT = (REG_eax<<3)|0x04; OUT = 0x24; debug(("movl (esp),eax\n")); OUT = 0xB8|REG_eax; LOUT = IEEE_MODE; debug(("movl %d,eax\n", IEEE_MODE)); OUT = 0x89; OUT = (REG_eax<<3)|0x44; OUT = 0x24; OUT = 0x04; debug(("movl eax,4(esp)\n")); OUT = 0xD9; OUT = 0x6C; OUT = 0x24; OUT = 0x04; debug(("fldcw 4(esp)\n")); }#endif}define_insn(epilogue, epilogue_xxx){ extern label *getLastEpilogueLabel(void); label *el; if( (el = getLastEpilogueLabel()) && (el->at == (CODEPC - 4)) ) { /* * Nothing to jump over to get to the epilogue... Replace * the jump code with regular epilogue. */ el->type = Lnull; CODEPC -= 5; } else if( el && (el->at != (CODEPC - 4)) ) { /* The function ends with a throw, not a return. */ } setEpilogueLabel((uintp)CODEPC); #if 0 /* If this method uses IEEE, restore it */ if (used_ieee_division == true) {#if 0 OUT = 0xD9; OUT = 0x2C; OUT = 0x24; debug(("fldcw (esp)\n"));#endif OUT = 0xD9; OUT = 0x6C; OUT = 0x24; OUT = 0; debug(("fldcw 0(esp)\n")); OUT = 0x81; OUT = 0xC0|REG_esp; LOUT = 8; debug(("addl 8,esp\n")); }#endif#if defined(KAFFE_PROFILER) if (profFlag) { profiler_end(globalMethod->totalClicks, 1); }#endif OUT = 0x58|REG_ebx; OUT = 0x58|REG_esi; OUT = 0x58|REG_edi; OUT = 0x89; OUT = 0xC0|(REG_ebp<<3)|REG_esp; OUT = 0x58|REG_ebp; debug(("popl ebx\n")); debug(("popl esi\n")); debug(("popl edi\n")); debug(("movl ebp,esp\n")); debug(("popl ebp\n")); OUT = 0xC3; debug(("ret\n"));}/* --------------------------------------------------------------------- */define_insn(spill_int, spill_Rxx){ int r = sreg_int(0); int o = const_int(1); OUT = 0x89; OUT = 0x80|(r<<3)|REG_ebp; LOUT = o; debug(("movl %s,%d(ebp)\n", regname(r), o));}define_insn(spill_float, fspill_Rxx){ int o; (void)sreg_float(0); o = const_int(1); OUT = 0xD9; OUT = 0x98|REG_ebp; LOUT = o; debug(("fstp %d(ebp)\n", o));}define_insn(spill_double, fspilll_Rxx){ int o; (void)sreg_double(0); o = const_int(1); OUT = 0xDD; OUT = 0x98|REG_ebp; LOUT = o; debug(("fstpl %d(ebp)\n", o));}define_insn(reload_int, reload_Rxx){ int o; int r; r = lreg_int(0); o = const_int(1); OUT = 0x8B; OUT = 0x80|(r<<3)|REG_ebp; LOUT = o; debug(("movl %d(ebp),%s\n", o, regname(r)));}define_insn(reload_float, freload_Rxx){ int o; lreg_float(0); o = const_int(1); OUT = 0xD9; OUT = 0x80|REG_ebp; LOUT = o; debug(("fld %d(ebp)\n", o));}define_insn(reload_double, freloadl_Rxx){ int r, o; r = lreg_double(0); o = const_int(1); OUT = 0xDD; OUT = 0x80|REG_ebp; LOUT = o; debug(("fldl %d(ebp) %d\n", o, r));}voidmovereg_RR(int toreg, int fromreg){ do_move_int(toreg, fromreg);}/* --------------------------------------------------------------------- */define_insn(move_int_const, move_RxC){ int val = const_int(2); int w = wreg_int(0); if (val == 0) { OUT = 0x31; OUT = 0xC0|(w<<3)|w; debug(("xorl %s,%s\n", regname(w), regname(w))); } else { OUT = 0xB8|w; LOUT = val; debug(("movl #%d,%s\n", val, regname(w))); }}define_insn(move_label_const, move_RxL){ label* l = const_label(2); int w = wreg_int(0); OUT = 0xB8|w; l->type |= Llong|Labsolute; l->at = CODEPC; LOUT = 0; debug(("movl #%s,%s\n", getLabelName(l), regname(w)));}define_insn(move_int, move_RxR){ int r = rreg_int(2); int w = wreg_int(0); if (r != w) { OUT = 0x89; OUT = 0xC0|(r<<3)|w; debug(("movl %s,%s\n", regname(r), regname(w))); }}define_insn(move_float_const, fmove_RxC){ jvalue d; d.d = const_float(2); wreg_float(0); if (d.d == 0.0) { OUT = 0xD9; OUT = 0xEE; debug(("fldz\n")); if ((d.j >> 63) & 1) { OUT = 0xD9; OUT = 0xe0; debug(("fchs\n")); } } else if (d.d == 1.0) { OUT = 0xD9; OUT = 0xE8; debug(("fld1\n")); } else { ABORT(); }}define_insn(move_float, fmove_RxR){ int or = rslot_float(2); int ow = wslot_float(0); if (or != ow) { wreg_float(0); OUT = 0xD9; OUT = 0x80|REG_ebp; LOUT = or; debug(("fld %d(ebp)\n", or)); }}define_insn(move_double_const, fmovel_RxC){ jvalue d; d.d = const_double(2); wreg_double(0); if (d.d == 0.0) { OUT = 0xD9; OUT = 0xEE; debug(("fldz\n")); if ((d.j >> 63) & 1) { OUT = 0xD9; OUT = 0xe0; debug(("fchs\n")); } } else if (d.d == 1.0) { OUT = 0xD9; OUT = 0xE8; debug(("fld1\n")); } else { ABORT(); }}define_insn(move_double, fmovel_RxR){ int or = rslot_double(2); int ow = wslot_double(0); if (or != ow) { wreg_double(0); OUT = 0xDD; OUT = 0x80|REG_ebp; LOUT = or; debug(("fldl %d(ebp)\n", or)); }}/* --------------------------------------------------------------------- */define_insn(add_int, add_RRR){ int r; int w; check_reg_01(); r = rreg_int(2); w = rwreg_int(0); OUT = 0x01; OUT = 0xC0|(r<<3)|w; debug(("addl %s,%s\n", regname(r), regname(w)));}define_insn(adc_int, adc_RRR){ int r; int w; r = rreg_int(2); w = rwreg_int(0); OUT = 0x11; OUT = 0xC0|(r<<3)|w; debug(("adcl %s,%s\n", regname(r), regname(w)));}define_insn(add_float, fadd_RRR){ int rr, rm; /* * XXX Order is important here... If we put slot 2 into memory and * slot 1 into the register we get a whole bunch of excess * spills/reloaeds. */ rm = rslot_float(1); /* Get slot 1 into memory */ rr = rreg_float(2); /* Load slot 2 into the register stack */ wreg_float(0); /* Result will be in register stack */ OUT = 0xD8; OUT = 0x80|REG_ebp; LOUT = rm; debug(("fadd %d(ebp)\n", rm));}define_insn(add_double, faddl_RRR){ int rr, rm; rm = rslot_double(1); /* Get slot 1 into memory */ rr = rreg_double(2); /* Load slot 2 into the register stack */ wreg_double(0); /* Result will be in register stack */ OUT = 0xDC; OUT = 0x80|REG_ebp; LOUT = rm; debug(("faddl %d(ebp)\n", rm));}define_insn(sub_int, sub_RRR){ int r; int w; check_reg_01(); r = rreg_int(2); w = rwreg_int(0); OUT = 0x29; OUT = 0xC0|(r<<3)|w; debug(("subl %s,%s\n", regname(r), regname(w)));}define_insn(sbc_int, sbc_RRR){ int r; int w; r = rreg_int(2); w = rwreg_int(0); OUT = 0x19; OUT = 0xC0|(r<<3)|w; debug(("sbbl %s,%s\n", regname(r), regname(w)));}define_insn(sub_float, fsub_RRR){ int rr, rm; rm = rslot_float(1); /* Get slot 1 into memory */ rr = rreg_float(2); /* Load slot 2 into the register stack */ wreg_float(0); /* Result will be in register stack */ OUT = 0xD8; OUT = 0xA8|REG_ebp; LOUT = rm; debug(("fsub %d(ebp)\n", rm));}define_insn(sub_double, fsubl_RRR){ int rr, rm; rm = rslot_double(1); /* Get slot 1 into memory */ rr = rreg_double(2); /* Load slot 2 into the register stack */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -