zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
}
- opline->op2_type = IS_CV;
- opline->op2.var = lookup_cv(CG(active_op_array), var_name);
+ opline->result_type = IS_CV;
+ opline->result.var = lookup_cv(CG(active_op_array), var_name);
- opline->result.num = is_last_catch && is_last_class;
+ if (is_last_catch && is_last_class) {
+ opline->extended_value = ZEND_LAST_CATCH;
+ }
if (!is_last_class) {
jmp_multicatch[j] = zend_emit_jump(0);
opline = &CG(active_op_array)->opcodes[opnum_catch];
- opline->extended_value = get_next_op_number(CG(active_op_array));
+ opline->op2.opline_num = get_next_op_number(CG(active_op_array));
}
}
opline = &CG(active_op_array)->opcodes[opnum_catch];
if (!is_last_catch) {
- opline->extended_value = get_next_op_number(CG(active_op_array));
+ opline->op2.opline_num = get_next_op_number(CG(active_op_array));
}
}
#define ZEND_FETCH_ARG_MASK 0x0fffffff
+#define ZEND_LAST_CATCH 0x00000001
+
#define ZEND_FREE_ON_RETURN (1<<0)
#define ZEND_SEND_BY_VAL 0
}
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
- case ZEND_CATCH:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
/* absolute index to relative offset */
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
+ }
+ break;
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
HANDLE_EXCEPTION();
}
-ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR)
+ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, JMP_ADDR, LAST_CATCH)
{
USE_OPLINE
zend_class_entry *ce, *catch_ce;
/* Check whether an exception has been thrown, if not, jump over code */
zend_exception_restore();
if (EG(exception) == NULL) {
- ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op2));
ZEND_VM_CONTINUE();
}
catch_ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
if (ce != catch_ce) {
if (!catch_ce || !instanceof_function(ce, catch_ce)) {
- if (opline->result.num) {
+ if (opline->extended_value == ZEND_LAST_CATCH) {
zend_rethrow_exception(execute_data);
HANDLE_EXCEPTION();
}
- ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op2));
ZEND_VM_CONTINUE();
}
}
exception = EG(exception);
- ex = EX_VAR(opline->op2.var);
+ ex = EX_VAR(opline->result.var);
if (UNEXPECTED(Z_ISREF_P(ex))) {
ex = Z_REFVAL_P(ex);
}
HANDLE_EXCEPTION();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_class_entry *ce, *catch_ce;
+ zend_object *exception;
+ zval *ex;
+
+ SAVE_OPLINE();
+ /* Check whether an exception has been thrown, if not, jump over code */
+ zend_exception_restore();
+ if (EG(exception) == NULL) {
+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_CONTINUE();
+ }
+ catch_ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
+ if (UNEXPECTED(catch_ce == NULL)) {
+ catch_ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), RT_CONSTANT(opline, opline->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);
+
+ CACHE_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)), catch_ce);
+ }
+ ce = EG(exception)->ce;
+
+#ifdef HAVE_DTRACE
+ if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
+ DTRACE_EXCEPTION_CAUGHT((char *)ce->name);
+ }
+#endif /* HAVE_DTRACE */
+
+ if (ce != catch_ce) {
+ if (!catch_ce || !instanceof_function(ce, catch_ce)) {
+ if (opline->extended_value == ZEND_LAST_CATCH) {
+ zend_rethrow_exception(execute_data);
+ HANDLE_EXCEPTION();
+ }
+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_CONTINUE();
+ }
+ }
+
+ exception = EG(exception);
+ ex = EX_VAR(opline->result.var);
+ if (UNEXPECTED(Z_ISREF_P(ex))) {
+ ex = Z_REFVAL_P(ex);
+ }
+ zval_ptr_dtor(ex);
+ ZVAL_OBJ(ex, EG(exception));
+ if (UNEXPECTED(EG(exception) != exception)) {
+ GC_ADDREF(EG(exception));
+ HANDLE_EXCEPTION();
+ } else {
+ EG(exception) = NULL;
+ ZEND_VM_NEXT_OPCODE();
+ }
+}
+
static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_VM_NEXT_OPCODE();
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
- USE_OPLINE
- zend_class_entry *ce, *catch_ce;
- zend_object *exception;
- zval *ex;
-
- SAVE_OPLINE();
- /* Check whether an exception has been thrown, if not, jump over code */
- zend_exception_restore();
- if (EG(exception) == NULL) {
- ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
- ZEND_VM_CONTINUE();
- }
- catch_ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
- if (UNEXPECTED(catch_ce == NULL)) {
- catch_ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), RT_CONSTANT(opline, opline->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);
-
- CACHE_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)), catch_ce);
- }
- ce = EG(exception)->ce;
-
-#ifdef HAVE_DTRACE
- if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
- DTRACE_EXCEPTION_CAUGHT((char *)ce->name);
- }
-#endif /* HAVE_DTRACE */
-
- if (ce != catch_ce) {
- if (!catch_ce || !instanceof_function(ce, catch_ce)) {
- if (opline->result.num) {
- zend_rethrow_exception(execute_data);
- HANDLE_EXCEPTION();
- }
- ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
- ZEND_VM_CONTINUE();
- }
- }
-
- exception = EG(exception);
- ex = EX_VAR(opline->op2.var);
- if (UNEXPECTED(Z_ISREF_P(ex))) {
- ex = Z_REFVAL_P(ex);
- }
- zval_ptr_dtor(ex);
- ZVAL_OBJ(ex, EG(exception));
- if (UNEXPECTED(EG(exception) != exception)) {
- GC_ADDREF(EG(exception));
- HANDLE_EXCEPTION();
- } else {
- EG(exception) = NULL;
- ZEND_VM_NEXT_OPCODE();
- }
-}
-
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
(void*)&&ZEND_EXT_NOP_SPEC_LABEL,
(void*)&&ZEND_TICKS_SPEC_LABEL,
(void*)&&ZEND_SEND_VAR_NO_REF_SPEC_VAR_LABEL,
- (void*)&&ZEND_CATCH_SPEC_CONST_CV_LABEL,
+ (void*)&&ZEND_CATCH_SPEC_CONST_LABEL,
(void*)&&ZEND_THROW_SPEC_CONST_LABEL,
(void*)&&ZEND_THROW_SPEC_TMP_LABEL,
(void*)&&ZEND_THROW_SPEC_VAR_LABEL,
HYBRID_CASE(ZEND_THROW_SPEC_CONST):
ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
+ HYBRID_CASE(ZEND_CATCH_SPEC_CONST):
+ ZEND_CATCH_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+ HYBRID_BREAK();
HYBRID_CASE(ZEND_SEND_VAL_SPEC_CONST):
ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
HYBRID_CASE(ZEND_INIT_USER_CALL_SPEC_CONST_CV):
ZEND_INIT_USER_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
- HYBRID_CASE(ZEND_CATCH_SPEC_CONST_CV):
- ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
- HYBRID_BREAK();
HYBRID_CASE(ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV):
ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
ZEND_EXT_NOP_SPEC_HANDLER,
ZEND_TICKS_SPEC_HANDLER,
ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER,
- ZEND_CATCH_SPEC_CONST_CV_HANDLER,
+ ZEND_CATCH_SPEC_CONST_HANDLER,
ZEND_THROW_SPEC_CONST_HANDLER,
ZEND_THROW_SPEC_TMP_HANDLER,
ZEND_THROW_SPEC_VAR_HANDLER,
"ZEND_VM_EXT_REF" => 1<<20,
"ZEND_VM_EXT_MASK" => 0x0f000000,
"ZEND_VM_EXT_NUM" => 0x01000000,
- // unused 0x2000000
+ "ZEND_VM_EXT_LAST_CATCH" => 0x02000000,
"ZEND_VM_EXT_JMP_ADDR" => 0x03000000,
"ZEND_VM_EXT_DIM_OBJ" => 0x04000000,
// unused 0x5000000
$vm_ext_decode = array(
"NUM" => ZEND_VM_EXT_NUM,
+ "LAST_CATCH" => ZEND_VM_EXT_LAST_CATCH,
"JMP_ADDR" => ZEND_VM_EXT_JMP_ADDR,
"DIM_OBJ" => ZEND_VM_EXT_DIM_OBJ,
"VAR_FETCH" => ZEND_VM_EXT_VAR_FETCH,
0x00000000,
0x01000000,
0x00001001,
- 0x03000103,
+ 0x02002003,
0x00000003,
0x00000771,
0x00000057,
#define ZEND_VM_EXT_REF 0x00100000
#define ZEND_VM_EXT_MASK 0x0f000000
#define ZEND_VM_EXT_NUM 0x01000000
+#define ZEND_VM_EXT_LAST_CATCH 0x02000000
#define ZEND_VM_EXT_JMP_ADDR 0x03000000
#define ZEND_VM_EXT_DIM_OBJ 0x04000000
#define ZEND_VM_EXT_TYPE 0x07000000
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
break;
case ZEND_CATCH:
- if (!opline->result.var) {
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[0]].start);
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
}
break;
case ZEND_DECLARE_ANON_CLASS:
}
break;
case ZEND_CATCH:
- if (!opline->result.num) {
- if (ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) == old->start) {
- opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, dst->start);
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ if (ZEND_OP2_JMP_ADDR(opline) == op_array->opcodes + old->start) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, op_array->opcodes + dst->start);
}
}
break;
BB_START(i + 1);
break;
case ZEND_CATCH:
- if (!opline->result.num) {
- BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
}
BB_START(i + 1);
break;
block->successors[1] = j + 1;
break;
case ZEND_CATCH:
- if (!opline->result.num) {
+ if (opline->extended_value != ZEND_LAST_CATCH) {
block->successors_count = 2;
- block->successors[0] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
+ block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
block->successors[1] = j + 1;
} else {
block->successors_count = 1;
} else {
uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags);
if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) {
- if (b) {
- fprintf(stderr, " BB%d", b->successors[n++]);
- } else {
- fprintf(stderr, " L%u", (uint32_t)(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes));
+ if (opline->opcode != ZEND_CATCH || opline->extended_value != ZEND_LAST_CATCH) {
+ if (b) {
+ fprintf(stderr, " BB%d", b->successors[n++]);
+ } else {
+ fprintf(stderr, " L%u", (uint32_t)(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes));
+ }
}
} else {
zend_dump_unused_op(opline, opline->op2, op2_flags);
}
if (ZEND_VM_EXT_JMP_ADDR == (flags & ZEND_VM_EXT_MASK)) {
- if (opline->opcode != ZEND_CATCH || !opline->result.num) {
- if (b) {
- fprintf(stderr, " BB%d", b->successors[n++]);
- } else {
- fprintf(stderr, " L%u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
- }
+ if (b) {
+ fprintf(stderr, " BB%d", b->successors[n++]);
+ } else {
+ fprintf(stderr, " L%u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
}
}
if (opline->result_type == IS_CONST) {
case ZEND_ASSERT_CHECK:
ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
break;
- case ZEND_CATCH:
- if (!opline->result.num) {
- new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
- }
- break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
+ }
+ break;
case ZEND_SWITCH_LONG:
case ZEND_SWITCH_STRING:
{
case ZEND_ASSERT_CHECK:
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
+ }
+ break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
- case ZEND_CATCH:
opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
break;
case ZEND_SWITCH_LONG:
case ZEND_ASSERT_CHECK:
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ }
+ break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_ASSERT_CHECK:
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ }
+ break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_ASSERT_CHECK:
SERIALIZE_PTR(opline->op2.jmp_addr);
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ SERIALIZE_PTR(opline->op2.jmp_addr);
+ }
+ break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_ASSERT_CHECK:
UNSERIALIZE_PTR(opline->op2.jmp_addr);
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ UNSERIALIZE_PTR(opline->op2.jmp_addr);
+ }
+ break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
case ZEND_ASSERT_CHECK:
opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
break;
+ case ZEND_CATCH:
+ if (opline->extended_value != ZEND_LAST_CATCH) {
+ opline->op2.jmp_addr = &new_opcodes[opline->op2.jmp_addr - op_array->opcodes];
+ }
+ break;
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
case ZEND_FE_FETCH_R:
/* RESULT */
switch (opline->opcode) {
case ZEND_CATCH:
- spprintf(&decode[3], 0, "%" PRIu32, opline->result.num);
+ if (opline->extended_value == ZEND_LAST_CATCH) {
+ if (decode[2]) {
+ efree(decode[2]);
+ decode[2] = NULL;
+ }
+ }
+ decode[3] = phpdbg_decode_op(ops, opline, &opline->result, opline->result_type);
break;
default:
decode[3] = phpdbg_decode_op(ops, opline, &opline->result, opline->result_type);
return 1;
}
- do {
+ cur = &op_array->opcodes[catch];
+ while (1) {
zend_class_entry *ce;
- cur = &op_array->opcodes[catch];
if (!(ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(cur, cur->op1))))) {
ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(cur, cur->op1)), RT_CONSTANT(cur, cur->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);
return 1;
}
- catch += cur->extended_value / sizeof(zend_op);
- } while (!cur->result.num);
+ if (cur->extended_value == ZEND_LAST_CATCH) {
+ return 0;
+ }
+
+ cur = OP_JMP_ADDR(cur, cur->op2);
+ }
return 0;
}
00009: } catch (Error $e) {
prompt> ok
[L7 %s FAST_RET ~%d try-catch(0) %s]
-[L9 %s CATCH<-%d> "Error" $e 1 %s]
+[L9 %s CATCH<1> "Error" $e %s]
>00005: x();
00006: } finally {
00007: print "ok\n";
00005: }
00006:
prompt> [L0 %s HANDLE_EXCEPTION %s]
-[L9 %s CATCH<-%d> "Exception" $e 1 %s]
+[L9 %s CATCH<1> "Exception" $e %s]
>00008: foo();
00009: } catch (Exception $e) {
00010: echo "ok";