Browse Source

Eliminated checks for (func->op_array.fn_flags & ZEND_ACC_GENERATOR) in fast path of DO_FCALL* handlers.

This slightly improves calls to regular function and method calls in cost of a bit slower generator initialization.
Separate call frame for generators, allocated on heap, now created by ZEND_GENERATOR_CREATE instruction.
pull/224/merge
Dmitry Stogov 10 years ago
parent
commit
ccf18da450
  1. 24
      Zend/zend_compile.c
  2. 8
      Zend/zend_compile.h
  3. 44
      Zend/zend_execute.c
  4. 1
      Zend/zend_execute.h
  5. 8
      Zend/zend_execute_API.c
  6. 32
      Zend/zend_generators.c
  7. 1
      Zend/zend_generators.h
  8. 1
      Zend/zend_globals.h
  9. 38
      Zend/zend_language_parser.y
  10. 5489
      Zend/zend_language_scanner.c
  11. 1
      Zend/zend_language_scanner.l
  12. 2
      Zend/zend_language_scanner_defs.h
  13. 129
      Zend/zend_vm_def.h
  14. 517
      Zend/zend_vm_execute.h
  15. 2
      Zend/zend_vm_opcodes.c
  16. 1
      Zend/zend_vm_opcodes.h
  17. 2
      ext/opcache/Optimizer/zend_cfg.c

24
Zend/zend_compile.c

@ -3489,24 +3489,6 @@ int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcnam
}
/* }}} */
static void zend_compile_assert_side_effects(zend_ast *ast) /* {{{ */
{
int i;
int children = zend_ast_is_list(ast) ? zend_ast_get_list(ast)->children : zend_ast_get_num_children(ast);
for (i = 0; i < children; i++) {
zend_ast *child = (zend_ast_is_list(ast) ? zend_ast_get_list(ast)->child : ast->child)[i];
if (child) {
if (child->kind == ZEND_AST_YIELD) {
zend_mark_function_as_generator();
} else if (ast->kind >= ZEND_AST_IS_LIST_SHIFT) {
zend_compile_assert_side_effects(child);
}
}
}
}
/* }}} */
static int zend_compile_assert(znode *result, zend_ast_list *args, zend_string *name, zend_function *fbc) /* {{{ */
{
if (EG(assertions) >= 0) {
@ -3549,8 +3531,6 @@ static int zend_compile_assert(znode *result, zend_ast_list *args, zend_string *
}
result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
zend_compile_assert_side_effects((zend_ast *) args);
}
return SUCCESS;
@ -5411,6 +5391,10 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */
}
zend_compile_params(params_ast, return_type_ast);
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
zend_mark_function_as_generator();
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
}
if (uses_ast) {
zend_compile_closure_uses(uses_ast);
}

8
Zend/zend_compile.h

@ -473,8 +473,10 @@ struct _zend_execute_data {
#define ZEND_CALL_RELEASE_THIS (1 << 6)
#define ZEND_CALL_ALLOCATED (1 << 7)
#define ZEND_CALL_INFO_SHIFT 24
#define ZEND_CALL_INFO(call) \
(Z_TYPE_INFO((call)->This) >> 24)
(Z_TYPE_INFO((call)->This) >> ZEND_CALL_INFO_SHIFT)
#define ZEND_CALL_KIND_EX(call_info) \
(call_info & (ZEND_CALL_CODE | ZEND_CALL_TOP))
@ -483,11 +485,11 @@ struct _zend_execute_data {
ZEND_CALL_KIND_EX(ZEND_CALL_INFO(call))
#define ZEND_SET_CALL_INFO(call, object, info) do { \
Z_TYPE_INFO((call)->This) = ((object) ? IS_OBJECT_EX : IS_UNDEF) | ((info) << 24); \
Z_TYPE_INFO((call)->This) = ((object) ? IS_OBJECT_EX : IS_UNDEF) | ((info) << ZEND_CALL_INFO_SHIFT); \
} while (0)
#define ZEND_ADD_CALL_FLAG_EX(call_info, flag) do { \
call_info |= ((flag) << 24); \
call_info |= ((flag) << ZEND_CALL_INFO_SHIFT); \
} while (0)
#define ZEND_ADD_CALL_FLAG(call, flag) do { \

