GithubHelp home page GithubHelp logo

prodigeni / vm.js Goto Github PK

View Code? Open in Web Editor NEW

This project forked from tarruda/vm.js

0.0 1.0 0.0 479 KB

Javascript bytecode compiler and VM implemented in pure coffeescript

License: MIT License

vm.js's Introduction

vm.js

Javascript bytecode compiler/vm written in CoffeeScript.

Dependency status Build Status

Installation

npm install vm.js

Tests

There are about 200 acceptance tests that are run twice: once inside a normal Vm and again inside a self-hosted Vm(think about the movie 'Inception' for an easy analogy). That means it is capable of running moderately complex javascript code(since it runs itself plus the esprima parser), so it should be stable enough for most uses.

npm test

Overview

vm.js implements a ECMAScript virtual machine that can be used from any ECMAScript3-compatible environment. Eventually it will provide a complete ECMAScript 6 environment(for now only some features are supported)

Here are some possible use cases:

  • Simple in-process javascript sandbox
  • Async-to-sync API adapter using fibers (lightweight in-process threads)
  • Use new ECMAScript features in very old browsers

Usage

The main API can be accessed through Vm instances. Each Vm is indirectly associated with a global object(through a Realm) and is isolated from other Vms.

Start by creating a new instance:

> Vm = require('vm.js')
> vm = new Vm()

Evaluate simple expressions:

> vm.eval('40 + 2')
42
> vm.eval('[a, b, c] = [1, 2, 3]') // Harmony destructuring assignment
[1, 2, 3]
> vm.realm.global.a
1
> vm.realm.global.b
2
> vm.realm.global.c
3

Compile programs and run later

// pass filename as second argument for stack traces/debugging
> script = Vm.compile('2 + 2', 'sum.js')
> vm.run(script)
4

Compiled scripts can be serialized/deserialized to/from JSON-friendly structures:

> scriptObj = script.toJSON()
> serializedScript = JSON.stringify(scriptObj)
> deserializedScript = Vm.fromJSON(JSON.parse(serializedScript))
> vm.run(deserializedScript)

Expose objects to be used by code running inside the Vm

> vm.realm.global.factorial = function factorial(n) { return n > 1 ? factorial(n - 1) * n : 1 }
> vm.eval('factorial(5)')
120

The inverse also works:

> vm.eval('function factorial(n) { return n > 1 ? factorial(n - 1) * n : 1 }')
> vm.realm.global.factorial(5)
120

Return values asynchronously using fiber pause/resume:

// created a paused fiber from compiled code
fiber = vm.createFiber(Vm.compile('user = null; user = fetchAsync("/users/1");'))
vm.realm.global.fetchAsync = function(url) {
  fiber.pause() // pause execution
  $.get(url, function(data) {
    // user === null
    fiber.setReturnValue(data)
    fiber.resume()
    // user === data
  });
}
// start fiber
fiber.run()

Builtin objects are exposed, but each Vm instance uses a copy-on-write algorithm to maintain its own state of builtin globals:

> vm.eval('Object.prototype') === Object.prototype
true
> vm.eval('Object.prototype.bark = function() { return "bark!" }')
> vm.eval('[].bark()')
'bark!'
> 'bark' in Object.prototype
false

Its possible to provide a instruction timeout(maximum number of instructions a fiber can execute).

> vm.eval("i = 0; while (true) i++", 'timeout.js', 500)
TimeoutError: Script timed out
    at timeout.js:1:20

The TimeoutError has a 'fiber' property that references the paused fiber(it can be resumed, optionally passing another timeout to the 'resume' method).

As shown above, some harmony features are available. Here's a generator example:

> vm.eval(
'function* fib() {' +
  'var i = 0, j = 1, t;' +
  'while (true) {' +
    'yield i;' +
    't = i;' +
    'i = j;' +
    'j += t;' +
  '}' +
'}')
> vm.eval('l = []')
> vm.eval('for (let i of fib()) {if (l.length > 10) break; l.push(i)}')
> vm.eval('l')
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Like normal functions, the 'fib' generator can be used outside a vm instance:

> g = vm.realm.global.fib(); l = [];
> while (l.length < 11) l.push(g.next())
> l
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

See more examples and supported features here.

Comments

This was inspired by Continuum which is a ECMAScript 6 virtual machine implemented in pure javascript. I wrote this because I wanted a smaller codebase(less than 5k lines of CoffeeScript code) and seamless integration with the host virtual machine(no need to call strange internal methods to access objects manipulated by the vm).

For parsing source code this library uses the esprima parser.

vm.js's People

Contributors

tarruda avatar alexgorbatchev avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.