diff --git a/ChangeLog b/ChangeLog index 1acc32fa4..14772894f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2014-11-03 Paulo Andrade + + * include/lightning.h, include/lightning/jit_private.h, + lib/lightning.c: Implement the new jit_set_code() interface, + that allows instructing lightning to use an alternate code + buffer. The new jit_realize() function should be called + before jit_set_code(), and usually call jit_get_code() + to query the amount of bytes expected to be required for + the code. + + * lib/jit_size.c: Minor update to have less chances of + miscalculating the code buffer by starting the counter + with the size of the longest instruction instead of zero, + as code emit fails if at any moment less than the longest + instruction bytes are available. + + * check/setcode.c: New file implementing some basic tests + of the new jit_set_code() interface. + + * check/Makefile.am: Update for newer test case. + 2014-06-03 Paulo Andrade * include/lightning.h, lib/lightning.c: Add the new diff --git a/check/Makefile.am b/check/Makefile.am index 48cd9fa0f..22a2035bf 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -16,7 +16,7 @@ AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE -check_PROGRAMS = lightning ccall self +check_PROGRAMS = lightning ccall self setcode lightning_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB) lightning_SOURCES = lightning.c @@ -27,6 +27,9 @@ ccall_SOURCES = ccall.c self_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB) self_SOURCES = self.c +setcode_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB) +setcode_SOURCES = setcode.c + $(top_builddir)/lib/liblightning.la: cd $(top_builddir)/lib; $(MAKE) $(AM_MAKEFLAGS) liblightning.la @@ -75,7 +78,6 @@ EXTRA_DIST = \ qalu_mul.tst qalu_mul.ok \ qalu_div.tst qalu_div.ok \ ret.tst ret.ok \ - ccall.ok \ check.sh \ check.x87.sh \ check.arm.sh check.swf.sh \ @@ -178,7 +180,7 @@ $(swf_TESTS): check.swf.sh TESTS += $(swf_TESTS) endif -TESTS += ccall self +TESTS += ccall self setcode CLEANFILES = $(TESTS) #TESTS_ENVIRONMENT=$(srcdir)/run-test; diff --git a/check/ccall.ok b/check/ccall.ok deleted file mode 100644 index 9766475a4..000000000 --- a/check/ccall.ok +++ /dev/null @@ -1 +0,0 @@ -ok diff --git a/check/self.ok b/check/self.ok deleted file mode 100644 index 9766475a4..000000000 --- a/check/self.ok +++ /dev/null @@ -1 +0,0 @@ -ok diff --git a/check/setcode.c b/check/setcode.c new file mode 100644 index 000000000..0047f3488 --- /dev/null +++ b/check/setcode.c @@ -0,0 +1,89 @@ +/* + * Simple test of using an alternate buffer for the code. + */ + +#include +#include +#include +#include +#if defined(__sgi) +# include +#endif + +#ifndef MAP_ANON +# define MAP_ANON MAP_ANONYMOUS +# ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS 0 +# endif +#endif + +#if !defined(__sgi) +#define mmap_fd -1 +#endif + +int +main(int argc, char *argv[]) +{ + jit_uint8_t *ptr; + jit_state_t *_jit; + jit_word_t length; +#if defined(__sgi) + int mmap_fd; +#endif + void (*function)(void); + +#if defined(__sgi) + mmap_fd = open("/dev/zero", O_RDWR); +#endif + + ptr = mmap(NULL, 1024 * 1024, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, mmap_fd, 0); + assert(ptr != MAP_FAILED); +#if defined(__sgi) + close(mmap_fd); +#endif + + init_jit(argv[0]); + _jit = jit_new_state(); + + jit_prolog(); + jit_prepare(); + jit_pushargi((jit_word_t)"%s\n"); + jit_ellipsis(); + jit_pushargi((jit_word_t)"ok"); + jit_finishi(printf); + + /* call to jit_realize() is only required when using an alternate + * code buffer. Note that not using mmap'ed memory may not work + * on several ports and/or operating system versions */ + jit_realize(); + + length = 0; + if (jit_get_code(&length) != NULL) + abort(); + + if (length <= 4) + abort(); + + /* check that a too small buffer fails */ + jit_set_code(ptr, 4); + function = jit_emit(); + if (function != NULL) + abort(); + + /* and calling again with enough space works */ + jit_set_code(ptr, 1024 * 1024); + function = jit_emit(); + if (function == NULL) + abort(); + + jit_clear_state(); + (*function)(); + jit_destroy_state(); + finish_jit(); + + munmap(ptr, 1024 * 1024); + + return (0); +} diff --git a/include/lightning.h b/include/lightning.h index 758f76088..84521c39a 100644 --- a/include/lightning.h +++ b/include/lightning.h @@ -887,6 +887,12 @@ extern void _jit_patch(jit_state_t*, jit_node_t*); extern void _jit_patch_at(jit_state_t*, jit_node_t*, jit_node_t*); #define jit_patch_abs(u,v) _jit_patch_abs(_jit,u,v) extern void _jit_patch_abs(jit_state_t*, jit_node_t*, jit_pointer_t); +#define jit_realize() _jit_realize(_jit) +extern void _jit_realize(jit_state_t*); +#define jit_get_code(u) _jit_get_code(_jit,u) +extern jit_pointer_t _jit_get_code(jit_state_t*, jit_word_t*); +#define jit_set_code(u,v) _jit_set_code(_jit,u,v) +extern void _jit_set_code(jit_state_t*, jit_pointer_t, jit_word_t); #define jit_emit() _jit_emit(_jit) extern jit_pointer_t _jit_emit(jit_state_t*); diff --git a/include/lightning/jit_private.h b/include/lightning/jit_private.h index 71729944d..1759bbe69 100644 --- a/include/lightning/jit_private.h +++ b/include/lightning/jit_private.h @@ -336,6 +336,7 @@ struct jit_compiler { #endif jit_node_t *head; jit_node_t *tail; + jit_uint32_t realize : 1; /* jit_realize() called? */ jit_uint32_t done : 1; /* emit state finished */ jit_uint32_t emit : 1; /* emit state entered */ jit_uint32_t again : 1; /* start over emiting function */ @@ -464,6 +465,8 @@ struct jit_state { jit_word_t length; } note; jit_compiler_t *comp; + /* Flags to know if user did set the code and data buffers */ + jit_uint32_t user_code : 1; }; struct jit_register { diff --git a/lib/jit_size.c b/lib/jit_size.c index 6efad618d..6678915a2 100644 --- a/lib/jit_size.c +++ b/lib/jit_size.c @@ -98,7 +98,7 @@ _jit_get_size(jit_state_t *_jit) jit_word_t size; jit_node_t *node; - for (size = 0, node = _jitc->head; node; node = node->next) + for (size = JIT_INSTR_MAX, node = _jitc->head; node; node = node->next) size += _szs[node->code]; return ((size + 4095) & -4096); diff --git a/lib/lightning.c b/lib/lightning.c index e0adeda79..ee21b1212 100644 --- a/lib/lightning.c +++ b/lib/lightning.c @@ -514,7 +514,7 @@ void _jit_save(jit_state_t *_jit, jit_int32_t reg) { reg = jit_regno(reg); - assert(!_jitc->emit); + assert(!_jitc->realize); _jitc->spill[reg] = jit_new_node_w(jit_code_save, reg); } @@ -524,7 +524,7 @@ _jit_load(jit_state_t *_jit, jit_int32_t reg) jit_node_t *node; reg = jit_regno(reg); - assert(!_jitc->emit); + assert(!_jitc->realize); assert(_jitc->spill[reg]); node = jit_new_node_w(jit_code_load, reg); /* create a path to flag the save/load is not required */ @@ -562,7 +562,7 @@ _jit_data(jit_state_t *_jit, jit_pointer_t data, jit_word_t key; jit_node_t *node; - assert(!_jitc->emit); + assert(!_jitc->realize); /* Ensure there is space even if asking for a duplicate */ if (((_jitc->data.offset + 7) & -8) + length > _jit->data.length) { @@ -887,7 +887,8 @@ _jit_clear_state(jit_state_t *_jit) void _jit_destroy_state(jit_state_t *_jit) { - munmap(_jit->code.ptr, _jit->code.length); + if (!_jit->user_code) + munmap(_jit->code.ptr, _jit->code.length); munmap(_jit->data.ptr, _jit->data.length); jit_free((jit_pointer_t *)&_jit); } @@ -895,21 +896,21 @@ _jit_destroy_state(jit_state_t *_jit) jit_node_t * _jit_new_node(jit_state_t *_jit, jit_code_t code) { - assert(!_jitc->emit); + assert(!_jitc->realize); return (link_node(new_node(code))); } jit_node_t * _jit_new_node_no_link(jit_state_t *_jit, jit_code_t code) { - assert(!_jitc->emit); + assert(!_jitc->realize); return (new_node(code)); } void _jit_link_node(jit_state_t *_jit, jit_node_t *node) { - assert(!_jitc->emit); + assert(!_jitc->realize); link_node(node); } @@ -918,7 +919,7 @@ _jit_new_node_w(jit_state_t *_jit, jit_code_t code, jit_word_t u) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; return (link_node(node)); } @@ -928,7 +929,7 @@ _jit_new_node_p(jit_state_t *_jit, jit_code_t code, jit_pointer_t u) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.p = u; return (link_node(node)); } @@ -938,7 +939,7 @@ _jit_new_node_ww(jit_state_t *_jit, jit_code_t code, jit_word_t u, jit_word_t v) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; node->v.w = v; return (link_node(node)); @@ -963,7 +964,7 @@ _jit_new_node_wf(jit_state_t *_jit, jit_code_t code, jit_word_t u, jit_float32_t v) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; node->v.f = v; return (link_node(node)); @@ -974,7 +975,7 @@ _jit_new_node_wd(jit_state_t *_jit, jit_code_t code, jit_word_t u, jit_float64_t v) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; node->v.d = v; return (link_node(node)); @@ -985,7 +986,7 @@ _jit_new_node_www(jit_state_t *_jit, jit_code_t code, jit_word_t u, jit_word_t v, jit_word_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; node->v.w = v; node->w.w = w; @@ -998,7 +999,7 @@ _jit_new_node_qww(jit_state_t *_jit, jit_code_t code, jit_word_t v, jit_word_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); assert(l != h); node->u.q.l = l; node->u.q.h = h; @@ -1012,7 +1013,7 @@ _jit_new_node_wwf(jit_state_t *_jit, jit_code_t code, jit_word_t u, jit_word_t v, jit_float32_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; node->v.w = v; node->w.f = w; @@ -1024,7 +1025,7 @@ _jit_new_node_wwd(jit_state_t *_jit, jit_code_t code, jit_word_t u, jit_word_t v, jit_float64_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.w = u; node->v.w = v; node->w.d = w; @@ -1036,7 +1037,7 @@ _jit_new_node_pww(jit_state_t *_jit, jit_code_t code, jit_pointer_t u, jit_word_t v, jit_word_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.p = u; node->v.w = v; node->w.w = w; @@ -1048,7 +1049,7 @@ _jit_new_node_pwf(jit_state_t *_jit, jit_code_t code, jit_pointer_t u, jit_word_t v, jit_float32_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.p = u; node->v.w = v; node->w.f = w; @@ -1060,7 +1061,7 @@ _jit_new_node_pwd(jit_state_t *_jit, jit_code_t code, jit_pointer_t u, jit_word_t v, jit_float64_t w) { jit_node_t *node = new_node(code); - assert(!_jitc->emit); + assert(!_jitc->realize); node->u.p = u; node->v.w = v; node->w.d = w; @@ -1703,6 +1704,49 @@ _jit_regarg_clr(jit_state_t *_jit, jit_node_t *node, jit_int32_t value) jit_regset_clrbit(&_jitc->regarg, jit_regno(node->w.w)); } +void +_jit_realize(jit_state_t *_jit) +{ + assert(!_jitc->realize); + if (_jitc->function) + jit_epilog(); + jit_optimize(); + _jitc->realize = 1; + +#if GET_JIT_SIZE + /* Heuristic to guess code buffer size */ + _jitc->mult = 4; + _jit->code.length = _jitc->pool.length * 1024 * _jitc->mult; +#else + _jit->code.length = jit_get_size(); +#endif +} + +jit_pointer_t +_jit_get_code(jit_state_t *_jit, jit_word_t *length) +{ + assert(_jitc->realize); + if (length) { + if (_jitc->done) + /* If code already generated, return exact size of code */ + *length = _jit->pc.uc - _jit->code.ptr; + else + /* Else return current size of the code buffer */ + *length = _jit->code.length; + } + + return (_jit->code.ptr); +} + +void +_jit_set_code(jit_state_t *_jit, jit_pointer_t ptr, jit_word_t length) +{ + assert(_jitc->realize); + _jit->code.ptr = ptr; + _jit->code.length = length; + _jit->user_code = 1; +} + jit_pointer_t _jit_emit(jit_state_t *_jit) { @@ -1714,39 +1758,35 @@ _jit_emit(jit_state_t *_jit) int mmap_fd; #endif - if (_jitc->function) - jit_epilog(); - jit_optimize(); + if (!_jitc->realize) + jit_realize(); _jitc->emit = 1; -#if GET_JIT_SIZE - /* Heuristic to guess code buffer size */ - _jitc->mult = 4; - _jit->code.length = _jitc->pool.length * 1024 * _jitc->mult; -#else - _jit->code.length = jit_get_size(); -#endif - + if (!_jit->user_code) { #if defined(__sgi) - mmap_fd = open("/dev/zero", O_RDWR); + mmap_fd = open("/dev/zero", O_RDWR); #endif - _jit->code.ptr = mmap(NULL, _jit->code.length, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, mmap_fd, 0); - assert(_jit->code.ptr != MAP_FAILED); + _jit->code.ptr = mmap(NULL, _jit->code.length, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, mmap_fd, 0); + assert(_jit->code.ptr != MAP_FAILED); + } _jitc->code.end = _jit->code.ptr + _jit->code.length - jit_get_max_instr(); _jit->pc.uc = _jit->code.ptr; for (;;) { if ((code = emit_code()) == NULL) { + _jitc->patches.offset = 0; for (node = _jitc->head; node; node = node->next) { if (node->link && (node->code == jit_code_label || node->code == jit_code_epilog)) node->flag &= ~jit_flag_patch; } + if (_jit->user_code) + goto fail; #if GET_JIT_SIZE ++_jitc->mult; length = _jitc->pool.length * 1024 * _jitc->mult; @@ -1778,14 +1818,14 @@ _jit_emit(jit_state_t *_jit) _jitc->code.end = _jit->code.ptr + _jit->code.length - jit_get_max_instr(); _jit->pc.uc = _jit->code.ptr; - _jitc->patches.offset = 0; } else break; } #if defined(__sgi) - close(mmap_fd); + if (!_jit->user_code) + close(mmap_fd); #endif _jitc->done = 1; @@ -1793,10 +1833,15 @@ _jit_emit(jit_state_t *_jit) result = mprotect(_jit->data.ptr, _jit->data.length, PROT_READ); assert(result == 0); - result = mprotect(_jit->code.ptr, _jit->code.length, PROT_READ | PROT_EXEC); - assert(result == 0); + if (!_jit->user_code) { + result = mprotect(_jit->code.ptr, _jit->code.length, + PROT_READ | PROT_EXEC); + assert(result == 0); + } return (_jit->code.ptr); +fail: + return (NULL); } /* Compute initial reglive and regmask set values of a basic block.