Skip to content

Conversation

tlively
Copy link
Member

@tlively tlively commented Jun 14, 2024

Implement binary and text parsing and printing of shared basic heap types and
incorporate them into the type hierarchy.

To avoid the massive amount of code duplication that would be necessary if we
were to add separate enum variants for each of the shared basic heap types, use
bit 0 to indicate whether the type is shared and replace getBasic() with
getUnsharedBasic(), which clears that bit. Update all the use sites to record
whether the original type was shared and produce shared or unshared output
without code duplication.

@tlively tlively requested a review from kripken June 14, 2024 22:00
src/wasm-type.h Outdated
return static_cast<BasicHeapType>(id);

// Get the shared or unshared version of this basic heap type.
constexpr BasicHeapType getSharedBasic(bool shared = true) const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this?

enum Shareability { Shared, Unshared }; .. getBasic(Shareability shared = Unshared)

Then existing callsites don't need to change, and also it avoids a function getSharedBasic(..) which might return a non-Shared result (that seems like it could avoid confusion). There could also be helpers (though maybe they are not needed),

getSharedBasic() { return getBasic(Shared); } getUnsharedBasic() { return getBasic(Unshared); }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's important that getBasic doesn't exist after this change. If it did exist, users might not consider sharedness when they use it. When the only options are getUnsharedBasic and getSharedBasic`, it's much harder to forget to handle sharedness correctly.

Regarding the Shareability enum, I don't think it's necessary because there's a clear correspondence with shared as true and unshared as false. Nobody would think that true mean unshared they way they might confuse e.g. nullability. If you disagree and think the enum is worth it, I can add it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I agree it's important to force users to consider sharedness. How about getBasic(Shareability shared) then, with no default? I think that's better because of the reason I said before, that it seems slightly confusing for a function getSharedBasic to not always return a shared result.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "shared" in getSharedBasic(bool) is more like "shared?" in that the parameter says whether it will actually be shared or not. I don't think that's too confusing. I'd prefer getMaybeSharedBasic(bool), but that's way too verbose.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought on this some more on the weekend and I still think getSharedBasic(bool) is not ideal. I get that we could get used to getSharedBasic(bool), but for a new reader, or maybe after not using the API for a time, it isn't immediately obvious if the bool refers to the shared or the basic. That is, the name suggests it is getting something both shared and basic - which does the bool refer to?

It doesn't feel like say setOpen(bool = true) where there is just one possibility, so is clear that "open" refers to the bool. That's just a simple setter function, really.

I don't feel strongly between less ambiguous options like getSharedBasic() / getUnsharedBasic() or getBasic(Sharability). I just think it would be best if reading the code makes it really obvious what the API does. But maybe there's a better option?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try switching to getGBasic(Shareability) and see what I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the latest commit. I still prefer it the way it was; the APIs using Shareability are generally more verbose and it seems like an unnecessary complication over using a bool.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this part is less good,

- typeBuilder[i].setShared(type.isShared()); + typeBuilder[i].setShareability(type.getShareability());

But maybe that could be

 typeBuilder[i].setShared(type.getShared()); 

? That is, I think we can call the setter setShared and have a getter getShared; Shareability can be the enum name, but the getters/setters can be more concise.

Other than that the last commit looks like an improvement to me actually. Even some parts that get a bit longer look like they benefit in clarity,

- HeapTypeT makeFuncType(bool) { return Ok{}; } + HeapTypeT makeFuncType(Shareability) { return Ok{}; }

(before, whether the bool was shared or open or some other property is not obvious).

I don't have an opinion on

- type.getUnsharedBasic() + type.getBasic(Unshared)

I think we could still use the old form there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to have (instead, or in addition for convenience) boolean-using getters/setters setShared(bool), bool isShared() as those are unambiguous, and use Shareability in ambiguous contexts. We do something similar for signed iirc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I updated {get,set}Shareability to {get,set}Shared and for the setters made the default parameter Shared. I'm happy with this.

Base automatically changed from parser-maybe-reftype to main June 14, 2024 23:28
@tlively tlively force-pushed the threads-shared-absheaptype branch 2 times, most recently from 293924d to a64adce Compare June 18, 2024 20:33
bool isTemp = false;
bool isOpen = false;
bool isShared = false;
Shareability share = Unshared;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This internal flag could maybe be a bool just for consistency with the two above it, but if it's more convenient otherwise sgtm as is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather avoid mixing bool and Shareability to avoid future questions of whether we should use one or the other in specific cases.

return a;
}
// Canonicalize to have `a` be the lesser type.
if (unsigned(a) > unsigned(b)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect to see if a.shared != b.shared return {} since I assume the LUB of func and (shared func) is empty. Is that not so?

Instead IIUC this computes the LUB on the unshared variants of them both, then makes that LUB shared if a is. Why is that correct? (and why is it ok to pick the shareability from a specifically?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's covered by the HeapType(a).getTop() != HeapType(b).getTop() check up above. Shared and unshared types will always have different top types.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, thanks!

builder[0].setShared(false);
builder[1].setShared(true);
builder[0].setShared(Unshared);
builder[1].setShared(Shared);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add overloads setShared(bool) then this could be a little shorter and I think just as unambiguous and clear, but I don't feel strongly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reason to avoid mixing bool and Shareability applies here.

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm % question

;; CHECK-TEXT-NEXT: (local.get $z)
;; CHECK-TEXT-NEXT: )
;; CHECK-BIN: (func $id2 (type $3) (param $w contref) (param $x nullcontref) (param $y (ref func)) (param $z (ref nocont)) (result contref)
;; CHECK-BIN: (func $id2 (type $3) (param $w contref) (param $x nullcontref) (param $y (ref cont)) (param $z (ref nocont)) (result contref)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this just wrong before? It does look right now. What fixed it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that on my read, good catch.

tlively added 5 commits June 18, 2024 17:18
Implement binary and text parsing and printing of shared basic heap types and incorporate them into the type hierarchy. To avoid the massive amount of code duplication that would be necessary if we were to add separate enum variants for each of the shared basic heap types, use bit 0 to indicate whether the type is shared and replace `getBasic()` with `getUnsharedBasic()`, which clears that bit. Update all the use sites to record whether the original type was shared and produce shared or unshared output without code duplication.
@tlively tlively force-pushed the threads-shared-absheaptype branch from 7124242 to aaf1896 Compare June 19, 2024 00:36
@tlively tlively enabled auto-merge (squash) June 19, 2024 00:43
@tlively tlively merged commit 2df678e into main Jun 19, 2024
@tlively tlively deleted the threads-shared-absheaptype branch June 19, 2024 01:20
@gkdn gkdn mentioned this pull request Aug 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants