Skip to content

Commit

Permalink
(WIP) InjectedClassRuntime.createFor
Browse files Browse the repository at this point in the history
  • Loading branch information
Godin committed Jun 29, 2022
1 parent 7d5e501 commit 7d2b34d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,8 @@
*******************************************************************************/
package org.jacoco.agent.rt.internal;

import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.Instrumentation;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.jacoco.core.internal.InputStreams;
import org.jacoco.core.runtime.AgentOptions;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.InjectedClassRuntime;
Expand Down Expand Up @@ -77,56 +71,7 @@ private static IRuntime createInjectedClassRuntime(
} catch (final ClassNotFoundException e) {
return null;
}
final IRuntime runtime = (IRuntime) (new ClassLoader() {
@Override
public Class<?> loadClass(String name)
throws ClassNotFoundException {
if (!name.startsWith(InjectedClassRuntime.class.getName())) {
return super.loadClass(name);
}
final InputStream resourceAsStream = getResourceAsStream(
name.replace('.', '/') + ".class");
final byte[] bytes;
try {
bytes = InputStreams.readFully(resourceAsStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
return defineClass(name, bytes, 0, bytes.length);
}
}.loadClass(InjectedClassRuntime.class.getName())
.getConstructor(Class.class, String.class)
.newInstance(Object.class, "$JaCoCo"));
final Object module = getModule(runtime.getClass());
if (module.equals(getModule(PreMain.class))) {
throw new IllegalStateException();
}
Instrumentation.class.getMethod("redefineModule", //
Class.forName("java.lang.Module"), //
Set.class, //
Map.class, //
Map.class, //
Set.class, //
Map.class //
).invoke(instrumentation, // instance
getModule(Object.class), // module
Collections.emptySet(), // extraReads
Collections.emptyMap(), // extraExports
Collections.singletonMap("java.lang",
Collections.singleton(module)), // extraOpens
Collections.emptySet(), // extraUses
Collections.emptyMap() // extraProvides
);
return runtime;
}

/**
* @return {@code cls.getModule()}
*/
private static Object getModule(final Class<?> cls) throws Exception {
return Class.class //
.getMethod("getModule") //
.invoke(cls);
return InjectedClassRuntime.createFor(instrumentation);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@
*******************************************************************************/
package org.jacoco.core.runtime;

import org.jacoco.core.internal.InputStreams;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.Instrumentation;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
* {@link IRuntime} which defines a new class using
* {@code java.lang.invoke.MethodHandles.Lookup.defineClass} introduced in Java
Expand Down Expand Up @@ -48,6 +56,57 @@ public InjectedClassRuntime(final Class<?> locator,
'/') + '/' + simpleClassName;
}

/**
* Creates a new {@link InjectedClassRuntime}.
*
* @param instrumentation
* instrumentation interface
* @return new runtime instance
*/
public static IRuntime createFor(final Instrumentation instrumentation)
throws Exception {
final ClassLoader classLoader = new ClassLoader() {
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (!name.startsWith(InjectedClassRuntime.class.getName())) {
return super.loadClass(name, resolve);
}
final InputStream resourceAsStream = getResourceAsStream(
name.replace('.', '/') + ".class");
final byte[] bytes;
try {
bytes = InputStreams.readFully(resourceAsStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
return defineClass(name, bytes, 0, bytes.length);
}
};
Instrumentation.class.getMethod("redefineModule", //
Class.forName("java.lang.Module"), //
Set.class, //
Map.class, //
Map.class, //
Set.class, //
Map.class //
).invoke(instrumentation, // instance
Class.class.getMethod("getModule").invoke(Object.class), // module
Collections.emptySet(), // extraReads
Collections.emptyMap(), // extraExports
Collections.singletonMap("java.lang",
Collections.singleton(
ClassLoader.class.getMethod("getUnnamedModule")
.invoke(classLoader))), // extraOpens
Collections.emptySet(), // extraUses
Collections.emptyMap() // extraProvides
);
return (IRuntime) classLoader
.loadClass(InjectedClassRuntime.class.getName())
.getConstructor(Class.class, String.class)
.newInstance(Object.class, "$JaCoCo");
}

@Override
public void startup(final RuntimeData data) throws Exception {
super.startup(data);
Expand Down

0 comments on commit 7d2b34d

Please sign in to comment.