2 * mono-basic-block.c: Routines for parsing basic blocks from the IL stream
5 * Rodrigo Kumpera (rkumpera@novell.com)
7 * Copyright 2010 Novell, Inc (http://www.novell.com)
12 #include <mono/metadata/debug-helpers.h>
13 #include <mono/metadata/metadata-internals.h>
14 #include <mono/metadata/mono-endian.h>
15 #include <mono/metadata/mono-basic-block.h>
16 #include <mono/metadata/opcodes.h>
18 #include <mono/utils/mono-error-internals.h>
19 #include <mono/utils/mono-compiler.h>
21 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
22 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
24 #if SIZEOF_VOID_P == 4
25 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
27 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
30 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
31 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
43 dump_bb_list (MonoSimpleBasicBlock
*bb
, MonoSimpleBasicBlock
**root
, const char *msg
)
45 printf ("------- %s --- root is %x ---\n", msg
, (*root
)->start
);
48 printf ("BB start %x end %x left ", bb
->start
, bb
->end
);
50 printf ("%x", bb
->left
->start
);
56 printf ("%x", bb
->right
->start
);
62 printf ("%x", bb
->parent
->start
);
66 printf(" color %s out [", bb
->colour
== RED
? "red" : "black");
68 for (tmp
= bb
->out_bb
; tmp
; tmp
= tmp
->next
) {
69 MonoSimpleBasicBlock
*to
= tmp
->data
;
70 printf ("%x ", to
->start
);
72 printf ("] %s\n", bb
->dead
? "dead" : "alive");
80 bb_unlink (MonoSimpleBasicBlock
*from
, MonoSimpleBasicBlock
*to
)
83 from
->out_bb
= g_slist_remove (from
->out_bb
, to
);
87 bb_link (MonoSimpleBasicBlock
*from
, MonoSimpleBasicBlock
*to
)
89 if (g_slist_find (from
->out_bb
, to
))
91 from
->out_bb
= g_slist_prepend (from
->out_bb
, to
);
95 static MonoSimpleBasicBlock
*
96 bb_grandparent (MonoSimpleBasicBlock
*bb
)
98 return bb
&& bb
->parent
? bb
->parent
->parent
: NULL
;
101 static MonoSimpleBasicBlock
*
102 bb_uncle (MonoSimpleBasicBlock
*bb
)
104 MonoSimpleBasicBlock
*gp
= bb_grandparent (bb
);
107 if (bb
->parent
== gp
->left
)
113 change_node (MonoSimpleBasicBlock
*from
, MonoSimpleBasicBlock
*to
, MonoSimpleBasicBlock
**root
)
115 MonoSimpleBasicBlock
*parent
= from
->parent
;
117 if (parent
->left
== from
)
128 rotate_right (MonoSimpleBasicBlock
*parent
, MonoSimpleBasicBlock
**root
)
130 MonoSimpleBasicBlock
*bb
= parent
->left
;
132 parent
->left
= bb
->right
;
133 parent
->left
->parent
= parent
;
137 change_node (parent
, bb
, root
);
142 rotate_left (MonoSimpleBasicBlock
*bb
, MonoSimpleBasicBlock
**root
)
144 MonoSimpleBasicBlock
*other
= bb
->right
;
146 bb
->right
= other
->left
;
147 bb
->right
->parent
= bb
;
151 change_node (bb
, other
, root
);
155 /* School book implementation of a RB tree with insert then fix (which requires a parent pointer)
156 * TODO implement Sedgewick's version that doesn't require parent pointers
159 bb_insert (MonoSimpleBasicBlock
*first
, MonoSimpleBasicBlock
*bb
, MonoSimpleBasicBlock
**root
)
161 MonoSimpleBasicBlock
*parent
, *uncle
, *grandparent
;
162 int bb_start
= bb
->start
;
166 if (bb_start
< parent
->start
) {
167 if (parent
->left
== NULL
) {
171 parent
= parent
->left
;
173 if (parent
->right
== NULL
) {
177 parent
= parent
->right
;
186 if (bb
->parent
== NULL
) {
191 if (bb
->parent
->colour
== BLACK
)
194 uncle
= bb_uncle (bb
);
195 if (uncle
&& uncle
->colour
== RED
) {
196 grandparent
= bb_grandparent (bb
);
198 bb
->parent
->colour
= BLACK
;
199 uncle
->colour
= BLACK
;
200 grandparent
->colour
= RED
;
205 grandparent
= bb_grandparent (bb
);
206 if ((bb
== bb
->parent
->right
) && (bb
->parent
== grandparent
->left
)) {
207 rotate_left (bb
->parent
, root
);
209 } else if ((bb
== bb
->parent
->left
) && (bb
->parent
== grandparent
->right
)) {
210 rotate_right (bb
->parent
, root
);
214 grandparent
= bb_grandparent (bb
);
215 bb
->parent
->colour
= BLACK
;
216 grandparent
->colour
= RED
;
217 if ((bb
== bb
->parent
->left
) && (bb
->parent
== grandparent
->left
))
218 rotate_right (grandparent
, root
);
220 rotate_left (grandparent
, root
);
226 bb_idx_is_contained (MonoSimpleBasicBlock
*bb
, int target
)
228 return bb
->start
<= target
&& target
< bb
->end
;
232 * Split the basic blocks from @first at @target.
233 * @hint is a guess of a very close to the target basic block. It is probed before the RB tree as it's often possible
234 * to provide a near to exact guess (next block splits, switch branch targets, etc)
237 static MonoSimpleBasicBlock
*
238 bb_split (MonoSimpleBasicBlock
*first
, MonoSimpleBasicBlock
*hint
, MonoSimpleBasicBlock
**root
, guint target
, gboolean link_blocks
, MonoMethod
*method
, MonoError
*error
)
240 MonoSimpleBasicBlock
*res
, *bb
= first
;
242 if (bb_idx_is_contained (hint
, target
)) {
244 } else if (hint
->next
&& bb_idx_is_contained (hint
->next
, target
)) {
249 if (bb_idx_is_contained (first
, target
))
251 if (first
->start
> target
)
254 first
= first
->right
;
259 mono_error_set_not_verifiable (error
, method
, "Invalid instruction target %x", target
);
263 if (first
->start
== target
)
266 res
= g_new0 (MonoSimpleBasicBlock
, 1);
268 res
->end
= first
->end
;
269 res
->next
= first
->next
;
270 res
->out_bb
= first
->out_bb
;
273 first
->end
= res
->start
;
275 first
->out_bb
= NULL
;
278 bb_link (first
, res
);
279 bb_insert (bb
, res
, root
);
285 bb_liveness (MonoSimpleBasicBlock
*bb
)
287 GPtrArray
* mark_stack
= g_ptr_array_new ();
290 /*All function entry points (prologue, EH handler/filter) are already marked*/
293 g_ptr_array_add (mark_stack
, bb
);
297 while (mark_stack
->len
> 0) {
298 MonoSimpleBasicBlock
*block
= g_ptr_array_remove_index_fast (mark_stack
, mark_stack
->len
- 1);
301 for (tmp
= block
->out_bb
; tmp
; tmp
= tmp
->next
) {
302 MonoSimpleBasicBlock
*to
= tmp
->data
;
304 g_ptr_array_add (mark_stack
, to
);
308 g_ptr_array_free (mark_stack
, TRUE
);
311 /*This doesn't returns endfilter because it's not useful to split at its boundary.
312 Endfilter must be the last instruction of a filter clause and MS enforces this, so we can't have
316 mono_opcode_has_static_branch (int opcode
)
321 case MONO_CEE_RETHROW
:
322 case MONO_CEE_ENDFINALLY
:
330 bb_formation_il_pass (const unsigned char *start
, const unsigned char *end
, MonoSimpleBasicBlock
*bb
, MonoSimpleBasicBlock
**root
, MonoMethod
*method
, MonoError
*error
)
332 unsigned const char *ip
= start
;
334 guint cli_addr
, offset
;
335 MonoSimpleBasicBlock
*branch
, *next
, *current
;
336 const MonoOpcode
*opcode
;
341 cli_addr
= ip
- start
;
342 size
= mono_opcode_value_and_size (&ip
, end
, &value
);
344 mono_error_set_not_verifiable (error
, method
, "Invalid instruction %x", *ip
);
348 while (current
&& cli_addr
>= current
->end
)
349 current
= current
->next
;
352 opcode
= &mono_opcodes
[value
];
353 switch (opcode
->argument
) {
356 if (!mono_opcode_has_static_branch (value
) || ip
>= end
)
358 if (!(next
= bb_split (bb
, current
, root
, ip
- start
, FALSE
, method
, error
)))
361 bb_unlink (current
, next
);
364 case MonoInlineString
:
366 case MonoInlineField
:
369 case MonoShortInlineR
:
374 case MonoInlineMethod
:
376 if (value
!= MONO_CEE_JMP
|| ip
>= end
)
378 if (!(next
= bb_split (bb
, current
, root
, ip
- start
, FALSE
, method
, error
)))
381 bb_unlink (current
, next
);
388 case MonoShortInlineVar
:
389 case MonoShortInlineI
:
396 case MonoShortInlineBrTarget
:
397 case MonoInlineBrTarget
:
398 if (opcode
->argument
== MonoShortInlineBrTarget
) {
399 offset
= cli_addr
+ 2 + (signed char)ip
[1];
402 offset
= cli_addr
+ 5 + (gint32
)read32 (ip
+ 1);
406 branch
= bb_split (bb
, current
, root
, offset
, TRUE
, method
, error
);
410 /*If we splitted the current BB*/
411 if (offset
< cli_addr
&& branch
->start
> current
->start
)
414 next
= bb_split (bb
, current
, root
, ip
- start
, opcode
->flow_type
!= MONO_FLOW_BRANCH
, method
, error
);
421 bb_link (current
, branch
);
422 if (next
&& opcode
->flow_type
== MONO_FLOW_BRANCH
&& next
!= branch
) {
423 bb_unlink (current
, next
);
427 case MonoInlineSwitch
: {
428 MonoSimpleBasicBlock
*tmp
;
429 guint32 j
, n
= read32 (ip
+ 1);
432 offset
= cli_addr
+ 5 + 4 * n
;
433 if (!(next
= bb_split (bb
, current
, root
, offset
, TRUE
, method
, error
)))
436 bb_link (current
, next
);
439 for (j
= 0; j
< n
; ++j
) {
441 mono_error_set_not_verifiable (error
, method
, "Invalid switch instruction %x", cli_addr
);
444 if (!(next
= bb_split (bb
, next
, root
, offset
+ (gint32
)read32 (ip
), TRUE
, method
, error
)))
446 bb_link (current
, next
);
453 mono_error_set_not_verifiable (error
, method
, "Invalid instruction %x", *ip
);
458 mono_error_set_not_verifiable (error
, method
, "Invalid last instruction");
462 bb_formation_eh_pass (MonoMethodHeader
*header
, MonoSimpleBasicBlock
*bb
, MonoSimpleBasicBlock
**root
, MonoMethod
*method
, MonoError
*error
)
465 int end
= header
->code_size
;
466 /*We must split at all points to verify for targets in the middle of an instruction*/
467 for (i
= 0; i
< header
->num_clauses
; ++i
) {
468 MonoExceptionClause
*clause
= header
->clauses
+ i
;
469 MonoSimpleBasicBlock
*try_block
, *handler
;
471 if (!(try_block
= bb_split (bb
, bb
, root
, clause
->try_offset
, TRUE
, method
, error
)))
474 handler
= bb_split (bb
, try_block
, root
, clause
->handler_offset
, FALSE
, method
, error
);
477 handler
->dead
= FALSE
;
479 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
) {
480 MonoSimpleBasicBlock
*filter
= bb_split (bb
, try_block
, root
, clause
->data
.filter_offset
, FALSE
, method
, error
);
483 filter
->dead
= FALSE
;
486 if (clause
->try_offset
+ clause
->try_len
< end
&& !bb_split (bb
, try_block
, root
, clause
->try_offset
+ clause
->try_len
, FALSE
, method
, error
))
489 if (clause
->handler_offset
+ clause
->handler_len
< end
&& !bb_split (bb
, handler
, root
, clause
->handler_offset
+ clause
->handler_len
, FALSE
, method
, error
))
495 * mono_basic_block_free:
497 * Release the memory associated with the list of basis blocks @bb.
500 mono_basic_block_free (MonoSimpleBasicBlock
*bb
)
503 MonoSimpleBasicBlock
*next
= bb
->next
;
505 g_slist_free (bb
->out_bb
);
512 * mono_basic_block_split:
514 * Return the list of basic blocks of method. Return NULL on failure and set @error.
516 MonoSimpleBasicBlock
*
517 mono_basic_block_split (MonoMethod
*method
, MonoError
*error
)
519 MonoSimpleBasicBlock
*bb
, *root
;
520 const unsigned char *start
, *end
;
521 MonoMethodHeader
*header
= mono_method_get_header (method
);
522 start
= header
->code
;
523 end
= start
+ header
->code_size
;
525 mono_error_init (error
);
528 mono_error_set_not_verifiable (error
, method
, "Could not decode header");
532 bb
= g_new0 (MonoSimpleBasicBlock
, 1);
534 bb
->end
= end
- start
;
539 bb_formation_il_pass (start
, end
, bb
, &root
, method
, error
);
540 if (!mono_error_ok (error
))
543 bb_formation_eh_pass (header
, bb
, &root
, method
, error
);
544 if (!mono_error_ok (error
))
550 dump_bb_list (bb
, &root
, g_strdup_printf("AFTER LIVENESS %s", mono_method_full_name (method
, TRUE
)));
553 mono_metadata_free_mh (header
);
557 mono_metadata_free_mh (header
);
558 mono_basic_block_free (bb
);
563 * mono_opcode_value_and_size:
565 * Returns the size of the opcode starting at *@ip, or -1 on error.
566 * Value is the opcode number.
569 mono_opcode_value_and_size (const unsigned char **ip
, const unsigned char *end
, int *value
)
571 const unsigned char *start
= *ip
, *p
;
572 int i
= *value
= mono_opcode_value (ip
, end
);
574 if (i
< 0 || i
>= MONO_CEE_LAST
)
578 switch (mono_opcodes
[i
].argument
) {
582 case MonoInlineString
:
584 case MonoInlineField
:
585 case MonoInlineMethod
:
588 case MonoShortInlineR
:
590 case MonoInlineBrTarget
:
596 case MonoShortInlineVar
:
597 case MonoShortInlineI
:
598 case MonoShortInlineBrTarget
:
605 case MonoInlineSwitch
: {
607 if (ADDP_IS_GREATER_OR_OVF (p
, 5, end
))
609 entries
= read32 (p
+ 1);
610 if (entries
>= (0xFFFFFFFFU
/ 4))
612 size
= 4 + 4 * entries
;
616 g_error ("Invalid opcode %d argument %d max opcode %d\n", i
, mono_opcodes
[i
].argument
, MONO_CEE_LAST
);
619 if (ADDP_IS_GREATER_OR_OVF (p
, size
, end
))
622 return (p
- start
) + size
;
628 * Returns the size of the opcode starting at @ip, or -1 on error.
631 mono_opcode_size (const unsigned char *ip
, const unsigned char *end
)
634 return mono_opcode_value_and_size (&ip
, end
, &tmp
);