Skip to content

Commit

Permalink
Implement bytecode weaver
Browse files Browse the repository at this point in the history
  • Loading branch information
Anton Gustafsson committed Jul 12, 2016
1 parent 1e97683 commit 20c0a77
Show file tree
Hide file tree
Showing 49 changed files with 2,357 additions and 137 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
## Changelog

# Version 0.3.1-SNAPSHOT
- Implemented experimental bytecode weaving
- Classes can be weaved at compile-time using the command-line interface,
or at runtime using a custom `ClassLoader` implementation.
- The weaver packs components into arrays, which improves cache locality;
this currently yields a 15% performance boost, but will hopefully improve
as more optimizations are introduced.
- `PackedMapper` that allows access to the backing arrays for fast access
- `Property` classes that represent properties of packed components
- Added `clear(Mask)` implementation to all `Bag` implementations
- Removed `Mapper.add(int, Component)`, `create` should be used instead

# Version 0.3.0 (released 2016-07-04)
- `ensureCapacity(int)` for all `Bag` implementations
Expand Down
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@

<modules>
<module>retinazer</module>
<module>retinazer-weaver</module>
<module>retinazer-weaver-cli</module>
</modules>

<profiles>
Expand Down
67 changes: 67 additions & 0 deletions retinazer-weaver-cli/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.github.antag99.retinazer</groupId>
<artifactId>retinazer-parent</artifactId>
<version>0.3.1-SNAPSHOT</version>
</parent>

<artifactId>retinazer-weaver-cli</artifactId>
<packaging>jar</packaging>
<name>retinazer-weaver-cli</name>

<properties>
<mainClass>com.github.antag99.retinazer.weaver.WeaverMain</mainClass>
<jcommander.version>1.48</jcommander.version>
<maven.javadoc.skip>true</maven.javadoc.skip>
</properties>

