Moved "zval.u2.cache_slot" into free room of "zend_op"

This commit is contained in:
Dmitry Stogov 2018-02-05 19:41:47 +03:00
parent 070a0091b3
commit ca035f26aa
23 changed files with 2805 additions and 1875 deletions

View file

@ -64,18 +64,20 @@ typedef struct _zend_loop_var {
} u; } u;
} zend_loop_var; } zend_loop_var;
static inline void zend_alloc_cache_slot(uint32_t literal) { static inline uint32_t zend_alloc_cache_slot(void) {
zend_op_array *op_array = CG(active_op_array); zend_op_array *op_array = CG(active_op_array);
Z_CACHE_SLOT(op_array->literals[literal]) = op_array->cache_size; uint32_t ret = op_array->cache_size;
op_array->cache_size += sizeof(void*); op_array->cache_size += sizeof(void*);
return ret;
} }
#define POLYMORPHIC_CACHE_SLOT_SIZE 2 #define POLYMORPHIC_CACHE_SLOT_SIZE 2
static inline void zend_alloc_polymorphic_cache_slot(uint32_t literal) { static inline uint32_t zend_alloc_polymorphic_cache_slot(void) {
zend_op_array *op_array = CG(active_op_array); zend_op_array *op_array = CG(active_op_array);
Z_CACHE_SLOT(op_array->literals[literal]) = op_array->cache_size; uint32_t ret = op_array->cache_size;
op_array->cache_size += POLYMORPHIC_CACHE_SLOT_SIZE * sizeof(void*); op_array->cache_size += POLYMORPHIC_CACHE_SLOT_SIZE * sizeof(void*);
return ret;
} }
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type); ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type);
@ -453,7 +455,6 @@ static inline void zend_insert_literal(zend_op_array *op_array, zval *zv, int li
zval_make_interned_string(zv); zval_make_interned_string(zv);
} }
ZVAL_COPY_VALUE(CT_CONSTANT_EX(op_array, literal_position), zv); ZVAL_COPY_VALUE(CT_CONSTANT_EX(op_array, literal_position), zv);
Z_CACHE_SLOT(op_array->literals[literal_position]) = -1;
} }
/* }}} */ /* }}} */
@ -531,8 +532,6 @@ static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *nam
zend_string *lc_name = zend_string_tolower(name); zend_string *lc_name = zend_string_tolower(name);
zend_add_literal_string(op_array, &lc_name); zend_add_literal_string(op_array, &lc_name);
zend_alloc_cache_slot(ret);
return ret; return ret;
} }
/* }}} */ /* }}} */
@ -2026,7 +2025,34 @@ static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var)
} else if (def->opcode == ZEND_NEW) { } else if (def->opcode == ZEND_NEW) {
/* Objects created via ZEND_NEW are only fully initialized /* Objects created via ZEND_NEW are only fully initialized
* after the DO_FCALL (constructor call) */ * after the DO_FCALL (constructor call) */
def = CG(active_op_array)->opcodes + def->op2.opline_num - 1; int level = 0;
while (def + 1 != opline) {
def++;
if (def->opcode == ZEND_DO_FCALL) {
if (level == 0) {
break;
}
level--;
} else {
switch(def->opcode) {
case ZEND_INIT_FCALL:
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_USER_CALL:
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_NEW:
level++;
break;
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
level--;
break;
}
}
}
if (def + 1 == opline) { if (def + 1 == opline) {
break; break;
} }
@ -2507,6 +2533,7 @@ static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast, int th
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
zend_resolve_class_name(name, type)); zend_resolve_class_name(name, type));
opline->extended_value = zend_alloc_cache_slot();
} else { } else {
zend_ensure_valid_class_fetch_type(fetch_type); zend_ensure_valid_class_fetch_type(fetch_type);
} }
@ -2742,7 +2769,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node); opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node);
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
convert_to_string(CT_CONSTANT(opline->op2)); convert_to_string(CT_CONSTANT(opline->op2));
zend_alloc_polymorphic_cache_slot(opline->op2.constant); opline->extended_value = zend_alloc_polymorphic_cache_slot();
} }
zend_adjust_for_fetch_type(opline, type); zend_adjust_for_fetch_type(opline, type);
@ -2777,12 +2804,15 @@ zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, i
} }
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
convert_to_string(CT_CONSTANT(opline->op1)); convert_to_string(CT_CONSTANT(opline->op1));
zend_alloc_polymorphic_cache_slot(opline->op1.constant); opline->extended_value = zend_alloc_polymorphic_cache_slot();
} }
if (class_node.op_type == IS_CONST) { if (class_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_class_name_literal( opline->op2.constant = zend_add_class_name_literal(
CG(active_op_array), Z_STR(class_node.u.constant)); CG(active_op_array), Z_STR(class_node.u.constant));
if (opline->op1_type != IS_CONST) {
opline->extended_value = zend_alloc_polymorphic_cache_slot();
}
} else { } else {
SET_NODE(opline->op2, &class_node); SET_NODE(opline->op2, &class_node);
} }
@ -3148,7 +3178,7 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
znode var_node, expr_node; znode var_node, expr_node;
zend_op *opline; zend_op *opline;
uint32_t offset; uint32_t offset, cache_slot;
zend_ensure_writable_variable(var_ast); zend_ensure_writable_variable(var_ast);
@ -3178,10 +3208,12 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
zend_compile_expr(&expr_node, expr_ast); zend_compile_expr(&expr_node, expr_ast);
opline = zend_delayed_compile_end(offset); opline = zend_delayed_compile_end(offset);
cache_slot = opline->extended_value;
opline->opcode = opcode; opline->opcode = opcode;
opline->extended_value = ZEND_ASSIGN_OBJ; opline->extended_value = ZEND_ASSIGN_OBJ;
zend_emit_op_data(&expr_node); opline = zend_emit_op_data(&expr_node);
opline->extended_value = cache_slot;
return; return;
EMPTY_SWITCH_DEFAULT_CASE() EMPTY_SWITCH_DEFAULT_CASE()
} }
@ -3385,7 +3417,7 @@ void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast) /
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_ns_func_name_literal( opline->op2.constant = zend_add_ns_func_name_literal(
CG(active_op_array), Z_STR(name_node->u.constant)); CG(active_op_array), Z_STR(name_node->u.constant));
zend_alloc_cache_slot(opline->op2.constant); opline->result.num = zend_alloc_cache_slot();
zend_compile_call_common(result, args_ast, NULL); zend_compile_call_common(result, args_ast, NULL);
} }
@ -3406,7 +3438,8 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a
opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), class); opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), class);
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), method); opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), method);
zend_alloc_cache_slot(opline->op2.constant); /* 2 slots, for class and method */
opline->result.num = zend_alloc_polymorphic_cache_slot();
zval_ptr_dtor(&name_node->u.constant); zval_ptr_dtor(&name_node->u.constant);
} else { } else {
zend_op *opline = get_next_op(CG(active_op_array)); zend_op *opline = get_next_op(CG(active_op_array));
@ -3415,7 +3448,7 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a
SET_UNUSED(opline->op1); SET_UNUSED(opline->op1);
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), str); opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), str);
zend_alloc_cache_slot(opline->op2.constant); opline->result.num = zend_alloc_cache_slot();
} }
} else { } else {
zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node); zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node);
@ -3521,7 +3554,7 @@ int zend_compile_func_defined(znode *result, zend_ast_list *args) /* {{{ */
opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL); opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL);
opline->op1_type = IS_CONST; opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, name); LITERAL_STR(opline->op1, name);
zend_alloc_cache_slot(opline->op1.constant); opline->extended_value = zend_alloc_cache_slot();
/* Lowercase constant name in a separate literal */ /* Lowercase constant name in a separate literal */
{ {
@ -3595,7 +3628,7 @@ static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t
opline->op1.num = zend_vm_calc_used_stack(num_args, fbc); opline->op1.num = zend_vm_calc_used_stack(num_args, fbc);
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
LITERAL_STR(opline->op2, lcname); LITERAL_STR(opline->op2, lcname);
zend_alloc_cache_slot(opline->op2.constant); opline->result.num = zend_alloc_cache_slot();
return SUCCESS; return SUCCESS;
} }
@ -3715,7 +3748,7 @@ static int zend_compile_assert(znode *result, zend_ast_list *args, zend_string *
opline->op2.constant = zend_add_ns_func_name_literal( opline->op2.constant = zend_add_ns_func_name_literal(
CG(active_op_array), name); CG(active_op_array), name);
} }
zend_alloc_cache_slot(opline->op2.constant); opline->result.num = zend_alloc_cache_slot();
if (args->children == 1 && if (args->children == 1 &&
(args->child[0]->kind != ZEND_AST_ZVAL || (args->child[0]->kind != ZEND_AST_ZVAL ||
@ -4075,7 +4108,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
ZVAL_NEW_STR(&name_node.u.constant, lcname); ZVAL_NEW_STR(&name_node.u.constant, lcname);
opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node); opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node);
zend_alloc_cache_slot(opline->op2.constant); opline->result.num = zend_alloc_cache_slot();
zend_compile_call_common(result, args_ast, fbc); zend_compile_call_common(result, args_ast, fbc);
} }
@ -4109,7 +4142,7 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), opline->op2.constant = zend_add_func_name_literal(CG(active_op_array),
Z_STR(method_node.u.constant)); Z_STR(method_node.u.constant));
zend_alloc_polymorphic_cache_slot(opline->op2.constant); opline->result.num = zend_alloc_polymorphic_cache_slot();
} else { } else {
SET_NODE(opline->op2, &method_node); SET_NODE(opline->op2, &method_node);
} }
@ -4170,12 +4203,11 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), opline->op2.constant = zend_add_func_name_literal(CG(active_op_array),
Z_STR(method_node.u.constant)); Z_STR(method_node.u.constant));
if (opline->op1_type == IS_CONST) { opline->result.num = zend_alloc_polymorphic_cache_slot();
zend_alloc_cache_slot(opline->op2.constant);
} else {
zend_alloc_polymorphic_cache_slot(opline->op2.constant);
}
} else { } else {
if (opline->op1_type == IS_CONST) {
opline->result.num = zend_alloc_cache_slot();
}
SET_NODE(opline->op2, &method_node); SET_NODE(opline->op2, &method_node);
} }
zend_check_live_ranges(opline); zend_check_live_ranges(opline);
@ -4238,17 +4270,13 @@ void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */
opline->op1_type = IS_CONST; opline->op1_type = IS_CONST;
opline->op1.constant = zend_add_class_name_literal( opline->op1.constant = zend_add_class_name_literal(
CG(active_op_array), Z_STR(class_node.u.constant)); CG(active_op_array), Z_STR(class_node.u.constant));
opline->op2.num = zend_alloc_cache_slot();
} else { } else {
SET_NODE(opline->op1, &class_node); SET_NODE(opline->op1, &class_node);
} }
zend_compile_call_common(&ctor_result, args_ast, NULL); zend_compile_call_common(&ctor_result, args_ast, NULL);
zend_do_free(&ctor_result); zend_do_free(&ctor_result);
/* We save the position of DO_FCALL for convenience in find_live_range().
* This info is not preserved for runtime. */
opline = &CG(active_op_array)->opcodes[opnum];
opline->op2.opline_num = get_next_op_number(CG(active_op_array));
} }
/* }}} */ /* }}} */
@ -4279,7 +4307,7 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable"); zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable");
} else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) { } else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node); zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node);
zend_alloc_cache_slot(opline->op2.constant); opline->extended_value = zend_alloc_cache_slot();
} else { } else {
/* name_ast should be evaluated only. FETCH_GLOBAL_LOCK instructs FETCH_W /* name_ast should be evaluated only. FETCH_GLOBAL_LOCK instructs FETCH_W
* to not free the name_node operand, so it can be reused in the following * to not free the name_node operand, so it can be reused in the following
@ -5209,6 +5237,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
opline->op1_type = IS_CONST; opline->op1_type = IS_CONST;
opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), opline->op1.constant = zend_add_class_name_literal(CG(active_op_array),
zend_resolve_class_name_ast(class_ast)); zend_resolve_class_name_ast(class_ast));
opline->extended_value = zend_alloc_cache_slot();
if (zend_string_equals_literal(var_name, "this")) { if (zend_string_equals_literal(var_name, "this")) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
@ -5218,7 +5247,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
opline->result.var = lookup_cv(CG(active_op_array), var_name); opline->result.var = lookup_cv(CG(active_op_array), var_name);
if (is_last_catch && is_last_class) { if (is_last_catch && is_last_class) {
opline->extended_value = ZEND_LAST_CATCH; opline->extended_value |= ZEND_LAST_CATCH;
} }
if (!is_last_class) { if (!is_last_class) {
@ -5675,9 +5704,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
/* Allocate cache slot to speed-up run-time class resolution */ /* Allocate cache slot to speed-up run-time class resolution */
if (opline->opcode == ZEND_RECV_INIT) { if (opline->opcode == ZEND_RECV_INIT) {
if (ZEND_TYPE_IS_CLASS(arg_info->type)) { if (ZEND_TYPE_IS_CLASS(arg_info->type)) {
zend_alloc_cache_slot(opline->op2.constant); opline->extended_value = zend_alloc_cache_slot();
} else {
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = -1;
} }
} else { } else {
if (ZEND_TYPE_IS_CLASS(arg_info->type)) { if (ZEND_TYPE_IS_CLASS(arg_info->type)) {
@ -5688,9 +5715,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
} }
} }
} else { } else {
if (opline->opcode == ZEND_RECV_INIT) { if (opline->opcode != ZEND_RECV_INIT) {
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = -1;
} else {
opline->op2.num = -1; opline->op2.num = -1;
} }
} }
@ -6272,6 +6297,7 @@ void zend_compile_use_trait(zend_ast *ast) /* {{{ */
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
zend_resolve_class_name_ast(trait_ast)); zend_resolve_class_name_ast(trait_ast));
opline->extended_value = zend_alloc_cache_slot();
ce->num_traits++; ce->num_traits++;
} }
@ -6314,6 +6340,7 @@ void zend_compile_implements(znode *class_node, zend_ast *ast) /* {{{ */
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
zend_resolve_class_name_ast(class_ast)); zend_resolve_class_name_ast(class_ast));
opline->extended_value = zend_alloc_cache_slot();
CG(active_class_entry)->num_interfaces++; CG(active_class_entry)->num_interfaces++;
} }
@ -7515,6 +7542,7 @@ void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */
opline->op2_type = IS_CONST; opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_class_name_literal( opline->op2.constant = zend_add_class_name_literal(
CG(active_op_array), Z_STR(class_node.u.constant)); CG(active_op_array), Z_STR(class_node.u.constant));
opline->extended_value = zend_alloc_cache_slot();
} else { } else {
SET_NODE(opline->op2, &class_node); SET_NODE(opline->op2, &class_node);
} }
@ -7586,7 +7614,9 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
} }
result->op_type = opline->result_type = IS_TMP_VAR; result->op_type = opline->result_type = IS_TMP_VAR;
opline->extended_value |= ast->kind == ZEND_AST_ISSET ? ZEND_ISSET : 0; if (ast->kind == ZEND_AST_ISSET) {
opline->extended_value |= ZEND_ISSET;
}
} }
/* }}} */ /* }}} */
@ -7749,7 +7779,7 @@ void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */
CG(active_op_array), resolved_name, 0); CG(active_op_array), resolved_name, 0);
} }
} }
zend_alloc_cache_slot(opline->op2.constant); opline->extended_value = zend_alloc_cache_slot();
} }
/* }}} */ /* }}} */
@ -7801,11 +7831,7 @@ void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
zend_set_class_name_op1(opline, &class_node); zend_set_class_name_op1(opline, &class_node);
if (opline->op1_type == IS_CONST) { opline->extended_value = zend_alloc_polymorphic_cache_slot();
zend_alloc_cache_slot(opline->op2.constant);
} else {
zend_alloc_polymorphic_cache_slot(opline->op2.constant);
}
} }
/* }}} */ /* }}} */

