mirror of
https://github.com/php/php-src.git
synced 2024-11-23 09:54:15 +08:00
Rewrote exception support. Fixes a few limitations and bugs in the old
implementation, and allows exceptions to 'fire' much earlier than before. Instructions on how to use the new mechanism will follow on internals@ shortly... Note - this (most probably) breaks the current implementation of set_exception_handler()
This commit is contained in:
parent
330d9f6352
commit
9e60cb553f
@ -122,7 +122,6 @@ void zend_init_compiler_data_structures(TSRMLS_D)
|
||||
CG(in_compilation) = 0;
|
||||
CG(start_lineno) = 0;
|
||||
init_compiler_declarables(TSRMLS_C);
|
||||
CG(throw_list) = NULL;
|
||||
zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC);
|
||||
|
||||
#ifdef ZEND_MULTIBYTE
|
||||
@ -1085,8 +1084,6 @@ 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;
|
||||
|
||||
if (CG(doc_comment)) {
|
||||
CG(active_op_array)->doc_comment = estrndup(CG(doc_comment), CG(doc_comment_len));
|
||||
@ -1095,11 +1092,22 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
|
||||
}
|
||||
}
|
||||
|
||||
void zend_do_handle_exception(TSRMLS_D)
|
||||
{
|
||||
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
|
||||
opline->opcode = ZEND_HANDLE_EXCEPTION;
|
||||
SET_UNUSED(opline->op1);
|
||||
SET_UNUSED(opline->op2);
|
||||
}
|
||||
|
||||
|
||||
void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
|
||||
{
|
||||
zend_do_extended_info(TSRMLS_C);
|
||||
zend_do_return(NULL, 0 TSRMLS_CC);
|
||||
zend_do_handle_exception(TSRMLS_C);
|
||||
|
||||
pass_two(CG(active_op_array) TSRMLS_CC);
|
||||
|
||||
if (CG(active_class_entry)
|
||||
@ -1115,8 +1123,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@ -1358,16 +1364,6 @@ void zend_do_end_function_call(znode *function_name, znode *result, znode *argum
|
||||
*result = opline->result;
|
||||
SET_UNUSED(opline->op2);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@ -1536,12 +1532,46 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC)
|
||||
}
|
||||
|
||||
|
||||
static int zend_add_try_element(zend_uint try_op TSRMLS_DC)
|
||||
{
|
||||
int try_catch_offset = CG(active_op_array)->last_try_catch++;
|
||||
|
||||
CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch);
|
||||
CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
|
||||
return try_catch_offset;
|
||||
}
|
||||
|
||||
static void zend_add_catch_element(int offset, zend_uint catch_op TSRMLS_DC)
|
||||
{
|
||||
CG(active_op_array)->try_catch_array[offset].catch_op = catch_op;
|
||||
}
|
||||
|
||||
|
||||
void zend_do_first_catch(znode *open_parentheses TSRMLS_DC)
|
||||
{
|
||||
open_parentheses->u.opline_num = get_next_op_number(CG(active_op_array));
|
||||
}
|
||||
|
||||
|
||||
void zend_initialize_try_catch_element(znode *try_token TSRMLS_DC)
|
||||
{
|
||||
zend_add_catch_element(try_token->u.opline_num, get_next_op_number(CG(active_op_array)) TSRMLS_CC);
|
||||
}
|
||||
|
||||
|
||||
void zend_do_mark_last_catch(znode *first_catch, znode *last_additional_catch TSRMLS_DC)
|
||||
{
|
||||
if (last_additional_catch->u.opline_num == -1) {
|
||||
CG(active_op_array)->opcodes[first_catch->u.opline_num].op1.u.EA.type = 1;
|
||||
} else {
|
||||
CG(active_op_array)->opcodes[last_additional_catch->u.opline_num].op1.u.EA.type = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void zend_do_try(znode *try_token TSRMLS_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 */
|
||||
try_token->u.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void throw_list_applier(long *opline_num, long *catch_opline)
|
||||
@ -1575,13 +1605,8 @@ void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var,
|
||||
opline->op1 = *catch_class;
|
||||
/* SET_UNUSED(opline->op1); *//* FIXME: Define IS_CLASS or something like that */
|
||||
opline->op2 = *catch_var;
|
||||
opline->op1.u.EA.type = 0; /* 1 means it's the last catch in the block */
|
||||
|
||||
if (first_catch) {
|
||||
zend_llist_apply_with_argument(CG(throw_list), (llist_apply_with_arg_func_t) throw_list_applier, &CG(catch_begin) TSRMLS_CC);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1599,12 +1624,6 @@ void zend_do_throw(znode *expr TSRMLS_DC)
|
||||
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)
|
||||
|
@ -52,7 +52,6 @@ typedef struct _zend_op zend_op;
|
||||
|
||||
typedef struct _znode {
|
||||
int op_type;
|
||||
zend_llist *throw_list; /* Try and save this space later on */
|
||||
union {
|
||||
zval constant;
|
||||
|
||||
@ -69,8 +68,8 @@ typedef struct _znode {
|
||||
|
||||
typedef struct _zend_execute_data zend_execute_data;
|
||||
|
||||
#define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, zend_op_array *op_array TSRMLS_DC
|
||||
#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, op_array TSRMLS_CC
|
||||
#define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, zend_op *opline, zend_op_array *op_array TSRMLS_DC
|
||||
#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, opline, op_array TSRMLS_CC
|
||||
|
||||
typedef int (*opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
|
||||
|
||||
@ -94,6 +93,12 @@ typedef struct _zend_brk_cont_element {
|
||||
} zend_brk_cont_element;
|
||||
|
||||
|
||||
typedef struct _zend_try_catch_element {
|
||||
zend_uint try_op;
|
||||
zend_uint catch_op; /* ketchup! */
|
||||
} zend_try_catch_element;
|
||||
|
||||
|
||||
#define ZEND_ACC_STATIC 0x01
|
||||
#define ZEND_ACC_ABSTRACT 0x02
|
||||
#define ZEND_ACC_FINAL 0x04
|
||||
@ -160,6 +165,9 @@ struct _zend_op_array {
|
||||
zend_uint last_brk_cont;
|
||||
zend_uint current_brk_cont;
|
||||
|
||||
zend_try_catch_element *try_catch_array;
|
||||
int last_try_catch;
|
||||
|
||||
/* static variables support */
|
||||
HashTable *static_variables;
|
||||
|
||||
@ -352,6 +360,7 @@ void zend_do_fetch_class_name(znode *result, znode *class_entry, znode *class_na
|
||||
void zend_do_begin_class_member_function_call(TSRMLS_D);
|
||||
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_handle_exception(TSRMLS_D);
|
||||
|
||||
void zend_do_try(znode *try_token TSRMLS_DC);
|
||||
void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, zend_bool first_catch TSRMLS_DC);
|
||||
@ -483,6 +492,9 @@ int print_class(zend_class_entry *class_entry TSRMLS_DC);
|
||||
void print_op_array(zend_op_array *op_array, int optimizations);
|
||||
int pass_two(zend_op_array *op_array TSRMLS_DC);
|
||||
zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array);
|
||||
void zend_do_first_catch(znode *open_parentheses TSRMLS_DC);
|
||||
void zend_initialize_try_catch_element(znode *try_token TSRMLS_DC);
|
||||
void zend_do_mark_last_catch(znode *first_catch, znode *last_additional_catch TSRMLS_DC);
|
||||
ZEND_API zend_bool zend_is_compiling(TSRMLS_D);
|
||||
ZEND_API char *zend_make_compiled_string_description(char *name TSRMLS_DC);
|
||||
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC);
|
||||
@ -680,6 +692,8 @@ int zendlex(znode *zendlval TSRMLS_DC);
|
||||
|
||||
#define ZEND_ISSET_ISEMPTY_PROP_OBJ 148
|
||||
|
||||
#define ZEND_HANDLE_EXCEPTION 149
|
||||
|
||||
/* end of block */
|
||||
/* END: OPCODES */
|
||||
|
||||
|
@ -435,7 +435,7 @@ ZEND_API void zend_throw_exception_ex(zend_class_entry *exception_ce, long code
|
||||
|
||||
efree(message);
|
||||
|
||||
EG(exception) = ex;
|
||||
zend_throw_exception_internal(ex TSRMLS_CC);
|
||||
}
|
||||
|
||||
/* at the moment we can't use zend_throw_exception_ex because we don't have a protable
|
||||
@ -465,7 +465,7 @@ ZEND_API void zend_throw_exception(zend_class_entry *exception_ce, char *message
|
||||
zend_update_property_long(default_exception_ptr, ex, "code", sizeof("code")-1, code TSRMLS_CC);
|
||||
}
|
||||
|
||||
EG(exception) = ex;
|
||||
zend_throw_exception_internal(ex TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...)
|
||||
|
@ -435,7 +435,7 @@ ZEND_API void zend_throw_exception_ex(zend_class_entry *exception_ce, long code
|
||||
|
||||
efree(message);
|
||||
|
||||
EG(exception) = ex;
|
||||
zend_throw_exception_internal(ex TSRMLS_CC);
|
||||
}
|
||||
|
||||
/* at the moment we can't use zend_throw_exception_ex because we don't have a protable
|
||||
@ -465,7 +465,7 @@ ZEND_API void zend_throw_exception(zend_class_entry *exception_ce, char *message
|
||||
zend_update_property_long(default_exception_ptr, ex, "code", sizeof("code")-1, code TSRMLS_CC);
|
||||
}
|
||||
|
||||
EG(exception) = ex;
|
||||
zend_throw_exception_internal(ex TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...)
|
||||
|
1070
Zend/zend_execute.c
1070
Zend/zend_execute.c
File diff suppressed because it is too large
Load Diff
@ -143,6 +143,9 @@ ZEND_API void zend_set_timeout(long seconds);
|
||||
ZEND_API void zend_unset_timeout(TSRMLS_D);
|
||||
ZEND_API void zend_timeout(int dummy);
|
||||
ZEND_API zend_class_entry *zend_fetch_class(char *class_name, uint class_name_len, int fetch_type TSRMLS_DC);
|
||||
void zend_throw_exception_internal(zval *exception TSRMLS_DC);
|
||||
ZEND_API void zend_clear_exception(TSRMLS_D);
|
||||
|
||||
|
||||
#ifdef ZEND_WIN32
|
||||
void zend_init_timeout_thread();
|
||||
|
@ -783,6 +783,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
||||
EG(scope) = current_scope;
|
||||
EG(This) = current_this;
|
||||
EG(current_execute_data) = EX(prev_execute_data);
|
||||
|
||||
if (EG(exception)) {
|
||||
zend_throw_exception_internal(NULL TSRMLS_CC);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@ -1188,6 +1192,38 @@ check_fetch_type:
|
||||
return *pce;
|
||||
}
|
||||
|
||||
void zend_throw_exception_internal(zval *exception TSRMLS_DC)
|
||||
{
|
||||
if (exception != NULL) {
|
||||
if (EG(exception)) {
|
||||
/* FIXME: bail out? */
|
||||
return;
|
||||
}
|
||||
EG(exception) = exception;
|
||||
}
|
||||
if ((EG(current_execute_data)->opline+1)->opcode == ZEND_HANDLE_EXCEPTION) {
|
||||
/* no need to rethrow the exception */
|
||||
return;
|
||||
}
|
||||
EG(opline_before_exception) = EG(current_execute_data)->opline;
|
||||
EG(current_execute_data)->opline = &EG(active_op_array)->opcodes[EG(active_op_array)->last-1-1];
|
||||
}
|
||||
|
||||
|
||||
ZEND_API void zend_clear_exception(TSRMLS_D)
|
||||
{
|
||||
if (!EG(exception)) {
|
||||
return;
|
||||
}
|
||||
zval_ptr_dtor(&EG(exception));
|
||||
EG(exception) = NULL;
|
||||
EG(current_execute_data)->opline = EG(opline_before_exception);
|
||||
#if ZEND_DEBUG
|
||||
EG(opline_before_exception) = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
@ -115,7 +115,6 @@ struct _zend_compiler_globals {
|
||||
|
||||
zend_llist open_files;
|
||||
|
||||
zend_llist *throw_list;
|
||||
long catch_begin;
|
||||
|
||||
struct _zend_ini_parser_param *ini_parser_param;
|
||||
@ -229,9 +228,11 @@ struct _zend_executor_globals {
|
||||
HashTable *ini_directives;
|
||||
zend_objects_store objects_store;
|
||||
zval *exception;
|
||||
zend_op *opline_before_exception;
|
||||
|
||||
struct _zend_execute_data *current_execute_data;
|
||||
|
||||
|
||||
zend_property_info std_property_info;
|
||||
|
||||
/* locale stuff */
|
||||
|
@ -212,20 +212,23 @@ unticked_statement:
|
||||
| T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
|
||||
| ';' /* empty statement */
|
||||
| T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
|
||||
T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
|
||||
additional_catches
|
||||
T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); }
|
||||
fully_qualified_class_name { zend_do_first_catch(&$7 TSRMLS_CC); }
|
||||
T_VARIABLE ')' { zend_do_begin_catch(&$1, &$9, &$11, 1 TSRMLS_CC); }
|
||||
'{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
|
||||
additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); }
|
||||
| T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
|
||||
;
|
||||
|
||||
|
||||
additional_catches:
|
||||
non_empty_additional_catches
|
||||
| /* empty */
|
||||
non_empty_additional_catches { $$ = $1; }
|
||||
| /* empty */ { $$.u.opline_num = -1; }
|
||||
;
|
||||
|
||||
non_empty_additional_catches:
|
||||
non_empty_additional_catches T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
|
||||
| T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
|
||||
non_empty_additional_catches T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$6, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
|
||||
| T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
|
||||
;
|
||||
|
||||
|
||||
|
@ -365,6 +365,7 @@ ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSR
|
||||
CG(active_op_array) = op_array;
|
||||
compiler_result = zendparse(TSRMLS_C);
|
||||
zend_do_return(&retval_znode, 0 TSRMLS_CC);
|
||||
zend_do_handle_exception(TSRMLS_C);
|
||||
CG(in_compilation) = original_in_compilation;
|
||||
if (compiler_result==1) { /* parser error */
|
||||
CG(unclean_shutdown) = 1;
|
||||
@ -529,6 +530,7 @@ zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC)
|
||||
retval = NULL;
|
||||
} else {
|
||||
zend_do_return(NULL, 0 TSRMLS_CC);
|
||||
zend_do_handle_exception(TSRMLS_C);
|
||||
CG(active_op_array) = original_active_op_array;
|
||||
pass_two(op_array TSRMLS_CC);
|
||||
retval = op_array;
|
||||
|
@ -83,10 +83,12 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
|
||||
op_array->scope = NULL;
|
||||
|
||||
op_array->brk_cont_array = NULL;
|
||||
op_array->try_catch_array = NULL;
|
||||
op_array->last_brk_cont = 0;
|
||||
op_array->current_brk_cont = -1;
|
||||
|
||||
op_array->static_variables = NULL;
|
||||
op_array->last_try_catch = 0;
|
||||
|
||||
op_array->return_reference = 0;
|
||||
op_array->done_pass_two = 0;
|
||||
@ -229,6 +231,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
|
||||
if (op_array->brk_cont_array) {
|
||||
efree(op_array->brk_cont_array);
|
||||
}
|
||||
if (op_array->try_catch_array) {
|
||||
efree(op_array->try_catch_array);
|
||||
}
|
||||
if (op_array->done_pass_two) {
|
||||
zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user