asm-js / validator

A reference validator for asm.js.
Apache License 2.0
1.78k stars 148 forks source link

DataView #47

Open curiousdannii opened 11 years ago

curiousdannii commented 11 years ago

It would be great if DataViews could be used to access the memory buffer. Any reason why they're not included?

kripken commented 11 years ago

No reason, we talked about it even, just need to get around to writing it up I think.

curiousdannii commented 11 years ago

I'd like to use this for a project of mine which will dynamically generate asm.js code. As typed arrays can't be made at odd offsets (other than Int8) it is very messy without DataViews. I'd love for this to be part of the spec before OdinMonkey gets included in a stable release.

kripken commented 11 years ago

Note that DataViews pose problems for some archs, like ARM where unaligned reads cause SIGILL. So it is not trivial to just support DataViews, but as I said, I think there is agreement this is worth investigating and doing.

curiousdannii commented 11 years ago

Hasn't the cross-arch work already been done for regular JS DataView? Or would you need to do it all again?

Or would 'shimming' DataView in my asm code not degrade its performance too much?

kripken commented 11 years ago

DataView works on ARM. But it is slower there. In asm, we could do the same, but it sort of goes against the spirit of asm, which is to generate very simple and fast machine code. There is no simple and fast machine code for unaligned reads/writes on ARM, sadly.

curiousdannii commented 11 years ago

I'm with you, but I'll push just a bit more. I know you do want to do it, I'm just sharing more reasons why I consider it important.

Ideally DataView would really just be some sugar around the appropriate machine code, as most of asm.js is, just it will likely be much more involved.

If DataView isn't available I will have to do something like this, as I do for IE compatibility now:

function getUint16( i ) { return array[i] << 8 + array[i + 1]; }

Ideally this would be inlined, and the performance would be about as good as we would all love. But will it be inlined? Will the JIT do a whole bunch of unsigned to signed to unsigned conversions? What about the cases when a constant even address is used, or, what about if it works out faster to getUint32 and then select the appropriate bits from that?

If DataView is supported then the burden of performance is put on the VM developers, who can know all these answers, rather than the user, who won't. Anyone using DataView will know it won't be as fast as nice uniform arrays, but then if they could avoid DataView, they would.

vvuk commented 11 years ago

I don't think DataView is appropriate -- you would need to do the same thing you need to do in C/C++ to perform unaligned reads on platforms that don't support them; that's exactly like your getUint16 function. But of course I'd write it as an asm.js function inside your asm block instead of an external...

curiousdannii commented 11 years ago

What are the chances that this will get into Firefox before OdinMonkey is in a stable release?

ghost commented 10 years ago

The whole unaligned SIGILL business I think can be handled by using a signal handler, so that's not the issue. The more pressing issue is that DataView isn't optimized anywhere so any non-Odin compiler would run 10-100x slower, which definitely violates a current prime directive of asm.js. In a future where more browsers are optimizing asm.js, we could consider adding it (which would be an optimization over the current state since it'd allow us to avoid the alignment mask required for typed arrays).

Note: DataView requires a gnarly pattern in asm.js because we can't rely on the getInt32 property lookup along the prototype chain to succeed. Also, because of the terrible terrible default of isBigEndian = true. It requires something like:

function f(global, foreign, buffer) {
  "use asm";
  var getInt32Pre = global.Object.getOwnPropertyDescriptor(global.DataView.prototype, 'getInt32').get;
  var getInt32 = function(i) { return getInt32Pre(i, false) }
}

I'm hoping we can extend Function.prototype.bind to allow pass-through place-holders since that would avoid the lambda and by binding 'false' to the second arg of getInt32.