/* * jit-cache.h - Translated method cache implementation. * * Copyright (C) 2002, 2004 Southern Storm Software, Pty Ltd. * * 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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _JIT_CACHE_H #define _JIT_CACHE_H #ifdef __cplusplus extern "C" { #endif /* * Opaque method cache type. */ typedef struct jit_cache *jit_cache_t; /* * Writing position within a cache. */ typedef struct { jit_cache_t cache; /* Cache this position is attached to */ unsigned char *ptr; /* Current code pointer */ unsigned char *limit; /* Limit of the current page */ } jit_cache_posn; /* * Create a method cache. Returns NULL if out of memory. * If "limit" is non-zero, then it specifies the maximum * size of the cache in bytes. If "cache_page_size" is * non-zero, then it indicates the size of each cache page. */ jit_cache_t _jit_cache_create(long limit, long cache_page_size); /* * Destroy a method cache. */ void _jit_cache_destroy(jit_cache_t cache); /* * Determine if the cache is full. The "posn" value should * be supplied while translating a method, or be NULL otherwise. */ int _jit_cache_is_full(jit_cache_t cache, jit_cache_posn *posn); /* * Start output of a method, returning a cache position. * The "align" value indicates the default alignment for * the start of the method. The "cookie" value is a * cookie for referring to the method. Returns the * method entry point, or NULL if the cache is full. */ void *_jit_cache_start_method(jit_cache_t cache, jit_cache_posn *posn, int align, void *cookie); /* * Return values for "_jit_cache_end_method". */ #define JIT_CACHE_END_OK 0 /* Function is OK */ #define JIT_CACHE_END_RESTART 1 /* Restart is required */ #define JIT_CACHE_END_TOO_BIG 2 /* Function is too big for the cache */ /* * End output of a method. Returns zero if a restart. */ int _jit_cache_end_method(jit_cache_posn *posn); /* * Allocate "size" bytes of storage in the method cache's * auxillary data area. Returns NULL if insufficient space * to satisfy the request. It may be possible to satisfy * the request after a restart. */ void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size); /* * Allocate "size" bytes of storage when we aren't currently * translating a method. */ void *_jit_cache_alloc_no_method (jit_cache_t cache, unsigned long size, unsigned long align); /* * Align the method code on a particular boundary if the * difference between the current position and the aligned * boundary is less than "diff". The "nop" value is used * to pad unused bytes. */ void _jit_cache_align(jit_cache_posn *posn, int align, int diff, int nop); /* * Mark the current position with a bytecode offset value. */ void _jit_cache_mark_bytecode(jit_cache_posn *posn, unsigned long offset); /* * Change to a new exception region within the current method. * The cookie will typically be NULL if no exception region. */ void _jit_cache_new_region(jit_cache_posn *posn, void *cookie); /* * Set the exception region cookie for the current region. */ void _jit_cache_set_cookie(jit_cache_posn *posn, void *cookie); /* * Find the method that is associated with a particular * program counter. Returns NULL if the PC is not associated * with a method within the cache. The exception region * cookie is returned in "*cookie", if "cookie" is not NULL. */ void *_jit_cache_get_method(jit_cache_t cache, void *pc, void **cookie); /* * Get the start of a method with a particular starting PC. * Returns NULL if the PC could not be located. * NOTE: This function is not currently aware of the * possibility of multiple regions per function. To ensure * correct results the ``pc'' argument has to be in the * first region. */ void *_jit_cache_get_start_method(jit_cache_t cache, void *pc); /* * Get the end of a method with a particular starting PC. * Returns NULL if the PC could not be located. */ void *_jit_cache_get_end_method(jit_cache_t cache, void *pc); /* * Get a list of all method that are presently in the cache. * The list is terminated by a NULL, and must be free'd with * "ILFree". Returns NULL if out of memory. */ void **_jit_cache_get_method_list(jit_cache_t cache); /* * Get the native offset that is associated with a bytecode * offset within a method. The value "start" indicates the * entry point for the method. Returns JIT_CACHE_NO_OFFSET * if the native offset could not be determined. */ #define JIT_CACHE_NO_OFFSET (~((unsigned long)0)) unsigned long _jit_cache_get_native(jit_cache_t cache, void *start, unsigned long offset, int exact); /* * Get the bytecode offset that is associated with a native * offset within a method. The value "start" indicates the * entry point for the method. Returns JIT_CACHE_NO_OFFSET * if the bytecode offset could not be determined. */ unsigned long _jit_cache_get_bytecode(jit_cache_t cache, void *start, unsigned long offset, int exact); /* * Get the number of bytes currently in use in the method cache. */ unsigned long _jit_cache_get_size(jit_cache_t cache); /* * Convert a return address into a program counter value * that can be used with "_jit_cache_get_method". Normally * return addresses point to the next instruction after * an instruction that falls within a method region. This * macro corrects for the "off by 1" address. */ #define jit_cache_return_to_pc(addr) \ ((void *)(((unsigned char *)(addr)) - 1)) /* * Output a single byte to the current method. */ #define jit_cache_byte(posn,value) \ do { \ if((posn)->ptr < (posn)->limit) \ { \ *(((posn)->ptr)++) = (unsigned char)(value); \ } \ } while (0) /* * Output a 16-bit word to the current method. */ #define jit_cache_word16(posn,value) \ do { \ if(((posn)->ptr + 1) < (posn)->limit) \ { \ *((jit_ushort *)((posn)->ptr)) = (jit_ushort)(value); \ (posn)->ptr += 2; \ } \ else \ { \ (posn)->ptr = (posn)->limit; \ } \ } while (0) /* * Output a 32-bit word to the current method. */ #define jit_cache_word32(posn,value) \ do { \ if(((posn)->ptr + 3) < (posn)->limit) \ { \ *((jit_uint *)((posn)->ptr)) = (jit_uint)(value); \ (posn)->ptr += 4; \ } \ else \ { \ (posn)->ptr = (posn)->limit; \ } \ } while (0) /* * Output a native word to the current method. */ #define jit_cache_native(posn,value) \ do { \ if(((posn)->ptr + sizeof(jit_nuint) - 1) < (posn)->limit) \ { \ *((jit_nuint *)((posn)->ptr)) = (jit_nuint)(value); \ (posn)->ptr += sizeof(jit_nuint); \ } \ else \ { \ (posn)->ptr = (posn)->limit; \ } \ } while (0) /* * Output a 64-bit word to the current method. */ #define jit_cache_word64(posn,value) \ do { \ if(((posn)->ptr + 7) < (posn)->limit) \ { \ *((jit_ulong *)((posn)->ptr)) = (jit_ulong)(value); \ (posn)->ptr += 8; \ } \ else \ { \ (posn)->ptr = (posn)->limit; \ } \ } while (0) /* * Get the output position within the current method. */ #define jit_cache_get_posn(posn) ((posn)->ptr) /* * Determine if there is sufficient space for N bytes in the current method. */ #define jit_cache_check_for_n(posn,n) \ (((posn)->ptr + (n)) <= (posn)->limit) /* * Mark the cache as full. */ #define jit_cache_mark_full(posn) \ do { \ (posn)->ptr = (posn)->limit; \ } while (0) #ifdef __cplusplus }; #endif #endif /* _JIT_CACHE_H */