From f8222682d94e30c39d86fc6a510b1139d74feb70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Mon, 16 Jul 2001 12:48:59 -0700
Subject: [PATCH] first incarnation of --with-machine-code it only work on x86
 with gcc so far, and that doesn't even work either...

Rev: bin/make_interpret_functions.pike:1.1
Rev: src/Makefile.in:1.268
Rev: src/acconfig.h:1.92
Rev: src/configure.in:1.538
Rev: src/interpret.c:1.220
Rev: src/interpret_functions.h:1.76
Rev: src/interpreter.h:1.70
Rev: src/las.c:1.257
Rev: src/lex.c:1.98
Rev: src/lex.h:1.19
Rev: src/peep.c:1.54
Rev: src/program.c:1.354
Rev: src/program.h:1.139
---
 bin/make_interpret_functions.pike | 140 ++++++++++++++++++++
 src/Makefile.in                   |   6 +-
 src/acconfig.h                    |   5 +-
 src/configure.in                  |   7 +-
 src/interpret.c                   | 104 ++++++++++++++-
 src/interpret_functions.h         | 207 +++++++++++++++++++++---------
 src/interpreter.h                 |  42 ++----
 src/las.c                         |   4 +-
 src/lex.c                         | 156 ++++++++++++++--------
 src/lex.h                         |   8 +-
 src/peep.c                        |  51 +++++++-
 src/program.c                     |  36 +++++-
 src/program.h                     |   7 +-
 13 files changed, 608 insertions(+), 165 deletions(-)
 create mode 100644 bin/make_interpret_functions.pike

diff --git a/bin/make_interpret_functions.pike b/bin/make_interpret_functions.pike
new file mode 100644
index 0000000000..80655d08dd
--- /dev/null
+++ b/bin/make_interpret_functions.pike
@@ -0,0 +1,140 @@
+#!/usr/local/bin/pike
+
+#ifdef OLD
+import ".";
+#define PC .Pike
+#else /* !OLD */
+#if constant(Parser.Pike)
+#define PC Parser.Pike
+#else /* !constant(Parser.Pike) */
+#define PC Parser.C
+#endif /* constant(Parser.Pike) */
+#endif /* OLD */
+
+mapping ops=([]);
+
+array fixit2(array x)
+{
+  array ret=({});
+  array opcodes=({});
+  for(int e=0;e<sizeof(x);e++)
+    {
+      if(objectp(x[e]) && ops[(string)x[e]])
+      {
+	opcodes+=x[e..e+1];
+	array tmp=fixit2((x[e+1]/ ({ PC.Token(",") }) )[-1][0]);
+	
+	ret+=({ tmp[0] });
+	opcodes+=tmp[1];
+	e++;
+      }
+      else if(arrayp(x[e]))
+      {
+	array tmp=fixit2(x[e]);
+	ret+=tmp[0];
+	opcodes+=tmp[1];
+      }
+      else
+      {
+	ret+=({x[e]});
+      }
+    }
+  return ({ ret, opcodes });
+}
+
+array fixit(array x)
+{
+  array ret=({});
+  for(int e=0;e<sizeof(x);e++)
+    {
+      if(objectp(x[e]) && ops[(string)x[e]])
+      {
+//	werror("DOING %s\n",(string)(x[e+1][1]));
+	array tmp=fixit2(x[e+1]);
+	ret+=({x[e]}) + tmp[0] + tmp[1];
+	e++;
+
+	/* Skip traling ; */
+	if(e+1<sizeof(x) && objectp(x[e+1]) && ";" == (string)x[e+1])
+	{
+	  object tmp=x[e+1];
+	  tmp->text="";
+	  ret+=({tmp});
+	  e++;
+	}
+      }
+      else
+      {
+	ret+=({x[e]});
+      }
+    }
+  return ret;
+}
+
+array filter_out_cases(array x)
+{
+  array y=x/({ PC.Token("CASE") });
+  for(int e=1;e<sizeof(y);e++) y[e]=y[e][1..];
+  return y*({});
+}
+
+array fix_cases(array x)
+{
+  int start=0;
+  int undone=0;
+  array ret=({});
+
+  while(1)
+  {
+    int casepos=search(x,PC.Token("CASE"), start);
+    werror("%O\n",PC.simple_reconstitute(x[casepos..casepos+1]));
+    if(casepos == -1) break;
+    int donepos=search(x,PC.Token("DONE"),casepos+1);
+    
+    ret+=x[undone..casepos-1]+
+      ({
+	PC.Token("OPCODE0"),
+	  ({
+	    PC.Token("("),
+	      x[casepos+1][1],
+	      PC.Token(","),
+	      PC.Token(sprintf("%O",(string)x[casepos+1][1])),
+	      PC.Token(","),
+	      ({ PC.Token("{") })+
+	      filter_out_cases(x[casepos+2..donepos-1])+
+	      ({  PC.Token("}") }),
+	      PC.Token(")"),
+	      PC.Token(";"),
+	      })
+	  });
+    
+    start=casepos+1;
+    undone=donepos+1;
+  }
+
+  return ret + x[undone..];
+}
+
+int main(int argc, array(string) argv)
+{
+  string file=argv[1];
+  mixed x=Stdio.read_file(file);
+  x=PC.split(x);
+  x=PC.tokenize(x,file);
+  x=PC.hide_whitespaces(x);
+  x=PC.group(x);
+
+  for(int e=0;e<=2;e++)
+    foreach( ({"","_JUMP","_TAIL","_TAILJUMP"}) , string postfix)
+      ops[sprintf("OPCODE%d%s",e,postfix)]=1;
+
+//  werror("%O\n",ops);
+
+  x=fix_cases(x);
+  x=fixit(x);
+
+  if(getenv("PIKE_DEBUG_PRECOMPILER"))
+    write(PC.simple_reconstitute(x));
+  else
+    write(PC.reconstitute_with_line_numbers(x));
+}
diff --git a/src/Makefile.in b/src/Makefile.in
index 2cd12a2f86..853182c43e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,5 +1,5 @@
 #
-# $Id: Makefile.in,v 1.267 2001/07/13 18:19:07 grubba Exp $
+# $Id: Makefile.in,v 1.268 2001/07/16 19:48:56 hubbe Exp $
 #
 
 # This line is needed on some machines.
@@ -718,6 +718,10 @@ $(SRCDIR)/language.h_src: $(SRCDIR)/language.yacc
 $(SRCDIR)/language.c: $(SRCDIR)/language.h_src
 	touch $(SRCDIR)/language.c
 
+
+interpret_functions_fixed.h: interpret_functions.h
+	./precompile.sh make_interpret_functions.pike >"$@" "$<" || { rm "$@"; exit 1; }
+
 # UnixWare make needs help to find the source file...
 builtin.o: $(SRCDIR)/builtin.c
 
diff --git a/src/acconfig.h b/src/acconfig.h
index 4dedd5f53a..629819abff 100644
--- a/src/acconfig.h
+++ b/src/acconfig.h
@@ -1,5 +1,5 @@
 /*
- * $Id: acconfig.h,v 1.91 2001/07/13 18:19:06 grubba Exp $
+ * $Id: acconfig.h,v 1.92 2001/07/16 19:48:56 hubbe Exp $
  */
 #ifndef MACHINE_H
 #define MACHINE_H
@@ -239,6 +239,9 @@
 /* Define if you have gcc-style computed goto, and want to use them. */
 #undef HAVE_COMPUTED_GOTO
 
+/* Define this to use machine code */
+#undef PIKE_USE_MACHINE_CODE
+
 /* You have gcc-type function attributes? */
 #undef HAVE_FUNCTION_ATTRIBUTES
 
diff --git a/src/configure.in b/src/configure.in
index 64804870fc..2489cd7866 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.537 2001/07/13 18:19:06 grubba Exp $")
+AC_REVISION("$Id: configure.in,v 1.538 2001/07/16 19:48:56 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -989,6 +989,11 @@ AC_ARG_WITH(security,    [  --with-security        enable internal pike security
 AC_ARG_WITH(bignums,     [  --without-bignums      disable internal conversion to bignums],[],[with_bignums=yes])
 AC_ARG_WITH(shared-nodes,[  --without-shared-nodes disable the SHARED_NODES mode of the optimizer],[],[with_shared_nodes=yes])
 AC_ARG_WITH(computed-goto,[  --with-computed-goto   Enable use of gcc-style computed goto (EXPERIMENTAL).], [], [with_computed_goto=no])
+AC_ARG_WITH(computed-goto,[  --with-machine-code    Enable use of machine code when possible (EXPERIMENTAL).], [
+  if test "$with_machine_code" = "yes"; then
+    AC_DEFINE(PIKE_USE_MACHINE_CODE)
+  else :; fi
+], [])
 
 AC_ARG_WITH(keypair-loop,[  --with-keypair-loop    Enable use of the keypair mapping loop method (EXPERIMENTAL).],[
   if test "$with_keypair_loop" = "yes"; then
diff --git a/src/interpret.c b/src/interpret.c
index 40bfa6c798..fed49fbbcc 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: interpret.c,v 1.219 2001/07/13 11:26:38 grubba Exp $");
+RCSID("$Id: interpret.c,v 1.220 2001/07/16 19:48:57 hubbe Exp $");
 #include "interpret.h"
 #include "object.h"
 #include "program.h"
@@ -744,6 +744,93 @@ static int o_catch(PIKE_OPCODE_T *pc);
 #define EVAL_INSTR_RET_CHECK(x)
 #endif
 
+
+#ifdef PIKE_USE_MACHINE_CODE
+
+#define LOW_GET_JUMP()	EXTRACT_INT(PROG_COUNTER)
+#define LOW_SKIPJUMP()	(PROG_COUNTER += sizeof(INT32))
+
+/* Labels to jump to to cause eval_instruction to return */
+/* FIXME: Replace these with assembler lables */
+void *do_inter_return_label;
+void *do_escape_catch_label;
+void *dummy_label;
+
+
+#define OPCODE0(O,N,C) void PIKE_CONCAT(opcode_,O)(void) C
+#define OPCODE1(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1) C
+#define OPCODE2(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1,INT32 arg2) C
+
+#define OPCODE0_JUMP(O,N,C) void PIKE_CONCAT(opcode_,O)(void) C
+#define OPCODE1_JUMP(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1) C
+#define OPCODE2_JUMP(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1,INT32 arg2) C
+
+#define OPCODE0_TAIL(O,N,C) void PIKE_CONCAT(opcode_,O)(void) C
+#define OPCODE1_TAIL(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1) C
+#define OPCODE2_TAIL(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1,INT32 arg2) C
+
+#define OPCODE0_TAILJUMP(O,N,C) void PIKE_CONCAT(opcode_,O)(void) C
+#define OPCODE1_TAILJUMP(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1) C
+#define OPCODE2_TAILJUMP(O,N,C) void PIKE_CONCAT(opcode_,O)(INT32 arg1,INT32 arg2) C
+
+#undef HAVE_COMPUTED_GOTO
+
+#if defined(__i386__) && defined(__GNUC__)
+#define PROG_COUNTER (((unsigned char **)__builtin_frame_address(0))[1])
+
+static int eval_instruction(PIKE_OPCODE_T *pc)
+{
+  do_inter_return_label = && inter_return_label;
+  do_escape_catch_label = && inter_escape_catch_label;
+
+  /* This code does not clobber %eax, but
+   * the code jumped to does.
+   */
+  __asm__ __volatile__( "	sub $8,%%esp\n"
+			"	jmp *%0"
+			: "=m" (pc)
+			:
+			: "cc", "memory", "eax" );
+
+  /* This code is never reached, but will
+   * prevent gcc from optimizing the labels below too much
+   */
+
+  fprintf(stderr,"We have reached the end of the world!\n");
+  goto *dummy_label;
+
+  /* %%esp will be slightly buggered after
+   * returning from the function code (8 bytes off), but that
+   * should not matter to these return statements. -Hubbe
+   */
+
+ inter_return_label: return -1;
+ inter_escape_catch_label: return -2;
+}
+
+#endif
+
+#ifdef PIKE_USE_SPARC_GCC
+#define PROG_COUNTER reg_pc
+register void *reg_pc __asm__ ("%i7");
+#endif
+
+#undef DONE
+#undef FETCH
+#undef INTER_RETURN
+#undef INTER_ESCAPE_CATCH
+
+#define DONE return
+#define FETCH
+#define INTER_RETURN {PROG_COUNTER=do_inter_return_label;DONE;}
+#define INTER_ESCAPE_CATCH {PROG_COUNTER=do_escape_catch_label;DONE;}
+
+#include "interpret_functions_fixed.h"
+
+
+#else /* PIKE_USE_MACHINE_CODE */
+
+
 #ifdef HAVE_COMPUTED_GOTO
 int lookup_sort_fun(const void *a, const void *b)
 {
@@ -761,11 +848,20 @@ int lookup_sort_fun(const void *a, const void *b)
 
 #undef eval_instruction
 #define eval_instruction eval_instruction_without_debug
+
 #undef PIKE_DEBUG
+#undef NDEBUG
+#undef DO_IF_DEBUG
+#define DO_IF_DEBUG(X)
 #define print_return_value()
 #include "interpreter.h"
-#undef print_return_value
+
 #define PIKE_DEBUG
+#define NDEBUG
+#undef DO_IF_DEBUG
+#define DO_IF_DEBUG(X) X
+#undef print_return_value
+
 #undef eval_instruction
 
 static inline int eval_instruction(unsigned char *pc)
@@ -781,6 +877,9 @@ static inline int eval_instruction(unsigned char *pc)
 #include "interpreter.h"
 #endif
 
+
+#endif /* PIKE_USE_MACHINE_CODE */
+
 static void trace_return_value(void)
 {
   char *s;
@@ -2080,4 +2179,3 @@ void really_clean_up_interpret(void)
   free_all_pike_frame_blocks();
 #endif
 }
-
diff --git a/src/interpret_functions.h b/src/interpret_functions.h
index 3ab6470274..391859e31b 100644
--- a/src/interpret_functions.h
+++ b/src/interpret_functions.h
@@ -1,5 +1,5 @@
 /*
- * $Id: interpret_functions.h,v 1.75 2001/07/15 23:14:36 hubbe Exp $
+ * $Id: interpret_functions.h,v 1.76 2001/07/16 19:48:57 hubbe Exp $
  *
  * Opcode definitions for the interpreter.
  */
@@ -56,6 +56,40 @@
 #define INTER_RETURN return -1
 #endif
 
+#ifndef OVERRIDE_JUMPS
+
+#undef GET_JUMP
+#undef SKIPJUMP
+#undef DOJUMP
+
+#ifdef PIKE_DEBUG
+
+#define GET_JUMP() (backlog[backlogp].arg=(\
+  (t_flag>3 ? sprintf(trace_buffer, "-    Target = %+ld\n", \
+                      (long)LOW_GET_JUMP()), \
+              write_to_stderr(trace_buffer,strlen(trace_buffer)) : 0), \
+  LOW_GET_JUMP()))
+
+#define SKIPJUMP() (GET_JUMP(), LOW_SKIPJUMP())
+
+#else /* !PIKE_DEBUG */
+
+#define GET_JUMP() LOW_GET_JUMP()
+#define SKIPJUMP() LOW_SKIPJUMP()
+
+#endif /* PIKE_DEBUG */
+
+#define DOJUMP() do { \
+    INT32 tmp; \
+    tmp = GET_JUMP(); \
+    PROG_COUNTER += tmp; \
+    FETCH; \
+    if(tmp < 0) \
+      fast_check_threads_etc(6); \
+  } while(0)
+
+#endif /* OVERRIDE_JUMPS */
+
 
 /* WARNING:
  * The surgeon general has stated that define code blocks
@@ -1851,71 +1885,120 @@ OPCODE1_JUMP(F_COND_RECUR, "recur if not overloaded", {
   /* Assume that the number of arguments is correct */
   /* FIXME: Use new recursion stuff */
   OPCODE0_TAILJUMP(F_RECUR, "recur", {
-    instr = 0;
-
-    OPCODE0_TAILJUMP(F_RECUR_AND_POP, "recur & pop", {
-      PIKE_OPCODE_T opcode = instr;
-      PIKE_OPCODE_T *addr;
-      struct pike_frame *new_frame;
-
-      fast_check_threads_etc(6);
-      check_c_stack(8192);
-      check_stack(256);
-
-      new_frame=alloc_pike_frame();
-      new_frame[0]=Pike_fp[0];
-
-      new_frame->refs=1;
-      new_frame->next=Pike_fp;
-
-      new_frame->save_sp = new_frame->expendible =
-	new_frame->locals = *--Pike_mark_sp;
-      new_frame->num_args = new_frame->args =
-	DO_NOT_WARN((INT32)(Pike_sp - new_frame->locals));
-      new_frame->save_mark_sp = Pike_mark_sp;
-      new_frame->mark_sp_base = Pike_mark_sp;
-
-      addr = PROG_COUNTER+GET_JUMP();
-      new_frame->num_locals =
-	DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-2],
-				 EXTRACT_UCHAR(addr-2));
-
-      DO_IF_DEBUG({
-	if(new_frame->num_args !=
-	   DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-1],
-				    EXTRACT_UCHAR(addr-1)))
-	  fatal("Wrong number of arguments in F_RECUR %d!=%d\n",
-		new_frame->num_args,
-		DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-1],
-					 EXTRACT_UCHAR(addr-1)));
-
-	if(t_flag > 3)
-	  fprintf(stderr,"-    Allocating %d extra locals.\n",
-		  new_frame->num_locals - new_frame->num_args);
-      });
-
-      Pike_fp->pc = PROG_COUNTER + DO_IF_ELSE_COMPUTED_GOTO(1, sizeof(INT32));
-      PROG_COUNTER=addr;
-      FETCH;
-
-      clear_svalues(Pike_sp, new_frame->num_locals - new_frame->num_args);
-      Pike_sp += new_frame->num_locals - new_frame->args;
-
-      if(new_frame->scope) add_ref(new_frame->scope);
-      add_ref(new_frame->current_object);
-      add_ref(new_frame->context.prog);
-      if(new_frame->context.parent)
-	add_ref(new_frame->context.parent);
-      Pike_fp=new_frame;
-      new_frame->flags=PIKE_FRAME_RETURN_INTERNAL;
-      if (opcode) {
-	/* F_RECUR_AND_POP */
-	new_frame->flags|=PIKE_FRAME_RETURN_POP;
-      }
+    PIKE_OPCODE_T *addr;
+    struct pike_frame *new_frame;
+    
+    fast_check_threads_etc(6);
+    check_c_stack(8192);
+    check_stack(256);
+    
+    new_frame=alloc_pike_frame();
+    new_frame[0]=Pike_fp[0];
+    
+    new_frame->refs=1;
+    new_frame->next=Pike_fp;
+    
+    new_frame->save_sp = new_frame->expendible =
+      new_frame->locals = *--Pike_mark_sp;
+    new_frame->num_args = new_frame->args =
+      DO_NOT_WARN((INT32)(Pike_sp - new_frame->locals));
+    new_frame->save_mark_sp = Pike_mark_sp;
+    new_frame->mark_sp_base = Pike_mark_sp;
+    
+    addr = PROG_COUNTER+GET_JUMP();
+    new_frame->num_locals =
+      DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-2],
+			       EXTRACT_UCHAR(addr-2));
+    
+    DO_IF_DEBUG({
+      if(new_frame->num_args !=
+	 DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-1],
+				  EXTRACT_UCHAR(addr-1)))
+	fatal("Wrong number of arguments in F_RECUR %d!=%d\n",
+	      new_frame->num_args,
+	      DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-1],
+				       EXTRACT_UCHAR(addr-1)));
+      
+      if(t_flag > 3)
+	fprintf(stderr,"-    Allocating %d extra locals.\n",
+		new_frame->num_locals - new_frame->num_args);
     });
