Skip to content

Commit 9e60cb5

Browse files
committed
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()
1 parent 330d9f6 commit 9e60cb5

11 files changed

+674
-569
lines changed

Zend/zend_compile.c

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ void zend_init_compiler_data_structures(TSRMLS_D)
122122
CG(in_compilation) = 0;
123123
CG(start_lineno) = 0;
124124
init_compiler_declarables(TSRMLS_C);
125-
CG(throw_list) = NULL;
126125
zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC);
127126

128127
#ifdef ZEND_MULTIBYTE
@@ -1085,8 +1084,6 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
10851084

10861085
zend_stack_push(&CG(foreach_copy_stack), (void *) &switch_entry.cond, sizeof(znode));
10871086
}
1088-
function_token->throw_list = CG(throw_list);
1089-
CG(throw_list) = NULL;
10901087

10911088
if (CG(doc_comment)) {
10921089
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
10951092
}
10961093
}
10971094

1095+
void zend_do_handle_exception(TSRMLS_D)
1096+
{
1097+
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1098+
1099+
opline->opcode = ZEND_HANDLE_EXCEPTION;
1100+
SET_UNUSED(opline->op1);
1101+
SET_UNUSED(opline->op2);
1102+
}
1103+
10981104

10991105
void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
11001106
{
11011107
zend_do_extended_info(TSRMLS_C);
11021108
zend_do_return(NULL, 0 TSRMLS_CC);
1109+
zend_do_handle_exception(TSRMLS_C);
1110+
11031111
pass_two(CG(active_op_array) TSRMLS_CC);
11041112

11051113
if (CG(active_class_entry)
@@ -1115,8 +1123,6 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
11151123
/* Pop the switch and foreach seperators */
11161124
zend_stack_del_top(&CG(switch_cond_stack));
11171125
zend_stack_del_top(&CG(foreach_copy_stack));
1118-
1119-
CG(throw_list) = function_token->throw_list;
11201126
}
11211127

11221128

@@ -1358,16 +1364,6 @@ void zend_do_end_function_call(znode *function_name, znode *result, znode *argum
13581364
*result = opline->result;
13591365
SET_UNUSED(opline->op2);
13601366

1361-
/* Check how much this is really needed
1362-
opline->op2.u.constant.value.lval = is_method;
1363-
*/
1364-
if (CG(throw_list) != NULL) {
1365-
long op_number = get_next_op_number(CG(active_op_array))-1;
1366-
zend_llist_add_element(CG(throw_list), &op_number);
1367-
} else {
1368-
opline->op2.u.opline_num = -1;
1369-
}
1370-
13711367
zend_stack_del_top(&CG(function_call_stack));
13721368
opline->extended_value = argument_list->u.constant.value.lval;
13731369
}
@@ -1536,12 +1532,46 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC)
15361532
}
15371533

15381534

1535+
static int zend_add_try_element(zend_uint try_op TSRMLS_DC)
1536+
{
1537+
int try_catch_offset = CG(active_op_array)->last_try_catch++;
1538+
1539+
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);
1540+
CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
1541+
return try_catch_offset;
1542+
}
1543+
1544+
static void zend_add_catch_element(int offset, zend_uint catch_op TSRMLS_DC)
1545+
{
1546+
CG(active_op_array)->try_catch_array[offset].catch_op = catch_op;
1547+
}
1548+
1549+
1550+
void zend_do_first_catch(znode *open_parentheses TSRMLS_DC)
1551+
{
1552+
open_parentheses->u.opline_num = get_next_op_number(CG(active_op_array));
1553+
}
1554+
1555+
1556+
void zend_initialize_try_catch_element(znode *try_token TSRMLS_DC)
1557+
{
1558+
zend_add_catch_element(try_token->u.opline_num, get_next_op_number(CG(active_op_array)) TSRMLS_CC);
1559+
}
1560+
1561+
1562+
void zend_do_mark_last_catch(znode *first_catch, znode *last_additional_catch TSRMLS_DC)
1563+
{
1564+
if (last_additional_catch->u.opline_num == -1) {
1565+
CG(active_op_array)->opcodes[first_catch->u.opline_num].op1.u.EA.type = 1;
1566+
} else {
1567+
CG(active_op_array)->opcodes[last_additional_catch->u.opline_num].op1.u.EA.type = 1;
1568+
}
1569+
}
1570+
1571+
15391572
void zend_do_try(znode *try_token TSRMLS_DC)
15401573
{
1541-
try_token->throw_list = (void *) CG(throw_list);
1542-
CG(throw_list) = (zend_llist *) emalloc(sizeof(zend_llist));
1543-
zend_llist_init(CG(throw_list), sizeof(long), NULL, 0);
1544-
/* Initialize try backpatch list used to backpatch throw, do_fcall */
1574+
try_token->u.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC);
15451575
}
15461576

15471577
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,
15751605
opline->op1 = *catch_class;
15761606
/* SET_UNUSED(opline->op1); *//* FIXME: Define IS_CLASS or something like that */
15771607
opline->op2 = *catch_var;
1608+
opline->op1.u.EA.type = 0; /* 1 means it's the last catch in the block */
15781609

