From 1807c0d78ff83f3f03502a2254edf28d29bbbdc1 Mon Sep 17 00:00:00 2001
From: Per Hedbor <ph@opera.com>
Date: Tue, 15 Jul 2014 14:59:30 +0200
Subject: [PATCH] Added F_CALL_BUILTIN_N and F_APPLY_N.

This calls the constant in arg1 with arg2 arguments from the stack.

These opcodes are used if the number of arguments is known and bigger
than 1.

It is not really all that big an optimization, it only removes the
mark stack handling. And, in fact, due to the fact that it removes
some peep optimizations it might be somewhat slower when not using the
amd64 machine code (since, as an example, APPLY/ASSIGN_LOCAL/POP is no
longer an opcode that is used in this case).

However, when using the amd64 code the assign local + pop opcode is
higly optimized, so it's not an issue that it is not merged into the
apply opcode. It is in fact more of a feature.

For that reason the code in docode.c is currently conditional.
The only code generator using it is the amd64 one.
---
 src/code/amd64.c          | 74 ++++++++++++++++++++++-----------------
 src/code/amd64.h          |  1 +
 src/docode.c              | 45 +++++++++++++++++-------
 src/interpret_functions.h |  9 +++++
 4 files changed, 84 insertions(+), 45 deletions(-)

diff --git a/src/code/amd64.c b/src/code/amd64.c
index 1459e36c8d..05721cb45e 100644
--- a/src/code/amd64.c
+++ b/src/code/amd64.c
@@ -387,6 +387,11 @@ static void mov_imm_reg( long imm, enum amd64_reg reg )
   }
 }
 
+/* static void mov_ptr_reg( void *x, enum amd64_reg reg ) */
+/* { */
+/*     mov_imm_reg( (long)x, reg ); */
+/* } */
+
 static void mov_mem128_reg( enum amd64_reg from_reg, int offset, enum amd64_reg to_reg )
 {
   if( from_reg > 7 )
@@ -542,25 +547,25 @@ static void add_mem_imm( enum amd64_reg reg, int offset, int imm32 )
   low_add_mem_imm( 1, reg, offset, imm32 );
 }
 
-static void add_mem8_imm( enum amd64_reg reg, int offset, int imm32 )
-{
-  int r2 = imm32 == -1 ? 1 : 0;
-  if( !imm32 ) return;
-  rex( 0, 0, 0, reg );
+/* static void add_mem8_imm( enum amd64_reg reg, int offset, int imm32 ) */
+/* { */
+/*   int r2 = imm32 == -1 ? 1 : 0; */
+/*   if( !imm32 ) return; */
+/*   rex( 0, 0, 0, reg ); */
 
-  if( imm32 == 1 || imm32 == -1 )
-    opcode( 0xfe ); /* INCL r/m8 */
-  else if( imm32 >= -128 && imm32 < 128 )
-    opcode( 0x80 ); /* ADD imm8,r/m32 */
-  else
-    Pike_fatal("Not sensible");
+/*   if( imm32 == 1 || imm32 == -1 ) */
+/*     opcode( 0xfe ); /\* INCL r/m8 *\/ */
+/*   else if( imm32 >= -128 && imm32 < 128 ) */
+/*     opcode( 0x80 ); /\* ADD imm8,r/m32 *\/ */
+/*   else */
+/*     Pike_fatal("Not sensible"); */
 
-  offset_modrm_sib( offset, r2, reg );
-  if( imm32 != 1 && !r2 )
-  {
-    ib( imm32 );
-  }
-}
+/*   offset_modrm_sib( offset, r2, reg ); */
+/*   if( imm32 != 1 && !r2 ) */
+/*   { */
+/*     ib( imm32 ); */
+/*   } */
+/* } */
 
 static void sub_reg_imm( enum amd64_reg reg, int imm32 )
 {
@@ -2809,25 +2814,10 @@ void ins_f_byte_with_arg(unsigned int a, INT32 b)
       */
       mov_imm_reg( 1, ARG1_REG );
     }
+
     /* Get function pointer */
-#if 0
-    amd64_load_fp_reg();
-    /* Ok.. This is.. interresting.
-       Let's trust that the efun really is constant, ok?
-    */
-    mov_mem_reg( fp_reg, OFFSETOF(pike_frame,context), P_REG_RAX );
-    mov_mem_reg( P_REG_RAX, OFFSETOF(inherit,prog), P_REG_RAX );
-    mov_mem_reg( P_REG_RAX, OFFSETOF(program,constants), P_REG_RAX );
-    add_reg_imm( P_REG_RAX, b*sizeof(struct program_constant) +
-                 OFFSETOF(program_constant,sval) );
-    mov_mem_reg( P_REG_RAX, OFFSETOF( svalue, u.efun ), P_REG_RAX );
-    mov_mem_reg( P_REG_RAX, OFFSETOF( callable, function), P_REG_RAX );
-    call_reg( P_REG_RAX );
-    sp_reg = -1;
-#else
     amd64_call_c_opcode(Pike_compiler->new_program->constants[b].sval.u.efun->function,
                         I_UPDATE_SP);
-#endif
     return;
 
   case F_CONSTANT:
@@ -3004,6 +2994,24 @@ void ins_f_byte_with_2_args(unsigned int a, INT32 b, INT32 c)
       LABEL_C;
       return;
      }
+
+#if 0
+   /* this is a: nonworking, and b: not really all that more efficient anyway.. */
+  case F_APPLY_N:
+     mov_imm_reg( APPLY_SVALUE_STRICT, ARG1_REG );
+     mov_imm_reg( c, ARG2_REG );
+     mov_ptr_reg( &((Pike_fp->context->prog->constants + b)->sval), ARG3_REG );
+     clear_reg( ARG4_REG );
+     amd64_call_c_opcode(mega_apply, I_UPDATE_SP);
+    return;
+#endif
+  case F_CALL_BUILTIN_N:
+    mov_imm_reg( c, ARG1_REG );
+    amd64_call_c_opcode(Pike_compiler->new_program->constants[b].sval.u.efun->function,
+                        I_UPDATE_SP);
+    return;
+
+
   case F_ADD_LOCALS_AND_POP:
     {
       LABELS();
diff --git a/src/code/amd64.h b/src/code/amd64.h
index efcaaaf768..3f20dda932 100644
--- a/src/code/amd64.h
+++ b/src/code/amd64.h
@@ -2,6 +2,7 @@
 #define OPCODE_INLINE_BRANCH
 #define OPCODE_RETURN_JUMPADDR
 #define OPCODE_INLINE_RETURN
+#define USE_APPLY_N
 
 #if defined(_M_X64) && !defined(__GNUC__)
 
diff --git a/src/docode.c b/src/docode.c
index c263f8f82e..17dae960e0 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -1902,6 +1902,7 @@ static int do_docode2(node *n, int flags)
   case F_APPLY:
     if(CAR(n)->token == F_CONSTANT)
     {
+      int args = count_args(CDR(n));
       if(TYPEOF(CAR(n)->u.sval) == T_FUNCTION)
       {
 	if(SUBTYPEOF(CAR(n)->u.sval) == FUNCTION_BUILTIN) /* driver fun? */
@@ -1909,13 +1910,21 @@ static int do_docode2(node *n, int flags)
 	  if(!CAR(n)->u.sval.u.efun->docode || 
 	     !CAR(n)->u.sval.u.efun->docode(n))
 	  {
-	    if(count_args(CDR(n))==1)
+	    if(args==1)
 	    {
 	      do_docode(CDR(n),0);
 	      tmp1=store_constant(& CAR(n)->u.sval,
 				  !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
 				  CAR(n)->name);
 	      emit1(F_CALL_BUILTIN1, DO_NOT_WARN((INT32)tmp1));
+#ifdef USE_APPLY_N
+	    }else if(args>0){
+	      do_docode(CDR(n),0);
+	      tmp1=store_constant(& CAR(n)->u.sval,
+				  !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
+				  CAR(n)->name);
+	      emit2(F_CALL_BUILTIN_N, DO_NOT_WARN((INT32)tmp1), args);
+#endif
 	    }else{
 	      emit0(F_MARK);
 	      PUSH_CLEANUP_FRAME(do_pop_mark, 0);
@@ -1929,23 +1938,35 @@ static int do_docode2(node *n, int flags)
 	  }
 	  if(n->type == void_type_string)
 	    return 0;
-
 	  return 1;
 	}else{
 	  if(CAR(n)->u.sval.u.object == Pike_compiler->fake_object)
 	    return do_lfun_call(SUBTYPEOF(CAR(n)->u.sval), CDR(n));
        	}
       }
-
-      emit0(F_MARK);
-      PUSH_CLEANUP_FRAME(do_pop_mark, 0);
-      do_docode(CDR(n),0);
-      tmp1=store_constant(& CAR(n)->u.sval,
-			  !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
-			  CAR(n)->name);
-      emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1));
-      POP_AND_DONT_CLEANUP;
-      
+#ifdef USE_APPLY_N
+      if( args <= 1 )
+#endif
+      {
+        emit0(F_MARK);
+        PUSH_CLEANUP_FRAME(do_pop_mark, 0);
+        do_docode(CDR(n),0);
+        tmp1=store_constant(& CAR(n)->u.sval,
+                            !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
+                            CAR(n)->name);
+        emit1(F_APPLY, DO_NOT_WARN((INT32)tmp1));
+        POP_AND_DONT_CLEANUP;
+      }
+#ifdef USE_APPLY_N
+      else
+      {
+        do_docode(CDR(n),0);
+        tmp1=store_constant(& CAR(n)->u.sval,
+                            !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND),
+                            CAR(n)->name);
+        emit2(F_APPLY_N, DO_NOT_WARN((INT32)tmp1), args);
+      }
+#endif
       return 1;
     }
     else if(CAR(n)->token == F_IDENTIFIER)
diff --git a/src/interpret_functions.h b/src/interpret_functions.h
index 9a62d79554..42fbc6825a 100644
--- a/src/interpret_functions.h
+++ b/src/interpret_functions.h
@@ -2493,6 +2493,15 @@ OPCODE1(F_CALL_BUILTIN1, "call builtin 1", I_UPDATE_ALL, {
   DO_CALL_BUILTIN(1);
 });
 
+OPCODE2(F_CALL_BUILTIN_N, "call builtin N", I_UPDATE_ALL, {
+  FAST_CHECK_THREADS_ON_CALL();
+  DO_CALL_BUILTIN(arg2);
+});
+
+OPCODE2( F_APPLY_N, "apply N", I_UPDATE_ALL, {
+   mega_apply( APPLY_SVALUE_STRICT, arg2, &((Pike_fp->context->prog->constants + arg1)->sval), 0 );
+});
+
 OPCODE1(F_CALL_BUILTIN1_AND_POP, "call builtin1 & pop", I_UPDATE_ALL, {
   FAST_CHECK_THREADS_ON_CALL();
   DO_CALL_BUILTIN(1);
-- 
GitLab