44
Zend/zend_execute.c

@ -2335,50 +2335,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
}
/* }}} */
ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value) /* {{{ */
{
/*
* Normally the execute_data is allocated on the VM stack (because it does
* not actually do any allocation and thus is faster). For generators
* though this behavior would be suboptimal, because the (rather large)
* structure would have to be copied back and forth every time execution is
* suspended or resumed. That's why for generators the execution context
* is allocated using a separate VM stack frame.
*/
zend_execute_data *execute_data;
uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
uint32_t used_stack = (ZEND_CALL_FRAME_SLOT + num_args + op_array->last_var + op_array->T - MIN(op_array->num_args, num_args)) * sizeof(zval);
execute_data = (zend_execute_data*)emalloc(used_stack);
ZEND_SET_CALL_INFO(execute_data, Z_TYPE(call->This) == IS_OBJECT, ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)));
EX(func) = (zend_function*)op_array;
Z_OBJ(EX(This)) = Z_OBJ(call->This);
ZEND_CALL_NUM_ARGS(execute_data) = num_args;
EX(prev_execute_data) = NULL;
/* copy arguments */
if (num_args > 0) {
zval *arg_src = ZEND_CALL_ARG(call, 1);
zval *arg_dst = ZEND_CALL_ARG(execute_data, 1);
zval *end = arg_src + num_args;
do {
ZVAL_COPY_VALUE(arg_dst, arg_src);
arg_src++;
arg_dst++;
} while (arg_src != end);
}
if (UNEXPECTED(!op_array->run_time_cache)) {
init_func_run_time_cache(op_array);
}
i_init_func_execute_data(execute_data, op_array, return_value, 1);
return execute_data;
}
/* }}} */
ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
{
EX(prev_execute_data) = EG(current_execute_data);

1
Zend/zend_execute.h

@ -37,7 +37,6 @@ void init_executor(void);
void shutdown_executor(void);
void shutdown_destructors(void);
ZEND_API void zend_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value);
ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value);
ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value);
ZEND_API void execute_ex(zend_execute_data *execute_data);
ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value);

8
Zend/zend_execute_API.c

@ -834,12 +834,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
if (func->type == ZEND_USER_FUNCTION) {
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
if (EXPECTED((func->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0)) {
zend_init_execute_data(call, &func->op_array, fci->retval);
zend_execute_ex(call);
} else {
zend_generator_create_zval(call, &func->op_array, fci->retval);
}
zend_init_execute_data(call, &func->op_array, fci->retval);
zend_execute_ex(call);
if (call_via_handler) {
/* We must re-initialize function again */
fci_cache->initialized = 0;

32
Zend/zend_generators.c

@ -379,38 +379,6 @@ static zend_object *zend_generator_create(zend_class_entry *class_type) /* {{{ *
}
/* }}} */
/* Requires globals EG(current_execute_data). */
ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array *op_array, zval *return_value) /* {{{ */
{
zend_generator *generator;
zend_execute_data *current_execute_data;
zend_execute_data *execute_data;
/* Create new execution context. We have to back up and restore EG(current_execute_data) here. */
current_execute_data = EG(current_execute_data);
execute_data = zend_create_generator_execute_data(call, op_array, return_value);
EG(current_execute_data) = current_execute_data;
object_init_ex(return_value, zend_ce_generator);
if (Z_TYPE(EX(This)) == IS_OBJECT && !(EX_CALL_INFO() & ZEND_CALL_CLOSURE)) {
ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_RELEASE_THIS);
Z_ADDREF(EX(This));
}
/* Save execution context in generator object. */
generator = (zend_generator *) Z_OBJ_P(return_value);
generator->execute_data = execute_data;
generator->frozen_call_stack = NULL;
/* EX(return_value) keeps pointer to zend_object (not a real zval) */
execute_data->return_value = (zval*)generator;
memset(&generator->execute_fake, 0, sizeof(zend_execute_data));
ZVAL_OBJ(&generator->execute_fake.This, (zend_object *) generator);
}
/* }}} */
static ZEND_COLD zend_function *zend_generator_get_constructor(zend_object *object) /* {{{ */
{
zend_throw_error(NULL, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated");

1
Zend/zend_generators.h

@ -102,7 +102,6 @@ static const zend_uchar ZEND_GENERATOR_AT_FIRST_YIELD = 0x4;
static const zend_uchar ZEND_GENERATOR_DO_INIT = 0x8;
void zend_register_generator_ce(void);
ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array *op_array, zval *return_value);
ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution);
ZEND_API void zend_generator_resume(zend_generator *generator);

1
Zend/zend_globals.h

@ -101,6 +101,7 @@ struct _zend_compiler_globals {
zend_bool increment_lineno;
zend_string *doc_comment;
uint32_t extra_fn_flags;
uint32_t compiler_options; /* set of ZEND_COMPILE_* constants */

38
Zend/zend_language_parser.y

@ -257,7 +257,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <num> returns_ref function is_reference is_variadic variable_modifiers
%type <num> method_modifiers non_empty_member_modifiers member_modifier
%type <num> class_modifiers class_modifier use_type
%type <num> class_modifiers class_modifier use_type backup_fn_flags
%type <str> backup_doc_comment
@ -481,9 +481,9 @@ unset_variable:
function_declaration_statement:
function returns_ref T_STRING backup_doc_comment '(' parameter_list ')' return_type
'{' inner_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2, $1, $4,
zend_ast_get_str($3), $6, NULL, $10, $8); }
backup_fn_flags '{' inner_statement_list '}' backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2 | $13, $1, $4,
zend_ast_get_str($3), $6, NULL, $11, $8); CG(extra_fn_flags) = $9; }
;
is_reference:
@ -713,9 +713,9 @@ class_statement:
| T_USE name_list trait_adaptations
{ $$ = zend_ast_create(ZEND_AST_USE_TRAIT, $2, $3); }
| method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')'
return_type method_body
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1, $2, $5,
zend_ast_get_str($4), $7, NULL, $10, $9); }
return_type backup_fn_flags method_body backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5,
zend_ast_get_str($4), $7, NULL, $11, $9); CG(extra_fn_flags) = $10; }
;
name_list:
@ -962,20 +962,20 @@ expr_without_variable:
| scalar { $$ = $1; }
| '`' backticks_expr '`' { $$ = zend_ast_create(ZEND_AST_SHELL_EXEC, $2); }
| T_PRINT expr { $$ = zend_ast_create(ZEND_AST_PRINT, $2); }
| T_YIELD { $$ = zend_ast_create(ZEND_AST_YIELD, NULL, NULL); }
| T_YIELD expr { $$ = zend_ast_create(ZEND_AST_YIELD, $2, NULL); }
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = zend_ast_create(ZEND_AST_YIELD, $4, $2); }
| T_YIELD_FROM expr { $$ = zend_ast_create(ZEND_AST_YIELD_FROM, $2); }
| T_YIELD { $$ = zend_ast_create(ZEND_AST_YIELD, NULL, NULL); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
| T_YIELD expr { $$ = zend_ast_create(ZEND_AST_YIELD, $2, NULL); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
| T_YIELD expr T_DOUBLE_ARROW expr { $$ = zend_ast_create(ZEND_AST_YIELD, $4, $2); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
| T_YIELD_FROM expr { $$ = zend_ast_create(ZEND_AST_YIELD_FROM, $2); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
| function returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type
'{' inner_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2, $1, $3,
backup_fn_flags '{' inner_statement_list '}' backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2 | $13, $1, $3,
zend_string_init("{closure}", sizeof("{closure}") - 1, 0),
$5, $7, $10, $8); }
$5, $7, $11, $8); CG(extra_fn_flags) = $9; }
| T_STATIC function returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars
return_type '{' inner_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $3 | ZEND_ACC_STATIC, $2, $4,
return_type backup_fn_flags '{' inner_statement_list '}' backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $3 | $14 | ZEND_ACC_STATIC, $2, $4,
zend_string_init("{closure}", sizeof("{closure}") - 1, 0),
$6, $8, $11, $9); }
$6, $8, $12, $9); CG(extra_fn_flags) = $10; }
;
function:
@ -986,6 +986,10 @@ backup_doc_comment:
/* empty */ { $$ = CG(doc_comment); CG(doc_comment) = NULL; }
;
backup_fn_flags:
/* empty */ { $$ = CG(extra_fn_flags); CG(extra_fn_flags) = 0; }
;
returns_ref:
/* empty */ { $$ = 0; }
| '&' { $$ = ZEND_ACC_RETURN_REFERENCE; }

