Directly inject probe array instance into companion class
This obsolets the runtime access hacks.
diff --git a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java
index 68f25fc..d6c7999 100644
--- a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java
+++ b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java
@@ -222,7 +222,7 @@
}
private CoverageTransformer createTransformer() {
- return new CoverageTransformer(runtime, options, recorder);
+ return new CoverageTransformer(runtime, options, null, recorder);
}
private static byte[] getClassData(Class<?> clazz) throws IOException {
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java
index d2175c3..724f5d4 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java
@@ -19,6 +19,7 @@
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.AgentOptions;
import org.jacoco.core.runtime.IRuntime;
+import org.jacoco.core.runtime.RuntimeData;
import org.jacoco.core.runtime.WildcardMatcher;
/**
@@ -33,6 +34,8 @@
AGENT_PREFIX = toVMName(name.substring(0, name.lastIndexOf('.')));
}
+ private final RuntimeData runtimeData;
+
private final Instrumenter instrumenter;
private final IExceptionLogger logger;
@@ -58,7 +61,9 @@
* logger for exceptions during instrumentation
*/
public CoverageTransformer(final IRuntime runtime,
- final AgentOptions options, final IExceptionLogger logger) {
+ final AgentOptions options, final RuntimeData runtimeData,
+ final IExceptionLogger logger) {
+ this.runtimeData = runtimeData;
this.instrumenter = new Instrumenter(runtime);
this.logger = logger;
// Class names will be reported in VM notation:
@@ -90,7 +95,8 @@
try {
classFileDumper.dump(classname, classfileBuffer);
- return instrumenter.instrument(classfileBuffer, classname, loader);
+ return instrumenter.instrument(classfileBuffer, classname, loader,
+ runtimeData);
} catch (final Exception ex) {
final IllegalClassFormatException wrapper = new IllegalClassFormatException(
ex.getMessage());
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/PreMain.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/PreMain.java
index e87d203..227ef3d 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/PreMain.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/PreMain.java
@@ -47,7 +47,7 @@
final IRuntime runtime = createRuntime(inst);
runtime.startup(agent.getData());
inst.addTransformer(new CoverageTransformer(runtime, agentOptions,
- IExceptionLogger.SYSTEM_ERR));
+ agent.getData(), IExceptionLogger.SYSTEM_ERR));
}
private static IRuntime createRuntime(final Instrumentation inst)
diff --git a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
index d3b7861..6130f90 100644
--- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
@@ -31,6 +31,7 @@
import org.jacoco.core.internal.instr.ProbeArrayStrategyFactory;
import org.jacoco.core.internal.instr.SignatureRemover;
import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
+import org.jacoco.core.runtime.RuntimeData;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
@@ -77,11 +78,11 @@
*
*/
public byte[] instrument(final ClassReader reader) {
- return instrument(reader, null);
+ return instrument(reader, null, null);
}
public byte[] instrument(final ClassReader reader,
- final ClassLoader classLoader) {
+ final ClassLoader classLoader, final RuntimeData runtimeData) {
final ClassWriter writer = new ClassWriter(reader, 0);
final IProbeArrayStrategy strategy;
if (classLoader == null) {
@@ -90,7 +91,7 @@
} else {
final long classId = CRC64.checksum(reader.b);
strategy = new CompanionClassStrategy(reader.getClassName(),
- classId, accessorGenerator, classLoader);
+ classId, classLoader, runtimeData);
}
final ClassVisitor visitor = new ClassProbesAdapter(
new ClassInstrumenter(strategy, writer), true);
@@ -111,13 +112,14 @@
*/
public byte[] instrument(final byte[] buffer, final String name)
throws IOException {
- return instrument(buffer, name, null);
+ return instrument(buffer, name, null, null);
}
public byte[] instrument(final byte[] buffer, final String name,
- final ClassLoader classLoader) throws IOException {
+ final ClassLoader classLoader, final RuntimeData runtimeData)
+ throws IOException {
try {
- return instrument(new ClassReader(buffer), classLoader);
+ return instrument(new ClassReader(buffer), classLoader, runtimeData);
} catch (final RuntimeException e) {
throw instrumentError(name, e);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/CompanionClassStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/CompanionClassStrategy.java
index 458e2fa..d95ad59 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/CompanionClassStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/CompanionClassStrategy.java
@@ -14,7 +14,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
+import org.jacoco.core.runtime.RuntimeData;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
@@ -43,18 +43,17 @@
private final String className;
private final String companionName;
private final long classId;
- private final IExecutionDataAccessorGenerator accessorGenerator;
private final ClassLoader classLoader;
+ private final RuntimeData runtimeData;
public CompanionClassStrategy(final String className, final long classId,
- final IExecutionDataAccessorGenerator accessorGenerator,
- final ClassLoader classLoader) {
+ final ClassLoader classLoader, final RuntimeData runtimeData) {
this.className = className;
this.classLoader = classLoader;
this.companionName = String.format("%s$jacoco%016x", className,
Long.valueOf(classId));
this.classId = classId;
- this.accessorGenerator = accessorGenerator;
+ this.runtimeData = runtimeData;
}
public int storeInstance(final MethodVisitor mv, final int variable) {
@@ -66,35 +65,26 @@
public void addMembers(final ClassVisitor cv, final int probeCount) {
// we reuse this to create and load the companion class
- loadCompanionClass(createCompanionClass(probeCount));
+ loadCompanionClass(createCompanionClass(), probeCount);
}
- private byte[] createCompanionClass(final int probeCount) {
+ private byte[] createCompanionClass() {
final ClassWriter cw = new ClassWriter(0);
- cw.visit(Opcodes.V1_1, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL,
- companionName, null, "java/lang/Object", null);
+ cw.visit(Opcodes.V1_1, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PUBLIC
+ | Opcodes.ACC_FINAL, companionName, null, "java/lang/Object",
+ null);
- cw.visitField(Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT
- | Opcodes.ACC_FINAL, InstrSupport.DATAFIELD_NAME,
+ cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC
+ | Opcodes.ACC_TRANSIENT, InstrSupport.DATAFIELD_NAME,
InstrSupport.DATAFIELD_DESC, null, null);
- final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>",
- "()V", null, null);
- mv.visitCode();
- final int stackSize = accessorGenerator.generateDataAccessor(classId,
- className, probeCount, mv);
- mv.visitFieldInsn(Opcodes.PUTSTATIC, companionName,
- InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC);
- mv.visitInsn(Opcodes.RETURN);
- mv.visitMaxs(stackSize, 0);
- mv.visitEnd();
-
cw.visitEnd();
return cw.toByteArray();
}
- private void loadCompanionClass(final byte[] definition) {
+ private void loadCompanionClass(final byte[] definition,
+ final int probeCount) {
try {
classLoader.loadClass(companionName);
// companion does already exist:
@@ -103,15 +93,22 @@
// expected
}
try {
- DEFINE_CLASS.invoke(classLoader, companionName.replace('/', '.'),
- definition, Integer.valueOf(0),
- Integer.valueOf(definition.length));
+ final Class<?> companion = (Class<?>) DEFINE_CLASS.invoke(
+ classLoader, companionName.replace('/', '.'), definition,
+ Integer.valueOf(0), Integer.valueOf(definition.length));
+
+ final boolean[] probes = runtimeData.getExecutionData(
+ Long.valueOf(classId), className, probeCount).getProbes();
+ companion.getField(InstrSupport.DATAFIELD_NAME).set(null, probes);
+
} catch (final IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (final IllegalAccessException e) {
throw new RuntimeException(e);
} catch (final InvocationTargetException e) {
throw new RuntimeException(e.getTargetException());
+ } catch (final NoSuchFieldException e) {
+ throw new RuntimeException(e);
}
}