Browse Source

- Initial support for exceptions.

experimental/apache_hooks
Andi Gutmans 25 years ago
parent
commit
29f5dbe10b
  1. 85
      Zend/zend_compile.c
  2. 10
      Zend/zend_compile.h
  3. 62
      Zend/zend_execute.c
  4. 2
      Zend/zend_execute_API.c
  5. 3
      Zend/zend_globals.h
  6. 6
      Zend/zend_language_parser.y
  7. 12
      Zend/zend_language_scanner.l

85
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));

10
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 */

62
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");

2
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;
}

3
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];
};

6
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); }
;

12
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;
}

Loading…
Cancel
Save