/*******************************************************************************
* Copyright 2014,
* Luis Pina <luis@luispina.me>,
* Michael Hicks <mwh@cs.umd.edu>
*
* This file is part of Rubah.
*
* Rubah is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rubah is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rubah. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package rubah.bytecode.transformers;
import java.util.HashMap;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import rubah.Rubah;
import rubah.framework.Method;
import rubah.framework.Type;
import rubah.runtime.RubahRuntime;
import rubah.runtime.Version;
import rubah.runtime.classloader.RubahClassloader;
public class DummifyStaticInitTransformer extends RubahTransformer {
private static final String ENUM_CLASS_NAME = Type.getType(Enum.class).getInternalName();
private static final String RUBAH_RUNTIME_CLASS_NAME = Type.getType(RubahRuntime.class).getInternalName();
private static final Type RUBAH_CLASSLOADER_TYPE = Type.getType(RubahClassloader.class);
protected Version version;
private boolean isEnum;
private boolean foundClinit;
public DummifyStaticInitTransformer(HashMap<String, Object> objectsMap, Version v1, ClassVisitor cv) {
super(objectsMap, v1.getNamespace(), cv);
this.version = v1;
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
this.isEnum = superName.equals(ENUM_CLASS_NAME);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor ret = super.visitMethod(access, name, desc, signature, exceptions);
Method m = (Method) this.objectsMap.get(name);
String methodName = (m == null ? name : m.getName());
if (methodName.equals("<clinit>")) {
this.foundClinit = true;
ret = new RegisterResolvedTransformer(ret);
if (this.version.getPrevious() != null && !this.isEnum && m != null) {
String prevVersionName = this.version.getPrevious().getUpdatableName(this.thisClass.getFqn());
if (prevVersionName != null && Rubah.getLoader().isResolved(prevVersionName)) {
// Class already resolved, generate dummy static initializer
this.generateDummyClinit(ret);
return null;
}
}
}
return ret;
}
@Override
public void visitEnd() {
if (!foundClinit) {
MethodVisitor mv = this.cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv = new RegisterResolvedTransformer(mv);
this.generateDummyClinit(mv);
}
this.cv.visitEnd();
}
private void generateDummyClinit(MethodVisitor mv) {
mv.visitCode();
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private class RegisterResolvedTransformer extends MethodVisitor {
public RegisterResolvedTransformer(MethodVisitor mv) {
super(ASM5, mv);
}
@Override
public void visitCode() {
this.mv.visitCode();
this.mv.visitMethodInsn(
INVOKESTATIC,
RUBAH_RUNTIME_CLASS_NAME,
"getLoader",
Type.getMethodDescriptor(RUBAH_CLASSLOADER_TYPE),
false);
this.mv.visitLdcInsn(thisClass.getASMType().getASMType());
this.mv.visitMethodInsn(
INVOKEVIRTUAL,
RUBAH_CLASSLOADER_TYPE.getInternalName(),
"registerResolved",
"(Ljava/lang/Class;)V", false);
}
}
}