Commit: fafce58683e74a397023cc1077aae210109b40b6
Author: Nikita Popov <ni...@php.net> Sat, 26 May 2012 22:44:53 +0200
Parents: 1a99d1c8874936f7e232840a580d7bc588d63a6c
Branches: master
Link:
http://git.php.net/?p=php-src.git;a=commitdiff;h=fafce58683e74a397023cc1077aae210109b40b6
Log:
Add YIELD opcode implementation
Changed paths:
M Zend/zend_compile.c
M Zend/zend_generators.c
M Zend/zend_vm_def.h
M Zend/zend_vm_execute.h
M Zend/zend_vm_opcodes.h
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index f0802ef..b0e6ee2 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -2660,11 +2660,17 @@ void zend_do_return(znode *expr, int do_end_vparse
TSRMLS_DC) /* {{{ */
void zend_do_yield(znode *expr TSRMLS_DC) /* {{{ */
{
+ zend_op *opline;
+
if ((CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0) {
zend_error(E_COMPILE_ERROR, "The \"yield\" statement can only
be used inside a generator function");
}
- /* do nothing for now */
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+ opline->opcode = ZEND_YIELD;
+ SET_NODE(opline->op1, expr);
+ SET_UNUSED(opline->op2);
}
/* }}} */
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 1ea910b..8161fc7 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -53,6 +53,10 @@ static void zend_generator_free_storage(zend_generator
*generator TSRMLS_DC) /*
efree(execute_data);
}
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
efree(generator);
}
/* }}} */
@@ -88,14 +92,28 @@ static zend_function *zend_generator_get_constructor(zval
*object TSRMLS_DC) /*
static void zend_generator_resume(zval *object, zend_generator *generator
TSRMLS_DC) /* {{{ */
{
- /* Go to next opcode (we don't want to run the last one again) */
- generator->execute_data->opline++;
+ /* Backup executor globals */
+ zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr);
+ zend_op **original_opline_ptr = EG(opline_ptr);
+ zend_op_array *original_active_op_array = EG(active_op_array);
/* We (mis) use the return_value_ptr_ptr to provide the generator object
* to the executor. This way YIELD will be able to set the yielded
value */
EG(return_value_ptr_ptr) = &object;
+ EG(opline_ptr) = &generator->execute_data->opline;
+ EG(active_op_array) = generator->execute_data->op_array;
+
+ /* Go to next opcode (we don't want to run the last one again) */
+ generator->execute_data->opline++;
+
+ /* Resume execution */
execute_ex(generator->execute_data TSRMLS_CC);
+
+ /* Restore executor globals */
+ EG(return_value_ptr_ptr) = original_return_value_ptr_ptr;
+ EG(opline_ptr) = original_opline_ptr;
+ EG(active_op_array) = original_active_op_array;
}
/* }}} */
@@ -190,6 +208,7 @@ ZEND_METHOD(Generator, next)
return;
}
+ object = getThis();
generator = (zend_generator *) zend_object_store_get_object(object
TSRMLS_CC);
zend_generator_ensure_initialized(object, generator TSRMLS_CC);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index f4d16be..b2fc051 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5255,4 +5255,45 @@ ZEND_VM_HANDLER(159, ZEND_SUSPEND_AND_RETURN_GENERATOR,
ANY, ANY)
ZEND_VM_LEAVE();
}
+ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV, ANY)
+{
+ /* The generator object is stored in return_value_ptr_ptr */
+ zend_generator *generator = (zend_generator *)
zend_object_store_get_object(*EG(return_value_ptr_ptr) TSRMLS_CC);
+
+ /* Destroy the previously yielded value */
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
+ {
+ USE_OPLINE
+ zend_free_op free_op1;
+ 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 {
+ generator->value = value;
+ Z_ADDREF_P(value);
+ }
+
+ FREE_OP1_IF_VAR();
+ }
+
+ ZEND_VM_RETURN();
+}
+
ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper)
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index c83a4db..775b0ec 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -3030,6 +3030,46 @@ static int ZEND_FASTCALL
ZEND_QM_ASSIGN_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL
ZEND_YIELD_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ /* The generator object is stored in return_value_ptr_ptr */
+ zend_generator *generator = (zend_generator *)
zend_object_store_get_object(*EG(return_value_ptr_ptr) TSRMLS_CC);
+
+ /* Destroy the previously yielded value */
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
+ {
+ USE_OPLINE
+
+ zval *value = opline->op1.zv;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CONST == IS_CONST || IS_CONST == 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 (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ generator->value = value;
+ Z_ADDREF_P(value);
+ }
+
+ }
+
+ ZEND_VM_RETURN();
+}
+
static int ZEND_FASTCALL
ZEND_ADD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -7616,6 +7656,46 @@ static int ZEND_FASTCALL
ZEND_INSTANCEOF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_A
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ /* The generator object is stored in return_value_ptr_ptr */
+ zend_generator *generator = (zend_generator *)
zend_object_store_get_object(*EG(return_value_ptr_ptr) TSRMLS_CC);
+
+ /* Destroy the previously yielded value */
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
+ {
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(),
&free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == 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 (!1) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ generator->value = value;
+ Z_ADDREF_P(value);
+ }
+
+ }
+
+ ZEND_VM_RETURN();
+}
+
static int ZEND_FASTCALL
ZEND_ADD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -12279,6 +12359,47 @@ static int ZEND_FASTCALL
ZEND_INSTANCEOF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ /* The generator object is stored in return_value_ptr_ptr */
+ zend_generator *generator = (zend_generator *)
zend_object_store_get_object(*EG(return_value_ptr_ptr) TSRMLS_CC);
+
+ /* Destroy the previously yielded value */
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
+ {
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(),
&free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_VAR == IS_CONST || IS_VAR == 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 (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ generator->value = value;
+ Z_ADDREF_P(value);
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
+
+ ZEND_VM_RETURN();
+}
+
static int ZEND_FASTCALL
ZEND_ADD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -28113,6 +28234,46 @@ static int ZEND_FASTCALL
ZEND_INSTANCEOF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_AR
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ /* The generator object is stored in return_value_ptr_ptr */
+ zend_generator *generator = (zend_generator *)
zend_object_store_get_object(*EG(return_value_ptr_ptr) TSRMLS_CC);
+
+ /* Destroy the previously yielded value */
+ if (generator->value) {
+ zval_ptr_dtor(&generator->value);
+ }
+
+ {
+ USE_OPLINE
+
+ zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(),
opline->op1.var TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CV == IS_CONST || IS_CV == 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 (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ generator->value = value;
+ Z_ADDREF_P(value);
+ }
+
+ }
+
+ ZEND_VM_RETURN();
+}
+
static int ZEND_FASTCALL
ZEND_ADD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -40903,6 +41064,31 @@ void zend_init_opcodes_handlers(void)
ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
+ ZEND_YIELD_SPEC_CONST_HANDLER,
+ ZEND_YIELD_SPEC_CONST_HANDLER,
+ ZEND_YIELD_SPEC_CONST_HANDLER,
+ ZEND_YIELD_SPEC_CONST_HANDLER,
+ ZEND_YIELD_SPEC_CONST_HANDLER,
+ ZEND_YIELD_SPEC_TMP_HANDLER,
+ ZEND_YIELD_SPEC_TMP_HANDLER,
+ ZEND_YIELD_SPEC_TMP_HANDLER,
+ ZEND_YIELD_SPEC_TMP_HANDLER,
+ ZEND_YIELD_SPEC_TMP_HANDLER,
+ ZEND_YIELD_SPEC_VAR_HANDLER,
+ ZEND_YIELD_SPEC_VAR_HANDLER,
+ ZEND_YIELD_SPEC_VAR_HANDLER,
+ ZEND_YIELD_SPEC_VAR_HANDLER,
+ ZEND_YIELD_SPEC_VAR_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_NULL_HANDLER,
+ ZEND_YIELD_SPEC_CV_HANDLER,
+ ZEND_YIELD_SPEC_CV_HANDLER,
+ ZEND_YIELD_SPEC_CV_HANDLER,
+ ZEND_YIELD_SPEC_CV_HANDLER,
+ ZEND_YIELD_SPEC_CV_HANDLER,
ZEND_NULL_HANDLER
};
zend_opcode_handlers = (opcode_handler_t*)labels;
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 9e24dee..53e00a1 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -160,3 +160,4 @@
#define ZEND_QM_ASSIGN_VAR 157
#define ZEND_JMP_SET_VAR 158
#define ZEND_SUSPEND_AND_RETURN_GENERATOR 159
+#define ZEND_YIELD 160
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php