void test_convert_swap(void) { struct expression *expr1; struct expression *expr2; expr1 = value_expr(J_INT, 1); expr2 = value_expr(J_INT, 2); assert_swap_stack(OPC_SWAP, expr1, expr2); expr_put(expr1); expr_put(expr2); }
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; }
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; }
static void assert_convert_ldc_w_float(enum vm_type expected_type, double expected_value, uint8_t cp_type, unsigned long opcode) { unsigned char code[] = { opcode, 0x01, 0x00 }; uint32_t cp_infos[NR_CP_ENTRIES]; uint8_t cp_types[NR_CP_ENTRIES]; struct expression *expr; struct basic_block *bb; if (opcode == OPC_LDC_W) const_set_float(cp_infos, 0x100, (float) expected_value); else const_set_double(cp_infos, 0x100, expected_value); cp_types[0x100] = cp_type; bb = alloc_simple_bb(code, ARRAY_SIZE(code)); convert_ir_const(bb->b_parent, cp_infos, NR_CP_ENTRIES, cp_types); expr = stack_pop(bb->mimic_stack); assert_fvalue_expr(expected_type, expected_value, &expr->node); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
void test_convert_dup(void) { struct expression *value1, *value2, *value3; value1 = value_expr(J_REFERENCE, 0xdeadbeef); value2 = value_expr(J_REFERENCE, 0xcafedeca); value3 = value_expr(J_LONG, 0xcafecafecafecafe); assert_dup_stack(OPC_DUP, value1); assert_dup2_stack(OPC_DUP2, value1, value2); assert_dup2_stack(OPC_DUP2, value3, NULL); expr_put(value1); expr_put(value2); expr_put(value3); }
void test_convert_dup_x1(void) { struct expression *value1, *value2, *value3; value1 = value_expr(J_REFERENCE, 0xdeadbeef); value2 = value_expr(J_REFERENCE, 0xcafebabe); value3 = value_expr(J_LONG, 0xdecacafebabebeef); assert_dup_x1_stack(OPC_DUP_X1, value1, value2); assert_dup2_x1_stack(OPC_DUP2_X1, value1, value2, value3); assert_dup2_x1_stack(OPC_DUP2_X1, value3, value2, value1); expr_put(value1); expr_put(value2); expr_put(value3); }
static void __assert_convert_load(unsigned char *code, unsigned long code_size, enum vm_type expected_type, unsigned char expected_index) { struct expression *expr; struct statement *stmt; struct basic_block *bb; bb = alloc_simple_bb(code, code_size); convert_to_ir(bb->b_parent); expr = stack_pop(bb->mimic_stack); assert_temporary_expr(expected_type, &expr->node); stmt = stmt_entry(bb->stmt_list.next); assert_store_stmt(stmt); assert_local_expr(expected_type, expected_index, stmt->store_src); assert_ptr_equals(&expr->node, stmt->store_dest); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
struct expression * convert_args(struct stack *mimic_stack, unsigned long nr_args, struct vm_method *method) { struct expression *args_list = NULL; unsigned long nr_total_args; unsigned long i; nr_total_args = nr_args; if (vm_method_is_jni(method)) { if (vm_method_is_static(method)) nr_total_args++; nr_total_args++; } if (nr_total_args == 0) { args_list = no_args_expr(); goto out; } /* * We scan the args map in reverse order, since the order of arguments * is already reversed. */ for (i = 0; i < nr_args; i++) { struct expression *expr = stack_pop(mimic_stack); if (vm_type_is_pair(expr->vm_type)) i++; if (i >= nr_args) break; args_list = insert_arg(args_list, expr, method, nr_total_args - i - 1); } if (vm_method_is_jni(method)) { struct expression *expr; if (vm_method_is_static(method)) { expr = value_expr(J_REFERENCE, (unsigned long) method->class->object); if (!expr) goto error; args_list = insert_arg(args_list, expr, method, 1); } /* * JNI methods also need a pointer to JNI environment. That's * done in jni_trampoline automagically which is why we never * use method index zero here for JNI methods. */ } out: return args_list; error: expr_put(args_list); return NULL; }
void test_convert_dup_x2(void) { struct expression *value1, *value2, *value3, *value4; value1 = value_expr(J_REFERENCE, 0xdeadbeef); value2 = value_expr(J_REFERENCE, 0xcafebabe); value3 = value_expr(J_REFERENCE, 0xb4df00d); value4 = value_expr(J_REFERENCE, 0x6559570); assert_dup_x2_stack(OPC_DUP_X2, value1, value2, value3); assert_dup2_x2_stack(OPC_DUP2_X2, value1, value2, value3, value4); expr_put(value1); expr_put(value2); expr_put(value3); expr_put(value4); }
/* The returned pointer could be stale because of expr_put() so only use the return value for pointer comparison. */ static struct expression *pop_and_put_expr(struct stack *stack) { struct expression *expr; expr = stack_pop(stack); expr_put(expr); return expr; }
static char * __expr_get(struct num_exp_ctx *ctx, int eof_okay) { char *s; if ((s = ctx->unget) != NULL) { ctx->unget = NULL; return s; } ctx->j = 0; do { if ((s = ctx->str) == NULL || *s == '\0') { if (ctx->argc == 0) { if (eof_okay) return NULL; expr_fail(ctx); } ctx->str = s = *(ctx->argv++); ctx->argc--; } while (isspace(*s)) s++; } while (*s == '\0'); if (isdigit(*s)) { while (isdigit(*s)) expr_put(ctx, *s++); } else if (*s == '$') { expr_put(ctx, *s++); while (isalnum(*s) || *s == '-' || *s == '_') expr_put(ctx, *s++); } else if (strchr("*/+-()|&", *s)) { expr_put(ctx, *s++); } else { expr_fail(ctx); } ctx->str = s; expr_put(ctx, '\0'); return ctx->word; }
int convert_pop2(struct parse_context *ctx) { struct expression *another_expr; struct expression *expr; expr = stack_pop(ctx->bb->mimic_stack); if (vm_type_is_pair(expr->vm_type)) goto out; another_expr = stack_peek(ctx->bb->mimic_stack); if (vm_type_is_pair(another_expr->vm_type)) goto out; expr_put(stack_pop(ctx->bb->mimic_stack)); out: expr_put(expr); return 0; }
void free_expression(struct expression *expr) { int i; if (!expr) return; for (i = 0; i < expr_nr_kids(expr); i++) if (expr->node.kids[i]) expr_put(to_expr(expr->node.kids[i])); free(expr); }
void free_statement(struct statement *stmt) { int i; if (!stmt) return; for (i = 0; i < stmt_nr_kids(stmt); i++) if (stmt->node.kids[i]) expr_put(to_expr(stmt->node.kids[i])); switch (stmt_type(stmt)) { case STMT_INVOKE: case STMT_INVOKEVIRTUAL: case STMT_INVOKEINTERFACE: if (stmt->invoke_result) expr_put(stmt->invoke_result); break; default: break; } free(stmt); }
static void assert_convert_fconst(enum vm_type expected_type, double expected_value, unsigned char opc) { struct expression *expr; struct basic_block *bb; bb = alloc_simple_bb(&opc, 1); convert_to_ir(bb->b_parent); expr = stack_pop(bb->mimic_stack); assert_fvalue_expr(expected_type, expected_value, &expr->node); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
static void __assert_convert_const(enum vm_type expected_type, long long expected_value, unsigned char *code, unsigned long code_size) { struct expression *expr; struct basic_block *bb; bb = alloc_simple_bb(code, code_size); convert_to_ir(bb->b_parent); expr = stack_pop(bb->mimic_stack); assert_value_expr(expected_type, expected_value, &expr->node); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
static int convert_if(struct parse_context *ctx, enum binary_operator binop) { struct statement *stmt; struct expression *if_value, *zero_value; zero_value = value_expr(J_INT, 0); if (!zero_value) return -ENOMEM; if_value = stack_pop(ctx->bb->mimic_stack); stmt = __convert_if(ctx, J_INT, binop, if_value, zero_value); if (!stmt) { expr_put(zero_value); return -ENOMEM; } convert_statement(ctx, stmt); return 0; }
static void assert_convert_ldc_w_string(enum vm_type expected_type, long long expected_value) { unsigned char code[] = { OPC_LDC_W, 0x01, 0x00 }; uint32_t cp_infos[NR_CP_ENTRIES]; uint8_t cp_types[NR_CP_ENTRIES]; struct basic_block *bb; struct expression *expr; const_set_int32_t(cp_infos, 0x100, 0x00); cp_types[0x100] = CAFEBABE_CONSTANT_TAG_STRING; bb = alloc_simple_bb(code, ARRAY_SIZE(code)); convert_ir_const(bb->b_parent, cp_infos, NR_CP_ENTRIES, cp_types); expr = stack_pop(bb->mimic_stack); assert_value_expr(expected_type, expected_value, &expr->node); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
static void assert_convert_ldc_float(float expected_value) { unsigned char code[] = { OPC_LDC, 0xff }; uint32_t cp_infos[NR_CP_ENTRIES]; uint8_t cp_types[NR_CP_ENTRIES]; struct expression *expr; struct basic_block *bb; const_set_float(cp_infos, 0xff, expected_value); cp_types[0xff] = CAFEBABE_CONSTANT_TAG_FLOAT; bb = alloc_simple_bb(code, ARRAY_SIZE(code)); convert_ir_const(bb->b_parent, cp_infos, NR_CP_ENTRIES, cp_types); expr = stack_pop(bb->mimic_stack); assert_fvalue_expr(J_FLOAT, expected_value, &expr->node); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
static void assert_convert_ldc(enum vm_type expected_type, long long expected_value, uint8_t cp_type) { uint32_t cp_infos[NR_CP_ENTRIES]; uint8_t cp_types[NR_CP_ENTRIES]; unsigned char code[] = { OPC_LDC, 0xff }; struct expression *expr; struct basic_block *bb; const_set_int32_t(cp_infos, 0xff, expected_value); cp_types[0xff] = cp_type; bb = alloc_simple_bb(code, ARRAY_SIZE(code)); convert_ir_const(bb->b_parent, cp_infos, NR_CP_ENTRIES, cp_types); expr = stack_pop(bb->mimic_stack); assert_value_expr(expected_type, expected_value, &expr->node); assert_true(stack_is_empty(bb->mimic_stack)); expr_put(expr); free_simple_bb(bb); }
int convert_athrow(struct parse_context *ctx) { struct stack *mimic_stack = ctx->bb->mimic_stack; struct expression *exception_ref; struct expression *nullcheck; struct statement *stmt; stmt = alloc_statement(STMT_ATHROW); if (!stmt) return -ENOMEM; exception_ref = stack_pop(mimic_stack); nullcheck = null_check_expr(exception_ref); if (!nullcheck) return -ENOMEM; stmt->exception_ref = &nullcheck->node; /* * According to the JVM specification athrow operation is * supposed to discard the java stack and push exception * reference on it. We don't do the latter because exception * reference is not transferred to exception handlers in * BC2IR layer. */ while (!stack_is_empty(mimic_stack)) { struct expression *expr = stack_pop(mimic_stack); expr_put(expr); } convert_statement(ctx, stmt); return 0; }
int convert_pop(struct parse_context *ctx) { expr_put(stack_pop(ctx->bb->mimic_stack)); return 0; }
static void assert_print_expr(struct string *expected, struct expression *expr) { assert_tree_print(expected, &expr->node); expr_put(expr); }