design icon indicating copy to clipboard operation
design copied to clipboard

WebAssembly.Memory: length, initial, maximum

Open jfbastien opened this issue 8 years ago • 24 comments

As suggested in #1024.

I'll follow-up with a similar suggestion for WebAssembly.Instance, which needs its own discussion about encapsulation as well as multiple memories. WebAssembly.Memory is simpler: there's only one Memory and it's not encapsulated.

jfbastien avatar Mar 30 '17 06:03 jfbastien

One thing that remains outstanding is how to identify that these are post-MVP things. We use 🦄 for future features, maybe we could use another marker for post-MVP?

length is trivial to polyfill. initial and maximum aren't, unless one wraps WebAssembly.Memory and WebAssembly.Instance in proxies, as well as all the free functions.

jfbastien avatar Mar 30 '17 06:03 jfbastien

@domenic

This needs to initialize those slots, not just state they exist. (Or, maybe grab them from the internal [[Memory]].

Ah yes! Done.

I don't think adding a shortcut for .buffer.length is a good idea. Objects with .length properties in JavaScript are uniformly indexed-access objects. The only reasonable name is .bufferLength, but then, why not .buffer.length?

That was discussed in #1024. I'm OK with any name that's consistent.

.buffer.length means we'd create an ArrayBuffer only to throw it away, no? Doesn't hurt much, but seems silly?

jfbastien avatar Mar 30 '17 07:03 jfbastien

.buffer.length means we'd create an ArrayBuffer only to throw it away, no? Doesn't hurt much, but seems silly?

Ah, I didn't realize the ArrayBuffer would be created lazily by implementations. (The spec creates it at creation time, but that's the spec; it's observably equivalent to create it lazily.)

More accurately you'd be creating it, and never throwing it away, since you require m.buffer === m.buffer.

If it is indeed anticipated that people will want to know the buffer length but not ever access the buffer itself, then yeah, adding a bufferByteLength makes sense. (I realize now it should be bufferByteLength instead of bufferLength since buffer is an ArrayBuffer, not a Uint8Array.)

domenic avatar Mar 30 '17 08:03 domenic

More accurately you'd be creating it, and never throwing it away, since you require m.buffer === m.buffer.

Until we detach due to grow or the grow_memory opcode, I believe that true.

If it is indeed anticipated that people will want to know the buffer length but not ever access the buffer itself, then yeah, adding a bufferByteLength makes sense. (I realize now it should be bufferByteLength instead of bufferLength since buffer is an ArrayBuffer, not a Uint8Array.)

I was writing code to massage some Emscripten output and it would be useful to have. People aren't clamoring for it.

bufferByteLength SGTM. Will let @lukewagner chime in.

jfbastien avatar Mar 30 '17 09:03 jfbastien

Given that conceptual model, byteLength is probably OK; it does make this object kind of take over the territory of ArrayBuffers though. I wonder if it should have been a subclass or something.

domenic avatar Mar 31 '17 00:03 domenic

I've renamed to byteLength and added markers for post-MVP features similar to what we do for feature testing. WDYT?

jfbastien avatar Mar 31 '17 04:03 jfbastien

maximum and current/length sound good to me, but I'm less convinced about initial. In V8 at least, we don't even remember that information. What would be the use case for "historic" information like that?

As for names, I would prefer either length or currentLength, and maximumLength. That's symmetric, and both those names would be analogously applicable to Table, whereas byteLength is not.

rossberg avatar Apr 03 '17 07:04 rossberg

maximum and current/length sound good to me, but I'm less convinced about initial. In V8 at least, we don't even remember that information. What would be the use case for "historic" information like that?

It's symmetrical with the WebAssembly.Memory constructor, which I agree a user could just remember, but symmetry is nice. It is, however, not accessible for an instance's module's Memory section without disassembling (and holding onto the binary).

As for names, I would prefer either length or currentLength, and maximumLength. That's symmetric, and both those names would be analogously applicable to Table, whereas byteLength is not.

If we want to be consistent I'd go with one of:

  • current_memory in units of pages, which is what the binary format does
  • byteLength which is what ArrayBuffer does

Going with the corresponding JS API seems more consistent IMO, but I'm happy painting the bikeshed any length.

maximumLength is different from the WebAssembly.Memory constructor, and I don't think it should differ.

jfbastien avatar Apr 03 '17 16:04 jfbastien

@jfbastien, re consistency: the right feature to look at would be neither of the above IMO but the "resizable limits" in the import/export types of memories/tables, because that's pretty much exactly what the current/maximum methods would be reflecting on a memory/table object and what is relevant for linking.

Fair point about the different units, but that doesn't need to affect naming. The constructors and grow methods of tables/memories already use different units in the same way.

Not convinced by the symmetry argument regarding initial. It is a very strange method to have IMO -- you cannot ask a JS array what size it was created with either. Furthermore, the constructor does not take a current length, so I'm not even sure what consistency would be established there. (Maybe it was a mistake to name the constructor param initial instead of just length, but that should not be the sole motivation for adding weird API.)

rossberg avatar Apr 03 '17 17:04 rossberg

I agree with @rossberg-chromium that including initial is odd. This seems a pretty unusual thing to track for a memory buffer. I'm indifferent on naming choice of byteLength / length but buy the utility of having a way to check size that doesn't require creating an ArrayBuffer.

I think a way to access the initial and maximum size of a memory import on a Modle is definitely useful too (possibly more so). Should we consider that?

flagxor avatar Apr 21 '17 00:04 flagxor

I agree with @rossberg-chromium that including initial is odd. This seems a pretty unusual thing to track for a memory buffer.

Yeah let's do it as part of #1046 in Module. Does this sound good?

I'm indifferent on naming choice of byteLength / length but buy the utility of having a way to check size that doesn't require creating an ArrayBuffer.

Same. We're inconsistent with one thing or another.

I think a way to access the initial and maximum size of a memory import on a Modle is definitely useful too (possibly more so). Should we consider that?

Yes, #1046.

jfbastien avatar Apr 21 '17 06:04 jfbastien

Updated, PTAL.

jfbastien avatar May 12 '17 03:05 jfbastien

@domenic, we need a name that works consistently for both memories and tables, and unfortunately byteLength does not.

@jfbastien, how about size?

rossberg avatar May 12 '17 06:05 rossberg

@domenic, we need a name that works consistently for both memories and tables, and unfortunately byteLength does not.

Why do we need this property?

@jfbastien, how about size?

If we indeed need that property then size is as good as any.

jfbastien avatar May 12 '17 06:05 jfbastien

@jfbastien, because tables share the exact same limits properties, so should expose them in a consistent manner. If length is verboten, then we'll have to find another name for it for tables anyway, so could just as well use that for memories, too.

rossberg avatar May 12 '17 06:05 rossberg

@jfbastien, because tables share the exact same limits properties, so should expose them in a consistent manner.

Can you clarify what limit property you mean? I don't understand what the similarity is.

jfbastien avatar May 12 '17 06:05 jfbastien

Tables can grow in the same way as memories, and they also have an initial size, a current size, and an optional maximum size (see e.g. the use of resizable_limits for both in the design docs). The only difference is that these sizes are measured in number of elements instead of pages.

rossberg avatar May 12 '17 07:05 rossberg

Tables can grow in the same way as memories, and they also have an initial size, a current size, and an optional maximum size (see e.g. the use of resizable_limits for both in the design docs). The only difference is that these sizes are measured in number of elements instead of pages.

Ah OK, so IIUC your point is: presence of initial and maximum plus growth, regardless of unit, is what should guide naming. Unit is irrelevant.

Is this accurate?

Two questions I think will help resolve this:

  1. Is this something we've done in the WebAssembly JS API elsewhere (either what you suggest or the opposite)?
  2. What do other web platform APIs do in these circumstances?

jfbastien avatar May 12 '17 07:05 jfbastien

Well, in the API, we already have the same symmetry in the Table vs Memory constructor arguments (both taking an object with initial and maximum properties. And it is present throughout the Wasm design and semantics, so I would expect that to be reflected accordingly.

rossberg avatar May 12 '17 07:05 rossberg

Well, in the API, we already have the same symmetry in the Table vs Memory constructor arguments (both taking an object with initial and maximum properties. And it is present throughout the Wasm design and semantics, so I would expect that to be reflected accordingly.

True. Your argument is then: we've ignored unit before, and we should therefore continue ignoring it. Right?

Seems sensible.

@domenic thoughts?

jfbastien avatar May 12 '17 07:05 jfbastien

Table already has Table.prototype.length so, if we want to be symmetric (which I like), we should have Memory.prototype.length and, to be symmetric with initial, maximum and grow, this must return the current number of pages. But of course it's quite useful to have number of bytes so I think it would be reasonable to additionally have Memory.prototype.byteLength that saved the user the *64*1024 or .buffer.

lukewagner avatar May 12 '17 15:05 lukewagner

Oh... if we've already decided to break the rule on .length only being for indexed objects, then I guess consistency argues we should continue to do so... it's a shame that wasn't caught earlier :(

domenic avatar May 12 '17 17:05 domenic

What's the current state of this proposal? Should I add it to the JS API specification?

That would be great, though I'd advise bringing it up at a CG meeting (either in-person or VC).

jfbastien avatar Oct 27 '17 04:10 jfbastien

We deliberately chose to make this post-MVP, so we should not rush it into the MVP spec now all of a sudden. There is a bit of a design space around how to provide this information and fit it nicely with #1046, which would expose equivalent information in other places. I think these features need to be designed together.

rossberg avatar Oct 27 '17 11:10 rossberg

If anyone wishes to pursue this feature, please make a new proposal to the CG.

sunfishcode avatar Feb 22 '24 21:02 sunfishcode