Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

- Initial support for exceptions.

  • Loading branch information...
commit 29f5dbe10b2f31e9ec12b54faede5b4c19dd30bd 1 parent ab48027
@andigutmans andigutmans authored
View
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));
View
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 */
View
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 @@ binary_assign_op_addr: {
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 @@ binary_assign_op_addr: {
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 @@ binary_assign_op_addr: {
(*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 @@ binary_assign_op_addr: {
case ZEND_NOP:
NEXT_OPCODE();
EMPTY_SWITCH_DEFAULT_CASE()
-
}
}
zend_error(E_ERROR, "Arrived at end of main loop which shouldn't happen");
View
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;
}
View
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];
};
View
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); }
;
View
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;
}
Please sign in to comment.
Something went wrong with that request. Please try again.