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

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

Attach filesAttach ScreenshotVotersWatch issueWatchersCreate sub-taskLinkCloneUpdate Comment AuthorReplace String in CommentUpdate Comment VisibilityDelete Comments
    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.4.5
    • 2.4.6
    • Static compilation
    • 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

          This comment will be Viewable by All Users Viewable by All Users
          Cancel

          People

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

            Dates

              Created:
              Updated:
              Resolved:

              Slack

                Issue deployment