void test_no_basic_block_when_offset_out_of_range(void) { struct compilation_unit *cu = compilation_unit_alloc(&method); struct basic_block *block = alloc_basic_block(cu, 1, 2); list_add_tail(&block->bb_list_node, &cu->bb_list); assert_ptr_equals(NULL, find_bb(cu, 0)); assert_ptr_equals(NULL, find_bb(cu, 2)); free_compilation_unit(cu); }
static struct statement *__convert_if(struct parse_context *ctx, enum vm_type vm_type, enum binary_operator binop, struct expression *binary_left, struct expression *binary_right) { struct basic_block *true_bb; struct expression *if_conditional; struct statement *if_stmt; int32_t if_target; if_target = bytecode_read_branch_target(ctx->opc, ctx->buffer); true_bb = find_bb(ctx->cu, ctx->offset + if_target); if_conditional = binop_expr(vm_type, binop, binary_left, binary_right); if (!if_conditional) goto failed; if_stmt = alloc_statement(STMT_IF); if (!if_stmt) goto failed_put_expr; if_stmt->if_true = true_bb; if_stmt->if_conditional = &if_conditional->node; return if_stmt; failed_put_expr: expr_put(if_conditional); failed: return NULL; }
struct tableswitch *alloc_tableswitch(struct tableswitch_info *info, struct compilation_unit *cu, struct basic_block *bb, unsigned long offset) { struct tableswitch *table; table = malloc(sizeof(*table)); if (!table) return NULL; table->src = bb; table->low = info->low; table->high = info->high; table->bb_lookup_table = malloc(sizeof(void *) * info->count); if (!table->bb_lookup_table) { free(table); return NULL; } for (unsigned int i = 0; i < info->count; i++) { int32_t target; target = read_s32(info->targets + i * 4); table->bb_lookup_table[i] = find_bb(cu, offset + target); } list_add(&table->list_node, &cu->tableswitch_list); return table; }
struct lookupswitch *alloc_lookupswitch(struct lookupswitch_info *info, struct compilation_unit *cu, struct basic_block *bb, unsigned long offset) { struct lookupswitch *table; table = malloc(sizeof(*table)); if (!table) return NULL; table->src = bb; table->count = info->count; table->pairs = malloc(sizeof(struct lookupswitch_pair) * info->count); if (!table->pairs) { free(table); return NULL; } for (unsigned int i = 0; i < info->count; i++) { int32_t target; target = read_lookupswitch_target(info, i); table->pairs[i].match = read_lookupswitch_match(info, i); table->pairs[i].bb_target = find_bb(cu, offset + target); } list_add(&table->list_node, &cu->lookupswitch_list); return table; }
void test_find_basic_block(void) { struct basic_block *b1; struct basic_block *b2; struct basic_block *b3; struct compilation_unit *cu = compilation_unit_alloc(&method); b1 = alloc_basic_block(cu, 0, 3); b2 = alloc_basic_block(cu, 3, 5); b3 = alloc_basic_block(cu, 5, 6); list_add_tail(&b1->bb_list_node, &cu->bb_list); list_add_tail(&b2->bb_list_node, &cu->bb_list); list_add_tail(&b3->bb_list_node, &cu->bb_list); assert_ptr_equals(b1, find_bb(cu, 2)); assert_ptr_equals(b2, find_bb(cu, 3)); assert_ptr_equals(b3, find_bb(cu, 5)); free_compilation_unit(cu); }
int convert_goto(struct parse_context *ctx) { struct basic_block *target_bb; struct statement *goto_stmt; int32_t goto_target; goto_target = bytecode_read_branch_target(ctx->opc, ctx->buffer); target_bb = find_bb(ctx->cu, goto_target + ctx->offset); goto_stmt = alloc_statement(STMT_GOTO); if (!goto_stmt) return -ENOMEM; goto_stmt->goto_target = target_bb; convert_statement(ctx, goto_stmt); return 0; }
int convert_tableswitch(struct parse_context *ctx) { struct tableswitch_info info; struct tableswitch *table; struct basic_block *master_bb; struct basic_block *default_bb; struct basic_block *b1; struct basic_block *b2; get_tableswitch_info(ctx->code, ctx->offset, &info); ctx->buffer->pos += info.insn_size; default_bb = find_bb(ctx->cu, ctx->offset + info.default_target); if (!default_bb) goto fail_default_bb; master_bb = ctx->bb; b1 = bb_split(master_bb, master_bb->end); b2 = bb_split(b1, master_bb->end); assert(b1 && b2); master_bb->has_branch = true; b1->has_branch = true; b2->has_branch = true; bb_add_successor(master_bb, default_bb ); bb_add_successor(master_bb, b1); bb_add_successor(b1, default_bb ); bb_add_successor(b1, b2); for (unsigned int i = 0; i < info.count; i++) { struct basic_block *target_bb; int32_t target; target = read_s32(info.targets + i * 4); target_bb = find_bb(ctx->cu, ctx->offset + target); if (!bb_successors_contains(b2, target_bb)) bb_add_successor(b2, target_bb); } table = alloc_tableswitch(&info, ctx->cu, b2, ctx->offset); if (!table) return -ENOMEM; struct statement *if_lesser_stmt; struct statement *if_greater_stmt; struct statement *stmt; struct expression *pure_index; pure_index = get_pure_expr(ctx, stack_pop(ctx->bb->mimic_stack)); if_lesser_stmt = branch_if_lesser_stmt(default_bb, pure_index, info.low); if (!if_lesser_stmt) goto fail_lesser_stmt; expr_get(pure_index); if_greater_stmt = branch_if_greater_stmt(default_bb, pure_index, info.high); if (!if_greater_stmt) goto fail_greater_stmt; stmt = alloc_statement(STMT_TABLESWITCH); if (!stmt) goto fail_stmt; expr_get(pure_index); stmt->index = &pure_index->node; stmt->table = table; do_convert_statement(master_bb, if_lesser_stmt, ctx->offset); do_convert_statement(b1, if_greater_stmt, ctx->offset); do_convert_statement(b2, stmt, ctx->offset); return 0; fail_stmt: free_statement(if_greater_stmt); fail_greater_stmt: free_statement(if_lesser_stmt); fail_lesser_stmt: free_tableswitch(table); fail_default_bb: return -1; }
int convert_lookupswitch(struct parse_context *ctx) { struct lookupswitch_info info; struct lookupswitch *table; struct basic_block *master_bb; struct basic_block *default_bb; struct basic_block *b1; get_lookupswitch_info(ctx->code, ctx->offset, &info); ctx->buffer->pos += info.insn_size; default_bb = find_bb(ctx->cu, ctx->offset + info.default_target); if (!default_bb) goto fail_default_bb; master_bb = ctx->bb; b1 = bb_split(master_bb, master_bb->end); assert(b1); b1->has_branch = true; bb_add_successor(master_bb, default_bb ); bb_add_successor(master_bb, b1); for (unsigned int i = 0; i < info.count; i++) { struct basic_block *target_bb; int32_t target; target = read_lookupswitch_target(&info, i); target_bb = find_bb(ctx->cu, ctx->offset + target); if (!bb_successors_contains(b1, target_bb)) bb_add_successor(b1, target_bb); } table = alloc_lookupswitch(&info, ctx->cu, b1, ctx->offset); if (!table) return -ENOMEM; struct statement *if_null_stmt; struct statement *stmt; struct expression *key; struct expression *bsearch; struct expression *pure_bsearch; key = stack_pop(ctx->bb->mimic_stack); bsearch = lookupswitch_bsearch_expr(key, table); if (!bsearch) return -1; pure_bsearch = get_pure_expr(ctx, bsearch); if_null_stmt = branch_if_null_stmt(default_bb, pure_bsearch); if (!if_null_stmt) goto fail_null_stmt; stmt = alloc_statement(STMT_LOOKUPSWITCH_JUMP); if (!stmt) goto fail_stmt; expr_get(pure_bsearch); stmt->lookupswitch_target = &pure_bsearch->node; convert_statement(ctx, if_null_stmt); do_convert_statement(b1, stmt, ctx->offset); return 0; fail_stmt: free_statement(if_null_stmt); fail_null_stmt: free_lookupswitch(table); fail_default_bb: return -1; }