From: Dmitry Stogov Date: Tue, 12 Jan 2016 09:20:35 +0000 (+0300) Subject: Introduced BIND_STATIC opcode instead of FETCH_R/FETCH_W(static)+ASSIGN/ASSIGN_REF... X-Git-Tag: php-7.1.0alpha1~617^2~74 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6579e484171889776d6cba23f8365758f2c8a4af;p=php Introduced BIND_STATIC opcode instead of FETCH_R/FETCH_W(static)+ASSIGN/ASSIGN_REF (similar to BIND_GLOBAL). In the future we may refer to static variable by index instead of name, to eliminate hash lookup. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e9cc4bf84c..2cc1a640aa 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3746,16 +3746,10 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_ } zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value); - opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL); - opline->extended_value = ZEND_FETCH_STATIC; - - if (by_ref) { - zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast); - zend_emit_assign_ref_znode(fetch_ast, &result); - } else { - zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast); - zend_emit_assign_znode(fetch_ast, &result); - } + opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node); + opline->op1_type = IS_CV; + opline->op1.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR(var_node.u.constant))); + opline->extended_value = by_ref; } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 2984f75b64..5b5f19995a 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -890,7 +890,6 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); /* global/local fetches */ #define ZEND_FETCH_GLOBAL 0x00000000 #define ZEND_FETCH_LOCAL 0x10000000 -#define ZEND_FETCH_STATIC 0x20000000 #define ZEND_FETCH_GLOBAL_LOCK 0x40000000 #define ZEND_FETCH_TYPE_MASK 0x70000000 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 8f30373e87..fffcb9cbb7 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1537,15 +1537,6 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_d if (EXPECTED(fetch_type == ZEND_FETCH_GLOBAL_LOCK) || EXPECTED(fetch_type == ZEND_FETCH_GLOBAL)) { ht = &EG(symbol_table); - } else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) { - ZEND_ASSERT(EX(func)->op_array.static_variables != NULL); - ht = EX(func)->op_array.static_variables; - if (GC_REFCOUNT(ht) > 1) { - if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(ht)--; - } - EX(func)->op_array.static_variables = ht = zend_array_dup(ht); - } } else { ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL); if (!EX(symbol_table)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b0637fcc55..47acc71e8f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1474,14 +1474,7 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type) } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - FREE_OP1(); - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { FREE_OP1(); } @@ -8028,4 +8021,55 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + HashTable *ht; + zval *varname; + zval *value; + zval *variable_ptr; + + SAVE_OPLINE(); + variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); + zval_ptr_dtor(variable_ptr); + + ht = EX(func)->op_array.static_variables; + ZEND_ASSERT(ht != NULL); + if (GC_REFCOUNT(ht) > 1) { + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { + GC_REFCOUNT(ht)--; + } + EX(func)->op_array.static_variables = ht = zend_array_dup(ht); + } + + varname = GET_OP2_ZVAL_PTR(BP_VAR_R); + value = zend_hash_find(ht, Z_STR_P(varname)); + + if (opline->extended_value) { + if (Z_CONSTANT_P(value)) { + if (UNEXPECTED(zval_update_constant_ex(value, 1, NULL) != SUCCESS)) { + ZVAL_NULL(variable_ptr); + HANDLE_EXCEPTION(); + } + } + if (UNEXPECTED(!Z_ISREF_P(value))) { + zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference)); + GC_REFCOUNT(ref) = 2; + GC_TYPE_INFO(ref) = IS_REFERENCE; + ZVAL_COPY_VALUE(&ref->val, value); + Z_REF_P(value) = ref; + Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; + ZVAL_REF(variable_ptr, ref); + } else { + Z_ADDREF_P(value); + ZVAL_REF(variable_ptr, Z_REF_P(value)); + } + } else { + ZVAL_COPY(variable_ptr, value); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_DEFINE_OP(137, ZEND_OP_DATA); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4de081d476..080c799f7a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7199,14 +7199,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { } @@ -32486,6 +32479,57 @@ check_indirect: ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + HashTable *ht; + zval *varname; + zval *value; + zval *variable_ptr; + + SAVE_OPLINE(); + variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var); + zval_ptr_dtor(variable_ptr); + + ht = EX(func)->op_array.static_variables; + ZEND_ASSERT(ht != NULL); + if (GC_REFCOUNT(ht) > 1) { + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { + GC_REFCOUNT(ht)--; + } + EX(func)->op_array.static_variables = ht = zend_array_dup(ht); + } + + varname = EX_CONSTANT(opline->op2); + value = zend_hash_find(ht, Z_STR_P(varname)); + + if (opline->extended_value) { + if (Z_CONSTANT_P(value)) { + if (UNEXPECTED(zval_update_constant_ex(value, 1, NULL) != SUCCESS)) { + ZVAL_NULL(variable_ptr); + HANDLE_EXCEPTION(); + } + } + if (UNEXPECTED(!Z_ISREF_P(value))) { + zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference)); + GC_REFCOUNT(ref) = 2; + GC_TYPE_INFO(ref) = IS_REFERENCE; + ZVAL_COPY_VALUE(&ref->val, value); + Z_REF_P(value) = ref; + Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; + ZVAL_REF(variable_ptr, ref); + } else { + Z_ADDREF_P(value); + ZVAL_REF(variable_ptr, Z_REF_P(value)); + } + } else { + ZVAL_COPY(variable_ptr, value); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_IDENTICAL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -33627,14 +33671,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { } @@ -42016,14 +42053,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - zval_ptr_dtor_nogc(free_op1); - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { zval_ptr_dtor_nogc(free_op1); } @@ -49390,6 +49420,31 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_BIND_STATIC_SPEC_CV_CONST_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = labels; diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index a2ed83ee9e..665efd65d1 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include #include -static const char *zend_vm_opcodes_names[183] = { +static const char *zend_vm_opcodes_names[184] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -205,9 +205,10 @@ static const char *zend_vm_opcodes_names[183] = { "ZEND_ISSET_ISEMPTY_STATIC_PROP", "ZEND_FETCH_CLASS_CONSTANT", "ZEND_BIND_LEXICAL", + "ZEND_BIND_STATIC", }; -static uint32_t zend_vm_opcodes_flags[183] = { +static uint32_t zend_vm_opcodes_flags[184] = { 0x00000000, 0x00000707, 0x00000707, @@ -391,6 +392,7 @@ static uint32_t zend_vm_opcodes_flags[183] = { 0x00027307, 0x00000373, 0x00100101, + 0x00100301, }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index bb677134c6..1b23b76516 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -255,7 +255,8 @@ END_EXTERN_C() #define ZEND_ISSET_ISEMPTY_STATIC_PROP 180 #define ZEND_FETCH_CLASS_CONSTANT 181 #define ZEND_BIND_LEXICAL 182 +#define ZEND_BIND_STATIC 183 -#define ZEND_VM_LAST_OPCODE 182 +#define ZEND_VM_LAST_OPCODE 183 #endif diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c index 65c19b21d9..9e71e00b65 100644 --- a/ext/opcache/Optimizer/zend_dfg.c +++ b/ext/opcache/Optimizer/zend_dfg.c @@ -92,6 +92,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg case ZEND_ASSIGN: case ZEND_ASSIGN_REF: case ZEND_BIND_GLOBAL: + case ZEND_BIND_STATIC: case ZEND_SEND_VAR_EX: case ZEND_SEND_REF: case ZEND_SEND_VAR_NO_REF: diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 1eacd401b1..53458644fc 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -510,9 +510,6 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * case ZEND_FETCH_LOCAL: fprintf(stderr, " (local)"); break; - case ZEND_FETCH_STATIC: - fprintf(stderr, " (static)"); - break; case ZEND_FETCH_GLOBAL_LOCK: fprintf(stderr, " (global+lock)"); break; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 6bc7fb7a53..41bd4eebb0 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -3067,6 +3067,7 @@ static void zend_update_type_info(const zend_op_array *op_array, } break; case ZEND_BIND_GLOBAL: + case ZEND_BIND_STATIC: tmp = (MAY_BE_REF | MAY_BE_ANY ); UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); break; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index b942391850..059550b63d 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -275,6 +275,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, } break; case ZEND_BIND_GLOBAL: + case ZEND_BIND_STATIC: if (opline->op1_type == IS_CV) { ssa_ops[k].op1_def = ssa_vars_count; var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;