View file

@ -2000,96 +2000,6 @@ use_read_property:
} }
} }
static zend_always_inline zval* zend_fetch_static_property_address(zval *varname, zend_uchar varname_type, znode_op op2, zend_uchar op2_type, int type EXECUTE_DATA_DC OPLINE_DC)
{
zval *retval;
zend_string *name, *tmp_name;
zend_class_entry *ce;
if (varname_type == IS_CONST) {
name = Z_STR_P(varname);
} else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) {
name = Z_STR_P(varname);
tmp_name = NULL;
} else {
if (varname_type == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) {
zval_undefined_cv(EX(opline)->op1.var EXECUTE_DATA_CC);
}
name = zval_get_tmp_string(varname, &tmp_name);
}
if (op2_type == IS_CONST) {
if (varname_type == IS_CONST && EXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(varname))) != NULL)) {
retval = CACHED_PTR(Z_CACHE_SLOT_P(varname) + sizeof(void*));
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
if (type != BP_VAR_IS) {
zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
return NULL;
}
return retval;
} else {
zval *class_name = RT_CONSTANT(opline, op2);
if (UNEXPECTED((ce = CACHED_PTR(Z_CACHE_SLOT_P(class_name))) == NULL)) {
ce = zend_fetch_class_by_name(Z_STR_P(class_name), class_name + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(ce == NULL)) {
if (varname_type != IS_CONST) {
zend_tmp_string_release(tmp_name);
}
return NULL;
}
CACHE_PTR(Z_CACHE_SLOT_P(class_name), ce);
}
}
} else {
if (op2_type == IS_UNUSED) {
ce = zend_fetch_class(NULL, op2.num);
if (UNEXPECTED(ce == NULL)) {
if (varname_type != IS_CONST) {
zend_tmp_string_release(tmp_name);
}
return NULL;
}
} else {
ce = Z_CE_P(EX_VAR(op2.var));
}
if (varname_type == IS_CONST &&
EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(varname)) == ce)) {
retval = CACHED_PTR(Z_CACHE_SLOT_P(varname) + sizeof(void*));
/* check if static properties were destoyed */
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
if (type != BP_VAR_IS) {
zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
return NULL;
}
return retval;
}
}
retval = zend_std_get_static_property(ce, name, type == BP_VAR_IS);
if (varname_type != IS_CONST) {
zend_tmp_string_release(tmp_name);
}
if (UNEXPECTED(retval == NULL)) {
return NULL;
}
if (varname_type == IS_CONST) {
CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(varname), ce, retval);
}
return retval;
}
#if ZEND_INTENSIVE_DEBUGGING #if ZEND_INTENSIVE_DEBUGGING
#define CHECK_SYMBOL_TABLES() \ #define CHECK_SYMBOL_TABLES() \

