Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (497)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Reflection Shenanigans...  (Read 2076 times)
0 Members and 1 Guest are viewing this topic.
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Posted 2009-06-30 23:14:56 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
class Foo
{
  public final int finalInt = 1;
}

{
  Foo foo = new Foo();
  System.out.println("initial:"+foo.finalInt);   // Prints '1'

  Field f = foo.getClass().getField("finalInt");
  f.setAccessible(true);         // Allowed (!)
 f.setInt(foo, 2);

  System.out.println("after set:"+foo.finalInt); // Prints '1' - ah, so setInt ignored then...
 System.out.println("from field:"+f.getInt());    // Prints '2' - wtf?
}  


It's fair to say that whatever I was expecting, that wasn't it. I was either expecting setAccessible() on a 'final' field to throw an exception, *or* for it to work and for foo.finalInt to actually be changed. In reality it appears that the supposedly final value *does* get changed internally, but that change isn't visible to external code.

Anyone know what's actually going on here? I suspect the VM has decided that since finalInt is final it can keep it cached, but it would be interesting to know quite how it's doing that.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Mr_Light

Senior Member


Medals: 1


shiny.


« Reply #1 - Posted 2009-06-30 23:31:34 »

I don't like saying this but try google. I've come across pretty much the same question a couple of times and there have been ppl explaining it in much better words then I ever could.

The following isn't the post I was refering to but has hints:
http://stuffthathappens.com/blog/2007/10/13/you-can-change-final-fields/

see a comment:
Quote
For the record, you can change final field value using reflection with
1.1, 1.2, 1.5 and 1.6 VM not with 1.3 and 1.4,
this feature was disable after 1.3 and re-enable in 1.5,
following the recommandation of JSR 133 expert group (memory model).

Rémi

see also:
http://www.javaspecialists.eu/archive/Issue096.html
http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf

hmm lovely Smiley

It's harder to read code than to write it. - it's even harder to write readable code.

The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
Offline cylab

JGO Ninja


Medals: 49



« Reply #2 - Posted 2009-07-01 09:10:49 »

I haven't read all the links mrlight provided Wink But I simply would assume the JIT to inline the final field, so if you change it via reflection, the field is changed, but the inlined values are not. Maybe this could be verified with -Xint while executing the testcase (can't try it for myself atm).

Mathias - I Know What [you] Did Last Summer!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Abuse

JGO Knight


Medals: 12


falling into the abyss of reality


« Reply #3 - Posted 2009-07-01 11:15:02 »

I haven't read all the links mrlight provided Wink But I simply would assume the JIT to inline the final field, so if you change it via reflection, the field is changed, but the inlined values are not. Maybe this could be verified with -Xint while executing the testcase (can't try it for myself atm).

Yep, that's exactly what is happening.

Inlining of constants is a rather annoying compile-time optimisation that pre-dates the many run-time optimisations that now exist.

I say annoying, because it makes recompilation of individual classes that contain public final values dangerous - as any other class referencing them (that is not part of the same recompilation) will not use the new values.

I would hope that if Java were ever to be rewritten from scratch, this mistake would not be repeated - optimisations that compromise encapsulation should be deferred until run-time, where their implications upon reflection & hotspot can be managed safely.

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline cylab

JGO Ninja


Medals: 49



« Reply #4 - Posted 2009-07-01 11:38:27 »

Inlining of constants is a rather annoying compile-time optimisation that pre-dates the many run-time optimisations that now exist.
(...)
I would hope that if Java were ever to be rewritten from scratch, this mistake would not be repeated - optimisations that compromise encapsulation should be deferred until run-time, where their implications upon reflection & hotspot can be managed safely.

Can you back this? Actually I am pretty sure that inlining is a runtime optimization and not a compile time one. At least there is no option to control this in javac...

Mathias - I Know What [you] Did Last Summer!
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 799
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #5 - Posted 2009-07-01 11:41:52 »

public static final int MY_INTEGER_PI = 3;

You won't find any getstatic on that field in your bytecode.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #6 - Posted 2009-07-01 13:10:13 »

It might be worth mentioning that I discovered this with just 'final' vars, even ones which are *not* 'static final'. Also the same behaviour results if the Field.setInt call is in a separate class, and if 'finalInt' is retrieved via a method call. Which would suggest to me that it's not just simple inlining that's causing this behaviour.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Abuse

JGO Knight


Medals: 12


falling into the abyss of reality


« Reply #7 - Posted 2009-07-01 17:06:28 »

It might be worth mentioning that I discovered this with just 'final' vars, even ones which are *not* 'static final'. Also the same behaviour results if the Field.setInt call is in a separate class, and if 'finalInt' is retrieved via a method call. Which would suggest to me that it's not just simple inlining that's causing this behaviour.

Ah sorry, missed the fact it was a non-static final. (infact, if it were static final it wouldn't be possible to set(...) a new value at all!)

I  guess the unpredictable behaviour that the Javadoc describes (and you are seeing) could be an artifact of the code caching occuring during jit/hotspot compilation.

I'm surprised nobody has asked the most important question!
Why on earth are you doing this? Smiley

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #8 - Posted 2009-07-01 23:26:11 »

I'm surprised nobody has asked the most important question!
Why on earth are you doing this? Smiley
Well I'm not really - I was writing some reflection code and forgot to ignore fields marked 'final' and so stumbled upon this behaviour by chance. I'm not so much interested in the behaviour (which although non-intuitive is documented as you point out), but rather why this happens like this. In particular no-one can seem to agree whether it's the compiler or the VM which is being overly agressive in it's inlining.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Roquen
« Reply #9 - Posted 2009-07-02 07:36:34 »

In particular no-one can seem to agree whether it's the compiler or the VM which is being overly agressive in it's inlining.

It's doing the correct thing.  Read Chapter 9 of JSR-133 (link above by Mr_Light).  By changing "immutables" you're breaking the program's claimed meaning, and all bets are off.  Not inlining and folding constants would not be enough.  You'd have to either treat all field reads as volatile (big performance hit) or have setting a final field invalidate all linked methods which access it (possible with the debugging interface) to trigger recompiles.  But this is just the tip of the iceberg.  Try this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
import java.lang.reflect.Field;

public class None
{
  public void setup()
  {
    int i;
    Field f;
   
    try {
      f = Integer.class.getDeclaredField("value");
      f.setAccessible(true);

      for(i=0; i<= 256; i++) {
        Integer bi = Integer.valueOf(i);
        f.setInt(bi, 0);
      }
    } catch(Exception e){
      System.out.println(e);
    }
  }
 
 
  public static void main(String[] args)
  {
    None n = new None();
   
    n.setup();
   
    for(int i=0;i<15;i++) {
      System.out.print(i);
      System.out.printf("+10 = %d\n", i+10);
    }
   
    System.exit(0);
  }
}


Now all methods which box integers are broken.  For real badness, change the character array of interned Strings.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #10 - Posted 2009-07-02 08:51:19 »

Try this:

Ooo, that's naughty. You get a cookie. Grin

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline pjt33
« Reply #11 - Posted 2009-07-02 09:29:31 »

Well I'm not really - I was writing some reflection code and forgot to ignore fields marked 'final' and so stumbled upon this behaviour by chance. I'm not so much interested in the behaviour (which although non-intuitive is documented as you point out), but rather why this happens like this. In particular no-one can seem to agree whether it's the compiler or the VM which is being overly agressive in it's inlining.
From memory, I think I've seen different behaviour in different Sun VMs. Although if you really want reflection shenanigans, you can use sun.misc.Unsafe to actually change the values of final fields...
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

UprightPath (20 views)
2014-09-20 20:14:06

BurntPizza (26 views)
2014-09-19 03:14:18

Dwinin (40 views)
2014-09-12 09:08:26

Norakomi (70 views)
2014-09-10 13:57:51

TehJavaDev (95 views)
2014-09-10 06:39:09

Tekkerue (49 views)
2014-09-09 02:24:56

mitcheeb (70 views)
2014-09-08 06:06:29

BurntPizza (52 views)
2014-09-07 01:13:42

Longarmx (39 views)
2014-09-07 01:12:14

Longarmx (45 views)
2014-09-07 01:11:22
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!