<dependencies>
<dependency>
<groupId>com.github.antag99.retinazer</groupId>
<artifactId>retinazer-weaver</artifactId>
<version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>${jcommander.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${mainClass}</mainClass>
</transformer>
</transformers>
<relocations>
<relocation>
<pattern>org.objectweb.asm</pattern>
<shadedPattern>com.github.antag99.retinazer.weaver.asm</shadedPattern>
</relocation>
<relocation>
<pattern>com.beust.jcommander</pattern>
<shadedPattern>com.github.antag99.retinazer.weaver.jcommander</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*******************************************************************************
* Copyright (C) 2015 Anton Gustafsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
package com.github.antag99.retinazer.weaver;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.regex.Pattern;

import com.beust.jcommander.JCommander;
import com.github.antag99.retinazer.weaver.Weaver.WeaverHandler;

final class WeaverMain {
public static void main(final String[] args) {
final WeaverParameters parameters = new WeaverParameters();
final JCommander commander = new JCommander(parameters, args);
if (parameters.help) {
commander.usage("java -jar retinazer-weaver.jar");
return;
}
if (parameters.classesDirectory == null) {
System.err.println("Please specify class directory");
return;
}

if (parameters.outputDirectory == null)
parameters.outputDirectory = parameters.classesDirectory;

if (!parameters.classesDirectory.exists()) {
System.err.println("Class directory does not exist: " + parameters.classesDirectory.getPath());
return;
}
if (!parameters.classesDirectory.isDirectory()) {
System.err.println("Class directory is not a directory: " + parameters.classesDirectory.getPath());
return;
}
if (!parameters.outputDirectory.exists()) {
if (!parameters.outputDirectory.mkdirs()) {
System.err.println("Failed to create output directory: " + parameters.outputDirectory.getPath());
return;
}
}
if (!parameters.outputDirectory.isDirectory()) {
System.err.println("Output directory is not a directory: " + parameters.outputDirectory.getPath());
return;
}
final Pattern pattern = parameters.filterPattern == null ? null : Pattern.compile(parameters.filterPattern);
final Weaver weaver = new Weaver(new WeaverHandler() {
final File inputDirectory = parameters.classesDirectory;
final File outputDirectory = parameters.outputDirectory;

@Override
public byte[] findClass(String internalName) {
File inputFile = new File(inputDirectory, internalName + ".class");
if (!inputFile.exists())
return null;
try {
return Files.readAllBytes(inputFile.toPath());
} catch (IOException ex) {
throw new WeaverException("Failed to access class " + internalName, ex);
}
}

@Override
public void saveClass(String internalName, byte[] classFile) {
File outputFile = new File(outputDirectory, internalName + ".class");
outputFile.getParentFile().mkdirs();
try {
Files.write(outputFile.toPath(), classFile);
} catch (IOException ex) {
throw new WeaverException("Failed to write class " + internalName, ex);
}
}
});
process(weaver, pattern, parameters.classesDirectory, parameters.classesDirectory);
}

private static void process(Weaver weaver, Pattern pattern, File inputDirectory, File file) {
if (file.isDirectory()) {
for (File child : file.listFiles()) {
process(weaver, pattern, inputDirectory, child);
}
} else {
if (file.getName().endsWith(".class")) {
String filePath = file.getAbsolutePath();
String inputDirectoryPath = inputDirectory.getAbsolutePath();
String relativePath = filePath.substring(inputDirectoryPath.length() + 1);
String internalName = relativePath.substring(0, relativePath.length() - ".class".length());
if (pattern == null || pattern.matcher(internalName).matches()) {
weaver.process(internalName);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (C) 2015 Anton Gustafsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
package com.github.antag99.retinazer.weaver;

import java.io.File;

import com.beust.jcommander.Parameter;

final class WeaverParameters {

@Parameter(names = { "--help", "-h" }, description = "Display this help message and exit")
public boolean help = false;

@Parameter(names = { "--classesDirectory", "-i" }, description = "Classes directory")
public File classesDirectory = null;

@Parameter(names = { "--outputDirectory", "-o" }, description = "Output directory", required = false)
public File outputDirectory = null;

@Parameter(names = { "--filter", "-f" }, description = "Pattern for internal names of classes to be included")
public String filterPattern = null;
}
47 changes: 47 additions & 0 deletions retinazer-weaver/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.github.antag99.retinazer</groupId>
<artifactId>retinazer-parent</artifactId>
<version>0.3.1-SNAPSHOT</version>
</parent>

<artifactId>retinazer-weaver</artifactId>
<packaging>jar</packaging>
<name>retinazer-weaver</name>

<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-debug-all</artifactId>
<version>5.1</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.objectweb.asm</pattern>
<shadedPattern>com.github.antag99.retinazer.weaver.asm</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*******************************************************************************
* Copyright (C) 2015 Anton Gustafsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
package com.github.antag99.retinazer.weaver;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

final class AccessProcessor extends ChainVisitor implements Opcodes {
private Weaver weaver;

public AccessProcessor(Weaver weaver) {
super(ASM5);

this.weaver = weaver;
}

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new MethodVisitor(ASM5, super.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == GETFIELD || opcode == PUTFIELD) {
Type fieldOwner = Type.getObjectType(owner);
if (fieldOwner.getSort() == Type.OBJECT) {
WeaverMetadata metadata = weaver.getMetadata(fieldOwner.getInternalName());
if (metadata.componentMetadata != null) { // Is it a component?
ComponentProperty property = metadata.componentMetadata.propertiesByName.get(name);
if (property != null) { // Ensure the field is not generated by the weaver
if (opcode == GETFIELD)
super.visitMethodInsn(INVOKEVIRTUAL, owner, property.getGetterName(), property.getGetterDesc(), false);
else
super.visitMethodInsn(INVOKEVIRTUAL, owner, property.getSetterName(), property.getSetterDesc(), false);
return; // Don't attempt to access the fields of packed components
}
}
}
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (C) 2015 Anton Gustafsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
package com.github.antag99.retinazer.weaver;

import org.objectweb.asm.ClassVisitor;

interface ChainSource {

void accept(ClassVisitor visitor);
}

0 comments on commit 20c0a77

Please sign in to comment.