@@ -41,13 +41,21 @@ typedef struct iseq_link_anchor {
41
41
LINK_ELEMENT * last ;
42
42
} LINK_ANCHOR ;
43
43
44
+ typedef enum {
45
+ LABEL_RESCUE_NONE ,
46
+ LABEL_RESCUE_BEG ,
47
+ LABEL_RESCUE_END ,
48
+ LABEL_RESCUE_TYPE_MAX
49
+ } LABEL_RESCUE_TYPE ;
50
+
44
51
typedef struct iseq_label_data {
45
52
LINK_ELEMENT link ;
46
53
int label_no ;
47
54
int position ;
48
55
int sc_state ;
49
56
int set ;
50
57
int sp ;
58
+ unsigned int rescued : 2 ;
51
59
} LABEL ;
52
60
53
61
typedef struct iseq_insn_data {
@@ -497,6 +505,9 @@ rb_iseq_compile_node(VALUE self, NODE *node)
497
505
LABEL * start = iseq -> compile_data -> start_label = NEW_LABEL (0 );
498
506
LABEL * end = iseq -> compile_data -> end_label = NEW_LABEL (0 );
499
507
508
+ start -> rescued = LABEL_RESCUE_BEG ;
509
+ end -> rescued = LABEL_RESCUE_END ;
510
+
500
511
ADD_TRACE (ret , FIX2INT (iseq -> location .first_lineno ), RUBY_EVENT_B_CALL );
501
512
ADD_LABEL (ret , start );
502
513
COMPILE (ret , "block body" , node -> nd_body );
@@ -2038,20 +2049,37 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
2038
2049
return COMPILE_OK ;
2039
2050
}
2040
2051
2052
+ static inline int
2053
+ tailcallable_p (rb_iseq_t * iseq )
2054
+ {
2055
+ switch (iseq -> type ) {
2056
+ case ISEQ_TYPE_RESCUE :
2057
+ case ISEQ_TYPE_ENSURE :
2058
+ /* rescue block can't tail call because of errinfo */
2059
+ return FALSE;
2060
+ default :
2061
+ return TRUE;
2062
+ }
2063
+ }
2064
+
2041
2065
static int
2042
2066
iseq_optimize (rb_iseq_t * iseq , LINK_ANCHOR * anchor )
2043
2067
{
2044
2068
LINK_ELEMENT * list ;
2045
2069
const int do_peepholeopt = iseq -> compile_data -> option -> peephole_optimization ;
2046
- const int do_tailcallopt = iseq -> compile_data -> option -> tailcall_optimization ;
2070
+ const int do_tailcallopt = tailcallable_p (iseq ) &&
2071
+ iseq -> compile_data -> option -> tailcall_optimization ;
2047
2072
const int do_si = iseq -> compile_data -> option -> specialized_instruction ;
2048
2073
const int do_ou = iseq -> compile_data -> option -> operands_unification ;
2074
+ int rescue_level = 0 ;
2075
+ int tailcallopt = do_tailcallopt ;
2076
+
2049
2077
list = FIRST_ELEMENT (anchor );
2050
2078
2051
2079
while (list ) {
2052
2080
if (list -> type == ISEQ_ELEMENT_INSN ) {
2053
2081
if (do_peepholeopt ) {
2054
- iseq_peephole_optimize (iseq , list , do_tailcallopt );
2082
+ iseq_peephole_optimize (iseq , list , tailcallopt );
2055
2083
}
2056
2084
if (do_si ) {
2057
2085
iseq_specialized_instruction (iseq , (INSN * )list );
@@ -2060,6 +2088,17 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
2060
2088
insn_operands_unification ((INSN * )list );
2061
2089
}
2062
2090
}
2091
+ if (list -> type == ISEQ_ELEMENT_LABEL ) {
2092
+ switch (((LABEL * )list )-> rescued ) {
2093
+ case LABEL_RESCUE_BEG :
2094
+ rescue_level ++ ;
2095
+ tailcallopt = FALSE;
2096
+ break ;
2097
+ case LABEL_RESCUE_END :
2098
+ if (!-- rescue_level ) tailcallopt = do_tailcallopt ;
2099
+ break ;
2100
+ }
2101
+ }
2063
2102
list = list -> next ;
2064
2103
}
2065
2104
return COMPILE_OK ;
@@ -3108,6 +3147,8 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
3108
3147
("defined guard in " ),
3109
3148
iseq -> location .label ),
3110
3149
ISEQ_TYPE_DEFINED_GUARD , 0 );
3150
+ lstart -> rescued = LABEL_RESCUE_BEG ;
3151
+ lend -> rescued = LABEL_RESCUE_END ;
3111
3152
APPEND_LABEL (ret , lcur , lstart );
3112
3153
ADD_LABEL (ret , lend );
3113
3154
ADD_CATCH_ENTRY (CATCH_TYPE_RESCUE , lstart , lend , rescue , lfinish [1 ]);
@@ -3878,6 +3919,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
3878
3919
rb_str_concat (rb_str_new2 ("rescue in " ), iseq -> location .label ),
3879
3920
ISEQ_TYPE_RESCUE , line );
3880
3921
3922
+ lstart -> rescued = LABEL_RESCUE_BEG ;
3923
+ lend -> rescued = LABEL_RESCUE_END ;
3881
3924
ADD_LABEL (ret , lstart );
3882
3925
COMPILE (ret , "rescue head" , node -> nd_head );
3883
3926
ADD_LABEL (ret , lend );
0 commit comments