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

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

codeconsole commented on PR #3023:
URL: https://github.com/apache/groovy/pull/3023#issuecomment-6401187140

   Pushed 528ca59e27. Replies in the order of the review:
   
   1. Done in 8e5972cc73. The `GroovyObjectOverrides` class Javadoc states both 
read criteria, where each is used, the one case where they differ (a synthetic 
or `@Internal` implementation other than `GroovyObject`'s default), and the 
single write criterion. `ScriptBytecodeAdapter.getProperty`, `PropertySelector` 
and `AbstractCallSite` each name theirs and point there. Unifying them fails 
`getPropertyMarkedInternalIsLeftToTheMetaClassByCallSites` and 
`generatedGetPropertyIsAnOverrideButNotCustom`. 
`defaultGetPropertyResolvesReadForTheSender` is unaffected, since the 
`GroovyObject` default is `false` under both.
   2. Comment added in 8e5972cc73, in 
`AbstractCallSite.createGroovyObjectGetPropertySite` and the 
`hasCustomGetProperty` Javadoc. For `NoSuchMethodException` the site is the 
same `PogoGetPropertySite` as before. A `LinkageError` used to escape the read, 
and now reaches the object's `getProperty` (9da6e65f14, 
`UnreadableClassGetPropertySiteTest`).
   3. Tests added in d9b089c3fd: `expandoOrMixinSetPropertyReceivesEveryWrite` 
and `expandoOrMixinGetPropertyAnswersEveryRead` cover class and per-instance 
expando closures and a mixin, after the sites have linked to the setter or 
getter, for static-name, computed-name, `this` and `@TypeChecked` accesses, 
with indy and classic. What keeps these off the fast path is the 
`mci.getClass() != MetaClassImpl.class` check, which runs before both probes, 
not `pickMethod`: for a mixed-in `setProperty`, `pickMethod` returns the 
`GroovyObject` default. Disabling `pickMethod` alone breaks nothing; removing 
the type check lets mixin writes through; removing both lets expando writes 
through, and the set test fails for both. The `Selector` comment says so now 
(034602f3c5). The classic and adapter paths intercept in every case.
   4. Added in 1725ee8c3b: 
`groovyObjectDefaultGetPropertyCarriesInternalAtRunTime`.
   5. Stated in the class Javadoc in 8e5972cc73: writes have one criterion, 
`overridesSetProperty`, shared by `ScriptBytecodeAdapter.setProperty`, 
`setGroovyObjectProperty` and the indy write sites. No write path has set aside 
a synthetic or `@Internal` `setProperty`, and classic compilation has no 
property-write call sites; its writes go through `ScriptBytecodeAdapter`.
   6. This PR adds no caller of these methods. The only one in main sources is 
the indy write fallback, `IndyGuardsFiltersAndSignatures.setProperty`, whose 
sender is the call site's lookup class; compiled code passes its class literal. 
With no sender there is nothing for the metaclass to use, so the object's 
method takes the access; the `setProperty` comment says so (8e5972cc73).
   7. groovy-callsite declares `api project(':')`, so it always comes with the 
core of the same version, and it already imports core internals 
(`org.apache.groovy.internal.util.UncheckedThrow`). No package is split: 
groovy-callsite holds only `org.codehaus.groovy.runtime.callsite`, which core 
does not contain, and `org.apache.groovy.internal.metaclass` exists only in 
core. There is no module-info; the automatic module names are 
`org.apache.groovy` and `org.apache.groovy.callsite`, and under OSGi 
groovy-callsite is a fragment of the `groovy` bundle (`Fragment-Host: groovy`) 
that imports the package optionally. The class is `@Internal`, not 
`@GroovyABI`. The Javadoc builds do not exclude internal packages, so it is 
listed like `MetaClassConstant` in the same package.
   
   Test gaps:
   - EMC/mixin `setProperty` under indy: item 3, plus the read counterpart.
   - `@Internal` retention: item 4.
   - Interface extending `GroovyObject` with a default `getProperty`: added, 
and the answer it locked was a bug. `!isDefault()` (GROOVY-8283, new in 5.0) 
stood for "no getProperty specialization" (its TODO), and `SetPropertySelector` 
already treated only `GroovyObject`'s own default as benign. Going around 
another interface's default skipped it on every `obj.x = v` and untyped 
`obj."$name"` read, while `obj.setProperty(...)` and `obj.x` reads reached it; 
Groovy 4.0.33 reached it on every path, as a declared or trait method still 
does. Fixed in 56d309f536: `overridesSetProperty` and `overridesGetProperty` 
set aside only `GroovyObject`'s default. 
`defaultOfAnotherInterfaceIsAnOverride`, 
`defaultSetPropertyOfAnotherInterfaceReceivesEveryWrite` and 
`defaultGetPropertyOfAnotherInterfaceAnswersEveryRead` cover an implementing 
class, a subclass and a sub-interface, with indy and classic; d807afef7b adds 
the inherited and sub-interface predicate cases and a `GroovyInterceptable` 
control. An `@Internal` default of another interface is still left to the 
metaclass by the call sites (`generatedGetPropertyIsAnOverrideButNotCustom`).
   - Inherited synthetic `getProperty`: added in 1725ee8c3b; 
`generatedGetPropertyIsAnOverrideButNotCustom` also covers a subclass 
inheriting a synthetic `getProperty` and one inheriting an `@Internal` one.
   
   Nits:
   - No change.
   - Done in d74021ddc8: one private factory builds the three `ClassValue`s and 
holds the lookup and the fallback.
   - No change.
   




> Dynamic property access fails or bypasses getProperty/setProperty when the 
> receiver class has no reflection metadata (GraalVM native image)
> -------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12489
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12489
>             Project: Groovy
>          Issue Type: Bug
>          Components: groovy-runtime
>    Affects Versions: 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> A dynamic property access that carries a sender has to know whether the 
> receiver overrides the {{setProperty}} or {{getProperty}} that 
> {{GroovyObject}} provides. Groovy answers this with {{Class.getMethod}} on 
> every access:
> * {{ScriptBytecodeAdapter.setProperty}}, {{setGroovyObjectProperty}} and 
> {{getProperty}} let any exception from the lookup escape.
> * The invokedynamic {{SetPropertySelector}} treats a failed lookup as an 
> override.
> * The invokedynamic {{PropertySelector}} goes to the meta-class instead, 
> reading around the class's own {{getProperty}}.
> Reflection over a class can fail while the class itself works. In a GraalVM 
> native image without reflection metadata for the class, {{getMethod}} throws 
> {{NoSuchMethodException}}. As a result, every write that carries a sender to 
> such an object fails, and so does every read through the adapter. Reads 
> through invokedynamic sites are answered by the meta-class instead, with a 
> {{MissingPropertyException}}, or, when the meta-class knows the property 
> through a registered superclass, with the wrong value and no error. 
> Applications such as Grails register every Groovy class for reflection only 
> so these checks can be answered. On the JVM, a public method naming a type 
> absent at run time makes the lookups throw {{NoClassDefFoundError}}. And 
> where reflection works, every access pays for a method search and a 
> {{Method}} copy.
> Proposed fix: cache each answer per class in a {{ClassValue}}, keeping the 
> existing criteria, and when reflection cannot answer, treat the class as 
> overriding so the access goes to the object's own method.
> PR: https://github.com/apache/groovy/pull/3023



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to