Update to description of JEP 193: Enhanced Volatiles
Remi Forax
forax at univ-mlv.fr
Fri Oct 31 15:59:57 UTC 2014
On 10/31/2014 02:57 PM, MacGregor, Duncan (GE Energy Management) wrote:
> I like the overall idea but also think the string feels wrong, it suggests
> that both the class of the object and the field name could be dynamic and
> might change with every invocation, but I really doubt we¹d want that.
A previous iteration of the API (in my head) was using a class named
FieldMirror like this:
public class Safe {
@Instrinsic
public static <T, V> V get(T receiver, FieldMirror<T, V> fieldMirror) { }
...
}
public class FieldMirror<T, V> {
public FieldMirror(Class<T> declaringClass, String fieldName,
Class<V> fieldType) { ... }
}
class Foo {
private static final FieldMirror<Foo, Integer> Foo_i = new
FieldMirror<>(Foo.class, "i", int.class);
int i;
public int get() {
return (int)Safe.get(this, Foo_i);
}
}
In that case, the creation of the FieldMirror requires to check if the
field exist and we need a supplementary check in the slow MH as Paul
called it, to verify that
the field mirror reference a visible field from the callsite. While
sending a String is ugly, it avoids this double check.
Duncan, as you can see, it also suggests that the field mirror taken as
argument of Safe.get() can be dynamic too,
so I don't see this API as an improvement, not compared to
class Foo {
private static final String Foo_i = "i";
int i;
public int get() {
return (int)Safe.get(this, Foo_i);
}
}
As I said, apart if we have a compiler representation of a field
reference, something like Foo::i,
I think I prefer to stick with Strings.
> [...]
>
> Regards, Duncan.
Rémi
>
> On 31/10/2014 13:37, "Paul Sandoz" <paul.sandoz at oracle.com> wrote:
>
>> Hi Remi,
>>
>> Thanks, that's an interesting approach which has not previously occurred
>> to me.
>>
>> So this proposal combines lookup and access into one call. IIUC to do
>> that effectively the dynamic call site needs to initially provide a
>> "slow" MH that performs an access-control-check, and then updates the
>> call site (once only) with a MH performing the faster check that assumes
>> the field identifier is held constant (and if not barfs).
>>
>> I find the use of the String a little raw, it does not uniquely identify
>> a field, unless there is more information encoded, and is error prone
>> when repeatedly declared. There is one less possible runtime exception
>> for arity but that is counter balanced with one each for access control
>> and constant-check per call-site.
>>
>> If we could introduce a more formal field identifier it would strengthen
>> the proposal. So i think it worth keeping this idea around while seeing
>> how we progress with handles and especially generic handles.
>>
>>
>> We could perform similar checks on VarHandle invocation too with a
>> dynamic call site, if such integrity [1] is a concern. For non-public
>> fields, the slow path checks that the lookup class has access to the
>> receiver class before proceeding [2], although that would then
>> differentiate from MH behaviour. It could even be configured as something
>> optional, or even perhaps programatically "these are the set of classes i
>> give access permission".
>>
>> An obvious observation: existing Unsafe or Atomic*Update refs need to be
>> guarded from leakage, so this pattern is not new or unexpected. When
>> converting Unsafe usages to VarHandle it's quite simple to maintain that
>> pattern. Further, it's possible have tooling that detect such leaks.
>>
>> Paul.
>>
>> [1] I am more concerned about integrity ("private" means private etc.)
>> rather than security with a security manager.
>>
>> [2] Can such checks be folded away?
>>
>>
>> On Oct 30, 2014, at 8:58 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>>
>>> On 10/30/2014 04:53 PM, Paul Sandoz wrote:
>>>> On Oct 30, 2014, at 4:47 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>>>>
>>>>> On 10/30/2014 03:02 PM, Paul Sandoz wrote:
>>>>>> Hi,
>>>>>>
>>>>>> I have, with the help of Brian, Doug and John, updated the
>>>>>> description of JEP 193: Enhanced Volatiles to reflect our current
>>>>>> thinking based on:
>>>>>>
>>>>>> - the prototype implementation in valhalla;
>>>>>> - performance measurements of that implementation; and
>>>>>> - investigations related to signature polymorphic methods and
>>>>>> invokedynamic.
>>>>>>
>>>>>> Thanks,
>>>>>> Paul.
>>>>> I seems that the changes are not propagated to the JEP yet,
>>>>> but there are available throught the corresponding bug:
>>>>> https://bugs.openjdk.java.net/browse/JDK-8046183
>>>>>
>>>> Doh! thanks, i forgot to send the link out,
>>>> Paul,
>>> Here is a kind of counter-proposal because I think that there is a far
>>> simpler and more secure API.
>>>
>>> I think that instead of having to first instantiate an object
>>> (VarHandle) and then call a method on it,
>>> this can be done in one method.
>>>
>>> |public class Safe {
>>> @Intrinsic
>>> public staticObject get(Object receiver, String fieldName) { }|
>>> || @Intrinsic
>>> public staticObject getRelaxed(Object receiver, String fieldName)
>>> { }|
>>> ||||@Intrinsic||
>>> ||||public staticObject getAcquire(Object receiver, String
>>> fieldName) { }|||
>>> |||||| @Intrinsic|||
>>> ||||public staticObject getRelaxed(Object receiver, String
>>> fieldName) { }|||
>>> ||||| @Intrinsic||||
>>> ||||public staticObject |||||||getSequential|(Object receiver,
>>> String fieldName) { }||
>>> |
>>> |||||| @Intrinsic|||||
>>> |||public static void set(|||||||Object receiver, String
>>> fieldName|||, Object value) { }|
>>> // and all other related variations
>>> ... }|
>>>
>>> and this is how to use it:
>>>
>>> class Foo {
>>>
>>> | int i;
>>>
>>> public void acquire() {
>>> |||boolean r= (boolean)Safe.compareAndSet(this, "i", 0, 1);
>>> ...
>>> | }
>>> }|
>>>
>>>
>>> At compile time, the compiler checks that a method Safe.compareAndSet
>>> with compatible parameter types exists
>>> but instead of generating an invokestatic, it generates an
>>> invokedynamic which uses the signature of the actual callsite.
>>> Using the actual types in the signature allows to avoid unnecessary
>>> boxing while
>>> keeping the typechecking rules simples (they are not changed !) as
>>> explained in the current draft of JEP 193.
>>>
>>> This API doesn't use any object to represent a field but uses a String
>>> as field name, you may think that
>>> 1) this mean that the field will be queried each time:
>>> It doesn't has to. invokedynamic allow to install a dynamic check
>>> that will test that the string doesn't change
>>> from one call to another. This check will be removed by the JIT
>>> because the string never change
>>> (if the string change, the best is to throw a runtime exception like
>>> IllegalArgumentException explaining
>>> that the field name must be a constant).
>>> 2) that using a String is not typesafe. Having a typesafe API is hard
>>> here, because the type of a field
>>> is not something you can get at compile time, there is no field
>>> reference syntax in Java (no Foo::i),
>>> so a String seems to be a good practical choice.
>>>
>>> And this API has a true real advantage compared to the VarHandle API,
>>> this API is inherently more secure.
>>> A VarHandle or any object representing a field will have some special
>>> security credential because it can access
>>> to a field without having to check at runtime if the field is visible
>> >from where the call is done (for performance reason).
>>> From my own experience, it's too easy to make this kind of object too
>>> visible introduced a security hole without
>>> even doing something hard.
>>> By not reifying the access to a field as an object, the API is more
>>> secure with the restriction
>>> that a method can only access to the field of the class that contains
>>> the call to the API.
>>>
>>> In term of implementation, the compiler will generate this bytecode for
>>> the class Foo:
>>>
>>> ||class Foo {
>>>
>>> | int i;
>>>
>>> public void acquire() {
>>> invokedynamic "compareAndSet" (Foo;String;II)Z
>>> BSM
>>> =||java.lang.invoke.SafeMetaProtocol|||.bootstrap(Lookup;String;MethodTyp
>>> e;MethodHandle)
>>> ARG = MH(||||||Safe.compareAndSet(||Object;String;Object;Object;)
>>> istore 0||||
>>> ...
>>> | }
>>> }|
>>>
>>> and from the JLS perspective, the compiler will recognize that the
>>> method inside Safe
>>> are special because there are annotated by an annotation that has a
>>> meta-annotation
>>> named BootstrapMethod that specifies the bootstrap method that should
>>> be used
>>> when emitting the invokedynamic call.
>>>
>>> ||||
>>>
>>> @BootstrapMethod(type=java.lang.invoke.SafeMetaProtocol.class,
>>> name="bootstrap")
>>> @interface Intrinsic {
>>> // empty
>>> }
>>>
>>> cheers,
>>> Rémi
>>>
More information about the valhalla-dev
mailing list