diff options
Diffstat (limited to 'Zend/zend_vm_def.h')
-rw-r--r-- | Zend/zend_vm_def.h | 508 |
1 files changed, 295 insertions, 213 deletions
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 75062824f2..115279dcfd 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -446,7 +446,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(16, ZEND_IS_IDENTICAL, CONST|TMP|VAR|CV, CONST|T { USE_OPLINE zval *op1, *op2; - zend_bool result; + bool result; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); @@ -461,7 +461,7 @@ ZEND_VM_HANDLER(196, ZEND_CASE_STRICT, TMP|VAR, CONST|TMP|VAR|CV) { USE_OPLINE zval *op1, *op2; - zend_bool result; + bool result; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); @@ -475,7 +475,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(17, ZEND_IS_NOT_IDENTICAL, CONST|TMP|VAR|CV, CON { USE_OPLINE zval *op1, *op2; - zend_bool result; + bool result; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); @@ -1727,8 +1727,9 @@ ZEND_VM_C_LABEL(fetch_this): } else if (type == BP_VAR_IS) { retval = &EG(uninitialized_zval); } else { - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(name)); - if (type == BP_VAR_RW) { + zend_error(E_WARNING, "Undefined %svariable $%s", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + if (type == BP_VAR_RW && !EG(exception)) { retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); } else { retval = &EG(uninitialized_zval); @@ -1746,8 +1747,9 @@ ZEND_VM_C_LABEL(fetch_this): } else if (type == BP_VAR_IS) { retval = &EG(uninitialized_zval); } else { - zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(name)); - if (type == BP_VAR_RW) { + zend_error(E_WARNING, "Undefined %svariable $%s", + (opline->extended_value & ZEND_FETCH_GLOBAL ? "global " : ""), ZSTR_VAL(name)); + if (type == BP_VAR_RW && !EG(exception)) { ZVAL_NULL(retval); } else { retval = &EG(uninitialized_zval); @@ -2104,6 +2106,11 @@ ZEND_VM_C_LABEL(fetch_obj_r_fast_copy): } retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, EX_VAR(opline->result.var)); +#if ZEND_DEBUG + if (!EG(exception) && zobj->handlers->read_property != zend_std_read_property) { + zend_verify_internal_read_property_type(zobj, name, retval); + } +#endif if (OP2_TYPE != IS_CONST) { zend_tmp_string_release(tmp_name); @@ -2822,6 +2829,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { zend_detach_symbol_table(execute_data); + zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); #ifdef ZEND_PREFER_RELOAD @@ -3892,7 +3900,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + bool should_throw = zend_internal_call_should_throw(fbc, call); #endif ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -4010,7 +4018,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER)) EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + bool should_throw = zend_internal_call_should_throw(fbc, call); #endif ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -4114,7 +4122,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER)) EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + bool should_throw = zend_internal_call_should_throw(fbc, call); #endif ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; @@ -4225,7 +4233,7 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV } SAVE_OPLINE(); - if (UNEXPECTED(!zend_check_type_slow(ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, NULL, 1, 0))) { zend_verify_return_error(EX(func), retval_ptr); HANDLE_EXCEPTION(); } @@ -4548,7 +4556,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, JMP_ADDR, LAST_CATCH|CACHE_SLOT) } catch_ce = CACHED_PTR(opline->extended_value & ~ZEND_LAST_CATCH); if (UNEXPECTED(catch_ce == NULL)) { - catch_ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_NO_AUTOLOAD); + catch_ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_SILENT); CACHE_PTR(opline->extended_value & ~ZEND_LAST_CATCH, catch_ce); } @@ -5002,7 +5010,7 @@ ZEND_VM_C_LABEL(send_again): HashTable *ht = Z_ARRVAL_P(args); zval *arg, *top; zend_string *name; - zend_bool have_named_params = 0; + bool have_named_params = 0; zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht)); @@ -5073,7 +5081,7 @@ ZEND_VM_C_LABEL(send_again): } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { zend_class_entry *ce = Z_OBJCE_P(args); zend_object_iterator *iter; - zend_bool have_named_params = 0; + bool have_named_params = 0; if (!ce || !ce->get_iterator) { zend_type_error("Only arrays and Traversables can be unpacked"); @@ -5090,26 +5098,27 @@ ZEND_VM_C_LABEL(send_again): HANDLE_EXCEPTION(); } - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); + const zend_object_iterator_funcs *funcs = iter->funcs; + if (funcs->rewind) { + funcs->rewind(iter); } - for (; iter->funcs->valid(iter) == SUCCESS; ++arg_num) { + for (; funcs->valid(iter) == SUCCESS; ++arg_num) { zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { break; } - arg = iter->funcs->get_current_data(iter); + arg = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { break; } zend_string *name = NULL; - if (iter->funcs->get_current_key) { + if (funcs->get_current_key) { zval key; - iter->funcs->get_current_key(iter, &key); + funcs->get_current_key(iter, &key); if (UNEXPECTED(EG(exception) != NULL)) { break; } @@ -5171,7 +5180,7 @@ ZEND_VM_C_LABEL(send_again): ZEND_CALL_NUM_ARGS(EX(call))++; } - iter->funcs->move_forward(iter); + funcs->move_forward(iter); } zend_iterator_dtor(iter); @@ -5235,7 +5244,7 @@ ZEND_VM_C_LABEL(send_array): arg_num = 1; param = ZEND_CALL_ARG(EX(call), 1); ZEND_HASH_FOREACH_VAL(ht, arg) { - zend_bool must_wrap = 0; + bool must_wrap = 0; if (skip > 0) { skip--; continue; @@ -5271,7 +5280,7 @@ ZEND_VM_C_LABEL(send_array): FREE_OP2(); } else { zend_string *name; - zend_bool have_named_params; + bool have_named_params; zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); arg_num = 1; param = ZEND_CALL_ARG(EX(call), 1); @@ -5292,7 +5301,7 @@ ZEND_VM_C_LABEL(send_array): HANDLE_EXCEPTION(); } - zend_bool must_wrap = 0; + bool must_wrap = 0; if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { @@ -5371,7 +5380,7 @@ ZEND_VM_COLD_HELPER(zend_missing_arg_helper, ANY, ANY) HANDLE_EXCEPTION(); } -ZEND_VM_COLD_HELPER(zend_verify_recv_arg_type_helper, ANY, ANY, zval *op_1) +ZEND_VM_HELPER(zend_verify_recv_arg_type_helper, ANY, ANY, zval *op_1) { USE_OPLINE @@ -5819,7 +5828,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO } } - zv = zend_hash_find_ex(&ce->constants_table, Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1); + zv = zend_hash_find_ex(CE_CONSTANTS_TABLE(ce), Z_STR_P(RT_CONSTANT(opline, opline->op2)), 1); if (EXPECTED(zv != NULL)) { c = Z_PTR_P(zv); scope = EX(func)->op_array.scope; @@ -5950,9 +5959,11 @@ ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY) { USE_OPLINE zval *op1; + HashTable *result_ht; SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR(BP_VAR_R); + result_ht = Z_ARRVAL_P(EX_VAR(opline->result.var)); ZEND_VM_C_LABEL(add_unpack_again): if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { @@ -5961,16 +5972,14 @@ ZEND_VM_C_LABEL(add_unpack_again): zend_string *key; ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { + if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) { + val = Z_REFVAL_P(val); + } + Z_TRY_ADDREF_P(val); if (key) { - zend_throw_error(NULL, "Cannot unpack array with string keys"); - FREE_OP1(); - HANDLE_EXCEPTION(); + zend_hash_update(result_ht, key, val); } else { - if (Z_ISREF_P(val) && Z_REFCOUNT_P(val) == 1) { - val = Z_REFVAL_P(val); - } - Z_TRY_ADDREF_P(val); - if (!zend_hash_next_index_insert(Z_ARRVAL_P(EX_VAR(opline->result.var)), val)) { + if (!zend_hash_next_index_insert(result_ht, val)) { zend_cannot_add_element(); zval_ptr_dtor_nogc(val); break; @@ -5995,48 +6004,59 @@ ZEND_VM_C_LABEL(add_unpack_again): HANDLE_EXCEPTION(); } - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); + const zend_object_iterator_funcs *funcs = iter->funcs; + if (funcs->rewind) { + funcs->rewind(iter); } - for (; iter->funcs->valid(iter) == SUCCESS; ) { + for (; funcs->valid(iter) == SUCCESS; ) { zval *val; if (UNEXPECTED(EG(exception) != NULL)) { break; } - val = iter->funcs->get_current_data(iter); + val = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { break; } - if (iter->funcs->get_current_key) { - zval key; - iter->funcs->get_current_key(iter, &key); + zval key; + if (funcs->get_current_key) { + funcs->get_current_key(iter, &key); if (UNEXPECTED(EG(exception) != NULL)) { break; } - if (UNEXPECTED(Z_TYPE(key) != IS_LONG)) { + if (UNEXPECTED(Z_TYPE(key) != IS_LONG && Z_TYPE(key) != IS_STRING)) { zend_throw_error(NULL, - (Z_TYPE(key) == IS_STRING) ? - "Cannot unpack Traversable with string keys" : - "Cannot unpack Traversable with non-integer keys"); + "Keys must be of type int|string during array unpacking"); zval_ptr_dtor(&key); break; } + } else { + ZVAL_UNDEF(&key); } ZVAL_DEREF(val); Z_TRY_ADDREF_P(val); - if (!zend_hash_next_index_insert(Z_ARRVAL_P(EX_VAR(opline->result.var)), val)) { - zend_cannot_add_element(); - zval_ptr_dtor_nogc(val); + zend_ulong num_key; + if (Z_TYPE(key) == IS_STRING && !ZEND_HANDLE_NUMERIC(Z_STR(key), num_key)) { + zend_hash_update(result_ht, Z_STR(key), val); + zval_ptr_dtor_str(&key); + } else { + if (!zend_hash_next_index_insert(result_ht, val)) { + zend_cannot_add_element(); + zval_ptr_dtor_nogc(val); + break; + } } - iter->funcs->move_forward(iter); + funcs->move_forward(iter); + if (UNEXPECTED(EG(exception))) { + break; + } } zend_iterator_dtor(iter); @@ -6124,6 +6144,11 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } else { ZVAL_EMPTY_ARRAY(result); } + } else if (Z_OBJ_P(expr)->properties == NULL + && Z_OBJ_HT_P(expr)->get_properties_for == NULL + && Z_OBJ_HT_P(expr)->get_properties == zend_std_get_properties) { + /* Optimized version without rebulding properties HashTable */ + ZVAL_ARR(result, zend_std_build_object_properties_array(Z_OBJ_P(expr))); } else { HashTable *obj_ht = zend_get_properties_for(expr, ZEND_PROP_PURPOSE_ARRAY_CAST); if (obj_ht) { @@ -6217,6 +6242,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL, SPEC(OBSER zend_vm_stack_free_call_frame(call); } + zend_destroy_static_vars(new_op_array); destroy_op_array(new_op_array); efree_size(new_op_array, sizeof(zend_op_array)); if (UNEXPECTED(EG(exception) != NULL)) { @@ -6372,11 +6398,8 @@ ZEND_VM_C_LABEL(offset_again): } } ZEND_VM_C_LABEL(str_index_dim): - if (ht == &EG(symbol_table)) { - zend_delete_global_variable(key); - } else { - zend_hash_del(ht, key); - } + ZEND_ASSERT(ht != &EG(symbol_table)); + zend_hash_del(ht, key); } else if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { hval = Z_LVAL_P(offset); ZEND_VM_C_LABEL(num_index_dim): @@ -6397,6 +6420,7 @@ ZEND_VM_C_LABEL(num_index_dim): hval = 1; ZEND_VM_C_GOTO(num_index_dim); } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_use_resource_as_offset(offset); hval = Z_RES_HANDLE_P(offset); ZEND_VM_C_GOTO(num_index_dim); } else if (OP2_TYPE == IS_CV && Z_TYPE_P(offset) == IS_UNDEF) { @@ -6528,7 +6552,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, JMP_ADDR) FREE_OP1_IF_VAR(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { - zend_bool is_empty = zend_fe_reset_iterator(array_ptr, 0 OPLINE_CC EXECUTE_DATA_CC); + bool is_empty = zend_fe_reset_iterator(array_ptr, 0 OPLINE_CC EXECUTE_DATA_CC); FREE_OP1(); if (UNEXPECTED(EG(exception))) { @@ -6621,7 +6645,7 @@ ZEND_VM_COLD_CONST_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) FREE_OP1_VAR_PTR(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { - zend_bool is_empty = zend_fe_reset_iterator(array_ptr, 1 OPLINE_CC EXECUTE_DATA_CC); + bool is_empty = zend_fe_reset_iterator(array_ptr, 1 OPLINE_CC EXECUTE_DATA_CC); if (OP1_TYPE == IS_VAR) { FREE_OP1_VAR_PTR(); @@ -6649,7 +6673,7 @@ ZEND_VM_COLD_CONST_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) } } -ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY, JMP_ADDR) +ZEND_VM_HELPER(zend_fe_fetch_object_helper, ANY, ANY) { USE_OPLINE zval *array; @@ -6658,19 +6682,22 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY, JMP_ADDR) HashTable *fe_ht; HashPosition pos; Bucket *p; + zend_object_iterator *iter; array = EX_VAR(opline->op1.var); SAVE_OPLINE(); - if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) { - fe_ht = Z_ARRVAL_P(array); - pos = Z_FE_POS_P(array); + + ZEND_ASSERT(Z_TYPE_P(array) == IS_OBJECT); + if ((iter = zend_iterator_unwrap(array)) == NULL) { + /* plain object */ + + fe_ht = Z_OBJPROP_P(array); + pos = zend_hash_iterator_pos(Z_FE_ITER_P(array), fe_ht); p = fe_ht->arData + pos; while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { /* reached end of iteration */ -ZEND_VM_C_LABEL(fe_fetch_r_exit): - ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); - ZEND_VM_CONTINUE(); + ZEND_VM_C_GOTO(fe_fetch_r_exit); } pos++; value = &p->val; @@ -6679,111 +6706,74 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): if (UNEXPECTED(value_type == IS_INDIRECT)) { value = Z_INDIRECT_P(value); value_type = Z_TYPE_INFO_P(value); - if (EXPECTED(value_type != IS_UNDEF)) { + if (EXPECTED(value_type != IS_UNDEF) + && EXPECTED(zend_check_property_access(Z_OBJ_P(array), p->key, 0) == SUCCESS)) { break; } - } else { + } else if (EXPECTED(Z_OBJCE_P(array)->default_properties_count == 0) + || !p->key + || zend_check_property_access(Z_OBJ_P(array), p->key, 1) == SUCCESS) { break; } } p++; } - Z_FE_POS_P(array) = pos; + EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos; if (RETURN_VALUE_USED(opline)) { - if (!p->key) { + if (UNEXPECTED(!p->key)) { ZVAL_LONG(EX_VAR(opline->result.var), p->h); - } else { + } else if (ZSTR_VAL(p->key)[0]) { ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key); + } else { + const char *class_name, *prop_name; + size_t prop_name_len; + zend_unmangle_property_name_ex( + p->key, &class_name, &prop_name, &prop_name_len); + ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len); } } } else { - zend_object_iterator *iter; - - ZEND_ASSERT(Z_TYPE_P(array) == IS_OBJECT); - if ((iter = zend_iterator_unwrap(array)) == NULL) { - /* plain object */ - - fe_ht = Z_OBJPROP_P(array); - pos = zend_hash_iterator_pos(Z_FE_ITER_P(array), fe_ht); - p = fe_ht->arData + pos; - while (1) { - if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - /* reached end of iteration */ - ZEND_VM_C_GOTO(fe_fetch_r_exit); - } - pos++; - value = &p->val; - value_type = Z_TYPE_INFO_P(value); - if (EXPECTED(value_type != IS_UNDEF)) { - if (UNEXPECTED(value_type == IS_INDIRECT)) { - value = Z_INDIRECT_P(value); - value_type = Z_TYPE_INFO_P(value); - if (EXPECTED(value_type != IS_UNDEF) - && EXPECTED(zend_check_property_access(Z_OBJ_P(array), p->key, 0) == SUCCESS)) { - break; - } - } else if (EXPECTED(Z_OBJCE_P(array)->default_properties_count == 0) - || !p->key - || zend_check_property_access(Z_OBJ_P(array), p->key, 1) == SUCCESS) { - break; - } - } - p++; - } - EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos; - if (RETURN_VALUE_USED(opline)) { - if (UNEXPECTED(!p->key)) { - ZVAL_LONG(EX_VAR(opline->result.var), p->h); - } else if (ZSTR_VAL(p->key)[0]) { - ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key); - } else { - const char *class_name, *prop_name; - size_t prop_name_len; - zend_unmangle_property_name_ex( - p->key, &class_name, &prop_name, &prop_name_len); - ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len); - } + const zend_object_iterator_funcs *funcs = iter->funcs; + if (EXPECTED(++iter->index > 0)) { + /* This could cause an endless loop if index becomes zero again. + * In case that ever happens we need an additional flag. */ + funcs->move_forward(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); } - } else { - if (EXPECTED(++iter->index > 0)) { - /* This could cause an endless loop if index becomes zero again. - * In case that ever happens we need an additional flag. */ - iter->funcs->move_forward(iter); + if (UNEXPECTED(funcs->valid(iter) == FAILURE)) { + /* reached end of iteration */ if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); } - if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) { - /* reached end of iteration */ - if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); - } - ZEND_VM_C_GOTO(fe_fetch_r_exit); - } - } - value = iter->funcs->get_current_data(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); - } - if (!value) { - /* failure in get_current_data */ - ZEND_VM_C_GOTO(fe_fetch_r_exit); +ZEND_VM_C_LABEL(fe_fetch_r_exit): + ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); + ZEND_VM_CONTINUE(); } - if (RETURN_VALUE_USED(opline)) { - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, EX_VAR(opline->result.var)); - if (UNEXPECTED(EG(exception) != NULL)) { - UNDEF_RESULT(); - HANDLE_EXCEPTION(); - } - } else { - ZVAL_LONG(EX_VAR(opline->result.var), iter->index); + } + value = funcs->get_current_data(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + if (!value) { + /* failure in get_current_data */ + ZEND_VM_C_GOTO(fe_fetch_r_exit); + } + if (RETURN_VALUE_USED(opline)) { + if (funcs->get_current_key) { + funcs->get_current_key(iter, EX_VAR(opline->result.var)); + if (UNEXPECTED(EG(exception) != NULL)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); } + } else { + ZVAL_LONG(EX_VAR(opline->result.var), iter->index); } - value_type = Z_TYPE_INFO_P(value); } + value_type = Z_TYPE_INFO_P(value); } if (EXPECTED(OP2_TYPE == IS_CV)) { @@ -6801,6 +6791,64 @@ ZEND_VM_C_LABEL(fe_fetch_r_exit): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +ZEND_VM_HOT_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY, JMP_ADDR) +{ + USE_OPLINE + zval *array; + zval *value; + uint32_t value_type; + HashTable *fe_ht; + HashPosition pos; + Bucket *p; + + array = EX_VAR(opline->op1.var); + if (UNEXPECTED(Z_TYPE_P(array) != IS_ARRAY)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_fe_fetch_object_helper); + } + fe_ht = Z_ARRVAL_P(array); + pos = Z_FE_POS_P(array); + p = fe_ht->arData + pos; + while (1) { + if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { + /* reached end of iteration */ + ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); + ZEND_VM_CONTINUE(); + } + pos++; + value = &p->val; + value_type = Z_TYPE_INFO_P(value); + ZEND_ASSERT(value_type != IS_INDIRECT); + if (EXPECTED(value_type != IS_UNDEF)) { + break; + } + p++; + } + Z_FE_POS_P(array) = pos; + if (RETURN_VALUE_USED(opline)) { + if (!p->key) { + ZVAL_LONG(EX_VAR(opline->result.var), p->h); + } else { + ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key); + } + } + + if (EXPECTED(OP2_TYPE == IS_CV)) { + zval *variable_ptr = EX_VAR(opline->op2.var); + SAVE_OPLINE(); + zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zval *res = EX_VAR(opline->op2.var); + zend_refcounted *gc = Z_COUNTED_P(value); + + ZVAL_COPY_VALUE_EX(res, value, gc, value_type); + if (Z_TYPE_INFO_REFCOUNTED(value_type)) { + GC_ADDREF(gc); + } + ZEND_VM_NEXT_OPCODE(); + } +} + ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) { USE_OPLINE @@ -6827,16 +6875,9 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) pos++; value = &p->val; value_type = Z_TYPE_INFO_P(value); + ZEND_ASSERT(value_type != IS_INDIRECT); if (EXPECTED(value_type != IS_UNDEF)) { - if (UNEXPECTED(value_type == IS_INDIRECT)) { - value = Z_INDIRECT_P(value); - value_type = Z_TYPE_INFO_P(value); - if (EXPECTED(value_type != IS_UNDEF)) { - break; - } - } else { - break; - } + break; } p++; } @@ -6905,15 +6946,16 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) } } } else { + const zend_object_iterator_funcs *funcs = iter->funcs; if (++iter->index > 0) { /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ - iter->funcs->move_forward(iter); + funcs->move_forward(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); } - if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) { + if (UNEXPECTED(funcs->valid(iter) == FAILURE)) { /* reached end of iteration */ if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); @@ -6922,7 +6964,7 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) ZEND_VM_C_GOTO(fe_fetch_w_exit); } } - value = iter->funcs->get_current_data(iter); + value = funcs->get_current_data(iter); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -6932,8 +6974,8 @@ ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY, JMP_ADDR) ZEND_VM_C_GOTO(fe_fetch_w_exit); } if (RETURN_VALUE_USED(opline)) { - if (iter->funcs->get_current_key) { - iter->funcs->get_current_key(iter, EX_VAR(opline->result.var)); + if (funcs->get_current_key) { + funcs->get_current_key(iter, EX_VAR(opline->result.var)); if (UNEXPECTED(EG(exception) != NULL)) { UNDEF_RESULT(); HANDLE_EXCEPTION(); @@ -7095,7 +7137,7 @@ ZEND_VM_C_LABEL(isset_again): ZEND_VM_C_GOTO(num_index_prop); } } - value = zend_hash_find_ex_ind(ht, str, OP2_TYPE == IS_CONST); + value = zend_hash_find_ex(ht, str, OP2_TYPE == IS_CONST); } else if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { hval = Z_LVAL_P(offset); ZEND_VM_C_LABEL(num_index_prop): @@ -7203,7 +7245,7 @@ ZEND_VM_HANDLER(194, ZEND_ARRAY_KEY_EXISTS, CV|TMPVAR|CONST, CV|TMPVAR|CONST) zval *key, *subject; HashTable *ht; - zend_bool result; + bool result; SAVE_OPLINE(); @@ -7530,7 +7572,8 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST) if (UNEXPECTED(!zv)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name)); } else { - if (zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2))) == FAILURE) { + ce = zend_do_link_class(ce, Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(lcname)); + if (!ce) { /* Reload bucket pointer, the hash table may have been reallocated */ zv = zend_hash_find(EG(class_table), Z_STR_P(lcname)); zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(lcname + 1)); @@ -7571,7 +7614,8 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT) ce = Z_CE_P(zv); if (!(ce->ce_flags & ZEND_ACC_LINKED)) { SAVE_OPLINE(); - if (zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL) == FAILURE) { + ce = zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key); + if (!ce) { HANDLE_EXCEPTION(); } } @@ -7581,12 +7625,14 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) +ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, NUM) { + zend_function *func; USE_OPLINE SAVE_OPLINE(); - do_bind_function(RT_CONSTANT(opline, opline->op1)); + func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num]; + do_bind_function(func, RT_CONSTANT(opline, opline->op1)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -7609,7 +7655,7 @@ ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, C { USE_OPLINE zval *expr; - zend_bool result; + bool result; SAVE_OPLINE(); expr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -7621,7 +7667,7 @@ ZEND_VM_C_LABEL(try_instanceof): if (OP2_TYPE == IS_CONST) { ce = CACHED_PTR(opline->extended_value); if (UNEXPECTED(ce == NULL)) { - ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(RT_CONSTANT(opline, opline->op2) + 1), ZEND_FETCH_CLASS_NO_AUTOLOAD); + ce = zend_lookup_class_ex(Z_STR_P(RT_CONSTANT(opline, opline->op2)), Z_STR_P(RT_CONSTANT(opline, opline->op2) + 1), ZEND_FETCH_CLASS_NO_AUTOLOAD); if (EXPECTED(ce)) { CACHE_PTR(opline->extended_value, ce); } @@ -7851,23 +7897,14 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT) +ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, NUM) { USE_OPLINE zend_function *func; - zval *zfunc; zval *object; zend_class_entry *called_scope; - func = CACHED_PTR(opline->extended_value); - if (UNEXPECTED(func == NULL)) { - zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1); - ZEND_ASSERT(zfunc != NULL); - func = Z_FUNC_P(zfunc); - ZEND_ASSERT(func->type == ZEND_USER_FUNCTION); - CACHE_PTR(opline->extended_value, func); - } - + func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num]; if (Z_TYPE(EX(This)) == IS_OBJECT) { called_scope = Z_OBJCE(EX(This)); if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) || @@ -8288,10 +8325,12 @@ ZEND_VM_COLD_CONST_HANDLER(121, ZEND_STRLEN, CONST|TMPVAR|CV, ANY) value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_P(value) == IS_STRING)) { ZVAL_LONG(EX_VAR(opline->result.var), Z_STRLEN_P(value)); - FREE_OP1(); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_str(value); + } ZEND_VM_NEXT_OPCODE(); } else { - zend_bool strict; + bool strict; if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(value) == IS_REFERENCE) { value = Z_REFVAL_P(value); @@ -8312,8 +8351,18 @@ ZEND_VM_COLD_CONST_HANDLER(121, ZEND_STRLEN, CONST|TMPVAR|CV, ANY) zend_string *str; zval tmp; + if (UNEXPECTED(Z_TYPE_P(value) == IS_NULL)) { + zend_error(E_DEPRECATED, + "strlen(): Passing null to parameter #1 ($string) of type string is deprecated"); + if (UNEXPECTED(EG(exception))) { + HANDLE_EXCEPTION(); + } + ZVAL_LONG(EX_VAR(opline->result.var), 0); + break; + } + ZVAL_COPY(&tmp, value); - if (zend_parse_arg_str_weak(&tmp, &str)) { + if (zend_parse_arg_str_weak(&tmp, &str, 1)) { ZVAL_LONG(EX_VAR(opline->result.var), ZSTR_LEN(str)); zval_ptr_dtor(&tmp); break; @@ -8545,7 +8594,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER)) EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + bool should_throw = zend_internal_call_should_throw(fbc, call); #endif if (ret == NULL) { @@ -8645,16 +8694,10 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF) ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); if (!ht) { - ZEND_ASSERT(EX(func)->op_array.fn_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)); ht = zend_array_dup(EX(func)->op_array.static_variables); ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); - } else if (GC_REFCOUNT(ht) > 1) { - if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { - GC_DELREF(ht); - } - ht = zend_array_dup(ht); - ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht); } + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT))); @@ -8703,6 +8746,16 @@ ZEND_VM_HOT_HANDLER(184, ZEND_FETCH_THIS, UNUSED, UNUSED) } } +ZEND_VM_HANDLER(200, ZEND_FETCH_GLOBALS, UNUSED, UNUSED) +{ + USE_OPLINE + + /* For symbol tables we need to deal with exactly the same problems as for property tables. */ + ZVAL_ARR(EX_VAR(opline->result.var), + zend_proptable_to_symtable(&EG(symbol_table), /* always_duplicate */ 1)); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(186, ZEND_ISSET_ISEMPTY_THIS, UNUSED, UNUSED) { USE_OPLINE @@ -8879,33 +8932,69 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(189, ZEND_IN_ARRAY, CONST|TMP|VAR|CV, CONST, NUM HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); zval *result; - SAVE_OPLINE(); - op1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); + op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST); - } else if (opline->extended_value) { + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_str(op1); + } + ZEND_VM_SMART_BRANCH(result, 0); + } + + if (opline->extended_value) { if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { result = zend_hash_index_find(ht, Z_LVAL_P(op1)); - } else { - result = NULL; + ZEND_VM_SMART_BRANCH(result, 0); + } + SAVE_OPLINE(); + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(op1) == IS_REFERENCE) { + op1 = Z_REFVAL_P(op1); + if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + result = zend_hash_find_ex(ht, Z_STR_P(op1), 0); + FREE_OP1(); + ZEND_VM_SMART_BRANCH(result, 0); + } else if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { + result = zend_hash_index_find(ht, Z_LVAL_P(op1)); + FREE_OP1(); + ZEND_VM_SMART_BRANCH(result, 0); + } + } else if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + ZVAL_UNDEFINED_OP1(); } } else if (Z_TYPE_P(op1) <= IS_FALSE) { + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(op1) == IS_UNDEF)) { + SAVE_OPLINE(); + ZVAL_UNDEFINED_OP1(); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } result = zend_hash_find_ex(ht, ZSTR_EMPTY_ALLOC(), 1); + ZEND_VM_SMART_BRANCH(result, 0); } else { zend_string *key; - zval key_tmp, *val; + zval key_tmp; - result = NULL; - ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_TYPE_P(op1) == IS_REFERENCE) { + op1 = Z_REFVAL_P(op1); + if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) { + result = zend_hash_find_ex(ht, Z_STR_P(op1), 0); + FREE_OP1(); + ZEND_VM_SMART_BRANCH(result, 0); + } + } + + SAVE_OPLINE(); + ZEND_HASH_FOREACH_STR_KEY(ht, key) { ZVAL_STR(&key_tmp, key); if (zend_compare(op1, &key_tmp) == 0) { - result = val; - break; + FREE_OP1(); + ZEND_VM_SMART_BRANCH(1, 1); } } ZEND_HASH_FOREACH_END(); } FREE_OP1(); - ZEND_VM_SMART_BRANCH(result, 1); + ZEND_VM_SMART_BRANCH(0, 1); } ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED) @@ -8919,7 +9008,7 @@ ZEND_VM_COLD_CONST_HANDLER(190, ZEND_COUNT, CONST|TMPVAR|CV, UNUSED) while (1) { if (Z_TYPE_P(op1) == IS_ARRAY) { - count = zend_array_count(Z_ARRVAL_P(op1)); + count = zend_hash_num_elements(Z_ARRVAL_P(op1)); break; } else if (Z_TYPE_P(op1) == IS_OBJECT) { zend_object *zobj = Z_OBJ_P(op1); @@ -9302,7 +9391,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op1_type == IS_CV && (op->op2_t /* (Infinite recursion when comparing arrays is an uncatchable fatal error) */ USE_OPLINE zval *op1, *op2; - zend_bool result; + bool result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -9315,7 +9404,7 @@ ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_IDENTICAL, op->op1_type == IS_CV && (op->o { USE_OPLINE zval *op1, *op2; - zend_bool result; + bool result; op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); @@ -9639,16 +9728,9 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FE_FETCH_R, op->op2_type == IS_CV && (op1_inf pos++; value = &p->val; value_type = Z_TYPE_INFO_P(value); + ZEND_ASSERT(value_type != IS_INDIRECT); if (EXPECTED(value_type != IS_UNDEF)) { - if (UNEXPECTED(value_type == IS_INDIRECT)) { - value = Z_INDIRECT_P(value); - value_type = Z_TYPE_INFO_P(value); - if (EXPECTED(value_type != IS_UNDEF)) { - break; - } - } else { - break; - } + break; } p++; } |