From: Rhys Weatherley Date: Fri, 21 May 2004 05:55:49 +0000 (+0000) Subject: Use computed goto's in the interpreter if supported by the underlying compiler. X-Git-Tag: r.0.0.4~94 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=9c3afc7153e46c1c4f6a494b4c84af7dee0a6a66;p=francis%2Flibjit.git Use computed goto's in the interpreter if supported by the underlying compiler. --- diff --git a/ChangeLog b/ChangeLog index 8e1fdd0..197a5ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,10 @@ jit/jit-opcode.c, jitplus/jit-plus-function.cpp: add the "jit_insn_alloca" instruction. + * configure.in, jit/.cvsignore, jit/Makefile.am, jit/jit-interp.c, + jit/mklabel.sh: use computed goto's in the interpreter if supported + by the underlying compiler. + 2004-05-20 Rhys Weatherley * include/jit/jit-value.h, jit/jit-insn.c, jit/jit-value.c: diff --git a/configure.in b/configure.in index d91559b..fd1cc8d 100644 --- a/configure.in +++ b/configure.in @@ -362,6 +362,29 @@ else LIB_STDCPP="" fi +dnl Check for computed goto support in the compiler. +AC_MSG_CHECKING(for computed goto support) +AC_TRY_COMPILE([], [ + static void *labels[] = {&&label0, &&label1, &&label2}; + unsigned char *pc = 0; + goto *labels[*pc]; + label0: ; + label1: ; + label2: ; +], AC_DEFINE(HAVE_COMPUTED_GOTO, 1, [Define if you have support for computed gotos]) compgoto=yes, compgoto=no) +AC_MSG_RESULT($compgoto) +AC_MSG_CHECKING(for pic computed goto support) +AC_TRY_COMPILE([], [ + static int labelOffsets[] = + {&&label0 - &&label0, &&label1 - &&label0, &&label2 - &&label0}; + unsigned char *pc = 0; + goto *(&&label0 + labelOffsets[*pc]); + label0: ; + label1: ; + label2: ; +], AC_DEFINE(HAVE_PIC_COMPUTED_GOTO, 1, [Define if you have PIC support for computed gotos]) piccompgoto=yes, piccompgoto=no) +AC_MSG_RESULT($piccompgoto) + dnl Checks for library functions. if test "x$suppress_libm" = "xno" ; then AC_CHECK_LIB(m, sin) diff --git a/jit/.cvsignore b/jit/.cvsignore index 743b011..47f9d31 100644 --- a/jit/.cvsignore +++ b/jit/.cvsignore @@ -3,5 +3,6 @@ Makefile.in .deps .libs jit-apply-rules.h +jit-interp-labels.h *.lo *.la diff --git a/jit/Makefile.am b/jit/Makefile.am index a623473..a0295a2 100644 --- a/jit/Makefile.am +++ b/jit/Makefile.am @@ -52,3 +52,13 @@ libjit_la_SOURCES = \ AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir) libjit_la_LDFLAGS = -version-info $(LIBJIT_VERSION) + +jit-interp.lo: jit-interp-labels.h + +jit-interp-labels.h: $(top_srcdir)/include/jit/jit-opcode.h \ + $(top_srcdir)/jit/jit-interp.h $(srcdir)/mklabel.sh + $(SHELL) $(srcdir)/mklabel.sh "$(AWK)" \ + $(top_srcdir)/include/jit/jit-opcode.h \ + $(top_srcdir)/jit/jit-interp.h >jit-interp-labels.h + +CLEANFILES = jit-interp-labels.h diff --git a/jit/jit-interp.c b/jit/jit-interp.c index 6579e4b..34bd53c 100644 --- a/jit/jit-interp.c +++ b/jit/jit-interp.c @@ -44,18 +44,19 @@ straight vanilla ANSI C. #if defined(JIT_BACKEND_INTERP) /* - * Macros that help with the definition of the interpreter switch loop. + * Determine what kind of interpreter dispatch to use. */ -#define VMSWITCH(pc) \ - for(;;) \ - { \ - switch((int)*((jit_nint *)(pc))) -#define VMSWITCHEND \ - } -#define VMCASE(opcode) \ - case opcode -#define VMBREAK \ - break +#ifdef HAVE_COMPUTED_GOTO + #if defined(PIC) && defined(HAVE_PIC_COMPUTED_GOTO) + #define JIT_INTERP_TOKEN_PIC 1 + #elif defined(PIC) + #define JIT_INTERP_SWITCH 1 + #else + #define JIT_INTERP_TOKEN 1 + #endif +#else /* !HAVE_COMPUTED_GOTO */ + #define JIT_INTERP_SWITCH 1 +#endif /* !HAVE_COMPUTED_GOTO */ /* * Modify the program counter and stack pointer. @@ -243,6 +244,9 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, void *handler; jit_jmp_buf *jbuf; + /* Define the label table for computed goto dispatch */ + #include "jit-interp-labels.h" + /* Set up the stack frame for this function */ frame = (jit_item *)alloca(func->frame_size); stacktop = frame + func->working_area; @@ -4468,7 +4472,6 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, VMCASE(JIT_OP_PUSH_FLOAT64): VMCASE(JIT_OP_PUSH_NFLOAT): VMCASE(JIT_OP_FLUSH_SMALL_STRUCT): - VMCASE(JIT_OP_END_MARKER): VMCASE(JIT_OP_ENTER_CATCH): VMCASE(JIT_OP_ENTER_FINALLY): VMCASE(JIT_OP_ENTER_FILTER): diff --git a/jit/mklabel.sh b/jit/mklabel.sh new file mode 100755 index 0000000..fe4b023 --- /dev/null +++ b/jit/mklabel.sh @@ -0,0 +1,298 @@ +#!/bin/sh +# +# mklabel.sh - Make label tables for computed goto's. +# +# 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 +# +# Usage: mklabel.sh awk jit-opcode.h jit-interp.h >jit-interp-labels.h + +# Validate the parameters. +if test "x$1" = "x" ; then + echo "Usage: $0 awk jit-opcode.h jit-interp.h >jit-interp-labels.h" 1>&2 + exit 1 +fi +if test "x$2" = "x" ; then + echo "Usage: $0 awk jit-opcode.h jit-interp.h >jit-interp-labels.h" 1>&2 + exit 1 +fi +if test "x$3" = "x" ; then + echo "Usage: $0 awk jit-opcode.h jit-interp.h >jit-interp-labels.h" 1>&2 + exit 1 +fi + +# Output the "do not edit" header. +echo '/* This file is automatically generated - do not edit */' +echo '' + +# Define a null assembly statement. This is a trick to stop gcc doing +# tail-end combination on the cases within the switch statements. +echo '#if defined(__GNUC__)' +echo '#define VMNULLASM() __asm__("")' +echo '#else' +echo '#define VMNULLASM()' +echo '#endif' +echo '#define VMFETCH(pc) ((int)*((jit_nint *)(pc)))' +echo '' + +# Are we compiling an interpreter that uses PIC computed goto's? +echo '#if defined(JIT_INTERP_TOKEN_PIC)' +echo '' + +# Output a table of PIC labels, based on an incoming stream +# of #define's for opcodes. Some awks don't support hex +# string to number conversion, which is why we have to convert +# the opcode value the hard way. +pic_table() +{ + "$1" 'BEGIN{ + nextval=0 + } + { + currval=0; + hexval=$3 + ch=substr(hexval,1,1); + if(ch == "(") + hexval=$5 + ch=substr(hexval,3,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + currval=currval*16; + ch=substr(hexval,4,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + currval=currval*16; + ch=substr(hexval,5,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + currval=currval*16; + ch=substr(hexval,6,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + while(nextval < currval) + { + print " &&'"$2"' - &&JIT_OP_NOP_label," + ++nextval + } + print " &&" $2 "_label - &&JIT_OP_NOP_label," + ++nextval + }' - + return 0 +} + +# Output the label table (PIC version). +echo 'static int const main_label_table[JIT_OP_END_MARKER] = {' +grep '^#define[ ]*JIT_OP_' "$2" | grep -v 'JIT_OP_NUM_OPCODES' | \ + pic_table "$1" JIT_OP_NOP_label +grep '^#define[ ]*JIT_OP_' "$3" | grep -v 'JIT_OP_NUM_INTERP_OPCODES' | \ + grep -v 'JIT_OP_END_MARKER' | pic_table "$1" JIT_OP_NOP_label +echo '};' +echo '' + +# Output the helper macros (PIC). +echo '#define VMSWITCH(pc) { goto *(&&JIT_OP_NOP_label + main_label_table[VMFETCH((pc))]);' +echo '#define VMSWITCHEND }' +echo '#define VMCASE(val) val##_label' +echo '#define VMBREAK \ + goto *(&&JIT_OP_NOP_label + main_label_table[VMFETCH((pc))])' +echo '' + +# Now to handle the non-PIC case of using computed goto's. +echo '#elif defined(JIT_INTERP_TOKEN)' +echo '' + +# Output a table of non-PIC labels, based on an incoming stream +# of #define's for opcodes. Some awks don't support hex +# string to number conversion, which is why we have to convert +# the opcode value the hard way. +non_pic_table() +{ + "$1" 'BEGIN{ + nextval=0 + } + { + currval=0; + hexval=$3 + ch=substr(hexval,1,1); + if(ch == "(") + hexval=$5 + ch=substr(hexval,3,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + currval=currval*16; + ch=substr(hexval,4,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + currval=currval*16; + ch=substr(hexval,5,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + currval=currval*16; + ch=substr(hexval,6,1); + if(ch == "0") currval=currval+0; else + if(ch == "1") currval=currval+1; else + if(ch == "2") currval=currval+2; else + if(ch == "3") currval=currval+3; else + if(ch == "4") currval=currval+4; else + if(ch == "5") currval=currval+5; else + if(ch == "6") currval=currval+6; else + if(ch == "7") currval=currval+7; else + if(ch == "8") currval=currval+8; else + if(ch == "9") currval=currval+9; else + if(ch == "A") currval=currval+10; else + if(ch == "B") currval=currval+11; else + if(ch == "C") currval=currval+12; else + if(ch == "D") currval=currval+13; else + if(ch == "E") currval=currval+14; else + if(ch == "F") currval=currval+15; + while(nextval < currval) + { + print " &&'"$2"'," + ++nextval + } + print " &&" $2 "_label," + ++nextval + }' - + return 0 +} + +# Output the label table (non-PIC). +echo 'static void * main_label_table[JIT_OP_END_MARKER] = {' +grep '^#define[ ]*JIT_OP_' "$2" | grep -v 'JIT_OP_NUM_OPCODES' | \ + non_pic_table "$1" JIT_OP_NOP_label +grep '^#define[ ]*JIT_OP_' "$3" | grep -v 'JIT_OP_NUM_INTERP_OPCODES' | \ + grep -v 'JIT_OP_END_MARKER' | non_pic_table "$1" JIT_OP_NOP_label +echo '};' +echo '' + +# Output the helper macros (non-PIC). +echo '#define VMSWITCH(pc) { goto *main_label_table[VMFETCH((pc))];' +echo '#define VMSWITCHEND }' +echo '#define VMCASE(val) val##_label' +echo '#define VMBREAK \ + goto *main_label_table[VMFETCH((pc))]' +echo '' + +# Output the non-goto case of the helper macros. +echo '#else /* JIT_INTERP_SWITCH */' +echo '' +echo '#define VMSWITCH(pc) for(;;) { switch(VMFETCH((pc)))' +echo '#define VMSWITCHEND }' +echo '#define VMCASE(val) case (val)' +echo '#define VMBREAK VMNULLASM(); break' +echo '' +echo '#endif /* JIT_INTERP_SWITCH */' + +# Done. +exit 0