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

Groovy compiler generates invalid byte code for local boolean variables that later on are referenced in a closure

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Blocker
    • Resolution: Fixed
    • 1.8.3
    • 1.8.4, 2.0-beta-1
    • None
    • None
    • Groovy 1.8.3 + Java 1.6.0_27

    Description

      Some sample code to show the bug:

      class GroovyBooleanTest {
      	public boolean someCall() {
      		return true;
      	}
      	
      	public void somecode() {
      		boolean val = someCall()
      		println val
      		def c = {
      			val
      		}
      		boolean val2 = c.call()
      		println val2
      	}
      
      }
      

      decompiled with jd-gui:

      import groovy.lang.Closure;
      import groovy.lang.GroovyObject;
      import groovy.lang.MetaClass;
      import groovy.lang.Reference;
      import org.codehaus.groovy.runtime.BytecodeInterface8;
      import org.codehaus.groovy.runtime.GeneratedClosure;
      import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
      import org.codehaus.groovy.runtime.callsite.CallSite;
      import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
      
      public class GroovyBooleanTest implements GroovyObject {
      	public GroovyBooleanTest()
        {
          GroovyBooleanTest this;
          CallSite[] arrayOfCallSite = $getCallSiteArray();
          MetaClass localMetaClass = $getStaticMetaClass();
          this.metaClass = localMetaClass;
        }
      
      	public boolean someCall() {
      		CallSite[] arrayOfCallSite = $getCallSiteArray();
      		return DefaultTypeTransformation.booleanUnbox(Boolean.TRUE);
      		return DefaultTypeTransformation
      				.booleanUnbox((Integer) DefaultTypeTransformation.box(0));
      	}
      
      	public void somecode() {
      		CallSite[] arrayOfCallSite = $getCallSiteArray();
      		boolean val = new Reference((Boolean) DefaultTypeTransformation.box(0));
      		Object localObject1;
      		boolean bool1;
      		if ((__$stMC) || (BytecodeInterface8.disabledStandardMetaClass())) {
      			localObject1 = arrayOfCallSite[0].callCurrent(this);
      			((Reference) val).set((Boolean) ScriptBytecodeAdapter.castToType(
      					localObject1, $get$$class$java$lang$Boolean()));
      		} else {
      			bool1 = someCall();
      			((Reference) val).set((Boolean) ScriptBytecodeAdapter.castToType(
      					(Boolean) DefaultTypeTransformation.box(bool1),
      					$get$$class$java$lang$Boolean()));
      		}
      		arrayOfCallSite[1]
      				.callCurrent(this, (Boolean) DefaultTypeTransformation
      						.box(DefaultTypeTransformation.booleanUnbox(val.get())));
      		GroovyBooleanTest._somecode_closure1 local_somecode_closure1 = new GroovyBooleanTest._somecode_closure1(
      				this, val);
      		Object c = local_somecode_closure1;
      
      		Object localObject2 = arrayOfCallSite[2].call(c);
      		boolean val2 = DefaultTypeTransformation.booleanUnbox(localObject2);
      		arrayOfCallSite[3].callCurrent(this,
      				(Boolean) DefaultTypeTransformation.box(val2));
      	}
      
      	static {
      		__$swapInit();
      		Long localLong1 = (Long) DefaultTypeTransformation.box(0L);
      		__timeStamp__239_neverHappen1319016363968 = DefaultTypeTransformation
      				.longUnbox(localLong1);
      		Long localLong2 = (Long) DefaultTypeTransformation.box(1319016363968L);
      		__timeStamp = DefaultTypeTransformation.longUnbox(localLong2);
      	}
      
      	class _somecode_closure1 extends Closure implements GeneratedClosure {
      		public _somecode_closure1(Object _thisObject, Reference val) {
      			super(_thisObject);
      			boolean bool = val;
      			this.val = bool;
      		}
      
      		public Object doCall(Object it) {
      			CallSite[] arrayOfCallSite = $getCallSiteArray();
      			return this.val.get();
      			return null;
      		}
      
      		public Boolean getVal() {
      			CallSite[] arrayOfCallSite = $getCallSiteArray();
      			return (Boolean) ScriptBytecodeAdapter.castToType(this.val.get(),
      					$get$$class$java$lang$Boolean());
      			return null;
      		}
      
      		public Object doCall() {
      			CallSite[] arrayOfCallSite = $getCallSiteArray();
      			return arrayOfCallSite[0].callCurrent(this, ScriptBytecodeAdapter
      					.createPojoWrapper(null, $get$$class$java$lang$Object()));
      			return null;
      		}
      
      		static {
      			__$swapInit();
      		}
      	}
      }
      

      Invalid byte code is shown in this line:

      		boolean val = new Reference((Boolean) DefaultTypeTransformation.box(0));
      

      JVM accepts this, but the debugger will show always "false" for such variables.

      The type information looks invalid also in the closure class:

      	class _somecode_closure1 extends Closure implements GeneratedClosure {
      		public _somecode_closure1(Object _thisObject, Reference val) {
      			super(_thisObject);
      			boolean bool = val;
      			this.val = bool;
      		}
      

      Attachments

        Activity

          People

            blackdrag Jochen Theodorou
            lhotari Lari Hotari
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: