Re: #ReflectiveAccessByInstrumentationAgents

2016-04-21 Thread Andrew Dinn


On 20/04/16 12:40, Alan Bateman wrote:
> 
> On 19/04/2016 18:00, Andrew Dinn wrote:
>> :
>> I have been building and testing on JDK9 Byteman using the EA program
>> releases and have not seen anything break so far. However, that may just
>> be because i) Byteman and the Byteman tests are only using runtime
>> classes from the java base module and ii) app code used in tests is not
>> modularized -- well, at least not using Jigsaw (see below).
> It's good to hear that you are testing with the EA builds.
> 
> I think the main thing for Byteman, and this will be true at least some
> other agents too, is that there will likely need to be updated to
> support instrumentation with modules. We have a reasonable compatibility
> story for existing JVM TI and java agents but as soon as you get into
> instrumenting code to statically or reflectively access code in other
> modules then it may require the agent to arrange for this access to be
> allowed.

Having to explicitly manage module dependencies to retain compatibiity
with previous behaviour is at the very least a /nuisance/ because it now
means I -- and, no doubt, others in the agent business -- will have to
implement a dual-source agent, one for JDK9(+) and another to continue
to operate in JDK8/7/6 (yes, people can and do still use the latest
Byteman release in all those JDK releases). A solution internal to the
JVM which preserved existing behaviour and so did not require the
insertion of JDK-specific jumps through JDK-specific hoops would be much
preferred. Still, I suppose the releavant implementors are a relatively
small crowd and ought to know what we are doing and how to fix it.

That minor rant aside (sorry, I feel better for that but I don't suppose
anyone else on this list does :-) I will happily investigate the
available dynamic module-management APIs and see what options exist to
remedy the changes to the status quo and retain as much backwards
compatibility as I can. At that point I will come back and comment on
the very useful advice you have provided below. Thanks very much for
your help so far.

regards,


Andrew Dinn
---
Senior Principal Software Engineer
Red Hat UK Ltd
Registered in UK and Wales under Company Registration No. 3798903
Directors: Michael Cunningham (US), Michael O'Neill (Ireland), Paul
Argiry (US)


Re: [9] Review request: 8153872: Nashorn no longer needs access to com.sun.javafx.application

2016-04-21 Thread Sundararajan Athijegannathan
+1


On 4/21/2016 10:19 AM, Mandy Chung wrote:
>> On Apr 19, 2016, at 8:25 AM, Kevin Rushforth  
>> wrote:
>>
>> Jim,
>>
>> Please review the following fix:
>>
>> https://bugs.openjdk.java.net/browse/JDK-8153872
>> http://cr.openjdk.java.net/~kcr/8153872/webrev.00/
>>
>> This is a simple backout of the earlier fix for JDK-8153754.
> +1
>
> Glad that this dependency is eliminated.
>
> Mandy



Re: #ReflectiveAccessByInstrumentationAgents

2016-04-21 Thread Alan Bateman


On 21/04/2016 08:31, Andrew Dinn wrote:

:
Having to explicitly manage module dependencies to retain compatibiity
with previous behaviour is at the very least a /nuisance/ because it now
means I -- and, no doubt, others in the agent business -- will have to
implement a dual-source agent, one for JDK9(+) and another to continue
to operate in JDK8/7/6 (yes, people can and do still use the latest
Byteman release in all those JDK releases). A solution internal to the
JVM which preserved existing behaviour and so did not require the
insertion of JDK-specific jumps through JDK-specific hoops would be much
preferred. Still, I suppose the releavant implementors are a relatively
small crowd and ought to know what we are doing and how to fix it.
In the JVM TI and java.lang.instrument docs then you'll see that the VM 
is required to arrange for the module of instrumented code to read the 
unnamed module of both the application and boot class loaders. This is 
how we get many existing agents doing instrumentation, profilers and the 
like, to instrument code in modules without any knowledge of modules.


We know of course that this isn't sufficient for all use-cases. In the 
discussion here then Byteman finds itself in a new world where it 
injects code into module A to access a type in module B that is not 
accessible to A. The only way that I can see this working is where 
Byteman adds supports for modules and in the example, it injects and 
executes code in module B to export the package to module A.


-Alan


Re: #ReflectiveAccessByInstrumentationAgents

2016-04-21 Thread Peter Levart

Hi Andrew,

On 04/21/2016 09:31 AM, Andrew Dinn wrote:


On 20/04/16 12:40, Alan Bateman wrote:

On 19/04/2016 18:00, Andrew Dinn wrote:

:
I have been building and testing on JDK9 Byteman using the EA program
releases and have not seen anything break so far. However, that may just
be because i) Byteman and the Byteman tests are only using runtime
classes from the java base module and ii) app code used in tests is not
modularized -- well, at least not using Jigsaw (see below).

It's good to hear that you are testing with the EA builds.

I think the main thing for Byteman, and this will be true at least some
other agents too, is that there will likely need to be updated to
support instrumentation with modules. We have a reasonable compatibility
story for existing JVM TI and java agents but as soon as you get into
instrumenting code to statically or reflectively access code in other
modules then it may require the agent to arrange for this access to be
allowed.

Having to explicitly manage module dependencies to retain compatibiity
with previous behaviour is at the very least a /nuisance/ because it now
means I -- and, no doubt, others in the agent business -- will have to
implement a dual-source agent, one for JDK9(+) and another to continue
to operate in JDK8/7/6 (yes, people can and do still use the latest
Byteman release in all those JDK releases). A solution internal to the
JVM which preserved existing behaviour and so did not require the
insertion of JDK-specific jumps through JDK-specific hoops would be much
preferred. Still, I suppose the releavant implementors are a relatively
small crowd and ought to know what we are doing and how to fix it.

That minor rant aside (sorry, I feel better for that but I don't suppose
anyone else on this list does :-) I will happily investigate the
available dynamic module-management APIs and see what options exist to
remedy the changes to the status quo and retain as much backwards
compatibility as I can. At that point I will come back and comment on
the very useful advice you have provided below. Thanks very much for
your help so far.

regards,


Andrew Dinn



The situation is not so complicated, I think. If instrumented code calls 
some code in your Byteman module(s) then you should 1st make this code 
public and reside in exported packages. All you have to do then is add 
read edges from modules of instrumented classes to modules of Byteman 
classes that are called by instrumented code as they are being 
instrumented. For example, having the following utility class compiled 
with JDK 8 (not using any JDK 9 API):


public class ClassFileTransformerWrapper {
public ClassFileTransformer wrap(Instrumentation instrumentation,
 ClassFileTransformer transformerImpl,
 Class... readableClasses) {
try {
Class.forName("java.lang.reflect.Module");
} catch (ClassNotFoundException e) {
// don't need to wrap if on JDK 8 or less
return transformerImpl;
}
// wrap it
return new ReadEdgeAddingClassFileTransformer(instrumentation,
transformerImpl,
readableClasses);
}
}

...which you call with your ClassFileTransformer implementation and the 
Class(es) where your Byteman code resides that contains methods called 
from instrumented code. The following delegating ClassFileTransformer, 
compiled with -target 9, will add read edges then:


public class ReadEdgeAddingClassFileTransformer implements 
ClassFileTransformer {


private final Instrumentation instrumentation;
private final ClassFileTransformer transformerImpl;
private final Set readableModules;

ReadEdgeAddingClassFileTransformer(Instrumentation instrumentation,
   ClassFileTransformer 
transformerImpl,

   Class[] readableClasses) {
this.instrumentation = instrumentation;
this.transformerImpl = transformerImpl;
this.readableModules = new HashSet<>();
for (Class c : readableClasses) {
this.readableModules.add(c.getModule());
}
}

@Override
public byte[] transform(ClassLoader loader,
String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws 
IllegalClassFormatException {

return transformerImpl.transform(loader,
 className,
 classBeingRedefined,
 protectionDomain,
 classfileBuffer);
}

@Override
public byte[] transform(Module module,
String className,
Class classBeingRedefined,
ProtectionDomain protectionD

Re: #ReflectiveAccessByInstrumentationAgents

2016-04-21 Thread Andrew Dinn
Hi Peter,

On 21/04/16 12:09, Peter Levart wrote:
> The situation is not so complicated, I think. . . .

Thank you very much for your example code.

I understand that it will be possible to localize the changes into a
small part of the agent codebase. My problem was not with this factoring
of the code but rather with the build and deployment process.

I was assuming that I would have to locate any jdk9-specific code in a
separate extension jar and ensure that clients consistently hoist both
the jdk9-specific extension jar and the vanilla agent jar into either
the system classpath or the bootstrap classpath when running on JDK9(+).

The alternative was to use the new multi-release jar model to deploy the
agent jar but, of course, I don't suppose that is ever going to work for
JDK6 deployments.

As you say, I can avoid this dilemma simply by bundling all the code
into the one agent jar and instantiating the relevant management classes
indirectly according to whether modules are present or not. That will
ensure that the JDK9(+)-compiled classes are not loaded when running on
JDK8(-).

Thanks once again for your, as ever, very helpful insights.

regards,


Andrew Dinn
---



Re: #ReflectiveAccessByInstrumentationAgents

2016-04-21 Thread Alan Bateman



On 21/04/2016 12:09, Peter Levart wrote:

:

The situation is not so complicated, I think. If instrumented code 
calls some code in your Byteman module(s) then you should 1st make 
this code public and reside in exported packages. All you have to do 
then is add read edges from modules of instrumented classes to modules 
of Byteman classes that are called by instrumented code as they are 
being instrumented. 
If the instrumentation is just injecting code to call into Byteman then 
I assume it just works now. That is, it doesn't appear that Byteman has 
embraced modules yet and so I assume it must be an agent specified via 
-javaagent with perhaps supporting code in other JAR files. In that 
case, the Byteman code is the unnamed module of the app class loader and 
the VM will automatically add a read edge when the transformer touches 
code in any named module. This is the compatibility support that I 
mentioned in another mail.


If you right this it should be simple as you say. On the other hand, 
some of the mails mention accessing non-public members, setAccessible, 
and even (it would appear) adjusting class loader delegation on the fly 
to facilitate the patches.


-Alan


java.lang.reflect.Module.WeakSet is not thread-safe

2016-04-21 Thread Peter Levart

Hi,

While browsing code in java.lang.reflect.Module (I sometimes do that 
just to see how thinks work ;-) I stumbled on the following nested class:


private static class WeakSet {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();

private final WeakHashMap map = new WeakHashMap<>();

/**
 * Adds the specified element to the set.
 */
void add(E e) {
writeLock.lock();
try {
map.put(e, Boolean.TRUE);
} finally {
writeLock.unlock();
}
}

/**
 * Returns {@code true} if this set contains the specified element.
 */
boolean contains(E e) {
readLock.lock();
try {
return map.containsKey(e);
} finally {
readLock.unlock();
}
}
}

...while this seems OK from 1st look, it is not. WeakHashMap is not 
thread-safe even for seemingly read-only operations. All its operations 
can mutate internal state in a non-thread-safe way. The simplest way to 
fix this is to use a writeLock for containsKey operation too. But such 
structure does not scale well to multiple threads for frequent lookups.


WeakSet is used in Module to keep track of transient read edges, exports 
and uses of services added dynamically to the module. Modification 
operations are not so performance critical, but lookup operations are.


I propose to add a thread-safe WeakPairMap data structure which 
associates a pair of weakly-reachable keys with a strongly-reachable 
value based on ConcurrentHashMap. Such data structure is 
footprint-friendly, since only a single instance exists for a particular 
purpose, totaling 3 instances for the transient structures serving all 
Modules in the system:


http://cr.openjdk.java.net/~plevart/jdk9-dev/Module.WeakSet.multithreadUnsafe/webrev.01/

So, what do you think?

Regards, Peter



Re: java.lang.reflect.Module.WeakSet is not thread-safe

2016-04-21 Thread Alan Bateman



On 21/04/2016 17:07, Peter Levart wrote:

:

...while this seems OK from 1st look, it is not. WeakHashMap is not 
thread-safe even for seemingly read-only operations. All its 
operations can mutate internal state in a non-thread-safe way. The 
simplest way to fix this is to use a writeLock for containsKey 
operation too. But such structure does not scale well to multiple 
threads for frequent lookups.
Sigh, it's a left over from early prototyping and was meant to be 
replaced (but wasn't). Now seems the right time.


-Alan


Re: java.lang.reflect.Module.WeakSet is not thread-safe

2016-04-21 Thread Peter Levart



On 04/21/2016 06:07 PM, Peter Levart wrote:
I propose to add a thread-safe WeakPairMap data structure which 
associates a pair of weakly-reachable keys with a strongly-reachable 
value based on ConcurrentHashMap. Such data structure is 
footprint-friendly, since only a single instance exists for a 
particular purpose, totaling 3 instances for the transient structures 
serving all Modules in the system:


http://cr.openjdk.java.net/~plevart/jdk9-dev/Module.WeakSet.multithreadUnsafe/webrev.01/ 



Oops...

It looks like I replaced one thread-unsafe construction with another one:

 389 // additional exports added at run-time
 390 // source module (1st key), target module (2nd key), exported 
packages (value)
 391 private static final WeakPairMap> 
transientExports =

 392 new WeakPairMap<>();

...that would've been OK if I hadn't used normal HashSet for holding the 
set of packages:


 623 // add package name to transientExports if absent
 624 transientExports
 625 .computeIfAbsent(this, other, (_this, _other) -> new 
HashSet<>())

 626 .add(pn);

Luckily this can be easily fixed by using a ConcurrentHashMap instead of 
HashSet which is even more space-friendly (HashSet is just a wrapper 
around HashMap and HashMap is basically the same structure as 
ConcurrentHashMap):


http://cr.openjdk.java.net/~plevart/jdk9-dev/Module.WeakSet.multithreadUnsafe/webrev.02/


Regards, Peter



Re: java.lang.reflect.Module.WeakSet is not thread-safe

2016-04-21 Thread Rémi Forax
I remember seeing this codd an thinking that synchronized should do the job.
I don't believe this use case requires something more complex.

Remi


Le 21 avril 2016 18:21:55 CEST, Alan Bateman  a écrit :
>
>
>On 21/04/2016 17:07, Peter Levart wrote:
>> :
>>
>> ...while this seems OK from 1st look, it is not. WeakHashMap is not 
>> thread-safe even for seemingly read-only operations. All its 
>> operations can mutate internal state in a non-thread-safe way. The 
>> simplest way to fix this is to use a writeLock for containsKey 
>> operation too. But such structure does not scale well to multiple 
>> threads for frequent lookups.
>Sigh, it's a left over from early prototyping and was meant to be 
>replaced (but wasn't). Now seems the right time.
>
>-Alan



Re: java.lang.reflect.Module.WeakSet is not thread-safe

2016-04-21 Thread Alan Bateman


On 21/04/2016 20:52, Rémi Forax wrote:

I remember seeing this codd an thinking that synchronized should do the job.
I don't believe this use case requires something more complex.

Remi
I've taken a first pass over it and WeakPairMap seems straight-forward 
to use but its implementation, with Pair/Weak/Primary/Secondary/Lookup 
is complex.


Prior to #ReflectionWithoutReadability then transientReads was 
important, less so now although I think we should continue to allow 
concurrent lookups.


-Alan