-
Notifications
You must be signed in to change notification settings - Fork 758
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
[Strings] Keep public and private types separate in StringLowering #6642
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -267,6 +267,44 @@ struct StringLowering : public StringGathering { | |
Type nnExt = Type(HeapType::ext, NonNullable); | ||
|
||
void updateTypes(Module* module) { | ||
// TypeMapper will not handle public types, but we do want to modify them as | ||
// well: we are modifying the public ABI here. We can't simply tell | ||
// TypeMapper to consider them private, as then they'd end up in the new big | ||
// rec group with the private types (and as they are public, that would make | ||
// the entire rec group public, and all types in the module with it). | ||
// Instead, manually handle singleton-rec groups of function types. This | ||
// keeps them at size 1, as expected, and handles the cases of function | ||
// imports and exports. If we need more (non-function types, non-singleton | ||
// rec groups, etc.) then more work will be necessary TODO | ||
// | ||
// Note that we do this before TypeMapper, which allows it to then fix up | ||
// things like the types of parameters (which depend on the type of the | ||
// function, which must be modified either in TypeMapper - but as just | ||
// explained we cannot do that - or before it, which is what we do here). | ||
for (auto& func : module->functions) { | ||
if (func->type.getRecGroup().size() != 1 || | ||
!Type(func->type, Nullable).getFeatures().hasStrings()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to add a |
||
continue; | ||
} | ||
|
||
// Fix up the stringrefs in this type that uses strings and is in a | ||
// singleton rec group. | ||
std::vector<Type> params, results; | ||
auto fix = [](Type t) { | ||
if (t.isRef() && t.getHeapType() == HeapType::string) { | ||
t = Type(HeapType::ext, t.getNullability()); | ||
} | ||
return t; | ||
}; | ||
for (auto param : func->type.getSignature().params) { | ||
params.push_back(fix(param)); | ||
} | ||
for (auto result : func->type.getSignature().results) { | ||
results.push_back(fix(result)); | ||
} | ||
func->type = Signature(params, results); | ||
} | ||
|
||
TypeMapper::TypeUpdates updates; | ||
|
||
// Strings turn into externref. | ||
|
@@ -288,19 +326,7 @@ struct StringLowering : public StringGathering { | |
} | ||
} | ||
|
||
// We consider all types that use strings as modifiable, which means we | ||
// mark them as non-public. That is, we are doing something TypeMapper | ||
// normally does not, as we are changing the external interface/ABI of the | ||
// module: we are changing that ABI from using strings to externs. | ||
auto publicTypes = ModuleUtils::getPublicHeapTypes(*module); | ||
std::vector<HeapType> stringUsers; | ||
for (auto t : publicTypes) { | ||
if (Type(t, Nullable).getFeatures().hasStrings()) { | ||
stringUsers.push_back(t); | ||
} | ||
} | ||
|
||
TypeMapper(*module, updates).map(stringUsers); | ||
TypeMapper(*module, updates).map(); | ||
} | ||
|
||
// Imported string functions. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. | ||
|
||
;; RUN: foreach %s %t wasm-opt --string-lowering -all -S -o - | filecheck %s | ||
|
||
;; A private type exists, and a public type is used by imports (one explicitly, | ||
;; one implicitly). When we lower stringref into externref the import's types | ||
;; should not be part of a rec group with the private type: public and private | ||
;; types must remain separate. | ||
(module | ||
(rec | ||
;; CHECK: (type $0 (func (param externref externref) (result i32))) | ||
|
||
;; CHECK: (type $1 (array (mut i16))) | ||
|
||
;; CHECK: (type $2 (func (param externref))) | ||
|
||
;; CHECK: (type $3 (func (param (ref extern)))) | ||
|
||
;; CHECK: (type $4 (func)) | ||
|
||
;; CHECK: (type $private (struct (field externref))) | ||
(type $private (struct (field stringref))) | ||
) | ||
(type $public (func (param stringref))) | ||
|
||
;; CHECK: (type $6 (func (param (ref null $1) i32 i32) (result (ref extern)))) | ||
|
||
;; CHECK: (type $7 (func (param i32) (result (ref extern)))) | ||
|
||
;; CHECK: (type $8 (func (param externref externref) (result (ref extern)))) | ||
|
||
;; CHECK: (type $9 (func (param externref (ref null $1) i32) (result i32))) | ||
|
||
;; CHECK: (type $10 (func (param externref) (result i32))) | ||
|
||
;; CHECK: (type $11 (func (param externref i32) (result i32))) | ||
|
||
;; CHECK: (type $12 (func (param externref i32 i32) (result (ref extern)))) | ||
|
||
;; CHECK: (import "a" "b" (func $import (type $2) (param externref))) | ||
(import "a" "b" (func $import (type $public) (param stringref))) | ||
|
||
;; CHECK: (import "a" "b" (func $import-implicit (type $3) (param (ref extern)))) | ||
(import "a" "b" (func $import-implicit (param (ref string)))) | ||
|
||
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $6) (param (ref null $1) i32 i32) (result (ref extern)))) | ||
|
||
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint (type $7) (param i32) (result (ref extern)))) | ||
|
||
;; CHECK: (import "wasm:js-string" "concat" (func $concat (type $8) (param externref externref) (result (ref extern)))) | ||
|
||
;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $9) (param externref (ref null $1) i32) (result i32))) | ||
|
||
;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $0) (param externref externref) (result i32))) | ||
|
||
;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $0) (param externref externref) (result i32))) | ||
|
||
;; CHECK: (import "wasm:js-string" "length" (func $length (type $10) (param externref) (result i32))) | ||
|
||
;; CHECK: (import "wasm:js-string" "charCodeAt" (func $charCodeAt (type $11) (param externref i32) (result i32))) | ||
|
||
;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $12) (param externref i32 i32) (result (ref extern)))) | ||
|
||
;; CHECK: (export "export" (func $export)) | ||
|
||
;; CHECK: (func $export (type $4) | ||
;; CHECK-NEXT: (local $0 (ref $private)) | ||
;; CHECK-NEXT: (nop) | ||
;; CHECK-NEXT: ) | ||
(func $export (export "export") | ||
;; Keep the private type alive. | ||
(local (ref $private)) | ||
) | ||
) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this going to be an issue any time we tell
TypeMapper
to consider some public type as if it were private? Is it ever actually safe to treat a public type as private?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think #6630 is an example of that. We are certain the type can be modified there, despite it being public. We leave the public type alone but replace references to that type with modified ones.