Skip to content

Commit

Permalink
feat(objectionary#528): suggest ugly solution
Browse files Browse the repository at this point in the history
  • Loading branch information
volodya-lombrozo committed Apr 3, 2024
1 parent c352335 commit 4dd3098
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public final class BytecodeClass implements Testable {
* Class writer.
*/
@ToString.Exclude
private final CustomClassWriter visitor;
private final CustomClassVisitor visitor;

/**
* Methods.
Expand Down Expand Up @@ -116,15 +116,6 @@ public BytecodeClass(final String name, final BytecodeClassProperties properties
this(name, properties, true);
}

public BytecodeClass(
final String name,
final BytecodeClassProperties properties,
final boolean verify,
final boolean frames
) {
this(name, BytecodeClass.writer(verify, frames), new ArrayList<>(0), properties);
}

/**
* Constructor.
* Has real usages.
Expand All @@ -137,7 +128,16 @@ public BytecodeClass(
final BytecodeClassProperties properties,
final boolean verify
) {
this(name, BytecodeClass.writer(verify, true), new ArrayList<>(0), properties);
this(name, BytecodeClass.writer(verify, false), new ArrayList<>(0), properties);
}

public BytecodeClass(
final String name,
final BytecodeClassProperties properties,
final boolean verify,
final boolean frames
) {
this(name, BytecodeClass.writer(verify, frames), new ArrayList<>(0), properties);
}

/**
Expand All @@ -151,7 +151,7 @@ public BytecodeClass(
*/
public BytecodeClass(
final String name,
final CustomClassWriter writer,
final CustomClassVisitor writer,
final Collection<BytecodeMethod> methods,
final BytecodeClassProperties properties
) {
Expand Down Expand Up @@ -192,7 +192,7 @@ public Bytecode bytecode() {
this.fields.forEach(field -> field.write(this.visitor));
this.methods.forEach(BytecodeMethod::write);
this.visitor.visitEnd();
return new Bytecode(this.visitor.toByteArray());
return this.visitor.bytecode();
} catch (final IllegalArgumentException exception) {
throw new IllegalArgumentException(
String.format("Can't create bytecode for the class '%s' ", this.name),
Expand Down Expand Up @@ -389,7 +389,7 @@ public BytecodeClass helloWorldMethod() {
* @param verify Verify bytecode.
* @return Verified class writer if verify is true, otherwise custom class writer.
*/
private static CustomClassWriter writer(final boolean verify, final boolean frames) {
private static CustomClassVisitor writer(final boolean verify, final boolean frames) {
final CustomClassWriter result;
final int flags;
if (frames) {
Expand All @@ -402,6 +402,6 @@ private static CustomClassWriter writer(final boolean verify, final boolean fram
} else {
result = new CustomClassWriter(flags);
}
return result;
return new CustomClassVisitor(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.ArrayList;
import java.util.List;
import org.eolang.jeo.representation.xmir.AllLabels;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;

Expand All @@ -39,7 +38,7 @@ public final class BytecodeMethod implements Testable {
/**
* ASM class visitor.
*/
private final ClassVisitor visitor;
private final CustomClassVisitor visitor;

/**
* Original class.
Expand Down Expand Up @@ -92,7 +91,7 @@ public final class BytecodeMethod implements Testable {
*/
BytecodeMethod(
final String name,
final ClassVisitor visitor,
final CustomClassVisitor visitor,
final BytecodeClass clazz,
final String descriptor,
final int... modifiers
Expand All @@ -108,7 +107,7 @@ public final class BytecodeMethod implements Testable {
*/
BytecodeMethod(
final BytecodeMethodProperties properties,
final ClassVisitor visitor,
final CustomClassVisitor visitor,
final BytecodeClass clazz
) {
this(properties, visitor, clazz, 0, 0);
Expand All @@ -125,7 +124,7 @@ public final class BytecodeMethod implements Testable {
*/
public BytecodeMethod(
final BytecodeMethodProperties properties,
final ClassVisitor visitor,
final CustomClassVisitor visitor,
final BytecodeClass clazz,
final int stack,
final int locals
Expand Down Expand Up @@ -243,16 +242,30 @@ public String testCode() {
@SuppressWarnings("PMD.AvoidCatchingGenericException")
void write() {
try {
final MethodVisitor mvisitor = this.properties.writeMethod(this.visitor);
this.annotations.forEach(annotation -> annotation.write(mvisitor));
this.defvalues.forEach(defvalue -> defvalue.writeTo(mvisitor));
if (!this.properties.isAbstract()) {
mvisitor.visitCode();
this.tryblocks.forEach(block -> block.writeTo(mvisitor));
this.instructions.forEach(instruction -> instruction.writeTo(mvisitor));
mvisitor.visitMaxs(this.stack, this.locals);
if (this.stack == 0 && this.locals == 0) {
final MethodVisitor mvisitor = this.properties.writeCustomMethodWithComputation(
this.visitor);
this.annotations.forEach(annotation -> annotation.write(mvisitor));
this.defvalues.forEach(defvalue -> defvalue.writeTo(mvisitor));
if (!this.properties.isAbstract()) {
mvisitor.visitCode();
this.tryblocks.forEach(block -> block.writeTo(mvisitor));
this.instructions.forEach(instruction -> instruction.writeTo(mvisitor));
mvisitor.visitMaxs(this.stack, this.locals);
}
mvisitor.visitEnd();
} else {
final MethodVisitor mvisitor = this.properties.writeMethod(this.visitor);
this.annotations.forEach(annotation -> annotation.write(mvisitor));
this.defvalues.forEach(defvalue -> defvalue.writeTo(mvisitor));
if (!this.properties.isAbstract()) {
mvisitor.visitCode();
this.tryblocks.forEach(block -> block.writeTo(mvisitor));
this.instructions.forEach(instruction -> instruction.writeTo(mvisitor));
mvisitor.visitMaxs(this.stack, this.locals);
}
mvisitor.visitEnd();
}
mvisitor.visitEnd();
} catch (final NegativeArraySizeException exception) {
throw new IllegalStateException(
String.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.eolang.jeo.representation.JavaName;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

Expand Down Expand Up @@ -133,12 +132,32 @@ public boolean isAbstract() {
return (this.access & Opcodes.ACC_ABSTRACT) != 0;
}


/**
* Add method to class writer.
* @param writer Class writer.
* @return Method visitor.
*/
MethodVisitor writeCustomMethodWithComputation(final CustomClassVisitor writer) {
Logger.debug(
this,
String.format("Creating method visitor with the following properties %s", this)
);
return writer.visitCustomMethodWithComputation(
this.access,
new JavaName(this.name).decode(),
this.descriptor,
this.signature,
this.exceptions
);
}

/**
* Add method to class writer.
* @param writer Class writer.
* @return Method visitor.
*/
MethodVisitor writeMethod(final ClassVisitor writer) {
MethodVisitor writeMethod(final CustomClassVisitor writer) {
Logger.debug(
this,
String.format("Creating method visitor with the following properties %s", this)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.eolang.jeo.representation.bytecode;

import java.lang.reflect.Field;
import org.eolang.jeo.representation.DefaultVersion;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.ClassNode;

public final class CustomClassVisitor extends ClassVisitor {

private final CustomClassWriter writer;


public CustomClassVisitor(final int api) {
this(api, new CustomClassWriter());
}

public CustomClassVisitor(final CustomClassWriter writer) {
this(new DefaultVersion().api(), writer);
}

public CustomClassVisitor(final int api, final CustomClassWriter writer) {
super(api, writer);
this.writer = writer;
}

public MethodVisitor visitCustomMethodWithComputation(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions
) {

try {
final Field field = ClassWriter.class.getDeclaredField("compute");
field.setAccessible(true);
field.setInt(this.writer, 4);
final MethodVisitor original = this.visitMethod(
access, name, descriptor, signature, exceptions
);
field.setInt(this.writer, 0);
return original;
} catch (final NoSuchFieldException | IllegalAccessException exception) {
throw new RuntimeException(exception);
}
}

public Bytecode bytecode() {
return new Bytecode(this.writer.toByteArray());
}
}

0 comments on commit 4dd3098

Please sign in to comment.