This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Strange visibility for constructor fields with -optimize

1 reply
erikrozendaal
Joined: 2011-04-14,
User offline. Last seen 1 year 26 weeks ago.

In my quest for better performance with the immutable TreeMap/TreeSet code I hit upon the following strange, but somewhat useful behavior:

$ scala -optimize
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Bar(final val a: Int, final val b: Int, final var c: Int, final var d: Int) {
def bar = a + c
}

// Exiting paste mode, now interpreting.

defined class Bar

scala> :javap -p Bar
Compiled from ""
public class Bar extends java.lang.Object implements scala.ScalaObject{
public final int a;
private final int b;
public final int c;
private final int d;
public final int a();
public final int b();
public final int c();
public final void c_$eq(int);
public final int d();
public final void d_$eq(int);
public int bar();
public Bar(int, int, int, int);
}

Notice the following:
- Fields a and c become public for some reason, while b and d are not. This only happens when they are referenced by a method and only when -optimize is specified.
- Fields c and d are marked final, even though they are vars (and mutation works). I guess final doesn't mean much at the JVM level?
- These even happens when a subclass refers to one of the fields defined in the parents class constructor!
- This doesn't happen for normal fields (not declared in the constructor argument) or non-final constructor args.

Now, this is actually useful for my latest RedBlack implementation:

sealed abstract class Tree[A, +B](
@(inline @getter) final val key: A,
@(inline @getter) final val value: B,
@(inline @getter) final val left: Tree[A, B],
@(inline @getter) final val right: Tree[A, B])
extends Serializable {
// useful stuff here
}

By annotating the getters as inlined the scala compiler generates direct field accessors instead of going through the getters (even on hotspot). This gives a decent performance boost in traversing the tree. (About 70% faster for finding the smallest/largest node, but there is no effect on arbitrary lookups. Maybe there is a special case optimization in HotSpot?)

Unfortunately, it looks like I'm relying on buggy behavior here. But I'd really like to be able to use direct field references without using accessors.

Would it be useful to formalize the behavior of @inline on final fields to:
- target the setter and getter by default
- make the field have the same accessibility as the getter/setter
- make the scala compiler emit "getfield" bytecode instead of invokevirtual to access fields (maybe only with -optimize).

Or maybe a new annotation (@directField? @exposed?) to enforce direct field access?

It's not often needed, but it is nice to not have to fall back on a Java class to get direct field access…

Regards,
Erik

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: Strange visibility for constructor fields with -optimize


On Wed, Jan 4, 2012 at 10:50 AM, Erik Rozendaal <erik [at] deler [dot] org> wrote:
Notice the following:
- Fields a and c become public for some reason, while b and d are not. This only happens when they are referenced by a method and only when -optimize is specified.
- Fields c and d are marked final, even though they are vars (and mutation works). I guess final doesn't mean much at the JVM level?
- These even happens when a subclass refers to one of the fields defined in the parents class constructor!
- This doesn't happen for normal fields (not declared in the constructor argument) or non-final constructor args.

https://issues.scala-lang.org/browse/SI-3569   
Unfortunately, it looks like I'm relying on buggy behavior here.

That's correct.  
But I'd really like to be able to use direct field references without using accessors.

Me too.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland