Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e0529a1e0 | ||
|
|
44f10cb5c6 | ||
|
|
d035346d2b | ||
|
|
5bee4d90c5 |
0
logo.png
Executable file → Normal file
0
logo.png
Executable file → Normal file
|
Before Width: | Height: | Size: 345 KiB After Width: | Height: | Size: 345 KiB |
0
progress_report/lit_review.tex
Executable file → Normal file
0
progress_report/lit_review.tex
Executable file → Normal file
0
proposal/letter.pdf
Executable file → Normal file
0
proposal/letter.pdf
Executable file → Normal file
0
proposal/letter.tex
Executable file → Normal file
0
proposal/letter.tex
Executable file → Normal file
0
proposal/proposal.pdf
Executable file → Normal file
0
proposal/proposal.pdf
Executable file → Normal file
0
proposal/proposal.tex
Executable file → Normal file
0
proposal/proposal.tex
Executable file → Normal file
0
public/vm/byte-stream.js
Executable file → Normal file
0
public/vm/byte-stream.js
Executable file → Normal file
@@ -4,21 +4,8 @@ byte_stream = require("./byte-stream");
|
||||
// This is a simple, kinda hacky bytecode parser for .bc0 files
|
||||
// Now takes in raw bytecode
|
||||
function getBytes(data) {
|
||||
/*
|
||||
var data = fs.readFileSync(filename);
|
||||
|
||||
if (data == null) {
|
||||
if (err["code"] === "ENOENT")
|
||||
console.log("Error: file " + filename + " does not exist.");
|
||||
else
|
||||
console.log("Error: " + err);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// Data contains our file, but we want it as a string
|
||||
var string_data = data.toString();
|
||||
console.log(string_data);
|
||||
|
||||
// Strip all the comments for easier parsing
|
||||
var without_comments = string_data.replace(new RegExp("#.*", "gi"), "");
|
||||
@@ -33,15 +20,37 @@ function getBytes(data) {
|
||||
});
|
||||
|
||||
// We now have an array of bytes. That's probably everything we need, right?
|
||||
console.log(bytes);
|
||||
return bytes;
|
||||
|
||||
}
|
||||
|
||||
function getLineNumbers(data) {
|
||||
var string_data = data.toString();
|
||||
|
||||
// Strip all the comments for easier parsing
|
||||
var without_comments = string_data.replace(new RegExp("#.*", "gi"), "");
|
||||
|
||||
// Each byte should now be a pair of two hex digits.
|
||||
// Put all these in an array.
|
||||
var lines = without_comments.split("\n");
|
||||
var line_numbers = [];
|
||||
for (var line_number = 0; line_number < lines.length; line_number++ ) {
|
||||
lines[line_number].replace(
|
||||
new RegExp("([0123456789ABCDEF][0123456789ABCDEF])", "gi"),
|
||||
function(next_byte) {
|
||||
// +1 because lines start at 1, for some weird reason.
|
||||
// Who doesn't start counting at 0?
|
||||
line_numbers.push(line_number+1);
|
||||
});
|
||||
}
|
||||
return line_numbers;
|
||||
}
|
||||
|
||||
var FunctionInfo = function (stream) {
|
||||
this.num_args = stream.get_u2();
|
||||
this.num_vars = stream.get_u2();
|
||||
this.code_length = stream.get_u2();
|
||||
this.code_byte_offset = stream.index;
|
||||
this.code = stream.get_bytes(this.code_length);
|
||||
}
|
||||
|
||||
@@ -50,8 +59,9 @@ var NativeInfo = function (stream) {
|
||||
this.function_table_index = stream.get_u2();
|
||||
}
|
||||
|
||||
var Bc0File = function (filename) {
|
||||
var file = getBytes(filename);
|
||||
var Bc0File = function (bytecode) {
|
||||
var file = getBytes(bytecode);
|
||||
this.line_numbers = getLineNumbers(bytecode);
|
||||
var stream = new byte_stream.ByteStream(file);
|
||||
|
||||
var magic = stream.get_u4();
|
||||
@@ -109,9 +119,50 @@ Bc0File.prototype.string_from_index = function (i) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function parse(filename) {
|
||||
return new Bc0File(filename);
|
||||
Bc0File.prototype.line_for_indices = function(function_index, byte_offset) {
|
||||
var offset_in_file = this.function_pool[function_index].code_byte_offset +
|
||||
byte_offset;
|
||||
return this.line_numbers[offset_in_file];
|
||||
}
|
||||
|
||||
Bc0File.prototype.indicies_for_line = function(line) {
|
||||
// Performs a linear search through the (bytecode to line number) map
|
||||
// to find the bytecode offsets corresponding to a line number
|
||||
var function_index = 0;
|
||||
while (function_index < this.function_pool.length - 1) {
|
||||
var function_start = this.function_pool[function_index + 1].code_byte_offset;
|
||||
if (this.line_numbers[function_start] > line) break;
|
||||
function_start++;
|
||||
}
|
||||
|
||||
// function_index should now be set to the index of the function containing our line
|
||||
var f = this.function_pool[function_index];
|
||||
var offset = 0;
|
||||
while (offset < f.code.length - 1) {
|
||||
if (this.line_numbers[f.code_byte_offset + offset] > line) break;
|
||||
offset++;
|
||||
}
|
||||
return [function_index, offset];
|
||||
}
|
||||
|
||||
function parse(bytecode) {
|
||||
return new Bc0File(bytecode);
|
||||
}
|
||||
|
||||
function parseFile(filename) {
|
||||
var data = fs.readFileSync(filename);
|
||||
|
||||
if (data == null) {
|
||||
if (err["code"] === "ENOENT")
|
||||
console.log("Error: file " + filename + " does not exist.");
|
||||
else
|
||||
console.log("Error: " + err);
|
||||
return;
|
||||
}
|
||||
|
||||
return parse(data);
|
||||
}
|
||||
|
||||
exports.getBytes = getBytes;
|
||||
exports.parse = parse;
|
||||
exports.parseFile = parseFile;
|
||||
|
||||
87
public/vm/c0vm.js
Executable file → Normal file
87
public/vm/c0vm.js
Executable file → Normal file
@@ -115,9 +115,10 @@ ProgramState.prototype.doIf = function(f) {
|
||||
}
|
||||
|
||||
ProgramState.prototype.step = function() {
|
||||
this.maintain_line_numbers();
|
||||
var opcode = this.frame.program[this.frame.pc]
|
||||
log("0x" + this.frame.pc.toString(16) + " Running opcode " +
|
||||
op.lookup_table[opcode]);
|
||||
op.lookup_table[opcode] + " at line " + this.bytecode_line);
|
||||
switch (opcode) {
|
||||
// Stack manipulation
|
||||
case op.POP:
|
||||
@@ -473,12 +474,18 @@ ProgramState.prototype.step = function() {
|
||||
}
|
||||
}
|
||||
|
||||
ProgramState.prototype.maintain_line_numbers = function() {
|
||||
this.bytecode_line = this.file.line_for_indices(this.frame.function_id,
|
||||
this.frame.pc);
|
||||
// this.c0_line = SOMEHOW GET THE LINE IN THE c0 FILE
|
||||
}
|
||||
|
||||
ProgramState.prototype.remove_breakpoint = function(opcode_index) {
|
||||
if (opcode_index < 0){
|
||||
console.log("Error: negative opcode_index" + opcode_index.toString());
|
||||
throw "Error - negative opcode index";
|
||||
}
|
||||
else if (opcode_index >= this.program.length) {
|
||||
else if (opcode_index >= this.frame.program.length) {
|
||||
console.log("Error: opcode index larger than max index:"
|
||||
+ opcode_index.toString());
|
||||
throw "Error - opcode index too large";
|
||||
@@ -499,7 +506,7 @@ ProgramState.prototype.set_breakpoint = function(function_index, opcode_index) {
|
||||
console.log("Error: negative opcode_index" + opcode_index.toString());
|
||||
throw "Error - negative opcode index";
|
||||
}
|
||||
else if (opcode_index >= this.program.length) {
|
||||
else if (opcode_index >= this.frame.program.length) {
|
||||
console.log("Error: opcode index larger than max index:"
|
||||
+ opcode_index.toString());
|
||||
throw "Error - opcode index too large";
|
||||
@@ -507,6 +514,48 @@ ProgramState.prototype.set_breakpoint = function(function_index, opcode_index) {
|
||||
this.breakpoints.push([function_index, opcode_index]);
|
||||
}
|
||||
|
||||
ProgramState.prototype.set_breakpoint_bytecode_line = function(line) {
|
||||
var indicies = this.file.indicies_for_line(line);
|
||||
if (indicies === null || indicies.length < 2) {
|
||||
console.log("Error - indicies_for_line returned an invalid result.");
|
||||
}
|
||||
this.set_breakpoint(indicies[0], indicies[1]);
|
||||
}
|
||||
|
||||
ProgramState.prototype.run = function() {
|
||||
while (true) {
|
||||
for (var i = 0; i < this.breakpoints.length; i++) {
|
||||
var breakpoint = this.breakpoints[i];
|
||||
|
||||
if (this.frame.function_id == breakpoint[0] &&
|
||||
this.frame.pc == breakpoint[1] &&
|
||||
this.stopped_at !== breakpoint) {
|
||||
log("Breakpoint reached!");
|
||||
this.stopped_at = breakpoint;
|
||||
|
||||
this.maintain_line_numbers();
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
this.stopped_at = undefined;
|
||||
|
||||
var val = this.step();
|
||||
if (val !== undefined) return val;
|
||||
|
||||
if (verbose) {
|
||||
console.log("Machine this:");
|
||||
console.log(" Current Stack Frame:");
|
||||
console.log(" Stack: " + this.frame.stack);
|
||||
console.log(" PC: " + this.frame.pc);
|
||||
console.log(" Vars: " + this.frame.variables);
|
||||
// console.log(" Code: " + this.frame.program);
|
||||
console.log(" Heap: " + this.heap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initialize_vm(file, callbacks, v) {
|
||||
verbose = typeof v !== 'undefined' ? v : true;
|
||||
log("Initializing with file " + file);
|
||||
@@ -520,41 +569,11 @@ function initialize_vm(file, callbacks, v) {
|
||||
return state;
|
||||
}
|
||||
|
||||
function run_vm(vm) {
|
||||
while (true) {
|
||||
for (breakpoint in vm.breakpoints) {
|
||||
if (vm.frame.function_id == breakpoint[0] &&
|
||||
vm.frame.pc == breakpoint[1]) {
|
||||
console.log("Breakpoint reached!");
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
|
||||
var val = vm.step();
|
||||
if (val !== undefined) return val;
|
||||
|
||||
if (verbose) {
|
||||
console.log("Machine vm:");
|
||||
console.log(" Current Stack Frame:");
|
||||
console.log(" Stack: " + vm.frame.stack);
|
||||
console.log(" PC: " + vm.frame.pc);
|
||||
console.log(" Vars: " + vm.frame.variables);
|
||||
// console.log(" Code: " + vm.frame.program);
|
||||
console.log(" Heap: " + vm.heap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (at_breakpoint) {
|
||||
// save state (maybe in a global in this file?)
|
||||
// return;
|
||||
// }
|
||||
// Takes in a parsed .bc0 file and runs it
|
||||
function execute(file, callbacks, v) {
|
||||
var state = initialize_vm(file, callbacks, v);
|
||||
return run_vm(state);
|
||||
return state.run();
|
||||
}
|
||||
|
||||
exports.execute = execute;
|
||||
exports.initialize_vm = initialize_vm;
|
||||
exports.run_vm = run_vm;
|
||||
|
||||
0
public/vm/cc0.cgi
Executable file → Normal file
0
public/vm/cc0.cgi
Executable file → Normal file
0
test/abort.c0.ex
Executable file → Normal file
0
test/abort.c0.ex
Executable file → Normal file
0
test/arith.c0.ex
Executable file → Normal file
0
test/arith.c0.ex
Executable file → Normal file
0
test/arrays.c0.ex
Executable file → Normal file
0
test/arrays.c0.ex
Executable file → Normal file
0
test/dsquared.c0.ex
Executable file → Normal file
0
test/dsquared.c0.ex
Executable file → Normal file
0
test/easyMath.c0.ex
Executable file → Normal file
0
test/easyMath.c0.ex
Executable file → Normal file
0
test/hellosir.c0.ex
Executable file → Normal file
0
test/hellosir.c0.ex
Executable file → Normal file
0
test/iadd.c0
Executable file → Normal file
0
test/iadd.c0
Executable file → Normal file
0
test/iadd.c0.bc0
Executable file → Normal file
0
test/iadd.c0.bc0
Executable file → Normal file
0
test/iadd.c0.ex
Executable file → Normal file
0
test/iadd.c0.ex
Executable file → Normal file
0
test/ishr.c0.ex
Executable file → Normal file
0
test/ishr.c0.ex
Executable file → Normal file
0
test/isqrt.c0.ex
Executable file → Normal file
0
test/isqrt.c0.ex
Executable file → Normal file
0
test/mid.c0.ex
Executable file → Normal file
0
test/mid.c0.ex
Executable file → Normal file
0
test/moreArrays.c0.ex
Executable file → Normal file
0
test/moreArrays.c0.ex
Executable file → Normal file
0
test/piazza1.c0.ex
Executable file → Normal file
0
test/piazza1.c0.ex
Executable file → Normal file
0
test/sample2.5.c0.ex
Executable file → Normal file
0
test/sample2.5.c0.ex
Executable file → Normal file
0
test/strings.c0.ex
Executable file → Normal file
0
test/strings.c0.ex
Executable file → Normal file
0
test/structs.c0.ex
Executable file → Normal file
0
test/structs.c0.ex
Executable file → Normal file
0
test/testError.c0.ex
Executable file → Normal file
0
test/testError.c0.ex
Executable file → Normal file
0
test/testif.c0.ex
Executable file → Normal file
0
test/testif.c0.ex
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
parser = require("../src/bytecode-parser.js");
|
||||
c0vm = require("../src/c0vm.js");
|
||||
c0ffi = require("../src/c0ffi.js");
|
||||
parser = require("../public/vm/bytecode-parser.js");
|
||||
c0vm = require("../public/vm/c0vm.js");
|
||||
c0ffi = require("../public/vm/c0ffi.js");
|
||||
|
||||
var callbacks = c0ffi.default_callbacks;
|
||||
console.log("Initial callbacks: " + callbacks[c0ffi.NATIVE_STRING_LENGTH](["hi"]));
|
||||
@@ -23,7 +23,7 @@ callbacks[c0ffi.NATIVE_PRINTLN] = function(args) {
|
||||
|
||||
function doTest(filename, expected_result) {
|
||||
return function(test) {
|
||||
var result = c0vm.execute(parser.parse(filename), callbacks, false);
|
||||
var result = c0vm.execute(parser.parseFile(filename), callbacks, false);
|
||||
test.ok(result == expected_result,
|
||||
filename + " - did not get expected result " + expected_result +
|
||||
", instead got " + result);
|
||||
@@ -35,7 +35,7 @@ exports.testIADD = doTest("iadd.c0.bc0", -2);
|
||||
|
||||
exports.testPrint = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("test.bc0"), callbacks, false);
|
||||
var result = c0vm.execute(parser.parseFile("test.bc0"), callbacks, false);
|
||||
test.ok(printout == "Hello, world.\nYou don't look so good.\n",
|
||||
"test.bc0 - Did not print to screen correctly: output was " + printout);
|
||||
test.done();
|
||||
@@ -50,7 +50,7 @@ exports.testMID = doTest("mid.c0.bc0", 155);
|
||||
// This one should throw an exception because an assertion fails
|
||||
exports.testSample25 = function(test) {
|
||||
test.throws(function () {
|
||||
c0vm.execute(parser.parse("sample2.5.c0.bc0"), callbacks, false)
|
||||
c0vm.execute(parser.parseFile("sample2.5.c0.bc0"), callbacks, false)
|
||||
});
|
||||
test.done();
|
||||
}
|
||||
@@ -61,14 +61,14 @@ exports.testDSQUARED = doTest("dsquared.c0.bc0", 17068);
|
||||
|
||||
exports.testArrays = function(test) {
|
||||
test.throws(function () {
|
||||
c0vm.execute(parser.parse("arrays.c0.bc0"), callbacks, false)
|
||||
c0vm.execute(parser.parseFile("arrays.c0.bc0"), callbacks, false)
|
||||
});
|
||||
test.done();
|
||||
}
|
||||
|
||||
exports.testMoreArray = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("moreArrays.c0.bc0"), callbacks, false);
|
||||
var result = c0vm.execute(parser.parseFile("moreArrays.c0.bc0"), callbacks, false);
|
||||
test.ok(printout == "2312",
|
||||
"moreArrays.c0.bc0 - Did not print to screen correctly, result was " +
|
||||
printout);
|
||||
@@ -77,7 +77,7 @@ exports.testMoreArray = function(test) {
|
||||
|
||||
exports.testStructs = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("structs.c0.bc0"), callbacks, false);
|
||||
var result = c0vm.execute(parser.parseFile("structs.c0.bc0"), callbacks, false);
|
||||
test.ok(printout == "potato chip123",
|
||||
"structs.c0.bc0 - Did not print to screen correctly, result was " +
|
||||
printout);
|
||||
@@ -86,14 +86,14 @@ exports.testStructs = function(test) {
|
||||
|
||||
exports.testAbort = function(test) {
|
||||
test.throws(function () {
|
||||
c0vm.execute(parser.parse("abort.c0.bc0"), callbacks, false);
|
||||
c0vm.execute(parser.parseFile("abort.c0.bc0"), callbacks, false);
|
||||
});
|
||||
test.done();
|
||||
}
|
||||
|
||||
exports.testArith = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("arith.c0.bc0"), callbacks, false);
|
||||
var result = c0vm.execute(parser.parseFile("arith.c0.bc0"), callbacks, false);
|
||||
test.ok(printout == "-2147483648 2147483647 -375 -2147483648 -9 -1 12 \n-12 12 Modulus testing 11-1 5 1 Testing constants -251 Testing inequalities \ny1 y2 y3 n4 n5 n6 y7 Testing bitwise operators \n992000 1045310 53250 -12083 Testing bit shifting\n-2147483648 7360588088-31-19\n",
|
||||
"arith.c0.bc0 - Did not print to screen correctly, result was " +
|
||||
printout);
|
||||
@@ -104,9 +104,29 @@ exports.testPIAZZA1 = doTest("piazza1.c0.bc0", 18);
|
||||
|
||||
exports.testSTRINGS = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("strings.c0.bc0"), callbacks, false);
|
||||
var result = c0vm.execute(parser.parseFile("strings.c0.bc0"), callbacks, false);
|
||||
test.ok(printout == "hello there!?",
|
||||
"strings.c0.bc0 - Did not print to screen correctly, result was " +
|
||||
printout);
|
||||
test.done();
|
||||
}
|
||||
|
||||
exports.testBREAKPOINT1 = function(test) {
|
||||
var vm = c0vm.initialize_vm(parser.parseFile("easyMath.c0.bc0"),
|
||||
callbacks, false);
|
||||
vm.set_breakpoint(0, 4);
|
||||
var result = vm.run();
|
||||
test.ok(result === vm,
|
||||
"VM did not stop at breakpoint, instead returned " + result);
|
||||
test.ok(vm.frame.stack[0] == 23 &&
|
||||
vm.frame.stack[1] == 19,
|
||||
"VM stack incorrect");
|
||||
|
||||
test.ok(vm.bytecode_line == 19,
|
||||
"VM reports incorrect line in bytecode: " + vm.bytecode_line);
|
||||
|
||||
result = vm.run();
|
||||
test.ok(result == 1748,
|
||||
"VM did not resume operation correctly, gave result " + result);
|
||||
test.done();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user