+    
+    Pike_fp->pc = PROG_COUNTER + DO_IF_ELSE_COMPUTED_GOTO(1, sizeof(INT32));
+    PROG_COUNTER=addr;
+    FETCH;
+    
+    clear_svalues(Pike_sp, new_frame->num_locals - new_frame->num_args);
+    Pike_sp += new_frame->num_locals - new_frame->args;
+    
+    if(new_frame->scope) add_ref(new_frame->scope);
+    add_ref(new_frame->current_object);
+    add_ref(new_frame->context.prog);
+    if(new_frame->context.parent)
+      add_ref(new_frame->context.parent);
+    Pike_fp=new_frame;
+    new_frame->flags=PIKE_FRAME_RETURN_INTERNAL;
+  });
+});
+
+/* Ugly code duplication */
+OPCODE0_JUMP(F_RECUR_AND_POP, "recur & pop", {
+  PIKE_OPCODE_T *addr;
+  struct pike_frame *new_frame;
+  
+  fast_check_threads_etc(6);
+  check_c_stack(8192);
+  check_stack(256);
+  
+  new_frame=alloc_pike_frame();
+  new_frame[0]=Pike_fp[0];
+  
+  new_frame->refs=1;
+  new_frame->next=Pike_fp;
+  
+  new_frame->save_sp = new_frame->expendible =
+    new_frame->locals = *--Pike_mark_sp;
+  new_frame->num_args = new_frame->args =
+    DO_NOT_WARN((INT32)(Pike_sp - new_frame->locals));
+  new_frame->save_mark_sp = Pike_mark_sp;
+  new_frame->mark_sp_base = Pike_mark_sp;
+  
+  addr = PROG_COUNTER+GET_JUMP();
+  new_frame->num_locals =
+    DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-2],
+			     EXTRACT_UCHAR(addr-2));
+  
+  DO_IF_DEBUG({
+    if(new_frame->num_args !=
+       DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-1],
+				EXTRACT_UCHAR(addr-1)))
+      fatal("Wrong number of arguments in F_RECUR %d!=%d\n",
+	    new_frame->num_args,
+	    DO_IF_ELSE_COMPUTED_GOTO((ptrdiff_t)addr[-1],
+				     EXTRACT_UCHAR(addr-1)));
+    
+    if(t_flag > 3)
+      fprintf(stderr,"-    Allocating %d extra locals.\n",
+	      new_frame->num_locals - new_frame->num_args);
   });
+  
+  Pike_fp->pc = PROG_COUNTER + DO_IF_ELSE_COMPUTED_GOTO(1, sizeof(INT32));
+  PROG_COUNTER=addr;
+  FETCH;
+  
+  clear_svalues(Pike_sp, new_frame->num_locals - new_frame->num_args);
+  Pike_sp += new_frame->num_locals - new_frame->args;
+  
+  if(new_frame->scope) add_ref(new_frame->scope);
+  add_ref(new_frame->current_object);
+  add_ref(new_frame->context.prog);
+  if(new_frame->context.parent)
+    add_ref(new_frame->context.parent);
+  Pike_fp=new_frame;
+  new_frame->flags=PIKE_FRAME_RETURN_INTERNAL | PIKE_FRAME_RETURN_POP;
 });
 
+
 /* Assume that the number of arguments is correct */
 /* FIXME: adjust Pike_mark_sp */
 OPCODE0_JUMP(F_TAIL_RECUR, "tail recursion", {
diff --git a/src/interpreter.h b/src/interpreter.h
index d88de1b1a5..28ccb89dad 100644
--- a/src/interpreter.h
+++ b/src/interpreter.h
@@ -14,20 +14,20 @@
 #ifdef HAVE_COMPUTED_GOTO
 
 #define CASE(OP)	PIKE_CONCAT(LABEL_,OP): FETCH
-#define FETCH		(instr = pc[0])
+#define FETCH		(instr = PROG_COUNTER[0])
 #ifdef PIKE_DEBUG
 #define DONE		continue
 #else /* !PIKE_DEBUG */
 #define DONE		do {	\
-    Pike_fp->pc = pc++;		\
+    Pike_fp->pc = PROG_COUNTER++;		\
     goto *instr;		\
   } while(0)
     
 #endif /* PIKE_DEBUG */
 
-#define LOW_GET_ARG()	((INT32)(ptrdiff_t)(*(pc++)))
-#define LOW_GET_JUMP()	((INT32)(ptrdiff_t)(*(pc)))
-#define LOW_SKIPJUMP()	(instr = (++pc)[0])
+#define LOW_GET_ARG()	((INT32)(ptrdiff_t)(*(PROG_COUNTER++)))
+#define LOW_GET_JUMP()	((INT32)(ptrdiff_t)(*(PROG_COUNTER)))
+#define LOW_SKIPJUMP()	(instr = (++PROG_COUNTER)[0])
 
 #define GET_ARG()	LOW_GET_ARG()
 #define GET_ARG2()	LOW_GET_ARG()
@@ -38,9 +38,9 @@
 #define DONE		break
 #define FETCH
 
-#define LOW_GET_ARG()	((pc++)[0])
-#define LOW_GET_JUMP()	EXTRACT_INT(pc)
-#define LOW_SKIPJUMP()	(pc += sizeof(INT32))
+#define LOW_GET_ARG()	((PROG_COUNTER++)[0])
+#define LOW_GET_JUMP()	EXTRACT_INT(PROG_COUNTER)
+#define LOW_SKIPJUMP()	(PROG_COUNTER += sizeof(INT32))
 
 #ifdef PIKE_DEBUG
 
@@ -71,32 +71,6 @@
 
 #endif /* HAVE_COMPUTED_GOTO */
 
-#ifdef PIKE_DEBUG
-
-#define GET_JUMP() (backlog[backlogp].arg=(\
-  (t_flag>3 ? sprintf(trace_buffer, "-    Target = %+ld\n", \
-                      (long)LOW_GET_JUMP()), \
-              write_to_stderr(trace_buffer,strlen(trace_buffer)) : 0), \
-  LOW_GET_JUMP()))
-
-#define SKIPJUMP() (GET_JUMP(), LOW_SKIPJUMP())
-
-#else /* !PIKE_DEBUG */
-
-#define GET_JUMP() LOW_GET_JUMP()
-#define SKIPJUMP() LOW_SKIPJUMP()
-
-#endif /* PIKE_DEBUG */
-
-#define DOJUMP() do { \
-    INT32 tmp; \
-    tmp = GET_JUMP(); \
-    pc += tmp; \
-    FETCH; \
-    if(tmp < 0) \
-      fast_check_threads_etc(6); \
-  } while(0)
-
 #ifndef STEP_BREAK_LINE
 #define STEP_BREAK_LINE
 #endif
diff --git a/src/las.c b/src/las.c
index 59402556f4..4d48eeba8b 100644
--- a/src/las.c
+++ b/src/las.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: las.c,v 1.256 2001/07/13 14:29:56 grubba Exp $");
+RCSID("$Id: las.c,v 1.257 2001/07/16 19:48:58 hubbe Exp $");
 
 #include "language.h"
 #include "interpret.h"
@@ -4975,6 +4975,8 @@ ptrdiff_t eval_low(node *n)
     foo.counter=10000;
     foo.yes=0;
 
+    make_program_executable(Pike_compiler->new_program);
+
     tmp_callback=add_to_callback(&evaluator_callbacks,
 				 check_evaluation_time,
 				 (void *)&foo,0);
diff --git a/src/lex.c b/src/lex.c
index e075ffd75b..4e434ff346 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.97 2001/07/15 23:14:37 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.98 2001/07/16 19:48:58 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -145,21 +145,64 @@ void exit_lex(void)
 #endif
 }
 
-#define OPCODE0(OP,DESC) { DESC, OP, 0 },
-#define OPCODE1(OP,DESC) { DESC, OP, I_HASARG },
-#define OPCODE2(OP,DESC) { DESC, OP, I_TWO_ARGS },
+#ifdef PIKE_USE_MACHINE_CODE
+#define ADDR(X) , (void *)PIKE_CONCAT(opcode_,X)
+#define NULLADDR , 0
 
-#define OPCODE0_TAIL(OP,DESC) { DESC, OP, 0 },
-#define OPCODE1_TAIL(OP,DESC) { DESC, OP, I_HASARG },
-#define OPCODE2_TAIL(OP,DESC) { DESC, OP, I_TWO_ARGS },
+#define OPCODE0(OP,DESC) void PIKE_CONCAT(opcode_,OP)(void);
+#define OPCODE1(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32);
+#define OPCODE2(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32,INT32);
 
-#define OPCODE0_JUMP(OP,DESC) { DESC, OP, I_ISJUMP },
-#define OPCODE1_JUMP(OP,DESC) { DESC, OP, I_HASARG },
-#define OPCODE2_JUMP(OP,DESC) { DESC, OP, I_TWO_ARGS },
+#define OPCODE0_TAIL(OP,DESC) void PIKE_CONCAT(opcode_,OP)(void);
+#define OPCODE1_TAIL(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32);
+#define OPCODE2_TAIL(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32,INT32);
 
-#define OPCODE0_TAILJUMP(OP,DESC) { DESC, OP, I_ISJUMP },
-#define OPCODE1_TAILJUMP(OP,DESC) { DESC, OP, I_HASARG },
-#define OPCODE2_TAILJUMP(OP,DESC) { DESC, OP, I_TWO_ARGS },
+#define OPCODE0_JUMP(OP,DESC) void PIKE_CONCAT(opcode_,OP)(void);
+#define OPCODE1_JUMP(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32);
+#define OPCODE2_JUMP(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32,INT32);
+
+#define OPCODE0_TAILJUMP(OP,DESC) void PIKE_CONCAT(opcode_,OP)(void);
+#define OPCODE1_TAILJUMP(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32);
+#define OPCODE2_TAILJUMP(OP,DESC) void PIKE_CONCAT(opcode_,OP)(INT32,INT32);
+
+#include "interpret_protos.h"
+
+#undef OPCODE0
+#undef OPCODE1
+#undef OPCODE2
+
+#undef OPCODE0_TAIL
+#undef OPCODE1_TAIL
+#undef OPCODE2_TAIL
+
+#undef OPCODE0_JUMP
+#undef OPCODE1_JUMP
+#undef OPCODE2_JUMP
+
+#undef OPCODE0_TAILJUMP
+#undef OPCODE1_TAILJUMP
+#undef OPCODE2_TAILJUMP
+
+#else
+#define ADDR(X)
+#define NULLADDR
+#endif
+
+#define OPCODE0(OP,DESC) { DESC, OP, 0 ADDR(OP) },
+#define OPCODE1(OP,DESC) { DESC, OP, I_HASARG ADDR(OP) },
+#define OPCODE2(OP,DESC) { DESC, OP, I_TWO_ARGS ADDR(OP) },
+
+#define OPCODE0_TAIL(OP,DESC) { DESC, OP, 0 ADDR(OP) },
+#define OPCODE1_TAIL(OP,DESC) { DESC, OP, I_HASARG ADDR(OP) },
+#define OPCODE2_TAIL(OP,DESC) { DESC, OP, I_TWO_ARGS ADDR(OP) },
+
+#define OPCODE0_JUMP(OP,DESC) { DESC, OP, I_ISJUMP ADDR(OP) },
+#define OPCODE1_JUMP(OP,DESC) { DESC, OP, I_HASARG ADDR(OP) },
+#define OPCODE2_JUMP(OP,DESC) { DESC, OP, I_TWO_ARGS ADDR(OP) },
+
+#define OPCODE0_TAILJUMP(OP,DESC) { DESC, OP, I_ISJUMP ADDR(OP) },
+#define OPCODE1_TAILJUMP(OP,DESC) { DESC, OP, I_HASARG ADDR(OP) },
+#define OPCODE2_TAILJUMP(OP,DESC) { DESC, OP, I_TWO_ARGS ADDR(OP) },
 
 #define LEXER
 
@@ -168,48 +211,48 @@ struct keyword instr_names[]=
 #ifndef PIKE_PRECOMPILER
 #include "interpret_protos.h"
 #endif /* !PIKE_PRECOMPILER */
-{ "%=",			F_MOD_EQ,0 },	
-{ "&=",			F_AND_EQ,0 },	
-{ "|=",			F_OR_EQ,0 },	
-{ "*=",			F_MULT_EQ,0 },	
-{ "+=",			F_ADD_EQ,0 },	
-{ "-=",			F_SUB_EQ,0 },	
-{ "/=",			F_DIV_EQ,0 },	
-{ "<<=",		F_LSH_EQ,0 },	
-{ ">>=",		F_RSH_EQ,0 },	
-{ "^=",			F_XOR_EQ,0 },	
-{ "arg+=1024",		F_PREFIX_1024,0 },
-{ "arg+=256",		F_PREFIX_256,0 },
-{ "arg+=256*X",		F_PREFIX_CHARX256,0 },
-{ "arg+=256*XX",	F_PREFIX_WORDX256,0 },
-{ "arg+=256*XXX",	F_PREFIX_24BITX256,0 },
-{ "arg+=512",		F_PREFIX_512,0 },
-{ "arg+=768",		F_PREFIX_768,0 },
-
-{ "arg+=1024",		F_PREFIX2_1024,0 },
-{ "arg+=256",		F_PREFIX2_256,0 },
-{ "arg+=256*X",		F_PREFIX2_CHARX256,0 },
-{ "arg+=256*XX",	F_PREFIX2_WORDX256,0 },
-{ "arg+=256*XXX",	F_PREFIX2_24BITX256,0 },
-{ "arg+=512",		F_PREFIX2_512,0 },
-{ "arg+=768",		F_PREFIX2_768,0 },
-
-{ "break",		F_BREAK,0 },	
-{ "case",		F_CASE,0 },	
-{ "continue",		F_CONTINUE,0 },	
-{ "default",		F_DEFAULT,0 },	
-{ "do-while",		F_DO,0 },	
-{ "for",		F_FOR,0 },
-
-{ "pointer",		F_POINTER, I_ISPOINTER },
-{ "data",		F_DATA, I_DATA },
-{ "byte",		F_BYTE, I_DATA },
-{ "lvalue_list",	F_LVALUE_LIST,0 },	
-{ "label",		F_LABEL,I_HASARG },
-{ "align",		F_ALIGN, I_HASARG },
-{ "nop",                F_NOP,0 },
-{ "function start",     F_START_FUNCTION,0 },
-{ "notreached!",        F_NOTREACHED, 0 },
+{ "%=",			F_MOD_EQ,0 NULLADDR },	
+{ "&=",			F_AND_EQ,0 NULLADDR },	
+{ "|=",			F_OR_EQ,0 NULLADDR },	
+{ "*=",			F_MULT_EQ,0 NULLADDR },	
+{ "+=",			F_ADD_EQ,0 NULLADDR },	
+{ "-=",			F_SUB_EQ,0 NULLADDR },	
+{ "/=",			F_DIV_EQ,0 NULLADDR },	
+{ "<<=",		F_LSH_EQ,0 NULLADDR },	
+{ ">>=",		F_RSH_EQ,0 NULLADDR },	
+{ "^=",			F_XOR_EQ,0 NULLADDR },	
+{ "arg+=1024",		F_PREFIX_1024,0 NULLADDR },
+{ "arg+=256",		F_PREFIX_256,0 NULLADDR },
+{ "arg+=256*X",		F_PREFIX_CHARX256,0 NULLADDR },
+{ "arg+=256*XX",	F_PREFIX_WORDX256,0 NULLADDR },
+{ "arg+=256*XXX",	F_PREFIX_24BITX256,0 NULLADDR },
+{ "arg+=512",		F_PREFIX_512,0 NULLADDR },
+{ "arg+=768",		F_PREFIX_768,0 NULLADDR },
+
+{ "arg+=1024",		F_PREFIX2_1024,0 NULLADDR },
+{ "arg+=256",		F_PREFIX2_256,0 NULLADDR },
+{ "arg+=256*X",		F_PREFIX2_CHARX256,0 NULLADDR },
+{ "arg+=256*XX",	F_PREFIX2_WORDX256,0 NULLADDR },
+{ "arg+=256*XXX",	F_PREFIX2_24BITX256,0 NULLADDR },
+{ "arg+=512",		F_PREFIX2_512,0 NULLADDR },
+{ "arg+=768",		F_PREFIX2_768,0 NULLADDR },
+
+{ "break",		F_BREAK,0 NULLADDR },	
+{ "case",		F_CASE,0 NULLADDR },	
+{ "continue",		F_CONTINUE,0 NULLADDR },	
+{ "default",		F_DEFAULT,0 NULLADDR },	
+{ "do-while",		F_DO,0 NULLADDR },	
+{ "for",		F_FOR,0 NULLADDR },
+
+{ "pointer",		F_POINTER, I_ISPOINTER NULLADDR },
+{ "data",		F_DATA, I_DATA NULLADDR },
+{ "byte",		F_BYTE, I_DATA NULLADDR },
+{ "lvalue_list",	F_LVALUE_LIST,0 NULLADDR },	
+{ "label",		F_LABEL,I_HASARG NULLADDR },
+{ "align",		F_ALIGN, I_HASARG NULLADDR },
+{ "nop",                F_NOP,0 NULLADDR },
+{ "function start",     F_START_FUNCTION,0 NULLADDR },
+{ "notreached!",        F_NOTREACHED, 0 NULLADDR },
 };
 
 struct instr instrs[F_MAX_INSTR - F_OFFSET];
@@ -248,6 +291,9 @@ void init_lex()
 
     instrs[instr_names[i].token - F_OFFSET].name = instr_names[i].word;
     instrs[instr_names[i].token - F_OFFSET].flags=instr_names[i].flags;
+#ifdef PIKE_USE_MACHINE_CODE
+    instrs[instr_names[i].token - F_OFFSET].address=instr_names[i].address;
+#endif
   }
 
 #ifdef PIKE_DEBUG
diff --git a/src/lex.h b/src/lex.h
index 96a47efe29..013e5cc290 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: lex.h,v 1.18 2001/07/09 14:19:16 grubba Exp $
+ * $Id: lex.h,v 1.19 2001/07/16 19:48:58 hubbe Exp $
  */
 #ifndef LEX_H
 #define LEX_H
@@ -17,6 +17,9 @@ struct keyword
   char *word;
   int token;
   int flags;
+#ifdef PIKE_USE_MACHINE_CODE
+  void *address;
+#endif
 };
 
 #define I_HASARG 1
@@ -40,6 +43,9 @@ struct instr
 #endif
   int flags;
   char *name;
+#ifdef PIKE_USE_MACHINE_CODE
+  void *address;
+#endif
 };
 
 #ifdef PIKE_DEBUG
diff --git a/src/peep.c b/src/peep.c
index d005636506..02020591f7 100644
--- a/src/peep.c
+++ b/src/peep.c
@@ -17,7 +17,7 @@
 #include "builtin_functions.h"
 #include "constants.h"
 
-RCSID("$Id: peep.c,v 1.53 2001/07/09 14:19:16 grubba Exp $");
+RCSID("$Id: peep.c,v 1.54 2001/07/16 19:48:59 hubbe Exp $");
 
 static void asm_opt(void);
 
@@ -135,6 +135,22 @@ void update_arg(int instr,INT32 arg)
 
 /**** Bytecode Generator *****/
 
+
+#if defined(__i386__) && defined(__GNUC__)
+
+#define PUSH_INT(X) ins_int((INT32)(X), add_to_program)
+#define PUSH_ADDR(X) PUSH_INT((X))
+#define PUSHL(X) add_to_program(0x68),PUSH_INT((X)
+#define CALL_ABSOLUTE(X) add_to_program(0x9a),PUSH_ADDR((X))
+#define RET() add_to_program(0xc3);
+#define POP(X) \
+  add_to_program(0x83),  /* Addl.b 0x4, %esp */ \
+  add_to_program(0xc4), \
+  add_to_program(-X)
+
+#endif
+
+
 void ins_f_byte(unsigned int b)
 {
 #ifdef PIKE_DEBUG
@@ -147,6 +163,14 @@ void ins_f_byte(unsigned int b)
   if(b>255)
     Pike_error("Instruction too big %d\n",b);
 #endif
+
+#ifdef PIKE_USE_MACHINE_CODE
+#if defined(__i386__) && defined(__GNUC__)
+  CALL_ABSOLUTE(instrs[b].address);
+  return
+#endif
+#endif
+
 #ifdef HAVE_COMPUTED_GOTO
   add_to_program(fcode_to_opcode[b]);
 #else /* !HAVE_COMPUTED_GOTO */
@@ -156,6 +180,17 @@ void ins_f_byte(unsigned int b)
 
 static void ins_f_byte_with_arg(unsigned int a,unsigned INT32 b)
 {
+#ifdef PIKE_USE_MACHINE_CODE
+#if defined(__i386__) && defined(__GNUC__)
+  add_to_program(0xc7);  /* movl $xxxx, (%esp) */
+  add_to_program(0x04); 
+  add_to_program(0x24); 
+  PUSH_INT(b);
+  ins_f_byte(a);
+  return;
+#endif
+#endif
+
 #ifndef HAVE_COMPUTED_GOTO
   switch(b >> 8)
   {
@@ -189,7 +224,19 @@ static void ins_f_byte_with_2_args(unsigned int a,
 				   unsigned INT32 c,
 				   unsigned INT32 b)
 {
-#ifndef HAVE_COMPUTED_GOTO
+#ifdef PIKE_USE_MACHINE_CODE
+#if defined(__i386__) && defined(__GNUC__)
+  add_to_program(0xc7);  /* movl $xxxx, 4(%esp) */
+  add_to_program(0x44);
+  add_to_program(0x24);
+  add_to_program(0x04);
+  PUSH_INT(c);
+  ins_f_byte_with_arg(a,b);
+  return
+#endif
+#endif
+
+#ifdef HAVE_COMPUTED_GOTO
   switch(b >> 8)
   {
   case 0 : break;
diff --git a/src/program.c b/src/program.c
index 6eed93cc8a..4be097b974 100644
--- a/src/program.c
+++ b/src/program.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: program.c,v 1.353 2001/07/13 11:26:39 grubba Exp $");
+RCSID("$Id: program.c,v 1.354 2001/07/16 19:48:59 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -991,7 +991,11 @@ void optimize_program(struct program *p)
 #include "program_areas.h"
 
   data=malloc(size);
-  if(!data) return; /* We are out of memory, but we don't care! */
+  if(!data) 
+  {
+    make_program_executable(p);
+    return; /* We are out of memory, but we don't care! */
+  }
 
   size=0;
 
@@ -1006,6 +1010,7 @@ void optimize_program(struct program *p)
   p->total_size=size + sizeof(struct program);
 
   p->flags |= PROGRAM_OPTIMIZED;
+  make_program_executable(p);
 }
 
 /* internal function to make the index-table */
@@ -3995,6 +4000,20 @@ void store_linenumber(INT32 current_line, struct pike_string *current_file)
   if(Pike_compiler->last_line != current_line ||
      Pike_compiler->last_file != current_file)
   {
+#ifdef PIKE_USE_MACHINE_CODE
+#if defined(__i386__) && defined(__GNUC__)
+    /* We need to update Pike_interpreter.frame_pointer->pc */
+    INT32 tmp=PC;
+    add_to_program(0x4c /* mov $xxxxx, %eax */);
+    ins_int((INT32)(&Pike_interpreter.frame_pointer), add_to_program);
+
+    add_to_program(0xc7); /* movl $xxxxx, yy%(eax) */
+    add_to_program(0x40);
+    add_to_program(OFFSETOF(pike_frame, pc));
+    ins_int((INT32)tmp, add_to_program);
+#endif
+#endif
+
     if((Pike_compiler->last_file != current_file) ||
        (DO_NOT_WARN((INT32)(PC - Pike_compiler->last_pc)) == 127))
     {
@@ -5484,7 +5503,6 @@ PMOD_EXPORT void *parent_storage(int depth)
 }
 
 
-
 PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
 {
   if(major == Pike_compiler->compat_major &&
@@ -5563,3 +5581,15 @@ PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
   Pike_compiler->compat_major=major;
   Pike_compiler->compat_minor=minor;
 }
+
+#ifdef PIKE_USE_MACHINE_CODE
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+void make_program_executable(struct program *p)
+{
+  mprotect(p->program, p->num_program, PROT_EXEC | PROT_READ | PROT_WRITE);
+}
+#endif
diff --git a/src/program.h b/src/program.h
index 8f94190df2..37d023b16b 100644
--- a/src/program.h
+++ b/src/program.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: program.h,v 1.138 2001/07/13 11:26:39 grubba Exp $
+ * $Id: program.h,v 1.139 2001/07/16 19:48:59 hubbe Exp $
  */
 #ifndef PROGRAM_H
 #define PROGRAM_H
@@ -563,8 +563,13 @@ PMOD_EXPORT int is_compatible(struct program *a, struct program *b);
 int yyexplain_not_implements(struct program *a, struct program *b, int flags);
 PMOD_EXPORT void *parent_storage(int depth);
 PMOD_EXPORT void change_compiler_compatibility(int major, int minor);
+void make_program_executable(struct program *p);
 /* Prototypes end here */
 
+#ifndef PIKE_USE_MACHINE_CODE
+#define make_program_executable(X)
+#endif
+
 #define ADD_FUNCTION(NAME, FUNC, TYPE, FLAGS) \
   quick_add_function(NAME, CONSTANT_STRLEN(NAME), FUNC, TYPE,\
                      CONSTANT_STRLEN(TYPE), FLAGS, \
-- 
GitLab