WebAssembly / gc

Branch of the spec repo scoped to discussion of GC integration in WebAssembly
https://webassembly.github.io/gc/
Other
996 stars 72 forks source link

Will this include non gc references? #2

Closed ghost closed 2 years ago

ghost commented 7 years ago

References are very important to modern languages, but recent languages like rust and swift leverage alternatives like Box types(non copy able heap references) and ARC(Automatic Reference Counting). Sometimes the docs refer to "opaque reference types" suggesting all of these are options. Can someone clarify?

lukewagner commented 7 years ago

The "opaque reference types" from the older GC.md are basically the type imports in @rossberg-chromium 's PR, where the type is imported from the host environment. Fundamentally, though, these would be references to some GC object with an embedding-specific type (say, a DOM Node on the web).

IIUC, ARC would not use the GC feature at all, but rather linear memory, using explicit reference counting, malloc and free. I'm afraid I don't know enough about Box types to comment on them.

ghost commented 7 years ago

could an ARC reference be represented by a foreignref?

rossberg commented 7 years ago

Our current sentiment is not to have foreignref but rather go for the last alternative described in that section of the PR, i.e., modelling foreign types as imports like Luke mentioned. These are assumed to be proper GC types, implemented with whatever GC strategy the implementation sees fit. In theory, an implementation could choose to use a variant of reference counting for all GC types, but given that RC is inferior to other GC techniques along almost any dimension that would be a poor choice.

If a user wants to implement RC themselves then that's a separate problem, as Luke pointed out.

ghost commented 7 years ago

I don't think I was clear enough. I know browsers want to integrate WASM into their current JavaScript GC and don't wan't to switch to ARC. My point is that I'd imagine ARC and Box references share quite a bit with GC and if the spec were more abstract they could benefit.

Maybe only implement structs, ref, new, etc in WASM itself and put upcast, downcast in a WebAssembly.GC API. If WASM allowed references to values inside a module you could create an RC allocator like this (kind of).

(struct $RC (field $c i32) (field $ref f64))
(global (array $RC) $references)

(func $new_f64 (result (ref f64))
  (i32.const 1)
  (f64.const 0)
  (new $RC) ;;create RC value
  (array_size) ;;get index of next value
  (set_global $references) ;;append RC to array
  ;;stack empty
  (ref_global $RC) ;;get pointer to RC array
  (array_size)
  (i32.const 1)
  (i32.sub) ;;get index of last RC
  (array_ref) ;;reference last element in the array
)

I know references are very important, but think that if WASM implements inheritance it may look dated years from now like XMLHttpRequest or var. languages like Rust, Swift, Haskell, and Go would be cut out because they implement references in a different way or not be able to take advantage. And WASM is supposed to be language neutral.

rossberg commented 7 years ago

@dmTmp, there is no intention to have inheritance in Wasm. What's proposed is solely subtyping, which is a different beast (even if the OO community chooses to continue to conflate the two). Moreover, the subtyping relation is supposed to be structural, i.e., purely driven by what types of data can soundly be used in place of other types of data.

I expect that almost all languages compiling to Wasm will need to exercise its subtyping and casts to some extend, because the Wasm type system is never gonna be expressive enough to encompass all source level type systems. See the use case examples in the PR. There is no specific language bias intended or implied -- rest assured that some of us care at least as much about languages like Haskell or ML or Rust as they do about old-fashioned OOPLs. ;)

That also means that casts are central to the design and need to be maximally cheap and simple. I don't see how we could afford the level of abstraction you have in mind. Nor, honestly, do I see the benefit -- why would user side reference counting need to be overlayed with Wasm's built-in GC types? Keep in mind that the Wasm type system isn't intended to build user-facing abstractions, it is intended to describe machine-facing data representations.

ghost commented 7 years ago

So WASM implements "type inheritance" vs "object inheritance", ie completely static? no built in dynamic dispatch. Does this mean down casting is like taking a reference to a subset of the struct without keeping track of the typing track of the type in a static way?

rossberg commented 7 years ago

@dmTmp, right, "dynamic dispatch" is just an OO abstraction for calling a function pointer, not something that's primitve on the Wasm level. A downcast takes e.g. a struct and dynamically checks whether it is actually a larger struct (subtypes of structs contain a superset of fields), but this generalises to other types in the canonical way. The result is statically known to have the subtype.

MikeInnes commented 4 years ago

One case worth considering is hybrid memory management strategies that (for example) primarily use ref counting but have a backup tracing GC for cycles, or do static analysis to free objects with a known lifetime more quickly, or implement memory re-use, etc. You don't need much support from the GC for that, so long as you have atomic operations on references (to implement counts) and an explicit free.

Atomics seem likely after the MVP. I'm more interested in free: Is this something wasm could support? Naively, it doesn't inherently seem to compromise VM safety (use-after-free could trap or return junk, just like a user-implemented malloc over linear memory would). But perhaps this is difficult to implement efficiently, or has other issues I'm not aware of.

I fully understand if free is just out of scope, but would be very interested to hear the thinking behind this and/or see it mentioned in the proposal, if possible.

rossberg commented 4 years ago

@MikeInnes:

Naively, it doesn't inherently seem to compromise VM safety

Maybe I misunderstand your suggestion, but AFAICS it surely does, unless the VM performs some form of liveness check at every access to a reference, which would be a severe cost.

MikeInnes commented 4 years ago

Thanks a lot for the response. I fully agree that some kind of check would be needed, and this would only be viable if it were very cheap. I imagine that there are tradeoffs that may make this achievable (e.g. making free opt-in per object, limiting it to large allocations, or having it be a hint/prioritisation rather than a guarantee that memory is reclaimed immediately).

Sorry if that's too vague. I'm not trying to make a proposal at this point, just wondering if the experts have already considered this use case at all, and whether it does or doesn't appear to conflict with the GC proposal's goals at first glance. If not, perhaps a more complete proposal could stand to be considered in future.

lars-t-hansen commented 4 years ago

FWIW, there's a tie-in with fallible allocation (#87) in that for large objects it is sometimes desirable to handle allocation failure and lifetimes explicitly. An implementation that allows for that on an opt-in basis is not free but doesn't have to be horrifically expensive, for example, a facade that's GC'd can safely hide a large array that's freed explicitly. (Like detaching an ArrayBuffer.)

tlively commented 2 years ago

Closing this because it looks like the questions have been answered. Feel free to reopen if there is more to add.