|
|
|
|
@ -32,18 +32,18 @@ |
|
|
|
|
/* These checks will also be done by the bytecode verifier, but for
|
|
|
|
|
* debugging purposes we have explicit checks, these should never fail! */ |
|
|
|
|
#ifdef CL_DEBUG |
|
|
|
|
static int bcfail(const char *msg, unsigned a, unsigned b, |
|
|
|
|
static int bcfail(const char *msg, long a, long b, |
|
|
|
|
const char *file, unsigned line) |
|
|
|
|
{ |
|
|
|
|
cli_errmsg("bytecode: check failed %s (%u and %u) at %s:%u\n", msg, a, b, file, line); |
|
|
|
|
cli_errmsg("bytecode: check failed %s (%lx and %lx) at %s:%u\n", msg, a, b, file, line); |
|
|
|
|
return CL_EARG; |
|
|
|
|
} |
|
|
|
|
#define CHECK_FUNCID(funcid) do { if (funcid >= bc->num_func) return \ |
|
|
|
|
bcfail("funcid out of bounds!",funcid, bc->num_func,__FILE__,__LINE__); } while(0) |
|
|
|
|
#define CHECK_EQ(a, b) do { if (a != b) return \ |
|
|
|
|
bcfail("Values "#a" and "#b" don't match!",a,b,__FILE__,__LINE__); } while(0) |
|
|
|
|
#define CHECK_GT(a, b) do {if (a <= b) return \ |
|
|
|
|
bcfail("Condition failed "#a" > "#b,a,b, __FILE__, __LINE__); } while(0) |
|
|
|
|
#define CHECK_EQ(a, b) do { if ((a) != (b)) return \ |
|
|
|
|
bcfail("Values "#a" and "#b" don't match!",(a),(b),__FILE__,__LINE__); } while(0) |
|
|
|
|
#define CHECK_GT(a, b) do {if ((a) <= (b)) return \ |
|
|
|
|
bcfail("Condition failed "#a" > "#b,(a),(b), __FILE__, __LINE__); } while(0) |
|
|
|
|
#else |
|
|
|
|
#define CHECK_FUNCID(x) |
|
|
|
|
#define CHECK_EQ(a,b) |
|
|
|
|
@ -51,8 +51,9 @@ static int bcfail(const char *msg, unsigned a, unsigned b, |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
struct stack_entry { |
|
|
|
|
struct cli_bc_func *func; |
|
|
|
|
const struct cli_bc_func *func; |
|
|
|
|
struct cli_bc_value *ret; |
|
|
|
|
struct cli_bc_value *values; |
|
|
|
|
struct cli_bc_bb *bb; |
|
|
|
|
unsigned bb_inst; |
|
|
|
|
}; |
|
|
|
|
@ -79,28 +80,39 @@ struct stack_entry { |
|
|
|
|
#define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type)) |
|
|
|
|
#define BINOPS(i) SIGNEXT(BINOPNOMOD(i)) |
|
|
|
|
|
|
|
|
|
static void jump(struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, struct cli_bc_inst **inst, |
|
|
|
|
struct cli_bc_value **value, unsigned *bb_inst) |
|
|
|
|
static int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst, |
|
|
|
|
unsigned *bb_inst) |
|
|
|
|
{ |
|
|
|
|
CHECK_GT(func->numBB, bbid); |
|
|
|
|
*bb = &func->BB[bbid]; |
|
|
|
|
*inst = (*bb)->insts; |
|
|
|
|
*value = &func->values[*inst - func->allinsts]; |
|
|
|
|
*bb_inst = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst) |
|
|
|
|
static struct cli_bc_value *allocate_stack(const struct cli_bc_func *func) |
|
|
|
|
{ |
|
|
|
|
unsigned i; |
|
|
|
|
struct cli_bc_value *values = cli_calloc(func->numValues+func->numConstants, sizeof(*values)); |
|
|
|
|
if (!values) |
|
|
|
|
return NULL; |
|
|
|
|
for (i=func->numValues;i<func->numValues+func->numConstants;i++) |
|
|
|
|
values[i] = func->constants[i-func->numValues]; |
|
|
|
|
return values; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst) |
|
|
|
|
{ |
|
|
|
|
unsigned i, stack_depth=0, bb_inst=0, stop=0; |
|
|
|
|
struct cli_bc_func *func2; |
|
|
|
|
struct stack_entry *stack = NULL; |
|
|
|
|
struct cli_bc_bb *bb = NULL; |
|
|
|
|
struct cli_bc_value *values = func->values; |
|
|
|
|
struct cli_bc_value *value; |
|
|
|
|
struct cli_bc_value *values = ctx->values; |
|
|
|
|
struct cli_bc_value *value, *old_values; |
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
value = &values[inst->dest]; |
|
|
|
|
CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value); |
|
|
|
|
CHECK_GT(func->numValues+func->numConstants, value - values); |
|
|
|
|
switch (inst->opcode) { |
|
|
|
|
case OP_ADD: |
|
|
|
|
value->v = BINOPNOMOD(0) + BINOPNOMOD(1); |
|
|
|
|
@ -175,22 +187,23 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
|
|
|
|
value->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v; |
|
|
|
|
break; |
|
|
|
|
case OP_BRANCH: |
|
|
|
|
jump(func, (values[inst->u.branch.condition].v&1) ? |
|
|
|
|
inst->u.branch.br_true : inst->u.branch.br_false, |
|
|
|
|
&bb, &inst, &value, &bb_inst); |
|
|
|
|
stop = jump(func, (values[inst->u.branch.condition].v&1) ? |
|
|
|
|
inst->u.branch.br_true : inst->u.branch.br_false, |
|
|
|
|
&bb, &inst, &bb_inst); |
|
|
|
|
continue; |
|
|
|
|
case OP_JMP: |
|
|
|
|
jump(func, inst->u.jump, &bb, &inst, &value, &bb_inst); |
|
|
|
|
stop = jump(func, inst->u.jump, &bb, &inst, &bb_inst); |
|
|
|
|
continue; |
|
|
|
|
case OP_RET: |
|
|
|
|
CHECK_GT(stack_depth, 0); |
|
|
|
|
stack_depth--; |
|
|
|
|
value = stack[stack_depth].ret; |
|
|
|
|
func = stack[stack_depth].func; |
|
|
|
|
CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value); |
|
|
|
|
CHECK_GT(value, &func->values[-1]); |
|
|
|
|
value->v = values[inst->u.unaryop].v; |
|
|
|
|
values = func->values; |
|
|
|
|
free(values); |
|
|
|
|
values = stack[stack_depth].values; |
|
|
|
|
CHECK_GT(func->numValues+func->numConstants, value-values); |
|
|
|
|
CHECK_GT(value-values, -1); |
|
|
|
|
if (!stack[stack_depth].bb) { |
|
|
|
|
stop = CL_BREAK; |
|
|
|
|
bb_inst--; |
|
|
|
|
@ -238,8 +251,6 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
|
|
|
|
CHECK_FUNCID(inst->u.ops.funcid); |
|
|
|
|
func2 = &bc->funcs[inst->u.ops.funcid]; |
|
|
|
|
CHECK_EQ(func2->numArgs, inst->u.ops.numOps); |
|
|
|
|
for (i=0;i<func2->numArgs;i++) |
|
|
|
|
func2->values[i] = func->values[inst->u.ops.ops[i]]; |
|
|
|
|
stack = cli_realloc2(stack, sizeof(*stack)*(stack_depth+1)); |
|
|
|
|
if (!stack) |
|
|
|
|
return CL_EMEM; |
|
|
|
|
@ -247,12 +258,18 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
|
|
|
|
stack[stack_depth].ret = value; |
|
|
|
|
stack[stack_depth].bb = bb; |
|
|
|
|
stack[stack_depth].bb_inst = bb_inst; |
|
|
|
|
stack[stack_depth].values = values; |
|
|
|
|
stack_depth++; |
|
|
|
|
cli_dbgmsg("Executing %d\n", inst->u.ops.funcid); |
|
|
|
|
old_values = values; |
|
|
|
|
values = allocate_stack(func2); |
|
|
|
|
if (!values) |
|
|
|
|
return CL_EMEM; |
|
|
|
|
for (i=0;i<func2->numArgs;i++) |
|
|
|
|
values[i] = old_values[inst->u.ops.ops[i]]; |
|
|
|
|
func = func2; |
|
|
|
|
values = func->values; |
|
|
|
|
CHECK_GT(func->numBB, 0); |
|
|
|
|
jump(func, 0, &bb, &inst, &value, &bb_inst); |
|
|
|
|
stop = jump(func, 0, &bb, &inst, &bb_inst); |
|
|
|
|
continue; |
|
|
|
|
case OP_COPY: |
|
|
|
|
BINOPNOMOD(1) = BINOPNOMOD(0); |
|
|
|
|
@ -260,6 +277,7 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
|
|
|
|
default: |
|
|
|
|
cli_errmsg("Opcode %u is not implemented yet!\n", inst->opcode); |
|
|
|
|
stop = CL_EARG; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
bb_inst++; |
|
|
|
|
inst++; |
|
|
|
|
|