Support blink over{riding|loading} v8-defined APIs. |
||
Issue descriptionSee https://codereview.chromium.org/2780693003/ More context: We define wasm APIs in V8. Examples: the WebAssembly.Module constructor; the WebAssembly.compile function. In Chrome: - we want to restrict certain uses of these APIs. For example, we want to block constructing a web assembly module via the synchronous API, on the main thread, if the wire bytes (the uncompiled module) is larger than 4KB - when we do that, we want to provide a usable error message (example: "Synchronous compilation of wasm modules over 4K is disabled in Chrome on the main thread. Consider using web workers, or the asynchronous WebAssembly.compile API") - we want to add an override to WebAssembly.compile, which would take a Response object (or promise of a Response object). - we want to block wasm compilation if developer specifies content security policy (CSP) Layering means the definition of these Chrome specific behaviors needs to happen in Chrome. So far, we did this through a mechanism inspired by how we disable eval when CSPs are enabled: V8 exposes injection points. Example: pre-existing eval mechanism; wasm-specific controls. Trouble is, errors are thrown on the v8 side; and we still need a mechanism to override WebAssembly.compile (for the Response object parameter). Rather than adding injection points (or maybe generalizing the ones we have), we could more naturally think of all the Wasm API customization as "overriding" (ideally, we'd explain eval customization the same way - it's a function on Object, after all). I was looking for precedents to doing this in the Chrome codebase, and haven't found any. I can think of 3 options: 1) "Extras". This would allow us to define the overrides in JS, which is attractive (arguably more maintainable), however, I wasn't able to write code referencing Wasm APIs as an "extra", because we snapshot extras, and the wasm types aren't defined in the context used at snapshot time. (Or maybe I'm missing something about how extras work?) The JS stuff would be like this: // for vanilla method: var old = WebAssembly.compile; WebAssembly.compile = function(arg) { if (arg instanceof Response) { // call internal stuff } else { return old(arg); } } // for constructor: var ctor = WebAssembly.Module; var proto = WebAssembly.Module.prototype; WebAssembly.Module = function(arg) { // chrome stuff return ctor(arg); } WebAssembly.Module.prototype = proto; 2) Overrides defined in C++. Instead of injecting those callbacks, the embedder replaces the functions/constructors to be overriden. This is the C++ version of the stuff above. 3) The v8 side tests if there's an embedder-injected override behavior and calls it; otherwise performs as usual. I don't like option 3, it seems unnecessarily constrained: V8 controls when the overriding behavior happens. Then, it requires embedder-facing entrypoints every time we want to enable overriding by embedder; and finally, it is unnecessary since option 2 would "just work" without changes to V8, and provide all flexibility the embedder may want. I would love option 1 over option 2, for the maintainability/ease of authoring reason. Not sure about the limitations I've mentioned: are they real, or have I missed something? Are they easy to overcome, or would we be looking at a complex feature, which is probably overkill given the current motivation?
,
Apr 6 2017
(jbroman's suggestion) Another approach might be something like: - ES/V8 describes a symbol, let's say @@toWebAssemblyModule - if WebAssembly.compile is given an argument a with the @@toWebAssemblyModule property, it produces a promise, it returns Promise.resolve(a[Symbol.toWebAssemblyModule]()); otherwise it does what it does today - Web specs (and Blink) provide a partial interface for the Response object which provides a method named by the @@toWebAssemblyModule symbol (which either reinvokes WebAssembly.compile with an array buffer, or pulls a cached module from somewhere) Q: So I make sure I understand - this requires Response know about wasm, correct? A: In a sense, yes. But it wouldn't require it to be in the Response class, but would use the existing Blink mechanism for extending a class with additional features. For example, Window has 21 partial interfaces in Blink, for features like crypto, fetch, performance, storage, etc. Document has a partial interface for XPath and another for fullscreen, etc. On the blink side, this translates into calls into a static class methods, so the code adding additional functionality can be separated from the main class.
,
Apr 18 2017
We decided to just use the explicit overloading mechanism introduced by https://codereview.chromium.org/2773063002/ |
||
►
Sign in to add a comment |
||
Comment 1 by mtrofin@chromium.org
, Apr 6 2017