Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is the JVM bytecode access modifier flag 0x1000 (hex) "synthetic" set?

For some Java byte code parser project I read the JVM spec and figured out that the bit mask values of the Java virtual machine class file format access modifier fields are

  ACC_PUBLIC = 0x0001
  ACC_FINAL = 0x0010
  ACC_SUPER = 0x0020 # old invokespecial instruction semantics (Java 1.0x?)
  ACC_INTERFACE = 0x0200
  ACC_ABSTRACT = 0x0400
  ACC_SYNTHETIC = 0x1000 
  ACC_ANNOTATION = 0x2000
  ACC_ENUM = 0x4000

Somehow I have no idea what 0x1000 is for. I saw it once in an inner class, but for all inner classes I checked since then, this flag was never set. Do you now what the meaning of this flag is and where/when it is set?

like image 954
Peter Kofler Avatar asked Feb 02 '23 10:02

Peter Kofler


2 Answers

A synthetic element is any element that is present in a compiled class file but not in the source code it is compiled from. By checking an element for it being synthetic, you allow a distinction of such elements for tools that process code reflectively. This is of course first of all relevant to libraries that use reflection but it is also relevant for other tools like IDEs that do not allow you to call synthetic methods or to work with synthetic classes. Finally, it is also important for the Java compiler to verify code during its compilation to never directly use synthetic elements. Synthetic elements are only used to make the Java runtime happy which simply processes (and verifies) the delivered code where it treats synthetic elements identically to any other element.

You already mentioned inner classes as an example where synthetic elements are inserted by the Java compiler, so let us look at such a class:

class Foo {

  private String foo;

  class Bar {

    private Bar() { }

    String bar() {
      return foo;
    }
  }

  Bar bar() {
    return new Bar();
  }
}

This compiles perfectly fine but without synthetic elements, it would be refused by a JVM that does not know a thing about inner classes. The Java compiler desugares the above class to something like the following:

class Foo {

  private String foo;

  String access$100() {  // synthetic method
    return foo;
  }

  Foo$Bar bar() {
    return new Foo$Bar(this, (Foo$1)null);
  }

  Foo() { } // NON-synthetic, but implicit!
}

class Foo$Bar {

  private final Foo $this; // synthetic field

  private Foo$Bar(Foo $this) {  // synthetic parameter
    this.$this = $this;
  }

  Foo$Bar(Foo $this, Foo$1 unused) {  // synthetic constructor
    this($this);
  }

  String bar() {
    return $this.access$100();
  }
}

class Foo$1 { /*empty, no constructor */ } // synthetic class

As said, the JVM does not know about inner classes but enforces private access of members, i.e. an inner class would not be able to access its enclosing classes' private properties. Thus, the Java compiler needs to add so-called accessors to an accessed class in order to expose its non-visible properties:

  1. The foo field is private and can therefore only be accessed from within Foo. The access$100 method exposes this field to its package in which an inner class is always to be found. This method is synthetic as it is added by the compiler.

  2. The Bar constructor is private and can therefore only be called from within its own class. In order to instantiate an instance of Bar, another (synthetic) constructor needs to expose the construction of an instance. However, constructors have a fixed name (internally, they are all called <init>), thus we cannot apply the technique for method accessors where we simply named them access$xxx. Instead, we make constructor accessors unique by creating a synthetic type Foo$1.

  3. In order to access its outer instance, an inner class needs to store a reference to this instance which is stored in a synthetic field $this. This reference needs to be handed to the inner instance by a synthetic parameter in the constructor.

Other examples for synthetic elements are classes that represent lambda expressions, bridge methods when overriding methods with a type-divergent signatures, the creation of Proxy classes or classes that are created by other tools like Maven builds or runtime code generators such as Byte Buddy (shameless plug).

like image 66
Rafael Winterhalter Avatar answered Feb 12 '23 09:02

Rafael Winterhalter


It's the "synthetic" flag, set when the field or method is generated by the compiler. AFAIK it's for inner classes, which meshes with your observation, and must be set when an artifact doesn't appear in the source code.

http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88571

like image 28
Dave Newton Avatar answered Feb 12 '23 07:02

Dave Newton