2013-02-13 12:26:47 +00:00
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
|
|
|
|
/* ops that use CLs:
|
|
|
|
op1:
|
|
|
|
ZEND_FETCH_CONSTANT:
|
|
|
|
ZEND_INIT_CTOR_CALL:
|
|
|
|
ZEND_INIT_STATIC_METHOD_CALL:
|
|
|
|
ZEND_INIT_METHOD_CALL:
|
|
|
|
ZEND_IMPORT_CLASS:
|
|
|
|
ZEND_IMPORT_FUNCTION:
|
|
|
|
ZEND_IMPORT_CONST:
|
|
|
|
ZEND_ADD_INTERFACE:
|
|
|
|
ZEND_VERIFY_ABSTRACT_CLASS:
|
|
|
|
ZEND_NEW:
|
|
|
|
ZEND_CATCH:
|
|
|
|
ZEND_INIT_FCALL_BY_NAME:
|
|
|
|
|
|
|
|
op2:
|
|
|
|
ZEND_UNSET_VAR:
|
|
|
|
ZEND_ISSET_ISEMPTY_VAR:
|
|
|
|
ZEND_FETCH_UNSET:
|
|
|
|
ZEND_FETCH_IS:
|
|
|
|
ZEND_FETCH_R:
|
|
|
|
ZEND_FETCH_W:
|
|
|
|
ZEND_FETCH_RW:
|
|
|
|
ZEND_FETCH_FUNC_ARG:
|
|
|
|
ZEND_ADD_INTERFACE:
|
|
|
|
ZEND_INSTANCEOF:
|
|
|
|
|
|
|
|
extended_value:
|
|
|
|
ZEND_DECLARE_INHERITED_CLASS:
|
|
|
|
|
|
|
|
ignore result
|
|
|
|
INIT_METHOD_CALL:
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define OP1_CONST_IS_CLASS 1
|
|
|
|
#define OP2_CONST_IS_CLASS 2
|
|
|
|
#define EXT_CONST_IS_CLASS 4
|
|
|
|
#define RESULT_IS_UNUSED 8
|
|
|
|
|
|
|
|
static const char op_const_means_class[256] = {
|
|
|
|
/* 0 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
/* 32 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
|
|
|
/* 64 */
|
|
|
|
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2,
|
|
|
|
/* 96 */
|
|
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
/* 128 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
/* 160 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
/* 192 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
/* 224 */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define GET_AVAILABLE_T() \
|
2013-02-22 06:56:05 +00:00
|
|
|
for (i = 0; i < T; i++) { \
|
2013-02-13 12:26:47 +00:00
|
|
|
if (!taken_T[i]) { \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
taken_T[i] = 1; \
|
|
|
|
if (i > max) { \
|
|
|
|
max = i; \
|
|
|
|
}
|
|
|
|
|
|
|
|
static void optimize_temporary_variables(zend_op_array *op_array)
|
|
|
|
{
|
|
|
|
int T = op_array->T;
|
2014-03-28 19:34:49 +00:00
|
|
|
int offset = op_array->last_var;
|
2013-02-13 12:26:47 +00:00
|
|
|
char *taken_T; /* T index in use */
|
|
|
|
zend_op **start_of_T; /* opline where T is first used */
|
|
|
|
char *valid_T; /* Is the map_T valid */
|
|
|
|
int *map_T; /* Map's the T to its new index */
|
|
|
|
zend_op *opline, *end;
|
|
|
|
int currT;
|
|
|
|
int i;
|
|
|
|
int max = -1;
|
|
|
|
int var_to_free = -1;
|
|
|
|
|
|
|
|
taken_T = (char *) emalloc(T);
|
2013-02-25 07:29:54 +00:00
|
|
|
start_of_T = (zend_op **) emalloc(T * sizeof(zend_op *));
|
2013-02-13 12:26:47 +00:00
|
|
|
valid_T = (char *) emalloc(T);
|
2013-02-25 07:29:54 +00:00
|
|
|
map_T = (int *) emalloc(T * sizeof(int));
|
2013-02-13 12:26:47 +00:00
|
|
|
|
|
|
|
end = op_array->opcodes;
|
2013-02-25 07:29:54 +00:00
|
|
|
opline = &op_array->opcodes[op_array->last - 1];
|
2013-02-13 12:26:47 +00:00
|
|
|
|
|
|
|
/* Find T definition points */
|
|
|
|
while (opline >= end) {
|
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
|
|
|
|
if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
|
2014-03-28 19:34:49 +00:00
|
|
|
start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
|
2014-03-28 19:34:49 +00:00
|
|
|
start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|
2014-03-31 14:13:16 +00:00
|
|
|
/* special puprose variable to keep HashPointer on VM stack */
|
|
|
|
if (opline->opcode == ZEND_OP_DATA &&
|
|
|
|
(opline-1)->opcode == ZEND_FE_FETCH &&
|
|
|
|
opline->op1_type == IS_TMP_VAR) {
|
|
|
|
start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline;
|
|
|
|
if (sizeof(HashPointer) > sizeof(zval)) {
|
|
|
|
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
|
|
|
|
start_of_T[VAR_NUM(ZEND_OP1(opline).var) + 1 - offset] = opline;
|
|
|
|
}
|
|
|
|
}
|
2013-02-13 12:26:47 +00:00
|
|
|
#endif
|
|
|
|
opline--;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(valid_T, 0, T);
|
|
|
|
memset(taken_T, 0, T);
|
|
|
|
|
|
|
|
end = op_array->opcodes;
|
2013-02-25 07:29:54 +00:00
|
|
|
opline = &op_array->opcodes[op_array->last - 1];
|
2013-02-13 12:26:47 +00:00
|
|
|
|
|
|
|
while (opline >= end) {
|
|
|
|
if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
|
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
|| ((op_const_means_class[opline->opcode] & OP1_CONST_IS_CLASS) && ZEND_OP1_TYPE(opline) == IS_CONST)
|
|
|
|
#endif
|
|
|
|
) {
|
2014-03-31 14:13:16 +00:00
|
|
|
|
|
|
|
/* special puprose variable to keep HashPointer on VM stack */
|
|
|
|
if (opline->opcode == ZEND_OP_DATA &&
|
|
|
|
(opline-1)->opcode == ZEND_FE_FETCH &&
|
|
|
|
opline->op1_type == IS_TMP_VAR) {
|
|
|
|
max++;
|
|
|
|
ZEND_OP1(opline).var = NUM_VAR(max + offset);
|
|
|
|
if (sizeof(HashPointer) > sizeof(zval)) {
|
|
|
|
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
|
|
|
|
max++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
|
|
|
|
if (!valid_T[currT]) {
|
|
|
|
GET_AVAILABLE_T();
|
|
|
|
map_T[currT] = i;
|
|
|
|
valid_T[currT] = 1;
|
|
|
|
}
|
|
|
|
ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip OP_DATA */
|
2013-02-22 06:56:05 +00:00
|
|
|
if (opline->opcode == ZEND_OP_DATA &&
|
2013-02-13 12:26:47 +00:00
|
|
|
(opline-1)->opcode == ZEND_ASSIGN_DIM) {
|
|
|
|
opline--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))
|
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
|| ((op_const_means_class[opline->opcode] & OP2_CONST_IS_CLASS) && ZEND_OP2_TYPE(opline) == IS_CONST)
|
|
|
|
#endif
|
|
|
|
) {
|
2014-03-28 19:34:49 +00:00
|
|
|
currT = VAR_NUM(ZEND_OP2(opline).var) - offset;
|
2013-02-13 12:26:47 +00:00
|
|
|
if (!valid_T[currT]) {
|
|
|
|
GET_AVAILABLE_T();
|
|
|
|
map_T[currT] = i;
|
|
|
|
valid_T[currT] = 1;
|
|
|
|
}
|
2014-03-28 19:34:49 +00:00
|
|
|
ZEND_OP2(opline).var = NUM_VAR(map_T[currT] + offset);
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
if ((op_const_means_class[opline->opcode] & EXT_CONST_IS_CLASS)) {
|
|
|
|
#else
|
|
|
|
if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
|
|
|
|
opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
|
|
|
|
#endif
|
2014-03-28 19:34:49 +00:00
|
|
|
currT = VAR_NUM(opline->extended_value) - offset;
|
2013-02-13 12:26:47 +00:00
|
|
|
if (!valid_T[currT]) {
|
|
|
|
GET_AVAILABLE_T();
|
|
|
|
map_T[currT] = i;
|
|
|
|
valid_T[currT] = 1;
|
|
|
|
}
|
2014-03-28 19:34:49 +00:00
|
|
|
opline->extended_value = NUM_VAR(map_T[currT] + offset);
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 18:49:05 +00:00
|
|
|
/* Allocate OP_DATA->op2 after "operands", but before "result" */
|
2013-02-13 12:26:47 +00:00
|
|
|
if (opline->opcode == ZEND_ASSIGN_DIM &&
|
2013-02-25 07:29:54 +00:00
|
|
|
(opline + 1)->opcode == ZEND_OP_DATA &&
|
|
|
|
ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) {
|
2014-03-28 19:34:49 +00:00
|
|
|
currT = VAR_NUM(ZEND_OP2(opline + 1).var) - offset;
|
2013-02-13 12:26:47 +00:00
|
|
|
GET_AVAILABLE_T();
|
|
|
|
map_T[currT] = i;
|
|
|
|
valid_T[currT] = 1;
|
|
|
|
taken_T[i] = 0;
|
2014-03-28 19:34:49 +00:00
|
|
|
ZEND_OP2(opline + 1).var = NUM_VAR(i + offset);
|
2013-02-13 12:26:47 +00:00
|
|
|
var_to_free = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
|
|
|
|
if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
|
|
|
|
#else
|
|
|
|
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
|
|
|
|
#endif
|
2014-03-28 19:34:49 +00:00
|
|
|
currT = VAR_NUM(ZEND_RESULT(opline).var) - offset;
|
2013-02-13 12:26:47 +00:00
|
|
|
if (valid_T[currT]) {
|
|
|
|
if (start_of_T[currT] == opline) {
|
|
|
|
taken_T[map_T[currT]] = 0;
|
|
|
|
}
|
2014-03-28 19:34:49 +00:00
|
|
|
ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset);
|
2013-02-13 12:26:47 +00:00
|
|
|
} else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */
|
|
|
|
GET_AVAILABLE_T();
|
|
|
|
|
|
|
|
if (RESULT_UNUSED(opline)) {
|
|
|
|
taken_T[i] = 0;
|
|
|
|
} else {
|
|
|
|
/* Code which gets here is using a wrongly built opcode such as RECV() */
|
|
|
|
map_T[currT] = i;
|
|
|
|
valid_T[currT] = 1;
|
|
|
|
}
|
2014-03-28 19:34:49 +00:00
|
|
|
ZEND_RESULT(opline).var = NUM_VAR(i + offset);
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|
|
|
|
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (var_to_free >= 0) {
|
|
|
|
taken_T[var_to_free] = 0;
|
|
|
|
var_to_free = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
opline--;
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(taken_T);
|
|
|
|
efree(start_of_T);
|
|
|
|
efree(valid_T);
|
|
|
|
efree(map_T);
|
2013-02-22 06:56:05 +00:00
|
|
|
op_array->T = max + 1;
|
2013-02-13 12:26:47 +00:00
|
|
|
}
|