View file

@ -663,7 +663,7 @@ ZEND_API int pass_two(zend_op_array *op_array)
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value); opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2); ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
} }
break; break;

View file

@ -192,7 +192,6 @@ struct _zval_struct {
} u1; } u1;
union { union {
uint32_t next; /* hash collision chain */ uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
uint32_t opline_num; /* opline number (for FAST_CALL) */ uint32_t opline_num; /* opline number (for FAST_CALL) */
uint32_t lineno; /* line number (for ast nodes) */ uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */ uint32_t num_args; /* arguments number for EX(This) */
@ -411,9 +410,6 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
#define Z_NEXT(zval) (zval).u2.next #define Z_NEXT(zval) (zval).u2.next
#define Z_NEXT_P(zval_p) Z_NEXT(*(zval_p)) #define Z_NEXT_P(zval_p) Z_NEXT(*(zval_p))
#define Z_CACHE_SLOT(zval) (zval).u2.cache_slot
#define Z_CACHE_SLOT_P(zval_p) Z_CACHE_SLOT(*(zval_p))
#define Z_LINENO(zval) (zval).u2.lineno #define Z_LINENO(zval) (zval).u2.lineno
#define Z_LINENO_P(zval_p) Z_LINENO(*(zval_p)) #define Z_LINENO_P(zval_p) Z_LINENO(*(zval_p))

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -70,9 +70,11 @@ $vm_op_flags = array(
"ZEND_VM_OP_CLASS_FETCH" => 0x70, "ZEND_VM_OP_CLASS_FETCH" => 0x70,
"ZEND_VM_OP_CONSTRUCTOR" => 0x80, "ZEND_VM_OP_CONSTRUCTOR" => 0x80,
"ZEND_VM_OP_CONST_FETCH" => 0x90, "ZEND_VM_OP_CONST_FETCH" => 0x90,
"ZEND_VM_OP_CACHE_SLOT" => 0xa0,
"ZEND_VM_EXT_VAR_FETCH" => 1<<16, "ZEND_VM_EXT_VAR_FETCH" => 1<<16,
"ZEND_VM_EXT_ISSET" => 1<<17, "ZEND_VM_EXT_ISSET" => 1<<17,
"ZEND_VM_EXT_CACHE_SLOT" => 1<<18,
"ZEND_VM_EXT_ARRAY_INIT" => 1<<19, "ZEND_VM_EXT_ARRAY_INIT" => 1<<19,
"ZEND_VM_EXT_REF" => 1<<20, "ZEND_VM_EXT_REF" => 1<<20,
"ZEND_VM_EXT_MASK" => 0x0f000000, "ZEND_VM_EXT_MASK" => 0x0f000000,
@ -114,6 +116,7 @@ $vm_op_decode = array(
"CLASS_FETCH" => ZEND_VM_OP_CLASS_FETCH, "CLASS_FETCH" => ZEND_VM_OP_CLASS_FETCH,
"CONSTRUCTOR" => ZEND_VM_OP_CONSTRUCTOR, "CONSTRUCTOR" => ZEND_VM_OP_CONSTRUCTOR,
"CONST_FETCH" => ZEND_VM_OP_CONST_FETCH, "CONST_FETCH" => ZEND_VM_OP_CONST_FETCH,
"CACHE_SLOT" => ZEND_VM_OP_CACHE_SLOT,
); );
$vm_ext_decode = array( $vm_ext_decode = array(
@ -129,6 +132,7 @@ $vm_ext_decode = array(
"ISSET" => ZEND_VM_EXT_ISSET, "ISSET" => ZEND_VM_EXT_ISSET,
"REF" => ZEND_VM_EXT_REF, "REF" => ZEND_VM_EXT_REF,
"SRC" => ZEND_VM_EXT_SRC, "SRC" => ZEND_VM_EXT_SRC,
"CACHE_SLOT" => ZEND_VM_EXT_CACHE_SLOT,
); );
$vm_kind_name = array( $vm_kind_name = array(

View file

@ -247,17 +247,17 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x00000707, 0x00000707,
0x07000003, 0x07000003,
0x00000003, 0x00000003,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x04006751, 0x04046751,
0x00000001, 0x00000001,
0x00000001, 0x00000001,
0x00000001, 0x00000001,
@ -283,47 +283,47 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x01000701, 0x01000701,
0x00000000, 0x00000000,
0x00000001, 0x00000001,
0x01000300, 0x01040300,
0x00000000, 0x00000000,
0x01000310, 0x01040310,
0x00000003, 0x00000003,
0x00000010, 0x0000a110,
0x00000310, 0x00040310,
0x00001007, 0x00001007,
0x00001001, 0x00001001,
0x00001001, 0x00001001,
0x01000073, 0x0100a173,
0x01000300, 0x01040300,
0x00004005, 0x00004005,
0x00186703, 0x00186703,
0x00106703, 0x00106703,
0x08000007, 0x08000007,
0x00010107, 0x00010107,
0x00000701, 0x00000701,
0x00000751, 0x00040751,
0x00002003, 0x00002003,
0x03000001, 0x03000001,
0x00000007, 0x00000007,
0x00010107, 0x00010107,
0x00000707, 0x00000707,
0x00000757, 0x00040757,
0x00010107, 0x00010107,
0x00006701, 0x00006701,
0x00000751, 0x00040751,
0x00010107, 0x00010107,
0x00006701, 0x00006701,
0x00000751, 0x00040751,
0x00010107, 0x00010107,
0x00000707, 0x00000707,
0x00000757, 0x00040757,
0x00010107, 0x00010107,
0x00006703, 0x00006703,
0x00000753, 0x00040753,
0x00010107, 0x00010107,
0x00000701, 0x00000701,
0x00000751, 0x00040751,
0x0000070b, 0x0000070b,
0x00000391, 0x00040391,
0x00001001, 0x00001001,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
@ -331,13 +331,13 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x00000000, 0x00000000,
0x01000000, 0x01000000,
0x00001001, 0x00001001,
0x02002003, 0x02042003,
0x00000003, 0x00000003,
0x00000771, 0x00040771,
0x00000057, 0x00000057,
0x0b000003, 0x0b000003,
0x01000757, 0x01040757,
0x01008773, 0x01048773,
0x00030107, 0x00030107,
0x00020707, 0x00020707,
0x00001003, 0x00001003,
@ -346,9 +346,9 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x01000000, 0x01000000,
0x00001003, 0x00001003,
0x00000007, 0x00000007,
0x00000003, 0x00040003,
0x09000003, 0x09000003,
0x00000103, 0x0000a103,
0x00002003, 0x00002003,
0x03000001, 0x03000001,
0x00004005, 0x00004005,
@ -356,29 +356,29 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00000751, 0x00040751,
0x00000751, 0x00040751,
0x00000751, 0x00040751,
0x00000751, 0x00040751,
0x00000751, 0x00040751,
0x00000000, 0x00000000,
0x00007305, 0x00047305,
0x00000000, 0x00000000,
0x00000100, 0x00000100,
0x00000000, 0x00000000,
0x00000003, 0x00000003,
0x00000303, 0x00000303,
0x00000300, 0x00040300,
0x00000100, 0x00000100,
0x00000000, 0x00000000,
0x00006701, 0x00006701,
0x00020757, 0x00060757,
0x00000000, 0x00000000,
0x00000000, 0x00000000,
0x00002000, 0x00002000,
0x00002003, 0x00002003,
0x00000103, 0x00000103,
0x00000000, 0x00040000,
0x00000000, 0x00000000,
0x00000101, 0x00000101,
0x00000071, 0x00000071,
@ -388,24 +388,24 @@ static uint32_t zend_vm_opcodes_flags[199] = {
0x00000003, 0x00000003,
0x00000020, 0x00000020,
0x00003000, 0x00003000,
0x00000010, 0x0000a110,
0x00000000, 0x00000000,
0x00000707, 0x00000707,
0x04006751, 0x04046751,
0x00000301, 0x00040301,
0x00002003, 0x00002003,
0x00000707, 0x00000707,
0x03000000, 0x03000000,
0x03000100, 0x03000100,
0x00007307, 0x00047307,
0x00007307, 0x00047307,
0x00007307, 0x00047307,
0x00007307, 0x00047307,
0x00007307, 0x00047307,
0x00007307, 0x00047307,
0x00007307, 0x00047307,
0x00027307, 0x00067307,
0x00000373, 0x00040373,
0x00100101, 0x00100101,
0x00100301, 0x00100301,
0x00000101, 0x00000101,

View file

@ -48,8 +48,10 @@
#define ZEND_VM_OP_CLASS_FETCH 0x00000070 #define ZEND_VM_OP_CLASS_FETCH 0x00000070
#define ZEND_VM_OP_CONSTRUCTOR 0x00000080 #define ZEND_VM_OP_CONSTRUCTOR 0x00000080
#define ZEND_VM_OP_CONST_FETCH 0x00000090 #define ZEND_VM_OP_CONST_FETCH 0x00000090
#define ZEND_VM_OP_CACHE_SLOT 0x000000a0
#define ZEND_VM_EXT_VAR_FETCH 0x00010000 #define ZEND_VM_EXT_VAR_FETCH 0x00010000
#define ZEND_VM_EXT_ISSET 0x00020000 #define ZEND_VM_EXT_ISSET 0x00020000
#define ZEND_VM_EXT_CACHE_SLOT 0x00040000
#define ZEND_VM_EXT_ARRAY_INIT 0x00080000 #define ZEND_VM_EXT_ARRAY_INIT 0x00080000
#define ZEND_VM_EXT_REF 0x00100000 #define ZEND_VM_EXT_REF 0x00100000
#define ZEND_VM_EXT_MASK 0x0f000000 #define ZEND_VM_EXT_MASK 0x0f000000

View file

@ -965,7 +965,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start); ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start); ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
} }
break; break;

View file

@ -42,76 +42,77 @@
#define LITERAL_PROPERTY 0x0900 #define LITERAL_PROPERTY 0x0900
#define LITERAL_GLOBAL 0x0A00 #define LITERAL_GLOBAL 0x0A00
#define LITERAL_EX_CLASS 0x4000
#define LITERAL_EX_OBJ 0x2000
#define LITERAL_MAY_MERGE 0x1000
#define LITERAL_KIND_MASK 0x0f00 #define LITERAL_KIND_MASK 0x0f00
#define LITERAL_NUM_RELATED_MASK 0x000f #define LITERAL_NUM_RELATED_MASK 0x000f
#define LITERAL_NUM_SLOTS_MASK 0x00f0
#define LITERAL_NUM_SLOTS_SHIFT 4
#define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK) #define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK)
#define LITERAL_NUM_SLOTS(info) ((info & LITERAL_NUM_SLOTS_MASK) >> LITERAL_NUM_SLOTS_SHIFT)
typedef struct _literal_info { typedef struct _literal_info {
uint32_t flags; /* bitmask (see defines above) */ uint32_t flags; /* bitmask (see defines above) */
union {
int num; /* variable number or class name literal number */
} u;
} literal_info; } literal_info;
#define LITERAL_FLAGS(kind, slots, related) \ #define LITERAL_INFO(n, kind, related) do { \
((kind) | ((slots) << LITERAL_NUM_SLOTS_SHIFT) | (related)) info[n].flags = ((kind) | (related)); \
#define LITERAL_INFO(n, kind, merge, slots, related) do { \
info[n].flags = (((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
} while (0) } while (0)
#define LITERAL_INFO_CLASS(n, kind, merge, slots, related, _num) do { \ static zend_bool class_name_type_hint(const zend_op_array *op_array, uint32_t arg_num)
info[n].flags = (LITERAL_EX_CLASS | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
info[n].u.num = (_num); \
} while (0)
#define LITERAL_INFO_OBJ(n, kind, merge, slots, related) do { \
info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
info[n].u.num = (uint32_t)-1; \
} while (0)
static void optimizer_literal_obj_info(literal_info *info,
zend_uchar op_type,
znode_op op,
int constant,
uint32_t kind,
uint32_t slots,
uint32_t related,
zend_op_array *op_array)
{ {
/* For now we merge only $this object properties and methods. zend_arg_info *arg_info;
* In general it's also possible to do it for any CV variable as well,
* but it would require complex dataflow and/or type analysis. if (arg_num > 0) {
*/ if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
if (Z_TYPE(op_array->literals[constant]) == IS_STRING && if (EXPECTED(arg_num <= op_array->num_args)) {
op_type == IS_UNUSED) { arg_info = &op_array->arg_info[arg_num-1];
LITERAL_INFO_OBJ(constant, kind, 1, slots, related); } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
arg_info = &op_array->arg_info[op_array->num_args];
} else {
return 0;
}
return ZEND_TYPE_IS_CLASS(arg_info->type);
}
} else { } else {
LITERAL_INFO(constant, kind, 0, slots, related); arg_info = op_array->arg_info - 1;
return ZEND_TYPE_IS_CLASS(arg_info->type);
} }
return 0;
} }
static void optimizer_literal_class_info(literal_info *info, static uint32_t add_static_slot(HashTable *hash,
zend_uchar op_type, zend_op_array *op_array,
znode_op op, uint32_t op1,
int constant, uint32_t op2,
uint32_t kind, uint32_t kind,
uint32_t slots, int *cache_size)
uint32_t related,
zend_op_array *op_array)
{ {
if (op_type == IS_CONST) { uint32_t ret;
LITERAL_INFO_CLASS(constant, kind, 1, slots, related, op.constant); zend_string *key;
size_t key_len;
zval *class_name = &op_array->literals[op1];
zval *prop_name = &op_array->literals[op2];
zval *pos, tmp;
key_len = Z_STRLEN_P(class_name) + sizeof("::") - 1 + Z_STRLEN_P(prop_name);
key = zend_string_alloc(key_len, 0);
memcpy(ZSTR_VAL(key), Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name) + sizeof("::") - 1,
Z_STRVAL_P(prop_name),
Z_STRLEN_P(prop_name) + 1);
ZSTR_H(key) = zend_hash_func(ZSTR_VAL(key), ZSTR_LEN(key));
ZSTR_H(key) += kind;
pos = zend_hash_find(hash, key);
if (pos) {
ret = Z_LVAL_P(pos);
} else { } else {
LITERAL_INFO(constant, kind, 0, slots, related); ret = *cache_size;
*cache_size += 2 * sizeof(void *);
ZVAL_LONG(&tmp, ret);
zend_hash_add(hash, key, &tmp);
} }
zend_string_release(key);
return ret;
} }
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx) void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
@ -127,9 +128,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
HashTable hash; HashTable hash;
zend_string *key = NULL; zend_string *key = NULL;
void *checkpoint = zend_arena_checkpoint(ctx->arena); void *checkpoint = zend_arena_checkpoint(ctx->arena);
int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot;
if (op_array->last_literal) { if (op_array->last_literal) {
cache_size = 0;
info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info)); info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
/* Mark literals of specific types */ /* Mark literals of specific types */
@ -138,66 +139,48 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
while (opline < end) { while (opline < end) {
switch (opline->opcode) { switch (opline->opcode) {
case ZEND_INIT_FCALL: case ZEND_INIT_FCALL:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1); LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1);
break; break;
case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_FCALL_BY_NAME:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2); LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 2);
break; break;
case ZEND_INIT_NS_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME:
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3); LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 3);
break; break;
case ZEND_INIT_METHOD_CALL: case ZEND_INIT_METHOD_CALL:
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1); LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
} }
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
optimizer_literal_obj_info( LITERAL_INFO(opline->op2.constant, LITERAL_METHOD, 2);
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_METHOD, 2, 2,
op_array);
} }
break; break;
case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL:
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
} }
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
optimizer_literal_class_info( LITERAL_INFO(opline->op2.constant, LITERAL_STATIC_METHOD, 2);
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_STATIC_METHOD, (opline->op1_type == IS_CONST) ? 1 : 2, 2,
op_array);
} }
break; break;
case ZEND_CATCH: case ZEND_CATCH:
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
break; break;
case ZEND_DEFINED: case ZEND_DEFINED:
LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1, 1, 2); LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 2);
break; break;
case ZEND_FETCH_CONSTANT: case ZEND_FETCH_CONSTANT:
if ((opline->op1.num & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) { if ((opline->op1.num & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5); LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 5);
} else { } else {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3); LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 3);
} }
break; break;
case ZEND_FETCH_CLASS_CONSTANT: case ZEND_FETCH_CLASS_CONSTANT:
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
} }
optimizer_literal_class_info( LITERAL_INFO(opline->op2.constant, LITERAL_CLASS_CONST, 1);
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_CLASS_CONST, (opline->op1_type == IS_CONST) ? 1 : 2, 1,
op_array);
break; break;
case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_W:
@ -208,16 +191,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_UNSET_STATIC_PROP: case ZEND_UNSET_STATIC_PROP:
case ZEND_ISSET_ISEMPTY_STATIC_PROP: case ZEND_ISSET_ISEMPTY_STATIC_PROP:
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2);
} }
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
optimizer_literal_class_info( LITERAL_INFO(opline->op1.constant, LITERAL_STATIC_PROPERTY, 1);
info,
opline->op2_type,
opline->op2,
opline->op1.constant,
LITERAL_STATIC_PROPERTY, 2, 1,
op_array);
} }
break; break;
case ZEND_FETCH_CLASS: case ZEND_FETCH_CLASS:
@ -225,12 +202,12 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_ADD_TRAIT: case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF: case ZEND_INSTANCEOF:
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2);
} }
break; break;
case ZEND_NEW: case ZEND_NEW:
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
} }
break; break;
case ZEND_ASSIGN_OBJ: case ZEND_ASSIGN_OBJ:
@ -247,13 +224,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_POST_DEC_OBJ: case ZEND_POST_DEC_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ: case ZEND_ISSET_ISEMPTY_PROP_OBJ:
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
optimizer_literal_obj_info( LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1);
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_PROPERTY, 2, 1,
op_array);
} }
break; break;
case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_ADD:
@ -270,47 +241,30 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_ASSIGN_BW_XOR: case ZEND_ASSIGN_BW_XOR:
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
if (opline->extended_value == ZEND_ASSIGN_OBJ) { if (opline->extended_value == ZEND_ASSIGN_OBJ) {
optimizer_literal_obj_info( LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1);
info,
opline->op1_type,
opline->op1,
opline->op2.constant,
LITERAL_PROPERTY, 2, 1,
op_array);
} else { } else {
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1); LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
} }
} }
break; break;
case ZEND_BIND_GLOBAL: case ZEND_BIND_GLOBAL:
LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 0, 1, 1); LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 1);
break; break;
case ZEND_RECV_INIT: case ZEND_RECV_INIT:
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 0, 0, 1); LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
if (Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) != (uint32_t)-1) {
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = cache_size;
cache_size += sizeof(void *);
}
break; break;
case ZEND_DECLARE_FUNCTION: case ZEND_DECLARE_FUNCTION:
case ZEND_DECLARE_CLASS: case ZEND_DECLARE_CLASS:
case ZEND_DECLARE_INHERITED_CLASS: case ZEND_DECLARE_INHERITED_CLASS:
case ZEND_DECLARE_INHERITED_CLASS_DELAYED: case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 0, 0, 2); LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
break; break;
case ZEND_RECV:
case ZEND_RECV_VARIADIC:
case ZEND_VERIFY_RETURN_TYPE:
if (opline->op2.num != (uint32_t)-1) {
opline->op2.num = cache_size;
cache_size += sizeof(void *);
}
default: default:
if (opline->op1_type == IS_CONST) { if (opline->op1_type == IS_CONST) {
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1); LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1);
} }
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1); LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
} }
break; break;
} }
@ -350,26 +304,15 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
} }
switch (Z_TYPE(op_array->literals[i])) { switch (Z_TYPE(op_array->literals[i])) {
case IS_NULL: case IS_NULL:
/* Only checking MAY_MERGE for IS_NULL here if (l_null < 0) {
* is because only IS_NULL can be default value for class type hinting(RECV_INIT). */ l_null = j;
if ((info[i].flags & LITERAL_MAY_MERGE)) {
if (l_null < 0) {
l_null = j;
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
}
j++;
}
map[i] = l_null;
} else {
map[i] = j;
if (i != j) { if (i != j) {
op_array->literals[j] = op_array->literals[i]; op_array->literals[j] = op_array->literals[i];
info[j] = info[i]; info[j] = info[i];
} }
j++; j++;
} }
map[i] = l_null;
break; break;
case IS_FALSE: case IS_FALSE:
if (l_false < 0) { if (l_false < 0) {
@ -422,34 +365,20 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
} }
break; break;
case IS_STRING: case IS_STRING:
if (info[i].flags & LITERAL_MAY_MERGE) { if (LITERAL_NUM_RELATED(info[i].flags) == 1) {
if (info[i].flags & LITERAL_EX_OBJ) { key = zend_string_copy(Z_STR(op_array->literals[i]));
int key_len = sizeof("$this->") - 1 + Z_STRLEN(op_array->literals[i]); } else {
key = zend_string_alloc(key_len, 0); key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0);
memcpy(ZSTR_VAL(key), "$this->", sizeof("$this->") - 1); ZSTR_H(key) = ZSTR_HASH(Z_STR(op_array->literals[i])) +
memcpy(ZSTR_VAL(key) + sizeof("$this->") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1); LITERAL_NUM_RELATED(info[i].flags) - 1;
ZSTR_LEN(key) = key_len;
} else if (info[i].flags & LITERAL_EX_CLASS) {
int key_len;
zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num];
key_len = Z_STRLEN_P(class_name) + sizeof("::") - 1 + Z_STRLEN(op_array->literals[i]);
key = zend_string_alloc(key_len, 0);
memcpy(ZSTR_VAL(key), Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name) + sizeof("::") - 1,
Z_STRVAL(op_array->literals[i]),
Z_STRLEN(op_array->literals[i]) + 1);
} else {
key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0);
}
ZSTR_H(key) = zend_hash_func(ZSTR_VAL(key), ZSTR_LEN(key));
ZSTR_H(key) += info[i].flags;
} }
if ((info[i].flags & LITERAL_MAY_MERGE) && pos = zend_hash_find(&hash, key);
(pos = zend_hash_find(&hash, key)) != NULL && if (pos != NULL &&
Z_TYPE(op_array->literals[i]) == Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) && Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_STRING &&
info[i].flags == info[Z_LVAL_P(pos)].flags) { LITERAL_NUM_RELATED(info[i].flags) == LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) &&
(LITERAL_NUM_RELATED(info[i].flags) != 2 ||
((info[i].flags & LITERAL_KIND_MASK) != LITERAL_VALUE &&
(info[Z_LVAL_P(pos)].flags & LITERAL_KIND_MASK) != LITERAL_VALUE))) {
zend_string_release(key); zend_string_release(key);
map[i] = Z_LVAL_P(pos); map[i] = Z_LVAL_P(pos);
zval_ptr_dtor_nogc(&op_array->literals[i]); zval_ptr_dtor_nogc(&op_array->literals[i]);
@ -461,19 +390,13 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
} }
} else { } else {
map[i] = j; map[i] = j;
if (info[i].flags & LITERAL_MAY_MERGE) { ZVAL_LONG(&zv, j);
ZVAL_LONG(&zv, j); zend_hash_add_new(&hash, key, &zv);
zend_hash_add_new(&hash, key, &zv); zend_string_release(key);
zend_string_release(key);
}
if (i != j) { if (i != j) {
op_array->literals[j] = op_array->literals[i]; op_array->literals[j] = op_array->literals[i];
info[j] = info[i]; info[j] = info[i];
} }
if (LITERAL_NUM_SLOTS(info[i].flags)) {
Z_CACHE_SLOT(op_array->literals[j]) = cache_size;
cache_size += LITERAL_NUM_SLOTS(info[i].flags) * sizeof(void*);
}
j++; j++;
n = LITERAL_NUM_RELATED(info[i].flags); n = LITERAL_NUM_RELATED(info[i].flags);
while (n > 1) { while (n > 1) {
@ -511,11 +434,19 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
break; break;
} }
} }
zend_hash_destroy(&hash); zend_hash_clean(&hash);
op_array->last_literal = j; op_array->last_literal = j;
op_array->cache_size = cache_size;
/* Update opcodes to use new literals table */ const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int));
memset(const_slot, -1, j * 6 * sizeof(int));
class_slot = const_slot + j;
func_slot = class_slot + j;
bind_var_slot = func_slot + j;
property_slot = bind_var_slot + j;
method_slot = property_slot + j;
/* Update opcodes to use new literals table */
cache_size = 0;
opline = op_array->opcodes; opline = op_array->opcodes;
end = opline + op_array->last; end = opline + op_array->last;
while (opline < end) { while (opline < end) {
@ -525,8 +456,288 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
if (opline->op2_type == IS_CONST) { if (opline->op2_type == IS_CONST) {
opline->op2.constant = map[opline->op2.constant]; opline->op2.constant = map[opline->op2.constant];
} }
switch (opline->opcode) {
case ZEND_RECV_INIT:
if (class_name_type_hint(op_array, opline->op1.num)) {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
}
break;
case ZEND_RECV:
case ZEND_RECV_VARIADIC:
if (class_name_type_hint(op_array, opline->op1.num)) {
opline->op2.num = cache_size;
cache_size += sizeof(void *);
}
break;
case ZEND_VERIFY_RETURN_TYPE:
if (class_name_type_hint(op_array, 0)) {
opline->op2.num = cache_size;
cache_size += sizeof(void *);
}
break;
case ZEND_ASSIGN_ADD:
case ZEND_ASSIGN_SUB:
case ZEND_ASSIGN_MUL:
case ZEND_ASSIGN_DIV:
case ZEND_ASSIGN_POW:
case ZEND_ASSIGN_MOD:
case ZEND_ASSIGN_SL:
case ZEND_ASSIGN_SR:
case ZEND_ASSIGN_CONCAT:
case ZEND_ASSIGN_BW_OR:
case ZEND_ASSIGN_BW_AND:
case ZEND_ASSIGN_BW_XOR:
if (opline->extended_value != ZEND_ASSIGN_OBJ) {
break;
}
if (opline->op2_type == IS_CONST) {
// op2 property
if (opline->op1_type == IS_UNUSED &&
property_slot[opline->op2.constant] >= 0) {
(opline+1)->extended_value = property_slot[opline->op2.constant];
} else {
(opline+1)->extended_value = cache_size;
cache_size += 2 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
property_slot[opline->op2.constant] = (opline+1)->extended_value;
}
}
}
break;
case ZEND_ASSIGN_OBJ:
case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_W:
case ZEND_FETCH_OBJ_RW:
case ZEND_FETCH_OBJ_IS:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_UNSET_OBJ:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
if (opline->op2_type == IS_CONST) {
// op2 property
if (opline->op1_type == IS_UNUSED &&
property_slot[opline->op2.constant] >= 0) {
opline->extended_value = property_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += 2 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
property_slot[opline->op2.constant] = opline->extended_value;
}
}
}
break;
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
if (opline->op2_type == IS_CONST) {
// op2 property
if (opline->op1_type == IS_UNUSED &&
property_slot[opline->op2.constant] >= 0) {
opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISSET);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_ISSET);
cache_size += 2 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISSET;
}
}
}
break;
case ZEND_INIT_FCALL:
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
// op2 func
if (func_slot[opline->op2.constant] >= 0) {
opline->result.num = func_slot[opline->op2.constant];
} else {
opline->result.num = cache_size;
cache_size += sizeof(void *);
func_slot[opline->op2.constant] = opline->result.num;
}
break;
case ZEND_INIT_METHOD_CALL:
if (opline->op2_type == IS_CONST) {
// op2 method
if (opline->op1_type == IS_UNUSED &&
method_slot[opline->op2.constant] >= 0) {
opline->result.num = method_slot[opline->op2.constant];
} else {
opline->result.num = cache_size;
cache_size += 2 * sizeof(void *);
if (opline->op1_type == IS_UNUSED) {
method_slot[opline->op2.constant] = opline->result.num;
}
}
}
break;
case ZEND_INIT_STATIC_METHOD_CALL:
if (opline->op2_type == IS_CONST) {
// op2 static method
if (opline->op1_type == IS_CONST) {
opline->result.num = add_static_slot(&hash, op_array,
opline->op1.constant,
opline->op2.constant,
LITERAL_STATIC_METHOD,
&cache_size);
} else {
opline->result.num = cache_size;
cache_size += 2 * sizeof(void *);
}
} else if (opline->op1_type == IS_CONST) {
// op1 class
if (class_slot[opline->op1.constant] >= 0) {
opline->result.num = class_slot[opline->op1.constant];
} else {
opline->result.num = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op1.constant] = opline->result.num;
}
}
break;
case ZEND_DEFINED:
// op1 const
if (const_slot[opline->op1.constant] >= 0) {
opline->extended_value = const_slot[opline->op1.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
const_slot[opline->op1.constant] = opline->extended_value;
}
break;
case ZEND_FETCH_CONSTANT:
// op2 const
if (const_slot[opline->op2.constant] >= 0) {
opline->extended_value = const_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
const_slot[opline->op2.constant] = opline->extended_value;
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
if (opline->op1_type == IS_CONST) {
// op1/op2 class_const
opline->extended_value = add_static_slot(&hash, op_array,
opline->op1.constant,
opline->op2.constant,
LITERAL_CLASS_CONST,
&cache_size);
} else {
opline->extended_value = cache_size;
cache_size += 2 * sizeof(void *);
}
break;
case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W:
case ZEND_FETCH_STATIC_PROP_RW:
case ZEND_FETCH_STATIC_PROP_IS:
case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP:
if (opline->op1_type == IS_CONST) {
// op1 static property
if (opline->op2_type == IS_CONST) {
opline->extended_value = add_static_slot(&hash, op_array,
opline->op2.constant,
opline->op1.constant,
LITERAL_STATIC_PROPERTY,
&cache_size);
} else {
opline->extended_value = cache_size;
cache_size += 2 * sizeof(void *);
}
} else if (opline->op2_type == IS_CONST) {
// op2 class
if (class_slot[opline->op2.constant] >= 0) {
opline->extended_value = class_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op2.constant] = opline->extended_value;
}
}
break;
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
if (opline->op1_type == IS_CONST) {
// op1 static property
if (opline->op2_type == IS_CONST) {
opline->extended_value = add_static_slot(&hash, op_array,
opline->op2.constant,
opline->op1.constant,
LITERAL_STATIC_PROPERTY,
&cache_size) | (opline->extended_value & ZEND_ISSET);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_ISSET);
cache_size += 2 * sizeof(void *);
}
} else if (opline->op2_type == IS_CONST) {
// op2 class
if (class_slot[opline->op2.constant] >= 0) {
opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISSET);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_ISSET);
cache_size += sizeof(void *);
class_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISSET;
}
}
break;
case ZEND_FETCH_CLASS:
case ZEND_ADD_INTERFACE:
case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF:
if (opline->op2_type == IS_CONST) {
// op2 class
if (class_slot[opline->op2.constant] >= 0) {
opline->extended_value = class_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op2.constant] = opline->extended_value;
}
}
break;
case ZEND_NEW:
if (opline->op1_type == IS_CONST) {
// op1 class
if (class_slot[opline->op1.constant] >= 0) {
opline->op2.num = class_slot[opline->op1.constant];
} else {
opline->op2.num = cache_size;
cache_size += sizeof(void *);
class_slot[opline->op1.constant] = opline->op2.num;
}
}
break;
case ZEND_CATCH:
if (opline->op1_type == IS_CONST) {
// op1 class
if (class_slot[opline->op1.constant] >= 0) {
opline->extended_value = class_slot[opline->op1.constant] | (opline->extended_value & ZEND_LAST_CATCH);
} else {
opline->extended_value = cache_size | (opline->extended_value & ZEND_LAST_CATCH);
cache_size += sizeof(void *);
class_slot[opline->op1.constant] = opline->extended_value & ~ZEND_LAST_CATCH;
}
}
break;
case ZEND_BIND_GLOBAL:
// op2 bind var
if (bind_var_slot[opline->op2.constant] >= 0) {
opline->extended_value = bind_var_slot[opline->op2.constant];
} else {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
bind_var_slot[opline->op2.constant] = opline->extended_value;
}
break;
}
opline++; opline++;
} }
op_array->cache_size = cache_size;
zend_hash_destroy(&hash);
zend_arena_release(&ctx->arena, checkpoint); zend_arena_release(&ctx->arena, checkpoint);
#if DEBUG_COMPACT_LITERALS #if DEBUG_COMPACT_LITERALS

