Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Decompiler #346

Closed
wants to merge 60 commits into from
Closed

Conversation

willemneal
Copy link
Contributor

@willemneal willemneal commented Nov 25, 2018

This PR is to improve the Decompiler to allow generating .ts files for a .wasm file and generating a .d.ts file. This will allow a assemblyscript file to depend on dynamically linked wasm files. For example, musl.

I'll also have another PR to improve the Parser, which will also parses instructions. This will allow new instructions to be translated as macros to implement new runtime features. For example, currently the wasm thread proposal has wait and wake instructions, which could translated to use an external Javascript version of an agent.

I've tried to minimize the transformation of the source code, but the global names are still being rewritten.

Example:

export class Test {
  constructor(public i:i32){
  }
  _if(i:i32): void{
    if (this.i < i){
      this.i = i;
    } else{
      this.i = this.i + 1;
    }
  }
}

Becomes:

function index/Test#_if($0: i32, $1: i32): void {
    if (load<i32>(0 + $0) < $1) {
        store<void>(0 + $0, $1);
    } else {
        store<void>(0 + $0, load<i32>(0 + $0) + 1);
    }
}

@willemneal willemneal changed the title Decompiler [WIP] Decompiler Nov 27, 2018
t._else(3);
println(t.i);
t._while(1);
println(t.i);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This files decompiles to:

function index/println($0: i32): void {
    return
}

function index/Test#constructor($0: i32, $1: i32): i32 {
    $0 = $0 ? $0 : $0 = $2 = ~lib/memory/memory.allocate(4);
    store<void>(0 + $2, $1);
    return $2;
}

function index/Test#_if($0: i32, $1: i32): void {
    if (load<i32>(0 + $0) < $1) {
        store<void>(0 + $0, $1);
    }
}

function index/Test#_else($0: i32, $1: i32): void {
    if (load<i32>(0 + $0) < $1) {
        store<void>(0 + $0, $1);
    } else {
        store<void>(0 + $0, load<i32>(0 + $0) + 1);
    }
}

function index/Test#_while($0: i32, $1: i32): void {
    do {
        if (load<i32>(0 + $0) > $1) {
            store<void>(0 + $0, load<i32>(0 + $0) - 1);
            break;
        }
    } while (1);
}

function index/Test#_doWhile($0: i32, $1: i32): void {
    do {
        if (load<i32>(0 + $0) < $1) {
            store<void>(0 + $0, load<i32>(0 + $0) + 1);
        }
        if (1) break;
    } while (1);
}

function index/MakeT(): i32 {
    return index/Test#constructor(0, 2);
}

function index/getT(): i32 {
    $0 = ~lib/array/Array<Test>#constructor(0, 0);
    ~lib/array/Array<Test>#push($0, global$6);
    return $0;
}

function index/getA(): i32 {
    return ~lib/array/Array<Test>#__get(global$9, 0);
}

function start(): void {
    global$4 = global$10 + global$2 & global$2 ^ -1;
    global$5 = global$4;
    global$6 = index/MakeT();
    global$9 = index/getT();
    index/Test#_if(global$6, 1);
    index/Test#_else(global$6, 3);
    index/println(load<i32>(0 + global$6));
    index/Test#_while(global$6, 1);
    return index/println(load<i32>(0 + global$6));
}

function null(): void {
    return;
}

function Test#get:i($0: i32): i32 {
    return load<i32>(0 + $0);
}

function Test#set:i($0: i32, $1: i32): void {
    return store<void>(0 + $0, $1);
}

declare function println(s: i32):void;

export class Test {
constructor(public i: i32){
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't decompile correctly. Still need to figure out how to handle if's that have a result value.

MaxGraey and others added 27 commits December 26, 2018 22:52
…ipt#355

This only affects static fields that currently must have a type annotation, while it wouldn't work if there wasn't an annotated type, like on normal globals, which aren't compiled lazily, though. Must be revisted if requirements on type annotations on fields ever become relaxed.
This also made it necessary to extend the internal per-function instances map by one level for the respective class instance key so functions on differnt class instances with the same own type arguments don't collide.
@MaxGraey
Copy link
Member

@dcodeIO @willemneal does we still need decompiler? In my opinion much better investigate time to allow static / dynamic linking

@dcodeIO
Copy link
Member

dcodeIO commented May 16, 2020

Closing this PR as part of 2020 vacuum as it seems to be outdated, i.e. the decompiler has been removed meanwhile. If there is interest in continuing this work, I suggest to implement it as its own project first, seeing how far we can go, and once it looks good reconsider adding it to the main repo.

@dcodeIO dcodeIO closed this May 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants