root/ext/opcache/Optimizer/optimize_func_calls.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. optimize_func_calls

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend OPcache                                                         |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
  16    |          Xinchen Hui <laruence@php.net>                              |
  17    +----------------------------------------------------------------------+
  18 */
  19 
  20 /* pass 4
  21  * - optimize INIT_FCALL_BY_NAME to DO_FCALL
  22  */
  23 
  24 #include "php.h"
  25 #include "Optimizer/zend_optimizer.h"
  26 #include "Optimizer/zend_optimizer_internal.h"
  27 #include "zend_API.h"
  28 #include "zend_constants.h"
  29 #include "zend_execute.h"
  30 #include "zend_vm.h"
  31 
  32 #define ZEND_OP2_IS_CONST_STRING(opline) \
  33         (ZEND_OP2_TYPE(opline) == IS_CONST && \
  34         Z_TYPE(op_array->literals[(opline)->op2.constant]) == IS_STRING)
  35 
  36 typedef struct _optimizer_call_info {
  37         zend_function *func;
  38         zend_op       *opline;
  39 } optimizer_call_info;
  40 
  41 void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
  42 {
  43         zend_op *opline = op_array->opcodes;
  44         zend_op *end = opline + op_array->last;
  45         int call = 0;
  46         void *checkpoint;
  47         optimizer_call_info *call_stack;
  48 
  49         if (op_array->last < 2) {
  50                 return;
  51         }
  52 
  53         checkpoint = zend_arena_checkpoint(ctx->arena);
  54         call_stack = zend_arena_calloc(&ctx->arena, op_array->last / 2, sizeof(optimizer_call_info));
  55         while (opline < end) {
  56                 switch (opline->opcode) {
  57                         case ZEND_INIT_FCALL_BY_NAME:
  58                         case ZEND_INIT_NS_FCALL_BY_NAME:
  59                                 if (ZEND_OP2_IS_CONST_STRING(opline)) {
  60                                         zend_function *func;
  61                                         zval *function_name = &op_array->literals[opline->op2.constant + 1];
  62                                         if ((func = zend_hash_find_ptr(&ctx->script->function_table,
  63                                                         Z_STR_P(function_name))) != NULL) {
  64                                                 call_stack[call].func = func;
  65                                         }
  66                                 }
  67                                 /* break missing intentionally */
  68                         case ZEND_NEW:
  69                         case ZEND_INIT_DYNAMIC_CALL:
  70                         case ZEND_INIT_METHOD_CALL:
  71                         case ZEND_INIT_STATIC_METHOD_CALL:
  72                         case ZEND_INIT_FCALL:
  73                         case ZEND_INIT_USER_CALL:
  74                                 call_stack[call].opline = opline;
  75                                 call++;
  76                                 break;
  77                         case ZEND_DO_FCALL:
  78                         case ZEND_DO_ICALL:
  79                         case ZEND_DO_UCALL:
  80                         case ZEND_DO_FCALL_BY_NAME:
  81                                 call--;
  82                                 if (call_stack[call].func && call_stack[call].opline) {
  83                                         zend_op *fcall = call_stack[call].opline;
  84 
  85                                         if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) {
  86                                                 fcall->opcode = ZEND_INIT_FCALL;
  87                                                 fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
  88                                                 Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
  89                                                 literal_dtor(&ZEND_OP2_LITERAL(fcall));
  90                                                 fcall->op2.constant = fcall->op2.constant + 1;
  91                                                 opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func);
  92                                         } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
  93                                                 fcall->opcode = ZEND_INIT_FCALL;
  94                                                 fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
  95                                                 Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
  96                                                 literal_dtor(&op_array->literals[fcall->op2.constant]);
  97                                                 literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
  98                                                 fcall->op2.constant = fcall->op2.constant + 1;
  99                                                 opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func);
 100                                         } else {
 101                                                 ZEND_ASSERT(0);
 102                                         }
 103                                 }
 104                                 call_stack[call].func = NULL;
 105                                 call_stack[call].opline = NULL;
 106                                 break;
 107                         case ZEND_FETCH_FUNC_ARG:
 108                         case ZEND_FETCH_OBJ_FUNC_ARG:
 109                         case ZEND_FETCH_DIM_FUNC_ARG:
 110                                 if (call_stack[call - 1].func) {
 111                                         if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
 112                                                 opline->extended_value &= ZEND_FETCH_TYPE_MASK;
 113                                                 opline->opcode -= 9;
 114                                         } else {
 115                                                 opline->extended_value &= ZEND_FETCH_TYPE_MASK;
 116                                                 opline->opcode -= 12;
 117                                         }
 118                                 }
 119                                 break;
 120                         case ZEND_SEND_VAL_EX:
 121                                 if (call_stack[call - 1].func) {
 122                                         if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
 123                                                 /* We won't convert it into_DO_FCALL to emit error at run-time */
 124                                                 call_stack[call - 1].opline = NULL;
 125                                         } else {
 126                                                 opline->opcode = ZEND_SEND_VAL;
 127                                         }
 128                                 }
 129                                 break;
 130                         case ZEND_SEND_VAR_EX:
 131                                 if (call_stack[call - 1].func) {
 132                                         if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
 133                                                 opline->opcode = ZEND_SEND_REF;
 134                                         } else {
 135                                                 opline->opcode = ZEND_SEND_VAR;
 136                                         }
 137                                 }
 138                                 break;
 139                         case ZEND_SEND_VAR_NO_REF:
 140                                 if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) {
 141                                         if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
 142                                                 opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND | ZEND_ARG_SEND_BY_REF;
 143                                         } else {
 144                                                 opline->opcode = ZEND_SEND_VAR;
 145                                                 opline->extended_value = 0;
 146                                         }
 147                                 }
 148                                 break;
 149 #if 0
 150                         case ZEND_SEND_REF:
 151                                 if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND && call_stack[call - 1].func) {
 152                                         /* We won't handle run-time pass by reference */
 153                                         call_stack[call - 1].opline = NULL;
 154                                 }
 155                                 break;
 156 #endif
 157                         case ZEND_SEND_UNPACK:
 158                                 call_stack[call - 1].func = NULL;
 159                                 call_stack[call - 1].opline = NULL;
 160                                 break;
 161                         default:
 162                                 break;
 163                 }
 164                 opline++;
 165         }
 166 
 167         zend_arena_release(&ctx->arena, checkpoint);
 168 }

/* [<][>][^][v][top][bottom][index][help] */