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); } }