Fast binary data exchange between JavaScript and C/C++ with SpiderMonkey JS engine - spidermonkey

Recently I learned that there are "External Arrays" in V8. So when you embed V8 in your app, you can map your C-array to JS-array, and even choose a type, either it's char, word, int etc. This can significantly speed up data exchange between JS and C. Now the question is there something like that in SpiderMonkey?
I tried google for "spidermonkey external arrays", "binary arrays", "map arrays" and some more, no luck so far.
I have SpiderMonkey source code, but it will take ages to familiarize with it.

In SpiderMonkey you can use ArrayBuffer.
var buffer = new ArrayBuffer(16)
var int32View = new Int32Array(buffer);
for (var i = 0; i < int32View.length; i++) {
int32View[i] = i * 3
}
array_dump(buffer)
now C++ part:
#include "js/jstypedarray.h"
static JSBool my_array_dump(JSContext *cx, uintN argc, jsval *vp) {
JSObject *obj;
JS_ValueToObject(cx, vp[0 + 2], &obj);
js::ArrayBuffer *A;
A = js::ArrayBuffer::fromJSObject(obj);
int *B = (int*) A->data;
for (int i = 0; i < A->byteLength / 4; i++) printf("%i ", B[i]);
return JS_TRUE;
}
Seems like this way you can pass huge amounts of data between JS and C/C++ with virtualy no overhead.
Of course it would be better to have this clearly explained in SpiderMonkey docs. But as it often happens when you hack into Mozilla projects, you eventually end up digging the includes and sources, so I think this answer might be useful for somebody.

Related

Reassigning imports.env.memory for WebAssembly module doesn't replace heap

I am developing an in-browser player for a proprietary video format. Our old player was a Chrome NaCl plugin, while the replacement is to be implemented in JavaScript and WebAssembly.
The video decode is to be done in a pipeline using two webworkers, both managing WASM modules. One worker does zlib decompression, while the other decodes the pixels. It's important for performance to avoid buffer copies. So my proposed pipeline is this:
In main JS thread, allocate a new WebAssembly.Memory object and fill it with data from the video feed.
Hand off ownership to the decompress worker.
Replace the heap for its WASM module with the new memory.
Call the decompress function.
Detach the heap from this module and transfer ownership to the decode worker.
Replace the heap for this WASM module with the new memory.
Call the decode function.
Detach the heap from this module and transfer ownership back to the main thread for WebGL display.
To see if I could do this, I set up an experiment as follows:
C code for the WASM module:
void decode(unsigned char *in, unsigned char *out)
{
for (int i=0; i<10; i++) {
*out++ = *in++ + 100;
}
}
I compile it like this:
emcc test_wasm.c -O3 -s WASM=1 -s SIDE_MODULE=1 -s "EXPORTED_FUNCTIONS=['_decode']" -o test_wasm.wasm
And this is the JS code that loads it:
export class LoadWasm {
wasmOnLoad(obj) {
this.instance = obj.instance;
console.log("Loaded WASM");
console.log(obj.instance);
// Fill buffer with some numbers
for (var i=0; i<10; i++) {
this.heap[i] = i;
}
// Have WASM code copy the data, adding 100 to each number
obj.instance.exports._decode(0, 128);
// Print output
for (var i=0; i<10; i++) {
console.log(i + ": " + this.heap[i] + " => " + this.heap[i+128]);
}
// Allocate a new heap for the WASM module
this.memory = new WebAssembly.Memory({
initial: 256
});
this.heap = new Uint8Array(this.memory.buffer);
// Replace the WASM module's heap
this.imports.env.memory = this.memory;
// Fill the heap with new data
for (var i=0; i<10; i++) {
this.heap[i] = i+10;
}
// Run the compute again
obj.instance.exports._decode(0, 128);
// Print out the results
for (var i=0; i<10; i++) {
console.log(i + ": " + this.heap[i] + " => " + this.heap[i+128]);
}
}
constructor() {
this.memory = new WebAssembly.Memory({
initial: 256
});
this.heap = new Uint8Array(this.memory.buffer);
this.imports = {
env: {
__memory_base: 0,
memory: this.memory,
abort: function(err) {
throw new Error('abort ' + err);
},
}
};
}
start() {
console.log("startWasm");
WebAssembly.instantiateStreaming(fetch('test_wasm.wasm'), this.imports)
.then(this.wasmOnLoad.bind(this));
}
}
And it's invoked from my main HTML page like this:
import { LoadWasm } from "./test_wasm.js";
var l = new LoadWasm();
l.start();
Unfortunately, this doesn't work. The first call to _decode works fine. And it works fine again if I don't replace the heap. But if I do replace the heap, I only get back zeros. The WASM module isn't using the new heap.
Because there is no shared memory (yet) between webworkers and the main JS thread, the only way to transfer data zero-copy between webworkers is handing off ownership of objects. As a result, I can't do the obvious thing and pass around and fill subarrays of the existing heap. I need to be able to fill a new heap while doing processing on the previous one, in order to get the required parallelism.
To solve this, I can think of a few options:
Option 1: Is there a way to replace the heap of an already-instantiated WASM module, and I'm just doing it wrong?
Option 2: Maybe I can create a new instance of the WASM module for each frame to decode. But how do I load and compile the WASM code only once and keep reusing it? I think it still has to go through a linking process, though. How much overhead is there to do this? Is it worth it?
Option 3: I understand that WASM supports threads already. I could request a decode to occur in the main JS thread, and inside the WASM code, it would hand off the computation to a worker thread. The problem is finding out when the computation is done. Is there a way to do a postMessage from a non-main thread in WASM? It seems that if I were to try to call a JS function from a non-main WASM thread, that would probably fail or crash the browser.
Are there any other ideas?
Thanks!
Option 2: Maybe I can create a new instance of the WASM module for each frame to decode. But how do I load and compile the WASM code only once and keep reusing it?
Modules are compiled, not instances. So every new instance is reusing the compiled module.

How can you detect if ANY sounds are currently playing in soundJS?

How can you detect if any sounds are playing in soundJS?
I have lots of sounds firing on and off sometimes legitimately over the top of each other. I need a way to find out if any sounds are playing at any given time
ie. something like
createjs.Sound.isPlaying()
or
createjs.Sound.status()
Nothing exists like this in SoundJS currently.
You can look it up yourself, but it involves digging into private members, which is not recommended, and could break content down the road. Here is a quick sample:
function countActiveSounds() {
var s = createjs.Sound.activePlugin,
count = 0;
for (var n in s._soundInstances) {
var inst = s._soundInstances[n];
for (var i=0, l=inst.length; i<l; i++) {
var p = inst[i];
if (p.playState == "playSucceeded") { count++; }
}
}
return count;
}
This involves reading the private _soundInstances hash, and checking if the sound state is "playSucceeded". Once it is complete, the state will changed to "playFinished".
Again, use this with caution :)
It might make sense to log a feature request to the SoundJS GitHub.

A guide to differences between v8 versions 3.28.73 and 3.14.5.9

I'm trying to compile a node.js extension module against node-v0.12.2 and some v8 3.28.73 classes had lost methods which were there in version 3.14.5.9 (used in node-v0.10.10). Of course, this is only one of the errors I'm facing.
The error message follows
‘AsciiValue’ is not a member of ‘v8::String’.
The function which calls the method is very short
char * getStringArg(v8::Local<v8::Value> value)
{
v8::String::AsciiValue string(value);
char *str = (char *) malloc(string.length() + 1);
strcpy(str, *string);
return str;
}
Where can I find a guide to the big differences between these v8 versions?
I'm advancing by way of trial and error.

Xively and Node-Red

I'm fairly new at all this but have muddled my way to getting my Arduino to post values to a Xively stream I've named "Lux and Temp." Three values; count, lux, and temperature.
Now what I want to do is take those values and do something with them using Node-Red.
http://nodered.org
I have Node-Red up and running, but I'll be danged if I can figure out how to parse the data from the Xively API feed. https://api.xively.com/v2/feeds/1823833592
Sadly, I don't have enough reputation points to be able to actually post the data it returns to here, since it has more than 3 URLs embedded in the data. It's a LONG string of data too. ;)
I'm just stumped though as to how to write the function to extract the parts I want.
My initial want is to make a simple Twitter feed out of it. Something like;
"Count 40, Lux 30, Temp 78.3"
I'll eventually want to recycle the code for other things like making my RasPi do something; maybe a display or some LEDs. In either case I need to parse the data and build various messages with it.
Anybody have any experience with the Node-Red functions that can walk me through a solution? The Node-Red site is pretty awesome, but I think it assumes I'm a MUCH more experienced user than I really am. It gives hints, but frankly about all I know is fairly basic Arduino and trivial level Python.
OK, it shouldn't be too tricky, but try putting this in a function block:
var newPayload = "";
var count, lux, temp;
var data = msg.payload.datastreams;
for (var i = 0 ; i< data.length; i++) {
if (data[i].id === 'Count') {
count = data[i].current_value;
}else if (data[i].id === 'Lux') {
lux = data[i].current_value;
} else if (data[i].id === 'Temp') {
temp = data[i].current_value;
}
}
newPayload = util.format('Count: %s, Lux: %s, Temp: %s', count, lux, temp);
msg.payload = newPayload;
return msg;
You may need to add a msg.payload = JSON.parse(msg.payload); to the start if however your getting the feed from xively is not already considered to be json.
[edit]
You could also just run the flow through a JSON parse node. (I always forget the converter nodes)
You should be able to wire that to a twitter output node.

spotify models.Track object

is the spotify models.Track object restricted to non-local tracks only?
I've built a little spotify app that will calculate the total play time of some random assortment of tracks that are dropped into the sidebar, but it seems like the Track object doesn't get any information from local files.
Here's what I got so far:
models.application.observe(models.EVENT.LINKSCHANGED, function () {
totalTime = 0;
var links = models.application.links;
if (links.length) {
for (var i = 0; i < links.length; i++) {
var track = models.Track.fromURI(links[i], function(t) {
totalTime = totalTime + t.duration;
});
}
}
document.getElementById("time").innerHTML = secondsToString(Math.round(totalTime/1000)) ;
});
Everything is firing correctly and working great on spotify tracks, but the whole reason i wrote this little app was so that I could calculate the total time of some of my really long audiobook files. Anyone know of a solution?
Link to the documentation page.
If this is indeed the case, I think you've found a bug/oversight.
However, local file URIs look like this: spotify:local:Coldplay:Mylo+Xyloto:Paradise:277
That last parameter is the length of the track, in integral seconds. It's a hacky workaround, but you could parse the URI and use the figure from that instead of models.Track.

Resources