diff options
author | Andi Gutmans <andi@php.net> | 2001-08-30 15:26:30 +0000 |
---|---|---|
committer | Andi Gutmans <andi@php.net> | 2001-08-30 15:26:30 +0000 |
commit | 29f5dbe10b2f31e9ec12b54faede5b4c19dd30bd (patch) | |
tree | 9e7ce561dfcf59255719f5b002fd7acceaa1dbb1 | |
parent | ab48027b3e6af90bbc601dff444bbc397d36b750 (diff) | |
download | php-git-29f5dbe10b2f31e9ec12b54faede5b4c19dd30bd.tar.gz |
- Initial support for exceptions.
-rw-r--r-- | Zend/zend_compile.c | 85 | ||||
-rw-r--r-- | Zend/zend_compile.h | 10 | ||||
-rw-r--r-- | Zend/zend_execute.c | 62 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 2 | ||||
-rw-r--r-- | Zend/zend_globals.h | 3 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 6 | ||||
-rw-r--r-- | Zend/zend_language_scanner.l | 12 |
7 files changed, 172 insertions, 8 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index a50ebc773a..7e13063159 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -81,6 +81,7 @@ void zend_init_compiler_data_structures(TSRMLS_D) CG(handle_op_arrays) = 1; CG(in_compilation) = 0; init_compiler_declarables(TSRMLS_C); + CG(throw_list) = NULL; } @@ -758,6 +759,8 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n zend_stack_push(&CG(foreach_copy_stack), (void *) &switch_entry.cond, sizeof(znode)); } + function_token->throw_list = CG(throw_list); + CG(throw_list) = NULL; } @@ -771,6 +774,8 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC) /* Pop the switch and foreach seperators */ zend_stack_del_top(&CG(switch_cond_stack)); zend_stack_del_top(&CG(foreach_copy_stack)); + + CG(throw_list) = function_token->throw_list; } @@ -919,7 +924,16 @@ void zend_do_end_function_call(znode *function_name, znode *result, znode *argum opline->result.op_type = IS_VAR; *result = opline->result; SET_UNUSED(opline->op2); - opline->op2.u.constant.value.lval = is_method; + + // Check how much this is really needed + //opline->op2.u.constant.value.lval = is_method; + if (CG(throw_list) != NULL) { + long op_number = get_next_op_number(CG(active_op_array))-1; + zend_llist_add_element(CG(throw_list), &op_number); + } else { + opline->op2.u.opline_num = -1; + } + zend_stack_del_top(&CG(function_call_stack)); opline->extended_value = argument_list->u.constant.value.lval; } @@ -1089,6 +1103,74 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) } +void zend_do_try(znode *try_token CLS_DC) +{ + try_token->throw_list = (void *) CG(throw_list); + CG(throw_list) = (zend_llist *) emalloc(sizeof(zend_llist)); + zend_llist_init(CG(throw_list), sizeof(long), NULL, 0); + // Initialize try backpatch list used to backpatch throw, do_fcall +} + +static void throw_list_applier(long *opline_num, long *catch_opline) +{ + zend_op *opline; + CLS_FETCH(); // Pass this by argument + + opline = &CG(active_op_array)->opcodes[*opline_num]; + + // Backpatch the opline of the catch statement + switch (opline->opcode) { + case ZEND_DO_FCALL: + case ZEND_DO_FCALL_BY_NAME: + case ZEND_THROW: + opline->op2.u.opline_num = *catch_opline; + break; + default: + zend_error(E_ERROR, "Bad opcode in throw list"); + break; + } +} + +void zend_do_begin_catch(znode *try_token, znode *catch_var CLS_DC) +{ + long catch_op_number = get_next_op_number(CG(active_op_array)); + zend_op *opline; + + opline = get_next_op(CG(active_op_array) CLS_CC); + opline->opcode = ZEND_CATCH; + opline->op1 = *catch_var; + SET_UNUSED(opline->op2); + + zend_llist_apply_with_argument(CG(throw_list), throw_list_applier, &catch_op_number); + zend_llist_destroy(CG(throw_list)); + efree(CG(throw_list)); + CG(throw_list) = (void *) try_token->throw_list; + + try_token->u.opline_num = catch_op_number; +} + +void zend_do_end_catch(znode *try_token CLS_DC) +{ + CG(active_op_array)->opcodes[try_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); +} + +void zend_do_throw(znode *expr CLS_DC) +{ + zend_op *opline; + long throw_op_number = get_next_op_number(CG(active_op_array)); + + opline = get_next_op(CG(active_op_array) CLS_CC); + opline->opcode = ZEND_THROW; + opline->op1 = *expr; + SET_UNUSED(opline->op2); + + if (CG(throw_list) != NULL) { + zend_llist_add_element(CG(throw_list), &throw_op_number); + } else { + opline->op2.u.opline_num = -1; + } +} + ZEND_API void function_add_ref(zend_function *function) { if (function->type == ZEND_USER_FUNCTION) { @@ -1778,6 +1860,7 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) opline->extended_value = ZEND_DO_FCALL; SET_UNUSED(opline->op2); + // FIXME: exception support not added to this op2 opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DO_FCALL; opline->result.u.var = get_temporary_variable(CG(active_op_array)); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 914c7d458d..658dfed51e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -48,6 +48,7 @@ typedef struct _zend_op_array zend_op_array; typedef struct _znode { int op_type; + zend_llist *throw_list; // Try and save this space later on union { zval constant; @@ -280,6 +281,12 @@ void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC); void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name TSRMLS_DC); void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC); void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); + +void zend_do_try(znode *try_token CLS_DC); +void zend_do_begin_catch(znode *try_token, znode *catch_var CLS_DC); +void zend_do_end_catch(znode *try_token CLS_DC); +void zend_do_throw(znode *expr CLS_DC); + ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time); void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce); void zend_do_early_binding(TSRMLS_D); @@ -530,6 +537,9 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_SEND_VAR_NO_REF 106 +#define ZEND_CATCH 107 +#define ZEND_THROW 108 + /* end of block */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 226af584c5..5a6ea6023e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -989,6 +989,11 @@ static int zend_check_symbol(zval **pz TSRMLS_DC) opline++; \ continue; +#define RETURN_FROM_EXECUTE_LOOP() \ + free_alloca(Ts); \ + EG(in_execution) = original_in_execution; \ + return; + typedef struct _object_info { zval *ptr; } object_info; @@ -1633,11 +1638,14 @@ do_fcall_common: zend_execute(EG(active_op_array) TSRMLS_CC); if (return_value_used && !Ts[opline->result.u.var].var.ptr) { - ALLOC_ZVAL(Ts[opline->result.u.var].var.ptr); - INIT_ZVAL(*Ts[opline->result.u.var].var.ptr); + if (!EG(exception)) { + ALLOC_ZVAL(Ts[opline->result.u.var].var.ptr); + INIT_ZVAL(*Ts[opline->result.u.var].var.ptr); + } } else if (!return_value_used && Ts[opline->result.u.var].var.ptr) { zval_ptr_dtor(&Ts[opline->result.u.var].var.ptr); } + EG(opline_ptr) = &opline; EG(active_op_array) = op_array; EG(return_value_ptr_ptr)=original_return_value; @@ -1666,7 +1674,16 @@ do_fcall_common: function_state.function = (zend_function *) op_array; EG(function_state_ptr) = &function_state; zend_ptr_stack_clear_multiple(TSRMLS_C); - } + + if (EG(exception)) { + if (opline->op2.u.opline_num == -1) { + RETURN_FROM_EXECUTE_LOOP(); + } else { + opline = &op_array->opcodes[opline->op2.u.opline_num]; + continue; + } + } + } NEXT_OPCODE(); case ZEND_RETURN: { zval *retval_ptr; @@ -1703,11 +1720,43 @@ do_fcall_common: (*EG(return_value_ptr_ptr))->is_ref = 0; } } - free_alloca(Ts); - EG(in_execution) = original_in_execution; - return; + RETURN_FROM_EXECUTE_LOOP(); } break; + case ZEND_THROW: + { + zval *value; + zval *exception; + + value = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R); + + // Not sure if a complete copy is what we want here + MAKE_STD_ZVAL(exception); + *exception = *value; + if (!EG(free_op1)) { + zval_copy_ctor(exception); + } + INIT_PZVAL(exception); + EG(exception) = exception; + + if (opline->op2.u.opline_num == -1) { + RETURN_FROM_EXECUTE_LOOP(); + } else { + opline = &op_array->opcodes[opline->op2.u.opline_num]; + continue; + } + } + NEXT_OPCODE(); + case ZEND_CATCH: + // Check if this is really an exception, if not, jump over code + if (EG(exception) == NULL) { + opline = &op_array->opcodes[opline->op2.u.opline_num]; + continue; + } + zend_hash_update(EG(active_symbol_table), opline->op1.u.constant.value.str.val, + opline->op1.u.constant.value.str.len+1, &EG(exception), sizeof(zval *), (void **) NULL); + EG(exception) = NULL; + NEXT_OPCODE(); case ZEND_SEND_VAL: 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)) { @@ -2490,7 +2539,6 @@ send_by_ref: case ZEND_NOP: NEXT_OPCODE(); EMPTY_SWITCH_DEFAULT_CASE() - } } zend_error(E_ERROR, "Arrived at end of main loop which shouldn't happen"); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 714f322d0c..2a0b042e03 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -155,6 +155,8 @@ void init_executor(TSRMLS_D) #ifdef ZEND_WIN32 EG(timed_out) = 0; #endif + + EG(exception) = NULL; } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 24b1f0442e..814f65be77 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -121,6 +121,8 @@ struct _zend_compiler_globals { void *ini_parser; #endif + zend_llist *throw_list; + struct _zend_ini_parser_param *ini_parser_param; int interactive; @@ -203,6 +205,7 @@ struct _zend_executor_globals { HashTable ini_directives; zend_objects objects; + zval *exception; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 97d4181032..d02ef4f7a7 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -105,6 +105,9 @@ %token T_FUNCTION %token T_CONST %token T_RETURN +%token T_TRY +%token T_CATCH +%token T_THROW %token T_USE %token T_GLOBAL %token T_STATIC @@ -201,6 +204,9 @@ unticked_statement: | T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_cvar foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); } | T_DECLARE { zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(TSRMLS_C); } | ';' /* empty statement */ + | T_TRY { zend_do_try(&$1 CLS_CC); } '{' inner_statement_list '}' + T_CATCH '(' T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8 CLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 CLS_CC); } + | T_THROW expr ';' { zend_do_throw(&$2 CLS_CC); } | T_DELETE cvar ';' { zend_do_end_variable_parse(BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1, ZEND_UNSET_OBJ TSRMLS_CC); } ; diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 2dd310d938..096f3e2920 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -648,6 +648,18 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_RETURN; } +<ST_IN_SCRIPTING>"try" { + return T_TRY; +} + +<ST_IN_SCRIPTING>"catch" { + return T_CATCH; +} + +<ST_IN_SCRIPTING>"throw" { + return T_THROW; +} + <ST_IN_SCRIPTING>"if" { return T_IF; } |