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