Why? ;)
Runs in all browsers
Familiar syntax
Dynamic typing
Existing code
Developer tools
Static typing
Spreadsheets: C/C++ and VBA, etc
Web browsers: C/C++ and JavaScript
Game engines: C/C++ and Lua, etc.
Libraries for scripting languages: Python and C/C++ modules like NumPy, etc.
When useful, gives you the best parts of multiple languages
JavaScript is the only standards-based language in web browsers
If we want to run other languages on the web, we need to go through JavaScript
Might seem like an odd solution
But replacing JavaScript with anything else would slow down the web
Adding another virtual machine (VM) alongside JavaScript is complicated (cross-VM GC, etc.)
Consensus to standardize any such change would be very hard
But it turns out to be not so odd!
Running other languages in JavaScript requires no standardization
Turns out performance can be good in many cases
No new VM means no new attack surface for exploits
Java (GWT) used in Blogger, enterprise apps
C# (Script#) used in Microsoft Office Web Apps
float array[5000]; // C++
int main() {
for (int i = 0; i < 5000; ++i) {
array[i] += 1.0f;
}
}
var g = Float32Array(32768); // JavaScript
function main() {
var a = 0, b = 0;
do {
a = 8 + (b << 2) | 0;
g[a >> 2] = +g[a >> 2] + 1.0;
b = b + 1 | 0;
} while ((b | 0) < 5000);
}
This is a subset of JS called asm.js
An optimizable subset of JavaScript, intended primary as a compiler target
Avoids potential slowdowns (types changing, GC pauses)
Low-level and easy to optimize
That asm.js example from before:
var g = Float32Array(32768); // JavaScript
function main() {
var a = 0, b = 0;
do {
a = 8 + (b << 2) | 0;
g[a >> 2] = +g[a >> 2] + 1.0;
b = b + 1 | 0;
} while ((b | 0) < 5000);
}
Integers remain integers
"Memory" is a fast typed array
Every compiler - GWT, CoffeeScript, etc. - generates a particular subset of JavaScript
Emscripten and Mandreel converged on a useful subset for C/C++
Added to a popular benchmark, Google Octane
asm.js formalizes that subset
(VMs and Emscripten from June 10th 2013, run on a 64-bit linux machine)
C/C++ compiled to JavaScript can run close to native speed
Beats Java in some cases
No need to standardize (asm.js is just like GWT, CoffeeScript, etc.), so improves at the speed that JS engines improve: FAST
Already fast enough even for demanding use cases like 3D games
..
We have VMs for many languages that are written in C/C++
We have C/C++ to JavaScript compilers
Hmmm...
We can compile those VMs!
..
..
We can run many languages on the web
By running them in JavaScript
What do other platforms/environments do?
Main project is written in C/C++
VM for a scripting language (e.g., Python) is also written in C/C++
VM has a C/C++ API to bridge the two "worlds"
Python makes it easy to run code in its VM:
// C code
PyRun_SimpleString("print 'hello from python!'");
Other APIs let you create Python objects and operate on them from C
Script language is just another module in the C/C++ project
(it happens to be a VM)
// C++ with Boost.Python
#include "boost/python.hpp"
char const* greet() {
return "hello from C!";
}
BOOST_PYTHON_MODULE(greeter) {
boost::python::def("greet", greet);
}
# Python
>>> import greeter
>>> greeter.greet()
hello from C!
Boost.Python can also wrap C++ classes
// C++ class
class Cat {
string name;
public:
Cat(string name_) : name(name_) {}
void meow() { printf("%s meows\n", name.c_str());
};
BOOST_PYTHON_MODULE(Cats) {
class <Cat>("Cat").def("meow", &Cat::meow);
}
// Python
>>>> import Cats
>>>> my_cat = Cats.Cat('Fluffy')
>>>> print my_cat.meow()
Fluffy meows
But can we do this in JavaScript?
YES!
Emscripten provides APIs on the C side
#include "emscripten.h"
int main() {
// Call JS from C
emscripten_run_script("alert('hello!')");
return 0;
}
Similar to how we called Python from C...
Difference doesn't matter though,
API is the same ;)
Implement a C API in JS:
// myLib.js
mergeInto(LibraryManager.library, {
js_func: function(x) { alert('you sent ' + x) }
});
// main.c (emcc main.c --js-library myLib.js)
void js_func(int x);
int main() {
js_func(3); // will cause alert('you sent 3')
return 0;
}
Very efficient:
// JavaScript output from last slide's files
function _js_func(x) { // from JavaScript library
alert('you sent ' + x);
}
function _main() { // compiled from C
_js_func(3);
return 0;
}
This is how emscripten implements C APIs (like SDL) using HTML5 APIs
Emscripten provides APIs on the JS side too
// C file that was compiled to JS
int c_add(int x, int y) { return x+y; }
// Call C from JS
var result = ccall('c_add', // name
'number', // return type
['number', 'number'], // argument types
[10, 20]); // arguments
// returns 30
cwrap is useful for multiple calls
// Call C from JS
var c_add = cwrap('c_add', // name
'number', // return type
['number', 'number']); // argument types
console.log(c_add(10, 20)); // 30
console.log(c_add(20, 30)); // 50
Wrapper behaves just like a normal JS function
Embind, written by IMVU, glues together C++ and JavaScript
// Access JS objects in C++ like C++ objects
#include "emscripten/val.h"
using namespace emscripten;
int main() {
val Math = val::global("Math");
return Math.call("abs", -10); // returns 10
}
Embind can also go the other way
// C++ library
#include "emscripten/bind.h"
using namespace emscripten;
int c_add(int a, int b) { return a+b; }
EMSCRIPTEN_BINDINGS(my_module) {
function("c_add", &c_add);
}
// Use it in JS
alert(Module.c_add(10, 20)); // shows 30
Classes as well:
// C++ class wrapped by Embind
class Cat {
string name;
public:
Cat(string name_) : name(name_) {}
void meow() { printf("%s meows\n", name.c_str());
};
EMSCRIPTEN_BINDINGS(Cats) { // much like Boost.Python...
class_<Cat>("Cat").constructor()
.function("meow", &Cat::meow);
}
// JavaScript
var myCat = new Module.Cat("Fluffy");
alert(myCat.meow()); // shows "Fluffy meows"
No way to know when a JS object is garbage-collected, must call myCat.delete() to clean it up
Weak refs in JavaScript (ES7) might help fix that
But overall, surprisingly easy despite big differences in languages
We can also connect JavaScript and dynamic languages running in JavaScript
In some ways this can be easier
The time in milliseconds, reported by Lua:
.
View source and search for text/lua if you don't believe ;)
We can use languages other than JavaScript on the web, by running them in JavaScript
Those languages can interact with JavaScript, allowing mixed-language projects
Thanks for listening!