Passing array of objects to Javascript function from C?

1,338 views
Skip to first unread message

Robert Goulet

unread,
Sep 19, 2016, 4:57:43 PM9/19/16
to emscripten-discuss
Hi,

How do we pass an array of objects to Javascript function from C?

Consider the following example:

struct data {
    double a;
    int b;
    unsigned char c;
};

std::vector<data> my_data;

EM_ASM_ARGS({
    var data_array = ???
    process_data(data_array);
}, my_data);

Is this possible? I couldn't find any clear documentation about this topic.

For the moment I've used the following workaround, but it doesn't look super efficient:

for( auto const & i : my_data ) {
    EM_ASM_ARGS({
        process_data($0, $1, $2);
    }, i.a, i.b, i.c);
}

Thanks!

Alon Zakai

unread,
Sep 19, 2016, 5:45:21 PM9/19/16
to emscripten-discuss
The most efficient way is to send the pointer into EM_ASM, then do reads directly to memory using the right offsets, but that requires using information about how the data is laid out in memory (on the plus side, the alignment rules are the natural 32-bit ones, with fully aligned doubles).

Otherwise multiple calls into EM_ASM adds overhead, but in many cases it wouldn't be noticeable.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Robert Goulet

unread,
Sep 20, 2016, 9:45:13 AM9/20/16
to emscripten-discuss
Do you have an example of sending pointer into EM_ASM and reading it directly from memory?

In my case I am calling EM_ASM close to a thousand times to pass engine profiling data to javascript for drawing on the web page, so I am trying to avoid adding time to the profiling result. If EM_ASM does add overhead, then I hope to reduce it by calling it only once instead of a thousand times per frame. I profiled it to about ~2.5ms per frame to do these thousand calls to EM_ASM, which is a lot if you consider the actual frame time is <= 17ms.

Jukka Jylänki

unread,
Sep 20, 2016, 12:33:01 PM9/20/16
to emscripte...@googlegroups.com
The src/library_xxx.js files are generally good examples.

Here's one snippet where C function passes a pointer to an integer array and length of that array to JS side, and JS code reads through the array: https://github.com/kripken/emscripten/blob/master/src/library_openal.js#L329. If not using JS code that lives in js-libraries, the i32 {{{ makeGetValue }}} can be replaced with a direct HEAP32[pointer >> 2].

Another example with filling a struct in JS side: https://github.com/kripken/emscripten/blob/master/src/library_html5.js#L180

and reading the fields from a pointer to a struct: https://github.com/kripken/emscripten/blob/master/src/library_html5.js#L1728



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

For more options, visit https://groups.google.com/d/optout.

Robert Goulet

unread,
Sep 20, 2016, 4:27:53 PM9/20/16
to emscripten-discuss
Thanks jj, I ended up using getValue on the JS side to get the data from the pointer I pass from C. Is there any performance concerns with this or should I use HEAP32 instead?
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.

Jukka Jylänki

unread,
Sep 20, 2016, 4:36:47 PM9/20/16
to emscripte...@googlegroups.com
Directly accessing HEAP32 will definitely be much faster than the very generic getValue() function. If you don't need any of the genericity of what getValue() offers, using HEAP32 is definitely recommended.

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

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Robert Goulet

unread,
Sep 20, 2016, 4:41:56 PM9/20/16
to emscripten-discuss
The JS code looks like this:

event.time = getValue(addr, 'double');
event.name = Pointer_stringify(getValue(addr + 8, '*'));
event.thread_id = getValue(addr + 12, 'i32');
event.type = getValue(addr + 16, 'i8');
event.core_id = getValue(addr + 17, 'i8');

since the different elements of the structure varies in size, I guess I have to use different HEAP methods?
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.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Charles Vaughn

unread,
Sep 20, 2016, 5:06:05 PM9/20/16
to emscripten-discuss
If you're struct is packed (or you know the padding points) and contiguous, you can use a DataView ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView ) to wrap a slice of the underlying buffer of the various HEAPs.

Something like: 

var view = new DataView(HEAP8.buffer.slice(addr));
event.time = view.getDouble(0, true);
event.name = Pointer_stringify(view.getUint32(8, true));
event.thread_id = view.getInt32(12, true);
event.type = view.getInt8(16, true);
event.core_id = view.getInt8(17, true);

Jukka Jylänki

unread,
Sep 21, 2016, 4:14:05 AM9/21/16
to emscripte...@googlegroups.com
You can also go via the HEAP objects, so

event.time = HEAPF64[addr>>3];
event.name = Pointer_stringify(HEAP32[addr+8 >> 2]);
event.thread_id = HEAP32[addr+12 >> 2];
event.type = HEAP8[addr + 16];
event.core_id = HEAP8[addr + 17];

event.core_id = view.getInt8(17, true);
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Charles Vaughn

unread,
Sep 21, 2016, 5:10:16 PM9/21/16
to emscripten-discuss
Yeah, I usually end up screwing up the pointer shifts.

Another thing to keep in mind is if you used packed structs (don't recommend that for Emscripten built code), you'll need to do something like DataView.
event.core_id = view.getInt8(17, true);
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.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Robert Goulet

unread,
Sep 21, 2016, 5:23:48 PM9/21/16
to emscripten-discuss
Thanks guys, the code works as expected now. I didn't get back as much performance as I hoped but its faster nonetheless. Cheers!

Robert Goulet

unread,
Nov 2, 2016, 3:22:48 PM11/2/16
to emscripten-discuss
Question about Emscripten HEAP access, is there a way to read 64bit integer signed/unsigned values? I see HEAPF64 and HEAP32, etc., but no HEAP64?

Thanks!

Brion Vibber

unread,
Nov 2, 2016, 3:53:34 PM11/2/16
to emscripten Mailing List
JavaScript can't natively handle 64-bit integers, and there's no Int64Array type to read from.

If you know the value will be in the range of 53 bits, or don't care that precision will be lost at larger magnitudes, then it can be handled as a double-precision float on the JS side:

  var low = Module.HEAP32[ptr / 4];
  var high = Module.HEAP32[(ptr + 4) / 4];
  var double = high * Math.pow(2, 32) + low;

-- brion

Thanks!
event.core_id = view.getInt8(17, true);
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Robert Goulet

unread,
Nov 2, 2016, 3:58:06 PM11/2/16
to emscripten-discuss
Ok, but then how does Emscripten handles C/C++ code that deals with int64_t/uint64_t values?
Thanks!
event.core_id = view.getInt8(17, true);
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.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Charles Vaughn

unread,
Nov 2, 2016, 4:19:36 PM11/2/16
to emscripten-discuss
With the Closure library's long support: https://github.com/kripken/emscripten/blob/incoming/src/long.js

Alon Zakai

unread,
Nov 2, 2016, 9:12:54 PM11/2/16
to emscripten-discuss
Actually, we used to use closure's long.js, but should not be using any of it now. Last usage was for printing, which I think is no longer relevant since we use musl printing.

We basically just lower the i64s into pairs of i32s, and emit code that emulates the i64 operations. That's for asm.js - in wasm, both asm2wasm and the wasm backend emit proper i64s directly. They can't be reflected into JS though, for the reasons mentioned above, and at the boundary to JS will assume a 32-bit pair (so an i64 parameter to a function becomes 2 parameters, etc.).

Thanks!
event.core_id = view.getInt8(17, true);
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
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-discuss+unsubscribe@googlegroups.com.

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