Open Bug 1450827 Opened 6 years ago Updated 2 years ago

[meta] Deprecate JS-Implemented WebIDL

Categories

(Core :: DOM: Core & HTML, enhancement, P3)

enhancement

Tracking

()

People

(Reporter: bholley, Unassigned)

References

(Depends on 2 open bugs)

Details

(Keywords: meta)

At one point in Mozilla's history, it was fashionable to implement browser functionality in JS whenever possible. This led to people doing lots of hacky things to implement web-exposed DOM functionality in JS, a practice that increased significantly in the B2G era. The hacky exposure mechanics caused lots of correctness and security issues, so we built a more robust mechanism to support JS implementations of WebIDL APIs. This solved some of the problems, but not all of them.

There are several fundamental issues that make JS a poor fit for DOM API implementations:

(1) Memory - Unlike native code, the memory overhead of JS code is duplicated per-process. This isn't a problem for frontend code, which only lives in the parent process (modulo frame scripts). But it is a problem when implementing the web platform, and will become more of a problem as we scale up the number of content processes.

(2) Security - Writing things in JS mostly eliminates the threat of memory hazards, but introduces other sorts of hazards (i.e. confused deputy bugs). Slaughterhouse solved a lot of these issues, but not all of them. Gecko C++ is safer than it used to be, and we now have the option of writing things in Rust where safety is a particular concern (i.e. string processing).

(3) Performance - JS-implemented WebIDL has double the FFI/marshaling overhead, since we have to convert everything into C++ and then back to JS again.

(4) Complexity / Special Snowflakes - We have very little DOM code written in JS, and so the sprinkling of JS we have introduces a whole separate set of quirks and idioms that people need to understand. Ripping out the support for this in the binding machinery would be nice too.

Now that the b2g code is gone, the only significant consumer is this stuff is WebRTC [1]. Moving that into native code isn't an urgent priority, but it would be nice to get there eventually (I spoke to Nils about this). In the mean time, I think we should avoid adding new JS-implemented DOM code.

Thoughts?

[1] https://searchfox.org/mozilla-central/search?q=JSImplementation&path=dom%2Fwebidl
We also have a couple of non-trivial add-on manager APIs that are exposed via WebIDL. They probably wouldn't be too difficult to convert to C++, though.

I don't really have any objections. Most extension APIs are implemented in JS, but they can't use WebIDL for a number of reasons (not least because they aren't all present at compile time). And I think Mossop is working on figuring out how we should handle things like AboutCapabilities in the future. I don't think JS WebIDL is going to be the answer.
I'm not sure I'm persuaded by this reasoning.

My reasoning here is that the code to implement WebIDL is in many ways much more like Web code than it is like systems programming code, and so it's not really that great a fit for a systems programming language like C++ or Rust. When we were writing the WebRTC code, it generally seemed to me easier to put logic in JS when we could, thus shimming the kind of library APIs that C++ is good at exposing to the webby APIs that WebIDL wanted. Obviously, others may well feel differently.

You raise four points, which I'll take in order from least to most compelling.

1. Complexity: I think the relevant sentence is "We have very little DOM code written in JS,". Sure, but this just devolves to the question of what the idiom ought to be. If we were to say you should generally implement these APIs in JS, then the argument would push the other way.

2. Memory/Performance: These seem like they're really the same underlying point, namely that this is expensive. I think the question here really is what the measured difference is. You raise the example of WebRTC. Can we get some measurement of what the actual impact is.

3. Security: I would probably need more detail here, but if there are insurmountable security problems, then obviously that's a big deal.

With that said, I'm not particularly attached to the existing code -- I'm not even sure how much of by WebRTC JS survives -- so if the consensus is that we ought not to have WebIDL implemented in JS, I'm not going to argue very hard.
Sorry "by WebRTC JS" should be "my WebRTC JS", as I know there has been a lot of rewriting.
(In reply to Eric Rescorla (:ekr) from comment #2)
> My reasoning here is that the code to implement WebIDL is in many ways much
> more like Web code than it is like systems programming code, and so it's not
> really that great a fit for a systems programming language like C++ or Rust.

In principle I agree that it's easiest to talk to JS from JS. The key difference here, though, is that the Web Platform needs to implement all sorts of strict and careful semantics at the content boundary. So many of the obvious and idiomatic things you would do from JS (new()ing a Promise, passing along an object literal, pulling properties off the Window, etc) can subtly do the wrong thing, leading to correctness/security issues.

The frontend is a separate story, because the relative proportion of code at the boundary with web content is much smaller. I agree that self-hosting is a big win for us there.

> When we were writing the WebRTC code, it generally seemed to me easier to
> put logic in JS when we could, thus shimming the kind of library APIs that
> C++ is good at exposing to the webby APIs that WebIDL wanted. Obviously,
> others may well feel differently.

I definitely agree that JS has ergonomic advantages for writing certain types of code. I'm just not convinced it's enough to warrant the significant investment we'd need to get to "great" here, especially when "dead" is so close within reach.

> 
> You raise four points, which I'll take in order from least to most
> compelling.

Another point, which I forgot to mention, is that JS-Implemented WebIDL APIs can't be exposed to workers. Adding support for that would be doable but quite a lot of work, much of it security-sensitive - and avoiding bytecode duplication would be even harder. The net result here is that a lot of the DOM APIs that were written in JS (like Console) got rewritten in C++.

> 
> 1. Complexity: I think the relevant sentence is "We have very little DOM
> code written in JS,". Sure, but this just devolves to the question of what
> the idiom ought to be. If we were to say you should generally implement
> these APIs in JS, then the argument would push the other way.

In practical terms, the dominant idiom (native code) is unlikely to change. We can tractably eliminate one idiom by moving all our JS-implemented DOM APIs to native code, but not by doing the opposite.

> 2. Memory/Performance: These seem like they're really the same underlying
> point, namely that this is expensive. I think the question here really is
> what the measured difference is.

I want to emphasize that there are different kinds of expensive - some of which scale with usage of the API, others of which are fixed when the API is used at all. My memory concern is mostly the latter.

> You raise the example of WebRTC. Can we get
> some measurement of what the actual impact is.

Not sure offhand, measurements would be good (mccr8 may have some).

I'm not too worried about the per-process impact of WebRTC because it's not used on many origins. But I'm confident that moving even a small percentage of our existing DOM APIs to JS would become a bottleneck for getting our per-process memory overhead to where it needs to be. So my main point here is that we likely can't afford very much JS-Implemented DOM code in the grand scheme of things, at which point the investment is tough to justify.

> 3. Security: I would probably need more detail here, but if there are
> insurmountable security problems, then obviously that's a big deal.

There are footguns that are very hard to eliminate while still allowing authors to write idiomatic JS code. Happy to get into some of those details offline.
As you know, I've been proponent of this for ages. Simplifying the platform makes it easier to maintain. Fewer weird idioms for reviewers (and patch authors) to know. 

Not that it matters too much, but also other browser engines seem to have dropped supporting js implemented webidl APIs.
I think the deprecation makes sense.

We can now use Rust for the kind of DOM back end code that's scare in C++, so we don't need JS to fill that role. Bug 1449861 should improve the match of WebIDL and Rust (and cause less copying in the ASCII case than currently happens with C++ code).

I've modified WebRTC code only once, but I don't see the JS usage in WebRTC as a compelling demonstration of JS-implemented WebIDL being something that we should use. The WebRTC JS code looks pretty thin and delegates a lot to C++ objects like PeerConnectionImpl. The JS layer doesn't appear to do things that are particularly nice to do in JS, either. I have trouble seeing the value of the JS layer between the Web-facing WebIDL and the C++-based FooImpl objects.
JS implemented WebIDL is also for main thread only, so implementing API first in JS will require one to reimplement in C++ later if/when the API should be supported in workers.
Depends on: 1451045
Depends on: 1252660
Bobby, we are trying to apply a unified behavior model to all of our about pages. In more detail, we try to establish a security model that builds upon a well defined API which allows content privileged about pages to query needed information not available in the content process.

We landed the fundamental architecture of that model within Bug 1430751. To ease adoption by front end developers, which mostly will be maintaining about pages, we decided to implement AboutCapabilities.webidl within JS. While it would be possible to rewrite AboutCapabilities within C++, it defeats the purpose of why we decided to implement that WebIDL in JS in the first place.

I agree that in most cases there is no need to have JS implemented WebIDLs, but doesn’t this case make a good case to not deprecate JS implemented WebIDLs?
Flags: needinfo?(bobbyholley)
Mossop and I discussed this yesterday. I agree that the current setup works well for interfaces that are basically internal but that we want to expose to unprivileged about:pages. However, as far as I can tell that's just l10n and AboutCapabilities, and I'm not entirely convinced it's worth keeping around such a large amount of Codegen and dom bindings complexity for that.

Looking at the current state of AboutCapabilities, it looks mostly trivial to implement in C++. If something more complex were to arise, you could forward the logic to a js-implemented XPIDL component, which Mossop is prototyping now.
Flags: needinfo?(bobbyholley)
Priority: -- → P3
Component: DOM → DOM: Core & HTML
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.