blob: fa44be618901d110115ee159d9ce979c593103cc [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Dynamic Runtime Environment"
*
* Copyright 2009, 2018 Oliver Frank and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0 *
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Oliver Frank - Initial API and implementation
* Stephan Herrmann - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otredyn.bytecode.asm;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import static org.eclipse.objectteams.otredyn.bytecode.asm.AsmBoundClass.ASM_API;
/**
* This class adds an method only with a return statement
* to the bytecode of a class with the ASM Core API
* @author Oliver Frank
*/
class AddEmptyMethodAdapter extends ClassVisitor {
private int access;
private String name;
private String desc;
private String signature;
private String[] exceptions;
private int maxLocals;
private String superToCall;
private boolean addThrow;
public AddEmptyMethodAdapter(ClassVisitor cv, String name, int access,
String desc, String[] exceptions, String signature,
int maxLocals, String superToCall, boolean addThrow) {
super(ASM_API, cv);
this.access = access;
this.desc = desc;
this.exceptions = exceptions;
this.name = name;
this.signature = signature;
this.maxLocals = maxLocals;
this.superToCall = superToCall;
this.addThrow = addThrow;
}
@Override
public void visitEnd() {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
if ((this.access & Opcodes.ACC_ABSTRACT) != 0) {
mv.visitEnd();
return;
}
mv.visitCode();
boolean needConstValue = true;
if (superToCall != null) {
needConstValue = false;
boolean isStatic = (this.access & Opcodes.ACC_STATIC) != 0;
int firstArgIndex = isStatic ? 0 : 1;
if (!isStatic)
mv.visitVarInsn(Opcodes.ALOAD, 0); // "this"
Type[] args = Type.getArgumentTypes(desc);
for (int i=0, slot=firstArgIndex; i < args.length; slot+=args[i++].getSize())
mv.visitVarInsn(args[i].getOpcode(Opcodes.ILOAD), slot);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, superToCall, name, desc, false);
} else if (this.addThrow) {
mv.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn("Empty method "+name+"() called");
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalStateException", "<init>", "(Ljava/lang/String;)V", false);
mv.visitInsn(Opcodes.ATHROW);
}
Type returnType = Type.getReturnType(this.desc);
switch (returnType.getSort()) {
case Type.VOID:
mv.visitInsn(Opcodes.RETURN);
break;
case Type.INT:
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
if (needConstValue)
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.IRETURN);
break;
case Type.FLOAT:
if (needConstValue)
mv.visitInsn(Opcodes.FCONST_1);
mv.visitInsn(Opcodes.FRETURN);
break;
case Type.LONG:
if (needConstValue)
mv.visitInsn(Opcodes.LCONST_1);
mv.visitInsn(Opcodes.LRETURN);
break;
case Type.DOUBLE:
case Type.OBJECT:
case Type.ARRAY:
if (needConstValue)
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitInsn(Opcodes.ARETURN);
break;
}
mv.visitMaxs(1, maxLocals);
mv.visitEnd();
}
@Override
public MethodVisitor visitMethod(int arg0, String arg1, String arg2, String arg3, String[] arg4) {
return null; // also consider other visitors
}
@Override
public String toString() {
return "AddEmptyMethod "+this.name+this.desc+" call super: "+this.superToCall;
}
}