Skip to content

Conversation

@dgryski
Copy link
Member

@dgryski dgryski commented Jan 16, 2026

Fixes #5180

@dgryski dgryski requested review from aykevl and niaow January 16, 2026 21:30
@dgryski dgryski force-pushed the dgryski/named-type-scope branch from cec236b to 4fd15a3 Compare January 16, 2026 21:40
@niaow
Copy link
Member

niaow commented Jan 16, 2026

Maybe add this to the compiler frontend tests (compiler/testdata/interface.*)

@dgryski dgryski force-pushed the dgryski/named-type-scope branch from 4fd15a3 to 91c1d8a Compare January 16, 2026 22:46
@dgryski
Copy link
Member Author

dgryski commented Jan 16, 2026

I don't think I can put it in the golden compiler/testdata/*.ll files since the pointer address will change between runs. It does have a test in the main testdata/ directory though.

@niaow
Copy link
Member

niaow commented Jan 16, 2026

Oh, we should not be using the pointer address for this.

@dgryski
Copy link
Member Author

dgryski commented Jan 16, 2026

There doesn't appear to be anything else aside from pointer addresses to allow us to differentiate scopes. Even the String() representation of a scope includes the pointer address. I'd love a more stable suggestion. I asked in #tools on Slack for advice.

@dgryski
Copy link
Member Author

dgryski commented Jan 16, 2026

Note also this the pointer address of the scope in the compiler, not the pointer at runtime on the device.

@niaow
Copy link
Member

niaow commented Jan 16, 2026

If that is the case then we could loop through the SSA and assign numbers to them? Non-deterministic compilation is not acceptable.

@dgryski
Copy link
Member Author

dgryski commented Jan 16, 2026

Ok. I'll see what I can come up with.

@dgryski
Copy link
Member Author

dgryski commented Jan 17, 2026

PTAL

@dgryski dgryski force-pushed the dgryski/named-type-scope branch from 91c1d8a to b6aa203 Compare January 19, 2026 17:26
@dgryski
Copy link
Member Author

dgryski commented Jan 19, 2026

(Oops, hadn't actually pushed my changes.... 🤦 )

@dgryski dgryski force-pushed the dgryski/named-type-scope branch 2 times, most recently from f6cd265 to f087248 Compare January 19, 2026 18:30
@dgryski dgryski force-pushed the dgryski/named-type-scope branch from f087248 to 7b86f95 Compare January 19, 2026 18:42
for scope != pkg {
parent := scope.Parent()
for i := range parent.NumChildren() {
if parent.Child(i) == scope {
Copy link
Member

Choose a reason for hiding this comment

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

This can result in O(n^2) overhead. Maybe build a map with everything in the package once and then look up from 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.

This code only runs for types declared in a local scope. I'll add a scope -> name cache for this function but walking the entire list of scopes looking for named types before we need them seems like overkill.

Copy link
Member

Choose a reason for hiding this comment

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

You still have not fixed this issue. You are still iterating over every child of every parent for every child. This index is what you should be caching.

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you want the id cached for only the matching child (so I don't need to iterate next time), or for every child? (I'm concerned the "every child" case will just bloat the cache with entries that will never be queried. This is already only walking up the scopes from the scope the type is defined in up to the parent scope, so we're only looking at the children of parent nodes on the path to the root.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Commit e56e3e5 caches the index of each scope that we encounter on the path to the root. We might have to double scan a particular parent if there are multiple scopes with types defined in them. (I'm going to run this over the test corpus and see if I can quantify the loops -- the numbers we're dealing with are pretty small..)

Copy link
Member

@niaow niaow Jan 20, 2026

Choose a reason for hiding this comment

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

or for every child?

Yes. The cache does not actually solve anything unless you do 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.

I added some logging to getScopeID and this is the output for running the compiler over the entire test corpus (180 packages, ~1.5 million lines of Go code):

~/go/src/github.com/dgryski/tinygo-test-corpus $ rg === corpus.out |sed 's/.*===//'
scopeIdx: id=46:10: loops=58
scopeIdx: id=46:10: loops=0
scopeIdx: id=46:10: loops=0
scopeIdx: id=25:4: loops=31
scopeIdx: id=25:4: loops=0
scopeIdx: id=25:4: loops=0
scopeIdx: id=25:4: loops=0
scopeIdx: id=25:4: loops=0
scopeIdx: id=25:4: loops=0
scopeIdx: id=4:1: loops=7
scopeIdx: id=4:1: loops=0
scopeIdx: id=4:1: loops=0
scopeIdx: id=4:1: loops=0
scopeIdx: id=0:3: loops=5
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=5
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=0:3: loops=0
scopeIdx: id=8:0: loops=10
scopeIdx: id=8:0: loops=0
scopeIdx: id=8:0: loops=0
scopeIdx: id=10:0: loops=11
scopeIdx: id=10:0: loops=0
scopeIdx: id=10:0: loops=0
scopeIdx: id=0:9:0:5:1:0: loops=21
scopeIdx: id=0:9:0:5:1:0: loops=0
scopeIdx: id=0:9:0:5:1:0: loops=0

Even only adding in the matching child, the number of iterations is very small, and this code just isn't called that frequently. Adding in all the children will just increase the memory usage for no benefit, since none of them are likely to have named types in them that we're going to query.

@niaow
Copy link
Member

niaow commented Jan 19, 2026

This is better

Copy link
Member

@niaow niaow left a comment

Choose a reason for hiding this comment

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

And again, this needs to be in the compiler testdata.

scopeid map[*types.Scope]string
}{
sync.Mutex{},
make(map[*types.Scope]string),
Copy link
Member

Choose a reason for hiding this comment

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

Move this into the compiler context to get rid of the lock and the memory leak.

for scope != pkg {
parent := scope.Parent()
for i := range parent.NumChildren() {
if parent.Child(i) == scope {
Copy link
Member

Choose a reason for hiding this comment

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

You still have not fixed this issue. You are still iterating over every child of every parent for every child. This index is what you should be caching.

@niaow
Copy link
Member

niaow commented Jan 20, 2026

Actually I just thought of a much simpler solution to this that I can try in a bit

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