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

Reply via email to