Skip to content

$clinit_Boolean is not always optimized out when emptyย #10055

Closed

Description

@niloc132

GWT version: 2.12.1, latest
Browser (with version): any
Operating System: any


Description

While most empty clinits seem to be correctly optimized out, sometimes they unnecessarily remain in the compiled output.

As an example, if you build https://github.com/gwtproject/gwt-site-webapp/ but change turn draft mode off, $clinit_Object is correctly removed, but $clinit_Boolean is not, despite being empty:

function $clinit_Boolean(){
  $clinit_Boolean = emptyMethod;
}

A Java lambda of type elemental2.core.ReadonlyArray.FindPredicateFn

(el, index, parent) -> !"none".equals(((HTMLElement) el).style.display)

is translated as

function GWTProjectEntryPoint$lambda$9$Type(){
}

defineClass(81, $wnd.Function, {}, GWTProjectEntryPoint$lambda$9$Type);
_.onInvoke_2 = function onInvoke_5(arg0, arg1, arg2){
  return $clinit_GWTProjectEntryPoint() , $clinit_Boolean() , $equals('none', castToNative(arg0, $wnd.HTMLElement).style.display)?false:true;
}
;

which looks like boxing of boolean to Boolean via inlining Boolean.valueOf(boolean) gone a bit wrong:

public static Boolean valueOf(boolean b) {
return b ? $create(true) : $create(false);
}

  private boolean shouldEnhanceLink(Element link) {
    return
        // Enhance only local links
        isSameOriginRexp.test(link.getAttribute("href"))
        // Do not load links that are marked as full page reload
        && !Boolean.parseBoolean(link.getAttribute("data-full-load"));
  }

is inlined into two different places, bringing Boolean.parseBoolean with it:

function $lambda$16(this$static, evt_0){
  //...
  if ($test(isSameOriginRexp, target.getAttribute('href')) && ($clinit_Boolean() , !$equalsIgnoreCase('true', target.getAttribute('data-full-load'))) && $handleAsClick(castToNative(evt_0, $wnd.MouseEvent))) {
    //...
  }
}
function $lambda$19(el_0){
  //...
  if ($test(isSameOriginRexp, el_0.getAttribute('href')) && ($clinit_Boolean() , !$equalsIgnoreCase('true', el_0.getAttribute('data-full-load')))) {
    //...
  }
}

public static boolean parseBoolean(String s) {
return "true".equalsIgnoreCase(s);
}

Steps to reproduce

Check out gwt-site-webapp @ 27070768ae49c048535358a03c70a5b9d84ddf98

git clone git@github.com:gwtproject/gwt-site-webapp.git
cd gwt-site-webapp
git checkout 27070768ae49c048535358a03c70a5b9d84ddf98

Change draft compile to false

diff --git a/pom.xml b/pom.xml
index 747c5b2..f8fc02e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,7 +81,7 @@
                     <compilerArgs>
                         <arg>-saveSource</arg>
                     </compilerArgs>
-                    <draftCompile>true</draftCompile>
+                    <draftCompile>false</draftCompile>
                     <style>PRETTY</style>
                     <failOnError>true</failOnError>
                     <launcherDir>${project.build.directory}/www</launcherDir>

Build the project, with mvn clean verify

Expected: If $clinit_Boolean is present, it is non-empty.
Actual: $clinit_Boolean is present, and only reassigns itself to emptyMethod

Activity

  1. niloc132 commented on Oct 21, 2025

    @niloc132
    MemberAuthor

    This can be traced to the clinit not being optimized out while in Java - though it is optimized out in JS, that isn't good enough, since it still has the $clinit_Boolean = emptyMethod; assignment.

    The implementation of Boolean has two fields, TRUE and FALSE, each of which are given a primitive value despite being boxed Booleans. Java requires then that we box via Boolean.valueOf(...), which is in turn implemented (eventually) via JsUtils.uncheckedCast(). That is a JSNI method, which isn't obviously sideeffect-free, so the method call must remain even if the field gets optimized out. So, when the GWT AST optimization is done, the method has gone from

    static {
      TRUE = uncheckedCast(true);
      FALSE = uncheckedCast(false);
    }

    to

    static {
      uncheckedCast(true);
      uncheckedCast(false);
    }

    The JS optimizer then inherits that code as

    function $clinit_Boolean(){
      $clinit_Boolean = emptyMethod;
      uncheckedCast(true);
      uncheckedCast(false);
    }

    and removes the two useless methods (through inlining, which makes it obvious that the method serves no purpose), leaving

    function $clinit_Boolean(){
      $clinit_Boolean = emptyMethod;
    }

    which it can't optimize away.


    There are a few options for a fix here.

    • We can't easily change the Java/GWT AST handling to inline the JSNI method - in theory we could handle some very simple methods, but there's a case to be made that the code itself shouldn't have been JSNI to begin with.
    • We could change @UncheckedCast handling to always assume that these methods are trivial and have no side effects. In theory, this annotation is "internal only", so GWT and jsinterop-base should be the only things using it, but practically someone could be using this in their own project in a method with side effects. This probably isn't safe to do.
    • We can change JsUtils.uncheckedCast to be more like jsinterop-base's Js.uncheckedCast - that is, the implementation can be Java instead of JSNI, but still with the @UncheckedCast to suppress the java type check on the way out. This is a simple fix that obviously works (since jsinterop-base does it), and I have confirmed that this fixes this case. It isn't quite as satisfying, since it won't improve related code automatically.
  2. added a commit that references this issue on Oct 22, 2025
    bae3167
  3. added a commit that references this issue on Nov 6, 2025
    b5155aa
  4. added this to the 2.13 milestone on Dec 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions