2 * seq-points.c: Sequence Points functions
5 * Marcos Henrich (marcos.henrich@xamarin.com)
7 * Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #include "seq-points.h"
15 insert_pred_seq_point (MonoInst
*last_seq_ins
, MonoInst
*ins
, GSList
**next
)
18 int src_index
= last_seq_ins
->backend
.size
;
19 int dst_index
= ins
->backend
.size
;
21 /* bb->in_bb might contain duplicates */
22 for (l
= next
[src_index
]; l
; l
= l
->next
)
23 if (GPOINTER_TO_UINT (l
->data
) == dst_index
)
26 next
[src_index
] = g_slist_append (next
[src_index
], GUINT_TO_POINTER (dst_index
));
30 recursively_make_pred_seq_points (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
32 const gpointer MONO_SEQ_SEEN_LOOP
= GINT_TO_POINTER(-1);
34 GArray
*predecessors
= g_array_new (FALSE
, TRUE
, sizeof (gpointer
));
35 GHashTable
*seen
= g_hash_table_new_full (g_direct_hash
, NULL
, NULL
, NULL
);
37 // Insert/remove sentinel into the memoize table to detect loops containing bb
38 bb
->pred_seq_points
= MONO_SEQ_SEEN_LOOP
;
40 for (int i
= 0; i
< bb
->in_count
; ++i
) {
41 MonoBasicBlock
*in_bb
= bb
->in_bb
[i
];
43 // This bb has the last seq point, append it and continue
44 if (in_bb
->last_seq_point
!= NULL
) {
45 predecessors
= g_array_append_val (predecessors
, in_bb
->last_seq_point
);
49 // We've looped or handled this before, exit early.
50 // No last sequence points to find.
51 if (in_bb
->pred_seq_points
== MONO_SEQ_SEEN_LOOP
)
54 // Take sequence points from incoming basic blocks
56 if (in_bb
== cfg
->bb_entry
)
59 if (in_bb
->pred_seq_points
== NULL
)
60 recursively_make_pred_seq_points (cfg
, in_bb
);
62 // Union sequence points with incoming bb's
63 for (int i
=0; i
< in_bb
->num_pred_seq_points
; i
++) {
64 if (!g_hash_table_lookup (seen
, in_bb
->pred_seq_points
[i
])) {
65 g_array_append_val (predecessors
, in_bb
->pred_seq_points
[i
]);
66 g_hash_table_insert (seen
, in_bb
->pred_seq_points
[i
], (gpointer
)&MONO_SEQ_SEEN_LOOP
);
69 // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
72 g_hash_table_destroy (seen
);
74 if (predecessors
->len
!= 0) {
75 bb
->pred_seq_points
= (MonoInst
**)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * predecessors
->len
);
76 bb
->num_pred_seq_points
= predecessors
->len
;
78 for (int newer
= 0; newer
< bb
->num_pred_seq_points
; newer
++) {
79 bb
->pred_seq_points
[newer
] = g_array_index(predecessors
, gpointer
, newer
);
83 g_free (predecessors
);
87 collect_pred_seq_points (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
*ins
, GSList
**next
)
89 // Doesn't have a last sequence point, must find from incoming basic blocks
90 if (bb
->pred_seq_points
== NULL
&& bb
!= cfg
->bb_entry
)
91 recursively_make_pred_seq_points (cfg
, bb
);
93 for (int i
= 0; i
< bb
->num_pred_seq_points
; i
++)
94 insert_pred_seq_point (bb
->pred_seq_points
[i
], ins
, next
);
100 mono_save_seq_point_info (MonoCompile
*cfg
)
103 GSList
*bb_seq_points
, *l
;
105 MonoDomain
*domain
= cfg
->domain
;
106 int i
, seq_info_size
;
107 GSList
**next
= NULL
;
108 SeqPoint
* seq_points
;
110 gboolean has_debug_data
= cfg
->gen_sdb_seq_points
;
112 if (!cfg
->seq_points
)
115 seq_points
= g_new0 (SeqPoint
, cfg
->seq_points
->len
);
117 for (i
= 0; i
< cfg
->seq_points
->len
; ++i
) {
118 SeqPoint
*sp
= &seq_points
[i
];
119 MonoInst
*ins
= (MonoInst
*)g_ptr_array_index (cfg
->seq_points
, i
);
121 sp
->il_offset
= ins
->inst_imm
;
122 sp
->native_offset
= ins
->inst_offset
;
123 if (ins
->flags
& MONO_INST_NONEMPTY_STACK
)
124 sp
->flags
|= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
;
127 ins
->backend
.size
= i
;
130 if (has_debug_data
) {
132 * For each sequence point, compute the list of sequence points immediately
133 * following it, this is needed to implement 'step over' in the debugger agent.
135 next
= g_new0 (GSList
*, cfg
->seq_points
->len
);
136 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
137 bb_seq_points
= g_slist_reverse (bb
->seq_points
);
139 for (l
= bb_seq_points
; l
; l
= l
->next
) {
140 MonoInst
*ins
= (MonoInst
*)l
->data
;
142 if (ins
->inst_imm
== METHOD_ENTRY_IL_OFFSET
|| ins
->inst_imm
== METHOD_EXIT_IL_OFFSET
)
143 /* Used to implement method entry/exit events */
145 if (ins
->inst_offset
== SEQ_POINT_NATIVE_OFFSET_DEAD_CODE
)
149 /* Link with the previous seq point in the same bb */
150 next
[last
->backend
.size
] = g_slist_append (next
[last
->backend
.size
], GUINT_TO_POINTER (ins
->backend
.size
));
152 /* Link with the last bb in the previous bblocks */
153 collect_pred_seq_points (cfg
, bb
, ins
, next
);
159 /* The second case handles endfinally opcodes which are in a separate bb by themselves */
160 if ((bb
->last_ins
&& bb
->last_ins
->opcode
== OP_ENDFINALLY
&& bb
->seq_points
) || (bb
->out_count
== 1 && bb
->out_bb
[0]->code
&& bb
->out_bb
[0]->code
->opcode
== OP_ENDFINALLY
)) {
162 MonoInst
*endfinally_seq_point
= NULL
;
165 * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
167 l
= g_slist_last (bb
->seq_points
);
169 endfinally_seq_point
= (MonoInst
*)l
->data
;
171 for (bb2
= cfg
->bb_entry
; bb2
; bb2
= bb2
->next_bb
) {
172 GSList
*l
= g_slist_last (bb2
->seq_points
);
175 MonoInst
*ins
= (MonoInst
*)l
->data
;
177 if (!(ins
->inst_imm
== METHOD_ENTRY_IL_OFFSET
|| ins
->inst_imm
== METHOD_EXIT_IL_OFFSET
) && ins
!= endfinally_seq_point
)
178 next
[endfinally_seq_point
->backend
.size
] = g_slist_append (next
[endfinally_seq_point
->backend
.size
], GUINT_TO_POINTER (ins
->backend
.size
));
185 if (cfg
->verbose_level
> 2) {
186 printf ("\nSEQ POINT MAP: \n");
188 for (i
= 0; i
< cfg
->seq_points
->len
; ++i
) {
189 SeqPoint
*sp
= &seq_points
[i
];
195 printf ("\tIL0x%x[0x%0x] ->", sp
->il_offset
, sp
->native_offset
);
196 for (l
= next
[i
]; l
; l
= l
->next
) {
197 int next_index
= GPOINTER_TO_UINT (l
->data
);
198 printf (" IL0x%x", seq_points
[next_index
].il_offset
);
205 array
= g_byte_array_new ();
207 { /* Add sequence points to seq_point_info */
208 SeqPoint zero_seq_point
= {0};
209 SeqPoint
* last_seq_point
= &zero_seq_point
;
211 for (i
= 0; i
< cfg
->seq_points
->len
; ++i
) {
212 SeqPoint
*sp
= &seq_points
[i
];
213 GSList
* next_list
= NULL
;
218 if (mono_seq_point_info_add_seq_point (array
, sp
, last_seq_point
, next_list
, has_debug_data
))
222 g_slist_free (next
[i
]);
229 cfg
->seq_point_info
= mono_seq_point_info_new (array
->len
, TRUE
, array
->data
, has_debug_data
, &seq_info_size
);
230 mono_jit_stats
.allocated_seq_points_size
+= seq_info_size
;
232 g_byte_array_free (array
, TRUE
);
234 // FIXME: dynamic methods
235 if (!cfg
->compile_aot
) {
236 mono_domain_lock (domain
);
237 // FIXME: How can the lookup succeed ?
238 if (!g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, cfg
->method_to_register
))
239 g_hash_table_insert (domain_jit_info (domain
)->seq_points
, cfg
->method_to_register
, cfg
->seq_point_info
);
240 mono_domain_unlock (domain
);
243 g_ptr_array_free (cfg
->seq_points
, TRUE
);
244 cfg
->seq_points
= NULL
;
248 mono_get_seq_points (MonoDomain
*domain
, MonoMethod
*method
)
250 MonoSeqPointInfo
*seq_points
;
251 MonoMethod
*declaring_generic_method
= NULL
, *shared_method
= NULL
;
253 if (method
->is_inflated
) {
254 declaring_generic_method
= mono_method_get_declaring_generic_method (method
);
255 shared_method
= mini_get_shared_method (method
);
259 seq_points
= (MonoSeqPointInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
260 if (!seq_points
&& method
->is_inflated
) {
261 /* generic sharing + aot */
262 seq_points
= (MonoSeqPointInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, declaring_generic_method
);
264 seq_points
= (MonoSeqPointInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, shared_method
);
266 mono_loader_unlock ();
272 * mono_find_next_seq_point_for_native_offset:
274 * Find the first sequence point after NATIVE_OFFSET.
277 mono_find_next_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
, SeqPoint
* seq_point
)
279 MonoSeqPointInfo
*seq_points
;
281 seq_points
= mono_get_seq_points (domain
, method
);
290 return mono_seq_point_find_next_by_native_offset (seq_points
, native_offset
, seq_point
);
294 * mono_find_prev_seq_point_for_native_offset:
296 * Find the first sequence point before NATIVE_OFFSET.
299 mono_find_prev_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
, SeqPoint
* seq_point
)
301 MonoSeqPointInfo
*seq_points
;
303 seq_points
= mono_get_seq_points (domain
, method
);
312 return mono_seq_point_find_prev_by_native_offset (seq_points
, native_offset
, seq_point
);
316 * mono_find_seq_point:
318 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
319 * should be the location of a sequence point.
322 mono_find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
, SeqPoint
*seq_point
)
324 MonoSeqPointInfo
*seq_points
;
326 seq_points
= mono_get_seq_points (domain
, method
);
335 return mono_seq_point_find_by_il_offset (seq_points
, il_offset
, seq_point
);
339 mono_bb_deduplicate_op_il_seq_points (MonoCompile
*cfg
, MonoBasicBlock
*bb
)
341 MonoInst
*ins
, *n
, *prev
;
343 MONO_BB_FOR_EACH_INS_SAFE (bb
, n
, ins
) {
344 if (ins
->opcode
!= OP_IL_SEQ_POINT
)
347 prev
= mono_inst_prev (ins
, FILTER_NOP
);
349 if (!prev
|| ins
== prev
|| prev
->opcode
!= OP_IL_SEQ_POINT
)
352 MONO_REMOVE_INS (bb
, prev
);