Commit: 6517ed021520a608a18da4653cb9c6b414121f6f
Author: Nikita Popov <ni...@php.net> Fri, 24 Aug 2012 13:29:40 +0200
Parents: f45a0f31c8354947c0e2b9ea44a63fc0a2c23a01
071580ea1f450513dba2dbf585a9498614f855e7
Branches: master
Link:
http://git.php.net/?p=php-src.git;a=commitdiff;h=6517ed021520a608a18da4653cb9c6b414121f6f
Log:
Merge remote-tracking branch 'php-src/master' into addGeneratorsSupport
Conflicts:
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Changed paths:
MM Zend/zend_compile.c
MM Zend/zend_compile.h
MM Zend/zend_opcode.c
MM Zend/zend_vm_def.h
MM Zend/zend_vm_execute.h
diff --cc Zend/zend_vm_def.h
index f8955c5,ce1674e..975a2a7
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@@ -1840,291 -1840,296 +1840,294 @@@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VA
ZEND_VM_NEXT_OPCODE();
}
- ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY)
+ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
{
- USE_OPLINE
-
- #if DEBUG_ZEND>=2
- printf("Jumping to %d\n", opline->op1.opline_num);
- #endif
- ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
- ZEND_VM_CONTINUE(); /* CHECK_ME */
- }
+ zend_bool nested;
+ zend_op_array *op_array = EX(op_array);
- ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY)
- {
- USE_OPLINE
- zend_free_op free_op1;
- zval *val;
- int ret;
++ /* Generators go throw a different cleanup process */
++ if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
++ /* The generator object is stored in return_value_ptr_ptr */
++ zend_generator *generator = (zend_generator *)
EG(return_value_ptr_ptr);
+
- SAVE_OPLINE();
- val = GET_OP1_ZVAL_PTR(BP_VAR_R);
++ /* Close the generator to free up resources */
++ zend_generator_close(generator, 1 TSRMLS_CC);
+
- if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
- ret = Z_LVAL_P(val);
- } else {
- ret = i_zend_is_true(val);
- FREE_OP1();
- if (UNEXPECTED(EG(exception) != NULL)) {
- HANDLE_EXCEPTION();
- }
- }
- if (!ret) {
- #if DEBUG_ZEND>=2
- printf("Conditional jmp to %d\n", opline->op2.opline_num);
- #endif
- ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
- ZEND_VM_CONTINUE();
++ /* Pass execution back to handling code */
++ ZEND_VM_RETURN();
+ }
+
- ZEND_VM_NEXT_OPCODE();
- }
+ EG(current_execute_data) = EX(prev_execute_data);
+ EG(opline_ptr) = NULL;
+ if (!EG(active_symbol_table)) {
- zval ***cv = EX_CVs();
- zval ***end = cv + op_array->last_var;
- while (cv != end) {
- if (*cv) {
- zval_ptr_dtor(*cv);
- }
- cv++;
- }
++ zend_free_compiled_variables(EX_CVs(), op_array->last_var);
+ }
- ZEND_VM_HANDLER(44, ZEND_JMPNZ, CONST|TMP|VAR|CV, ANY)
- {
- USE_OPLINE
- zend_free_op free_op1;
- zval *val;
- int ret;
+ if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->prototype) {
+ zval_ptr_dtor((zval**)&op_array->prototype);
+ }
- SAVE_OPLINE();
- val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ nested = EX(nested);
- if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
- ret = Z_LVAL_P(val);
- zend_vm_stack_free(execute_data TSRMLS_CC);
++ /* For generators the execute_data is stored on the heap, for everything
++ * else it is stored on the VM stack. */
++ if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
++ efree(execute_data);
+ } else {
- ret = i_zend_is_true(val);
- FREE_OP1();
- if (UNEXPECTED(EG(exception) != NULL)) {
- HANDLE_EXCEPTION();
- }
++ zend_vm_stack_free(execute_data TSRMLS_CC);
+ }
- if (ret) {
- #if DEBUG_ZEND>=2
- printf("Conditional jmp to %d\n", opline->op2.opline_num);
- #endif
- ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
- ZEND_VM_CONTINUE();
+
+ if (nested) {
+ execute_data = EG(current_execute_data);
}
+ if (nested) {
+ USE_OPLINE
- ZEND_VM_NEXT_OPCODE();
- }
+ LOAD_REGS();
+ LOAD_OPLINE();
+ if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
- ZEND_VM_HANDLER(45, ZEND_JMPZNZ, CONST|TMP|VAR|CV, ANY)
- {
- USE_OPLINE
- zend_free_op free_op1;
- zval *val;
- int retval;
+ EX(function_state).function = (zend_function *)
EX(op_array);
+ EX(function_state).arguments = NULL;
+ EX(object) = EX(current_object);
- SAVE_OPLINE();
- val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ EG(opline_ptr) = &EX(opline);
+ EG(active_op_array) = EX(op_array);
+ EG(return_value_ptr_ptr) = EX(original_return_value);
+ destroy_op_array(op_array TSRMLS_CC);
+ efree(op_array);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zend_throw_exception_internal(NULL TSRMLS_CC);
+ HANDLE_EXCEPTION_LEAVE();
+ } else if (RETURN_VALUE_USED(opline)) {
+ if (!EX_T(opline->result.var).var.ptr) { /*
there was no return statement */
+ zval *retval;
- if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
- retval = Z_LVAL_P(val);
- } else {
- retval = i_zend_is_true(val);
- FREE_OP1();
- if (UNEXPECTED(EG(exception) != NULL)) {
- HANDLE_EXCEPTION();
- }
- }
- if (EXPECTED(retval != 0)) {
- #if DEBUG_ZEND>=2
- printf("Conditional jmp on true to %d\n",
opline->extended_value);
- #endif
-
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
- ZEND_VM_CONTINUE(); /* CHECK_ME */
- } else {
- #if DEBUG_ZEND>=2
- printf("Conditional jmp on false to %d\n",
opline->op2.opline_num);
- #endif
-
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
- ZEND_VM_CONTINUE(); /* CHECK_ME */
- }
- }
+ ALLOC_ZVAL(retval);
+ ZVAL_BOOL(retval, 1);
+ INIT_PZVAL(retval);
+ EX_T(opline->result.var).var.ptr =
retval;
+ }
+ }
- ZEND_VM_HANDLER(46, ZEND_JMPZ_EX, CONST|TMP|VAR|CV, ANY)
- {
- USE_OPLINE
- zend_free_op free_op1;
- zval *val;
- int retval;
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_LEAVE();
+ } else {
-
+ EG(opline_ptr) = &EX(opline);
+ EG(active_op_array) = EX(op_array);
+ EG(return_value_ptr_ptr) = EX(original_return_value);
+ if (EG(active_symbol_table)) {
- if
(EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
-
zend_hash_destroy(EG(active_symbol_table));
- FREE_HASHTABLE(EG(active_symbol_table));
- } else {
- /* clean before putting into the cache,
since clean
- could call dtors, which could use
cached hash */
-
zend_hash_clean(EG(active_symbol_table));
- *(++EG(symtable_cache_ptr)) =
EG(active_symbol_table);
- }
++
zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
+ }
+ EG(active_symbol_table) = EX(symbol_table);
- SAVE_OPLINE();
- val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ EX(function_state).function = (zend_function *)
EX(op_array);
+ EX(function_state).arguments = NULL;
- if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
- retval = Z_LVAL_P(val);
- } else {
- retval = i_zend_is_true(val);
- FREE_OP1();
- if (UNEXPECTED(EG(exception) != NULL)) {
- HANDLE_EXCEPTION();
- }
- }
- Z_LVAL(EX_T(opline->result.var).tmp_var) = retval;
- Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL;
- if (!retval) {
- #if DEBUG_ZEND>=2
- printf("Conditional jmp to %d\n", opline->op2.opline_num);
- #endif
- ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
- ZEND_VM_CONTINUE();
- }
- ZEND_VM_NEXT_OPCODE();
- }
+ if (EG(This)) {
+ if (UNEXPECTED(EG(exception) != NULL) &&
IS_CTOR_CALL(EX(called_scope))) {
+ if (IS_CTOR_USED(EX(called_scope))) {
+ Z_DELREF_P(EG(This));
+ }
+ if (Z_REFCOUNT_P(EG(This)) == 1) {
+
zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
+ }
+ }
+ zval_ptr_dtor(&EG(This));
+ }
+ EG(This) = EX(current_this);
+ EG(scope) = EX(current_scope);
+ EG(called_scope) = EX(current_called_scope);
- ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMP|VAR|CV, ANY)
- {
- USE_OPLINE
- zend_free_op free_op1;
- zval *val;
- int retval;
+ EX(object) = EX(current_object);
+ EX(called_scope) = DECODE_CTOR(EX(called_scope));
- SAVE_OPLINE();
- val = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ zend_vm_stack_clear_multiple(TSRMLS_C);
- if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) {
- retval = Z_LVAL_P(val);
- } else {
- retval = i_zend_is_true(val);
- FREE_OP1();
- if (UNEXPECTED(EG(exception) != NULL)) {
- HANDLE_EXCEPTION();
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zend_throw_exception_internal(NULL TSRMLS_CC);
+ if (RETURN_VALUE_USED(opline) &&
EX_T(opline->result.var).var.ptr) {
+
zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+ }
+ HANDLE_EXCEPTION_LEAVE();
+ }
+
+ ZEND_VM_INC_OPCODE();
+ ZEND_VM_LEAVE();
}
}
- Z_LVAL(EX_T(opline->result.var).tmp_var) = retval;
- Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL;
- if (retval) {
- #if DEBUG_ZEND>=2
- printf("Conditional jmp to %d\n", opline->op2.opline_num);
- #endif
- ZEND_VM_SET_OPCODE(opline->op2.jmp_addr);
- ZEND_VM_CONTINUE();
- }
- ZEND_VM_NEXT_OPCODE();
+ ZEND_VM_RETURN();
}
- ZEND_VM_HANDLER(70, ZEND_FREE, TMP|VAR, ANY)
+ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
{
USE_OPLINE
+ zend_bool should_change_scope = 0;
+ zend_function *fbc = EX(function_state).function;
SAVE_OPLINE();
- if (OP1_TYPE == IS_TMP_VAR) {
- zendi_zval_dtor(EX_T(opline->op1.var).tmp_var);
- } else {
- zval_ptr_dtor(&EX_T(opline->op1.var).var.ptr);
+ if (UNEXPECTED((fbc->common.fn_flags &
(ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) {
+ if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) !=
0)) {
+ zend_error_noreturn(E_ERROR, "Cannot call abstract
method %s::%s()", fbc->common.scope->name, fbc->common.function_name);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE(); /* Never reached */
+ }
+ if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) !=
0)) {
+ zend_error(E_DEPRECATED, "Function %s%s%s() is
deprecated",
+ fbc->common.scope ? fbc->common.scope->name :
"",
+ fbc->common.scope ? "::" : "",
+ fbc->common.function_name);
+ }
}
- CHECK_EXCEPTION();
- ZEND_VM_NEXT_OPCODE();
- }
-
- ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY)
- {
- USE_OPLINE
- zval *tmp = &EX_T(opline->result.var).tmp_var;
-
- SAVE_OPLINE();
- tmp->value.str.val = emalloc(1);
- tmp->value.str.val[0] = 0;
- tmp->value.str.len = 0;
- Z_SET_REFCOUNT_P(tmp, 1);
- tmp->type = IS_STRING;
- Z_UNSET_ISREF_P(tmp);
- /*CHECK_EXCEPTION();*/
- ZEND_VM_NEXT_OPCODE();
- }
-
- ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
- {
- USE_OPLINE
- zval *str = &EX_T(opline->result.var).tmp_var;
-
- SAVE_OPLINE();
+ if (fbc->common.scope &&
+ !(fbc->common.fn_flags & ZEND_ACC_STATIC) &&
+ !EX(object)) {
- if (OP1_TYPE == IS_UNUSED) {
- /* Initialize for erealloc in add_char_to_string */
- Z_STRVAL_P(str) = NULL;
- Z_STRLEN_P(str) = 0;
- Z_TYPE_P(str) = IS_STRING;
+ if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+ /* FIXME: output identifiers properly */
+ zend_error(E_STRICT, "Non-static method %s::%s() should
not be called statically", fbc->common.scope->name, fbc->common.function_name);
+ } else {
+ /* FIXME: output identifiers properly */
+ /* An internal function assumes $this is present and
won't check that. So PHP would crash by allowing the call. */
+ zend_error_noreturn(E_ERROR, "Non-static method
%s::%s() cannot be called statically", fbc->common.scope->name,
fbc->common.function_name);
+ }
+ }
- INIT_PZVAL(str);
+ if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) {
+ should_change_scope = 1;
+ EX(current_this) = EG(This);
+ EX(current_scope) = EG(scope);
+ EX(current_called_scope) = EG(called_scope);
+ EG(This) = EX(object);
+ EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ?
fbc->common.scope : NULL;
+ EG(called_scope) = EX(called_scope);
}
- add_char_to_string(str, str, opline->op2.zv);
+ zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope),
&EX(current_object), &EX(fbc));
+ EX(function_state).arguments =
zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
+ LOAD_OPLINE();
- /* FREE_OP is missing intentionally here - we're always working on the
same temporary variable */
- /*CHECK_EXCEPTION();*/
- ZEND_VM_NEXT_OPCODE();
- }
+ if (fbc->type == ZEND_INTERNAL_FUNCTION) {
+ temp_variable *ret = &EX_T(opline->result.var);
- ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TMP|UNUSED, CONST)
- {
- USE_OPLINE
- zval *str = &EX_T(opline->result.var).tmp_var;
+ MAKE_STD_ZVAL(ret->var.ptr);
+ ZVAL_NULL(ret->var.ptr);
+ ret->var.ptr_ptr = &ret->var.ptr;
+ ret->var.fcall_returned_reference = (fbc->common.fn_flags &
ZEND_ACC_RETURN_REFERENCE) != 0;
+
+ if (fbc->common.arg_info) {
+ zend_uint i=0;
+ zval **p = (zval**)EX(function_state).arguments;
+ ulong arg_count = opline->extended_value;
- SAVE_OPLINE();
+ while (arg_count>0) {
+ zend_verify_arg_type(fbc, ++i, *(p-arg_count),
0 TSRMLS_CC);
+ arg_count--;
+ }
+ }
- if (OP1_TYPE == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- Z_STRVAL_P(str) = NULL;
- Z_STRLEN_P(str) = 0;
- Z_TYPE_P(str) = IS_STRING;
+ if (!zend_execute_internal) {
+ /* saves one function call if zend_execute_internal is
not used */
+ fbc->internal_function.handler(opline->extended_value,
ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ?
&ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
+ } else {
+ zend_execute_internal(EXECUTE_DATA,
RETURN_VALUE_USED(opline) TSRMLS_CC);
+ }
- INIT_PZVAL(str);
- }
+ if (!RETURN_VALUE_USED(opline)) {
+ zval_ptr_dtor(&ret->var.ptr);
+ }
+ } else if (fbc->type == ZEND_USER_FUNCTION) {
+ EX(original_return_value) = EG(return_value_ptr_ptr);
+ EG(active_symbol_table) = NULL;
+ EG(active_op_array) = &fbc->op_array;
+ EG(return_value_ptr_ptr) = NULL;
+ if (RETURN_VALUE_USED(opline)) {
+ temp_variable *ret = &EX_T(opline->result.var);
- add_string_to_string(str, str, opline->op2.zv);
+ ret->var.ptr = NULL;
+ EG(return_value_ptr_ptr) = &ret->var.ptr;
+ ret->var.ptr_ptr = &ret->var.ptr;
+ ret->var.fcall_returned_reference =
(fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+ }
- /* FREE_OP is missing intentionally here - we're always working on the
same temporary variable */
- /*CHECK_EXCEPTION();*/
- ZEND_VM_NEXT_OPCODE();
- }
- if (EXPECTED(zend_execute == execute)) {
++ if (EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
++ if (RETURN_VALUE_USED(opline)) {
++ EX_T(opline->result.var).var.ptr =
zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
++ }
++ } else if (EXPECTED(zend_execute == execute)) {
+ if (EXPECTED(EG(exception) == NULL)) {
+ ZEND_VM_ENTER();
+ }
+ } else {
+ zend_execute(EG(active_op_array) TSRMLS_CC);
+ }
- ZEND_VM_HANDLER(56, ZEND_ADD_VAR, TMP|UNUSED, TMP|VAR|CV)
- {
- USE_OPLINE
- zend_free_op free_op2;
- zval *str = &EX_T(opline->result.var).tmp_var;
- zval *var;
- zval var_copy;
- int use_copy = 0;
+ EG(opline_ptr) = &EX(opline);
+ EG(active_op_array) = EX(op_array);
+ EG(return_value_ptr_ptr) = EX(original_return_value);
+ if (EG(active_symbol_table)) {
- if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
- zend_hash_destroy(EG(active_symbol_table));
- FREE_HASHTABLE(EG(active_symbol_table));
- } else {
- /* clean before putting into the cache, since
clean
- could call dtors, which could use cached
hash */
- zend_hash_clean(EG(active_symbol_table));
- *(++EG(symtable_cache_ptr)) =
EG(active_symbol_table);
- }
++
zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
+ }
+ EG(active_symbol_table) = EX(symbol_table);
+ } else { /* ZEND_OVERLOADED_FUNCTION */
+ MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr);
+ ZVAL_NULL(EX_T(opline->result.var).var.ptr);
- SAVE_OPLINE();
- var = GET_OP2_ZVAL_PTR(BP_VAR_R);
- /* Not sure what should be done here if it's a static
method */
++ /* Not sure what should be done here if it's a static method */
+ if (EXPECTED(EX(object) != NULL)) {
+
Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name,
opline->extended_value, EX_T(opline->result.var).var.ptr,
&EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline)
TSRMLS_CC);
+ } else {
+ zend_error_noreturn(E_ERROR, "Cannot call overloaded
function for non-object");
+ }
- if (OP1_TYPE == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- Z_STRVAL_P(str) = NULL;
- Z_STRLEN_P(str) = 0;
- Z_TYPE_P(str) = IS_STRING;
+ if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
+ efree((char*)fbc->common.function_name);
+ }
+ efree(fbc);
- INIT_PZVAL(str);
+ if (!RETURN_VALUE_USED(opline)) {
+ zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+ } else {
+ Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr);
+ Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1);
+ EX_T(opline->result.var).var.fcall_returned_reference =
0;
+ EX_T(opline->result.var).var.ptr_ptr =
&EX_T(opline->result.var).var.ptr;
+ }
}
- if (Z_TYPE_P(var) != IS_STRING) {
- zend_make_printable_zval(var, &var_copy, &use_copy);
+ EX(function_state).function = (zend_function *) EX(op_array);
+ EX(function_state).arguments = NULL;
- if (use_copy) {
- var = &var_copy;
+ if (should_change_scope) {
+ if (EG(This)) {
+ if (UNEXPECTED(EG(exception) != NULL) &&
IS_CTOR_CALL(EX(called_scope))) {
+ if (IS_CTOR_USED(EX(called_scope))) {
+ Z_DELREF_P(EG(This));
+ }
+ if (Z_REFCOUNT_P(EG(This)) == 1) {
+ zend_object_store_ctor_failed(EG(This)
TSRMLS_CC);
+ }
+ }
+ zval_ptr_dtor(&EG(This));
}
+ EG(This) = EX(current_this);
+ EG(scope) = EX(current_scope);
+ EG(called_scope) = EX(current_called_scope);
}
- add_string_to_string(str, str, var);
- if (use_copy) {
- zval_dtor(var);
+ EX(object) = EX(current_object);
+ EX(called_scope) = DECODE_CTOR(EX(called_scope));
+
+ zend_vm_stack_clear_multiple(TSRMLS_C);
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zend_throw_exception_internal(NULL TSRMLS_CC);
+ if (RETURN_VALUE_USED(opline) &&
EX_T(opline->result.var).var.ptr) {
+ zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
+ }
+ HANDLE_EXCEPTION();
}
- /* original comment, possibly problematic:
- * FREE_OP is missing intentionally here - we're always working on the
same temporary variable
- * (Zeev): I don't think it's problematic, we only use variables
- * which aren't affected by FREE_OP(Ts, )'s anyway, unless they're
- * string offsets or overloaded objects
- */
- FREE_OP2();
- CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
@@@ -5346,206 -5350,26 +5376,184 @@@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR
ZEND_VM_HANDLER(159, ZEND_LEAVE, ANY, ANY)
{
- USE_OPLINE
- zend_uint i, op_num = opline - EG(active_op_array)->opcodes;
-
- SAVE_OPLINE();
zend_exception_restore(TSRMLS_C);
- if (EX(leaving)) {
- zend_uint catch_op_num = 0, finally_op_num = 0;
- for (i = 0; i < EX(leaving); i++) {
- if (EG(active_op_array)->try_catch_array[i].try_op >
op_num) {
- break;
- }
- if (op_num <
EG(active_op_array)->try_catch_array[i].finally_op) {
- finally_op_num =
EG(active_op_array)->try_catch_array[i].finally_op;
- }
- if (EG(exception)) {
- if (op_num <
EG(active_op_array)->try_catch_array[i].catch_op) {
- catch_op_num =
EG(active_op_array)->try_catch_array[i].catch_op;
- }
- }
- }
-
- if (catch_op_num && finally_op_num) {
- if (catch_op_num > finally_op_num) {
-
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
- ZEND_VM_CONTINUE();
- } else {
- EX(leaving) = 0;
-
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
- ZEND_VM_CONTINUE();
- }
- } else if (catch_op_num) {
-
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
- ZEND_VM_CONTINUE();
- } else if (finally_op_num) {
-
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
- ZEND_VM_CONTINUE();
- } else {
- ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
- }
- } else {
+ if (!EX(leaving)) {
ZEND_VM_NEXT_OPCODE();
+ } else {
+ zend_uint leaving = EX(leaving);
+ switch (leaving) {
+ case ZEND_RETURN:
+ case ZEND_RETURN_BY_REF:
+ case ZEND_THROW:
+ leaving = ZEND_LEAVE;
+ case ZEND_JMP:
+ case ZEND_BRK:
+ case ZEND_CONT:
+ case ZEND_GOTO:
+
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, leaving);
+ break;
+ }
}
+
+ ZEND_VM_CONTINUE();
}
+ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED,
CONST|TMP|VAR|CV|UNUSED)
+{
+ USE_OPLINE
+
+ /* The generator object is stored in return_value_ptr_ptr */
+ zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
+
+ /* Destroy the previously yielded value */
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
+ /* Destroy the previously yielded key */
+ if (generator->key) {
+ zval_ptr_dtor(&generator->key);
+ }
+
+ /* Set the new yielded value */
+ if (OP1_TYPE != IS_UNUSED) {
+ zend_free_op free_op1;
+
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable
by reference,
+ * but we still allow them with a notice. */
+ if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) {
+ zval *value, *copy;
+
+ zend_error(E_NOTICE, "Only variable references
should be yielded by reference");
+
+ value = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying
*/
+ if (!IS_OP1_TMP_FREE()) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr =
GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
+
+ if (OP1_TYPE == IS_VAR && UNEXPECTED(value_ptr
== NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot
yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the
function did
+ * not return by reference we throw a notice. */
+ if (OP1_TYPE == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value ==
ZEND_RETURNS_FUNCTION
+ &&
EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr ==
&EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable
references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ FREE_OP1_IF_VAR();
+ }
+ } else {
+ zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+ /* Consts, temporary variables and references need
copying */
+ if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value)
> 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying
*/
+ if (!IS_OP1_TMP_FREE()) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ FREE_OP1_IF_VAR();
+ }
+ } else {
+ /* If no value was specified yield null */
+ Z_ADDREF(EG(uninitialized_zval));
+ generator->value = &EG(uninitialized_zval);
+ }
+
+ /* Set the new yielded key */
+ if (OP2_TYPE != IS_UNUSED) {
+ zend_free_op free_op2;
+ zval *key = GET_OP2_ZVAL_PTR(BP_VAR_R);
+
+ /* Consts, temporary variables and references need copying */
+ if (OP2_TYPE == IS_CONST || OP2_TYPE == IS_TMP_VAR
+ || (PZVAL_IS_REF(key) && Z_REFCOUNT_P(key) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, key);
+
+ /* Temporary variables don't need ctor copying */
+ if (!IS_OP1_TMP_FREE()) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->key = copy;
+ } else {
+ Z_ADDREF_P(key);
+ generator->key = key;
+ }
+
+ if (Z_TYPE_P(generator->key) == IS_LONG
+ && Z_LVAL_P(generator->key) >
generator->largest_used_integer_key
+ ) {
+ generator->largest_used_integer_key =
Z_LVAL_P(generator->key);
+ }
+
+ FREE_OP2_IF_VAR();
+ } else {
+ /* If no key was specified we use auto-increment keys */
+ generator->largest_used_integer_key++;
+
+ ALLOC_INIT_ZVAL(generator->key);
+ ZVAL_LONG(generator->key, generator->largest_used_integer_key);
+ }
+
+ /* If a value is sent it should go into the result var */
+ generator->send_target = &EX_T(opline->result.var);
+
+ /* Initialize the sent value to NULL */
+ Z_ADDREF(EG(uninitialized_zval));
+ AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+
+ /* We increment to the next op, so we are at the correct position when
the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
+ /* The GOTO VM uses a local opline variable. We need to set the opline
+ * variable in execute_data so we don't resume at an old position. */
+ SAVE_OPLINE();
+
+ ZEND_VM_RETURN();
+}
+
+ZEND_VM_HANDLER(161, ZEND_DELEGATE_YIELD, CONST|TMP|VAR|CV, ANY)
+{
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper)
diff --cc Zend/zend_vm_execute.h
index 8d2b7bf,bd19124..402442f
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@@ -457,40 -427,6 +457,13 @@@ ZEND_API void execute_ex(zend_execute_d
zend_error_noreturn(E_ERROR, "Arrived at end of main loop which
shouldn't happen");
}
+ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
+{
+ zend_execute_data *execute_data =
zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
+
+ execute_ex(execute_data TSRMLS_CC);
+}
+
- static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
- {
- USE_OPLINE
-
- #if DEBUG_ZEND>=2
- printf("Jumping to %d\n", opline->op1.opline_num);
- #endif
- ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
- ZEND_VM_CONTINUE(); /* CHECK_ME */
- }
-
- static int ZEND_FASTCALL
ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
- {
- USE_OPLINE
- zval *tmp = &EX_T(opline->result.var).tmp_var;
-
- SAVE_OPLINE();
- tmp->value.str.val = emalloc(1);
- tmp->value.str.val[0] = 0;
- tmp->value.str.len = 0;
- Z_SET_REFCOUNT_P(tmp, 1);
- tmp->type = IS_STRING;
- Z_UNSET_ISREF_P(tmp);
- /*CHECK_EXCEPTION();*/
- ZEND_VM_NEXT_OPCODE();
- }
-
static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
{
zend_bool nested;
@@@ -564,7 -489,7 +537,6 @@@
ZEND_VM_INC_OPCODE();
ZEND_VM_LEAVE();
} else {
--
EG(opline_ptr) = &EX(opline);
EG(active_op_array) = EX(op_array);
EG(return_value_ptr_ptr) = EX(original_return_value);
@@@ -725,7 -662,7 +697,7 @@@ static int ZEND_FASTCALL zend_do_fcall_
MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr);
ZVAL_NULL(EX_T(opline->result.var).var.ptr);
-- /* Not sure what should be done here if it's a static
method */
++ /* Not sure what should be done here if it's a static method */
if (EXPECTED(EX(object) != NULL)) {
Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name,
opline->extended_value, EX_T(opline->result.var).var.ptr,
&EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline)
TSRMLS_CC);
} else {
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php