diff options
Diffstat (limited to 'org.jacoco.core')
-rw-r--r-- | org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java | 324 |
1 files changed, 0 insertions, 324 deletions
diff --git a/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java deleted file mode 100644 index 39b90fb6..00000000 --- a/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java +++ /dev/null @@ -1,324 +0,0 @@ -// BEGIN android-change -package org.jacoco.core.data; - -import static java.lang.String.format; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.charset.Charset; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; - -import org.jacoco.core.data.ExecutionDataWriter; - -/** - * Memory-mapped execution data implementation. - * - * Stores the probe data in a section of a memory-mapped file, so that it will be available without - * requiring a flush of the coverage data. - */ -public final class MappedExecutionData implements IExecutionData { - - private static FileChannel CHANNEL; - - private final long id; - private final String name; - private final int probeCount; - - // Stores the memory-mapped byte buffer containing the probe data, packed as bits. - private MappedByteBuffer probeBuffer; - - /** - * Creates the mapped execution data. - */ - public MappedExecutionData(final long id, final String name, final int probeCount) - throws IOException { - this.id = id; - this.name = name; - this.probeCount = probeCount; - - createMemoryMappedProbeArray(id, name, probeCount); - } - - /** - * Maps a section of the already-opened file for the probe data. - * - * @param id the class id - * @param name the VM class name - * @param probeCount the number of probes for this class - */ - private void createMemoryMappedProbeArray( - final long id, final String name, final int probeCount) throws IOException { - // TODO: Figure out a more portable way to do this. Currently needed to avoid - // cross-VM race conditions when writing/mapping the file. Since most processes - // are forked from zygote, they will initially share the same output file, but - // without synchronization across VMs, this can cause simultaneous maps/writes from - // different VMs to interrupt each other, resulting in malformed execution data. - // Adding file locks did not resolve this issue. Note that only new classes that - // were loaded after the fork will end up in the new file. Classes that were - // already loaded will end up in the original output file for the pre-forked - // process, which is OK. - if (CHANNEL == null) { - throw new IOException("Memory mapped file was not initialized."); - } - - synchronized (CHANNEL) { - int byteCount = (probeCount + 7) / 8; - - // Write the ExecutionData block info. - ByteBuffer execDataBuffer = ByteBuffer.allocate(11); - execDataBuffer.put(ExecutionDataWriter.BLOCK_EXECUTIONDATA); - execDataBuffer.putLong(id); - execDataBuffer.putShort((short) name.length()); - execDataBuffer.flip(); - CHANNEL.write(execDataBuffer); - CHANNEL.write(ByteBuffer.wrap(name.getBytes(Charset.forName("UTF-8")))); - - // Write the probe info and map part of this file for the probe data. - CHANNEL.write(toVarIntByteBuffer(probeCount)); - probeBuffer = CHANNEL.map(FileChannel.MapMode.READ_WRITE, CHANNEL.position(), byteCount); - CHANNEL.position(CHANNEL.position() + byteCount); - } - } - - /** - * Creates the output file that will be mapped for probe data. - */ - public static void prepareFile(int pid) throws IOException { - // Write header information to the file. - ByteBuffer headerBuffer = ByteBuffer.allocate(5); - headerBuffer.put(ExecutionDataWriter.BLOCK_HEADER); - headerBuffer.putChar(ExecutionDataWriter.MAGIC_NUMBER); - headerBuffer.putChar(ExecutionDataWriter.FORMAT_VERSION); - headerBuffer.flip(); - - // If this file already exists (due to pid re-usage), the previous coverage data - // will be lost when the file is overwritten. - File outputFile = new File("/data/misc/trace/jacoco-" + pid + ".mm.ec"); - CHANNEL = new RandomAccessFile(outputFile, "rw").getChannel(); - synchronized (CHANNEL) { - CHANNEL.write(headerBuffer); - } - } - - /** - * Writes a variable-length int to a {@link ByteBuffer}. - * - * @param value the value to write - * @return a ByteBuffer that can be used to write to a FileChannel containing the value - */ - private ByteBuffer toVarIntByteBuffer(int value) { - ByteBuffer buffer = ByteBuffer.allocate(5); - if (value == 0) { - buffer.put((byte) 0); - } else { - while (value > 0) { - if ((value & 0xFFFFFF80) == 0) { - buffer.put((byte) value); - } else { - buffer.put((byte) (0x80 | (value & 0x7F))); - } - value >>>= 7; - } - } - buffer.flip(); - return buffer; - } - - /** - * Return the unique identifier for this class. The identifier is the CRC64 - * checksum of the raw class file definition. - * - * @return class identifier - */ - public long getId() { - return id; - } - - /** - * The VM name of the class. - * - * @return VM name - */ - public String getName() { - return name; - } - - /** - * The number of instrumentation probes for this class. - * - * @return number of probes - */ - public int getProbeCount() { - return probeCount; - } - - /** - * Returns a copy of the probe data as a boolean array. - * - * Changes to the returned array will not be reflected in the execution data. - * - * @return copy of the probe data - */ - public boolean[] getProbesCopy() { - final int bytes = (probeCount + 7) / 8; - boolean[] probes = new boolean[probeCount]; - for (int index = 0; index < probeCount; index += 8) { - byte byteProbe = probeBuffer.get(index / 8); - for (int bit = 0; (bit < 8) && ((index + bit) < probeCount); bit++) { - probes[index + bit] = ((byteProbe & 0x1) > 0); - byteProbe >>>= 1; - } - } - return probes; - } - - /** - * Sets all probes to <code>false</code>. - */ - public void reset() { - final int bytes = (probeCount + 7) / 8; - synchronized (probeBuffer) { - for (int i = 0; i < bytes; i++) { - probeBuffer.put(i, (byte) 0); - } - } - } - - /** - * Checks whether any probe has been hit. - * - * @return <code>true</code>, if at least one probe has been hit - */ - public boolean hasHits() { - final int bytes = (probeCount + 7) / 8; - synchronized (probeBuffer) { - for (int i = 0; i < bytes; i++) { - if (probeBuffer.get(i) > 0) { - return true; - } - } - } - return false; - } - - /** - * Merges the given execution data into the probe data of this object. I.e. - * a probe entry in this object is marked as executed (<code>true</code>) if - * this probe or the corresponding other probe was executed. So the result - * is - * - * <pre> - * A or B - * </pre> - * - * The probe array of the other object is not modified. - * - * @param other - * execution data to merge - */ - public void merge(final IExecutionData other) { - merge(other, true); - } - - /** - * Merges the given execution data into the probe data of this object. A - * probe in this object is set to the value of <code>flag</code> if the - * corresponding other probe was executed. For <code>flag==true</code> this - * corresponds to - * - * <pre> - * A or B - * </pre> - * - * For <code>flag==false</code> this can be considered as a subtraction - * - * <pre> - * A and not B - * </pre> - * - * The probe array of the other object is not modified. - * - * @param other - * execution data to merge - * @param flag - * merge mode - */ - public void merge(final IExecutionData other, final boolean flag) { - synchronized (probeBuffer) { - for (int i = 0; i < probeCount; i++) { - if (other.getProbe(i)) { - setProbe(i); - } - } - } - } - - /** - * Asserts that this execution data object is compatible with the given - * parameters. The purpose of this check is to detect a very unlikely class - * id collision. - * - * @param id - * other class id, must be the same - * @param name - * other name, must be equal to this name - * @param probecount - * probe data length, must be the same as for this data - * @throws IllegalStateException - * if the given parameters do not match this instance - */ - public void assertCompatibility(final long id, final String name, final int probeCount) - throws IllegalStateException { - if (this.id != id) { - throw new IllegalStateException(format( - "Different ids (%016x and %016x).", Long.valueOf(this.id), - Long.valueOf(id))); - } - if (!this.name.equals(name)) { - throw new IllegalStateException(format( - "Different class names %s and %s for id %016x.", this.name, - name, Long.valueOf(id))); - } - if (this.probeCount != probeCount) { - throw new IllegalStateException(format( - "Incompatible execution data for class %s with id %016x.", - name, Long.valueOf(id))); - } - } - - /** - * Returns the execution data probe for a given index. A value of - * <code>true</code> indicates that the corresponding probe was - * executed. - * - * @param index the probe's index to look up - * - * @return probe data - */ - public boolean getProbe(final int index) { - int offset = index / 8; - int bit = 1 << (index % 8); - return (probeBuffer.get(offset) & bit) != 0; - } - - /** - * Sets the execution data probe at the given index to <code>true</code>. - * - * @param index the probe's index to set - */ - public void setProbe(final int index) { - int offset = index / 8; - int bit = 1 << (index % 8); - byte currentValue = probeBuffer.get(offset); - if ((currentValue & bit) == 0) { - synchronized (probeBuffer) { - probeBuffer.put(offset, (byte) (probeBuffer.get(offset) | bit)); - } - } - } -} -// END android-change |