Passing ArrayBuffer from Js to compiled C++ code and receive processed ArrayBuffer back

2,549 views
Skip to first unread message

llu...@gmail.com

unread,
Apr 12, 2014, 5:19:34 AM4/12/14
to emscripte...@googlegroups.com
I am in the process of porting a crypto implementation to JS using emscripten.  The compilation of C++ code to js is pretty smooth. But I have some issues in dealing the interaction of JS and compiled C++ code. I have a few question and hope to get some advice from this list. 

1. In recent releases uses fastcomp, and and it seems embind no longer works. If I use 'extern "C"' to disable the c++ mangling, and use cwrap to call c function from Js, it should work, right?

2. I personally prefer to use "embind", that allow me to expose C++ class to JS directly. I will have to use 12.0 or earlier release. Is it a recommended practice? Can I expect embind be supported again?

3. I need to pass ArrayBuffer from JS to compiled C++ code, and get back a new (or modified) ArrayBuffer. It is not clear to me how can I do it. The simplified code will be something like this:
class MyCrypto {
   MyCryto();
 
   void Process(const string& input, vector<string>& output); 
};

EMSCRIPTEN_BINDINGS(MyCryptoModule) {
  class_<MyCrypto>("MyCrypto").constructor()
  .function("Process", &MyCrypto::Process);
  register_vector<std::string>("VectorString");
}


This code compiled well. But I don't know how JS code can be written to call function. 

var crypto = new Module.MyCrypto();
crypto.Process(...);

I would like the input to be ArrayBuffer, 
var input = new ArrayBuffer(256);

What will be the output look like? Will this work at all? 

If std::vector brings trouble, I can give it up and change "output" to be std::string. 
   void Process(const string& input, string& output); 

Compiler will complain about this form. 
error: non-const lvalue reference to type 'basic_string[[3 * ...]>' cannot bind to a temporary of type 'basic_string[[3 * ...]>

Thanks in advance

lucoy

 

Joshua Litt

unread,
Apr 13, 2014, 2:23:02 PM4/13/14
to emscripte...@googlegroups.com
I can't speak to the nuances of what you are trying to do, personally I abandoned embind when it became clear I would end up having to wrap my entire api anyways.  The regular emscripten C interfaces are pretty intuitive, though I am not sure there is anyway to pass in structs and this has made it a real pain for me(20+ arguments to functions).

This article: http://kapadia.github.io/emscripten/2013/09/13/emscripten-pointers-and-pointers.html explains well how to pass in arrays to emscripten compiled C, you can wrap your C++ functions in C and then pass in arrays that way.

Sorry I can't help more with embind.

Chad Austin

unread,
Apr 14, 2014, 3:01:23 PM4/14/14
to emscripte...@googlegroups.com
Hi lucoy,

On Sat, Apr 12, 2014 at 2:19 AM, <llu...@gmail.com> wrote:
2. I personally prefer to use "embind", that allow me to expose C++ class to JS directly. I will have to use 12.0 or earlier release. Is it a recommended practice? Can I expect embind be supported again?

fastcomp embind is a work in progress.  There is a pull request which enables embind in fastcomp, but it breaks asm.js validation as we don't yet have a great solution for embind being able to look up C++ functions by function pointer.

https://github.com/kripken/emscripten/pull/2287

3. I need to pass ArrayBuffer from JS to compiled C++ code, and get back a new (or modified) ArrayBuffer. It is not clear to me how can I do it. The simplified code will be something like this:
class MyCrypto {
   MyCryto();
 
   void Process(const string& input, vector<string>& output); 
};

EMSCRIPTEN_BINDINGS(MyCryptoModule) {
  class_<MyCrypto>("MyCrypto").constructor()
  .function("Process", &MyCrypto::Process);
  register_vector<std::string>("VectorString");
}

If I recall correctly (confirm this), an emscripten-bound function taking std::string can be given an ArrayBuffer.  That is, you could call:

var ab = new Uint8Array(...);
crypto.Process(ab, ...);

embind will handle the copy from the array buffer to the std::string.

Now, getting the data _out_ is a little trickier.  There is a way to zero-copy transfer an ArrayBuffer from C++ to JavaScript in embind.  It's called memory_view, and we mostly use it for WebGL.

So what you could do is something like:

void Process(const std::string& input, emscripten::val onComplete) {
    // generate output from input
    onComplete(emscripten::memory_view(output_size, output_ptr));
}

On the JavaScript side, you would call:

Process(input_buffer, function(output) {
    // output is a Uint8Array that aliases directly into the Emscripten heap
});

Does that help?

This code compiled well. But I don't know how JS code can be written to call function. 

var crypto = new Module.MyCrypto();
crypto.Process(...);

I would like the input to be ArrayBuffer, 
var input = new ArrayBuffer(256);

What will be the output look like? Will this work at all? 

If std::vector brings trouble, I can give it up and change "output" to be std::string. 
   void Process(const string& input, string& output); 

Why not write:

std::string Process(const std::string& input)

?  Output reference parameters generally aren't necessary in C++11.
 

Compiler will complain about this form. 
error: non-const lvalue reference to type 'basic_string[[3 * ...]>' cannot bind to a temporary of type 'basic_string[[3 * ...]>

Thanks in advance

lucoy

 

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Chad Austin
Technical Director, IMVU

llu...@gmail.com

unread,
Apr 16, 2014, 1:12:34 PM4/16/14
to emscripte...@googlegroups.com
Thanks for the link to that article, it is very helpful. I am trying that approach now. 

lucoy

llu...@gmail.com

unread,
Apr 16, 2014, 1:16:25 PM4/16/14
to emscripte...@googlegroups.com
Thanks Chad. 

I decided not to delay the use of embind for now. Once it is submitted to latest version again, I plan to try again. 

lucoy
Hi lucoy,

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages