summaryrefslogtreecommitdiff
path: root/Zend/zend_vm_execute.h
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_vm_execute.h')
-rw-r--r--Zend/zend_vm_execute.h296
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;