for fun and profit!
My Fat Ass
Mud
c -> Emscripten -> javaScript
vitali@Moo:[~/demo] >> gcc
vitali@Moo:[~/demo] >> gcc hello.c -o hello.js
vitali@Moo:[~/demo] >> gcc hello.c -o hello.js -Wall
vitali@Moo:[~/demo] >> emcc hello.c -o hello.js -Wall
vitali@Moo:[~/demo] >> emcc hello.c -o hello.js -Wall
vitali@Moo:[~/demo] >>
OMG! Look! it's the same interface as gcc.
(more on that later...)
vitali@Moo:[~/demo] >> emcc hello.c -o hello.js -Wall
vitali@Moo:[~/demo] >> node hello.js
Hello World
OMG! Look! it's the same interface as gcc.
(more on that later...)
source code (.c )
> gcc hello.c -o hello
source code (.c )
> gcc hello.c -o hello
source code (.c )
compiler
> gcc hello.c -c
> gcc hello.c -o hello
source code (.c )
??
compiler
> gcc hello.c -c
> gcc hello.c -o hello
source code (.c )
object file (.o)
compiler
> gcc hello.c -c
> gcc hello.c -o hello
source code (.c )
object file (.o)
compiler
> gcc hello.c -c
> gcc hello.c -o hello
source code (.c )
object file (.o)
compiler
linker
> gcc hello.c -c
> ld hello.o -o hello -lc -e main
> gcc hello.c -o hello
source code (.c )
??
object file (.o)
compiler
linker
> gcc hello.c -c
> ld hello.o -o hello -lc -e main
> gcc hello.c -o hello
source code (.c )
Profit!
object file (.o)
compiler
linker
> gcc hello.c -c
> ld hello.o -o hello -lc -e main
> gcc hello.c -o hello
> man ld | grep "include gcc" -c
0
> man ld | grep "include gcc" -c
0
Q.E.D
IR
IR
IR
IR
define i32 @add1(i32 %a, i32 %b) {
entry:
%tmp1 = add i32 %a, %b
ret i32 %tmp1
}
define i32 @add2(i32 %a, i32 %b) {
entry:
%tmp1 = icmp eq i32 %a, 0
br i1 %tmp1, label %done, label %recurse
recurse:
%tmp2 = sub i32 %a, 1
%tmp3 = add i32 %b, 1
%tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3)
ret i32 %tmp4
done:
ret i32 %b
}
IR
IR
IR
IR
IR
IR
IR
IR
IR
IR
IR
IR
IR
IR
LLVM IR
LLVM IR
int fib(int num)
{
if (num < 1) return 0;
if (num == 1) return 1;
return fib(num-1) + fib(num-2);
}
function(global, env, heap) {
'use asm';
function _fib($num) {
$num = $num|0;
if (($num|0) < (1)) return 0;
if (($num|0) == (1)) return 1;
return ((_fib((($num-1)|0))|0) + (_fib((($num-2)|0))|0)) |0;
}
return {fib : _fib};
}
function($global, $env, $scope) {
'use asm';
function _ng$fib($num) {
$num = $num|0;
if (($num|0) < (1)) return 0;
if (($num|0) == (1)) return 1;
return ((_ng$fib((($num-1)|0))|0) + (_ng$fib((($num-2)|0))|0)) |0;
}
return {FactoryServiceInjectorProvider : _ng$fib};
}
function(global, env, heap) {
'use asm';
function _fib($num) {
$num = $num|0;
if (($num|0) < (1)) return 0;
if (($num|0) == (1)) return 1;
return ((_fib((($num-1)|0))|0) + (_fib((($num-2)|0))|0)) |0;
}
return {fib : _fib};
}
function(global, env, heap) {
'use asm';
.....
function(global, env, heap) {.....
return {fib : _fib};
function _fib($num) {
$num = $num|0;
function(global, env, heap) {
'use asm';
function _fib($num) {
$num = $num|0;
if (($num|0) < (1)) return 0;
if (($num|0) == (1)) return 1;
return ((_fib((($num-1)|0))|0) + (_fib((($num-2)|0))|0)) |0;
}
return {fib : _fib};
}
void init(DrawDabFunctionCallback draw_dab_cb,
GetColorFunctionCallback get_color_cb);
void stroke_to(float x, float y, float pressure,
float xtilt, float ytilt, double dtime);
typedef void (*GetColorFunctionCallback) (
float x, float y, float radius,
float* color_r, float* color_g,
float* color_b, float* color_a
);
typedef int (*DrawDabFunctionCallback) (
float x, float y,
float radius,
float color_r, float color_g, float color_b,
float opaque, float hardness,
float alpha_eraser,
float aspect_ratio, float angle,
float lock_alpha,
float colorize
);
// cwrap
var init = Module.cwrap("init", "void", ["number", "number"]);
var strokeTo = Module.cwrap("stroke_to", "void", R.repeat("number", 5));
// ccall
Module.ccall("init", "void", ["number", "number"], [drawDabProxyPtr, colorProxyPtr]);
Module.ccall("stroke_to", "void", R.repeat("number", 5), R.repeat(0, 5));
-s EXPORTED_FUNCTIONS="['_init','_stroke_to']"
var colorProxyPtr = Module.Runtime.addFunction(getColor);
var drawDabProxyPtr = Module.Runtime.addFunction(drawDab);
-s RESERVED_FUNCTION_POINTERS=2
var getColor = function(x, y, radius, r_ptr, g_ptr, b_ptr, a_ptr) {
var convert = R.map(R.divide(R.__, 255)); // look ma, I'm using ramda!
var color = convert([255, 215, 0, 255]);
Module.setValue(r_ptr, color[0], "float");
Module.setValue(g_ptr, color[1], "float");
Module.setValue(b_ptr, color[2], "float");
Module.setValue(a_ptr, color[3], "float");
};
window.Module
window.Module
window.Module
var m1 = MyModule();
var m2 = MyModule();
m1.ccall(...);
m1.Runtime.addFunction(...);
m2.ccall(...);
m2.Runtime.addFunction(...);
-s MODULARIZE=1 -s EXPORT_NAME="MyModule"
-g[4-1]
emcc src/native/main.c -I src/native/libmypaint -o bin/lib.debug.js -O0
-s EXPORTED_FUNCTIONS="['_init', '_stroke_to']"
-s RESERVED_FUNCTION_POINTERS="2"
-s NO_EXIT_RUNTIME="1" # don't exit after main() is done
-s MODULARIZE="1"
-s NO_FILESYSTEM="1"
-s NO_BROWSER="1"
vitali@Moo:[/dist] (master) >> wc -l `find ../native -name '*.c'`
.......
5363 total
vitali@Moo:[/dist] (master) >> ls -lh
total 692K
-rw-rw-r-- 1 vitali vitali 523K libmypaint.debug.js
-rw-rw-r-- 1 vitali vitali 166K libmypaint.release.js
vitali@Moo:[/dist] (master) >> wc -l `find ../native -name '*.c'`
.......
5363 total
vitali@Moo:[/dist] (master) >> ls -lh
total 692K
-rw-rw-r-- 1 vitali vitali 523K libmypaint.debug.js
-rw-rw-r-- 1 vitali vitali 166K libmypaint.release.js
vitali@Moo:[/dist] (master) >> wc -l `find ../native -name '*.c'`
.......
5363 total
vitali@Moo:[/dist] (master) >> ls -lh
total 692K
-rw-rw-r-- 1 vitali vitali 523K libmypaint.debug.js
-rw-rw-r-- 1 vitali vitali 166K libmypaint.release.js
-o3 -s NO_FILESYSTEM="1" -s NO_BROWSER="1"
function _usleep(useconds) {
.....
// We're single-threaded, so use a busy loop. Super-ugly.
....
while (self['performance']['now']() - start < msec) {
// Do nothing.
}
....
}
function _usleep(useconds) {
.....
// We're single-threaded, so use a busy loop. Super-ugly.
....
while (self['performance']['now']() - start < msec) {
// Do nothing.
}
....
}
void emscripten_sleep(unsigned int ms);
void emscripten_sleep_with_yield(unsigned int ms);
int main() {
...
#ifdef __EMSCRIPTEN__
// 60 fps , 1 -> simulate infinite loop
emscripten_set_main_loop(one_iter, 60, 1);
....
}