use of javassist.bytecode.BadBytecode in project fakereplace by fakereplace.
the class MethodReplacementTransformer method transform.
@Override
public boolean transform(ClassLoader loader, String className, Class<?> oldClass, ProtectionDomain protectionDomain, ClassFile file, Set<Class<?>> classesToRetransform, ChangedClassImpl changedClass, Set<MethodInfo> modifiedMethods) throws IllegalClassFormatException, BadBytecode, DuplicateMemberException {
if (oldClass == null || className == null) {
return false;
}
final Set<MethodData> methodsToRemove = new HashSet<>();
final Set<FakeMethod> methodsToAdd = new HashSet<>();
final Set<FakeMethod> constructorsToAdd = new HashSet<>();
BaseClassData data = ClassDataStore.instance().getBaseClassData(loader, className);
// state for added static methods
CodeAttribute staticCodeAttribute = null, virtualCodeAttribute = null, constructorCodeAttribute = null;
try {
// stick our added methods into the class file
// we can't finalise the code yet because we will probably need
// the add stuff to them
MethodInfo virtMethod = new MethodInfo(file.getConstPool(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
modifiedMethods.add(virtMethod);
virtMethod.setAccessFlags(AccessFlag.PUBLIC);
if (file.isInterface()) {
virtMethod.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.ABSTRACT | AccessFlag.SYNTHETIC);
} else {
virtMethod.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.SYNTHETIC);
Bytecode b = new Bytecode(file.getConstPool(), 0, 3);
if (BuiltinClassData.skipInstrumentation(file.getSuperclass())) {
b.addNew(NoSuchMethodError.class.getName());
b.add(Opcode.DUP);
b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
b.add(Opcode.ATHROW);
} else {
b.add(Bytecode.ALOAD_0);
b.add(Bytecode.ILOAD_1);
b.add(Bytecode.ALOAD_2);
b.addInvokespecial(file.getSuperclass(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
b.add(Bytecode.ARETURN);
}
virtualCodeAttribute = b.toCodeAttribute();
virtMethod.setCodeAttribute(virtualCodeAttribute);
MethodInfo m = new MethodInfo(file.getConstPool(), Constants.ADDED_STATIC_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
modifiedMethods.add(m);
m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC | AccessFlag.SYNTHETIC);
b = new Bytecode(file.getConstPool(), 0, 3);
b.addNew(NoSuchMethodError.class.getName());
b.add(Opcode.DUP);
b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
b.add(Opcode.ATHROW);
staticCodeAttribute = b.toCodeAttribute();
m.setCodeAttribute(staticCodeAttribute);
file.addMethod(m);
m = new MethodInfo(file.getConstPool(), "<init>", Constants.ADDED_CONSTRUCTOR_DESCRIPTOR);
modifiedMethods.add(m);
m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.SYNTHETIC);
b = new Bytecode(file.getConstPool(), 0, 4);
if (ManipulationUtils.addBogusConstructorCall(file, b)) {
constructorCodeAttribute = b.toCodeAttribute();
m.setCodeAttribute(constructorCodeAttribute);
constructorCodeAttribute.setMaxLocals(6);
file.addMethod(m);
}
}
file.addMethod(virtMethod);
} catch (DuplicateMemberException e) {
e.printStackTrace();
}
Set<MethodData> methods = new HashSet<>();
methods.addAll(data.getMethods());
ListIterator<?> it = file.getMethods().listIterator();
// IncompatibleClassChange exception will be thrown
while (it.hasNext()) {
MethodInfo m = (MethodInfo) it.next();
MethodData md = null;
boolean upgradedVisibility = false;
for (MethodData i : methods) {
if (i.getMethodName().equals(m.getName()) && i.getDescriptor().equals(m.getDescriptor())) {
// depends on what has changed
if (i.getAccessFlags() != m.getAccessFlags()) {
if (AccessFlagUtils.upgradeVisibility(m.getAccessFlags(), i.getAccessFlags())) {
upgradedVisibility = true;
} else if (AccessFlagUtils.downgradeVisibility(m.getAccessFlags(), i.getAccessFlags())) {
// ignore this, we don't need to do anything
} else {
// we can't handle this yet
continue;
}
}
m.setAccessFlags(i.getAccessFlags());
// if it is the constructor
if (m.getName().equals("<init>")) {
try {
Constructor<?> meth = i.getConstructor(oldClass);
AnnotationDataStore.recordConstructorAnnotations(meth, (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag));
AnnotationDataStore.recordConstructorParameterAnnotations(meth, (ParameterAnnotationsAttribute) m.getAttribute(ParameterAnnotationsAttribute.visibleTag));
// now revert the annotations:
m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
m.addAttribute(AnnotationReplacer.duplicateParameterAnnotationsAttribute(file.getConstPool(), meth));
} catch (Exception e) {
throw new RuntimeException(e);
}
} else if (!m.getName().equals("<clinit>")) {
// we do not have to worry about them
try {
Method meth = i.getMethod(oldClass);
AnnotationDataStore.recordMethodAnnotations(meth, (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag));
AnnotationDataStore.recordMethodParameterAnnotations(meth, (ParameterAnnotationsAttribute) m.getAttribute(ParameterAnnotationsAttribute.visibleTag));
// now revert the annotations:
m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
m.addAttribute(AnnotationReplacer.duplicateParameterAnnotationsAttribute(file.getConstPool(), meth));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
md = i;
break;
}
}
// we do not need to deal with these
if (m.getName().equals(Constants.ADDED_METHOD_NAME) || m.getName().equals(Constants.ADDED_STATIC_METHOD_NAME)) {
break;
}
// so it is still in the original
if (md == null || upgradedVisibility) {
if ((m.getAccessFlags() & AccessFlag.STATIC) != 0) {
Class<?> c = addMethod(file, loader, m, methodsToAdd, staticCodeAttribute, true, oldClass);
if (c != null) {
classesToRetransform.add(c);
}
} else if ((m.getName().equals("<init>"))) {
addConstructor(file, loader, m, constructorsToAdd, constructorCodeAttribute, oldClass);
} else if (m.getName().equals("<clinit>")) {
// nop, we can't change this, just ignore it
} else {
Class<?> c = addMethod(file, loader, m, methodsToAdd, virtualCodeAttribute, false, oldClass);
if (c != null) {
classesToRetransform.add(c);
}
}
if (!upgradedVisibility) {
it.remove();
}
} else {
methods.remove(md);
}
if (upgradedVisibility) {
methods.remove(md);
}
}
for (MethodData md : methods) {
if (md.getType() == MemberType.NORMAL) {
MethodInfo removedMethod = createRemovedMethod(file, md, oldClass, methodsToRemove);
if (removedMethod != null) {
modifiedMethods.add(removedMethod);
}
}
}
ClassDataStore.instance().modifyCurrentData(loader, className, (builder) -> {
for (MethodData method : methodsToRemove) {
builder.removeMethod(method);
}
for (FakeMethod fake : methodsToAdd) {
ClassDataStore.instance().registerReplacedMethod(fake.proxyName, builder.addFakeMethod(fake.name, fake.descriptor, fake.proxyName, fake.accessFlags));
}
for (FakeMethod fake : constructorsToAdd) {
ClassDataStore.instance().registerReplacedMethod(fake.proxyName, builder.addFakeConstructor(fake.name, fake.descriptor, fake.proxyName, fake.accessFlags, fake.methodCount));
}
});
// the method declaration to propagate the call to the parent
if (!file.isInterface()) {
try {
staticCodeAttribute.computeMaxStack();
virtualCodeAttribute.computeMaxStack();
if (constructorCodeAttribute != null) {
constructorCodeAttribute.computeMaxStack();
}
} catch (BadBytecode e) {
e.printStackTrace();
}
}
return true;
}
use of javassist.bytecode.BadBytecode in project javaparser by javaparser.
the class JavassistTypeDeclarationAdapter method getInterfaces.
private List<ResolvedReferenceType> getInterfaces(boolean acceptIncompleteList) {
List<ResolvedReferenceType> interfaces = new ArrayList<>();
try {
if (ctClass.getGenericSignature() == null) {
for (String interfaceType : ctClass.getClassFile().getInterfaces()) {
try {
ResolvedReferenceTypeDeclaration declaration = typeSolver.solveType(JavassistUtils.internalNameToCanonicalName(interfaceType));
interfaces.add(new ReferenceTypeImpl(declaration, typeSolver));
} catch (UnsolvedSymbolException e) {
if (!acceptIncompleteList) {
throw e;
}
}
}
} else {
SignatureAttribute.ClassSignature classSignature = SignatureAttribute.toClassSignature(ctClass.getGenericSignature());
for (SignatureAttribute.ClassType interfaceType : classSignature.getInterfaces()) {
try {
interfaces.add(JavassistUtils.signatureTypeToType(interfaceType, typeSolver, typeDeclaration).asReferenceType());
} catch (UnsolvedSymbolException e) {
if (!acceptIncompleteList) {
throw e;
}
}
}
}
} catch (BadBytecode e) {
throw new RuntimeException(e);
}
return interfaces;
}
use of javassist.bytecode.BadBytecode in project droolsjbpm-integration by kiegroup.
the class BytecodeInjectReactive method enhanceAttributesAccess.
protected void enhanceAttributesAccess(Map<String, CtField> fieldsMap, CtClass managedCtClass) throws Exception {
final ConstPool constPool = managedCtClass.getClassFile().getConstPool();
final ClassPool classPool = managedCtClass.getClassPool();
for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
final MethodInfo methodInfo = (MethodInfo) oMethod;
final String methodName = methodInfo.getName();
// skip methods added by enhancement, and abstract methods (methods without any code)
if (methodName.startsWith(DROOLS_PREFIX) || methodInfo.getCodeAttribute() == null) {
continue;
}
try {
final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
while (itr.hasNext()) {
final int index = itr.next();
final int op = itr.byteAt(index);
if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
continue;
}
final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
CtField ctField = fieldsMap.get(fieldName);
if (ctField == null) {
continue;
}
// if we are in constructors, only need to intercept assignment statement for Reactive Collection/List/... (regardless they may be final)
if (methodInfo.isConstructor() && !(isCtFieldACollection(ctField))) {
continue;
}
if (op == Opcode.PUTFIELD) {
// addMethod is a safe add, if constant already present it return the existing value without adding.
final int methodIndex = addMethod(constPool, writeMethods.get(fieldName));
itr.writeByte(Opcode.INVOKEVIRTUAL, index);
itr.write16bit(methodIndex, index + 1);
}
}
methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
} catch (BadBytecode bb) {
final String msg = String.format("Unable to perform field access transformation in method [%s]", methodName);
throw new Exception(msg, bb);
}
}
}
use of javassist.bytecode.BadBytecode in project pinpoint by naver.
the class JavassistMethod method insertCatch.
private void insertCatch(int from, String src, CtClass exceptionType, String exceptionName) throws CannotCompileException {
CtClass cc = behavior.getDeclaringClass();
ConstPool cp = behavior.getMethodInfo().getConstPool();
CodeAttribute ca = behavior.getMethodInfo().getCodeAttribute();
CodeIterator iterator = ca.iterator();
Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals());
b.setStackDepth(1);
Javac jv = new Javac(b, cc);
try {
jv.recordParams(behavior.getParameterTypes(), Modifier.isStatic(getModifiers()));
jv.recordLocalVariables(ca, from);
int var = jv.recordVariable(exceptionType, exceptionName);
b.addAstore(var);
jv.compileStmnt(src);
int stack = b.getMaxStack();
int locals = b.getMaxLocals();
if (stack > ca.getMaxStack())
ca.setMaxStack(stack);
if (locals > ca.getMaxLocals())
ca.setMaxLocals(locals);
int len = iterator.getCodeLength();
int pos = iterator.append(b.get());
ca.getExceptionTable().add(from, len, len, cp.addClassInfo(exceptionType));
iterator.append(b.getExceptionTable(), pos);
behavior.getMethodInfo().rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
} catch (NotFoundException e) {
throw new CannotCompileException(e);
} catch (CompileError e) {
throw new CannotCompileException(e);
} catch (BadBytecode e) {
throw new CannotCompileException(e);
}
}
use of javassist.bytecode.BadBytecode in project pinpoint by naver.
the class JavassistMethod method insertBeforeConstructor.
private int insertBeforeConstructor(int pos, String src) throws CannotCompileException {
CtClass cc = behavior.getDeclaringClass();
CodeAttribute ca = behavior.getMethodInfo().getCodeAttribute();
CodeIterator iterator = ca.iterator();
Bytecode b = new Bytecode(behavior.getMethodInfo().getConstPool(), ca.getMaxStack(), ca.getMaxLocals());
b.setStackDepth(ca.getMaxStack());
Javac jv = new Javac(b, cc);
try {
jv.recordParams(behavior.getParameterTypes(), false);
jv.recordLocalVariables(ca, 0);
jv.compileStmnt(src);
ca.setMaxStack(b.getMaxStack());
ca.setMaxLocals(b.getMaxLocals());
iterator.skipConstructor();
if (pos != -1) {
iterator.insertEx(pos, b.get());
} else {
pos = iterator.insertEx(b.get());
}
iterator.insert(b.getExceptionTable(), pos);
behavior.getMethodInfo().rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
return pos + b.length();
} catch (NotFoundException e) {
throw new CannotCompileException(e);
} catch (CompileError e) {
throw new CannotCompileException(e);
} catch (BadBytecode e) {
throw new CannotCompileException(e);
}
}
Aggregations