Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-7705

CompileStatic closure accessing "thisObject" private field: setProperty instead of synthetic method

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.4.5
    • Fix Version/s: 2.4.6
    • Component/s: Static compilation
    • Labels:
      None

      Description

      When a closure sets the private field of a class, it does it via a ScriptBytecodeAdapter.setGroovyObjectProperty on the closure object itself, whereas when getting a private field of the class it uses a synthetic "pfaccess$0" method.

      Source:

      Source
      @CompileStatic
      class SetFromClosure {
      	private int x
      
      	void doIt() {
      		def closure = {
      			x = 5
      			println x
      		}
      		closure()
      	}
      }
      

      Decompiled result of closure class (via Fernflower in IntelliJ):

      class SetFromClosure$_doIt_closure1 extends Closure implements GeneratedClosure {
        public SetFromClosure$_doIt_closure1(Object _outerInstance, Object _thisObject) {
          super(_outerInstance, _thisObject);
        }
      
        public Object doCall(Object it) {
          byte var2 = 5;
          ScriptBytecodeAdapter.setGroovyObjectProperty(Integer.valueOf(var2), SetFromClosure$_doIt_closure1.class, this, (String)"x");
          DefaultGroovyMethods.println((SetFromClosure)this.getThisObject(), Integer.valueOf(SetFromClosure.pfaccess$0((SetFromClosure)this.getThisObject())));
          return null;
        }
      
        public Object call(Object args) {
          return this.doCall(args);
        }
      
        public Object call() {
          return this.doCall((Object)null);
        }
      
        public Object doCall() {
          return this.doCall((Object)null);
        }
      }
      

      Workaround is to remove "private" keyword on the variable declaration, which causes Groovy to generate public getter and setter. In that mode, the static compiler does generate direct calls to both the getter and the setter. In one example within my project the performance speedup was 10x with this workaround. The only thing I notice in the workaround that is odd is that instead of normal Java casts used, ScriptBytecodeAdapter.castToType is used on "getThisObject" before calling the getters or setters.

      This issue could possibly related to GROOVY-6825, but in that case it's an inner class, and the issue description (currently) is not clear enough to see if it's also generating a setProperty call.

        Attachments

          Activity

            People

            • Assignee:
              shils Shil Sinha
              Reporter:
              gillius Jason Winnebeck
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: