04:56
<Domenic>
James M Snell: BTW I think it would be really cool if there were some sort of language feature (?) where we could give a BufferSource to platform APIs and say "please transfer this to yourself, I won't use it" and then they wouldn't need to do copies. It's hard to imagine how it would work though... there's nothing straightforward, like there is in languages with move semantics that parameters can declare themselves as having.
04:56
<Domenic>
I guess if we were starting from scratch maybe we'd design every BufferSource-taking API as transferring, and ask you to make a copy if you plan to use it later?
04:58
<Domenic>
But something like new Response(body.take()) or new Response(take body) or something would be neat, where it's a call-site opt-in. I guess maybe new Response(body.transfer()) (with https://github.com/tc39/proposal-arraybuffer-transfer) is possible for a highly-integrated platform + JS engine to recognize and optimize, but that's a hard lift.
05:10
<James M Snell>
Yeah definitely difficult. For apis like the Request and Response constructors we could probably get away with a new option that communicates the intent, e.g. `new Response(buf, { transfer: true })`... but that's difficult to do consistently for all apis.
05:12
<James M Snell>
I certainly wouldn't mind a language level take/move type construct tho
05:15
<Domenic>
Yeah and it feels unfortunate to have to program it in one-off for each API. Then you have to litigate whether that API's really in the fast-path or not, and that'll have different answers for web vs. server... this feels like an area where the language can come in and just say "now there's a global fast thing available" because it doesn't have to judge.
05:16
<bakkot>
I wonder how hard the new Response(body.transfer()) pattern actually is to optimize
05:17
<Domenic>
I guess the most feasible path would be trying to hack on an engine to see how optimizable new Response(body.transfer()) can be, and then whether that hack can be generalized, or if generalizing it would benefit from some annotation (ideally in IDL to do code-gen for all BufferSource cases)
05:17
<Domenic>
I think the difficulty is not as much technical as "codebase-organizational" in that the teams that implement new Response() are pretty far from the teams that implement the JS engine, and want to operate without too much interaction and intertwingling of code.
05:18
<bakkot>
I'm imagining an internal bit on array buffers which is like "this is not aliased anywhere", which could be checked by platform APIs
05:19
<bakkot>
So the JS engine people could be responsible for figuring out how to set that bit, and the platform people would just need to check it
05:19
<bakkot>
Don't actually know if that's at all feasible though.
05:19
<Domenic>
Yeah if you could pull that off it seems pretty reasonable.
08:45
<Luca Casonato>
But something like new Response(body.take()) or new Response(take body) or something would be neat, where it's a call-site opt-in. I guess maybe new Response(body.transfer()) (with https://github.com/tc39/proposal-arraybuffer-transfer) is possible for a highly-integrated platform + JS engine to recognize and optimize, but that's a hard lift.
Yeah - we’ve been thinking about this a lot for Deno. The least invasive solution we’ve been able to come up with so far is copy-on-write clones, but unfortunately V8 looks unlikely to implement these due to security concerns
08:47
<Luca Casonato>
I wonder how hard the new Response(body.transfer()) pattern actually is to optimize
I can’t speak for all runtimes, but for Deno this would maybe be a 100 LOC change after we’ve specified the behavior
08:47
<Luca Casonato>
It doesn’t seem very difficult
08:49
<Luca Casonato>
Oh actually I think I misunderstood - the idea for the optimization is to prevent the clone in new Response because they passed in buffer is “fresh” and not anymore accessible by any other JS? This would be much more difficult, maybe impossible at our current integration level with V8
08:52
<Andreu Botella>
Would it be that difficult? You could use the BackingStore as the "owned buffer".
08:53
<Andreu Botella>
The issue that we've been thinking about a lot for Deno is that there are a number of async APIs that take buffers, and those can lead to data races
15:40
<shu>
yes, that would be difficult for an API to tell its argument is in fact not aliased without some pretty deep VM support exposed at the API boundary, if there's no language equivalent to, like, rvalue references
15:41
<shu>
dynamic rvalue references also does not seem like a thing that anyone would want to implement
15:41
<shu>
well, i guess it doesn't have to be dynamic
15:42
<littledan>
can we just transition to refcounting? that makes alias detection easier.
15:42
<shu>
i hear refcounting is also faster
15:42
<littledan>
totally
15:59
<bakkot>
shu: hard to do precisely, but what about a conservative thing where it can say "not aliased" or "maybe aliased" and be precise enough for new Response(body.transfer()) to be analyzed as "not aliased"
16:14
<littledan>
this is the kind of thing Swift uses to omit the refcounting operations. It just composes so beautifully.
16:15
<littledan>
Stage 1? 🥺
16:17
<shu>
bakkot: where do we track this bit, for every single argument?
16:26
<bakkot>
just for array buffers
16:27
<shu>
the "may aliased" analysis is a static one, no?
16:28
<shu>
like, once things are compiled to bytecode, how do i know if a virtual register store (in a register VM) or a stack push (in a stack VM) is an actual binding assignment or a temporary?
16:31
<bakkot>
the register store / stack push isn't aliasing in itself, presumably - it only becomes aliased once you read it off the stack (or dup etc). but I suppose updating all those ops so that they'd know to set the bit is expensive
16:43
<shu>
indeed, my point is i suspect to get that bit for ArrayBuffers you need to implement that bit for all data flow
16:43
<shu>
which is a tall ask
17:23
<bakkot>
yeah fair enough
17:33
<tolmasky>
Another nitpick about the spec that makes certain tooling difficult: sometimes camel case intrinsics are simply lowercased for their sections (such as sec-asycngeneratorfunction), but other times they are dash cased (such as sec-async-function)
17:34
<Mathieu Hofman>

I'm still of the opinion that Copy-on-Write is the least intrusive change for developers, and would provide performance improvements for existing programs that use array buffers.

The current paradigm is that if you want to make sure the receiver of an arraybuffer doesn't change the data, or if as the receiver you want to use the data asynchronously insulating yourself from later changes by the caller, you simply do ab.slice(0) in both cases. If the implementation would keep the same memory backing store until either side attempts to write in it, all these use cases would now be zero copy unless they attempted to do the mutation this pattern is protecting against. No need for explicit transfer of ownership, which is somewhat a foreign concept in JavaScript.

I can understand such a level of indirection is a complication for implementations, and the write guards would make optimizations more difficult, but I am wondering if we're weighting the potential improvements for users correctly related to the implementation's concerns.

17:59
<shu>
Mathieu Hofman: my characterization is "security risk" and not just "complication"
17:59
<shu>
like, a direct security risk instead of security risk arising from more complexity
17:59
<shu>
and in that light, i stand by that increasing likelihood of browser users not being exploited is the correct tradeoff
18:00
<shu>
V8 has CoW optimization for regular arrays, for instance, which aren't used as an attack vector as much
18:01
<shu>
i would also contend transfer of ownership is not at all a foreign concept in JS, because detaching obviously exists?
18:01
<Mathieu Hofman>
I don't understand what is fundamentally a security risk about copy on write? I understand it's possible for optimizations to be buggy and miss the update in backing memory, but that stems from an implementation complexity
18:02
<Mathieu Hofman>
detaching doesn't exist in JS itself, it only happens when integrating with host APIs
18:02
<shu>
Mathieu Hofman: it is as i described here: https://github.com/tc39/proposal-arraybuffer-transfer#if-performance-is-the-goal-why-add-new-methods-instead-of-implementing-copy-on-write-cow-as-a-transparent-optimization
18:05
<Mathieu Hofman>
I read that, and understood the it as an implementation choice, which is impacting the usability by end users.
18:05
<shu>
if your rebuttal is "bugs are an implementation problem", the response is that there are bugs we have seen crop up over and over to an extent that we consider other mitigations necessary than just "be really correct"
18:05
<shu>
because, you know, engineers aren't perfect
18:06
<shu>
i can't help but feel that reducing that motivation to "implementation choices should never impact usability of end users" is naive
18:07
<Mathieu Hofman>
I think I was just asking if there was a way to estimate the performance improvement CoW would bring to existing programs, so that it can be weighted against the implementation complexity it'd require
18:07
<shu>
i don't know how one would estimate that except by doing the implementation
18:07
<Mathieu Hofman>
I'm not asking to strictly put the need of end users above the needs of implementation
18:10
<shu>
should the risk calculus change in the future (like, we figure out another mitigation that is even better and less constraining of APIs), having a transfer method certainly doesn't preclude CoW optimizations
18:11
<Mathieu Hofman>
fair
18:12
<shu>
for this point, i contend it doesn't serve us well to not consider hosts in language design, and further, transferables are a well established part of the ecosystem
18:14
<Mathieu Hofman>
but I don't see how transfer solves all the use cases. As the discussion goes above, as the receiver of an array buffer, how can I guarantee I have exclusive access to the buffer, besides myself calling .transfer(), which would be a breaking change for existing APIs, and hard to express would happen in the API contract (besides as mentioned, an explicit transfer option). As I said, transfer is not a concept core to the JS language
18:16
<Mathieu Hofman>
What other parts of the ecosystem besides structured cloning have a concept of transfer of ownership ?
18:21
<Mathieu Hofman>
I am wondering if we should also add a way to make the target buffer "read-only" when transferring, and a way to test whether the AB is read-only.
18:24
<Mathieu Hofman>
I believe Jack Works started exploring that in https://github.com/tc39/proposal-limited-arraybuffer
18:46
<jmdyck>
Another nitpick about the spec that makes certain tooling difficult: sometimes camel case intrinsics are simply lowercased for their sections (such as sec-asycngeneratorfunction), but other times they are dash cased (such as sec-async-function)
It sounds like you're talking about the id attribute of <emu-clause> elements. It's true that the mapping from section-title to section-id isn't entirely consistent, but how does that make tooling difficult? Can't the tool just get the title-to-id mapping (e.g. from a biblio file) and remember it? Also, your example is odd, because there's no section with id="sec-async-function".
18:47
<tolmasky>
sec-async-function-.*
18:49
<tolmasky>
I go intrinsics table -> sec-${transform(intrinsic_name)-* to grab all the methods/etc., the actual selector is now sec-${intrinsic_name.toLowercase() or sec-get-${intrinsic_name.toLowerCase()} or sec-${dashcase(intrinsic_name)} or sec-get-${dashcase(intrinsic_name)
18:50
<tolmasky>
Unfortunately the biblio seems to be missing certain things, I am just trying to get every intrinsic (not just top level ones, so like, Array.whatever.whatever), along with its parameters, etc. in a structured format)
18:50
<tolmasky>
the above seems to grab everything
18:51
<jmdyck>
The table is only the "well known" intrinsics, not every intrinsic.
18:52
<tolmasky>
right, thats why I then climb the rest of the spec
18:53
<tolmasky>
not sure if that is what you mean, or just wanted me to correct my statement to say "I want to grab all the well known intrinsics", either way, sure
18:55
<jmdyck>
okay, so if you're crawling the rest of the spec anyway, you could pick up the id for each intrinsic in the process. I.e., you don't really need the well-known intrinsics table?
18:59
<tolmasky>
I climb the spec to find all the intrinsics, then i want to find their definitions, hence needing to create the id. so, if I want to find what the parameters of AsyncFunction, then I have to go to sec-asyncfunction-constructor or whatever, hence the need to generate these things. I already find them all, I was just commenting that I noticed this. It's not a super big deal and would just remove 2 lines. If there's opposition to standardizing around lowercasing or dashcasing its certainly not preventing me from doing anything
18:59
<shu>
I am wondering if we should also add a way to make the target buffer "read-only" when transferring, and a way to test whether the AB is read-only.
what's the argument for making it the same API?
19:00
<shu>
i'm open to the idea of RO buffers
19:00
<shu>
What other parts of the ecosystem besides structured cloning have a concept of transfer of ownership ?
just structured clone afaik, but that's a pretty core part of the ecosystem
19:04
<jmdyck>
tolmasky: I don't understand how you can find all the intrinsics without finding their definitions.
19:07
<tolmasky>
I'm putting the code online so I can show you, one sec
19:09
<shu>
but I don't see how transfer solves all the use cases. As the discussion goes above, as the receiver of an array buffer, how can I guarantee I have exclusive access to the buffer, besides myself calling .transfer(), which would be a breaking change for existing APIs, and hard to express would happen in the API contract (besides as mentioned, an explicit transfer option). As I said, transfer is not a concept core to the JS language
i don't quite see it that way, i think the transfer semantics is a core concept to the JS language, and the discussion above is about the scalability challenges of the status quo of expressing move-semantics APIs, which is a separate options bag or overloads (like the transfer list in structured cloning) or something
19:10
<shu>
having a language level affordance like take doesn't really answer the question of the API design, like the fast-path slow-path thing
19:10
<shu>
do you have overloads for all existing buffersource-taking APIs? do all future APIs need to have both overloads? those still need to be answered
19:12
<shu>
CoW comes at it at a different angle, but is not ideal in its own way since you can still end up with a copy, and i think is an independent optimization that shouldn't be depended to motivate move semantics in either direction
19:19
<Justin Ridgewell>
Here's an updated gist that we discussed in module meeting: https://gist.github.com/jridgewell/fa9754e38299d1f067e8aa8ac9ae336e
19:20
<Justin Ridgewell>
The way that I think about all features we add is  "how would I write this today", and this is how I would write module keyword today
19:29
<Justin Ridgewell>
If we were to switch to as ‘foo’, it solves my main concern (how do we do runtime reflections using a single syntax, eg as ‘text’ or as ‘buffer’
19:32
<Justin Ridgewell>
But we’re likely to see conflicts, eg next’s as ‘image’ would include the intrinsic width/height of the original image, and an asset url usable in an <img src>. I imagine other frameworks might want the aspect ratio, or another optional value. Maybe they just want a data url (AMP needed that)
20:27
<Mathieu Hofman>
what's the argument for making it the same API?
avoid some of the pitfalls of Object.freeze which if replicated would allow anyone with access to the ArrayBuffer to make read-only in place, potentially violating the expectations of the sharer. However since this is also a concern I have for transfer as well, aka if just holding an arraybuffer should give you the authority to detach it, maybe that ship has sailed?
20:28
<Mathieu Hofman>
just structured clone afaik, but that's a pretty core part of the ecosystem
Yeah structured cloning is very web specific, and I don't know of any generic user libraries which deals with such concepts at their interface
20:33
<Mathieu Hofman>
I think in general JS has a concept of access through possession of object references, but in my opinion, the language itself does not have a built-in notion of ownership, and by extension of transfer of such ownership. We may introduce some notion of ownership with resource management, but that'd be somewhat tied with the concept of scope. The semantics of that proposal make it unlikely for these managed resources to be shared further than the owner, and I don't think transfer of ownership will mix.
20:34
<tolmasky>
jmdyck: Here: https://runkit.com/tolmasky/extracting-intrinsic-objects-from-ecmascript-specification -- I am not aware of an easier way of doing this. I found it pretty difficult to navigate biblio successfully. (shouldn't really be necessary to make your way through this, but here is parseSignature if it matters: https://runkit-packages.com/14.x.x/1670358356466/@reified/ecma262/tools/update-intrinsics/parse-signature.js )
20:36
<tolmasky>
Anyways, the only reason I asked about the consistency of the IDs is that it would allow me to avoid testing so many permutations (line 33). But again, it's not actually a big deal, I was moreso curious if there was a reason for it, and if not, maybe I would in my free time do a PR making them consistent
20:37
<Mathieu Hofman>
The same way programmers share object references and can spread it to capture the (shallow) state of that object, I see CoW as optimizing the same pattern for byte arrays, where you shared the data, and expressing that you're interested in capturing the state of that data.
20:40
<Mathieu Hofman>
Which is why I suggested readonly array buffers as an alternative, where you explicitly create an immutable copy, which can be relied upon. If Records and Tuples catch on, this would roughly be the equivalent for bytes (which raises the question whether those have any links)
20:43
<Mathieu Hofman>
We could probably argue that "read-only" array buffers may need to be non-transferable, so that they are really immutable, aka they will keep working.
20:46
<bakkot>
tolmasky: no reason for the inconsistency in IDs, just different authors writing different parts and not doing exactly the same things
20:46
<bakkot>
wouldn't say no to a PR making them consistent if you feel like doing it, though mind that we'd need oldids on everything to keep old links working
20:46
<tolmasky>
If I did a PR to make them consistent, would that be useful, or are we afraid of breaking links or something
20:47
<tolmasky>
kind of makes no difference to me since we want to run this on every iteration of the spec, so we'll need this code forever either way, but just curious
20:50
<bakkot>
if you put oldids links won't break, so no particular risk
20:50
<bakkot>
I don't know if anyone else has ever been affected about the inconsistency, though, so I don't know if it's necessarily useful per se
22:30
<shu>
Mathieu Hofman: as for web specificity, i point you to the other champions of the proposal coming from node
22:30
<shu>
structured clone may be have originated from the web, but it is a core part of the ecosystem
22:31
<shu>
CoW and RO TAs are orthogonal and i am supportive of exploring them independently
22:31
<shu>
"The semantics of that proposal make it unlikely for these managed resources to be shared further than the owner, and I don't think transfer of ownership will mix." <- i don't understand this
22:32
<shu>
oh "that proposal" is referring to resource management, i see
22:32
<shu>
i mean i also disagree? DisposableStacks have a move?
22:33
<shu>
i agree that there's no built-in notion of ownership in the formal sense, but there's certainly a sense of "i'm going to neuter the object"
22:34
<Mathieu Hofman>
I think the use case for move is mainly for moving a set of resource ownership from a constructor scope to the constructed object. I don't see it as aimed to move ownership to a 3rd party
22:34
<shu>
it's the same use case as the buffer one, no?
22:34
<shu>
i mean the buffer reader isn't an unknown 3p
22:35
<shu>
that is -- if the disagreement is with how widely applicable the notion of "ownership" is in the transfer proposal, i contend it is exactly as widely applicable as DisposableStack's
22:36
<shu>
like this isn't designed to enable native APIs to take ownership, that does require more work
22:38
<Mathieu Hofman>
I dunno about the reader API specifically, but having written a decent amount of code dealing with node streams, it never seemed clear to me what the expected semantics of passing array buffers around were. It seems that the receiver often assumes the producer will no longer mutate the buffer, but that is far from being enforced / checked or even explicit.
22:39
<Mathieu Hofman>
And I think maybe that's where read-only stream would at least make those semantics more explicit.
22:40
<shu>
i confess i don't know what the immediate disagreement is
22:41
<Mathieu Hofman>
Regarding structured cloned I guess we'll have to disagree how relevant it is to the ecosystem. One particular web API used in node for roughly the same use case (worker rpc) does not make it a strong precedent in my mind for a widely used pattern.
22:42
<shu>
well, what's your position on the proposal? the closest i can make out is perhaps that you think it is mutually exclusive with CoW optimizations and RO buffers
22:45
<Mathieu Hofman>
I think all I'm trying to say is that I don't believe transfer sufficiently solves all the use cases related to the expression of "ownership intent" for array buffers, and that defensive code does need more tools. Currently defensive code uses `slice` but if we can't optimize that, I'd like the transfer proposal to try and tackle more fully the ergonomics of passing array buffers around.
22:45
<shu>
i see
22:45
<shu>
thank you, noted, and i will ponder it. i would love some dynamic notion of ownership
22:45
<Mathieu Hofman>
I think I agree that CoW would be an orthogonal optimization.
22:46
<shu>
i think ownership is very important for shared memory work as well
22:50
<Domenic>
ReadableStream as implemented in the web/Node/Deno/etc. has transfer semantics
22:51
<littledan>
Yeah I am confused by this whole discussion
22:57
<Domenic>
Let me try to generalize my original "proposals" into a problem statement. There are a lot of BufferSource-accepting APIs that cannot deal with mutations after accepting the value. They have two choices today: clone or transfer. Transfer is a bit of a risky choice for API authors. If we could somehow make it the caller's choice which semantics are done, that would lead to a lot more efficiently. And, opting in to the efficient "don't copy" path should be automatic, or at least extremely easy to opt in to, for API authors. In particular, it should be something doable from any code generator like Web IDL, so that every BufferSource-accepting API can generate a prelude that handles this.
23:00
<littledan>
Oh yeah the Wasm JS API has some unfortunate cloning, for example. And I was always confused why it wasn’t transfer.
23:00
<Kris Kowal>
I for one am also on team zero-copy, by whatever means necessary.
23:00
<Mathieu Hofman>
So a more relevant example would be `WritableStreamDefaultWriter.write()`? It's not clear what would happen if you pass a chunk to that API and mutate the array buffer before the promise resolves.
23:01
<Domenic>
Here is a strawperson with lots of objectionable properties, but hopefully it communicates the idea. There is a new argument-passing syntax, f(take arg). This sets a bit on arg and also puts arg into a TDZ-like state, so the caller can't use it. API authors can then do something like function f(arg) { if (!isBitSet(arg) { arg = arg.slice(); } ... }.
23:02
<Domenic>
So a more relevant example would be `WritableStreamDefaultWriter.write()`? It's not clear what would happen if you pass a chunk to that API and mutate the array buffer before the promise resolves.
WritableStream is not yet zero-copy friendly. ReadableStream is the relevant example here. https://streams.spec.whatwg.org/#byob-reader-prototype
23:02
<Kris Kowal>
This is also a description of linear types, fwiw.
23:03
<Mathieu Hofman>
Wouldn't that `take` only impact the binding? What if the array buffer had been assigned to another variable?
23:03
<Domenic>
Yes, that doesn't really work
23:04
<Domenic>
I guess you want take to do something more directly related to ArrayBuffer transferring
23:05
<Mathieu Hofman>
It seems what you want is transferring the buffer temporarily and transferring it back. Or somehow put it in an "exclusive use" mode
23:05
<Domenic>

Such that

const ab = getArrrayBuffer();
f(take ab);

function f(abArg) {
  console.assert(abArg !== ab);
}

which is weird, but whatever.

23:05
<Domenic>
I don't think transferring it back is necessary in a majority of cases. But it would be a fun bonus.
23:05
<Domenic>
Presumably this is a well-researched area in programming language design.
23:05
<Domenic>
So I feel pretty silly just spouting strawpeople around.
23:06
<Mathieu Hofman>
Is it for reference types though? I can see this kind of flow analysis with value types.
23:06
<littledan>
I think this is the ancient linear types vs copy on write dilemma. Rust and Swift take opposite defaults here.
23:07
<littledan>
I don’t know how this stuff can be added to languages later—that is the real research problem here
23:07
<Domenic>
It feels like if you scoped it to ArrayBuffers and made some compromises, it might be doable?
23:07
<Domenic>
(e.g., no transferring back)
23:08
<littledan>
? I am willing to believe it but I can’t picture it yet
23:08
<Andreu Botella>
In the case of Deno, there are APIs like async Deno.writeFile(path, buffer) which don't currently clone or detach the buffer, and therefore have latent memory soundness or data race bugs
23:08
<Andreu Botella>
I don't think such APIs can be changed to detach the buffer without breakage
23:08
<littledan>
In Swift and Rust, this stuff is really core to how variables work in the first place
23:09
<littledan>
Swift is actually working on adding linear types now to help you avoid unintentional copying
23:10
<littledan>
But it is a huge change to the model of everything
23:31
<Kris Kowal>
(e.g., no transferring back)
Linear types takes this stance. They take the stronger stance that a variable may only be written once (TDZ) and can only be read once (your post-TDZ)
23:32
<Kris Kowal>
It makes for programs that can be represented with wire diagrams, and made parallel trivially, which is nifty. But, would weird to bolt post-TDZ onto JavaScript in its old age.
23:33
<Kris Kowal>
But doing that kind of stuff with revokable object APIs as a matter of analogy to linear types seems like fair game to me.
23:35
<Kris Kowal>
But as littledan said and Mathieu Hofman is arguing, this is indeed the age old conversation about linear types versus CoW and both can be made to work.
23:37
<Kris Kowal>
I think I’m more sympathetic at the moment to the “whatever WebGL needs” is the fixed point in this design, regardless of my preference for CoW just in terms of developer ergonomics.
23:37
<Kris Kowal>
So…does WebGL require transfer and detach semantics for TypedArrays?
23:39
<Mathieu Hofman>
I think we should take the example of piping in user land from a readable stream to a writable stream, and make that work with a single reusable buffer using zero copies besides into and out of that buffer, while guaranteeing the userland cannot do the wrong thing (aka ask the reader to write in the buffer before the writer is done reading out of the buffer)
23:40
<Kris Kowal>
That would be outrageously cool.
23:42
<Mathieu Hofman>
What kind of "exclusive use" mode do we need to add to array buffer to make this possible? Then I'd still ask to compare that added complexity with the equivalent flow if the program could assume copy on write to similarly perform "zero copy" piping.
23:42
<Kris Kowal>
Concretely, how do we employ TypedArrays for such a thing? Wouldn’t that require Read/Write/Opaque views into encapsulated buffers?
23:43
<Mathieu Hofman>
I don't believe typed arrays help here if you can get at an underlying mutable array buffer
23:43
<Kris Kowal>
That’s my intuition.
23:46
<Kris Kowal>
So, your notion is to add a level of indirection between ArrayBuffer and its underlying storage, then guarding it with either RO/WO/O modes or CoW with a userspace write barrier.
23:47
<Kris Kowal>
Strike prior, implementations already have this detachment concept, so that level of indirection clearly exists.
23:47
<Kris Kowal>
I will now walk away slowly.
23:50
<Mathieu Hofman>
Right there is already a detachment guard, maybe we'd introduce a way to lock the ab into read-only mode, preventing any writes, then release it?
23:51
<Mathieu Hofman>
That'd allow the receiver to claim the lock and release it once done, guaranteeing no mutation can occur on the AB while being read.
23:52
<Mathieu Hofman>
I dunno, I haven't thought this through, just spinning ideas here
23:53
<Kris Kowal>
I’m imagining const ab2 = ab1.take() (per Domenic’s take aparatus) would be the key. That would permanently detach ab1, leavingab2 for the receiver to read/write.
23:53
<Kris Kowal>
The trouble…
23:53
<Mathieu Hofman>
I don't think you need to detach or even duplicate the buffer
23:54
<Kris Kowal>
is that interferes with the sender if they went on to read or write ab1. CoW would make that safe.
23:56
<Kris Kowal>
But I think I read coherent murmurings about CoW being a pain to implement because the old view retains the underlying buffer possibly a long time.
23:56
<Mathieu Hofman>
Correct, it's still not backwards compatible and requires the sender to respect these semantics. I don't think anything besides CoW would be non-breaking. At first I thought that we could have the sender put the buffer in RO mode, but there is no way to guarantee it wouldn't keep a copy of the capability to release the lock.
23:58
<Kris Kowal>
It’d be a shame if CoW effectively forced copies to be made behind the scenes depending on GC timing.
23:59
<Kris Kowal>
Then zero-alloc becomes a puppet show. Did I or did I not dispose of my reference to the buffer in a timely enough fashion? Is it even possible to guarantee?