use of org.objectweb.asm.ClassWriter in project saral by PaulNoth.
the class ByteCodeGenerator method generateByteCode.
public byte[] generateByteCode(Init compilationUnit) {
String name = compilationUnit.getScope().getClassName();
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES + ClassWriter.COMPUTE_MAXS);
cw.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, name, null, "java/lang/Object", null);
InitGenerator initGenerator = new InitGenerator(cw);
return initGenerator.generate(compilationUnit).toByteArray();
}
use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.
the class FilterGenerator method generateClass.
byte[] generateClass(String name, Method method) {
name = name.replace('.', '/');
final Parameter[] params = method.getParameters();
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, name, null, "java/lang/Object", new String[] { Type.getInternalName(EventFilter.class) });
SubtypeFilterDelegate sfilter = null;
final List<FilterDelegate> additional = new ArrayList<>();
boolean cancellation = false;
for (Annotation anno : method.getAnnotations()) {
Object obj = filterFromAnnotation(anno.annotationType());
if (obj == null) {
continue;
}
if (obj instanceof SubtypeFilter) {
if (sfilter != null) {
throw new IllegalStateException("Cannot have both @Include and @Exclude annotations present at once");
}
sfilter = ((SubtypeFilter) obj).getDelegate(anno);
} else if (obj instanceof EventTypeFilter) {
final EventTypeFilter etf = (EventTypeFilter) obj;
additional.add(etf.getDelegate(anno));
if (etf == EventTypeFilter.CANCELLATION) {
cancellation = true;
}
}
}
if (!cancellation && Cancellable.class.isAssignableFrom(method.getParameterTypes()[0])) {
additional.add(new CancellationEventFilterDelegate(Tristate.FALSE));
}
if (sfilter != null) {
sfilter.createFields(cw);
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
if (sfilter != null) {
sfilter.writeCtor(name, cw, mv);
}
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "filter", "(" + Type.getDescriptor(Event.class) + ")[Ljava/lang/Object;", null, null);
mv.visitCode();
// index of the next available local variable
int local = 2;
if (sfilter != null) {
local = sfilter.write(name, cw, mv, method, local);
}
for (FilterDelegate eventFilter : additional) {
local = eventFilter.write(name, cw, mv, method, local);
}
// local var indices of the parameters values
final int[] plocals = new int[params.length - 1];
for (int i = 1; i < params.length; i++) {
final Parameter param = params[i];
ParameterFilterSourceDelegate source = null;
final List<ParameterFilterDelegate> paramFilters = new ArrayList<>();
for (Annotation anno : param.getAnnotations()) {
Object obj = filterFromAnnotation(anno.annotationType());
if (obj == null) {
continue;
}
if (obj instanceof ParameterSource) {
if (source != null) {
throw new IllegalStateException("Cannot have multiple parameter filter source annotations (for " + param.getName() + ")");
}
source = ((ParameterSource) obj).getDelegate(anno);
} else if (obj instanceof ParameterFilter) {
paramFilters.add(((ParameterFilter) obj).getDelegate(anno));
}
}
if (source == null) {
throw new IllegalStateException("Cannot have additional parameters filters without a source (for " + param.getName() + ")");
}
if (source instanceof AllCauseFilterSourceDelegate && !paramFilters.isEmpty()) {
// TODO until better handling for filtering arrays is added
throw new IllegalStateException("Cannot have additional parameters filters without an array source (for " + param.getName() + ")");
}
final Tuple<Integer, Integer> localState = source.write(cw, mv, method, param, local);
local = localState.getFirst();
plocals[i - 1] = localState.getSecond();
for (ParameterFilterDelegate paramFilter : paramFilters) {
paramFilter.write(cw, mv, method, param, plocals[i - 1]);
}
}
// create the return array
if (params.length == 1) {
mv.visitInsn(ICONST_1);
} else {
mv.visitIntInsn(BIPUSH, params.length);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
// load the event into the array
mv.visitInsn(DUP);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(AASTORE);
// load all the params into the array
for (int i = 1; i < params.length; i++) {
mv.visitInsn(DUP);
mv.visitIntInsn(BIPUSH, i);
Type paramType = Type.getType(params[i].getType());
mv.visitVarInsn(paramType.getOpcode(ILOAD), plocals[i - 1]);
GeneratorUtils.visitBoxingMethod(mv, paramType);
mv.visitInsn(AASTORE);
}
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
final byte[] data = cw.toByteArray();
if (FILTER_DEBUG) {
final Path outDir = Paths.get(".sponge.debug.out");
final Path outFile = outDir.resolve(name + ".class");
if (!Files.exists(outFile.getParent())) {
try {
Files.createDirectories(outFile.getParent());
} catch (IOException e) {
Lantern.getLogger().warn("Unable to create the filter debug directory.", e);
}
}
try (final OutputStream out = Files.newOutputStream(outFile)) {
out.write(data);
} catch (IOException e) {
Lantern.getLogger().warn("Unable to create the filter debug class.", e);
}
}
return data;
}
use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.
the class ClassEventListenerFactory method generateClass.
private static byte[] generateClass(String name, Class<?> handle, Method method, Class<?> eventClass, Class<? extends EventFilter> filter) {
name = name.replace('.', '/');
final String handleName = Type.getInternalName(handle);
final String handleDescriptor = Type.getDescriptor(handle);
final String filterName = Type.getInternalName(filter);
String eventDescriptor = "(";
for (int i = 0; i < method.getParameterCount(); i++) {
eventDescriptor += Type.getDescriptor(method.getParameterTypes()[i]);
}
eventDescriptor += ")V";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
FieldVisitor fv;
cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, name, null, BASE_HANDLER, null);
{
fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, "FILTER", "L" + filterName + ";", null, null);
fv.visitEnd();
}
{
mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, filterName);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, filterName, "<init>", "()V", false);
mv.visitFieldInsn(PUTSTATIC, name, "FILTER", "L" + filterName + ";");
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", '(' + handleDescriptor + ")V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, BASE_HANDLER, "<init>", "(Ljava/lang/Object;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "handle", HANDLE_METHOD_DESCRIPTOR, null, new String[] { "java/lang/Exception" });
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, name, "FILTER", "L" + filterName + ";");
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(EventFilter.class), "filter", FILTER_DESCRIPTOR, true);
mv.visitVarInsn(ASTORE, 2);
mv.visitVarInsn(ALOAD, 2);
Label l2 = new Label();
mv.visitJumpInsn(IFNULL, l2);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, name, "handle", "Ljava/lang/Object;");
mv.visitTypeInsn(CHECKCAST, handleName);
for (int i = 0; i < method.getParameterCount(); i++) {
mv.visitVarInsn(ALOAD, 2);
mv.visitIntInsn(BIPUSH, i);
mv.visitInsn(AALOAD);
Type paramType = Type.getType(method.getParameterTypes()[i]);
GeneratorUtils.visitUnboxingMethod(mv, paramType);
}
mv.visitMethodInsn(INVOKEVIRTUAL, handleName, method.getName(), eventDescriptor, false);
mv.visitLabel(l2);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.
the class InventoryConstructorFactory method generateCarriedClass.
/**
* Gets the generated class for the target class that
* also implements {@link CarriedInventory}.
*
* @param inventoryType The inventory type
* @return The carried inventory type
*/
private Class<? extends AbstractInventory> generateCarriedClass(Class<? extends AbstractInventory> inventoryType) {
final String name = inventoryType.getName() + "$$Carried";
final String className = name.replace('.', '/');
// Generate the class bytecode and load it
final ClassWriter cw = new ClassWriter(0);
final String superName = Type.getInternalName(inventoryType);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className, String.format("L%s;L%s<L%s;>;", superName, CARRIED_INVENTORY_NAME, CARRIER_NAME), superName, new String[] { CARRIED_INVENTORY_NAME });
final FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC, String.format("L%s<L%s;>;", CARRIER_REFERENCE_NAME, CARRIER_NAME), null);
fv.visitEnd();
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitLdcInsn(Type.getType(CARRIER_DESC));
mv.visitMethodInsn(INVOKESTATIC, CARRIER_REFERENCE_NAME, "of", String.format("(Ljava/lang/Class;)L%s;", CARRIER_REFERENCE_NAME), true);
mv.visitFieldInsn(PUTFIELD, className, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
mv = cw.visitMethod(ACC_PROTECTED, "setCarrier", String.format("(L%s;)V", CARRIER_NAME), null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, superName, "setCarrier", String.format("(L%s;)V", CARRIER_NAME), false);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEINTERFACE, CARRIER_REFERENCE_NAME, "set", String.format("(L%s;)V", CARRIER_NAME), true);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
mv = cw.visitMethod(ACC_PUBLIC, "getCarrier", "()Ljava/util/Optional;", String.format("()Ljava/util/Optional<L%s;>;", CARRIER_NAME), null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, CARRIER_REF_FIELD, CARRIER_REFERENCE_DESC);
mv.visitMethodInsn(INVOKEINTERFACE, CARRIER_REFERENCE_NAME, "get", "()Ljava/util/Optional;", true);
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
cw.visitEnd();
return this.classLoader.defineClass(name, cw.toByteArray());
}
use of org.objectweb.asm.ClassWriter in project LanternServer by LanternPowered.
the class FieldAccessFactory method createSetter.
/**
* Creates a setter {@link BiConsumer} for the given {@link Field}.
*
* @param field The field
* @param <T> The target object type
* @param <V> The field value type
* @return The bi consumer
*/
public static <T, V> BiConsumer<T, V> createSetter(Field field) {
checkNotNull(field, "field");
field.setAccessible(true);
boolean isFinal = Modifier.isFinal(field.getModifiers());
// Better check is somebody changed the final modifier already
if (!isFinal) {
final Field[] fields = field.getDeclaringClass().getDeclaredFields();
boolean isFound = false;
for (Field field1 : fields) {
// The same signature, now check if somebody tinkered with the field
if (field.getName().equals(field1.getName()) && field.getType().equals(field1.getType())) {
isFinal = Modifier.isFinal(field1.getModifiers());
isFound = true;
break;
}
}
if (!isFound) {
throw new IllegalStateException("Something funky happened with: " + field.getName());
}
} else {
try {
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
// Final fields don't allow direct access, so MethodHandles will do the trick.
if (isFinal) {
try {
final MethodHandle methodHandle = MethodHandleMagic.trustedLookup().in(field.getDeclaringClass()).unreflectSetter(field).asType(setterMethodType);
return (a, b) -> {
try {
methodHandle.invokeExact(a, b);
} catch (Throwable throwable) {
throw new IllegalStateException(throwable);
}
};
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
final ClassWriter cw = new ClassWriter(0);
final String className = field.getName().replace('.', '/') + "$$LanternSetter$" + setterCounter.incrementAndGet();
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className, "Ljava/lang/Object;Ljava/util/function/BiConsumer<Ljava/lang/Object;Ljava/lang/Object;>;", "java/lang/Object", new String[] { "java/util/function/BiConsumer" });
// Add a empty constructor
BytecodeUtils.visitEmptyConstructor(cw);
// Generate the apply method
final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null);
mv.visitCode();
final String descriptor = Type.getDescriptor(field.getType());
final String targetName = Type.getInternalName(field.getDeclaringClass());
final boolean isStatic = Modifier.isStatic(field.getModifiers());
if (!isStatic) {
// Load the target parameter
mv.visitVarInsn(ALOAD, 1);
// Cast it
mv.visitTypeInsn(CHECKCAST, targetName);
}
// Load the value parameter
mv.visitVarInsn(ALOAD, 2);
// Unbox the values in case they are primitives, otherwise cast
GeneratorUtils.visitUnboxingMethod(mv, Type.getType(field.getType()));
// Put the value into the field
if (isStatic) {
mv.visitFieldInsn(PUTSTATIC, targetName, field.getName(), descriptor);
} else {
mv.visitFieldInsn(PUTFIELD, targetName, field.getName(), descriptor);
}
// Return
mv.visitInsn(RETURN);
mv.visitMaxs(2, 3);
mv.visitEnd();
// Finish class generation
cw.visitEnd();
// Define the class and create a function instance
final MethodHandles.Lookup lookup = MethodHandleMagic.trustedLookup().in(field.getDeclaringClass());
final Class<?> functionClass = MethodHandleMagic.defineNestmateClass(lookup, cw.toByteArray());
try {
return (BiConsumer<T, V>) functionClass.newInstance();
} catch (Exception e) {
throw new IllegalStateException("Something went wrong!", e);
}
}
Aggregations