View file

@ -552,7 +552,7 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa
} }
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
if (ZEND_OP2_JMP_ADDR(opline) == op_array->opcodes + old->start) { if (ZEND_OP2_JMP_ADDR(opline) == op_array->opcodes + old->start) {
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, op_array->opcodes + dst->start); ZEND_SET_OP_JMP_ADDR(opline, opline->op2, op_array->opcodes + dst->start);
} }

View file

@ -193,14 +193,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
} else if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) { } else if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL; fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
literal_dtor(&ZEND_OP2_LITERAL(fcall)); literal_dtor(&ZEND_OP2_LITERAL(fcall));
fcall->op2.constant = fcall->op2.constant + 1; fcall->op2.constant = fcall->op2.constant + 1;
opline->opcode = zend_get_call_op(fcall, call_stack[call].func); opline->opcode = zend_get_call_op(fcall, call_stack[call].func);
} else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
fcall->opcode = ZEND_INIT_FCALL; fcall->opcode = ZEND_INIT_FCALL;
fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func);
Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant]);
literal_dtor(&op_array->literals[fcall->op2.constant + 2]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
fcall->op2.constant = fcall->op2.constant + 1; fcall->op2.constant = fcall->op2.constant + 1;

View file

@ -438,7 +438,7 @@ static inline int ct_eval_isset_dim(zval *result, uint32_t extended_value, zval
// TODO // TODO
return FAILURE; return FAILURE;
} else { } else {
ZVAL_BOOL(result, extended_value != ZEND_ISSET); ZVAL_BOOL(result, !(extended_value & ZEND_ISSET));
return SUCCESS; return SUCCESS;
} }
} }
@ -592,7 +592,7 @@ static inline int ct_eval_isset_obj(zval *result, uint32_t extended_value, zval
} }
return SUCCESS; return SUCCESS;
} else { } else {
ZVAL_BOOL(result, extended_value != ZEND_ISSET); ZVAL_BOOL(result, !(extended_value & ZEND_ISSET));
return SUCCESS; return SUCCESS;
} }
} }

View file

@ -385,7 +385,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
BB_START(i + 1); BB_START(i + 1);
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes); BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
} }
BB_START(i + 1); BB_START(i + 1);
@ -546,7 +546,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
block->successors[1] = j + 1; block->successors[1] = j + 1;
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
block->successors_count = 2; block->successors_count = 2;
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]; block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = j + 1; block->successors[1] = j + 1;

View file

@ -674,7 +674,7 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
} else { } else {
uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags); uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags);
if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) { if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) {
if (opline->opcode != ZEND_CATCH || opline->extended_value != ZEND_LAST_CATCH) { if (opline->opcode != ZEND_CATCH || !(opline->extended_value & ZEND_LAST_CATCH)) {
if (b) { if (b) {
fprintf(stderr, " BB%d", b->successors[n++]); fprintf(stderr, " BB%d", b->successors[n++]);
} else { } else {

View file

@ -206,7 +206,6 @@ int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv)
op_array->last_literal++; op_array->last_literal++;
op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval)); op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval));
ZVAL_COPY_VALUE(&op_array->literals[i], zv); ZVAL_COPY_VALUE(&op_array->literals[i], zv);
Z_CACHE_SLOT(op_array->literals[i]) = -1;
return i; return i;
} }
@ -232,13 +231,10 @@ static inline void drop_leading_backslash(zval *val) {
} }
} }
static inline void alloc_cache_slots_op1(zend_op_array *op_array, zend_op *opline, uint32_t num) { static inline uint32_t alloc_cache_slots(zend_op_array *op_array, uint32_t num) {
Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size; uint32_t ret = op_array->cache_size;
op_array->cache_size += num * sizeof(void *);
}
static inline void alloc_cache_slots_op2(zend_op_array *op_array, zend_op *opline, uint32_t num) {
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
op_array->cache_size += num * sizeof(void *); op_array->cache_size += num * sizeof(void *);
return ret;
} }
#define REQUIRES_STRING(val) do { \ #define REQUIRES_STRING(val) do { \
@ -275,15 +271,43 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_RETURN_BY_REF: case ZEND_RETURN_BY_REF:
case ZEND_INSTANCEOF: case ZEND_INSTANCEOF:
return 0; return 0;
case ZEND_INIT_STATIC_METHOD_CALL:
case ZEND_CATCH: case ZEND_CATCH:
case ZEND_FETCH_CLASS_CONSTANT: REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_LAST_CATCH);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_DEFINED: case ZEND_DEFINED:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
opline->extended_value = alloc_cache_slots(op_array, 1);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_NEW: case ZEND_NEW:
REQUIRES_STRING(val); REQUIRES_STRING(val);
drop_leading_backslash(val); drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val); opline->op1.constant = zend_optimizer_add_literal(op_array, val);
alloc_cache_slots_op1(op_array, opline, 1); opline->op2.num = alloc_cache_slots(op_array, 1);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_INIT_STATIC_METHOD_CALL:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
if (opline->op2_type != IS_CONST) {
opline->result.num = alloc_cache_slots(op_array, 1);
}
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break;
case ZEND_FETCH_CLASS_CONSTANT:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
if (opline->op2_type != IS_CONST) {
opline->extended_value = alloc_cache_slots(op_array, 1);
}
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
break; break;
case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_R:
@ -292,9 +316,23 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_FETCH_STATIC_PROP_IS: case ZEND_FETCH_STATIC_PROP_IS:
case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP:
TO_STRING_NOWARN(val); TO_STRING_NOWARN(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val); opline->op1.constant = zend_optimizer_add_literal(op_array, val);
alloc_cache_slots_op1(op_array, opline, 2); if (opline->op2_type == IS_CONST && opline->extended_value + sizeof(void*) == op_array->cache_size) {
op_array->cache_size += sizeof(void *);
} else {
opline->extended_value = alloc_cache_slots(op_array, 2);
}
break;
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
TO_STRING_NOWARN(val);
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
if (opline->op2_type == IS_CONST && (opline->extended_value & ~ZEND_ISSET) + sizeof(void*) == op_array->cache_size) {
op_array->cache_size += sizeof(void *);
} else {
opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISSET);
}
break; break;
case ZEND_SEND_VAR: case ZEND_SEND_VAR:
opline->opcode = ZEND_SEND_VAL; opline->opcode = ZEND_SEND_VAL;
@ -351,11 +389,22 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
(opline + 1)->op2.var == opline->result.var) { (opline + 1)->op2.var == opline->result.var) {
return 0; return 0;
} }
case ZEND_INIT_FCALL_BY_NAME:
/*case ZEND_INIT_NS_FCALL_BY_NAME:*/
case ZEND_ADD_INTERFACE: case ZEND_ADD_INTERFACE:
case ZEND_ADD_TRAIT: case ZEND_ADD_TRAIT:
case ZEND_INSTANCEOF: case ZEND_INSTANCEOF:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
opline->extended_value = alloc_cache_slots(op_array, 1);
break;
case ZEND_INIT_FCALL_BY_NAME:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
opline->result.num = alloc_cache_slots(op_array, 1);
break;
case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_R:
case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_W:
case ZEND_FETCH_STATIC_PROP_RW: case ZEND_FETCH_STATIC_PROP_RW:
@ -363,12 +412,22 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_UNSET:
case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
case ZEND_UNSET_STATIC_PROP: case ZEND_UNSET_STATIC_PROP:
REQUIRES_STRING(val);
drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
if (opline->op1_type != IS_CONST) {
opline->extended_value = alloc_cache_slots(op_array, 1);
}
break;
case ZEND_ISSET_ISEMPTY_STATIC_PROP: case ZEND_ISSET_ISEMPTY_STATIC_PROP:
REQUIRES_STRING(val); REQUIRES_STRING(val);
drop_leading_backslash(val); drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
alloc_cache_slots_op2(op_array, opline, 1); if (opline->op1_type != IS_CONST) {
opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_ISSET);
}
break; break;
case ZEND_INIT_FCALL: case ZEND_INIT_FCALL:
REQUIRES_STRING(val); REQUIRES_STRING(val);
@ -380,7 +439,7 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
val = &tmp; val = &tmp;
} }
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
alloc_cache_slots_op2(op_array, opline, 1); opline->result.num = alloc_cache_slots(op_array, 1);
break; break;
case ZEND_INIT_DYNAMIC_CALL: case ZEND_INIT_DYNAMIC_CALL:
if (Z_TYPE_P(val) == IS_STRING) { if (Z_TYPE_P(val) == IS_STRING) {
@ -398,19 +457,25 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
drop_leading_backslash(val); drop_leading_backslash(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
alloc_cache_slots_op2(op_array, opline, 1); opline->result.num = alloc_cache_slots(op_array, 1);
} else { } else {
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
} }
break; break;
case ZEND_INIT_METHOD_CALL: case ZEND_INIT_METHOD_CALL:
REQUIRES_STRING(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
opline->result.num = alloc_cache_slots(op_array, 2);
break;
case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL:
REQUIRES_STRING(val); REQUIRES_STRING(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
alloc_cache_slots_op2(op_array, opline, 2); if (opline->op1_type != IS_CONST) {
opline->result.num = alloc_cache_slots(op_array, 2);
}
break; break;
/*case ZEND_FETCH_CLASS_CONSTANT:*/
case ZEND_ASSIGN_OBJ: case ZEND_ASSIGN_OBJ:
case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_R:
case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_W:
@ -423,10 +488,14 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
case ZEND_PRE_DEC_OBJ: case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ: case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ: case ZEND_POST_DEC_OBJ:
TO_STRING_NOWARN(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
opline->extended_value = alloc_cache_slots(op_array, 2);
break;
case ZEND_ISSET_ISEMPTY_PROP_OBJ: case ZEND_ISSET_ISEMPTY_PROP_OBJ:
TO_STRING_NOWARN(val); TO_STRING_NOWARN(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
alloc_cache_slots_op2(op_array, opline, 2); opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISSET);
break; break;
case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_ADD:
case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_SUB:
@ -443,7 +512,7 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
if (opline->extended_value == ZEND_ASSIGN_OBJ) { if (opline->extended_value == ZEND_ASSIGN_OBJ) {
TO_STRING_NOWARN(val); TO_STRING_NOWARN(val);
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
alloc_cache_slots_op2(op_array, opline, 2); (opline+1)->extended_value = alloc_cache_slots(op_array, 2);
} else { } else {
opline->op2.constant = zend_optimizer_add_literal(op_array, val); opline->op2.constant = zend_optimizer_add_literal(op_array, val);
} }
@ -766,7 +835,7 @@ void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, z
new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)); new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline)); ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
} }
break; break;
@ -806,7 +875,7 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]); ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]); ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
} }
break; break;
@ -1174,7 +1243,7 @@ static void zend_redo_pass_two(zend_op_array *op_array)
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes]; opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes]; opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
} }
break; break;
@ -1260,7 +1329,7 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes]; opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes]; opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
} }
break; break;

View file

@ -447,7 +447,7 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
SERIALIZE_PTR(opline->op2.jmp_addr); SERIALIZE_PTR(opline->op2.jmp_addr);
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
SERIALIZE_PTR(opline->op2.jmp_addr); SERIALIZE_PTR(opline->op2.jmp_addr);
} }
break; break;
@ -1053,7 +1053,7 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
UNSERIALIZE_PTR(opline->op2.jmp_addr); UNSERIALIZE_PTR(opline->op2.jmp_addr);
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
UNSERIALIZE_PTR(opline->op2.jmp_addr); UNSERIALIZE_PTR(opline->op2.jmp_addr);
} }
break; break;

View file

@ -453,7 +453,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes]; opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
break; break;
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value != ZEND_LAST_CATCH) { if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes]; opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
} }
break; break;

View file

@ -115,7 +115,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *opline) /*{{{ */
/* RESULT */ /* RESULT */
switch (opline->opcode) { switch (opline->opcode) {
case ZEND_CATCH: case ZEND_CATCH:
if (opline->extended_value == ZEND_LAST_CATCH) { if (opline->extended_value & ZEND_LAST_CATCH) {
if (decode[2]) { if (decode[2]) {
efree(decode[2]); efree(decode[2]);
decode[2] = NULL; decode[2] = NULL;

View file

@ -764,16 +764,16 @@ PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *execute_data, zen
while (1) { while (1) {
zend_class_entry *ce; zend_class_entry *ce;
if (!(ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(cur, cur->op1))))) { if (!(ce = CACHED_PTR(cur->extended_value & ~ZEND_LAST_CATCH))) {
ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(cur, cur->op1)), RT_CONSTANT(cur, cur->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD); ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(cur, cur->op1)), RT_CONSTANT(cur, cur->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);
CACHE_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(cur, cur->op1)), ce); CACHE_PTR(cur->extended_value & ~ZEND_LAST_CATCH, ce);
} }
if (ce == exception->ce || (ce && instanceof_function(exception->ce, ce))) { if (ce == exception->ce || (ce && instanceof_function(exception->ce, ce))) {
return 1; return 1;
} }
if (cur->extended_value == ZEND_LAST_CATCH) { if (cur->extended_value & ZEND_LAST_CATCH) {
return 0; return 0;
} }

View file

@ -26,7 +26,7 @@ prompt> [L7 %s ECHO<1> "ok\n"
00009: } catch (Error $e) { 00009: } catch (Error $e) {
prompt> ok prompt> ok
[L7 %s FAST_RET ~%d try-catch(0) %s] [L7 %s FAST_RET ~%d try-catch(0) %s]
[L9 %s CATCH<1> "Error" $e %s] [L9 %s CATCH<%d> "Error" $e %s]
>00005: x(); >00005: x();
00006: } finally { 00006: } finally {
00007: print "ok\n"; 00007: print "ok\n";

View file

@ -25,7 +25,7 @@ prompt> [L0 %s HANDLE_EXCEPTION
00005: } 00005: }
00006: 00006:
prompt> [L0 %s HANDLE_EXCEPTION %s] prompt> [L0 %s HANDLE_EXCEPTION %s]
[L9 %s CATCH<1> "Exception" $e %s] [L9 %s CATCH<%d> "Exception" $e %s]
>00008: foo(); >00008: foo();
00009: } catch (Exception $e) { 00009: } catch (Exception $e) {
00010: echo "ok"; 00010: echo "ok";