Skip to content

Commit

Permalink
Move debug class dump logic from ClassInstrumentor to SandboxClassLoader
Browse files Browse the repository at this point in the history
This makes it easier to dump debug classes when using custom
ClassInstrumentors. It avoids having to duplicate the class dump logic.

PiperOrigin-RevId: 352033921
  • Loading branch information
hoisie committed Jan 21, 2021
1 parent ff49c49 commit e365416
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
package org.robolectric.internal.bytecode;

import com.google.common.base.Strings;
import java.io.IOException;
import java.lang.invoke.MethodType;
import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.atomic.AtomicInteger;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
Expand All @@ -35,17 +29,12 @@

public abstract class ClassInstrumentor {
private static final String ROBO_INIT_METHOD_NAME = "$$robo$init";
// The directory where instrumented class files will be dumped
private static final String DUMP_CLASSES_PROPERTY = "robolectric.dumpClassesDirectory";
private static final AtomicInteger DUMP_CLASSES_COUNTER = new AtomicInteger();
static final Type OBJECT_TYPE = Type.getType(Object.class);
private static final ShadowImpl SHADOW_IMPL = new ShadowImpl();
final Decorator decorator;
final String dumpClassesDirectory;

protected ClassInstrumentor(Decorator decorator) {
this.decorator = decorator;
this.dumpClassesDirectory = System.getProperty(DUMP_CLASSES_PROPERTY, "");
}

private MutableClass analyzeClass(
Expand Down Expand Up @@ -83,18 +72,7 @@ public String map(final String internalName) {
ClassRemapper visitor = new ClassRemapper(writer, remapper);
classNode.accept(visitor);

byte[] classBytes = writer.toByteArray();
if (!Strings.isNullOrEmpty(dumpClassesDirectory)) {
String outputClassName =
mutableClass.getName() + "-robo-instrumented-" + DUMP_CLASSES_COUNTER.getAndIncrement();
Path path = Paths.get(dumpClassesDirectory, outputClassName + ".class");
try {
Files.write(path, classBytes);
} catch (IOException e) {
throw new AssertionError(e);
}
}
return classBytes;
return writer.toByteArray();
}

public byte[] instrument(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;

import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject;
import org.robolectric.util.Logger;
import org.robolectric.util.PerfStatsCollector;
Expand All @@ -21,10 +26,15 @@
* shadow classes.
*/
public class SandboxClassLoader extends URLClassLoader {
// The directory where instrumented class files will be dumped
private static final String DUMP_CLASSES_PROPERTY = "robolectric.dumpClassesDirectory";
private static final AtomicInteger DUMP_CLASSES_COUNTER = new AtomicInteger();

private final InstrumentationConfiguration config;
private final ResourceProvider resourceProvider;
private final ClassInstrumentor classInstrumentor;
private final ClassNodeProvider classNodeProvider;
private final String dumpClassesDirectory;

/** Constructor for use by tests. */
SandboxClassLoader(InstrumentationConfiguration config) {
Expand Down Expand Up @@ -55,6 +65,7 @@ protected byte[] getClassBytes(String internalClassName) throws ClassNotFoundExc
return getByteCode(internalClassName);
}
};
this.dumpClassesDirectory = System.getProperty(DUMP_CLASSES_PROPERTY, "");
}

private static URL[] getClassPathUrls(ClassLoader classloader) {
Expand Down Expand Up @@ -133,6 +144,7 @@ protected Class<?> maybeInstrumentClass(String className) throws ClassNotFoundEx
ClassDetails classDetails = new ClassDetails(origClassBytes);
if (config.shouldInstrument(classDetails)) {
bytes = classInstrumentor.instrument(origClassBytes, config, classNodeProvider);
maybeDumpClassBytes(classDetails, bytes);
} else {
bytes = postProcessUninstrumentedClass(classDetails, origClassBytes);
}
Expand All @@ -146,6 +158,19 @@ protected Class<?> maybeInstrumentClass(String className) throws ClassNotFoundEx
}
}

private void maybeDumpClassBytes(ClassDetails classDetails, byte[] classBytes) {
if (!Strings.isNullOrEmpty(dumpClassesDirectory)) {
String outputClassName =
classDetails.getName() + "-robo-instrumented-" + DUMP_CLASSES_COUNTER.getAndIncrement();
Path path = Paths.get(dumpClassesDirectory, outputClassName + ".class");
try {
Files.write(path, classBytes);
} catch (IOException e) {
throw new AssertionError(e);
}
}
}

protected byte[] postProcessUninstrumentedClass(
ClassDetails classDetails, byte[] origClassBytes) {
return origClassBytes;
Expand Down

0 comments on commit e365416

Please sign in to comment.