... | ... |
@@ -67,12 +67,12 @@ int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, un |
67 | 67 |
ctx->bc = bc; |
68 | 68 |
ctx->numParams = func->numArgs; |
69 | 69 |
ctx->funcid = funcid; |
70 |
+ ctx->values = cli_malloc(sizeof(*ctx->values)*(func->numArgs+1)); |
|
71 |
+ if (!ctx->values) { |
|
72 |
+ cli_errmsg("bytecode: error allocating memory for parameters\n"); |
|
73 |
+ return CL_EMEM; |
|
74 |
+ } |
|
70 | 75 |
if (func->numArgs) { |
71 |
- ctx->values = cli_malloc(sizeof(*ctx->values)*func->numArgs); |
|
72 |
- if (!ctx->values) { |
|
73 |
- cli_errmsg("bytecode: error allocating memory for parameters\n"); |
|
74 |
- return CL_EMEM; |
|
75 |
- } |
|
76 | 76 |
ctx->operands = cli_malloc(sizeof(*ctx->operands)*func->numArgs); |
77 | 77 |
if (!ctx->operands) { |
78 | 78 |
cli_errmsg("bytecode: error allocating memory for parameters\n"); |
... | ... |
@@ -81,7 +81,7 @@ int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, un |
81 | 81 |
} |
82 | 82 |
for (i=0;i<func->numArgs;i++) { |
83 | 83 |
ctx->values[i].ref = MAX_OP; |
84 |
- ctx->operands[i] = i; |
|
84 |
+ ctx->operands[i+1] = i; |
|
85 | 85 |
} |
86 | 86 |
return CL_SUCCESS; |
87 | 87 |
} |
... | ... |
@@ -168,7 +168,7 @@ static inline operand_t readOperand(struct cli_bc_func *func, unsigned char *p, |
168 | 168 |
{ |
169 | 169 |
uint64_t v; |
170 | 170 |
unsigned numValues = func->numArgs + func->numInsts + func->numConstants; |
171 |
- if ((p[*off]&0xf0) == 0x40) { |
|
171 |
+ if ((p[*off]&0xf0) == 0x40 || p[*off] == 0x50) { |
|
172 | 172 |
p[*off] |= 0x20; |
173 | 173 |
/* TODO: unique constants */ |
174 | 174 |
func->values = cli_realloc2(func->values, (numValues+1)*sizeof(*func->values)); |
... | ... |
@@ -229,8 +229,10 @@ static inline unsigned char *readData(const unsigned char *p, unsigned *off, uns |
229 | 229 |
} |
230 | 230 |
(*off)++; |
231 | 231 |
l = readNumber(p, off, len, ok); |
232 |
- if (!l) |
|
232 |
+ if (!l) { |
|
233 |
+ *datalen = l; |
|
233 | 234 |
return NULL; |
235 |
+ } |
|
234 | 236 |
newoff = *off + l; |
235 | 237 |
if (newoff > len) { |
236 | 238 |
cli_errmsg("Line ended while reading data\n"); |
... | ... |
@@ -610,7 +612,6 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx) |
610 | 610 |
{ |
611 | 611 |
struct cli_bc_inst inst; |
612 | 612 |
struct cli_bc_func func; |
613 |
- struct cli_bc_value value; |
|
614 | 613 |
unsigned i; |
615 | 614 |
if (!ctx || !ctx->bc || !ctx->func) |
616 | 615 |
return CL_ENULLARG; |
... | ... |
@@ -624,13 +625,14 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx) |
624 | 624 |
} |
625 | 625 |
memset(&func, 0, sizeof(func)); |
626 | 626 |
func.values = ctx->values; |
627 |
+ func.numInsts = 1; |
|
627 | 628 |
|
628 | 629 |
inst.opcode = OP_CALL_DIRECT; |
629 | 630 |
inst.type = 0;/* TODO: support toplevel functions with return values */ |
630 | 631 |
inst.u.ops.numOps = ctx->numParams; |
631 | 632 |
inst.u.ops.funcid = ctx->funcid; |
632 | 633 |
inst.u.ops.ops = ctx->operands; |
633 |
- return cli_vm_execute(ctx->bc, ctx, &func, &inst, &value); |
|
634 |
+ return cli_vm_execute(ctx->bc, ctx, &func, &inst, func.values); |
|
634 | 635 |
} |
635 | 636 |
|
636 | 637 |
void cli_bytecode_destroy(struct cli_bc *bc) |
... | ... |
@@ -57,6 +57,35 @@ struct stack_entry { |
57 | 57 |
unsigned bb_inst; |
58 | 58 |
}; |
59 | 59 |
|
60 |
+ |
|
61 |
+/* Get the operand of a binary operator, upper bits |
|
62 |
+ * (beyond the size of the operand) may have random values. |
|
63 |
+ * Use this when the active bits of the result of a binop are the same |
|
64 |
+ * regardless of the state of the inactive (high) bits of their operands. |
|
65 |
+ * For example (a + b)&mask == ((a&mask) + (b&mask)) |
|
66 |
+ * but (a / b)&mask != ((a&mask) / (b&mask)) |
|
67 |
+ * */ |
|
68 |
+#define BINOPNOMOD(i) (values[inst->u.binop[i]].v) |
|
69 |
+#define UNOPNOMOD(i) (values[inst->u.binop[i]].v) |
|
70 |
+ |
|
71 |
+/* get the operand of a binary operator, upper bits are cleared */ |
|
72 |
+#define BINOP(i) (BINOPNOMOD(i)&((1 << inst->type)-1)) |
|
73 |
+#define UNOP(x) (UNOPNOMOD(i)&((1 << inst->type)-1)) |
|
74 |
+ |
|
75 |
+/* get the operand as a signed value */ |
|
76 |
+#define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type)) |
|
77 |
+#define BINOPS(i) SIGNEXT(BINOPNOMOD(i)) |
|
78 |
+ |
|
79 |
+static void jump(struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, struct cli_bc_inst **inst, |
|
80 |
+ struct cli_bc_value **value, unsigned *bb_inst) |
|
81 |
+{ |
|
82 |
+ CHECK_GT(func->numBB, bbid); |
|
83 |
+ *bb = &func->BB[bbid]; |
|
84 |
+ *inst = (*bb)->insts; |
|
85 |
+ *value = &func->values[*inst - func->allinsts]; |
|
86 |
+ *bb_inst = 0; |
|
87 |
+} |
|
88 |
+ |
|
60 | 89 |
int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst, struct cli_bc_value *value) |
61 | 90 |
{ |
62 | 91 |
unsigned i, stack_depth=0, bb_inst=0, stop=0; |
... | ... |
@@ -68,33 +97,93 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
68 | 68 |
do { |
69 | 69 |
switch (inst->opcode) { |
70 | 70 |
case OP_ADD: |
71 |
- values->v = values[inst->u.binop[0]].v + values[inst->u.binop[1]].v; |
|
71 |
+ values->v = BINOPNOMOD(0) + BINOPNOMOD(1); |
|
72 | 72 |
break; |
73 | 73 |
case OP_SUB: |
74 |
- values->v = values[inst->u.binop[0]].v - values[inst->u.binop[1]].v; |
|
74 |
+ values->v = BINOPNOMOD(0) - BINOPNOMOD(1); |
|
75 | 75 |
break; |
76 | 76 |
case OP_MUL: |
77 |
- values->v = values[inst->u.binop[0]].v * values[inst->u.binop[1]].v; |
|
77 |
+ values->v = BINOPNOMOD(0) * BINOPNOMOD(1); |
|
78 |
+ break; |
|
79 |
+ case OP_UDIV: |
|
80 |
+ { |
|
81 |
+ uint64_t d = BINOP(1); |
|
82 |
+ if (UNLIKELY(!d)) |
|
83 |
+ return CL_EBYTECODE; |
|
84 |
+ values->v = BINOP(0) / d; |
|
85 |
+ break; |
|
86 |
+ } |
|
87 |
+ case OP_SDIV: |
|
88 |
+ { |
|
89 |
+ int64_t a = BINOPS(0); |
|
90 |
+ int64_t b = BINOPS(1); |
|
91 |
+ if (UNLIKELY(b == 0 || (b == -1 && a == (-9223372036854775807LL-1LL)))) |
|
92 |
+ return CL_EBYTECODE; |
|
93 |
+ values->v = a / b; |
|
94 |
+ break; |
|
95 |
+ } |
|
96 |
+ case OP_UREM: |
|
97 |
+ { |
|
98 |
+ uint64_t d = BINOP(1); |
|
99 |
+ if (UNLIKELY(!d)) |
|
100 |
+ return CL_EBYTECODE; |
|
101 |
+ values->v = BINOP(0) % d; |
|
102 |
+ break; |
|
103 |
+ } |
|
104 |
+ case OP_SREM: |
|
105 |
+ { |
|
106 |
+ int64_t a = BINOPS(0); |
|
107 |
+ int64_t b = BINOPS(1); |
|
108 |
+ if (UNLIKELY(b == 0 || (b == -1 && (a == -9223372036854775807LL-1LL)))) |
|
109 |
+ return CL_EBYTECODE; |
|
110 |
+ values->v = a % b; |
|
111 |
+ break; |
|
112 |
+ } |
|
113 |
+ case OP_SHL: |
|
114 |
+ values->v = BINOPNOMOD(0) << BINOP(1); |
|
78 | 115 |
break; |
116 |
+ case OP_LSHR: |
|
117 |
+ values->v = BINOP(0) >> BINOP(1); |
|
118 |
+ break; |
|
119 |
+ case OP_ASHR: |
|
120 |
+ { |
|
121 |
+ int64_t v = BINOPS(0); |
|
122 |
+ values->v = CLI_SRS(v, BINOP(1)); |
|
123 |
+ break; |
|
124 |
+ } |
|
79 | 125 |
case OP_AND: |
80 |
- values->v = values[inst->u.binop[0]].v & values[inst->u.binop[1]].v; |
|
126 |
+ values->v = BINOPNOMOD(0) & BINOPNOMOD(1); |
|
81 | 127 |
break; |
82 | 128 |
case OP_OR: |
83 |
- values->v = values[inst->u.binop[0]].v | values[inst->u.binop[1]].v; |
|
129 |
+ values->v = BINOPNOMOD(0) | BINOPNOMOD(1); |
|
84 | 130 |
break; |
85 | 131 |
case OP_XOR: |
86 |
- values->v = values[inst->u.binop[0]].v ^ values[inst->u.binop[1]].v; |
|
132 |
+ values->v = BINOPNOMOD(0) ^ BINOPNOMOD(1); |
|
133 |
+ break; |
|
134 |
+ case OP_SEXT: |
|
135 |
+ values->v = SIGNEXT(values[inst->u.cast.source].v); |
|
87 | 136 |
break; |
88 |
- case OP_ZEXT: |
|
89 | 137 |
case OP_TRUNC: |
138 |
+ /* fall-through */ |
|
139 |
+ case OP_ZEXT: |
|
90 | 140 |
values->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v; |
91 | 141 |
break; |
142 |
+ case OP_BRANCH: |
|
143 |
+ jump(func, (values[inst->u.branch.condition].v&1) ? |
|
144 |
+ inst->u.branch.br_true : inst->u.branch.br_false, |
|
145 |
+ &bb, &inst, &value, &bb_inst); |
|
146 |
+ continue; |
|
147 |
+ case OP_JMP: |
|
148 |
+ jump(func, inst->u.jump, &bb, &inst, &value, &bb_inst); |
|
149 |
+ continue; |
|
92 | 150 |
case OP_RET: |
93 | 151 |
CHECK_GT(stack_depth, 0); |
94 | 152 |
stack_depth--; |
95 | 153 |
value = stack[stack_depth].ret; |
96 |
- value->v = values[inst->u.unaryop].v; |
|
97 | 154 |
func = stack[stack_depth].func; |
155 |
+ CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value); |
|
156 |
+ CHECK_GT(value, &func->values[-1]); |
|
157 |
+ value->v = values[inst->u.unaryop].v; |
|
98 | 158 |
values = func->values; |
99 | 159 |
if (!stack[stack_depth].bb) { |
100 | 160 |
stop = CL_BREAK; |
... | ... |
@@ -106,10 +195,37 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
106 | 106 |
inst = &bb->insts[bb_inst]; |
107 | 107 |
break; |
108 | 108 |
case OP_ICMP_EQ: |
109 |
- value->v = values[inst->u.binop[0]].v == values[inst->u.binop[1]].v ? 1 : 0; |
|
109 |
+ value->v = BINOP(0) == BINOP(1) ? 1 : 0; |
|
110 |
+ break; |
|
111 |
+ case OP_ICMP_NE: |
|
112 |
+ value->v = BINOP(0) != BINOP(1) ? 1 : 0; |
|
113 |
+ break; |
|
114 |
+ case OP_ICMP_UGT: |
|
115 |
+ value->v = BINOP(0) > BINOP(1) ? 1 : 0; |
|
116 |
+ break; |
|
117 |
+ case OP_ICMP_UGE: |
|
118 |
+ value->v = BINOP(0) >= BINOP(1) ? 1 : 0; |
|
119 |
+ break; |
|
120 |
+ case OP_ICMP_ULT: |
|
121 |
+ value->v = BINOP(0) < BINOP(1) ? 1 : 0; |
|
122 |
+ break; |
|
123 |
+ case OP_ICMP_ULE: |
|
124 |
+ value->v = BINOP(0) <= BINOP(1) ? 1 : 0; |
|
125 |
+ break; |
|
126 |
+ case OP_ICMP_SGT: |
|
127 |
+ value->v = BINOPS(0) > BINOPS(1) ? 1 : 0; |
|
128 |
+ break; |
|
129 |
+ case OP_ICMP_SGE: |
|
130 |
+ value->v = BINOPS(0) >= BINOPS(1) ? 1 : 0; |
|
131 |
+ break; |
|
132 |
+ case OP_ICMP_SLE: |
|
133 |
+ value->v = BINOPS(0) <= BINOPS(1) ? 1 : 0; |
|
134 |
+ break; |
|
135 |
+ case OP_ICMP_SLT: |
|
136 |
+ value->v = BINOPS(0) < BINOPS(1) ? 1 : 0; |
|
110 | 137 |
break; |
111 | 138 |
case OP_SELECT: |
112 |
- values->v = values[inst->u.three[0]].v ? |
|
139 |
+ values->v = (values[inst->u.three[0]].v&1) ? |
|
113 | 140 |
values[inst->u.three[1]].v : values[inst->u.three[2]].v; |
114 | 141 |
break; |
115 | 142 |
case OP_CALL_DIRECT: |
... | ... |
@@ -126,13 +242,15 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func |
126 | 126 |
stack[stack_depth].bb = bb; |
127 | 127 |
stack[stack_depth].bb_inst = bb_inst; |
128 | 128 |
stack_depth++; |
129 |
+ cli_dbgmsg("Executing %d\n", inst->u.ops.funcid); |
|
129 | 130 |
func = func2; |
130 | 131 |
values = func->values; |
131 | 132 |
CHECK_GT(func->numBB, 0); |
132 |
- bb = &func->BB[0]; |
|
133 |
- inst = &bb->insts[0]; |
|
134 |
- bb_inst = 0; |
|
133 |
+ jump(func, 0, &bb, &inst, &value, &bb_inst); |
|
135 | 134 |
continue; |
135 |
+ case OP_COPY: |
|
136 |
+ BINOPNOMOD(1) = BINOPNOMOD(0); |
|
137 |
+ break; |
|
136 | 138 |
default: |
137 | 139 |
cli_errmsg("Opcode %u is not implemented yet!\n", inst->opcode); |
138 | 140 |
stop = CL_EARG; |
... | ... |
@@ -259,6 +259,8 @@ const char *cl_strerror(int clerror) |
259 | 259 |
return "CL_EMAXFILES"; |
260 | 260 |
case CL_EFORMAT: |
261 | 261 |
return "CL_EFORMAT: Bad format or broken data"; |
262 |
+ case CL_EBYTECODE: |
|
263 |
+ return "CL_EBYTECODE: error during bytecode execution"; |
|
262 | 264 |
default: |
263 | 265 |
return "Unknown error code"; |
264 | 266 |
} |