diff --git a/src/docode.c b/src/docode.c
index 62343a50fd519db008efd348fb6e4d0c2bdb11c4..52b7c01d08a646f691b8bc60118746672a3399e9 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: docode.c,v 1.68 2000/04/20 02:41:44 hubbe Exp $");
+RCSID("$Id: docode.c,v 1.69 2000/04/25 09:32:45 hubbe Exp $");
 #include "las.h"
 #include "program.h"
 #include "language.h"
@@ -200,6 +200,30 @@ static inline struct compiler_frame *find_local_frame(INT32 depth)
   return f;
 }
 
+int do_lfun_call(int id,node *args)
+{
+#if 1
+  if(id == compiler_frame->current_function_number)
+  {
+    if(new_program->identifier_references[id].id_flags & ID_INLINE)
+    {
+      int n=count_args(args);
+      if(n == count_arguments(ID_FROM_INT(new_program, id) -> type))
+      {
+	emit0(F_MARK);
+	do_docode(args,0);
+	emit1(F_RECUR,0); /* 0 is label at beginning of function */
+	return 1;
+      }
+    }
+  }
+#endif
+  emit0(F_MARK);
+  do_docode(args,0);
+  emit1(F_CALL_LFUN, id);
+  return 1;
+}
+
 static int do_docode2(node *n,int flags)
 {
   INT32 tmp1,tmp2,tmp3;
@@ -743,12 +767,7 @@ static int do_docode2(node *n,int flags)
 	  return 1;
 	}else{
 	  if(CAR(n)->u.sval.u.object == fake_object)
-	  {
-	    emit0(F_MARK);
-	    do_docode(CDR(n),0);
-	    emit1(F_CALL_LFUN, CAR(n)->u.sval.subtype);
-	    return 1;
-	  }
+	    return do_lfun_call(CAR(n)->u.sval.subtype,CDR(n));
        	}
       }
 
@@ -762,12 +781,10 @@ static int do_docode2(node *n,int flags)
       return 1;
     }
     else if(CAR(n)->token == F_IDENTIFIER &&
-	    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(new_program, CAR(n)->u.id.number)->identifier_flags))
+	    IDENTIFIER_IS_FUNCTION(ID_FROM_INT(new_program,
+					       CAR(n)->u.id.number)->identifier_flags))
     {
-      emit0(F_MARK);
-      do_docode(CDR(n),0);
-      emit1(F_CALL_LFUN, CAR(n)->u.id.number);
-      return 1;
+      return do_lfun_call(CAR(n)->u.id.number,CDR(n));
     }
     else
     {
@@ -1277,7 +1294,8 @@ static int do_docode2(node *n,int flags)
 void do_code_block(node *n)
 {
   init_bytecode();
-  label_no=0;
+  label_no=1;
+  emit1(F_LABEL,0);
   DO_CODE_BLOCK(n);
   assemble();
 }
@@ -1289,7 +1307,7 @@ int docode(node *n)
   dynamic_buffer instrbuf_save = instrbuf;
 
   instrbuf.s.str=0;
-  label_no=0;
+  label_no=1;
   init_bytecode();
 
   tmp=do_docode(n,0);
diff --git a/src/interpret.c b/src/interpret.c
index 9e9910531b176f180251c0957f71ea916a62c5c9..777e81e25a7a7dbb7c213079770f5a5eadfefd3d 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: interpret.c,v 1.147 2000/04/21 23:07:10 hubbe Exp $");
+RCSID("$Id: interpret.c,v 1.148 2000/04/25 09:32:46 hubbe Exp $");
 #include "interpret.h"
 #include "object.h"
 #include "program.h"
@@ -1068,10 +1068,8 @@ void mega_apply2(enum apply_type type, INT32 args, void *arg1, void *arg2)
 	num_locals=EXTRACT_UCHAR(pc++);
 	num_args=EXTRACT_UCHAR(pc++);
 
-	/* FIXME: this is only needed if this function contains
-	 * trampolines
-	 */
-	new_frame->expendible+=num_locals;
+	if(function->identifier_flags & IDENTIFIER_SCOPED)
+	  new_frame->expendible+=num_locals;
 	
 	/* adjust arguments on stack */
 	if(args < num_args) /* push zeros */
diff --git a/src/interpret_functions.h b/src/interpret_functions.h
index e9903ee4d89e91de956f544b7797764a7c06529e..7fd30b9027902c287511e839afaba9b1de0cc723 100644
--- a/src/interpret_functions.h
+++ b/src/interpret_functions.h
@@ -1,5 +1,5 @@
 /*
- * $Id: interpret_functions.h,v 1.15 2000/04/21 00:29:48 hubbe Exp $
+ * $Id: interpret_functions.h,v 1.16 2000/04/25 09:32:46 hubbe Exp $
  *
  * Opcode definitions for the interpreter.
  */
@@ -996,29 +996,31 @@ BREAK;
 	return args+1;
       }
 
