@marioslab/ulang-vm
Version:
Virtual machine & assembler for recreational programming like it's 1992.
404 lines • 34.2 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as ulang from "./wrapper";
export { compile, printMemory } from "./wrapper";
export var VirtualMachineState;
(function (VirtualMachineState) {
VirtualMachineState[VirtualMachineState["Stopped"] = 0] = "Stopped";
VirtualMachineState[VirtualMachineState["Running"] = 1] = "Running";
VirtualMachineState[VirtualMachineState["Paused"] = 2] = "Paused";
})(VirtualMachineState || (VirtualMachineState = {}));
export var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["None"] = 0] = "None";
LogLevel[LogLevel["Info"] = 1] = "Info";
})(LogLevel || (LogLevel = {}));
export class VirtualMachine {
constructor(canvasElement) {
this.state = VirtualMachineState.Stopped;
this.compilerResult = null;
this.vmStart = 0;
this.executedInstructions = 0;
this.vsyncHit = false;
this.debugSyscallHit = false;
this.breakpoints = [];
this.bpPtr = 0;
this.numBps = 0;
this.syscallHandlerPtr = 0;
this.lastStepHitBreakpoint = false;
this.stateChangeListener = null;
this.logLevel = LogLevel.Info;
this.mouseX = 0;
this.mouseY = 0;
this.mouseButtonDown = false;
this.keys = new Map();
this.listeners = [];
if (typeof (canvasElement) === "string")
this.canvas = document.getElementById(canvasElement);
else
this.canvas = canvasElement;
this.rgbaFramePtr = ulang.alloc(320 * 240 * 4);
this.addEventListener("mousemove", (e) => {
var rect = this.canvas.getBoundingClientRect();
this.mouseX = ((e.clientX - rect.left) / this.canvas.clientWidth * 320) | 0;
this.mouseY = ((e.clientY - rect.top) / this.canvas.clientHeight * 240) | 0;
});
this.addEventListener("mousedown", (e) => {
var rect = this.canvas.getBoundingClientRect();
this.mouseX = ((e.clientX - rect.left) / this.canvas.clientWidth * 320) | 0;
this.mouseY = ((e.clientY - rect.top) / this.canvas.clientHeight * 240) | 0;
this.mouseButtonDown = true;
});
this.addEventListener("mouseup", (e) => {
var rect = this.canvas.getBoundingClientRect();
this.mouseX = ((e.clientX - rect.left) / this.canvas.clientWidth * 320) | 0;
this.mouseY = ((e.clientY - rect.top) / this.canvas.clientHeight * 240) | 0;
this.mouseButtonDown = false;
});
this.addEventListener("mouseleave", (e) => {
var rect = this.canvas.getBoundingClientRect();
this.mouseX = ((e.clientX - rect.left) / this.canvas.clientWidth * 320) | 0;
this.mouseY = ((e.clientY - rect.top) / this.canvas.clientHeight * 240) | 0;
this.mouseButtonDown = false;
});
let syscallHandler = (syscall, vmPtr) => {
let vm = ulang.ptrToUlangVm(vmPtr);
switch (syscall) {
case 0:
this.pause();
this.debugSyscallHit = true;
return 0;
case 1:
let buffer = vm.popUint();
ulang.argbToRgba(vm.memoryPtr() + buffer, this.rgbaFramePtr, 320 * 240);
let frame = new Uint8ClampedArray(ulang.HEAPU8().buffer, this.rgbaFramePtr, 320 * 240 * 4);
let imageData = new ImageData(frame, 320, 240);
this.canvas.getContext("2d").putImageData(imageData, 0, 0);
this.vsyncHit = true;
return 0;
case 2: {
let str = "";
while (true) {
let argType = vm.popUint();
if (argType == 6)
break;
switch (argType) {
case 0:
str += vm.popInt();
break;
case 1:
str += "0x" + vm.popInt().toString(16);
break;
case 2:
str += vm.popFloat();
break;
case 3:
let strAddr = vm.popUint();
str += ulang.UTF8ArrayToString(ulang.HEAPU8(), vm.memoryPtr() + strAddr);
break;
case 4:
str += " ";
break;
case 5:
str += "\n";
break;
default:
break;
}
}
console.log(str);
return -1;
}
case 3: {
vm.pushInt(this.mouseX);
vm.pushInt(this.mouseY);
vm.pushInt(this.mouseButtonDown ? -1 : 0);
return -1;
}
case 4: {
}
case 5: {
vm.pushFloat(performance.now() / 1000);
return -1;
}
}
};
this.syscallHandlerPtr = ulang.addFunction(syscallHandler, "iii");
}
addEventListener(type, listener) {
this.canvas.addEventListener(type, listener);
this.listeners.push({ type: type, listener: listener });
}
dipose() {
this.stop();
for (let i = 0; i < this.listeners.length; i++) {
let listener = this.listeners[i];
this.canvas.removeEventListener(listener.type, listener.listener);
}
ulang.free(this.rgbaFramePtr);
}
setLogLevel(logLevel) {
this.logLevel = logLevel;
}
setStateChangeListener(listener) {
this.stateChangeListener = listener;
}
setBreakpoints(breakpoints) {
this.breakpoints = breakpoints;
if (this.bpPtr != 0) {
ulang.free(this.bpPtr);
this.bpPtr = 0;
this.numBps = 0;
}
if (this.state != VirtualMachineState.Stopped)
this.calculateBreakpoints();
}
calculateBreakpoints() {
if (this.bpPtr != 0)
return this.bpPtr;
// Needs to come before the next line, as WASM memory can grow and pointers may get relocated
let addressToLine = this.vm.program().addressToLine();
let p = this.bpPtr = ulang.alloc(4 * this.breakpoints.length);
for (let i = 0; i < this.breakpoints.length; i++) {
let bpLine = this.breakpoints[i];
for (let j = 0; j < addressToLine.length; j++) {
if (addressToLine[j] == bpLine) {
ulang.setUint32(p, j * 4);
p += 4;
this.numBps++;
break;
}
}
}
return this.bpPtr;
}
run(source) {
if (this.compilerResult) {
this.compilerResult.free();
this.compilerResult = null;
}
if (this.vm) {
this.vm.free();
this.vm = null;
}
this.compilerResult = ulang.compile(source);
if (this.compilerResult.error.isSet()) {
alert("Can't run program with errors.");
this.compilerResult.error.print();
this.compilerResult.free();
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
return;
}
this.vm = ulang.newVm(this.compilerResult.program);
for (let i = 0; i <= 255; i++) {
this.vm.setSyscall(i, this.syscallHandlerPtr);
}
this.vmStart = performance.now();
this.executedInstructions = 0;
this.lastStepHitBreakpoint = false;
this.state = VirtualMachineState.Running;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
requestAnimationFrame(() => this.frame());
}
stop() {
if (this.state != VirtualMachineState.Running && this.state != VirtualMachineState.Paused)
return;
this.state = VirtualMachineState.Stopped;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmTime();
this.printVmState();
}
pause() {
if (this.state != VirtualMachineState.Running)
return;
this.state = VirtualMachineState.Paused;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmState();
}
continue() {
if (this.state != VirtualMachineState.Paused)
return;
this.state = VirtualMachineState.Running;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmState();
requestAnimationFrame(() => this.frame());
}
step() {
if (this.state != VirtualMachineState.Paused)
return;
if (!this.vm.step()) {
if (this.vsyncHit || this.debugSyscallHit) {
this.vsyncHit = false;
this.debugSyscallHit = false;
}
else {
this.state = VirtualMachineState.Stopped;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
return;
}
}
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmState();
}
getCurrentLine() {
if (this.state != VirtualMachineState.Paused)
return -1;
let pc = this.vm.registers()[14].ui() >> 2;
let addressToLine = this.vm.program().addressToLine();
if (pc >= addressToLine.length)
return -1;
return addressToLine[pc];
}
getState() {
return this.state;
}
getRegisters() {
return this.vm.registers();
}
getProgram() {
return this.vm.program();
}
getInt(addr) {
return ulang.getInt32(this.vm.memoryPtr() + addr);
}
getFloat(addr) {
return ulang.getFloat32(this.vm.memoryPtr() + addr);
}
printVmTime() {
if (this.logLevel == LogLevel.None)
return;
let vmTime = (performance.now() - this.vmStart) / 1000;
console.log("VM took " + vmTime + " secs");
console.log("Executed " + this.executedInstructions + " instructions, " + ((this.executedInstructions / vmTime) | 0) + " ins/s");
}
printVmState() {
if (this.logLevel == LogLevel.None)
return;
this.vm.print();
}
getCanvas() {
return this.canvas;
}
frame() {
if (this.state == VirtualMachineState.Running) {
let frameStart = performance.now();
const instsPerStep = 20000;
// if we had a breakpoint in the last frame, we need
// to step over the current instruction, so we don't
// get stuck there.
if (this.lastStepHitBreakpoint) {
this.lastStepHitBreakpoint = false;
if (!this.vm.step()) {
if (this.vsyncHit || this.debugSyscallHit) {
this.vsyncHit = false;
this.debugSyscallHit = false;
requestAnimationFrame(() => this.frame());
return;
}
this.state = VirtualMachineState.Stopped;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmTime();
this.printVmState();
return;
}
}
while (true) {
this.executedInstructions += instsPerStep;
let result = 0;
if (this.breakpoints.length > 0)
this.calculateBreakpoints();
if (this.numBps > 0) {
result = this.vm.stepNBP(instsPerStep, this.bpPtr, this.numBps);
// hit a breakpoint, pause execution
if (result >= 1) {
this.lastStepHitBreakpoint = true;
this.state = VirtualMachineState.Paused;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmState();
return;
}
}
else {
result = this.vm.stepN(instsPerStep);
}
if (!result) {
if (this.vsyncHit || this.debugSyscallHit) {
this.vsyncHit = false;
this.debugSyscallHit = false;
requestAnimationFrame(() => this.frame());
return;
}
this.state = VirtualMachineState.Stopped;
if (this.stateChangeListener)
this.stateChangeListener(this, this.state);
this.printVmTime();
this.printVmState();
return;
}
let frameTime = performance.now() - frameStart;
if (frameTime > 16) {
requestAnimationFrame(() => this.frame());
return;
}
}
}
}
}
let loaded = false;
export function loadUlang() {
return __awaiter(this, void 0, void 0, function* () {
if (!loaded) {
loaded = true;
yield ulang.loadUlang();
}
});
}
export function createPlayerFromGist(canvas, gistId) {
return __awaiter(this, void 0, void 0, function* () {
yield loadUlang();
let response = yield fetch(`https:/api.github.com/gists/${gistId}`);
if (response.status >= 400)
throw new Error(`Couldn't fetch gist ${gistId}`);
let gist = yield response.json();
if (!gist.files || !gist.files["source.ul"] || !gist.files["source.ul"].content) {
throw new Error("Gist ${gistId} is not a ulang program.");
}
return new UlangPlayer(canvas, gist.files["source.ul"].content);
});
}
export class UlangPlayer {
constructor(canvas, source) {
this.vm = new VirtualMachine(canvas);
this.source = source;
}
play() {
this.vm.run(this.source);
}
getVirtualMachine() {
return this.vm;
}
getSource() {
return this.source;
}
dispose() {
if (this.vm)
this.vm.dipose();
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQUEsT0FBTyxLQUFLLEtBQUssTUFBTSxXQUFXLENBQUM7QUFFbkMsT0FBTyxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFakQsTUFBTSxDQUFOLElBQVksbUJBRVg7QUFGRCxXQUFZLG1CQUFtQjtJQUM5QixtRUFBTyxDQUFBO0lBQUUsbUVBQU8sQ0FBQTtJQUFFLGlFQUFNLENBQUE7QUFDekIsQ0FBQyxFQUZXLG1CQUFtQixLQUFuQixtQkFBbUIsUUFFOUI7QUFFRCxNQUFNLENBQU4sSUFBWSxRQUdYO0FBSEQsV0FBWSxRQUFRO0lBQ25CLHVDQUFJLENBQUE7SUFDSix1Q0FBSSxDQUFBO0FBQ0wsQ0FBQyxFQUhXLFFBQVEsS0FBUixRQUFRLFFBR25CO0FBT0QsTUFBTSxPQUFPLGNBQWM7SUF1QjFCLFlBQWEsYUFBeUM7UUFwQjlDLFVBQUssR0FBRyxtQkFBbUIsQ0FBQyxPQUFPLENBQUM7UUFDcEMsbUJBQWMsR0FBaUMsSUFBSSxDQUFBO1FBQ25ELFlBQU8sR0FBRyxDQUFDLENBQUM7UUFDWix5QkFBb0IsR0FBRyxDQUFDLENBQUM7UUFDekIsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixvQkFBZSxHQUFHLEtBQUssQ0FBQztRQUN4QixnQkFBVyxHQUFhLEVBQUUsQ0FBQztRQUMzQixVQUFLLEdBQUcsQ0FBQyxDQUFDO1FBQ1YsV0FBTSxHQUFHLENBQUMsQ0FBQztRQUNYLHNCQUFpQixHQUFHLENBQUMsQ0FBQztRQUN0QiwwQkFBcUIsR0FBRyxLQUFLLENBQUM7UUFDOUIsd0JBQW1CLEdBQTZELElBQUksQ0FBQztRQUNyRixhQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQztRQUN6QixXQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ1gsV0FBTSxHQUFHLENBQUMsQ0FBQztR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