Some followup on this: Whether you pass in Closure or interface does not matter - Groovy (as of 2.4.5) generates the same (poor) code to set the fields. In the SAM coercion case, it actually creates a closure first then creates the SAM instance from it, it doesn't directly make the closure be a subclass. I also discovered that static compiler can implicitly coerce Closure to interface type but NOT abstract class of single abstract method.
As far as I can tell, there is no way to work around this situation, so I will have modify all of my classes in this framework to remove "private" from their fields, so they have real getters and setters, then CompileStatic will bind to those. At least that is a very easy and safe change to make in a lot of files very quickly. I still wish there was an easy way to cache the closures (it's not trivial for me here because I have closures inside of closures, so even if I cache the top-level closure, the inner closures will get recreated). Jason From: Winnebeck, Jason [mailto:[email protected]] Sent: Monday, December 07, 2015 12:13 PM To: [email protected] Subject: CompileStatic closure accessing "this object" private variable via setGroovyObjectProperty I have code with performance issues using closures accessing private fields: @CompileStatic class X { private Y a,b,c void blah() { doClosureThing { //This gets run in a loop, 1000s of times a = ... b = ... c = ... }}} When profiling, I see the majority of time is spent in ScriptBytecodeAdapter.setGroovyObjectProperty. Looking at the bytecode, I see the closure is setting X variables a,b,c via this method, which essentially delegates to a reflection-based set: "getThisObject().setProperty("a", value)". I notice that the read references to a, b, c use a generated method like "pfaccess$1" to actually read the values. Is this expected behavior for static compiler? If I create setters for the fields, the closure bytecode references the setters directly (although there is an awkward ScriptBytecodeAdapter.castToType of getThisObject instead of a normal cast), and the speedup is about 10x for my code (70ms to 6ms). This is in performance-sensitive code and we use this pattern in a lot of classes to execute small pieces of business logic on 1000s+ items. Any recommendations on how to improve without requiring changes other than in the shared doClosureThing method? One thing I am about to try is changing my methods like doClosureThing from a Closure to an abstract class, trying to replicate the behavior I get with delegates by manually creating non-abstract methods that delegate to the original closure's delegate, but it is a lot of work and I'm not even sure if it will do anything. Jason Winnebeck Software Engineer III Contractor - IT Software Development | Windstream 600 Willowbrook Office Park, Rochester, NY 14450 [email protected]<mailto:[email protected]> | windstreambusiness.com o: 585.794-4585 ________________________________ This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.
