The code violated the strict aliasing restriction, because it
dereferenced the same pointer as zval** once and as void**
afterwards. Now both occurances dereference void** and cast to
zval* in the former case.
Generators are now automatically detected by the presence of a `yield`
expression in their body.
This removes the ZEND_SUSPEND_AND_RETURN_GENERATOR opcode. Instead
additional checks for ZEND_ACC_GENERATOR are added to the fcall_common
helper and zend_call_function.
This also adds a new function zend_generator_create_zval, which handles
the actual creation of the generator zval from an op array.
I feel like I should deglobalize the zend_create_execute_data_from_op_array
code a bit. It currently changes EG(current_execute_data) and
EG(opline_ptr) which is somewhat confusing (given the name).
To make the generator function show up in backtraces one has to insert an
additional execute_data into the chain, as prev_execute_data->function_state
is used to determine the called function.
Adding the additional stack frame is also required for func_get_args(), as
the arguments are fetched from there too. The arguments have to be copied
in order to keep them around. Due to the way they are saved doing so is
quite ugly, so I added another function zend_copy_arguments to zend_execute.c
which handles this.
To keep things clean two new functions are introduced:
zend_clean_and_cache_symbol_table(HashTable *symbol_table)
zend_free_compiled_variables(zval ***CVs, int num)
This adds another function execute_ex(), which accepts a zend_execute_data
struct to run (contrary to execute(), which accepts a zend_op_array from
which it initialized the execute_data).
This needs a bit more cleanup.
. ZEND_RECV now always has IS_CV as its result
. ZEND_CATCH now has to be used only with constant class names
. ZEND_FETCH_DIM_? may fetch array and dimension operans in a different order