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

Saving and Loading snapshots using the current NPM Package fails. #84

Open
nathandtrone opened this issue Nov 9, 2024 · 0 comments
Open

Comments

@nathandtrone
Copy link

I think the documentation needs more thorough explanation. I'm working using a google colab https://colab.research.google.com, to create a test environment to build this project and it is giving me trouble "out of the box". I can share that colab with you if requested(but not publicly to protect my account),

Here's what I'm doing so far at a basic level. Following the readme from this repo. This is assuming we are limited to working with just NodeJS as the base dependencies.

admin$ npm i node-gyp microvium == Microvium ^8.0.0
admin$ node -v == v16.20.2
admin$ touch script.mvm.js

The following source code sections all belong to the same script.mvm.js file. It is split into sections for reading.

Compile some stringified Javascript into a snapshot

//script.mvm.js
const Microvium = require('microvium');
const Snapshot = Microvium.Snapshot;
const fs = require("fs");

//I forget where I got this example, but disclosure, this isn't my creation. Found it in passing.
console.log("\nCompile Test");
function compile(sourceText) {
    // Create an empty VM
    const vm = Microvium.create();
    // Add Microvium's default globals such as `vmExport` and `vmImport`
    Microvium.addDefaultGlobals(vm);
    try {
        // Evaluate the script
        vm.evaluateModule({ sourceText, debugFilename: 'firmware.js' });
        // Create the snapshot
        const snapshot = vm.createSnapshot();
        // If you want the disassembly for debug purposes
        const { disassembly } = Microvium.decodeSnapshot(snapshot);
        //console.log("disassembly: ",disassembly);
        // The `snapshot.data` is a Node Buffer (Uint8Array) containing the snapshot bytes
        return { "result": snapshot.data, "error": null }
    } catch (e) {
        return { "result": null, "error": e.message }
    }
}
var bin = compile("var i = 0; i+= 100; i /= 2; i; var s = \"Some data\"; console.log(s+i); console = console;");
console.log("compile: ",Array.from(bin.result).map(v=>v.toString(16)).join(","));
console.log( "ASCII: " + Array.from(bin.result).map(v=>{ let c = String.fromCharCode(v); if( v==0 ) { return "."; } if( c.match( /[^A-z\d\w \(\)\{\}\.`~\*@\+=\/\:\-&,;]/ ) ) { return "."; } return c; }).join("") );

Expected output:

Compile Test
Some data50
compile:  8,1c,0,0,2e,0,50,10,3,0,0,0,1c,0,1c,0,1c,0,1c,0,2a,0,2a,0,2a,0,2e,0,2d,0,1,0,1,0,1,0,1,0,1,0,1,0,19,0,1,0
ASCII: ......P.............*.*.*...-.................

Test Two, Evaluating Javascript Strings

console.log("\nEval Module Test");
var vm_eval = Microvium.create();
// Create a "print" function in the global scope that refers to this lambda function in the host
vm_eval.globalThis.print = (s)=>{console.log(s);}
// Run some module source code
vm_eval.evaluateModule({ sourceText: 'print("Something Evaled!");' });
//console.log(JSON.stringify(vm_eval.vm));

Expected output:

Eval Module Test
Something Evaled!

Test Three, Taking a Snapshot, and Loading a Snapshot

console.log("\nSnapshot Test");
const snapshotFilename = 'script.mvm-bc';
var vms = Microvium.create();
//fs.writeFileSync("microvium.txt",JSON.stringify([Microvium,Microvium.Microvium,Snapshot,vms,vms.vm].map(v=>Object.keys(v)),null,"\t"));
vms.globalThis.print = console.warn;
vms.globalThis.console = { warn: console.warn };
console.warn = vms.vmImport(1);
console.log("vms.vmImport console.warn: ", console.warn);
function print(s) { console.warn(s); }
function sayHello() { print('Hello, World!'); }
vms.vmExport(1, sayHello); //Attempted to abstract once more
vms.vmExport(2, print);

console.log("vms.globalThis: ",vms.globalThis);
//console.log( "vms.createSnapshot:", vms.createSnapshot.toString() );
var snapshot = vms.createSnapshot();
console.log( "Snapshot: ", snapshot );
fs.writeFileSync( snapshotFilename, snapshot.data );
fs.writeFileSync( snapshotFilename+".json", JSON.stringify(snapshot.reconstructionInfo) );
console.log( "BIN["+snapshot.data.length+"]: ", Array.from(snapshot.data).map(v=>v.toString()).join(",") );
console.log( "ASCII: " + Array.from(snapshot.data).map(v=>{ let c = String.fromCharCode(v); if( v==0 ) { return "."; } if( c.match( /[^A-z\d\w \(\)\{\}\.`~\*@\+=\/\:\-&,;]/ ) ) { return "."; } return c; }).join("") );
//vms.globalThis.print = s => console.log(s);
//vms.evaluateModule({ sourceText: 'print("Hello, World!");' });

This is where things begin to break down. No matter what I try, I cannot get the snapshot feature to function properly. There's no documentation on that portion of the library, so I've gone to looking at the source and adding things I find there. None of the custom options work.

Output:

Snapshot Test
vms.vmImport console.warn:  [Function (anonymous)]
{}
Snapshot:  SnapshotClass {
  reconstructionInfo: { names: { allocation: [Object], block: [Object] } },
  sourceMap: undefined,
  _data: <Buffer 08 1c 00 00 66 00 c7 99 03 00 00 00 1c 00 1c 00 24 00 24 00 32 00 34 00 64 00 66 00 01 00 61 00 02 00 61 00 65 00 01 00 01 00 01 00 01 00 01 00 01 00 ... 52 more bytes>
}
BIN[102]:  8,28,0,0,102,0,199,153,3,0,0,0,28,0,28,0,36,0,36,0,50,0,52,0,100,0,102,0,1,0,97,0,2,0,97,0,101,0,1,0,1,0,1,0,1,0,1,0,1,0,57,0,0,0,38,64,78,111,116,32,97,118,97,105,108,97,98,108,101,32,111,110,32,116,104,105,115,32,104,111,115,116,32,40,100,101,116,97,99,104,101,100,41,0,0,80,136,57,0,97,1,0
ASCII: ....f...............2.4.d.f...a...a.e.............9...&@Not available on this host (detached)..P.9.a..

Load the Snapshot output from above. (Note the "Not available on this host (detached)" in the hexdump.)

console.log("\nSnapshot Load Test");
// Load the snapshot from file
const snapshot2 = Snapshot.fromFileSync(snapshotFilename);
snapshot2.reconstructionInfo = JSON.parse(fs.readFileSync(snapshotFilename+".json"));
console.log("snapshot2: ",snapshot2);
// Restore the virtual machine from the snapshot
var vm2 = Microvium.restore(snapshot2, {
  [1]: console.log
});
// Locate the function with ID 1234. This is the `sayHello` function that the script exported
const sayHello2 = vm2.resolveExport(1);

// Call the `sayHello` function in the script
sayHello2(); // "Hello, World!"

Output:

Snapshot Load Test
snapshot2:  SnapshotClass {
  reconstructionInfo: { names: { allocation: [Object], block: [Object] } },
  sourceMap: undefined,
  _data: <Buffer 08 1c 00 00 66 00 c7 99 03 00 00 00 1c 00 1c 00 24 00 24 00 32 00 34 00 64 00 66 00 01 00 61 00 02 00 61 00 65 00 01 00 01 00 01 00 01 00 01 00 01 00 ... 52 more bytes>
}
/content/node_modules/microvium/dist/lib/native-vm-friendly.js:186
        const result = this.vm.call(func, args);
                               ^

Error: Not available on this host (detached)
    at ValueWrapper.apply (/content/node_modules/microvium/dist/lib/native-vm-friendly.js:186:32)

I would like to see an update made to the documentation showing more about the snapshotting and the logic behind that functionalities byte codes. Preferrably not leaving out any source code to reduce user error. If you feel it would fit that is.. At the moment it leaves a lot of questions open for the user, and many pitfalls without any real explanation to the classes, objects, and methods. That said, this is an amazing project and I am eager to see it grow. I'm working on a single-file minified source for compiling using a streamlined c# compiler written for use inside of this JS-Engine itself, it has some amazing potential.

Thank you for your amazing work.

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

No branches or pull requests

1 participant