Untitled

mail@pastecode.io avatar
unknown
javascript
5 months ago
5.9 kB
2
Indexable
var indentLevel = 0;
function log(message) {
  console.log(" ".repeat(indentLevel) + message);
}
class VMContext {
  constructor(bytecode) {
    this.ip = 0;
    this.registers = new Array(32).fill(0);
    this.stack = [];
    this.frames = [];
    this.bytecode = bytecode;
  }

  readNextValue() {
    const valueType = this.bytecode[this.ip++];
    if (valueType === 1) {
      return this.bytecode[this.ip++];
    }
    if (valueType === 2) {
      return (this.bytecode[this.ip++] << 8) | this.bytecode[this.ip++];
    }
    if (valueType === 4) {
      const value = this.bytecode.slice(this.ip, this.ip + 4);
      this.ip += 4;
      return (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
    }
    if (valueType === 5) {
      const value = this.bytecode.slice(this.ip, this.ip + 4);
      this.ip += 4;
      const buffer = new ArrayBuffer(4);
      const view = new DataView(buffer);
      for (let i = 0; i < 4; i++) {
        view.setUint8(i, value[i]);
      }
      return view.getFloat32(0);
    }
    if (valueType === 3) {
      const length = this.bytecode[this.ip++] | (this.bytecode[this.ip++] << 8);
      const value = this.bytecode.slice(this.ip, this.ip + length);
      this.ip += length;
      return String.fromCharCode(...value);
    }
    throw new Error("Invalid value type");
  }
}

const handlers = [
  null,
  (context) => {
    const a = context.stack.pop();
    const b = context.stack.pop();
    context.stack.push(a ^ b);
  },
  (context) => {
    const address = context.readNextValue();
    const value = context.stack.pop();
    if (value === 0) {
      context.ip = address;
    }
  },
  (context) => {
    const reg = context.readNextValue();
    const value = context.stack.pop();
    context.registers[reg] = value;
  },
  (context) => {
    context.stack.push(context.readNextValue());
  },
  (context) => {
    const a = context.stack.pop();
    const b = context.stack.pop();
    context.stack.push(a + b);
  },
  (context) => {
    const a = context.stack.pop();
    const b = context.stack.pop();
    context.stack.push(b !== a ? 1 : 0);
  },
  (context) => {
    const a = context.stack.pop();
    const b = context.stack.pop();
    context.stack.push(a & b);
  },
  (context) => {
    const a = context.stack.pop();
    const b = context.stack.pop();
    context.stack.push(b << a);
  },
  (context) => {
    indentLevel--;
    var ret_address = context.stack.pop();
    var ret_value = context.stack.pop();
    context.ip = ret_address;
    context.stack.push(ret_value);
    context.registers = context.frames.pop();
    return 3;
  },
  (context) => {
    const address = context.readNextValue();
    context.ip = address;
  },
  (context) => {
    const reg = context.readNextValue();
    context.stack.push(context.registers[reg]);
  },
];

/* annotations.js */
/* Experiment with distinct markers for functions, classes, and fields. */

/**
 * @virtualize
 */
function testFunction() {
  {
    const bytecode = [
      0x03, 0x01, 0x00, 0x04, 0x02, 0x05, 0x39, 0x0b, 0x01, 0x00, 0x09,
    ];
    let vm = new VMContext(bytecode);

    vm.stack.push(-1);
    while (true) {
      const opcode = bytecode[vm.ip++];
      if (handlers[opcode](vm) == 3) {
        return vm.stack.pop();
      }
    }
  }
}

function testString() {
  return "Hello, World!";
}

/**
 * @virtualize
 */
function testParam(a) {
  {
    const bytecode = [
      0x03, 0x01, 0x00, 0x03, 0x01, 0x01, 0x0b, 0x01, 0x01, 0x04, 0x01, 0x01,
      0x05, 0x0b, 0x01, 0x00, 0x09,
    ];
    let vm = new VMContext(bytecode);
    vm.stack.push(a);
    vm.stack.push(-1);
    while (true) {
      const opcode = bytecode[vm.ip++];
      if (handlers[opcode](vm) == 3) {
        return vm.stack.pop();
      }
    }
  }
}

/**
 * @virtualize
 */
function stringConcat(a, b) {
  {
    const bytecode = [
      0x03, 0x01, 0x00, 0x03, 0x01, 0x01, 0x03, 0x01, 0x02, 0x0b, 0x01, 0x01,
      0x0b, 0x01, 0x02, 0x05, 0x0b, 0x01, 0x00, 0x09,
    ];
    let vm = new VMContext(bytecode);
    vm.stack.push(a);
    vm.stack.push(b);
    vm.stack.push(-1);
    while (true) {
      const opcode = bytecode[vm.ip++];
      if (handlers[opcode](vm) == 3) {
        return vm.stack.pop();
      }
    }
  }
}

/**
 * @virtualize
 */
function bitwiseAdd(a, b) {
  {
    const bytecode = [
      0x03, 0x01, 0x00, 0x03, 0x01, 0x01, 0x03, 0x01, 0x02, 0x0b, 0x01, 0x01,
      0x0b, 0x01, 0x02, 0x07, 0x03, 0x01, 0x03, 0x0b, 0x01, 0x01, 0x0b, 0x01,
      0x02, 0x01, 0x03, 0x01, 0x04, 0x0b, 0x01, 0x03, 0x04, 0x01, 0x00, 0x06,
      0x02, 0x04, 0x00, 0x00, 0x00, 0x4e, 0x0b, 0x01, 0x03, 0x04, 0x01, 0x01,
      0x08, 0x03, 0x01, 0x05, 0x0b, 0x01, 0x04, 0x0b, 0x01, 0x05, 0x07, 0x03,
      0x01, 0x03, 0x0b, 0x01, 0x04, 0x0b, 0x01, 0x05, 0x01, 0x03, 0x01, 0x04,
      0x0a, 0x04, 0x00, 0x00, 0x00, 0x1d, 0x0b, 0x01, 0x03, 0x04, 0x01, 0x00,
      0x0b, 0x01, 0x03, 0x04, 0x01, 0x01, 0x0b, 0x01, 0x04, 0x0b, 0x01, 0x05,
      0x0b, 0x01, 0x04, 0x0b, 0x01, 0x05, 0x0b, 0x01, 0x04, 0x0b, 0x01, 0x00,
      0x09,
    ];
    let vm = new VMContext(bytecode);
    vm.stack.push(a);
    vm.stack.push(b);
    vm.stack.push(-1);
    while (true) {
      const opcode = bytecode[vm.ip++];
      if (handlers[opcode](vm) == 3) {
        return vm.stack.pop();
      }
    }
  }
}

var a = testFunction();
console.log(`testFunction() returned ${a}`);
var b = testString();
console.log(`testString() returned ${b}`);
var c = testParam(42);
console.log(`testParam( 42 ) returned ${c}`);
var d = stringConcat("Hello, ", "World!");
console.log(`stringConcat( "Hello, ", "World!" ) returned ${d}`);
var e = bitwiseAdd(18, 2);
console.log(`bitwiseAdd( 18, 2 ) returned ${e}`);
Leave a Comment