Commit:    edfeab8bf2750da4616f802650d28b0774eccba3
Author:    Dmitry Stogov <dmi...@zend.com>         Thu, 18 Apr 2013 22:12:31 
+0400
Parents:   7deb3d41ebd80131e21733d6eaa51e7ccab3b949
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=edfeab8bf2750da4616f802650d28b0774eccba3

Log:
Added an optimization pass to convert FCALL_BY_NAME into DO_FCALL.

Changed paths:
  A  ext/opcache/Optimizer/optimize_func_calls.c
  M  ext/opcache/Optimizer/pass1_5.c
  M  ext/opcache/Optimizer/zend_optimizer.c
  M  ext/opcache/Optimizer/zend_optimizer.h

diff --git a/ext/opcache/Optimizer/optimize_func_calls.c 
b/ext/opcache/Optimizer/optimize_func_calls.c
new file mode 100644
index 0000000..ee271f2
--- /dev/null
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -0,0 +1,136 @@
+/* pass 4
+ * - optimize INIT_FCALL_BY_NAME to DO_FCALL
+ */
+
+typedef struct _optimizer_call_info {
+       zend_function *func;
+       zend_op       *opline;
+} optimizer_call_info;
+
+static void optimize_func_calls(zend_op_array *op_array, 
zend_persistent_script *script TSRMLS_CC) {
+       zend_op *opline = op_array->opcodes;
+       zend_op *end = opline + op_array->last;
+       int call = 0;
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+       optimizer_call_info *call_stack = ecalloc(op_array->nested_calls + 1, 
sizeof(optimizer_call_info));
+#else
+       int stack_size = 4;
+       optimizer_call_info *call_stack = ecalloc(stack_size, 
sizeof(optimizer_call_info));
+#endif
+
+       while (opline < end) {
+               switch (opline->opcode) {
+                       case ZEND_INIT_FCALL_BY_NAME:
+                       case ZEND_INIT_NS_FCALL_BY_NAME:
+                               if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+                                       zend_function *func;
+                                       zval *function_name = 
&op_array->literals[opline->op2.constant + 1].constant;
+                                       if 
((zend_hash_quick_find(&script->function_table,
+                                                       
Z_STRVAL_P(function_name), Z_STRLEN_P(function_name) + 1,
+                                                       
Z_HASH_P(function_name), (void **)&func) == SUCCESS)) {
+                                               call_stack[call].func = func;
+                                       }
+                               }
+                               /* break missing intentionally */
+                       case ZEND_NEW:
+                       case ZEND_INIT_METHOD_CALL:
+                       case ZEND_INIT_STATIC_METHOD_CALL:
+                               call_stack[call].opline = opline;
+                               call++;
+#if ZEND_EXTENSION_API_NO < PHP_5_5_X_API_NO
+                               if (call == stack_size) {
+                                       stack_size += 4;
+                                       call_stack = erealloc(call_stack, 
sizeof(optimizer_call_info) * stack_size);
+                                       memset(call_stack + 4, 0, 4 * 
sizeof(optimizer_call_info));
+                               }
+#endif
+                               break;
+                       case ZEND_DO_FCALL_BY_NAME:
+                               call--;
+                               if (call_stack[call].func && 
call_stack[call].opline) {
+                                       zend_op *fcall = 
call_stack[call].opline;
+
+                                       opline->opcode = ZEND_DO_FCALL;
+                                       ZEND_OP1_TYPE(opline) = IS_CONST;
+                                       opline->op1.constant = 
fcall->op2.constant + 1;
+                                       op_array->literals[fcall->op2.constant 
+ 1].cache_slot = op_array->literals[fcall->op2.constant].cache_slot;
+                                       literal_dtor(&ZEND_OP2_LITERAL(fcall));
+                                       if (fcall->opcode == 
ZEND_INIT_NS_FCALL_BY_NAME) {
+                                               
literal_dtor(&op_array->literals[fcall->op2.constant + 2].constant);
+                                       }
+                                       MAKE_NOP(fcall);
+                               } else if (opline->extended_value == 0 &&
+                                          call_stack[call].opline &&
+                                          call_stack[call].opline == 
ZEND_INIT_FCALL_BY_NAME &&
+                                          
ZEND_OP2_TYPE(call_stack[call].opline) == IS_CONST) {
+
+                                       zend_op *fcall = 
call_stack[call].opline;
+
+                                       opline->opcode = ZEND_DO_FCALL;
+                                       ZEND_OP1_TYPE(opline) = IS_CONST;
+                                       opline->op1.constant = 
fcall->op2.constant + 1;
+                                       op_array->literals[fcall->op2.constant 
+ 1].cache_slot = op_array->literals[fcall->op2.constant].cache_slot;
+                                       literal_dtor(&ZEND_OP2_LITERAL(fcall));
+                                       MAKE_NOP(fcall);
+                               }
+                               call_stack[call].func = NULL;
+                               call_stack[call].opline = NULL;
+                               break;
+                       case ZEND_FETCH_FUNC_ARG:
+                       case ZEND_FETCH_OBJ_FUNC_ARG:
+                       case ZEND_FETCH_DIM_FUNC_ARG:
+                               if (call_stack[call - 1].func) {
+                                       if 
(ARG_SHOULD_BE_SENT_BY_REF(call_stack[call].func, (opline->extended_value & 
ZEND_FETCH_ARG_MASK))) {
+                                               opline->extended_value = 0;
+                                               opline->opcode -= 9;
+                                       } else {
+                                               opline->extended_value = 0;
+                                               opline->opcode -= 12;
+                                       }
+                               }
+                               break;
+                       case ZEND_SEND_VAL:
+                               if (opline->extended_value == 
ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
+                                       if 
(ARG_MUST_BE_SENT_BY_REF(call_stack[call].func, opline->op2.num)) {
+                                               /* We won't convert it 
into_DO_FCALL to emit error at run-time */
+                                               call_stack[call].opline = NULL;
+                                       } else {
+                                               opline->extended_value = 
ZEND_DO_FCALL;
+                                       }
+                               }
+                               break;
+                       case ZEND_SEND_VAR:
+                               if (opline->extended_value == 
ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
+                                       if 
(ARG_SHOULD_BE_SENT_BY_REF(call_stack[call].func, opline->op2.num)) {
+                                               opline->opcode = ZEND_SEND_REF;
+                                       }
+                                       opline->extended_value = ZEND_DO_FCALL;
+                               }
+                               break;
+                       case ZEND_SEND_VAR_NO_REF:
+                               if (!(opline->extended_value & 
ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) {
+                                       if 
(ARG_SHOULD_BE_SENT_BY_REF(call_stack[call].func, opline->op2.num)) {
+                                               opline->extended_value |= 
ZEND_ARG_COMPILE_TIME_BOUND | ZEND_ARG_SEND_BY_REF;
+                                       } else if (opline->extended_value) {
+                                               opline->extended_value |= 
ZEND_ARG_COMPILE_TIME_BOUND;
+                                       } else {
+                                               opline->opcode = ZEND_SEND_VAR;
+                                               opline->extended_value = 
ZEND_DO_FCALL;
+                                       }
+                               }
+                               break;
+                       case ZEND_SEND_REF:
+                               if (opline->extended_value == 
ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
+                                       /* We won't handle run-time pass by 
reference */
+                                       call_stack[call].opline = NULL;
+                               }
+                               break;
+
+                       default:
+                               break;
+               }
+               opline++;
+       }
+
+       efree(call_stack);
+}
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index 3a32970..ec5a786 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -3,7 +3,6 @@
  * - perform compile-time evaluation of constant binary and unary operations
  * - optimize series of ADD_STRING and/or ADD_CHAR
  * - convert CAST(IS_BOOL,x) into BOOL(x)
