Skip to content

Modified abstract domain in global initialization checker #23138

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 6 commits into from
May 27, 2025

Conversation

EnzeXing
Copy link
Contributor

@EnzeXing EnzeXing commented May 12, 2025

This PR modifies the abstract domain of the global object initialization checker. It closely follows the abstract definitional interpreter framework, but changes the heap to map from scopes (including abstract objects or local environments) to a pair of valsMap and outersMap, both of which over-approximates the information of scope bodies of the concrete scopes they represent.

[test_scala2_library_tasty]

@EnzeXing EnzeXing force-pushed the global-init-checker-redesign branch from 5591de9 to dbdfe1a Compare May 19, 2025 04:59
@EnzeXing EnzeXing changed the title WIP: Modified abstract domain in global initialization checker Modified abstract domain in global initialization checker May 19, 2025
@EnzeXing EnzeXing force-pushed the global-init-checker-redesign branch from dbdfe1a to 7582cf9 Compare May 20, 2025 07:30
@EnzeXing EnzeXing marked this pull request as ready for review May 20, 2025 07:33
Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

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

I like this redesign, great work @EnzeXing 🎉

I left some comments, but I see no issue block the merge given that we expect further PRs coming up soon.

@EnzeXing You can decide which comments to address in this PR and which are left to later PRs.

We can discuss the comment related to Cartesian Product Algorithm in next meeting.

* ThisValue ::= Ref | vs // possible values for 'this'
* LocalEnv(meth, ownerObject) // represents environments for methods or functions
* Scope ::= Ref | LocalEnv
* ScopeSet ::= Set(Scope)
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: The name Scope, ScopeSet, and LocalEnv are actually keys to the heap. ScopeBody is not intuitive enough. Better names will help understanding and maintenance.

It's a minor issue (the same for other naming issues mentioned below), we can delay it to a later PR if it's not easy to come up with better names.

instance.initOuter(klass, outer)
val owner = State.currentObject
val instance = new OfClass(klass, owner, ctor, outerScope.level + 1, summon[Regions.Data])
instance.initOuter(klass, outerScope)
instance
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: I was thinking, given that now we simplied OfClass, maybe we can remove this helper method.

Advantage: the initialization code for the outer will be at the place where we initialize the object, which will be more regular than before.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I worried about missing the call to initOuter when initializing the object

given Join[Value] with
extension (a: Value)
def join(b: Value): Value =
assert(!a.isInstanceOf[Package] && !b.isInstanceOf[Package], "Unexpected join between " + a + " and " + b)
Copy link
Contributor

Choose a reason for hiding this comment

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

For future: If Package causes troubles and is not essential, we could simply remove it from the abstract domain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Package led to many edge cases where we have to report internal errors.

if sym.is(Flags.Lazy) then
val rhs = sym.defTree.asInstanceOf[ValDef].rhs
eval(rhs, thisV, sym.enclosingClass.asClass, cacheResult = true)
else
// Assume forward reference check is doing a good job
val value = Env.valValue(sym)
val value = scopeSet.scopes.map(_.varValue(sym)).join
Copy link
Contributor

Choose a reason for hiding this comment

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

For future: Might be good to define a helper method in scopeSet to hide the abstract domain details from the semantic logic. It will be more robust to refactoring changes.

given State.Data = new State.Data
given Trace = Trace.empty
given Heap.MutableData = Heap.empty
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that now the heap is shared globally, maybe add a TODO to do garbage collection on the heap.

recur(scopeSet.scopes.map(_.outer).join)
else
recur(scopeSet.scopes.map(_.outer).join)
end recur
Copy link
Contributor

Choose a reason for hiding this comment

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

For future: if possible, try to hide abstract domain details from the semantic logic. That would make the code more robust against refactoring and easier to understand.

if scopes.isEmpty then
Env.NoEnv
else
scopes.reduce { (s1, s2) => s1.join(s2) }

Choose a reason for hiding this comment

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

Nit: Can be more concise by values.foldLeft(Bottom)(_ join _) and scopes.foldLeft(Env.NoEnv)(_ join _)

@EnzeXing EnzeXing force-pushed the global-init-checker-redesign branch from 2d7916f to b9922ce Compare May 27, 2025 11:51
@olhotak olhotak merged commit 2703b6b into scala:main May 27, 2025
29 checks passed
@WojciechMazur WojciechMazur added this to the 3.7.2 milestone Jun 18, 2025
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.

5 participants