Skip to content

Require specific array types for string ops #7810

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

tlively
Copy link
Member

@tlively tlively commented Aug 8, 2025

The operations for creating strings from arrays and decoding strings
into arrays previously accepted any array types with i8 or i16 elements,
depending on the specific operation. This violates the principal types
properties of the WebAssembly type system and was a bug in the design of
the defunct stringref proposal.

In practice, these operations are only useful when lowered to calls to
the standard JS string builtins, which have strict requirements about
what array types they accept. Reflect those requirements by restricting
the array types we allow to be used with the string Expressions in our
IR. This allows us to remove the special casing for these operations in
ChildTyper.

Since Precompute only worked on string operations taking immutable
arrays, but those arrays are now invalid to use with string operations,
let it precompute on mutable arrays in the special case where the array
allocation is an immediate child of the string operation so it is known
not to escape elsewhere. Hopefully this is enough to prevent serious
optimization regressions.

The operations for creating strings from arrays and decoding strings
into arrays previously accepted any array types with i8 or i16 elements,
depending on the specific operation. This violates the principal types
properties of the WebAssembly type system and was a bug in the design of
the defunct stringref proposal.

In practice, these operations are only useful when lowered to calls to
the standard JS string builtins, which have strict requirements about
what array types they accept. Reflect those requirements by restricting
the array types we allow to be used with the string Expressions in our
IR. This allows us to remove the special casing for these operations in
ChildTyper.

Since Precompute only worked on string operations taking immutable
arrays, but those arrays are now invalid to use with string operations,
let it precompute on mutable arrays in the special case where the array
allocation is an immediate child of the string operation so it is known
not to escape elsewhere. Hopefully this is enough to prevent serious
optimization regressions.
@tlively tlively requested a review from kripken August 8, 2025 21:51
// Certain heap types are used by standard operations. Provide central accessors
// for them to avoid having to build them everywhere they are used.
HeapType getMutI8Array();
HeapType getMutI16Array();
Copy link
Member

Choose a reason for hiding this comment

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

Could this be in ir/array*.h perhaps?

Copy link
Member Author

Choose a reason for hiding this comment

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

This will eventually get more types, not all of which are arrays. In particular I'm thinking of (type (struct (field (mut i32)))), which we will need for waitqueueref.

@@ -213,23 +213,23 @@ class PrecomputingExpressionRunner

Flow visitStringNew(StringNew* curr) {
if (curr->op != StringNewWTF16Array) {
// TODO: handle other string ops. For now we focus on JS-like strings.
// TOOD: handle other string ops. For now we focus on JS-like strings.
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
// TOOD: handle other string ops. For now we focus on JS-like strings.
// TODO: handle other string ops. For now we focus on JS-like strings.

@@ -213,23 +213,23 @@ class PrecomputingExpressionRunner

Flow visitStringNew(StringNew* curr) {
if (curr->op != StringNewWTF16Array) {
// TODO: handle other string ops. For now we focus on JS-like strings.
// TOOD: handle other string ops. For now we focus on JS-like strings.
return Flow(NONCONSTANT_FLOW);
}

// string.encode_wtf16_array is effectively an Array read operation, so
Copy link
Member

Choose a reason for hiding this comment

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

This comment mentions string.encode, but in string.new - looks like it might have been copy-pasted from StringEncode, below? Might as well fix it here.

type.getArray().element == array16Element) {
updates[type] = array16;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Don't we still need this?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, because now it's no longer possible for any array operation to take a reference to an array type other than the one this code is introducing. Basically we're requiring that this replacement would be a no-op by construction.

;; CHECK-NEXT: )
(func $string.new-immutable (result externref)
;; This array is immutable and we can optimize here.
(func $string.new-mutable-indirect (result externref)
(string.new_wtf16_array
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment comparing to the above.

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