- * - convert INTI_FCALL_BY_NAME, DO_FCALL_BY_NAME into DO_FCALL
  */
 
 if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
@@ -374,23 +373,6 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                        }
                        break;
 
-               case ZEND_INIT_FCALL_BY_NAME:
-                       if (opline->extended_value == 0 /* not method */ &&
-                               ZEND_OP1_TYPE(opline) == IS_UNUSED &&
-                               ZEND_OP2_TYPE(opline) == IS_CONST) {
-                               if ((opline + 1)->opcode == 
ZEND_DO_FCALL_BY_NAME &&
-                                       (opline + 1)->extended_value == 0) {
-                                       (opline + 1)->opcode = ZEND_DO_FCALL;
-                                       COPY_NODE((opline + 1)->op1, 
opline->op2);
-                                       
zend_str_tolower(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), 
Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline + 1)) 
= zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), 
Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)) + 1);
-                                       op_array->literals[(opline + 
1)->op1.constant].cache_slot = op_array->last_cache_slot++;
-#endif
-                                       MAKE_NOP(opline);
-                               }
-                       }
-                       break;
                case ZEND_DO_FCALL:
                        /* define("name", scalar); */
                        if (collect_constants &&
diff --git a/ext/opcache/Optimizer/zend_optimizer.c 
b/ext/opcache/Optimizer/zend_optimizer.c
index fc0066e..9cbcd06 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -113,6 +113,7 @@ int zend_optimizer_add_literal(zend_op_array *op_array, 
const zval *zv TSRMLS_DC
 #include "Optimizer/block_pass.c"
 #include "Optimizer/optimize_temp_vars_5.c"
 #include "Optimizer/compact_literals.c"
+#include "Optimizer/optimize_func_calls.c"
 
 static void zend_optimize(zend_op_array           *op_array,
                           zend_persistent_script  *script,
@@ -128,7 +129,6 @@ static void zend_optimize(zend_op_array           *op_array,
         * - perform compile-time evaluation of constant binary and unary 
operations
         * - optimize series of ADD_STRING and/or ADD_CHAR
         * - convert CAST(IS_BOOL,x) into BOOL(x)
-        * - convert INTI_FCALL_BY_NAME + DO_FCALL_BY_NAME into DO_FCALL
         */
 #include "Optimizer/pass1_5.c"
 
@@ -146,6 +146,13 @@ static void zend_optimize(zend_op_array           
*op_array,
         */
 #include "Optimizer/pass3.c"
 
+       /* pass 4:
+        * - INIT_FCALL_BY_NAME -> DO_FCALL
+        */
+       if (ZEND_OPTIMIZER_PASS_4 & OPTIMIZATION_LEVEL) {
+               optimize_func_calls(op_array, script TSRMLS_CC);
+       }
+
        /* pass 5:
         * - CFG optimization
         */
diff --git a/ext/opcache/Optimizer/zend_optimizer.h 
b/ext/opcache/Optimizer/zend_optimizer.h
index 4be37ba..5a3d715 100644
--- a/ext/opcache/Optimizer/zend_optimizer.h
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -28,7 +28,7 @@
 #define ZEND_OPTIMIZER_PASS_1          (1<<0)   /* CSE, STRING construction    
 */
 #define ZEND_OPTIMIZER_PASS_2          (1<<1)   /* Constant conversion and 
jumps */
 #define ZEND_OPTIMIZER_PASS_3          (1<<2)   /* ++, +=, series of jumps     
 */
-#define ZEND_OPTIMIZER_PASS_4          (1<<3)
+#define ZEND_OPTIMIZER_PASS_4          (1<<3)   /* INIT_FCALL_BY_NAME -> 
DO_FCALL */
 #define ZEND_OPTIMIZER_PASS_5          (1<<4)   /* CFG based optimization      
 */
 #define ZEND_OPTIMIZER_PASS_6          (1<<5)
 #define ZEND_OPTIMIZER_PASS_7          (1<<6)
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to