/* src/vm/jit/dseg.c - data segment handling stuff Copyright (C) 1996-2005, 2006, 2007, 2008 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include "vm/types.h" #include "mm/memory.hpp" #include "vm/options.h" #include "vm/jit/codegen-common.hpp" #include "vm/jit/methodheader.h" /* dseg_finish ***************************************************************** Fills the data segment with the values stored. *******************************************************************************/ void dseg_finish(jitdata *jd) { codeinfo *code; codegendata *cd; dsegentry *de; /* get required compiler data */ code = jd->code; cd = jd->cd; /* process all data segment entries */ for (de = cd->dseg; de != NULL; de = de->next) { switch (de->type) { case TYPE_INT: *((s4 *) (code->entrypoint + de->disp)) = de->val.i; break; case TYPE_LNG: *((s8 *) (code->entrypoint + de->disp)) = de->val.l; break; case TYPE_FLT: *((float *) (code->entrypoint + de->disp)) = de->val.f; break; case TYPE_DBL: *((double *) (code->entrypoint + de->disp)) = de->val.d; break; case TYPE_ADR: *((void **) (code->entrypoint + de->disp)) = de->val.a; break; } } } static s4 dseg_find_s4(codegendata *cd, s4 value) { dsegentry *de; /* search all data segment entries for a matching entry */ for (de = cd->dseg; de != NULL; de = de->next) { if (IS_INT_TYPE(de->type)) if (de->flags & DSEG_FLAG_READONLY) if (de->val.i == value) return de->disp; } /* no matching entry was found */ return 0; } static s4 dseg_find_s8(codegendata *cd, s8 value) { dsegentry *de; /* search all data segment entries for a matching entry */ for (de = cd->dseg; de != NULL; de = de->next) { if (IS_LNG_TYPE(de->type)) if (de->flags & DSEG_FLAG_READONLY) if (de->val.l == value) return de->disp; } /* no matching entry was found */ return 0; } static s4 dseg_find_float(codegendata *cd, float value) { dsegentry *de; imm_union val; /* we compare the hex value of the float as 0.0 == -0.0 */ val.f = value; /* search all data segment entries for a matching entry */ for (de = cd->dseg; de != NULL; de = de->next) { if (IS_FLT_TYPE(de->type)) if (de->flags & DSEG_FLAG_READONLY) if (de->val.i == val.i) return de->disp; } /* no matching entry was found */ return 0; } static s4 dseg_find_double(codegendata *cd, double value) { dsegentry *de; imm_union val; /* we compare the hex value of the double as 0.0 == -0.0 */ val.d = value; /* search all data segment entries for a matching entry */ for (de = cd->dseg; de != NULL; de = de->next) { if (IS_DBL_TYPE(de->type)) if (de->flags & DSEG_FLAG_READONLY) if (de->val.l == val.l) return de->disp; } /* no matching entry was found */ return 0; } static s4 dseg_find_address(codegendata *cd, void *value) { dsegentry *de; /* search all data segment entries for a matching entry */ for (de = cd->dseg; de != NULL; de = de->next) { if (IS_ADR_TYPE(de->type)) if (de->flags & DSEG_FLAG_READONLY) if (de->val.a == value) return de->disp; } /* no matching entry was found */ return 0; } /* dseg_add_s4_intern ********************************************************** Internal function to add an s4 value to the data segment. *******************************************************************************/ static s4 dseg_add_s4_intern(codegendata *cd, s4 value, u4 flags) { dsegentry *de; /* Increase data segment size, which is also the displacement into the data segment. */ cd->dseglen += 4; /* allocate new entry */ de = DNEW(dsegentry); de->type = TYPE_INT; de->flags = flags; de->disp = -(cd->dseglen); de->val.i = value; de->next = cd->dseg; /* insert into the chain */ cd->dseg = de; return de->disp; } /* dseg_add_unique_s4 ********************************************************** Adds uniquely an s4 value to the data segment. *******************************************************************************/ s4 dseg_add_unique_s4(codegendata *cd, s4 value) { s4 disp; disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_UNIQUE); return disp; } /* dseg_add_s4 ***************************************************************** Adds an s4 value to the data segment. It tries to reuse previously added values. *******************************************************************************/ s4 dseg_add_s4(codegendata *cd, s4 value) { s4 disp; /* search the data segment if the value is already stored */ disp = dseg_find_s4(cd, value); if (disp != 0) return disp; disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_READONLY); return disp; } /* dseg_add_s8_intern ********************************************************** Internal function to add an s8 value to the data segment. *******************************************************************************/ static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags) { dsegentry *de; /* Increase data segment size, which is also the displacement into the data segment. */ cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8); /* allocate new entry */ de = DNEW(dsegentry); de->type = TYPE_LNG; de->flags = flags; de->disp = -(cd->dseglen); de->val.l = value; de->next = cd->dseg; /* insert into the chain */ cd->dseg = de; return de->disp; } /* dseg_add_unique_s8 ********************************************************** Adds uniquely an s8 value to the data segment. *******************************************************************************/ s4 dseg_add_unique_s8(codegendata *cd, s8 value) { s4 disp; disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_UNIQUE); return disp; } /* dseg_add_s8 ***************************************************************** Adds an s8 value to the data segment. It tries to reuse previously added values. *******************************************************************************/ s4 dseg_add_s8(codegendata *cd, s8 value) { s4 disp; /* search the data segment if the value is already stored */ disp = dseg_find_s8(cd, value); if (disp != 0) return disp; disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_READONLY); return disp; } /* dseg_add_float_intern ******************************************************* Internal function to add a float value to the data segment. *******************************************************************************/ static s4 dseg_add_float_intern(codegendata *cd, float value, u4 flags) { dsegentry *de; /* Increase data segment size, which is also the displacement into the data segment. */ cd->dseglen += 4; /* allocate new entry */ de = DNEW(dsegentry); de->type = TYPE_FLT; de->flags = flags; de->disp = -(cd->dseglen); de->val.f = value; de->next = cd->dseg; /* insert into the chain */ cd->dseg = de; return de->disp; } /* dseg_add_unique_float ******************************************************* Adds uniquely an float value to the data segment. *******************************************************************************/ s4 dseg_add_unique_float(codegendata *cd, float value) { s4 disp; disp = dseg_add_float_intern(cd, value, DSEG_FLAG_UNIQUE); return disp; } /* dseg_add_float ************************************************************** Adds an float value to the data segment. It tries to reuse previously added values. *******************************************************************************/ s4 dseg_add_float(codegendata *cd, float value) { s4 disp; /* search the data segment if the value is already stored */ disp = dseg_find_float(cd, value); if (disp != 0) return disp; disp = dseg_add_float_intern(cd, value, DSEG_FLAG_READONLY); return disp; } /* dseg_add_double_intern ****************************************************** Internal function to add a double value to the data segment. *******************************************************************************/ static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags) { dsegentry *de; /* Increase data segment size, which is also the displacement into the data segment. */ cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8); /* allocate new entry */ de = DNEW(dsegentry); de->type = TYPE_DBL; de->flags = flags; de->disp = -(cd->dseglen); de->val.d = value; de->next = cd->dseg; /* insert into the chain */ cd->dseg = de; return de->disp; } /* dseg_add_unique_double ****************************************************** Adds uniquely a double value to the data segment. *******************************************************************************/ s4 dseg_add_unique_double(codegendata *cd, double value) { s4 disp; disp = dseg_add_double_intern(cd, value, DSEG_FLAG_UNIQUE); return disp; } /* dseg_add_double ************************************************************* Adds a double value to the data segment. It tries to reuse previously added values. *******************************************************************************/ s4 dseg_add_double(codegendata *cd, double value) { s4 disp; /* search the data segment if the value is already stored */ disp = dseg_find_double(cd, value); if (disp != 0) return disp; disp = dseg_add_double_intern(cd, value, DSEG_FLAG_READONLY); return disp; } /* dseg_add_address_intern ***************************************************** Internal function to add an address pointer to the data segment. *******************************************************************************/ static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags) { dsegentry *de; /* Increase data segment size, which is also the displacement into the data segment. */ #if SIZEOF_VOID_P == 8 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8); #else cd->dseglen += 4; #endif /* allocate new entry */ de = DNEW(dsegentry); de->type = TYPE_ADR; de->flags = flags; de->disp = -(cd->dseglen); de->val.a = value; de->next = cd->dseg; /* insert into the chain */ cd->dseg = de; return de->disp; } /* dseg_add_unique_address ***************************************************** Adds uniquely an address value to the data segment. *******************************************************************************/ s4 dseg_add_unique_address(codegendata *cd, void *value) { s4 disp; disp = dseg_add_address_intern(cd, value, DSEG_FLAG_UNIQUE); return disp; } /* dseg_add_address ************************************************************ Adds an address value to the data segment. It tries to reuse previously added values. *******************************************************************************/ s4 dseg_add_address(codegendata *cd, void *value) { s4 disp; /* search the data segment if the value is already stored */ disp = dseg_find_address(cd, value); if (disp != 0) return disp; disp = dseg_add_address_intern(cd, value, DSEG_FLAG_READONLY); return disp; } /* dseg_add_target ************************************************************* XXX *******************************************************************************/ void dseg_add_target(codegendata *cd, basicblock *target) { jumpref *jr; jr = DNEW(jumpref); jr->tablepos = dseg_add_unique_address(cd, NULL); jr->target = target; jr->next = cd->jumpreferences; cd->jumpreferences = jr; } /* dseg_adddata **************************************************************** Adds a data segment reference to the codegendata. *******************************************************************************/ #if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP) void dseg_adddata(codegendata *cd) { dataref *dr; dr = DNEW(dataref); dr->datapos = cd->mcodeptr - cd->mcodebase; dr->next = cd->datareferences; cd->datareferences = dr; } #endif /* dseg_resolve_datareferences ************************************************* Resolve data segment references. *******************************************************************************/ #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP) void dseg_resolve_datareferences(jitdata *jd) { codeinfo *code; codegendata *cd; dataref *dr; /* get required compiler data */ code = jd->code; cd = jd->cd; /* data segment references resolving */ for (dr = cd->datareferences; dr != NULL; dr = dr->next) *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint; } #endif /* dseg_display **************************************************************** Displays the content of the methods' data segment. *******************************************************************************/ #if !defined(NDEBUG) void dseg_display(jitdata *jd) { codeinfo *code; codegendata *cd; dsegentry *de; imm_union val; /* get required compiler data */ code = jd->code; cd = jd->cd; if (opt_debugcolor) printf("\033[34m"); /* blue */ printf(" --- dump of datasegment\n"); /* process all data segment entries */ for (de = cd->dseg; de != NULL; de = de->next) { #if SIZEOF_VOID_P == 8 printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp)); #else printf("0x%08x:", (ptrint) (code->entrypoint + de->disp)); #endif printf(" %6x (%6d): ", de->disp, de->disp); /* We read the values from the data segment as some values, like the line number table, have been written directly to the data segment. */ switch (de->type) { case TYPE_INT: val.i = *((s4 *) (code->entrypoint + de->disp)); printf("(INT) %d (0x%08x)", val.i, val.i); break; case TYPE_LNG: val.l = *((s8 *) (code->entrypoint + de->disp)); #if SIZEOF_VOID_P == 8 printf("(LNG) %ld (0x%016lx)", val.l, val.l); #else printf("(LNG) %lld (0x%016llx)", val.l, val.l); #endif break; case TYPE_FLT: val.f = *((float *) (code->entrypoint + de->disp)); printf("(FLT) %g (0x%08x)", val.f, val.i); break; case TYPE_DBL: val.d = *((double *) (code->entrypoint + de->disp)); #if SIZEOF_VOID_P == 8 printf("(DBL) %g (0x%016lx)", val.d, val.l); #else printf("(DBL) %g (0x%016llx)", val.d, val.l); #endif break; case TYPE_ADR: val.a = *((void **) (code->entrypoint + de->disp)); #if SIZEOF_VOID_P == 8 printf("(ADR) %016lx", (ptrint) val.a); #else printf("(ADR) %08x", (ptrint) val.a); #endif break; } printf("\n"); } printf(" --- begin of data segment: "); #if SIZEOF_VOID_P == 8 printf("0x%016lx\n", (ptrint) code->entrypoint); #else printf("0x%08x\n", (ptrint) code->entrypoint); #endif if (opt_debugcolor) printf("\033[m"); } #endif /* !defined(NDEBUG) */ /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */