-
Notifications
You must be signed in to change notification settings - Fork 73
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
(ref null extern)? #142
Comments
May I ask what the last minute change of renaming |
AFAIK the C API hasn't been updated since that change was made, so it pretty much reflects the "before" state. (Confusingly, it does have an "Extern" class, but it means something else.) The primary motivation for the late change to the reftypes proposal was to avoid funcref being a subtype of anyref, in order to allow engines to represent funcrefs differently (e.g. as fat pointers). That left the former "anyref" being used only for external references, so it was renamed to "externref" to reflect that. With the GC proposal now looking to re-introduce an "anyref" top type that every other reference is a subtype of, this decision would effectively be reversed. (Which was the primary counter-argument raised back then: if we'll reintroduce anyref anyway, then dropping it temporarily is just churn.) To be fair, as the ongoing discussions indicate, it's not entirely clear yet what will happen to the type system described in the current version of the GC proposal.
I don't think the fact that "externref" exists is creating any problems. It only creates the question how exactly it should be designed, in particular regarding its relations and interactions with the other types. If the reftypes proposal had kept anyref as a top type, then we wouldn't be facing this question now; we'd simply be stuck with one of the possible solutions, with all its pros and cons. |
Hmm, I understand the intention, but I do not see how it guarantees engines to do that forever, as it's really just a name in reference-types as long as it doesn't introduce subtyping anyway. What really allows this is that there is no subtyping just yet, not the name. Might as well still be named What I'm trying to get at is, now with GC, we are looking at
so the intended guarantee to allow engines to represent funcrefs differently only holds in a scenario where extern values are exclusively stored in As soon as
(still allowing Even though reference types is in phase 4, it might not even be too late to correct this by means of a text format only change to reference types. Other than that I agree of course that if we want |
Yes, precisely. Removing the subtyping was the significant change. The renaming was just a (text format only) "cleanup" afterwards, so that the type names reflect reality ("anyref" doesn't make sense if it isn't any reference).
Realistically, everything that's in the same subtyping hierarchy must use the same representation. In particular, when code for one module is compiled, the engine doesn't know yet what other modules might get loaded later. So the special-case you're hinting at would only apply in a situation where the engine has a chance to inspect all modules up front, which is not a realistic scenario. (That said, in V8 at least we're not planning to make use of special funcref representations, so we don't care much if we lose this freedom.) |
The removal of anyref certainly has made the type structure less clear. In a first approximation, externref it is the class of "foreign" references, i.e., values that are not (necessarilly) representations of Wasm concepts and that it probably has no interpretation for. That does not imply that their representation is arbitrary! Any such reference must still be compatible with e.g. GC references. That is similar to the situation of foreign "raw" pointers in some existing engines, which e.g. are represented as either tagged integer or boxed in the heap, so have a compatible representation. In the C API (which, as @jakobkummerow said, is a bit out of sync with the recent changes), there is an API function that allows the host to allocate "foreign" objects on the Wasm heap, which follows a similar model -- it cannot just stuck in any of its own values. The compatibility between externref and GC type representations is crucial to make type imports work. In particular, any imported type, like all other im/export entities, ought to be implementable by both another Wasm module or the host. In the latter case, it will be an externref, but the importing module can't know, so cannot distinguish statically. So the union A closely related question is whether this union needs to be disjoint. A priori, there is no reason that it has to. For example, a Wasm function (export exotic function in JS) could be both a funcref and an externref. Similarly, given the right amount of normalisation at the boundaries, i31 values could be both i31ref and externref. In a recent discussion with @jakobkummerow and @tebbi, we explored that option and did not see any immediate problem with that. However, we were discussing it in the context of the idea that externrefs are not considered to have extern as their RTTs, so one cannot cast down to |
Note that this arbitrary overlapping of |
Huh? I did not close this. What's going on with GitHub? |
The merge of upstream brought in a bunch of commits with things like "Fixes #142" in their messages, and GitHub "helpfully" closes the corresponding issue in response to that landing. What GitHub doesn't know is that in this case, the issue numbers refer to issues in a different repo. It doesn't look like there is a way to turn this off, so this will be an issue for all future merges as well unless GitHub changes something :/ |
We've since decided to re-unify anyref and externref. |
@dcodeIO raised an interesting point in #130:
(ref null extern)
runs into somewhat similar issues as(ref i31 extern)
.For JavaScript embeddings (with "extern" typically referring to JS values), the key question would be whether JavaScript
null
should be distinguishable from a Wasm nullref, or whether the two should in fact be the same. I can see arguments for both solutions; at any rate this should be specified. Aside from that, since everything is running on the same engine, that engine can be assumed to be able to tell JS and Wasm values apart, and specifically to be able to guarantee that externrefs don't accidentally look like a nullref. (I do have concerns about RTTs for externref values, but that's yet another separate discussion.)For the Wasm C/C++ API: in the current design of that API, "true" (arbitrary bits) host pointers (
Foreign
) must always be boxed by the engine, because they must fit into the unified representation demanded by the unified type system (everything is aRef
). If we wanted to allow engines to not box them, then "extern" would have to be a separate type, not nullable and not overlapping with any other types.To be clear, I'm not arguing for anything in particular in this post; just pointing out that we should be aware of the tradeoff: if externrefs are nullable (and/or overlapping with i31), then we have to assume some amount of boxing is going on under the hood, at least in some scenarios. If we want to enable guaranteed-non-boxing implementations, then we have to make "extern" a standalone type: neither a subtype of anyref, nor union-able with other types.
The text was updated successfully, but these errors were encountered: