Added more tests, function calls work

Fixed a bunch of bugs in other opcodes, too
This commit is contained in:
Mitchell Plamann
2015-03-28 19:14:10 -04:00
parent 6774610569
commit 9159cf1389
28 changed files with 412 additions and 28 deletions

View File

@@ -1,10 +1,17 @@
op = require("./opcodes");
var INT_MIN = 0x80000000;
var INT_MAX = 0x7FFFFFFF;
var verbose = false;
function log(message) {
if (verbose) console.log(message);
}
function c0_assertion_failure(val) {
throw "c0 assertion failure: " + val;
}
var StackFrame = function(file, f) {
log("Creating stack frame");
this.stack = [];
@@ -12,7 +19,7 @@ var StackFrame = function(file, f) {
this.program = f.code;
this.variables = [];
for (var i = 0; i < f.num_vars; i++)
variables.push(0);
this.variables.push(0);
this.file = file;
}
@@ -21,7 +28,7 @@ var ProgramState = function(parsed_file) {
var main_function = parsed_file.function_pool[0];
this.frame = new StackFrame(parsed_file, parsed_file.function_pool[0]);
this.call_stack = [this.frame];
this.call_stack = [];
this.file = parsed_file;
}
@@ -33,13 +40,23 @@ ProgramState.prototype.pop = function() {
return this.frame.stack.pop();
}
ProgramState.prototype.goto_offset = function() {
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2]
var address_offset = (c1 << 8) + c2;
// Handle negative values
if ((address_offset & 0x8000) != 0)
address_offset = -0x8000 + (address_offset & 0x7FFF);
this.frame.pc += address_offset;
}
ProgramState.prototype.doIf = function(f) {
var y = this.pop();
var x = this.pop();
if (f(x,y)) {
var address_offset = (this.frame.program[this.frame.pc+1] * 0x1000) +
this.frame.program[this.frame.pc+2];
this.frame.pc += address_offset;
this.goto_offset();
} else {
this.frame.pc += 3;
}
@@ -47,7 +64,7 @@ ProgramState.prototype.doIf = function(f) {
ProgramState.prototype.step = function() {
var opcode = this.frame.program[this.frame.pc]
log("Running opcode " +
log("0x" + this.frame.pc.toString(16) + " Running opcode " +
op.lookup_table[opcode]);
switch (opcode) {
// Stack manipulation
@@ -81,8 +98,13 @@ ProgramState.prototype.step = function() {
// Returning from a function
case op.RETURN:
var retVal = this.pop();
throw retVal;
if (this.call_stack.length == 0)
throw retVal;
this.frame = this.call_stack.pop();
this.push(retVal);
break;
// Arithmetic
case op.IADD:
this.frame.pc++;
@@ -200,20 +222,20 @@ ProgramState.prototype.step = function() {
case op.IF_CMPNE:
this.doIf(function (x,y) {return y != x;});
break;
case op.IF_CMPLT:
case op.IF_ICMPLT:
this.doIf(function (x,y) {return y > x;});
break;
case op.IF_CMPGE:
case op.IF_ICMPGE:
this.doIf(function (x,y) {return y <= x;});
break;
case op.IF_CMPGT:
case op.IF_ICMPGT:
this.doIf(function (x,y) {return y < x;});
break;
case op.IF_CMPLE:
case op.IF_ICMPLE:
this.doIf(function (x,y) {return y >= x;});
break;
case op.GOTO:
this.doIf(function (x,y) {return true;});
this.goto_offset();
break;
case op.ATHROW:
this.frame.pc++;
@@ -226,8 +248,34 @@ ProgramState.prototype.step = function() {
c0_assertion_failure(a);
break;
// Function call operations
case op.INVOKESTATIC:
var c1 = this.frame.program[this.frame.pc+1];
var c2 = this.frame.program[this.frame.pc+2];
this.frame.pc += 3;
var index = (c1 << 8) + c2;
var f = this.file.function_pool[index];
var newFrame = new StackFrame(this.file, f);
for (var i = f.num_args - 1; i >= 0; i--) {
newFrame.variables[i] = this.pop();
}
this.call_stack.push(this.frame);
this.frame = newFrame;
break;
default:
console.log("Error: Unknown opcode: 0x" + opcode.toString(16) + "\n");
var opcode_name;
try {
opcode_name = op.lookup_table[opcode];
} catch (ignored) {
opcode_name = "UNKNOWN";
}
console.log("Error: Unknown opcode: 0x" + opcode.toString(16) +
" (" + opcode_name + ")\n");
throw "Error - unknown opcode";
}
return false;

View File

@@ -90,12 +90,12 @@ exports.lookup_table = {
0x13: "ILDC",
0x14: "ALDC",
0x00: "NOP",
0x9F: "IF",
0xA0: "IF",
0xA1: "IF",
0xA2: "IF",
0xA3: "IF",
0xA4: "IF",
0x9F: "IF_CMPEQ",
0xA0: "IF_CMPNE",
0xA1: "IF_ICMPLT",
0xA2: "IF_ICMPGE",
0xA3: "IF_ICMPGT",
0xA4: "IF_ICMPLE",
0xA7: "GOTO",
0xBF: "ATHROW",
0xCF: "ASSERT",

23
test/dsquared.c0 Normal file
View File

@@ -0,0 +1,23 @@
int dsquared(int x, int y)
{
return x*x + y*y;
}
int main ()
{
int a1 = 15;
int b1 = 122;
int a2 = 42;
int b2 = 0;
int a3 = -7;
int b3 = -11;
int a4 = -4;
int b4 = 3;
int sum = 0;
sum = sum + dsquared(a1,b1);
sum = sum + dsquared(a2,b2);
sum = sum + dsquared(a3,b3);
sum = sum + dsquared(a4,b4);
return sum;
}

78
test/dsquared.c0.bc0 Normal file
View File

@@ -0,0 +1,78 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 00 # string pool total size
# string pool
00 02 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 09 # number of local variables = 9
00 57 # code length = 87 bytes
10 0F # bipush 15 # 15
36 00 # vstore 0 # a1 = 15;
10 7A # bipush 122 # 122
36 01 # vstore 1 # b1 = 122;
10 2A # bipush 42 # 42
36 02 # vstore 2 # a2 = 42;
10 00 # bipush 0 # 0
36 03 # vstore 3 # b2 = 0;
10 F9 # bipush -7 # -7
36 04 # vstore 4 # a3 = -(7);
10 F5 # bipush -11 # -11
36 05 # vstore 5 # b3 = -(11);
10 FC # bipush -4 # -4
36 06 # vstore 6 # a4 = -(4);
10 03 # bipush 3 # 3
36 07 # vstore 7 # b4 = 3;
10 00 # bipush 0 # 0
36 08 # vstore 8 # sum = 0;
15 08 # vload 8 # sum
15 00 # vload 0 # a1
15 01 # vload 1 # b1
B8 00 01 # invokestatic 1 # dsquared(a1, b1)
60 # iadd # (sum + dsquared(a1, b1))
36 08 # vstore 8 # sum = (sum + dsquared(a1, b1));
15 08 # vload 8 # sum
15 02 # vload 2 # a2
15 03 # vload 3 # b2
B8 00 01 # invokestatic 1 # dsquared(a2, b2)
60 # iadd # (sum + dsquared(a2, b2))
36 08 # vstore 8 # sum = (sum + dsquared(a2, b2));
15 08 # vload 8 # sum
15 04 # vload 4 # a3
15 05 # vload 5 # b3
B8 00 01 # invokestatic 1 # dsquared(a3, b3)
60 # iadd # (sum + dsquared(a3, b3))
36 08 # vstore 8 # sum = (sum + dsquared(a3, b3));
15 08 # vload 8 # sum
15 06 # vload 6 # a4
15 07 # vload 7 # b4
B8 00 01 # invokestatic 1 # dsquared(a4, b4)
60 # iadd # (sum + dsquared(a4, b4))
36 08 # vstore 8 # sum = (sum + dsquared(a4, b4));
15 08 # vload 8 # sum
B0 # return #
#<dsquared>
00 02 # number of arguments = 2
00 02 # number of local variables = 2
00 0C # code length = 12 bytes
15 00 # vload 0 # x
15 00 # vload 0 # x
68 # imul # (x * x)
15 01 # vload 1 # y
15 01 # vload 1 # y
68 # imul # (y * y)
60 # iadd # ((x * x) + (y * y))
B0 # return #
00 00 # native count
# native pool

1
test/dsquared.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
17068

1
test/dsquared.c0.c0out Normal file
View File

@@ -0,0 +1 @@
17068

BIN
test/dsquared.c0.ex Executable file

Binary file not shown.

10
test/isqrt.c0 Normal file
View File

@@ -0,0 +1,10 @@
int main () {
int n = 15122;
int i = 0; int k = 0;
while (k <= n) {
k += 2*i + 1;
i++;
}
return i-1;
}

51
test/isqrt.c0.bc0 Normal file
View File

@@ -0,0 +1,51 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 01 # int pool count
# int pool
00 00 3B 12
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 03 # number of local variables = 3
00 34 # code length = 52 bytes
13 00 00 # ildc 0 # c[0] = 15122
36 00 # vstore 0 # n = 15122;
10 00 # bipush 0 # 0
36 01 # vstore 1 # i = 0;
10 00 # bipush 0 # 0
36 02 # vstore 2 # k = 0;
# <00:loop>
15 02 # vload 2 # k
15 00 # vload 0 # n
A4 00 06 # if_icmple +6 # if (k <= n) goto <01:body>
A7 00 1A # goto +26 # goto <02:exit>
# <01:body>
15 02 # vload 2 # k
10 02 # bipush 2 # 2
15 01 # vload 1 # i
68 # imul # (2 * i)
10 01 # bipush 1 # 1
60 # iadd # ((2 * i) + 1)
60 # iadd #
36 02 # vstore 2 # k += ((2 * i) + 1);
15 01 # vload 1 # i
10 01 # bipush 1 # 1
60 # iadd #
36 01 # vstore 1 # i += 1;
A7 FF E2 # goto -30 # goto <00:loop>
# <02:exit>
15 01 # vload 1 # i
10 01 # bipush 1 # 1
64 # isub # (i - 1)
B0 # return #
00 00 # native count
# native pool

0
test/isqrt.c0.bc0out Normal file
View File

1
test/isqrt.c0.c0out Normal file
View File

@@ -0,0 +1 @@
122

BIN
test/isqrt.c0.ex Executable file

Binary file not shown.

10
test/mid.c0 Normal file
View File

@@ -0,0 +1,10 @@
int main()
{
int low = 0x15;
int high = 0x122;
int mid;
mid = low + (high - low)/2;
return mid;
}

35
test/mid.c0.bc0 Normal file
View File

@@ -0,0 +1,35 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 01 # int pool count
# int pool
00 00 01 22
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 03 # number of local variables = 3
00 19 # code length = 25 bytes
10 15 # bipush 21 # 21
36 00 # vstore 0 # low = 21;
13 00 00 # ildc 0 # c[0] = 290
36 01 # vstore 1 # high = 290;
15 00 # vload 0 # low
15 01 # vload 1 # high
15 00 # vload 0 # low
64 # isub # (high - low)
10 02 # bipush 2 # 2
6C # idiv # ((high - low) / 2)
60 # iadd # (low + ((high - low) / 2))
36 02 # vstore 2 # mid = (low + ((high - low) / 2));
15 02 # vload 2 # mid
B0 # return #
00 00 # native count
# native pool

1
test/mid.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
155

1
test/mid.c0.c0out Normal file
View File

@@ -0,0 +1 @@
155

BIN
test/mid.c0.ex Executable file

Binary file not shown.

7
test/sample2.5.c0 Normal file
View File

@@ -0,0 +1,7 @@
int main () {
int i; int sum = 0;
for (i = 15; i <= 122; i++)
sum += i;
assert(sum == 0);
return sum;
}

55
test/sample2.5.c0.bc0 Normal file
View File

@@ -0,0 +1,55 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 25 # string pool total size
# string pool
73 61 6D 70 6C 65 32 2E 35 2E 63 30 3A 35 2E 32 2D 35 2E 31 39 3A 20 61 73 73 65 72 74 20 66 61 69 6C 65 64 00 # "sample2.5.c0:5.2-5.19: assert failed"
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 02 # number of local variables = 2
00 3B # code length = 59 bytes
10 00 # bipush 0 # 0
36 01 # vstore 1 # sum = 0;
10 0F # bipush 15 # 15
36 00 # vstore 0 # i = 15;
# <00:loop>
15 00 # vload 0 # i
10 7A # bipush 122 # 122
A4 00 06 # if_icmple +6 # if (i <= 122) goto <01:body>
A7 00 14 # goto +20 # goto <02:exit>
# <01:body>
15 01 # vload 1 # sum
15 00 # vload 0 # i
60 # iadd #
36 01 # vstore 1 # sum += i;
15 00 # vload 0 # i
10 01 # bipush 1 # 1
60 # iadd #
36 00 # vstore 0 # i += 1;
A7 FF E8 # goto -24 # goto <00:loop>
# <02:exit>
15 01 # vload 1 # sum
10 00 # bipush 0 # 0
9F 00 06 # if_cmpeq +6 # if (sum == 0) goto <03:cond_true>
A7 00 08 # goto +8 # goto <04:cond_false>
# <03:cond_true>
10 01 # bipush 1 # true
A7 00 05 # goto +5 # goto <05:cond_end>
# <04:cond_false>
10 00 # bipush 0 # false
# <05:cond_end>
14 00 00 # aldc 0 # s[0] = "sample2.5.c0:5.2-5.19: assert failed"
CF # assert # assert(sum == 0) [failure message on stack]
15 01 # vload 1 # sum
B0 # return #
00 00 # native count
# native pool

0
test/sample2.5.c0.bc0out Normal file
View File

0
test/sample2.5.c0.c0out Normal file
View File

BIN
test/sample2.5.c0.ex Executable file

Binary file not shown.

8
test/testif.c0 Normal file
View File

@@ -0,0 +1,8 @@
int main() {
int x = 4;
if (x < 3)
x = 23;
else
x = 32;
return x;
}

36
test/testif.c0.bc0 Normal file
View File

@@ -0,0 +1,36 @@
C0 C0 FF EE # magic number
00 09 # version 4, arch = 1 (64 bits)
00 00 # int pool count
# int pool
00 00 # string pool total size
# string pool
00 01 # function count
# function_pool
#<main>
00 00 # number of arguments = 0
00 01 # number of local variables = 1
00 1C # code length = 28 bytes
10 04 # bipush 4 # 4
36 00 # vstore 0 # x = 4;
15 00 # vload 0 # x
10 03 # bipush 3 # 3
A1 00 06 # if_icmplt +6 # if (x < 3) goto <00:then>
A7 00 0A # goto +10 # goto <01:else>
# <00:then>
10 17 # bipush 23 # 23
36 00 # vstore 0 # x = 23;
A7 00 07 # goto +7 # goto <02:endif>
# <01:else>
10 20 # bipush 32 # 32
36 00 # vstore 0 # x = 32;
# <02:endif>
15 00 # vload 0 # x
B0 # return #
00 00 # native count
# native pool

1
test/testif.c0.bc0out Normal file
View File

@@ -0,0 +1 @@
32

1
test/testif.c0.c0out Normal file
View File

@@ -0,0 +1 @@
32

BIN
test/testif.c0.ex Executable file

Binary file not shown.

View File

@@ -3,12 +3,17 @@ c0vm = require("../src/c0vm.js")
var callbacks = {}
// Tests that IADD, BIPUSH, and RETURN (from main) work
exports.testIADD = function(test) {
var result = c0vm.execute(parser.parse("iadd.c0.bc0"), callbacks, false);
test.ok(result == -2, "iadd.c0.bc0 - Error in IADD, BIPUSH, or RETURN");
test.done();
};
function doTest(filename, expected_result) {
return function(test) {
var result = c0vm.execute(parser.parse(filename), callbacks, false);
test.ok(result == expected_result,
filename + " - did not get expected result " + expected_result +
", instead got " + result);
test.done();
}
}
exports.testIADD = doTest("iadd.c0.bc0", -2);
exports.testPrint = function(test) {
var result = c0vm.execute(parser.parse("test.bc0"), callbacks, false);
@@ -16,8 +21,19 @@ exports.testPrint = function(test) {
test.done();
}
exports.testISHR = function(test) {
var result = c0vm.execute(parser.parse("ishr.c0.bc0"), callbacks, false);
test.ok(result == -1, "ishr.c0.bc0 - -1 >> 1 gave " + result + ", not -1");
exports.testISHR = doTest("ishr.c0.bc0", -1);
exports.testISQRT = doTest("isqrt.c0.bc0", 122);
exports.testMID = doTest("mid.c0.bc0", 155);
// This one should throw an exception because an assertion fails
exports.testSample25 = function(test) {
test.throws(c0vm.execute(parser.parse("sample2.5.c0.bc0"), callbacks, false));
test.done();
}
exports.testIF = doTest("testif.c0.bc0", 32);
exports.testDSQUARED = doTest("dsquared.c0.bc0", 17068);