diff options
Diffstat (limited to 'Zend/zend_vm_execute.h')
| -rw-r--r-- | Zend/zend_vm_execute.h | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 8e7094fed7..db617a6bd8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3485,6 +3485,73 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + /* The generator object is stored in EX(return_value) */ + zend_generator *generator = (zend_generator *) EX(return_value); + + zval *val; + + + SAVE_OPLINE(); + val = EX_CONSTANT(opline->op1); + if (Z_TYPE_P(val) == IS_ARRAY) { + ZVAL_COPY_VALUE(&generator->values, val); + if (IS_CONST != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) { + Z_ADDREF_P(val); + } + Z_FE_POS(generator->values) = 0; + + } else if (IS_CONST != IS_CONST && Z_TYPE_P(val) == IS_OBJECT && Z_OBJCE_P(val)->get_iterator) { + zend_class_entry *ce = Z_OBJCE_P(val); + if (ce == zend_ce_generator) { + + } else { + zend_object_iterator *iter = ce->get_iterator(ce, val, 0); + + if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) { + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, + "Object of type %s did not create an Iterator", ce->name->val); + } + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + iter->index = 0; + if (iter->funcs->rewind) { + iter->funcs->rewind(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + OBJ_RELEASE(&iter->std); + HANDLE_EXCEPTION(); + } + } + + ZVAL_OBJ(&generator->values, &iter->std); + } + } else { + // TODO: Should be an engine exception + zend_throw_exception(NULL, "Can use \"yield *\" only with arrays and Traversables", 0); + HANDLE_EXCEPTION(); + } + + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + /* 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(); +} + static int ZEND_FASTCALL ZEND_STRLEN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9500,6 +9567,74 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + /* The generator object is stored in EX(return_value) */ + zend_generator *generator = (zend_generator *) EX(return_value); + + zval *val; + zend_free_op free_op1; + + SAVE_OPLINE(); + val = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); + if (Z_TYPE_P(val) == IS_ARRAY) { + ZVAL_COPY_VALUE(&generator->values, val); + if (IS_TMP_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) { + Z_ADDREF_P(val); + } + Z_FE_POS(generator->values) = 0; + + } else if (IS_TMP_VAR != IS_CONST && Z_TYPE_P(val) == IS_OBJECT && Z_OBJCE_P(val)->get_iterator) { + zend_class_entry *ce = Z_OBJCE_P(val); + if (ce == zend_ce_generator) { + + } else { + zend_object_iterator *iter = ce->get_iterator(ce, val, 0); + zval_ptr_dtor_nogc(free_op1); + + if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) { + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, + "Object of type %s did not create an Iterator", ce->name->val); + } + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + iter->index = 0; + if (iter->funcs->rewind) { + iter->funcs->rewind(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + OBJ_RELEASE(&iter->std); + HANDLE_EXCEPTION(); + } + } + + ZVAL_OBJ(&generator->values, &iter->std); + } + } else { + // TODO: Should be an engine exception + zend_throw_exception(NULL, "Can use \"yield *\" only with arrays and Traversables", 0); + HANDLE_EXCEPTION(); + } + + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + /* 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(); +} + static int ZEND_FASTCALL ZEND_TYPE_CHECK_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12768,6 +12903,75 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + /* The generator object is stored in EX(return_value) */ + zend_generator *generator = (zend_generator *) EX(return_value); + + zval *val; + zend_free_op free_op1; + + SAVE_OPLINE(); + val = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1); + if (Z_TYPE_P(val) == IS_ARRAY) { + ZVAL_COPY_VALUE(&generator->values, val); + if (IS_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) { + Z_ADDREF_P(val); + } + Z_FE_POS(generator->values) = 0; + + zval_ptr_dtor_nogc(free_op1); + } else if (IS_VAR != IS_CONST && Z_TYPE_P(val) == IS_OBJECT && Z_OBJCE_P(val)->get_iterator) { + zend_class_entry *ce = Z_OBJCE_P(val); + if (ce == zend_ce_generator) { + + } else { + zend_object_iterator *iter = ce->get_iterator(ce, val, 0); + zval_ptr_dtor_nogc(free_op1); + + if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) { + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, + "Object of type %s did not create an Iterator", ce->name->val); + } + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + iter->index = 0; + if (iter->funcs->rewind) { + iter->funcs->rewind(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + OBJ_RELEASE(&iter->std); + HANDLE_EXCEPTION(); + } + } + + ZVAL_OBJ(&generator->values, &iter->std); + } + } else { + // TODO: Should be an engine exception + zend_throw_exception(NULL, "Can use \"yield *\" only with arrays and Traversables", 0); + HANDLE_EXCEPTION(); + } + + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + /* 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(); +} + static int ZEND_FASTCALL ZEND_TYPE_CHECK_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -24950,6 +25154,73 @@ static int ZEND_FASTCALL ZEND_QM_ASSIGN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + /* The generator object is stored in EX(return_value) */ + zend_generator *generator = (zend_generator *) EX(return_value); + + zval *val; + + + SAVE_OPLINE(); + val = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var); + if (Z_TYPE_P(val) == IS_ARRAY) { + ZVAL_COPY_VALUE(&generator->values, val); + if (IS_CV != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) { + Z_ADDREF_P(val); + } + Z_FE_POS(generator->values) = 0; + + } else if (IS_CV != IS_CONST && Z_TYPE_P(val) == IS_OBJECT && Z_OBJCE_P(val)->get_iterator) { + zend_class_entry *ce = Z_OBJCE_P(val); + if (ce == zend_ce_generator) { + + } else { + zend_object_iterator *iter = ce->get_iterator(ce, val, 0); + + if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) { + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, + "Object of type %s did not create an Iterator", ce->name->val); + } + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + iter->index = 0; + if (iter->funcs->rewind) { + iter->funcs->rewind(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + OBJ_RELEASE(&iter->std); + HANDLE_EXCEPTION(); + } + } + + ZVAL_OBJ(&generator->values, &iter->std); + } + } else { + // TODO: Should be an engine exception + zend_throw_exception(NULL, "Can use \"yield *\" only with arrays and Traversables", 0); + HANDLE_EXCEPTION(); + } + + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + /* 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(); +} + static int ZEND_FASTCALL ZEND_STRLEN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -41208,6 +41479,31 @@ void zend_init_opcodes_handlers(void) ZEND_COALESCE_SPEC_CV_HANDLER, ZEND_COALESCE_SPEC_CV_HANDLER, ZEND_COALESCE_SPEC_CV_HANDLER, + ZEND_YIELD_FROM_SPEC_CONST_HANDLER, + ZEND_YIELD_FROM_SPEC_CONST_HANDLER, + ZEND_YIELD_FROM_SPEC_CONST_HANDLER, + ZEND_YIELD_FROM_SPEC_CONST_HANDLER, + ZEND_YIELD_FROM_SPEC_CONST_HANDLER, + ZEND_YIELD_FROM_SPEC_TMP_HANDLER, + ZEND_YIELD_FROM_SPEC_TMP_HANDLER, + ZEND_YIELD_FROM_SPEC_TMP_HANDLER, + ZEND_YIELD_FROM_SPEC_TMP_HANDLER, + ZEND_YIELD_FROM_SPEC_TMP_HANDLER, + ZEND_YIELD_FROM_SPEC_VAR_HANDLER, + ZEND_YIELD_FROM_SPEC_VAR_HANDLER, + ZEND_YIELD_FROM_SPEC_VAR_HANDLER, + ZEND_YIELD_FROM_SPEC_VAR_HANDLER, + ZEND_YIELD_FROM_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_YIELD_FROM_SPEC_CV_HANDLER, + ZEND_YIELD_FROM_SPEC_CV_HANDLER, + ZEND_YIELD_FROM_SPEC_CV_HANDLER, + ZEND_YIELD_FROM_SPEC_CV_HANDLER, + ZEND_YIELD_FROM_SPEC_CV_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; |
