0% found this document useful (0 votes)
21 views

Embind and Emscripten - Blending C++11, JavaScript, and The Web Browser - Chad Austin - CppCon 2014

Uploaded by

alan88w
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

Embind and Emscripten - Blending C++11, JavaScript, and The Web Browser - Chad Austin - CppCon 2014

Uploaded by

alan88w
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 76

Hi,

 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  

You might also like