Skip to content

Instantly share code, notes, and snippets.

@Nafees10
Created October 24, 2019 21:24
Show Gist options
  • Select an option

  • Save Nafees10/d438de2ac56f93bf455453204fc525c1 to your computer and use it in GitHub Desktop.

Select an option

Save Nafees10/d438de2ac56f93bf455453204fc525c1 to your computer and use it in GitHub Desktop.

Revisions

  1. Nafees10 created this gist Oct 24, 2019.
    265 changes: 265 additions & 0 deletions badvm.d
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,265 @@
    import std.stdio;
    import std.datetime.stopwatch;

    void main(string[] args){
    FCall caller;
    Switcher swExec;
    StopWatch sw;
    if (args.hasElement("output")){
    caller = new FCall(cast(ubyte[])outputProgramInstructions, cast(int[])outputProgramArgs, 64);
    swExec = new Switcher(cast(ubyte[])outputProgramInstructions, cast(int[])outputProgramArgs, 64);
    }else{
    caller = new FCall(cast(ubyte[])programInstructions, cast(int[])programArgs, 64);
    swExec = new Switcher(cast(ubyte[])programInstructions, cast(int[])programArgs, 64);
    }
    caller.push(1);
    swExec.push(1);
    if (args.hasElement("sw")){
    writeln("starting Switcher");
    sw.start();
    swExec.execute;
    sw.stop;
    }else{
    writeln("starting FCall");
    sw.start();
    caller.execute;
    sw.stop;
    }
    writeln("execution took: ", sw.peek.total!"msecs", "msecs");
    }

    /// Instructions:
    /// 0 : push
    /// 1 : add
    /// 2 : isLess
    /// 3 : jumpIf (to zero)
    /// 4 : Writeln
    /// 5 : push popped element twice
    class Switcher{
    private:
    ubyte[] _program;
    int[] _args;
    Stack _stack;
    public:
    this(ubyte[] program, int[] args, uint maxStack){
    _program = program.dup;
    _args = args.dup;
    _stack = new Stack(maxStack);
    }
    ~this(){
    .destroy(_stack);
    }
    /// pushes to stack
    void push(int element){
    _stack.push(element);
    }
    /// Executes program
    void execute(){
    int* _argPtr = &_args[0];
    ubyte* instPtr = &_program[0];
    ubyte* lastInstruction = &_program[_program.length-1] + 1;
    while (instPtr < lastInstruction){
    switch (*instPtr){
    case 0:
    _stack.push(*_argPtr);
    break;
    case 1:
    _stack.push(_stack.pop + _stack.pop);
    break;
    case 2:
    _stack.push(cast(int)(_stack.pop > _stack.pop));
    break;
    case 3:
    if (_stack.pop == 1){
    instPtr = &_program[0] - 1;
    _argPtr = &_args[0] - 1;
    }
    break;
    case 4:
    writeln(_stack.pop);
    break;
    case 5:
    int element = _stack.pop;
    _stack.push([element, element]);
    default:
    break;
    }
    instPtr++;
    _argPtr++;
    }
    }
    }

    class FCall{
    private:
    void delegate(int)[] _program;
    int[] _args;
    Stack _stack;

    void delegate(int)* _instPtr;
    int* _argPtr;

    void delegate(int)[ubyte] _instructionTable;

    void pushRuntime(int a){
    _stack.push(a);
    }
    void add(int a){
    _stack.push(_stack.pop + _stack.pop);
    }
    void isLess(int a){
    _stack.push(cast(int)(_stack.pop > _stack.pop));
    }
    void jumpIf(int a){
    if (_stack.pop == 1){
    _instPtr = &_program[0] - 1;
    _argPtr = &_args[0] - 1;
    }
    }
    void writeLn(int a){
    writeln(_stack.pop);
    }
    void rePush(int a){
    int element = _stack.pop;
    _stack.push([element, element]);
    }
    public:
    this(ubyte[] program, int[] args, uint maxStack){
    _args = args.dup;
    _stack = new Stack(maxStack);

    _instructionTable[0] = &this.pushRuntime;
    _instructionTable[1] = &this.add;
    _instructionTable[2] = &this.isLess;
    _instructionTable[3] = &this.jumpIf;
    _instructionTable[4] = &this.writeLn;
    _instructionTable[5] = &this.rePush;

    // translate the program
    _program.length = program.length;
    foreach (i, inst; program){
    _program[i] = _instructionTable[inst];
    }
    }
    ~this(){
    .destroy(_stack);
    }
    /// pushes to stack
    void push(int element){
    _stack.push(element);
    }
    /// executes the program
    void execute(){
    _instPtr = &_program[0];
    _argPtr = &_args[0];
    void delegate(int)* lastInstruction = &_program[_program.length - 1] + 1;
    while (_instPtr < lastInstruction){
    (*_instPtr)(*_argPtr);
    _instPtr ++;
    _argPtr ++;
    }
    }
    }

    /// Fixed max-length stack (not using utils.lists.Stack because that one isnt optimized to be fast as much as this should be)
    ///
    /// Be aware that no bound checking is done here, so be careful
    package class Stack{
    private:
    /// the actual stack
    int[] _stackArray;
    /// pointer of the next element that'll be written to next
    int* _peekPtr;
    public:
    this(uint length=64){
    _stackArray.length = length;
    _peekPtr = _stackArray.ptr;
    }
    /// Reads n number of elements from stack, in reverse order (i.e: [nth-last pushed, (n-1)th-last pushed, ..., last pushed])
    ///
    /// Returns: the elements read
    int[] pop(uint n){
    _peekPtr -= n;
    return _peekPtr[0 .. n];
    }
    /// Reads the last element pushed to stack
    ///
    /// Returns: the element pop-ed
    int pop(){
    _peekPtr --;
    return *_peekPtr;
    }
    /// pushes elements to stack. First in array is pushed first
    void push(int[] elements){
    _peekPtr[0 .. elements.length] = elements;
    _peekPtr += elements.length;
    }
    /// pushes an element to stack
    void push(int element){
    *_peekPtr = element;
    _peekPtr ++;
    }
    /// Returns: number of elements present
    @property uint count(){
    return cast(uint)(_peekPtr - _stackArray.ptr);
    }
    /// Returns: the element at an index (this is possible as the stack is actually an array)
    int read(uint index){
    return _stackArray[index];
    }
    /// Writes a value to an index on the stackArray (possible because the stack is actually a stack)
    void write(uint index, int value){
    _stackArray[index] = value;
    }
    }

    /// program, with output
    const ubyte[] outputProgramInstructions = [
    0,
    1,
    5,
    4,
    5,
    0,
    2,
    3
    ];
    /// program, with output
    const int[] outputProgramArgs = [
    1,
    0,
    0,
    0,
    0,
    1000000
    ];
    /// program, without output
    const ubyte[] programInstructions = [
    0,
    1,
    5,
    0,
    2,
    3
    ];
    /// program, without output
    const int[] programArgs = [
    1,
    0,
    0,
    1000000
    ];

    /// Returns: true if an aray has an element, false if no
    ///
    /// I stole it from my repo github/nafees10/utils
    bool hasElement(T)(T[] array, T element){
    bool r = false;
    foreach(cur; array){
    if (cur == element){
    r = true;
    break;
    }
    }
    return r;
    }