use of dyvilx.tools.compiler.backend.MethodWriterImpl in project Dyvil by Dyvil.
the class CodeClass method write.
@Override
public void write(ClassWriter writer) throws BytecodeException {
// Header
String signature = this.getSignature();
String superClass = null;
String[] interfaces = this.getInterfaceArray();
if (this.superType != null) {
superClass = this.superType.getInternalName();
}
final long flags = ModifierUtil.getFlags(this);
int modifiers = ModifierUtil.getJavaModifiers(flags);
if ((modifiers & Modifiers.INTERFACE) == 0) {
modifiers |= ASMConstants.ACC_SUPER;
}
writer.visit(ClassFormat.CLASS_VERSION, modifiers, this.getInternalName(), signature, superClass, interfaces);
// Source
writer.visitSource(this.getHeader().getName() + DyvilFileType.DYVIL_EXTENSION, null);
if (this.enclosingClass != null) {
this.writeInnerClassInfo(writer);
}
// Annotations
this.writeAnnotations(writer, flags);
if (this.superType != null) {
IClass iclass = this.superType.getTheClass();
if (iclass != null) {
iclass.writeInnerClassInfo(writer);
}
}
if (this.interfaces != null) {
for (IType type : this.interfaces) {
final IClass iclass = type.getTheClass();
if (iclass != null) {
iclass.writeInnerClassInfo(writer);
}
}
}
// Compute Trait Classes
final Set<IClass> traitClasses;
if ((modifiers & Modifiers.INTERFACE) == 0) {
traitClasses = new ArraySet<>();
this.traitInit = !fillTraitClasses(this, traitClasses, true) && !traitClasses.isEmpty();
} else {
traitClasses = null;
}
for (int i = 0; i < this.compilableCount; i++) {
this.compilables[i].write(writer);
}
this.metadata.write(writer);
this.writeClassParameters(writer);
if (this.body != null) {
this.body.write(writer);
}
this.metadata.writePost(writer);
// Create the static <clinit> method
MethodWriter initWriter = new MethodWriterImpl(writer, writer.visitMethod(Modifiers.STATIC, "<clinit>", "()V", null, null));
initWriter.visitCode();
this.writeStaticInit(initWriter);
initWriter.visitEnd(Types.VOID);
if (traitClasses == null || traitClasses.isEmpty()) {
return;
}
// Create the virtual <traitinit> method
initWriter = new MethodWriterImpl(writer, writer.visitMethod(Modifiers.PROTECTED, TraitMetadata.INIT_NAME, "()V", null, null));
initWriter.visitCode();
initWriter.setLocalType(0, this.getInternalName());
for (IClass traitClass : traitClasses) {
final String internal = traitClass.getInternalName();
// Load 'this'
initWriter.visitVarInsn(Opcodes.ALOAD, 0);
// Invoke the static <traitinit> method of the trait class
initWriter.visitMethodInsn(Opcodes.INVOKESTATIC, internal, TraitMetadata.INIT_NAME, "(L" + internal + ";)V", true);
}
initWriter.visitInsn(Opcodes.RETURN);
initWriter.visitEnd();
}
use of dyvilx.tools.compiler.backend.MethodWriterImpl in project Dyvil by Dyvil.
the class CodeConstructor method write.
@Override
public void write(ClassWriter writer) throws BytecodeException {
final long flags = ModifierUtil.getFlags(this);
final MethodWriter methodWriter = new MethodWriterImpl(writer, writer.visitMethod(ModifierUtil.getJavaModifiers(flags), "<init>", this.getDescriptor(), this.getSignature(), this.getInternalExceptions()));
// Write Modifiers and Annotations
ModifierUtil.writeModifiers(methodWriter, flags);
this.attributes.write(methodWriter);
if (this.hasModifier(Modifiers.DEPRECATED) && this.getAnnotation(Deprecation.DEPRECATED_CLASS) == null) {
methodWriter.visitAnnotation(Deprecation.DYVIL_EXTENDED, true).visitEnd();
}
// Write Parameters
methodWriter.setThisType(this.enclosingClass.getInternalName());
this.parameters.write(methodWriter);
// Write Code
final Label start = new Label();
final Label end = new Label();
methodWriter.visitCode();
methodWriter.visitLabel(start);
if (this.initializerCall != null) {
this.initializerCall.writeExpression(methodWriter, Types.VOID);
}
if (this.initializerCall == null || this.initializerCall.isSuper()) {
this.enclosingClass.writeClassInit(methodWriter);
}
if (this.value != null) {
this.value.writeExpression(methodWriter, Types.VOID);
}
methodWriter.visitLabel(end);
methodWriter.visitEnd(Types.VOID);
// Write Local Variable Data
methodWriter.visitLocalVariable("this", 'L' + this.enclosingClass.getInternalName() + ';', null, start, end, 0);
this.parameters.writeLocals(methodWriter, start, end);
}
use of dyvilx.tools.compiler.backend.MethodWriterImpl in project Dyvil by Dyvil.
the class IParameter method writeDefaultValue.
default void writeDefaultValue(ClassWriter writer) {
final IValue value = this.getValue();
assert value != null;
final ICallableMember method = this.getMethod();
final IType type = this.getType();
final String name;
final int access;
if (method == null) {
name = "init$paramDefault$" + this.getInternalName();
access = Modifiers.STATIC;
} else {
name = method.getInternalName() + "$paramDefault$" + this.getInternalName();
access = (method.getAttributes().flags() & Modifiers.MEMBER_MODIFIERS) | Modifiers.STATIC;
}
final String desc = "()" + this.getDescriptor();
final String signature = "()" + this.getSignature();
final MethodWriter mw = new MethodWriterImpl(writer, writer.visitMethod(access, name, desc, signature, null));
mw.visitCode();
value.writeExpression(mw, type);
mw.visitEnd(type);
}
use of dyvilx.tools.compiler.backend.MethodWriterImpl in project Dyvil by Dyvil.
the class CaseClassMetadata method write.
@Override
public void write(ClassWriter writer) throws BytecodeException {
super.write(writer);
MethodWriter mw;
final String internal = this.theClass.getInternalName();
if ((this.members & EQUALS) == 0) {
mw = new MethodWriterImpl(writer, writer.visitMethod(Modifiers.PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null));
mw.setThisType(internal);
mw.visitParameter(1, "obj", Types.OBJECT, 0);
mw.visitCode();
CaseClasses.writeEquals(mw, this.theClass);
mw.visitEnd();
}
if ((this.members & HASHCODE) == 0) {
mw = new MethodWriterImpl(writer, writer.visitMethod(Modifiers.PUBLIC, "hashCode", "()I", null, null));
mw.setThisType(internal);
mw.visitCode();
CaseClasses.writeHashCode(mw, this.theClass);
mw.visitEnd();
}
if ((this.members & TOSTRING) == 0) {
mw = new MethodWriterImpl(writer, writer.visitMethod(Modifiers.PUBLIC, "toString", "()Ljava/lang/String;", null, null));
mw.setThisType(internal);
mw.visitCode();
CaseClasses.writeToString(mw, this.theClass);
mw.visitEnd();
}
}
use of dyvilx.tools.compiler.backend.MethodWriterImpl in project Dyvil by Dyvil.
the class CodeMethod method write.
@Override
public void write(ClassWriter writer) throws BytecodeException {
final boolean interfaceClass = this.enclosingClass.isInterface();
final long flags = ModifierUtil.getFlags(this);
final String ownerClassName = this.enclosingClass.getInternalName();
final String mangledName = this.getInternalName();
final String descriptor = this.getDescriptor();
final String signature = this.needsSignature() ? this.getSignature() : null;
final String[] exceptionTypes = this.getInternalExceptions();
MethodWriter methodWriter = new MethodWriterImpl(writer, writer.visitMethod(ModifierUtil.getJavaModifiers(flags), mangledName, descriptor, signature, exceptionTypes));
if (!this.isStatic()) {
methodWriter.setThisType(ownerClassName);
}
this.writeAnnotations(methodWriter, flags);
this.writeParameters(methodWriter);
final Label start = new Label();
final Label end = new Label();
if (this.value != null) {
methodWriter.visitCode();
methodWriter.visitLabel(start);
this.value.writeExpression(methodWriter, this.type);
methodWriter.visitLabel(end);
methodWriter.visitEnd(this.type);
} else if (this.hasModifier(Modifiers.STATIC | Modifiers.ABSTRACT)) {
// no value, but no abstract flag
methodWriter.visitCode();
methodWriter.visitTypeInsn(Opcodes.NEW, "java/lang/AbstractMethodError");
methodWriter.visitInsn(Opcodes.DUP);
methodWriter.visitLdcInsn(ClassFormat.internalToPackage(ownerClassName) + '.' + mangledName + descriptor);
methodWriter.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/AbstractMethodError", "<init>", "(Ljava/lang/String;)V", false);
methodWriter.visitInsn(Opcodes.ATHROW);
methodWriter.visitEnd(this.type);
}
if (!this.isStatic()) {
methodWriter.visitLocalVariable("this", 'L' + ownerClassName + ';', null, start, end, 0);
}
this.parameters.writeLocals(methodWriter, start, end);
if (this.overrideMethods == null) {
return;
}
final int lineNumber = this.lineNumber();
final int opcode = this.getInvokeOpcode();
final int bridgeModifiers = Modifiers.PUBLIC | Modifiers.SYNTHETIC | Modifiers.BRIDGE | (this.isStatic() ? Modifiers.STATIC : 0);
/*
* Contains entries in the format 'mangledName(paramTypes)returnType'
* Used to ensure unique bridge methods
*/
final Set<String> descriptors = new HashSet<>(1 + this.overrideMethods.size());
descriptors.add(mangledName + descriptor);
for (IMethod overrideMethod : this.overrideMethods) {
final String overrideDescriptor = overrideMethod.getDescriptor();
final String overrideMangledName = overrideMethod.getInternalName();
final String overrideEntry = overrideMangledName + overrideDescriptor;
// generated
if (descriptors.contains(overrideEntry)) {
continue;
}
descriptors.add(overrideEntry);
// Generate a bridge method
methodWriter = new MethodWriterImpl(writer, writer.visitMethod(bridgeModifiers, overrideMangledName, overrideDescriptor, null, exceptionTypes));
methodWriter.visitCode();
if (!this.isStatic()) {
methodWriter.setThisType(ownerClassName);
methodWriter.visitVarInsn(Opcodes.ALOAD, 0);
}
// Generate Parameters and load arguments
this.writeBridgeParameters(methodWriter, overrideMethod);
// Generate Type Parameters and load reified type arguments
this.writeBridgeTypeParameters(methodWriter, overrideMethod);
final IType overrideReturnType = overrideMethod.getType();
methodWriter.visitLineNumber(lineNumber);
methodWriter.visitMethodInsn(opcode, ownerClassName, mangledName, descriptor, interfaceClass);
this.type.writeCast(methodWriter, overrideReturnType, lineNumber);
methodWriter.visitInsn(overrideReturnType.getReturnOpcode());
methodWriter.visitEnd();
}
}
Aggregations