diff --git a/public/vm/bytecode-parser.js b/public/vm/bytecode-parser.js index 1479957..2943d38 100644 --- a/public/vm/bytecode-parser.js +++ b/public/vm/bytecode-parser.js @@ -90,6 +90,7 @@ var Bc0File = function (filename) { this.function_pool = []; for (var i = 0; i < this.function_count; i++) { this.function_pool.push(new FunctionInfo(stream)); + this.function_pool[i].function_id = i; } this.native_count = stream.get_u2(); diff --git a/public/vm/c0ffi.js b/public/vm/c0ffi.js index c3ce859..d8b1412 100644 --- a/public/vm/c0ffi.js +++ b/public/vm/c0ffi.js @@ -108,3 +108,46 @@ exports.NATIVE_STRING_TERMINATED = 92 exports.NATIVE_STRING_TO_CHARARRAY = 93 exports.NATIVE_STRING_TOLOWER = 94 +callbacks = {}; +callbacks[exports.NATIVE_STRING_LENGTH] = + function(args) { + return args[0].length; + }; + +callbacks[exports.NATIVE_STRING_TO_CHARARRAY] = + function(args, vm) { + var address = vm.heap.length; + vm.heap.push(args[0].length+1); + vm.heap.push(1); + for (var i = 0; i < args[0].length; i++) { + vm.heap.push(args[0][i]); + } + vm.heap.push(0); + return address; + }; + + +callbacks[exports.NATIVE_STRING_FROM_CHARARRAY] = + function(args, vm) { + var i = args[0] + 2; + var result = ""; + while (vm.heap[i] !== 0) { + result += vm.heap[i]; + i++; + } + return result; + }; + +callbacks[exports.NATIVE_CHAR_CHR] = + function(args) { + return String.fromCharCode(args[0]); + }; + +callbacks[exports.NATIVE_CHAR_ORD] = + function(args) { + if (typeof args[0] == "string") + return args[0].charCodeAt(0); + return args[0]; + }; + +exports.default_callbacks = callbacks; diff --git a/public/vm/c0vm.js b/public/vm/c0vm.js index 827f7de..d2f9b72 100755 --- a/public/vm/c0vm.js +++ b/public/vm/c0vm.js @@ -42,6 +42,7 @@ var StackFrame = function(file, f) { this.stack = []; this.pc = 0; this.program = f.code; + this.function_id = f.function_id; this.variables = []; for (var i = 0; i < f.num_vars; i++) this.variables.push(0); @@ -69,6 +70,8 @@ var ProgramState = function(parsed_file, callback_dict) { } } + this.breakpoints = []; + // Memory is just a big array of bytes, right? // "Allocation" is appending onto this array // A pointer to memory is an index into this array. @@ -341,7 +344,7 @@ ProgramState.prototype.step = function() { } log("Calling native function with index " + index + " with arguments " + arg_array); - this.push(native_function(arg_array)); + this.push(native_function(arg_array, this)); break; // Memory allocation operations: @@ -470,8 +473,11 @@ ProgramState.prototype.step = function() { } } -// Takes in a parsed .bc0 file and runs it -function execute(file, callbacks, v) { +ProgramState.prototype.set_breakpoint = function(function_index, opcode_index) { + this.breakpoints.push([function_index, opcode_index]); +} + +function initialize_vm(file, callbacks, v) { verbose = typeof v !== 'undefined' ? v : true; log("Initializing with file " + file); @@ -481,25 +487,44 @@ function execute(file, callbacks, v) { log("Beginning execution"); + return state; +} + +function run_vm(vm) { while (true) { - var val = state.step(); + 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 state:"); + console.log("Machine vm:"); console.log(" Current Stack Frame:"); - console.log(" Stack: " + state.frame.stack); - console.log(" PC: " + state.frame.pc); - console.log(" Vars: " + state.frame.variables); - // console.log(" Code: " + state.frame.program); - console.log(" Heap: " + state.heap); + 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); } exports.execute = execute; +exports.initialize_vm = initialize_vm; +exports.run_vm = run_vm; diff --git a/public/vm/vm.js b/public/vm/vm.js index e00e72f..c8981af 100644 --- a/public/vm/vm.js +++ b/public/vm/vm.js @@ -131,6 +131,7 @@ var Bc0File = function (filename) { this.function_pool = []; for (var i = 0; i < this.function_count; i++) { this.function_pool.push(new FunctionInfo(stream)); + this.function_pool[i].function_id = i; } this.native_count = stream.get_u2(); @@ -267,6 +268,49 @@ exports.NATIVE_STRING_TERMINATED = 92 exports.NATIVE_STRING_TO_CHARARRAY = 93 exports.NATIVE_STRING_TOLOWER = 94 +callbacks = {}; +callbacks[exports.NATIVE_STRING_LENGTH] = + function(args) { + return args[0].length; + }; + +callbacks[exports.NATIVE_STRING_TO_CHARARRAY] = + function(args, vm) { + var address = vm.heap.length; + vm.heap.push(args[0].length+1); + vm.heap.push(1); + for (var i = 0; i < args[0].length; i++) { + vm.heap.push(args[0][i]); + } + vm.heap.push(0); + return address; + }; + + +callbacks[exports.NATIVE_STRING_FROM_CHARARRAY] = + function(args, vm) { + var i = args[0] + 2; + var result = ""; + while (vm.heap[i] !== 0) { + result += vm.heap[i]; + i++; + } + return result; + }; + +callbacks[exports.NATIVE_CHAR_CHR] = + function(args) { + return String.fromCharCode(args[0]); + }; + +callbacks[exports.NATIVE_CHAR_ORD] = + function(args) { + if (typeof args[0] == "string") + return args[0].charCodeAt(0); + return args[0]; + }; + +exports.default_callbacks = callbacks; },{}],4:[function(require,module,exports){ op = require("./opcodes"); @@ -313,6 +357,7 @@ var StackFrame = function(file, f) { this.stack = []; this.pc = 0; this.program = f.code; + this.function_id = f.function_id; this.variables = []; for (var i = 0; i < f.num_vars; i++) this.variables.push(0); @@ -340,6 +385,8 @@ var ProgramState = function(parsed_file, callback_dict) { } } + this.breakpoints = []; + // Memory is just a big array of bytes, right? // "Allocation" is appending onto this array // A pointer to memory is an index into this array. @@ -612,7 +659,7 @@ ProgramState.prototype.step = function() { } log("Calling native function with index " + index + " with arguments " + arg_array); - this.push(native_function(arg_array)); + this.push(native_function(arg_array, this)); break; // Memory allocation operations: @@ -741,8 +788,11 @@ ProgramState.prototype.step = function() { } } -// Takes in a parsed .bc0 file and runs it -function execute(file, callbacks, v) { +ProgramState.prototype.set_breakpoint = function(function_index, opcode_index) { + this.breakpoints.push([function_index, opcode_index]); +} + +function initialize_vm(file, callbacks, v) { verbose = typeof v !== 'undefined' ? v : true; log("Initializing with file " + file); @@ -752,28 +802,47 @@ function execute(file, callbacks, v) { log("Beginning execution"); + return state; +} + +function run_vm(vm) { while (true) { - var val = state.step(); + 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 state:"); + console.log("Machine vm:"); console.log(" Current Stack Frame:"); - console.log(" Stack: " + state.frame.stack); - console.log(" PC: " + state.frame.pc); - console.log(" Vars: " + state.frame.variables); - // console.log(" Code: " + state.frame.program); - console.log(" Heap: " + state.heap); + 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); } exports.execute = execute; +exports.initialize_vm = initialize_vm; +exports.run_vm = run_vm; },{"./opcodes":6}],5:[function(require,module,exports){ parser = require("./bytecode-parser"); diff --git a/test/tests.js b/test/tests.js index 9d6a198..96e1d7d 100644 --- a/test/tests.js +++ b/test/tests.js @@ -2,7 +2,8 @@ parser = require("../src/bytecode-parser.js"); c0vm = require("../src/c0vm.js"); c0ffi = require("../src/c0ffi.js"); -var callbacks = {} +var callbacks = c0ffi.default_callbacks; +console.log("Initial callbacks: " + callbacks[c0ffi.NATIVE_STRING_LENGTH](["hi"])); var printout = ""; callbacks[c0ffi.NATIVE_PRINT] = function(args) { @@ -20,30 +21,6 @@ callbacks[c0ffi.NATIVE_PRINTLN] = function(args) { return 0; } -callbacks[c0ffi.NATIVE_STRING_LENGTH] = function(args) { - return args[0].length; -} - -callbacks[c0ffi.NATIVE_STRING_TO_CHARARRAY] = function(args) { - return args[0]; -} - -callbacks[c0ffi.NATIVE_STRING_FROM_CHARARRAY] = function(args) { - console.log("string_from_chararray: " + args); - return args[0]; -} - -callbacks[c0ffi.NATIVE_CHAR_CHR] = function(args) { - return String.fromCharCode(args[0]); -} - -callbacks[c0ffi.NATIVE_CHAR_ORD] = function(args) { - console.log("native_car_ord: " + args); - if (typeof args[0] == "string") - return args[0].charCodeAt(0); - return args[0]; -} - function doTest(filename, expected_result) { return function(test) { var result = c0vm.execute(parser.parse(filename), callbacks, false);