Exploring Static Init

Discussion in 'Java' started by Roedy Green, Aug 27, 2005.

  1. Roedy Green

    Roedy Green Guest

    After Thomas surprised me with the enum decompilation, I thought I
    would have a look at a static init decompilation to see I what I
    thought was true was indeed true.

    Here is my little test program:

    // experiment to see order of initialisation
    public class Init2
    {
    static {
    // define m multiple times
    m = 1;
    }
    static final int inlined = 2;
    static final int notInlined = Math.min( 3 , 4 );
    static int m = 5;
    static
    {
    m = inlined + 6; // effectively 8
    m = notInlined + 7; // effectively 10
    }
    }


    DJ compiles it like this:
    public class Init2
    {

    public Init2()
    {
    }

    static final int inlined = 2;
    static final int notInlined;
    static int m = 1;

    static
    {
    notInlined = Math.min(3, 4);
    m = 5;
    m = 8;
    m = notInlined + 7;
    }


    Javap decompiles it like this:


    javap -c Init2

    Compiled from "Init2.java"
    public class Init2 extends java.lang.Object{
    static final int inlined;

    static final int notInlined;

    static int m;

    public Init2();
    Code:
    0: aload_0
    1: invokespecial #1; //Method java/lang/Object."<init>":()V
    4: return

    static {};
    Code:
    0: iconst_1
    1: putstatic #2; //Field m:I
    4: iconst_3
    5: iconst_4
    6: invokestatic #3; //Method java/lang/Math.min:(II)I
    9: putstatic #4; //Field notInlined:I
    12: iconst_5
    13: putstatic #2; //Field m:I
    16: bipush 8
    18: putstatic #2; //Field m:I
    21: getstatic #4; //Field notInlined:I
    24: bipush 7
    26: iadd
    27: putstatic #2; //Field m:I
    30: return

    }


    So what do we discover? Probably nothing new to the old timers.

    1. static final int inlined = 2; gets inlined. It is treated like a
    literal. The line m = inlined + 6; is effectively turned to m = 2+ 6;
    which is collapsed further to m = 8;.

    This is why you have to recompile the classes that use constants in
    some other class when that base class changes the constant values. The
    dependent code has to be re-inlined. The original source of the
    constant value is lost in the class file.

    2. The initialisations are done in strict order, whether they are
    attached to a single line or are part of a static block. You might
    reasonably have expected all the one liners to have been done first,
    but that is not so.

    This is why you have to be careful with field-ordering IDEs like
    Eclipse. Changing the field order can change the dependency order
    during initialization. There is no clever spreadsheet-like discovery
    of dependencies. Initialisation proceeds mindlessly top to bottom.

    3. You are allowed to initialise variables not defined yet in static
    blocks, but you are not allowed to refer to variables not initialised
    yet. This is because the definition and initialisation, though mixed
    together in Java source, are separate in the class file. Note the m=1.

    4. JavaC is not doing even the most rudimentary optimisation of
    discarding a save to a variable immediately followed by a save of a
    different value to that same variable.





















































































































































    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
    Roedy Green, Aug 27, 2005
    #1
    1. Advertising

  2. "Roedy Green" <> wrote in message
    news:...
    >
    > 2. The initialisations are done in strict order, whether they are
    > attached to a single line or are part of a static block. You might
    > reasonably have expected all the one liners to have been done first,
    > but that is not so.


    That is to say, the order is predictable. This is a good thing. (By the
    way, the same is true of instance initialization: top to bottom.)
    >
    > This is why you have to be careful with field-ordering IDEs like
    > Eclipse. Changing the field order can change the dependency order
    > during initialization.


    Very true.

    > There is no clever spreadsheet-like discovery
    > of dependencies. Initialisation proceeds mindlessly top to bottom.


    Again "predictably from top to bottom", and again, unless you want subtle
    bugs introduced by the compiler's attempt to make sense out of code that
    doesn't have an obvious single meaning, that's desirable..
    Mike Schilling, Aug 27, 2005
    #2
    1. Advertising

  3. Roedy Green wrote:
    >
    > 3. You are allowed to initialise variables not defined yet in static
    > blocks, but you are not allowed to refer to variables not initialised
    > yet. This is because the definition and initialisation, though mixed
    > together in Java source, are separate in the class file. Note the m=1.


    This will be definite assignment/unassignment, which presumably works
    the same way as for locals and instance variables. The JLS has a rather
    dull chapter on the subject.

    > 4. JavaC is not doing even the most rudimentary optimisation of
    > discarding a save to a variable immediately followed by a save of a
    > different value to that same variable.


    IIRC, javac used to do more optimisation. You can easily see how class
    file size and number of byte code instructions can go down. Great for
    J2ME. However byte code optimisation can, apparently, make it more
    difficult for HotSpot to optimise its intermediate representations.
    Indeed, javac does some pessimisation, duplicating small finally blocks
    for exception and normal cases.

    Tom Hawtin
    --
    Unemployed English Java programmer
    http://jroller.com/page/tackline/
    Thomas Hawtin, Aug 27, 2005
    #3
  4. Roedy Green coughed up:
    > After Thomas


    please *always* supply a last name if you can when the first name is a
    common one.


    > surprised me with the enum decompilation, I thought I
    > would have a look at a static init decompilation to see I what I
    > thought was true was indeed true.
    >
    > Here is my little test program:


    ....[rip]...

    > So what do we discover? Probably nothing new to the old timers.
    >
    > 1. static final int inlined = 2; gets inlined. It is treated like a
    > literal. The line m = inlined + 6; is effectively turned to m = 2+ 6;
    > which is collapsed further to m = 8;.
    >
    > This is why you have to recompile the classes that use constants in
    > some other class when that base class changes the constant values. The
    > dependent code has to be re-inlined. The original source of the
    > constant value is lost in the class file.


    Yep. Hence the need for intelligent make{rs} able to garner such
    dependencies out of source.


    > 2. The initialisations are done in strict order, whether they are
    > attached to a single line or are part of a static block. You might
    > reasonably have expected all the one liners to have been done first,
    > but that is not so.
    >
    > This is why you have to be careful with field-ordering IDEs like
    > Eclipse. Changing the field order can change the dependency order
    > during initialization. There is no clever spreadsheet-like discovery
    > of dependencies. Initialisation proceeds mindlessly top to bottom.


    Correct, but I seem to remember eclipse not mucking with field orders when
    there are explicit initializers. Am I wrong here? Seems to ring a bell....


    > 3. You are allowed to initialise variables not defined yet in static
    > blocks, but you are not allowed to refer to variables not initialised
    > yet. This is because the definition and initialisation, though mixed
    > together in Java source, are separate in the class file. Note the m=1.


    Interesting. I'm going to think on this---it doesn't seem right. By the
    way, over time it seems that in the universe "definition" and "declaration"
    are being used interchangeably. Oh well...


    > 4. JavaC is not doing even the most rudimentary optimisation of
    > discarding a save to a variable immediately followed by a save of a
    > different value to that same variable.


    I don't believe that it /strictly/ can, if I understand you correctly. The
    static initializers happen at class load time which can occur at any point
    in the runtime, which might occur at the same time some other thread is
    attempting reading and mucking with those values.

    This is my question then: Does access to variables mid-static initialization
    get blocked until the initialization of the class is complete? If a static
    block does this:

    public static int a = 5;
    static { a = 6; a = 7; }

    is access to "a" disallowed from outside until the static initialization
    period is over?




    --
    Whyowhydidn'tsunmakejavarequireanuppercaselettertostartclassnames....
    Thomas G. Marshall, Aug 27, 2005
    #4
  5. Roedy Green

    Roedy Green Guest

    On Sat, 27 Aug 2005 10:46:16 +0100, Thomas Hawtin
    <> wrote or quoted :

    >IIRC, javac used to do more optimisation. You can easily see how class
    >file size and number of byte code instructions can go down. Great for
    >J2ME. However byte code optimisation can, apparently, make it more
    >difficult for HotSpot to optimise its intermediate representations.
    >Indeed, javac does some pessimisation, duplicating small finally blocks
    >for exception and normal cases.


    This is opening the door for byte code optimisers where the code will
    eventually be interpreted. The save x save x optimisation is safe,
    simple to find, and I would think unlikely to confuse a hotspot
    optimiser. Perhaps it does in some special case so they turn it off
    generally.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
    Roedy Green, Aug 28, 2005
    #5
  6. "Roedy Green" <> wrote in message
    news:p...
    > On Sat, 27 Aug 2005 10:46:16 +0100, Thomas Hawtin
    > <> wrote or quoted :
    >
    >>IIRC, javac used to do more optimisation. You can easily see how class
    >>file size and number of byte code instructions can go down. Great for
    >>J2ME. However byte code optimisation can, apparently, make it more
    >>difficult for HotSpot to optimise its intermediate representations.
    >>Indeed, javac does some pessimisation, duplicating small finally blocks
    >>for exception and normal cases.

    >
    > This is opening the door for byte code optimisers where the code will
    > eventually be interpreted. The save x save x optimisation is safe,
    > simple to find, and I would think unlikely to confuse a hotspot
    > optimiser. Perhaps it does in some special case so they turn it off
    > generally.


    Or pehrpas bytecode optimization is considered of little importance in the
    scheme of things, so little or no resources are devoted to it.
    Mike Schilling, Aug 28, 2005
    #6
  7. Roedy Green

    Roedy Green Guest

    On Sat, 27 Aug 2005 23:44:32 GMT, "Mike Schilling"
    <> wrote or quoted :

    >Or pehrpas bytecode optimization is considered of little importance in the
    >scheme of things, so little or no resources are devoted to it.


    When Hotspot gets hold of it, the problem is solved. The problem only
    exists when you run the code elsewhere, e.g. in a cellphone.

    There you fight for every byte. I'm surprised at Sun being so
    cavalier. Perhaps they are trusting some third party will step in.

    The tools to do it may be masking as obfuscators which also try to
    reduce footprint.



    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
    Roedy Green, Aug 28, 2005
    #7
  8. Roedy Green

    Roedy Green Guest

    On Sat, 27 Aug 2005 14:52:12 GMT, "Thomas G. Marshall"
    <> wrote or quoted
    :

    >Correct, but I seem to remember eclipse not mucking with field orders when
    >there are explicit initializers. Am I wrong here? Seems to ring a bell....


    Eclipse has a tidying feature to put code in some order you specify,
    e.g. collecting publics together alphabetically. You have to be aware
    that if you use this feature, you can disturb delicate ordering that
    static init depends on.

    If you want to make your code robust to survive such tidying, put
    tricky initialisation in a static { } block where it won't be
    reordered.

    ditto for instance init.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
    Roedy Green, Aug 28, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tony Cheng
    Replies:
    1
    Views:
    8,209
    Juan T. Llibre
    Feb 24, 2006
  2. Pavils Jurjans
    Replies:
    0
    Views:
    353
    Pavils Jurjans
    May 9, 2006
  3. Replies:
    1
    Views:
    657
    Jules
    Aug 18, 2005
  4. Jess
    Replies:
    4
    Views:
    440
  5. news.aon.at
    Replies:
    11
    Views:
    644
    Ian Collins
    Jan 29, 2011
Loading...

Share This Page