com.artemis.Weaver Maven / Gradle / Ivy
package com.artemis;
import static com.artemis.meta.ClassMetadataUtil.packedFieldAccess;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import com.artemis.meta.ClassMetadata;
import com.artemis.meta.ClassMetadata.GlobalConfiguration;
import com.artemis.meta.ClassMetadata.OptimizationType;
import com.artemis.meta.ClassMetadata.WeaverType;
import com.artemis.meta.FieldDescriptor;
import com.artemis.meta.MetaScanner;
import com.artemis.weaver.ComponentAccessTransmuter;
import com.artemis.weaver.ComponentTypeTransmuter;
import com.artemis.weaver.EsOptimizationTransmuter;
import com.artemis.weaver.ProfilerTransmuter;
public class Weaver {
public static final String PACKED_ANNOTATION = "Lcom/artemis/annotations/PackedWeaver;";
public static final String PROFILER_ANNOTATION = "Lcom/artemis/annotations/Profile;";
public static final String POOLED_ANNOTATION = "Lcom/artemis/annotations/PooledWeaver;";
public static final String WOVEN_ANNOTATION = "Lcom/artemis/annotations/internal/Transmuted";
public static final String PRESERVE_VISIBILITY_ANNOTATION = "Lcom/artemis/annotations/PreserveProcessVisiblity;";
private final File targetClasses;
public Weaver(File outputDirectory) {
this.targetClasses = outputDirectory;
}
public WeaverLog execute() {
WeaverLog log = new WeaverLog();
List classes = ClassUtil.find(targetClasses);
rewriteComponents(classes, log);
rewriteFieldAccess(classes, packedFieldAccess(log.components), log);
rewriteProfilers(classes);
if (ClassMetadata.GlobalConfiguration.optimizeEntitySystems)
rewriteEntitySystems(classes, log);
sort(log);
return log;
}
private static void sort(WeaverLog log) {
Comparator comparator = new Comparator() {
@Override
public int compare(ClassMetadata o1, ClassMetadata o2) {
return o1.type.toString().compareTo(o2.type.toString());
}
};
Collections.sort(log.components, comparator);
Collections.sort(log.componentSystems, comparator);
Collections.sort(log.systems, comparator);
}
public static List rewriteEntitySystems(List classes, WeaverLog log) {
Timer timer = new Timer();
List processed = new ArrayList();
ExecutorService threadPool = newThreadPool();
for (File f : classes) {
ClassMetadata meta = scan(classReaderFor(f.toString()));
if (meta.sysetemOptimizable != OptimizationType.NOT_OPTIMIZABLE) {
processed.add(meta);
optimizeEntitySystem(threadPool, f.getAbsolutePath());
}
}
awaitTermination(threadPool);
log.timeSystems = timer.duration();
log.systems = processed;
return processed;
}
private static void rewriteProfilers(List classes) {
ExecutorService threadPool = newThreadPool();
for (File f : classes)
processProfilers(threadPool, f.getAbsolutePath());
awaitTermination(threadPool);
}
private static void rewriteComponents(List classes, WeaverLog log) {
Timer timer = new Timer();
ExecutorService threadPool = newThreadPool();
List processed = new ArrayList();
for (File f : classes)
processClass(threadPool, f.getAbsolutePath(), processed);
awaitTermination(threadPool);
log.components = processed;
log.timeComponents = timer.duration();
}
// TODO: collect rewritten systems
private static void rewriteFieldAccess(List classes, List packed, WeaverLog log) {
if (packed.isEmpty())
return;
Timer timer = new Timer();
ExecutorService threadPool = newThreadPool();
List> tasks = new ArrayList>();
for (File file : classes) {
String path = file.getAbsolutePath();
ClassReader cr = classReaderFor(path);
ComponentAccessTransmuter transmuter = new ComponentAccessTransmuter(path, cr, packed);
tasks.add(threadPool.submit(transmuter));
}
try {
List processed = new ArrayList();
for (Future result : tasks) {
ClassMetadata metadata = result.get();
if (metadata != null)
processed.add(metadata);
}
awaitTermination(threadPool);
log.timeComponentSystems = timer.duration();
log.componentSystems = processed;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public static void retainFieldsWhenPacking(boolean ideFriendlyPacking) {
ClassMetadata.GlobalConfiguration.ideFriendlyPacking = ideFriendlyPacking;
}
public static void enablePooledWeaving(boolean enablePooledWeaving) {
ClassMetadata.GlobalConfiguration.enabledPooledWeaving = enablePooledWeaving;
}
public static void enablePackedWeaving(boolean enablePackedWeaving) {
ClassMetadata.GlobalConfiguration.enabledPackedWeaving = enablePackedWeaving;
}
public static void optimizeEntitySystems(boolean enabled) {
ClassMetadata.GlobalConfiguration.optimizeEntitySystems = enabled;
}
private static ExecutorService newThreadPool() {
return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
}
private static void processClass(ExecutorService threadPool, String file, List processed) {
ClassReader cr = classReaderFor(file);
ClassMetadata meta = scan(cr);
if (meta.annotation == WeaverType.NONE)
return;
if (meta.annotation == WeaverType.POOLED && !GlobalConfiguration.enabledPooledWeaving) {
if (!meta.forcePooledWeaving) return;
}
if (meta.annotation == WeaverType.PACKED && !GlobalConfiguration.enabledPackedWeaving)
return;
meta.weaverTask = threadPool.submit(new ComponentTypeTransmuter(file, cr, meta));
processed.add(meta);
}
private static void optimizeEntitySystem(ExecutorService threadPool, String file) {
ClassReader cr = classReaderFor(file);
ClassMetadata meta = scan(cr);
if (meta.sysetemOptimizable != OptimizationType.NOT_OPTIMIZABLE)
threadPool.submit(new EsOptimizationTransmuter(file, cr, meta));
}
private static void processProfilers(ExecutorService threadPool, String file) {
ClassReader cr = classReaderFor(file);
ClassMetadata meta = scan(cr);
if (meta.profilingEnabled)
threadPool.submit(new ProfilerTransmuter(file, meta, cr));
}
static ClassReader classReaderFor(InputStream file) {
try {
return new ClassReader(file);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
static ClassReader classReaderFor(String file) {
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
return classReaderFor(stream);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (stream != null) try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static ClassMetadata scan(ClassReader source) {
ClassMetadata info = new ClassMetadata();
source.accept(new MetaScanner(info), 0);
info.type = Type.getObjectType(source.getClassName());
for (FieldDescriptor fd : info.fields) {
if ((fd.access & ACC_PUBLIC) == ACC_PUBLIC) {
info.directFieldAccess = true;
}
}
return info;
}
private static void awaitTermination(ExecutorService threadPool) {
threadPool.shutdown();
try {
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static class Timer {
private long start = System.nanoTime();
public int duration() {
return (int)((System.nanoTime() - start) / 1000000);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy