a performant scheme interpreter in asm.js

31
A Performant Scheme interpreter in asm.js Noah Van Es, Jens Nicolay, Quentin Stievenart, Theo D’Hondt, Coen De Roover 6 April 2016, Symposium on Applied Computing, Pisa [email protected] @noahvanes github.com/noahvanes

Upload: noahves

Post on 13-Jan-2017

159 views

Category:

Technology


2 download

TRANSCRIPT

A Performant Scheme interpreter in asm.js

Noah Van Es, Jens Nicolay, Quentin Stievenart, Theo D’Hondt, Coen De Roover

6 April 2016, Symposium on Applied Computing, Pisa

[email protected] @noahvanes github.com/noahvanes

Context: JavaScript

‣ Language of the web

‣ “Universal virtual machine”

‣ Supports other languages:

‣ popular compilation target

‣ implementation language for interpreters

Context: JavaScript

‣ Language of the web

‣ “Universal virtual machine”

‣ Supports other languages:

‣ popular compilation target

‣ implementation language for interpretersProblem: performance is unacceptable!

asm.js

“An extraordinarily optimizable, low-level subset of JavaScript”

- asmjs.org

‣ Low-level subset of JavaScript

‣ very limited language ✓ no garbage collection

✓ static typing

‣ backward compatible

asm.js

“An extraordinarily optimizable, low-level subset of JavaScript”

- asmjs.org

‣ Optimizable

‣ ‘use asm’ annotation

‣ static typing, unboxed values, …

‣ AOT-compilation

asm.js

“An extraordinarily optimizable, low-level subset of JavaScript”

- asmjs.org

asm.js: Example

asm.js: Example

type annotations

asm.js: Example

global heap byte addressing

Compiling from C to asm.js

‣ Used as a compilation target

‣ Emscripten toolchain

C program LLVM IR asm.js

Compiling from C to asm.js

‣ Used as a compilation target

‣ Emscripten toolchain

‣ Portable IR

‣ can be further compiled AOT …

‣ … or executed directly as JS

C program LLVM IR asm.js

Integrating asm.js by hand

‣ Integrate handwritten asm.js into existing application

‣ Key questions:

‣ is asm.js human-writable?

‣ can existing interpreters migrate to asm.js?

‣ balance between development effort and performance?

SLIP: Simple Language Implementation Platform

‣ Scheme-like language

‣ Omits non-idiomatic features

‣ http://soft.vub.ac.be/~tjdhondt/PLE

SLIP: Simple Language Implementation Platform

‣ Scheme-like language

‣ Omits non-idiomatic features

‣ http://soft.vub.ac.be/~tjdhondt/PLE

SLIP: Base implementations

‣ Reference C implementation: ~6000 LOC

‣ Plain JS implementation: ~4000 LOC

‣ Design characteristics:

✓ continuation-passing style

✓ register-machine architecture

✓ low-level memory model

✓ garbage collection

✓ trampoline

✓ unified abstract grammar

Integrating asm.js

‣ Refactor critical modules to asm.js

MEMORY MANAGEMENT

ABSTRACT GRAMMAR

COMPILER

EVALUATOR

NATIVES

PRINTERPARSER

POOL

REPL

plain JS asm.js

Integrating asm.js

‣ Refactor critical modules to asm.js

MEMORY MANAGEMENT

ABSTRACT GRAMMAR

COMPILER

EVALUATOR

NATIVES

PRINTERPARSER

POOL

REPL

plain JS asm.js

Integrating asm.js

‣ Refactor critical modules to asm.js

MEMORY MANAGEMENT

ABSTRACT GRAMMAR

COMPILER

EVALUATOR

NATIVES

PRINTERPARSER

POOL

REPL

plain JS asm.js

Integrating asm.js

‣ Refactor critical modules to asm.js

MEMORY MANAGEMENT

ABSTRACT GRAMMAR

COMPILER

EVALUATOR

NATIVES

PRINTERPARSER

POOL

REPL

plain JS asm.js

Integrating asm.js

‣ Iterative integration process

‣ Milestones

plain JS asm.js

100%24%

76%

7%

93% 81%

19%

asm0 asm1 asm2 asm3

Development effort

‣ Challenges in writing asm.js by hand

‣ limited type system

‣ explicit typecasts

‣ manual memory management

‣ poor abstraction mechanisms

‣ interface between JS and asm.js

Development effort

‣ Challenges in writing asm.js by hand

‣ limited type system

‣ explicit typecasts

‣ manual memory management

‣ poor abstraction mechanisms

‣ interface between JS and asm.js

Macros to the rescue

‣ Macros to facilitate writing asm.js by hand

‣ Using the sweet.js macro expander

‣ Macros help to improve:

‣ readability

‣ maintainability

‣ performance

Macros use cases

‣ Auto-generate function table, trampoline, …

Macros use cases

‣ Auto-generate function table, trampoline, …

Macros use cases

‣ Auto-generate function table, trampoline, …

Performance comparison with JavaScript

‣ Too much overhead in first iterations ‣ asm3: ~80% faster than original JS implementation

spee

dup

asm0 asm1 asm2 asm30

1

2

3

4

5

Performance comparison with Cm

illise

cond

s

0

2000

4000

6000

8000

tower-fib nqueens qsort hanoi tak cpstak ctak destruct array1 primes

asm4 native C Emscripten

Performance comparison with C

‣ asm4 is ~19% slower than native C

‣ asm4 is ~46% faster than Emscripten

Table 1

native slip.js (asm4) compiled

1,0 1,185 1,742

native asm4 compiled

tower-fib 3583 3518 4711 1,31481998325426

nqueens 1033 1296 1864 1,80445304937076

qsort 2749 3948 5003 1,81993452164423

hanoi 3890 4046 7204 1,85192802056555

tak 772 878 1483 1,92098445595855

cpstak 936 985 1517 1,6207264957265

ctak 3118 5222 4541 1,45638229634381

destruct 4216 4350 7801 1,8503320683112

array1 2710 3518 5900 2,17712177121771

primes 3461 3832 6105 1,76394105749783

tower-fib

nqueens

qsort

hanoi

tak

cpstak

ctak

destruct

array1

primes

0 2000 4000 6000 8000

native asm4 compiled

0,00,20,40,60,81,01,21,41,61,82,0

native slip.js (asm4) compiled

Table 1-1

asm0 asm1 asm2 asm3

1,0 0,47 0,34 0,28

asm0 asm1 asm2 asm3slo

wdo

wn

native C asm4 Emscripten

Try it yourself!

‣ http://noahvanes.github.io/slip.js

Conclusion

‣ Integrated asm.js into interpreter

‣ Development effort: considerable

‣ more components had to be ported

‣ maintainability & readability improved by macros

‣ Performance: huge improvements

‣ close to native speed on the web!

[email protected]

github.com/noahvanes