Assertions in static blocks ?

Ulf Zibis Ulf.Zibis at gmx.de
Sat Mar 6 12:24:04 PST 2010


David, very much thanks for your detailed explanation and your effort 
checking the spec. :-)

I've found a much simpler workaround which seems to work as expected:

class EUC_TWMapping3 extends EUC_TWMapping2 {
     static final short PL0_5_B2C_RANGE; // plane 0, 5 b2c range
     static final short PLANE_B2C_RANGE; // plane 2..4, 6..15 b2c range

     static {
         PL0_5_B2C_RANGE = 0x2300; // Initialize here to force the 
static block
         PLANE_B2C_RANGE = 0x1f00; // and the assertions, if enabled, to 
run.
         // assert plane offsets and content
         for (int p=0, range, offset=0; p<b2c.length; p++) {
             range = p % 4 == 0 ? PL0_5_B2C_RANGE : PLANE_B2C_RANGE;
             for (int i=range; i<b2c[p].length(); i++)
                 assert b2c[p].charAt(i) == UNMAPPABLE_DECODING;
             assert (offset += range) <= Character.MAX_VALUE + 1;
         }
     }
}

-Ulf


Am 06.03.2010 20:55, schrieb David Schlosnagle:
> Ulf,
>
> The behavior you're encountering is consistent with JLS §4.12.4 [1] which
> states:
>      We call a variable, of primitive type or type String, that is final and
>      initialized with a compile-time constant expression (§15.28) a constant
>      variable. Whether a variable is a constant variable or not may have
>      implications with respect to class initialization (§12.4.1), binary
>      compatibility (§13.1, §13.4.9) and definite assignment (§16).
>
> Later in JLS §13.1 [2] it states:
>      References to fields that are constant variables (§4.12.4)  are resolved at
>      compile time to the constant value that is denoted. No reference to such a
>      constant field should be present in the code in a binary file (except in
>      the class or interface containing the constant field, which will have code
>      to initialize it), and such constant fields must always appear to have been
>      initialized; the default initial value for the type of such a field must
>      never be observed. See §13.4.8 for a discussion.
>
> Check out Java Puzzler 93: Class Warfare [3] which gives an example of this and
> how it impacts binary compatibility. Josh and Neal also covered this in the
> 2009 JavaOne Puzzler talk, see #7 "When Words Collide" [4].
>
> Based on that, anywhere that PL0_5_B2C_RANGE or PLANE_B2C_RANGE are used the
> actual values will be inlined into the referencing class file at compile time
> as "sipush  8960" or "sipush 7936" respectively, and therefore do not reference
> the class EUC_TWMapping3 or cause it to be initialized.
>
> If you do want to ensure the assertions are run when at class initialization,
> I'd recommend something like the following which will ensure that the value is
> not inlined at compile time:
>
> class EUC_TWMapping3 extends EUC_TWMapping {
>      static final short PL0_5_B2C_RANGE = planeZeroFiveB2CRange(); //
> plane 0, 5 b2c range
>      static final short PLANE_B2C_RANGE = planeB2CRange(); // plane
> 2..4, 6..15 b2c range
>
>      private static final short planeZeroFiveB2CRange() {
>          short range = 0x2300; // plane 0, 5 b2c range
>          assert range>= b2c.length; // assert by values from EUC_TWMapping
>          return range;
>      }
>
>      private static final short planeB2CRange() {
>          short range = 0x1f00; // plane 2..4, 6..15 b2c range
>          assert range<= b2c.length; // assert by values from EUC_TWMapping
>          return range;
>      }
> }
>
> [1]: http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.12.4
> [2]: http://java.sun.com/docs/books/jls/third_edition/html/binaryComp.html#13.1
> [3]: http://www.javapuzzlers.com
> [4]: http://developers.sun.com/learning/javaoneonline/j1sessn.jsp?sessn=TS-5186&yr=2009&track=javase
>
> - Dave
>
>
>
> On Sat, Mar 6, 2010 at 6:35 AM, Ulf Zibis<Ulf.Zibis at gmx.de>  wrote:
>    
>> Am 06.03.2010 02:28, schrieb Keith McGuigan:
>>      
>>> Ulf Zibis wrote:
>>>        
>>>> Neal, Keith, thanks for your answer.
>>>>
>>>> ... but shouldn't javac claim, that there the code in the static block
>>>> will be *never reached*, if there is no trigger to run it?
>>>>          
>>> Not really.  That would be like claiming that the code in a method will
>>> never be reached if no one calls the method.  javac can't know that you're
>>> not going to take that class and deploy it somewhere else with other code
>>> that will end up calling the method (or initializing the class, etc.).
>>>        
>> But javac can know about the risk, because running Class.forName() is "not
>> very common", especially if there is nothing but constants in that class.
>> The minimum, javac could do is to throw a warning.
>>
>> On the other hand, javac throws errors, even if the stated problem never
>> occurs:
>>             char c1 = 12345;
>>             char c2 = c1 % 100;
>> would result in ERROR: "possible loss of precision", but
>>             c1 *= 12345;
>> compiles without problem.
>>
>> Do you know, if following static initializer will be guaranteed to run, when
>> accessing the static value? :
>>
>> class EUC_TWMapping3 extends EUC_TWMapping {
>>     static final short PL0_5_B2C_RANGE; // plane 0, 5 b2c range
>>     static final short PLANE_B2C_RANGE; // plane 2..4, 6..15 b2c range
>>     static {
>>         PL0_5_B2C_RANGE = 0x2300; // initialized here to force the
>> assertions!
>>         PLANE_B2C_RANGE = 0x1f00; //      "             "            "
>>         // assert by values from EUC_TWMapping
>>         assert PL0_5_B2C_RANGE>= b2c.length;
>>         assert PLANE_B2C_RANGE<= b2c.length;
>>     }
>> }
>>
>> -Ulf
>>
>>
>>
>>
>>      
>
>    




More information about the compiler-dev mailing list