Skip to content

[Custom Descriptors] Update Heap2Local #7667

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

Merged
merged 3 commits into from
Jun 20, 2025
Merged

[Custom Descriptors] Update Heap2Local #7667

merged 3 commits into from
Jun 20, 2025

Conversation

tlively
Copy link
Member

@tlively tlively commented Jun 19, 2025

When optimizing allocations of structs with descriptors, store the
descriptor in a local the same way we store normal fields. Update
ref.get_desc on optimized allocations to simply get the local holding
the descriptor. Lower ref.cast_desc to unreachable when the optimized
allocation flows in as the descriptor because it cannot have also been
the descriptor on the cast value without being considered to have
escaped. When the optimized allocation is itself the cast value, compare
the local containing its descriptor to the target descriptor to
determine whether the cast would have succeeded.

When optimizing allocations of structs with descriptors, store the
descriptor in a local the same way we store normal fields. Update
ref.get_desc on optimized allocations to simply get the local holding
the descriptor. Lower ref.cast_desc to unreachable when the optimized
allocation flows in as the descriptor because it cannot have also been
the descriptor on the cast value without being considered to have
escaped. When the optimized allocation is itself the cast value, compare
the local containing its descriptor to the target descriptor to
determine whether the cast would have succeeded.
@tlively tlively requested a review from kripken June 19, 2025 05:56
// remove the allocation it will not even be needed for validation.
replaceCurrent(curr->ref);
if (curr->desc) {
if (analyzer.getInteraction(curr->ref) == ParentChildInteraction::Flows) {
Copy link
Member

Choose a reason for hiding this comment

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

Why is this checking the interaction? I can't figure that out. What other interaction is being ruled out?

Copy link
Member Author

Choose a reason for hiding this comment

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

We're optimizing an allocation that flows into the cast either as the ref or as the desc. This intends to differentiate between those two cases.

(I guess maybe I also have to check the case where the same allocation flows into both locations...)

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. Makes sense.

(I think the case of flowing into both is already handled, by the first case?)

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 was, but not optimally, and adding a test revealed a segfault when the allocation target does not have a descriptor. PTAL at the fixes.

(ref.cast_desc (ref (exact $super))
(local.get $ref)
(struct.new $super.desc)
)
Copy link
Member

Choose a reason for hiding this comment

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

Side question about the spec, why is this instruction called ref.cast_desc and given a type to cast to, if what it actually does is compare the desc for equality? Seems like ref.eq_desc..?

Copy link
Member Author

Choose a reason for hiding this comment

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

If all you want to do is check equality of descriptors, you can already do that with ref.get_desc and ref.eq. If that check succeeds, you know what type the described value must have, but the type system does not have that information. So the main point of this instruction is to be a cast, i.e. to check that a value has a particular type and use that type in further validation. It just happens to implement that cast by checking equality of descriptors.

Copy link
Member

Choose a reason for hiding this comment

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

I see, thanks. The name seems slightly odd but I get the use case.

// If we are doing a ref.cast_desc of the optimized allocation, but we
// know it does not have a descriptor, then we know the cast must fail. We
// also know the cast must fail if the optimized allocation flows in as
// the descriptor, since it cannot possible have been used in the
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// the descriptor, since it cannot possible have been used in the
// the descriptor, since it cannot possibly have been used in the

Copy link
Member Author

Choose a reason for hiding this comment

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

Wow my typing correctness has really gone downhill recently 😓

@tlively
Copy link
Member Author

tlively commented Jun 20, 2025

Looks like CI found some unrelated UB when running the clusterfuzz tests:

======================================================================
FAIL: test_run_py (test.unit.test_cluster_fuzz.ClusterFuzz.test_run_py)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/binaryen/binaryen/test/unit/test_cluster_fuzz.py", line 116, in test_run_py
    self.assertEqual(stderr, '')
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^
AssertionError: "/home/runner/work/binaryen/binaryen/src/[256 chars]2:24" != ''
- /home/runner/work/binaryen/binaryen/src/passes/OptimizeInstructions.cpp:3612:24: runtime error: shift exponent 64 is too large for 64-bit type 'unsigned long long'
- SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/runner/work/binaryen/binaryen/src/passes/OptimizeInstructions.cpp:3612:24

@tlively tlively enabled auto-merge (squash) June 20, 2025 18:35
@tlively tlively merged commit 6ea7fc2 into main Jun 20, 2025
16 checks passed
@tlively tlively deleted the heap2local-desc branch June 20, 2025 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants