Embind and Emscripten - Blending C++11, JavaScript, and The Web Browser - Chad Austin - CppCon 2014
Embind and Emscripten - Blending C++11, JavaScript, and The Web Browser - Chad Austin - CppCon 2014
my
name
is
Chad
Aus0n,
technical
director
at
IMVU,
and
today
we’re
going
to
talk
about
a
library
we’ve
developed
for
connec0ng
C++
and
JavaScript
with
Emscripten.
1
2
IMVU
is
an
online
social
plaIorm
where
you
can
sign
up,
dress
up
an
avatar,
and
meet
people
from
all
around
the
world.
We
offer
other
ac0vi0es
such
as
games
as
well.
3
The
content
in
our
world
is
created
by
our
customers,
and
to
our
knowledge,
we
have
the
largest
catalog
of
3D
virtual
goods
on
the
Internet.
4
We
currently
offer
a
downloadable
applica0on
for
Windows
and
Mac.
Windows
and
Mac
are
great
plaIorms,
but
in
recent
years,
other
plaIorms
have
grown
to
prominence.
We’d
like
our
content
available
everywhere:
mobile
plaIorms,
desktop,
server-‐side
renderers,
and
even
the
web
browser!
For
almost
all
plaIorms,
it’s
obvious
that
C++
is
a
great
choice
for
the
core
engine.
However,
our
big
ques0on
was,
what
about
the
web
browser?
In
2011,
I
benchmarked
an
upcoming
tool
called
Emscripten
and
was
quite
impressed.
5
Emscripten
works
very
well
in
prac0ce,
so
the
implica0on
is
that
C++
is
the
portable,
high-‐performance
language
EVERYWHERE.
6
Here
is
our
Emscripten
applica0on
running
in
Firefox.
UI
is
HTML
and
CSS.
Chat
over
WebSockets,
graphics
in
WebGL.
7
asm.js
is
the
subset
of
JavaScript
that
can
be
sta0cally
compiled
into
machine
code.
More
informa0on
at
h`p://asmjs.org/
8
The
C
heap
is
stored
in
an
ArrayBuffer
in
JavaScript.
One
con0guous
blob
of
memory.
This
memory
is
indexed
by
eight
different
typed
array
views
that
alias
each
other.
This
is
how
C
memory
seman0cs
are
implemented.
9
In
this
example,
we
can
see
how
the
load,
increment,
and
store
are
translated
into
JavaScript.
The
p
=
p
|
0
line
indicates
that
p
is
an
unsigned
32-‐bit
integer.
The
second
line
is
a
load,
addi0on,
and
store.
It
can
get
compiled
into
a
single
instruc0on
in
a
good
JavaScript
JIT.
10
Compila0on
is
just
half
of
the
story.
Without
being
able
to
access
the
plaIorm’s
capabili0es,
your
program
can’t
do
anything
interes0ng.
Emscripten
provides
a
whole
bunch
of
APIs.
It
implements
a
bunch
of
POSIX
and
has
some
hand-‐rolled
APIs
for
specific
bits
of
browser
func0onality.
11
Here’s
an
example
of
how
I
can
translate
a
bit
of
JavaScript
into
the
equivalent
Emscripten
C++.
The
body
of
the
lambda
will
run
a
second
in
the
future.
Func0ons
like
this
are
very
useful
when
available.
But
we
can’t
hope
that
Emscripten
will
implement
handy
dandy
wrappers
for
everything.
Browsers
have
hundreds
and
thousands
of
APIs
and
are
always
adding
more.
Embind
sets
out
to
make
it
possible
to
access
these
JavaScript
APIs
directly
from
C++.
12
In
addi0on,
Embind
makes
it
possible
to
use
C++
libraries
from
web
applica0ons.
You
can
take
exis0ng
C++
and
expose
it
to
JavaScript.
13
14
15
16
It’s
important,
when
building
bindings,
to
realize
you’re
building
a
JavaScript
API.
You
need
to
think
about
how
it’s
going
to
be
used
from
JavaScript.
Thus,
Embind
tries
to
use
JavaScript
terminology
when
appropriate.
Embind
tries
to
have
minimal
overhead
–
unlike
Boost.Python.
17
18
19
20
When
the
‘health’
property
is
accessed
from
JavaScript,
it
actually
calls
the
underlying
C
++
ge`er
and
se`er.
21
Enums
are
nice
and
simple,
but
it’s
important
to
give
everything
a
name
so
JavaScript
can
find
it.
22
23
24
25
What
is
p?
Well,
it’s
actually
an
Embind
Instance
Handle.
That
is,
it’s
a
special
JavaScript
object,
provided
by
Embind,
that
holds
a
raw
pointer
into
the
Emscripten
heap,
where
a
Point
struct
lives.
If
you
don’t
delete
p,
the
Point
in
the
Emscripten
heap
leaks!
26
To
that
end,
Embind
provides
value
types,
which
denote
that
a
type
will
be
passed
by
value
across
the
language
boundary.
You
can
either
bind
to
JavaScript
Objects
or
JavaScript
Arrays
27
I
wish
value_object
.field
was
called
.property,
given
we
want
Embind
to
use
JavaScript
terminology.
J
Maybe
we’ll
rename
that.
28
29
30
31
32
33
34
func0on(name,
&fp)
generates
the
signature
informa0on
at
compile
0me
from
the
func0on
pointer.
35
_embind_register_func0on
is
the
internal
implementa0on
of
func0on().
36
37
_embind_register_func0on
is
called
from
C++
but
implemented
in
JavaScript.
38
39
40
Na0ve
executables
pay
almost
no
penalty
for
huge
executables,
since
they’re
just
memory-‐mapped
and
paged
in
as
executed.
However,
JavaScript
applica0ons
require
the
customer
to
use
the
network
connec0on
to
download
and
their
CPU
to
parse
and
op0mize
the
JavaScript.
So
even
dead
code
hurts
in
JavaScript.
Careful!
41
42
43
44
asm.js
func0on
pointers
are
typed.
They
are
indices
into
typed
func0on
pointers.
So
a
func0on
pointer
isn’t
enough
informa0on
to
look
up
the
corresponding
JavaScript
func0on:
you
need
to
know
which
table
to
look
at
too.
45
First,
we
need
to
be
able
to
map
a
type
to
the
corresponding
asm.js
signature
code.
46
Take
a
func0on
pointer
as
argument,
but
don’t
use
its
value,
just
its
deduced
type.
Then,
create
a
sta0c
constexpr
character
array
where
the
first
entry
is
the
SignatureCode
of
the
first
type,
followed
by
the
SignatureCodes
of
the
argument
types,
followed
by
the
termina0ng
zero.
This
produces
a
compile-‐0me
constant
string!
If
you
call
getSignature,
the
call
is
completely
inlined
and
op0mized
down
to
a
single
constant
pointer
into
the
applica0on’s
sta0c
data
segment.
47
48
The
return
types
and
argument
types
are
passed
in
the
argTypes
array.
The
return
type
is
the
first
element.
Remember
that
TYPEID
is
simply
a
unique
iden0fier
for
a
type,
and
we
can
compute
a
TYPEID
from
a
type
at
compile
0me.
49
50
51
52
53
The
implementa0on
of
LightTypeID
allocates
a
byte
in
the
sta0c
data
segment…
and
uses
that
byte’s
address
as
the
TYPEID!
We
know
it
doesn’t
conflict
with
typeid,
since
two
objects
can’t
share
an
address.
I
don’t
fully
understand
the
linkage
rules
that
make
the
template
defini0on
legal
in
a
header,
but
someone
in
the
audience
said
what
I’m
doing
is
okay.
J
54
55
Once
we
have
the
ability
to
look
up
TYPEIDs
from
argument
lists,
we
can
build
a
sta0c
array
of
them
at
compile
0me…
And
then
use
its
constant
address
as
the
signature
descrip0on.
56
Auer
the
above
op0miza0ons,
func0on
registra0on
is
en0rely
table-‐driven,
resul0ng
in
small
generated
code.
57
58
59
60
61
62
63
64
select_overload
simplifies
overload
selec0on
syntax
by
only
requiring
the
interes0ng
bit
of
knowledge
–
the
desired
func0on
signature
–
while
not
requiring
inferred
informa0on
such
as
the
class
type.
65
select_overload
is
overloaded:
once
for
func0on
pointers,
and
once
for
member
func0on
pointers.
66
67
68
69
Given
a
captureless
lambda
type
with
unknown
signature,
we
want
to
convert
the
lambda
into
a
func0on
pointer,
so
that
we
can
use
the
func0on
pointer
to
deduce
the
signature
for
the
binding.
70
Maybe
this
should
be
in
the
standard.
71
Give
a
lambda,
we
can
grab
a
pointer
to
its
call
operator,
remove
the
“member-‐ness”
from
the
call
operator’s
type,
and
then
we
have
the
appropriate
func0on
type
for
the
lambda.
72
op0onal_override
simply
calls
the
lambda’s
implicit
func0on
pointer
conversion
operator.
73
74
75
76