5489
Zend/zend_language_scanner.c
File diff suppressed because it is too large
View File

1
Zend/zend_language_scanner.l

@ -178,6 +178,7 @@ void startup_scanner(void)
{
CG(parse_error) = 0;
CG(doc_comment) = NULL;
CG(extra_fn_flags) = 0;
zend_stack_init(&SCNG(state_stack), sizeof(int));
zend_ptr_stack_init(&SCNG(heredoc_label_stack));
}

2
Zend/zend_language_scanner_defs.h

@ -1,4 +1,4 @@
/* Generated by re2c 0.15.3 */
/* Generated by re2c 0.13.5 */
#line 3 "Zend/zend_language_scanner_defs.h"
enum YYCONDTYPE {

129
Zend/zend_vm_def.h

@ -3612,27 +3612,16 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
EX(call) = call->prev_execute_data;
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (EXPECTED(RETURN_VALUE_USED(opline))) {
ret = EX_VAR(opline->result.var);
zend_generator_create_zval(call, &fbc->op_array, ret);
} else {
zend_vm_stack_free_args(call);
}
zend_vm_stack_free_call_frame(call);
} else {
ret = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
ret = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
ZEND_VM_ENTER();
}
ZEND_VM_ENTER();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
@ -3720,32 +3709,20 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
LOAD_OPLINE();
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (EXPECTED(RETURN_VALUE_USED(opline))) {
ret = EX_VAR(opline->result.var);
zend_generator_create_zval(call, &fbc->op_array, ret);
} else {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
}
zend_vm_stack_free_args(call);
}
} else {
ret = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
ret = NULL;
if (RETURN_VALUE_USED(opline)) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
zval retval;
@ -4010,6 +3987,72 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC)
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
}
ZEND_VM_HANDLER(41, ZEND_GENERATOR_CREATE, ANY, ANY)
{
zval *return_value = EX(return_value);
if (EXPECTED(return_value)) {
USE_OPLINE
zend_generator *generator;
zend_execute_data *gen_execute_data;
uint32_t num_args, used_stack, call_info;
object_init_ex(return_value, zend_ce_generator);
/*
* Normally the execute_data is allocated on the VM stack (because it does
* not actually do any allocation and thus is faster). For generators
* though this behavior would be suboptimal, because the (rather large)
* structure would have to be copied back and forth every time execution is
* suspended or resumed. That's why for generators the execution context
* is allocated on heap.
*/
num_args = EX_NUM_ARGS();
used_stack = (ZEND_CALL_FRAME_SLOT + num_args + EX(func)->op_array.last_var + EX(func)->op_array.T - MIN(EX(func)->op_array.num_args, num_args)) * sizeof(zval);
gen_execute_data = (zend_execute_data*)emalloc(used_stack);
memcpy(gen_execute_data, execute_data, used_stack);
/* Save execution context in generator object. */
generator = (zend_generator *) Z_OBJ_P(EX(return_value));
generator->execute_data = gen_execute_data;
generator->frozen_call_stack = NULL;
memset(&generator->execute_fake, 0, sizeof(zend_execute_data));
ZVAL_OBJ(&generator->execute_fake.This, (zend_object *) generator);
gen_execute_data->opline = opline + 1;
/* EX(return_value) keeps pointer to zend_object (not a real zval) */
gen_execute_data->return_value = (zval*)generator;
call_info = Z_TYPE_INFO(EX(This));
if ((call_info & Z_TYPE_MASK) == IS_OBJECT
&& !(call_info & ((ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS) << ZEND_CALL_INFO_SHIFT))) {
ZEND_ADD_CALL_FLAG_EX(call_info, ZEND_CALL_RELEASE_THIS);
Z_ADDREF(gen_execute_data->This);
}
ZEND_ADD_CALL_FLAG_EX(call_info, (ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED));
Z_TYPE_INFO(gen_execute_data->This) = call_info;
gen_execute_data->prev_execute_data = NULL;
call_info = EX_CALL_INFO();
EG(current_execute_data) = EX(prev_execute_data);
if (EXPECTED(!(call_info & (ZEND_CALL_TOP|ZEND_CALL_ALLOCATED)))) {
EG(vm_stack_top) = (zval*)execute_data;
execute_data = EX(prev_execute_data);
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else if (EXPECTED(!(call_info & ZEND_CALL_TOP))) {
zend_execute_data *old_execute_data = execute_data;
execute_data = EX(prev_execute_data);
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else {
ZEND_VM_RETURN();
}
} else {
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
}
}
ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE

517
Zend/zend_vm_execute.h

@ -744,27 +744,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_U
EX(call) = call->prev_execute_data;
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (EXPECTED(0)) {
ret = EX_VAR(opline->result.var);
zend_generator_create_zval(call, &fbc->op_array, ret);
} else {
zend_vm_stack_free_args(call);
}
zend_vm_stack_free_call_frame(call);
} else {
ret = NULL;
if (0) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
ret = NULL;
if (0) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
ZEND_VM_ENTER();
}
ZEND_VM_ENTER();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
@ -834,27 +823,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_U
EX(call) = call->prev_execute_data;
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (EXPECTED(1)) {
ret = EX_VAR(opline->result.var);
zend_generator_create_zval(call, &fbc->op_array, ret);
} else {
zend_vm_stack_free_args(call);
}
zend_vm_stack_free_call_frame(call);
} else {
ret = NULL;
if (1) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
ret = NULL;
if (1) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 0);
ZEND_VM_ENTER();
}
ZEND_VM_ENTER();
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
@ -942,32 +920,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HA
LOAD_OPLINE();
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (EXPECTED(0)) {
ret = EX_VAR(opline->result.var);
zend_generator_create_zval(call, &fbc->op_array, ret);
} else {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
}
zend_vm_stack_free_args(call);
}
} else {
ret = NULL;
if (0) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
ret = NULL;
if (0) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
zval retval;
@ -1083,32 +1049,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_USED_HAND
LOAD_OPLINE();
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
if (EXPECTED(1)) {
ret = EX_VAR(opline->result.var);
zend_generator_create_zval(call, &fbc->op_array, ret);
} else {
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
}
zend_vm_stack_free_args(call);
}
} else {
ret = NULL;
if (1) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
ret = NULL;
if (1) {
ret = EX_VAR(opline->result.var);
ZVAL_NULL(ret);
}
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
call->prev_execute_data = execute_data;
i_init_func_execute_data(call, &fbc->op_array, ret, 1);
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
if (EXPECTED(zend_execute_ex == execute_ex)) {
ZEND_VM_ENTER();
} else {
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
zval retval;
@ -1195,6 +1149,72 @@ fcall_end:
ZEND_VM_CONTINUE();
}
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GENERATOR_CREATE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zval *return_value = EX(return_value);
if (EXPECTED(return_value)) {
USE_OPLINE
zend_generator *generator;
zend_execute_data *gen_execute_data;
uint32_t num_args, used_stack, call_info;
object_init_ex(return_value, zend_ce_generator);
/*
* Normally the execute_data is allocated on the VM stack (because it does
* not actually do any allocation and thus is faster). For generators
* though this behavior would be suboptimal, because the (rather large)
* structure would have to be copied back and forth every time execution is
* suspended or resumed. That's why for generators the execution context
* is allocated on heap.
*/
num_args = EX_NUM_ARGS();
used_stack = (ZEND_CALL_FRAME_SLOT + num_args + EX(func)->op_array.last_var + EX(func)->op_array.T - MIN(EX(func)->op_array.num_args, num_args)) * sizeof(zval);
gen_execute_data = (zend_execute_data*)emalloc(used_stack);
memcpy(gen_execute_data, execute_data, used_stack);
/* Save execution context in generator object. */
generator = (zend_generator *) Z_OBJ_P(EX(return_value));
generator->execute_data = gen_execute_data;
generator->frozen_call_stack = NULL;
memset(&generator->execute_fake, 0, sizeof(zend_execute_data));
ZVAL_OBJ(&generator->execute_fake.This, (zend_object *) generator);
gen_execute_data->opline = opline + 1;
/* EX(return_value) keeps pointer to zend_object (not a real zval) */
gen_execute_data->return_value = (zval*)generator;
call_info = Z_TYPE_INFO(EX(This));
if ((call_info & Z_TYPE_MASK) == IS_OBJECT
&& !(call_info & ((ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS) << ZEND_CALL_INFO_SHIFT))) {
ZEND_ADD_CALL_FLAG_EX(call_info, ZEND_CALL_RELEASE_THIS);
Z_ADDREF(gen_execute_data->This);
}
ZEND_ADD_CALL_FLAG_EX(call_info, (ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED));
Z_TYPE_INFO(gen_execute_data->This) = call_info;
gen_execute_data->prev_execute_data = NULL;
call_info = EX_CALL_INFO();
EG(current_execute_data) = EX(prev_execute_data);
if (EXPECTED(!(call_info & (ZEND_CALL_TOP|ZEND_CALL_ALLOCATED)))) {
EG(vm_stack_top) = (zval*)execute_data;
execute_data = EX(prev_execute_data);
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else if (EXPECTED(!(call_info & ZEND_CALL_TOP))) {
zend_execute_data *old_execute_data = execute_data;
execute_data = EX(prev_execute_data);
zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
LOAD_NEXT_OPLINE();
ZEND_VM_LEAVE();
} else {
ZEND_VM_RETURN();
}
} else {
ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));
}
}
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -56848,6 +56868,7 @@ void zend_init_opcodes_handlers(void)
ZEND_ECHO_SPEC_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
ZEND_ECHO_SPEC_CV_HANDLER,
ZEND_GENERATOR_CREATE_SPEC_HANDLER,
ZEND_JMP_SPEC_HANDLER,
ZEND_JMPZ_SPEC_CONST_HANDLER,
ZEND_JMPZ_SPEC_TMPVAR_HANDLER,
@ -59881,150 +59902,150 @@ void zend_init_opcodes_handlers(void)
776 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_RETVAL,
826 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
851 | SPEC_RULE_OP1,
3845,
856,
857 | SPEC_RULE_OP1,
862 | SPEC_RULE_OP1,
867 | SPEC_RULE_OP1,
872 | SPEC_RULE_OP1,
877 | SPEC_RULE_OP1,
882 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
3845,
3845,
3845,
907 | SPEC_RULE_OP1,
912 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
937 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
962 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
987 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1012,
1013 | SPEC_RULE_OP1,
1018 | SPEC_RULE_OP2,
1023 | SPEC_RULE_RETVAL,
1025 | SPEC_RULE_OP2,
1030 | SPEC_RULE_OP1,
1035,
1036 | SPEC_RULE_OP2,
1041 | SPEC_RULE_OP1,
1046 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG,
1056 | SPEC_RULE_OP1,
1061 | SPEC_RULE_OP1,
1066 | SPEC_RULE_OP2,
1071 | SPEC_RULE_OP1,
1076 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1101 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1126 | SPEC_RULE_OP1,
1131 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1156 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1181 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1206 | SPEC_RULE_OP1,
1211 | SPEC_RULE_OP1,
1216 | SPEC_RULE_OP1,
1221 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1246 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1271 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1296 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1321 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1346 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1371 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1396 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1421 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1446 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1471 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1496 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1521 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1546 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1571 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1596 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1621 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1646 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1671 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1696 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
3845,
1721,
857,
858 | SPEC_RULE_OP1,
863 | SPEC_RULE_OP1,
868 | SPEC_RULE_OP1,
873 | SPEC_RULE_OP1,
878 | SPEC_RULE_OP1,
883 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
3846,
3846,
3846,
908 | SPEC_RULE_OP1,
913 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
938 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
963 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
988 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1013,
1014 | SPEC_RULE_OP1,
1019 | SPEC_RULE_OP2,
1024 | SPEC_RULE_RETVAL,
1026 | SPEC_RULE_OP2,
1031 | SPEC_RULE_OP1,
1036,
1037 | SPEC_RULE_OP2,
1042 | SPEC_RULE_OP1,
1047 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG,
1057 | SPEC_RULE_OP1,
1062 | SPEC_RULE_OP1,
1067 | SPEC_RULE_OP2,
1072 | SPEC_RULE_OP1,
1077 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1102 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1127 | SPEC_RULE_OP1,
1132 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1157 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1182 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1207 | SPEC_RULE_OP1,
1212 | SPEC_RULE_OP1,
1217 | SPEC_RULE_OP1,
1222 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1247 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1272 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1297 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1322 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1347 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1372 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1397 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1422 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1447 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1472 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1497 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1522 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1547 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1572 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1597 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1622 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1647 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1672 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1697 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
3846,
1722,
1723,
1724,
1725,
1726 | SPEC_RULE_OP1,
1731 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1756 | SPEC_RULE_OP1,
1761 | SPEC_RULE_OP2,
1766 | SPEC_RULE_OP1,
1771 | SPEC_RULE_OP1,
1776 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1801 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1826 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1851 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1876 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG,
1886 | SPEC_RULE_OP1,
1891 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1916,
1917 | SPEC_RULE_OP1,
1922 | SPEC_RULE_OP1,
1927 | SPEC_RULE_OP1,
1932 | SPEC_RULE_OP1,
1937 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1962 | SPEC_RULE_OP1,
1967 | SPEC_RULE_OP1,
1972 | SPEC_RULE_OP1,
1977 | SPEC_RULE_OP2,
1982 | SPEC_RULE_RETVAL,
1984 | SPEC_RULE_RETVAL,
1986 | SPEC_RULE_RETVAL,
1988 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2013 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2038 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2063 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2088 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA,
2213,
2214 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2239,
2240 | SPEC_RULE_OP2,
2245,
2246 | SPEC_RULE_OP1,
2251 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2276 | SPEC_RULE_OP2,
2281 | SPEC_RULE_OP2,
2286,
2287 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA,
2412 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2437,
1726,
1727 | SPEC_RULE_OP1,
1732 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1757 | SPEC_RULE_OP1,
1762 | SPEC_RULE_OP2,
1767 | SPEC_RULE_OP1,
1772 | SPEC_RULE_OP1,
1777 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1802 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1827 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1852 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1877 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG,
1887 | SPEC_RULE_OP1,
1892 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1917,
1918 | SPEC_RULE_OP1,
1923 | SPEC_RULE_OP1,
1928 | SPEC_RULE_OP1,
1933 | SPEC_RULE_OP1,
1938 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
1963 | SPEC_RULE_OP1,
1968 | SPEC_RULE_OP1,
1973 | SPEC_RULE_OP1,
1978 | SPEC_RULE_OP2,
1983 | SPEC_RULE_RETVAL,
1985 | SPEC_RULE_RETVAL,
1987 | SPEC_RULE_RETVAL,
1989 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2014 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2039 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2064 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2089 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA,
2214,
2215 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2240,
2241 | SPEC_RULE_OP2,
2246,
2247 | SPEC_RULE_OP1,
2252 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2277 | SPEC_RULE_OP2,
2282 | SPEC_RULE_OP2,
2287,
2288 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA,
2413 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2438,
2439,
2440 | SPEC_RULE_OP1,
2445 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2470,
2440,
2441 | SPEC_RULE_OP1,
2446 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2471,
2472 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2497,
2472,
2473 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2498,
2499,
2500 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2525 | SPEC_RULE_OP1,
2530,
2500,
2501 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2526 | SPEC_RULE_OP1,
2531,
2532,
2533,
2534 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2559 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2584 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2609 | SPEC_RULE_OP1,
2614 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2639,
2640 | SPEC_RULE_OP2,
2645 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2670 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2695 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2720 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2745 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2770 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2795 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2820 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2845 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2870 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2895 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
3845
2534,
2535 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2560 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2585 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2610 | SPEC_RULE_OP1,
2615 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2640,
2641 | SPEC_RULE_OP2,
2646 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2671 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2696 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2721 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2746 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2771 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2796 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2821 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2846 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2871 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2896 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
3846
};
zend_opcode_handlers = labels;
zend_handlers_count = sizeof(labels) / sizeof(void*);
@ -60123,7 +60144,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 2920 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 2921 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60131,7 +60152,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 2945 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 2946 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60139,7 +60160,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 2970 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 2971 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60150,17 +60171,17 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 2995 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 2996 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
} else if ((op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG)) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3020 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 3021 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
} else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3045 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 3046 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
}
break;
case ZEND_MUL:
@ -60168,7 +60189,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3070 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 3071 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60176,7 +60197,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3095 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 3096 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60184,7 +60205,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3120 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
spec = 3121 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60195,7 +60216,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3145 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3146 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60203,7 +60224,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3220 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3221 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60214,7 +60235,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3295 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3296 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60222,7 +60243,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3370 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3371 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
if (op->op1_type > op->op2_type) {
zend_swap_operands(op);
}
@ -60233,12 +60254,12 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3445 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3446 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
} else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3520 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3521 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
}
break;
case ZEND_IS_SMALLER_OR_EQUAL:
@ -60246,55 +60267,55 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3595 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3596 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
} else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break;
}
spec = 3670 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
spec = 3671 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
}
break;
case ZEND_QM_ASSIGN:
if ((op1_info == MAY_BE_DOUBLE)) {
spec = 3835 | SPEC_RULE_OP1;
spec = 3836 | SPEC_RULE_OP1;
} else if ((!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) {
spec = 3840 | SPEC_RULE_OP1;
spec = 3841 | SPEC_RULE_OP1;
}
break;
case ZEND_PRE_INC:
if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) {
spec = 3745 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
spec = 3746 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
} else if ((op1_info == MAY_BE_LONG)) {
spec = 3755 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
spec = 3756 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
} else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) {
spec = 3765 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
spec = 3766 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
}
break;
case ZEND_PRE_DEC:
if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) {
spec = 3775 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
spec = 3776 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
} else if ((op1_info == MAY_BE_LONG)) {
spec = 3785 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
spec = 3786 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
} else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) {
spec = 3795 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
spec = 3796 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL;
}
break;
case ZEND_POST_INC:
if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) {
spec = 3805 | SPEC_RULE_OP1;
spec = 3806 | SPEC_RULE_OP1;
} else if ((op1_info == MAY_BE_LONG)) {
spec = 3810 | SPEC_RULE_OP1;
spec = 3811 | SPEC_RULE_OP1;
} else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) {
spec = 3815 | SPEC_RULE_OP1;
spec = 3816 | SPEC_RULE_OP1;
}
break;
case ZEND_POST_DEC:
if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) {
spec = 3820 | SPEC_RULE_OP1;
spec = 3821 | SPEC_RULE_OP1;
} else if ((op1_info == MAY_BE_LONG)) {
spec = 3825 | SPEC_RULE_OP1;
spec = 3826 | SPEC_RULE_OP1;
} else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) {
spec = 3830 | SPEC_RULE_OP1;
spec = 3831 | SPEC_RULE_OP1;
}
break;
default:

2
Zend/zend_vm_opcodes.c

@ -63,7 +63,7 @@ static const char *zend_vm_opcodes_names[184] = {
"ZEND_ASSIGN",
"ZEND_ASSIGN_REF",
"ZEND_ECHO",
NULL,
"ZEND_GENERATOR_CREATE",
"ZEND_JMP",
"ZEND_JMPZ",
"ZEND_JMPNZ",

1
Zend/zend_vm_opcodes.h

@ -111,6 +111,7 @@ END_EXTERN_C()
#define ZEND_ASSIGN 38
#define ZEND_ASSIGN_REF 39
#define ZEND_ECHO 40
#define ZEND_GENERATOR_CREATE 41
#define ZEND_JMP 42
#define ZEND_JMPZ 43
#define ZEND_JMPNZ 44

2
ext/opcache/Optimizer/zend_cfg.c

@ -57,6 +57,7 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend
//TODO: support for stackless CFG???
if (0/*stackless*/) {
if (opcode == ZEND_INCLUDE_OR_EVAL ||
opcode == ZEND_GENERATOR_CREATE ||
opcode == ZEND_YIELD ||
opcode == ZEND_YIELD_FROM ||
opcode == ZEND_DO_FCALL ||
@ -268,6 +269,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
break;
case ZEND_INCLUDE_OR_EVAL:
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
case ZEND_GENERATOR_CREATE:
case ZEND_YIELD:
case ZEND_YIELD_FROM:
if (build_flags & ZEND_CFG_STACKLESS) {

Loading…
Cancel
Save