Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch and SharedArrayBuffer #897

Open
juj opened this issue Apr 17, 2019 · 6 comments
Open

Fetch and SharedArrayBuffer #897

juj opened this issue Apr 17, 2019 · 6 comments
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: api

Comments

@juj
Copy link

juj commented Apr 17, 2019

Multithreaded WebAssembly applications may wish to perform HTTP POST uploads from data that lives within their WebAssembly heaps. That is, they may execute

var x = new XMLHttpRequest();
x.open('POST', 'http://localhost.com/', true);
var a = new Uint8Array(new SharedArrayBuffer(10));
x.send(a);

but that fails with an error

VM231:1 Uncaught TypeError: Failed to execute 'send' on 'XMLHttpRequest': The provided ArrayBufferView value must not be shared.

as a workaround, one can perform a deep copy of the data from a shared array view to an unshared array view with

var x = new XMLHttpRequest();
x.open('POST', 'http://localhost.com/', true);
var a = new Uint8Array(new Uint8Array(new SharedArrayBuffer(10)));
x.send(a);

This works, but having to do this potentially large deep intermediate copy of all data to upload can be costly.

Several other entry points of web apis have been expanded to allow SABs as inputs. Would it make sense for xhr.send() as well?

CC @lars-t-hansen

@domenic
Copy link
Member

domenic commented Apr 17, 2019

In general I think XHR is considered legacy and new capability should not be added to it, but the same question with regard to the fetch() API might make sense.

@annevk annevk transferred this issue from whatwg/xhr Apr 18, 2019
@annevk
Copy link
Member

annevk commented Apr 18, 2019

Given that Fetch and XHR share some infrastructure it might end up affecting both, but let's discuss it in whatwg/fetch indeed. I've moved the issue.

I guess the semantics here would be that the browser does a copy and not reads the bytes lazily?

@annevk annevk added addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest labels Apr 18, 2019
@lars-t-hansen
Copy link

If the semantics are that the browser does a copy, you'll probably force it to make a copy, just to be sure that racing writes that would not be observable under a copy model are not in fact observed. What have we done elsewhere where we accept shared memory?

@annevk
Copy link
Member

annevk commented Apr 23, 2019

I don't think there really is precedent within the web platform necessarily. What do other software platforms do?

@annevk
Copy link
Member

annevk commented Jan 30, 2021

There is precedent now in https://encoding.spec.whatwg.org/#dom-textdecoder-decode.

@domenic @wanderview @ricea @ddragana thoughts on adding SharedArrayBuffer support to fetch()/Request/Response? Should we also have sharedArrayBuffer() on Body?

Or would we instead require folks to do this through streams somehow?

@annevk annevk changed the title XMLHttpRequest.send() with a SharedArrayBuffer as a source? Fetch and SharedArrayBuffer Jan 30, 2021
@ricea
Copy link
Collaborator

ricea commented Feb 1, 2021

I haven't looked at what would be required in detail, but my first instinct is that allowing reading from a SharedArrayBuffer would be relatively safe, as we always end up copying the data without otherwise inspecting it anyway. However, if some hypothetical browser wanted to do a zero-copy optimisation of uploads then some mischief might be possible.

Reading into a SharedArrayBuffer with streams it would look something like (untested):

async function toSharedArrayBuffer(response) {
  const parts = [];
  let totalLength = 0;
  for await (const buffer of response.body) {
    parts.push(buffer);
    totalLength += buffer.byteLength;
  }
  const sab = new SharedArrayBuffer(totalLength);
  const u8 = new Uint8Array(sab);
  let offset = 0;
  for (const buffer of parts) {
    u8.set(buffer, offset);
    offset += buffer.byteLength;
  }
  return sab;
}

This is certainly long and fiddly enough that it would be useful to have a built-in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs implementer interest Moving the issue forward requires implementers to express interest topic: api
Development

No branches or pull requests

5 participants