[ 
https://issues.apache.org/jira/browse/GROOVY-12191?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18099650#comment-18099650
 ] 

ASF GitHub Bot commented on GROOVY-12191:
-----------------------------------------

blackdrag commented on PR #2736:
URL: https://github.com/apache/groovy/pull/2736#issuecomment-5101740980

   > > There is one point that escapes me right now. Why do we need the 
hierarchy at all? I don´t think this is for MetaClassImpl cases.
   > 
   > You are right that this is **not** because `MetaClassImpl` shares one 
method table up the hierarchy. Each class still has its own MetaClass / 
`ClassInfo` domain.
   > 
   > Hierarchy fan-out exists for **cross-class MOP visibility** that 
already-linked subtype sites must re-observe:
   > 
   >     1. **Parent ExpandoMetaClass / registry mutation**
   >        `Parent.metaClass.foo = { … }` must force sites linked for `Child` 
to re-select so `new Child().foo()` sees the method. Without retiring Child’s 
SwitchPoint, a previously linked miss (or older target) stays installed.
   > 
   >     2. **Interface MetaClass changes**
   >        Same rule for implementors.
   > 
   >     3. **Array covariance**
   >        `Object[]` / interface arrays are MOP-relevant supertypes of 
reference arrays even though array classes are `final` — a pure “exact class 
only” domain would leave `String[]` sites stale after `Object[]` MetaClass 
changes.
   
   This all sounds all like there is some problem deeper down. 
   I would have to recheck the code, but why do we have to do the hierarchy if 
no ExpandoMetaClass is in use. And even if we use a single EMC I question if 
that is needed. I think this is only the case if EMC is enabled globally. 
Regarding the general argumentation I think the meta class should provide the 
guard or switchpoint, since this is logic specific to an potentially unknown 
meta class. And I think the array case shows this even more. Who says that if 
the MetaClass of Object[] changes, the callsite on a receiver String[] has 
become invalid? And if we really have a hierarchy of meta classes where when I 
add a method to the parent, I have it in the child, then this might not be a 
replacement of the meta-class, but an update. This is what the version was for 
in the past, especially to also cover the per-instance meta-class cases. Most 
likely this can be done by the switchpoints as well, but then you have them per 
instance, not per class. Also... Assume the following case in pseudo code:
   ```
     class A extends B
     class B extends C { def fooC() }
     def call(C x){ x.fooC() }
     def c = new C()
     call(c)
     B.metaClass = new EMC
     B.metaClass.fooB0 = {}
     call(c)
     B.metaClass = null
     call(c)
     enableEMCglobally()
     call(c)
     c.metaClass = null
     call(c)
     def metaClassB = B.metaClass
     B.metaClass = new MetaClassImpl()
     call(c)
     metaClassB.fooB1 = {...}
     call(c)  
     A.fooA = {}
     call(c)
     def b = new B()
     b.metaClass = new EMC
     b.metaClass.fooB2 = {}
     call(c)
   ```
   Technically none of these operations would have to invalidate the callsite, 
since fooC is unchanged, but of course that is not how it works in reality. But 
the question is when do we invalidate and why. For me this is not yet the stage 
to propose a follow-up, first I would like to better understand the old and new 
behavior and think about if the difference matters. Also of interest is when 
and if the those foo methods becomes visible on the instance c as well as the 
metaClass of C. 
   
   
   




> Scope indy SwitchPoint invalidation
> -----------------------------------
>
>                 Key: GROOVY-12191
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12191
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Daniel Sun
>            Priority: Major
>             Fix For: 6.0.0-beta-1
>
>
> h3. Problem
> With invokedynamic enabled (default since Groovy 4), linked MOP call sites 
> were guarded by a *single process-wide* {{SwitchPoint}} 
> ({{{}IndyInterface.switchPoint{}}}).
> Any MetaClass registry change or category enter/leave invalidated that switch 
> point, so *every* linked site fell back and re-linked — including sites whose 
> receiver type was unrelated.
> That global invalidation is expensive when MetaClass churn is common (e.g. 
> ExpandoMetaClass / mixins on startup or per-request paths, Grails-like 
> patterns). Unrelated hot monomorphic sites pay re-link and JIT deopt cost 
> they should not.
> h3. Goal
> Keep linked call sites optimized unless the *relevant* MetaClass state for 
> that site actually changed.
> h3. Approach
> One SwitchPoint domain {*}per class{*}, stored on {{{}ClassInfo{}}}:
>  * MetaClass change for type {{T}} retires {{{}T{}}}'s SwitchPoint *and* 
> those of loaded subtypes / implementors (hierarchy fan-out).
>  * Unrelated types keep their SwitchPoints; their call sites stay optimized.
>  * Category enter/leave (and {{{}VMPlugin.invalidateCallSites(){}}}) 
> bulk-retire *all* loaded class SwitchPoints so sites re-link under the new 
> category state. There is *no* second category SwitchPoint on the hot path.
>  * Linked handles always install a *single* class-domain guard via 
> {{IndyInvalidation.guardWithMopSwitchPoints(...)}} — same monomorphic guard 
> shape as before, without global deopt on unrelated MetaClass churn.
> Final classes short-circuit hierarchy fan-out (no full {{ClassInfo}} scan). 
> Non-final types batch retirements with {{{}SwitchPoint.invalidateAll{}}}.
> h3. Invalidation map
> ||Event||What is retired||
> |MetaClass change for type {{T}} (registry / 
> {{{}ClassInfo.incVersion{}}})|{{T}} + loaded subtypes / implementors|
> |Category enter/leave, {{invalidateCallSites()}}|All loaded class 
> SwitchPoints (bulk)|
> |Unattributed MetaClass registry event|All loaded class SwitchPoints (bulk)|
> |First MetaClass *install* on a class|Version bump only (no linked sites 
> yet); replacement / clear retires that class's SwitchPoint|
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to