1579-
if (first_catch) {
1580-
zend_llist_apply_with_argument(CG(throw_list), (llist_apply_with_arg_func_t) throw_list_applier, &CG(catch_begin) TSRMLS_CC);
1581-
zend_llist_destroy(CG(throw_list));
1582-
efree(CG(throw_list));
1583-
CG(throw_list) = (void *) try_token->throw_list;
1584-
}
15851610
try_token->u.opline_num = catch_op_number;
15861611
}
15871612

@@ -1599,12 +1624,6 @@ void zend_do_throw(znode *expr TSRMLS_DC)
15991624
opline->opcode = ZEND_THROW;
16001625
opline->op1 = *expr;
16011626
SET_UNUSED(opline->op2);
1602-
1603-
if (CG(throw_list) != NULL) {
1604-
zend_llist_add_element(CG(throw_list), &throw_op_number);
1605-
} else {
1606-
opline->op2.u.opline_num = -1;
1607-
}
16081627
}
16091628

16101629
ZEND_API void function_add_ref(zend_function *function)

Zend/zend_compile.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ typedef struct _zend_op zend_op;
5252

5353
typedef struct _znode {
5454
int op_type;
55-
zend_llist *throw_list; /* Try and save this space later on */
5655
union {
5756
zval constant;
5857

@@ -69,8 +68,8 @@ typedef struct _znode {
6968

7069
typedef struct _zend_execute_data zend_execute_data;
7170

72-
#define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, zend_op_array *op_array TSRMLS_DC
73-
#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, op_array TSRMLS_CC
71+
#define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, zend_op *opline, zend_op_array *op_array TSRMLS_DC
72+
#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, opline, op_array TSRMLS_CC
7473

7574
typedef int (*opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
7675

@@ -94,6 +93,12 @@ typedef struct _zend_brk_cont_element {
9493
} zend_brk_cont_element;
9594

9695

96+
typedef struct _zend_try_catch_element {
97+
zend_uint try_op;
98+
zend_uint catch_op; /* ketchup! */
99+
} zend_try_catch_element;
100+
101+
97102
#define ZEND_ACC_STATIC 0x01
98103
#define ZEND_ACC_ABSTRACT 0x02
99104
#define ZEND_ACC_FINAL 0x04
@@ -160,6 +165,9 @@ struct _zend_op_array {
160165
zend_uint last_brk_cont;
161166
zend_uint current_brk_cont;
162167

168+
zend_try_catch_element *try_catch_array;
169+
int last_try_catch;
170+
163171
/* static variables support */
164172
HashTable *static_variables;
165173

@@ -352,6 +360,7 @@ void zend_do_fetch_class_name(znode *result, znode *class_entry, znode *class_na
352360
void zend_do_begin_class_member_function_call(TSRMLS_D);
353361
void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC);
354362
void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC);
363+
void zend_do_handle_exception(TSRMLS_D);
355364

356365
void zend_do_try(znode *try_token TSRMLS_DC);
357366
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);
483492
void print_op_array(zend_op_array *op_array, int optimizations);
484493
int pass_two(zend_op_array *op_array TSRMLS_DC);
485494
zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array);
495+
void zend_do_first_catch(znode *open_parentheses TSRMLS_DC);
496+
void zend_initialize_try_catch_element(znode *try_token TSRMLS_DC);
497+
void zend_do_mark_last_catch(znode *first_catch, znode *last_additional_catch TSRMLS_DC);
486498
ZEND_API zend_bool zend_is_compiling(TSRMLS_D);
487499
ZEND_API char *zend_make_compiled_string_description(char *name TSRMLS_DC);
488500
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);
680692

681693
#define ZEND_ISSET_ISEMPTY_PROP_OBJ 148
682694

695+
#define ZEND_HANDLE_EXCEPTION 149
696+
683697
/* end of block */
684698
/* END: OPCODES */
685699

Zend/zend_default_classes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ ZEND_API void zend_throw_exception_ex(zend_class_entry *exception_ce, long code
435435

436436
efree(message);
437437

438-
EG(exception) = ex;
438+
zend_throw_exception_internal(ex TSRMLS_CC);
439439
}
440440

441441
/* 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
465465
zend_update_property_long(default_exception_ptr, ex, "code", sizeof("code")-1, code TSRMLS_CC);
466466
}
467467

468-
EG(exception) = ex;
468+
zend_throw_exception_internal(ex TSRMLS_CC);
469469
}
470470

471471
static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...)

Zend/zend_exceptions.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ ZEND_API void zend_throw_exception_ex(zend_class_entry *exception_ce, long code
435435

436436
efree(message);
437437

438-
EG(exception) = ex;
438+
zend_throw_exception_internal(ex TSRMLS_CC);
439439
}
440440

441441
/* 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
465465
zend_update_property_long(default_exception_ptr, ex, "code", sizeof("code")-1, code TSRMLS_CC);
466466
}
467467

468-
EG(exception) = ex;
468+
zend_throw_exception_internal(ex TSRMLS_CC);
469469
}
470470

471471
static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...)

0 commit comments

Comments
 (0)