static void assert_dup_x2_stack(unsigned char opc, struct expression *value1, struct expression *value2, struct expression *value3) { struct basic_block *bb; struct statement *stmt; bb = alloc_simple_bb(&opc, 1); stack_push(bb->mimic_stack, expr_get(value3)); stack_push(bb->mimic_stack, expr_get(value2)); stack_push(bb->mimic_stack, expr_get(value1)); convert_to_ir(bb->b_parent); stmt = stmt_entry(bb->stmt_list.next); assert_store_stmt(stmt); assert_ptr_equals(value1, to_expr(stmt->store_src)); assert_temporary_expr(value1->vm_type, stmt->store_dest); assert_ptr_equals(to_expr(stmt->store_dest), pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value2, pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value3, pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value1, pop_and_put_expr(bb->mimic_stack)); assert_true(stack_is_empty(bb->mimic_stack)); free_simple_bb(bb); }
static void assert_dup2_x2_stack(unsigned char opc, struct expression *value1, struct expression *value2, struct expression *value3, struct expression *value4) { struct statement *stmt, *stmt2; struct basic_block *bb; if (value1->vm_type == J_LONG || value1->vm_type == J_DOUBLE) { if (value2->vm_type == J_LONG || value2->vm_type == J_DOUBLE) { assert_dup_x1_stack(opc, value1, value2); return; } else { assert_dup_x2_stack(opc, value1, value2, value3); return; } } else { if (value3->vm_type == J_LONG || value3->vm_type == J_DOUBLE) { assert_dup2_x1_stack(opc, value1, value2, value3); return; } } bb = alloc_simple_bb(&opc, 1); stack_push(bb->mimic_stack, expr_get(value4)); stack_push(bb->mimic_stack, expr_get(value3)); stack_push(bb->mimic_stack, expr_get(value2)); stack_push(bb->mimic_stack, expr_get(value1)); convert_to_ir(bb->b_parent); stmt = stmt_entry(bb->stmt_list.next); stmt2 = stmt_entry(stmt->stmt_list_node.next); assert_store_stmt(stmt); assert_ptr_equals(value2, to_expr(stmt->store_src)); assert_temporary_expr(value2->vm_type, stmt->store_dest); assert_store_stmt(stmt2); assert_ptr_equals(value1, to_expr(stmt2->store_src)); assert_temporary_expr(value1->vm_type, stmt2->store_dest); assert_ptr_equals(to_expr(stmt2->store_dest), pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(to_expr(stmt->store_dest), pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value3, pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value4, pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value1, pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value2, pop_and_put_expr(bb->mimic_stack)); assert_true(stack_is_empty(bb->mimic_stack)); free_simple_bb(bb); }
static int __convert_dup2(struct parse_context *ctx, struct expression *value1, struct expression *value2) { struct expression *dup, *dup2; dup = get_pure_expr(ctx, value1); dup2 = get_pure_expr(ctx, value2); convert_expression(ctx, dup2); convert_expression(ctx, dup); convert_expression(ctx, dup_expr(ctx, expr_get(dup2))); convert_expression(ctx, dup_expr(ctx, expr_get(dup))); return 0; }
static void expr_term(struct num_exp_ctx *ctx, unsigned int *vp) { char *tok; tok = expr_get(ctx); if (*tok == '(') { expr_eval(ctx, vp, 1); expr_expect(ctx, ')'); } else if (isdigit(*tok)) { char *ep; *vp = strtoul(tok, &ep, 0); if (*ep) expr_fail(ctx); } else if (*tok == '$') { sc_macro_t *mac; char *argv[32]; int argc; if (!(mac = find_macro(ctx->state->profile, tok + 1))) expr_fail(ctx); argc = build_argv(ctx->state, "<expr>", mac->value, argv, 32); if (argc < 0 || get_uint_eval(ctx->state, argc, argv, vp) < 0) expr_fail(ctx); } else { parse_error(ctx->state, "Unexpected token \"%s\" in expression", tok); expr_fail(ctx); } }
static void assert_swap_stack(unsigned char opc, void *value1, void *value2) { struct basic_block *bb; bb = alloc_simple_bb(&opc, 1); stack_push(bb->mimic_stack, expr_get(value1)); stack_push(bb->mimic_stack, expr_get(value2)); convert_to_ir(bb->b_parent); assert_ptr_equals(value1, pop_and_put_expr(bb->mimic_stack)); assert_ptr_equals(value2, pop_and_put_expr(bb->mimic_stack)); assert_true(stack_is_empty(bb->mimic_stack)); free_simple_bb(bb); }
static void expr_expect(struct num_exp_ctx *ctx, int c) { char *tok; tok = expr_get(ctx); if (tok[0] != (char)c || tok[1]) expr_fail(ctx); }
static int __convert_dup(struct parse_context *ctx, struct expression *value) { struct expression *dup; dup = get_pure_expr(ctx, value); convert_expression(ctx, dup); convert_expression(ctx, dup_expr(ctx, expr_get(dup))); return 0; }
int convert_iinc(struct parse_context *ctx) { struct statement *store_stmt; struct expression *local_expression, *binop_expression, *const_expression; unsigned int index; int const_value; store_stmt = alloc_statement(STMT_STORE); if (!store_stmt) goto failed; if (ctx->is_wide) { index = bytecode_read_u16(ctx->buffer); const_value = bytecode_read_s16(ctx->buffer); } else { index = bytecode_read_u8(ctx->buffer); const_value = bytecode_read_s8(ctx->buffer); } local_expression = local_expr(J_INT, index); if (!local_expression) goto failed; store_stmt->store_dest = &local_expression->node; const_expression = value_expr(J_INT, const_value); if (!const_expression) goto failed; expr_get(local_expression); binop_expression = binop_expr(J_INT, OP_ADD, local_expression, const_expression); if (!binop_expression) { expr_put(local_expression); expr_put(const_expression); goto failed; } store_stmt->store_src = &binop_expression->node; convert_statement(ctx, store_stmt); return 0; failed: free_statement(store_stmt); return warn("out of memory"), -ENOMEM; }
struct expression * dup_expr(struct parse_context *ctx, struct expression *expr) { struct expression *dest; struct statement *stmt; dest = temporary_expr(expr->vm_type, ctx->cu); expr_get(dest); stmt = alloc_statement(STMT_STORE); stmt->store_dest = &dest->node; stmt->store_src = &expr->node; convert_statement(ctx, stmt); return dest; }
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; }