From: Andi Gutmans Date: Mon, 27 Nov 2000 18:46:23 +0000 (+0000) Subject: - Allow passing references which are returned from functions and new X-Git-Tag: php-4.0.4RC3~45 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8d9082563a92c4f93d561e93e6eca7594e275c01;p=php - Allow passing references which are returned from functions and new - statements to be passed by reference. --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 047029523a..c975e5c88a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -916,6 +916,7 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC) unsigned char *arg_types; int original_op=op; zend_function **function_ptr_ptr, *function_ptr; + int send_by_reference; zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); @@ -939,20 +940,13 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC) arg_types = NULL; } - if (op==ZEND_SEND_VAL) { - switch (param->op_type) { - case IS_CONST: /* constants behave like variables when passed to functions, - * as far as reference counting is concerned. Treat them - * as if they were variables here. - */ - break; - case IS_VAR: - op = ZEND_SEND_VAR_NO_REF; - break; - } + send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(offset, 1, arg_types)?ZEND_ARG_SEND_BY_REF:0; + + if (op == ZEND_SEND_VAL && param->op_type == IS_VAR) { + op = ZEND_SEND_VAR_NO_REF; } - if (op!=ZEND_SEND_VAR_NO_REF - && ARG_SHOULD_BE_SENT_BY_REF(offset, 1, arg_types)) { + + if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference == ZEND_ARG_SEND_BY_REF) { /* change to passing by reference */ switch (param->op_type) { case IS_VAR: @@ -964,9 +958,11 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC) } } - if (original_op==ZEND_SEND_VAR) { + if (original_op == ZEND_SEND_VAR) { switch(op) { case ZEND_SEND_VAR_NO_REF: + zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC); + break; case ZEND_SEND_VAR: if (function_ptr) { zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC); @@ -981,10 +977,19 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC) } opline = get_next_op(CG(active_op_array) CLS_CC); - if (function_ptr) { - opline->extended_value = ZEND_DO_FCALL; + + if (op == ZEND_SEND_VAR_NO_REF) { + if (function_ptr) { + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference; + } else { + opline->extended_value = 0; + } } else { - opline->extended_value = ZEND_DO_FCALL_BY_NAME; + if (function_ptr) { + opline->extended_value = ZEND_DO_FCALL; + } else { + opline->extended_value = ZEND_DO_FCALL_BY_NAME; + } } opline->opcode = op; opline->op1 = *param; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b6f87f7628..b30fde873c 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -597,6 +597,8 @@ int zendlex(znode *zendlval CLS_DC); #define ZEND_MEMBER_FUNC_CALL 1<<0 #define ZEND_CTOR_CALL 1<<1 +#define ZEND_ARG_SEND_BY_REF (1<<0) +#define ZEND_ARG_COMPILE_TIME_BOUND (1<<1) #define AI_USE_PTR(ai) \ if ((ai).ptr_ptr) { \ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index eb61393b69..a64ba0db7f 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1656,37 +1656,55 @@ do_fcall_common: zend_ptr_stack_push(&EG(argument_stack), valptr); } NEXT_OPCODE(); - case ZEND_SEND_VAR: case ZEND_SEND_VAR_NO_REF: - if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) { - if (opline->opcode==ZEND_SEND_VAR_NO_REF) { - zend_error(E_ERROR, "Only variables can be passed by reference"); + if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ + if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { + goto send_by_var; } - goto send_by_ref; + } else if (!ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) { + goto send_by_var; } { zval *varptr; varptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R); - if (varptr == &EG(uninitialized_zval)) { - ALLOC_ZVAL(varptr); - INIT_ZVAL(*varptr); - varptr->refcount = 0; - } else if (PZVAL_IS_REF(varptr)) { - zval *original_var = varptr; - - ALLOC_ZVAL(varptr); - *varptr = *original_var; - varptr->is_ref = 0; - varptr->refcount = 0; - zval_copy_ctor(varptr); + if (varptr != &EG(uninitialized_zval) && (PZVAL_IS_REF(varptr) || varptr->refcount == 1)) { + varptr->is_ref = 1; + varptr->refcount++; + zend_ptr_stack_push(&EG(argument_stack), varptr); + NEXT_OPCODE(); } - varptr->refcount++; - zend_ptr_stack_push(&EG(argument_stack), varptr); - FREE_OP(&opline->op1, EG(free_op1)); /* for string offsets */ + zend_error(E_ERROR, "Only variables can be passed by reference"); } NEXT_OPCODE(); + case ZEND_SEND_VAR: + if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) + && ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) { + goto send_by_ref; + } +send_by_var: + { + zval *varptr; + varptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R); + + if (varptr == &EG(uninitialized_zval)) { + ALLOC_ZVAL(varptr); + INIT_ZVAL(*varptr); + varptr->refcount = 0; + } else if (PZVAL_IS_REF(varptr)) { + zval *original_var = varptr; + + ALLOC_ZVAL(varptr); + *varptr = *original_var; + varptr->is_ref = 0; + varptr->refcount = 0; + zval_copy_ctor(varptr); + } + varptr->refcount++; + zend_ptr_stack_push(&EG(argument_stack), varptr); + FREE_OP(&opline->op1, EG(free_op1)); /* for string offsets */ + } + NEXT_OPCODE(); send_by_ref: case ZEND_SEND_REF: { zval **varptr_ptr;