Assertions in static blocks ?

David Schlosnagle schlosna at gmail.com
Sat Mar 6 17:39:28 PST 2010


David,

You're correct, Ulf's example code from earlier today where the actual
value is initialized in a static initializer block does use getstatic
and would trigger the EUC_TWMapping3 class's initialization and
provides the desired functionality.

Sorry, I meant to clarify the answer to Ulf's original email from
February 12 "If accessing the static final constants from another
class, the static block is not executed." showing this isn't a bug. In
that email's code they were compile time constants, and the JLS
justifies why the static block wasn't executed. This can lead to
surprising behavior if you're not aware of it which is one reason I
prefer extracting any complex initialization behavior into a separate
method when possible to make it more explicit.

- Dave

On Fri, Feb 12, 2010 at 9:06 AM, Ulf Zibis <Ulf.Zibis at gmx.de> wrote:
> If accessing the static final constants from another class, the static block
> is not executed.
> This causes the assertions to remain un-proofed, even if -ea -esa is set.
>
> Is that correct ?
...snip...
> class EUC_TWMapping3 extends EUC_TWMapping {
>    static final short PL0_5_B2C_RANGE = 0x2300; // plane 0, 5 b2c range
>    static final short PLANE_B2C_RANGE = 0x1f00; // plane 2..4, 6..15 b2c
> range

On Sat, Mar 6, 2010 at 7:34 PM, David Holmes - Sun Microsystems
<David.Holmes at sun.com> wrote:
> David, Ulf,
>
> Note that in Ulf's example:
>
> 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;
>    }
> }
>
> the fields are _NOT_ initialized with compile-time constant expressions and
> so access to them will be via a getstatic bytecode which will result in
> class initialization.
>
> David Holmes
> ------------
>
> David Schlosnagle said the following on 03/07/10 05:55:
>>
>> 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