-      CASE(F_CALL_LFUN_AND_RETURN);
-      {
-	INT32 args=Pike_sp - *--Pike_mark_sp;
-	if(Pike_fp->expendible >= Pike_sp-args)
-	{
-	  MEMMOVE(Pike_sp-args+1,Pike_sp-args,args*sizeof(struct svalue));
-	  Pike_sp++;
-	  Pike_sp[-args-1].type=PIKE_T_INT;
-	}else{
-	  free_svalue(Pike_sp-args-1);
-	}
-	/* More stack sabotage */
-	Pike_sp[-args-1].u.object=Pike_fp->current_object;
-	Pike_sp[-args-1].subtype=GET_ARG()+Pike_fp->context.identifier_level;
+OPCODE1(F_CALL_LFUN_AND_RETURN,"call lfun & return")
+{
+  INT32 args=sp - *--Pike_mark_sp;
+
+  if(Pike_fp->expendible >= Pike_sp-args)
+  {
+    MEMMOVE(Pike_sp-args+1,Pike_sp-args,args*sizeof(struct svalue));
+    Pike_sp++;
+    Pike_sp[-args-1].type=PIKE_T_INT;
+  }else{
+    free_svalue(Pike_sp-args-1);
+  }
+  /* More stack sabotage */
+  Pike_sp[-args-1].u.object=Pike_fp->current_object;
+  Pike_sp[-args-1].subtype=arg1+Pike_fp->context.identifier_level;
 #ifdef PIKE_DEBUG
-	if(t_flag > 9)
-	  fprintf(stderr,"-    IDENTIFIER_LEVEL: %d\n",Pike_fp->context.identifier_level);
+  if(t_flag > 9)
+    fprintf(stderr,"-    IDENTIFIER_LEVEL: %d\n",Pike_fp->context.identifier_level);
 #endif
-	Pike_sp[-args-1].type=PIKE_T_FUNCTION;
-	add_ref(Pike_fp->current_object);
-
-	return args+1;
-      }
+  Pike_sp[-args-1].type=PIKE_T_FUNCTION;
+  add_ref(Pike_fp->current_object);
+  
+  return args+1;
+}
+BREAK
 
       CASE(F_RETURN_LOCAL);
       instr=GET_ARG();
@@ -1157,13 +1159,31 @@ OPCODE0(F_MOD, "%")
 BREAK;
 
 OPCODE1(F_ADD_INT, "add integer")
-  push_int(arg1);
-  f_add(2);
+  if(sp[-1].type == T_INT
+#ifdef AUTO_BIGNUM
+      && (!INT_TYPE_ADD_OVERFLOW(sp[-1].u.integer, arg1))
+#endif
+     )
+  {
+    sp[-1].u.integer+=arg1;
+  }else{
+    push_int(arg1);
+    f_add(2);
+  }
 BREAK;
 
 OPCODE1(F_ADD_NEG_INT, "add -integer")
-  push_int(-arg1);
-  f_add(2);
+  if(sp[-1].type == T_INT
+#ifdef AUTO_BIGNUM
+      && (!INT_TYPE_ADD_OVERFLOW(sp[-1].u.integer, -arg1))
+#endif
+     )
+  {
+    sp[-1].u.integer-=arg1;
+  }else{
+    push_int(-arg1);
+    f_add(2);
+  }
 BREAK;
 
 OPCODE0(F_PUSH_ARRAY, "@")
@@ -1464,3 +1484,84 @@ BREAK;
       return args;
     }
 
+
+/* Assume that the number of arguments is correct */
+OPCODE0_JUMP(F_RECUR,"recur")
+{
+  int x,num_locals,args;
+  char *addr;
+  struct svalue *expendible=fp->expendible;
+  struct svalue *locals=fp->locals;
+  struct svalue *save_sp;
+
+  fast_check_threads_etc(6);
+  check_c_stack(8192);
+  check_stack(256);
+
+  save_sp=fp->expendible=fp->locals=*--Pike_mark_sp;
+  args=sp-fp->locals;
+
+  addr=pc+EXTRACT_INT(pc);
+  num_locals=EXTRACT_UCHAR(addr-1);
+
+#ifdef PIKE_DEBUG
+  if(args != EXTRACT_UCHAR(addr-2))
+    fatal("Wrong number of arguments in F_RECUR %d!=%d\n",args,EXTRACT_UCHAR(addr-2));
+#endif
+
+  clear_svalues(sp, num_locals - args);
+  sp += num_locals - args;
+
+  x=eval_instruction(addr);
+  if(x!=-1) mega_apply(APPLY_STACK, x, 0,0);
+  pc+=sizeof(INT32);
+  if(save_sp+1 < sp)
+  {
+    assign_svalue(save_sp,sp-1);
+    pop_n_elems(sp-save_sp-1);
+  }
+  fp->expendible=expendible;
+  fp->locals=locals;
+  print_return_value();
+#ifdef PIKE_DEBUG
+  if(sp != save_sp+1)
+    fatal("Stack whack in F_RECUR sp=%p, expected=%p\n",sp,save_sp+1);
+#endif
+}
+BREAK
+
+/* Assume that the number of arguments is correct */
+OPCODE0_JUMP(F_TAIL_RECUR,"tail recursion")
+{
+  int x,num_locals;
+  char *addr;
+  int args=sp - *--mark_sp;
+
+  fast_check_threads_etc(6);
+
+  addr=pc+EXTRACT_INT(pc);
+  num_locals=EXTRACT_UCHAR(addr-1);
+
+
+#ifdef PIKE_DEBUG
+  if(args != EXTRACT_UCHAR(addr-2))
+    fatal("Wrong number of arguments in F_TAIL_RECUR %d != %d\n",args,EXTRACT_UCHAR(addr-2));
+#endif
+
+  if(sp-args != fp->locals)
+  {
+    assign_svalues(fp->locals, sp-args, args, BIT_MIXED);
+    pop_n_elems(sp - (fp->locals + args));
+  }
+
+  clear_svalues(sp, num_locals - args);
+  sp += num_locals - args;
+
+#ifdef PIKE_DEBUG
+  if(sp != fp->locals + fp->num_locals)
+    fatal("Sp whacked!\n");
+#endif
+
+  pc=addr;
+}
+BREAK
diff --git a/src/language.yacc b/src/language.yacc
index b20a0652f842bff25b92da318d0c329c131e0493..95083e795aacf870408229794d3f7d7f2820b74d 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -33,6 +33,7 @@
 %token F_BRANCH_IF_NOT_LOCAL_ARROW
 %token F_INC_LOOP F_DEC_LOOP
 %token F_INC_NEQ_LOOP F_DEC_NEQ_LOOP
+%token F_RECUR F_TAIL_RECUR
 
 %token F_LEXICAL_LOCAL F_LEXICAL_LOCAL_LVALUE
 
@@ -192,7 +193,7 @@
 /* This is the grammar definition of Pike. */
 
 #include "global.h"
-RCSID("$Id: language.yacc,v 1.180 2000/04/20 02:41:45 hubbe Exp $");
+RCSID("$Id: language.yacc,v 1.181 2000/04/25 09:32:46 hubbe Exp $");
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
 #endif
@@ -710,13 +711,17 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER push_compiler_frame0
       free_string(s);
     }
 
-    if(compiler_pass==1)
+/*    if(compiler_pass==1) */
     {
-      $<number>5=define_function(check_node_hash($4)->u.sval.u.string,
-				 check_node_hash($<n>$)->u.sval.u.string,
-				 $1 & (~ID_EXTERN),
-				 IDENTIFIER_PIKE_FUNCTION,
-				 0);
+      /* FIXME:
+       * set current_function_number for local functions as well
+       */
+      compiler_frame->current_function_number=
+	define_function(check_node_hash($4)->u.sval.u.string,
+			check_node_hash($<n>$)->u.sval.u.string,
+			$1 & (~ID_EXTERN),
+			IDENTIFIER_PIKE_FUNCTION,
+			0);
     }
   }
   block_or_semi
@@ -778,14 +783,16 @@ def: modifiers type_or_error optional_stars F_IDENTIFIER push_compiler_frame0
       lex.current_file = save_file;
 #endif /* PIKE_DEBUG */
 
-      f=dooptcode(check_node_hash($4)->u.sval.u.string, check_node_hash($10),
-		  check_node_hash($<n>9)->u.sval.u.string, $1);
+      f=dooptcode(check_node_hash($4)->u.sval.u.string,
+		  check_node_hash($10),
+		  check_node_hash($<n>9)->u.sval.u.string,
+		  $1);
 #ifdef PIKE_DEBUG
       if(recoveries && sp-evaluator_stack < recoveries->sp)
 	fatal("Stack error (underflow)\n");
 
-      if(compiler_pass == 1 && f!=$<number>5)
-	fatal("define_function screwed up! %d != %d\n",f,$<number>5);
+      if(compiler_pass == 1 && f!=compiler_frame->current_function_number)
+	fatal("define_function screwed up! %d != %d\n",f,compiler_frame->current_function_number);
 #endif
     }
     pop_compiler_frame();
diff --git a/src/las.h b/src/las.h
index b1f71a36735958c3444ce8c7b550fc2c0d2e283f..286dc591de23c80e9ece75f802dbfaee06aa1f1c 100644
--- a/src/las.h
+++ b/src/las.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: las.h,v 1.34 2000/04/23 02:42:01 mast Exp $
+ * $Id: las.h,v 1.35 2000/04/25 09:32:46 hubbe Exp $
  */
 #ifndef LAS_H
 #define LAS_H
@@ -52,6 +52,7 @@ struct compiler_frame
   int current_number_of_locals;
   int max_number_of_locals;
   int lexical_scope;
+  int current_function_number;
   struct local_variable variable[MAX_LOCAL];
 };
 
diff --git a/src/lex.c b/src/lex.c
index 053732ae51b2fd115a46efa3c099f0650111769b..26c1a1eb5170f84af989ca7e59a15d0b9d5d72fe 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.77 2000/04/21 00:29:48 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.78 2000/04/25 09:32:46 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -174,7 +174,6 @@ struct keyword instr_names[]=
 { "mark & call",        F_MARK_APPLY, I_HASARG },
 { "mark, call & pop",   F_MARK_APPLY_POP, I_HASARG },
 { "apply and return",   F_APPLY_AND_RETURN, I_HASARG },
-{ "call lfun & return", F_CALL_LFUN_AND_RETURN, I_HASARG },
 { "call function",      F_CALL_FUNCTION, 0 },
 { "call function & return", F_CALL_FUNCTION_AND_RETURN, 0 },
 };
diff --git a/src/peep.in b/src/peep.in
index 2d031c9dd06f4dc7d68215f3fc62b418e5b4f808..728a010f5e077e750f35ad25e2e36ad8b0f4aa4b 100644
--- a/src/peep.in
+++ b/src/peep.in
@@ -1,5 +1,5 @@
 //
-// $Id: peep.in,v 1.28 2000/04/20 02:41:45 hubbe Exp $
+// $Id: peep.in,v 1.29 2000/04/25 09:32:46 hubbe Exp $
 //
 
 NOP :
@@ -276,3 +276,6 @@ CONSTANT POP_VALUE :
 LOCAL POP_VALUE :
 IDENTIFIER POP_VALUE :
 TRAMPOLINE POP_VALUE :
+
+
+RECUR RETURN: TAIL_RECUR ($1a)
diff --git a/src/program.c b/src/program.c
index 335830241c2ceab6e9f0b6bcc0237abcb160584d..679b8a31985b338b7d58df1f08653f825c231876 100644
--- a/src/program.c
+++ b/src/program.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: program.c,v 1.232 2000/04/23 03:01:26 mast Exp $");
+RCSID("$Id: program.c,v 1.233 2000/04/25 09:32:46 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -3670,6 +3670,7 @@ void push_compiler_frame(int lexical_scope)
   f->current_number_of_locals=0;
   f->max_number_of_locals=0;
   f->previous=compiler_frame;
+  f->current_function_number=-2; /* no function */
   compiler_frame=f;
 }