asmclassgenerator.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 1,558 行 · 第 1/5 页
JAVA
1,558 行
internalBaseClassName,
BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
);
cw.visitSource(sourceFile,null);
if (classNode.isInterface()) {
ClassNode owner = classNode;
if (owner instanceof InnerClassNode) {
owner = owner.getOuterClass();
}
String outerClassName = owner.getName();
String name = outerClassName + "$" + context.getNextInnerClassIdx();
interfaceClassLoadingClass = new InnerClassNode(owner, name, 4128, ClassHelper.OBJECT_TYPE);
super.visitClass(classNode);
createInterfaceSyntheticStaticFields();
} else {
super.visitClass(classNode);
createMopMethods();
createSyntheticStaticFields();
}
for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
ClassNode innerClass = (ClassNode) iter.next();
String innerClassName = innerClass.getName();
String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
{
int index = innerClassName.lastIndexOf('$');
if (index>=0) innerClassName = innerClassName.substring(index+1);
}
String outerClassName = internalClassName; // default for inner classes
MethodNode enclosingMethod = innerClass.getEnclosingMethod();
if (enclosingMethod != null) {
// local inner classes do not specify the outer class name
outerClassName = null;
innerClassName = null;
}
cw.visitInnerClass(
innerClassInternalName,
outerClassName,
innerClassName,
innerClass.getModifiers());
}
//TODO: an inner class should have an entry of itself
cw.visitEnd();
}
catch (GroovyRuntimeException e) {
e.setModule(classNode.getModule());
throw e;
}
}
private void createMopMethods() {
visitMopMethodList(classNode.getMethods(), true);
visitMopMethodList(classNode.getSuperClass().getAllDeclaredMethods(), false);
}
private String[] buildExceptions(ClassNode[] exceptions) {
if (exceptions==null) return null;
String[] ret = new String[exceptions.length];
for (int i = 0; i < exceptions.length; i++) {
ret[i] = BytecodeHelper.getClassInternalName(exceptions[i]);
}
return ret;
}
/**
* filters a list of method for MOP methods. For all methods that are no
* MOP methods a MOP method is created if the method is not public and the
* call would be a call on "this" (isThis == true). If the call is not on
* "this", then the call is a call on "super" and all methods are used,
* unless they are already a MOP method
*
* @see #generateMopCalls(LinkedList, boolean)
*
* @param methods unfiltered list of methods for MOP
* @param isThis if true, then we are creating a MOP method on "this", "super" else
*/
private void visitMopMethodList(List methods, boolean isThis){
LinkedList mopCalls = new LinkedList();
for (Iterator iter = methods.iterator(); iter.hasNext();) {
MethodNode mn = (MethodNode) iter.next();
if ((mn.getModifiers() & ACC_ABSTRACT) !=0 ) continue;
// no this$ methods for protected/public isThis=true
// super$ method for protected/public isThis=false
// --> results in XOR
if (isThis ^ (mn.getModifiers() & (ACC_PUBLIC|ACC_PROTECTED)) == 0) continue;
String methodName = mn.getName();
if (isMopMethod(methodName) || methodName.startsWith("<")) continue;
String name = getMopMethodName(mn,isThis);
if (containsMethod(methods,name,mn.getParameters())) continue;
mopCalls.add(mn);
}
generateMopCalls(mopCalls, isThis);
mopCalls.clear();
}
private boolean containsMethod(List methods, String name, Parameter[] paras) {
for (Iterator iter = methods.iterator(); iter.hasNext();) {
MethodNode element = (MethodNode) iter.next();
if (element.getName().equals(name) && equalParameterTypes(paras,element.getParameters())) return true;
}
return false;
}
private boolean equalParameterTypes(Parameter[] p1, Parameter[] p2) {
if (p1.length!=p2.length) return false;
for (int i=0; i<p1.length; i++) {
if (!p1[i].getType().equals(p2[i].getType())) return false;
}
return true;
}
/**
* generates a Meta Object Protocoll method, that is used to call a non public
* method, or to make a call to super.
* @param mopCalls list of methods a mop call method should be generated for
* @param useThis true if "this" should be used for the naming
*/
private void generateMopCalls(LinkedList mopCalls, boolean useThis) {
for (Iterator iter = mopCalls.iterator(); iter.hasNext();) {
MethodNode method = (MethodNode) iter.next();
String name = getMopMethodName(method,useThis);
Parameter[] parameters = method.getParameters();
String methodDescriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameters());
cv = cw.visitMethod(Opcodes.ACC_PUBLIC & Opcodes.ACC_SYNTHETIC, name, methodDescriptor, null, null);
cv.visitVarInsn(ALOAD,0);
BytecodeHelper helper = new BytecodeHelper(cv);
int newRegister = 1;
for (int i=0; i<parameters.length; i++) {
ClassNode type = parameters[i].getType();
helper.load(parameters[i].getType(),newRegister);
// increment to next register, double/long are using two places
newRegister++;
if (type == ClassHelper.double_TYPE || type == ClassHelper.long_TYPE) newRegister++;
}
cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(method.getDeclaringClass()), method.getName(), methodDescriptor);
helper.doReturn(method.getReturnType());
cv.visitMaxs(0, 0);
cv.visitEnd();
classNode.addMethod(name,Opcodes.ACC_PUBLIC & Opcodes.ACC_SYNTHETIC,method.getReturnType(),parameters,null,null);
}
}
/**
* creates a MOP method name from a method
* @param method the method to be called by the mop method
* @param useThis if true, then it is a call on "this", "super" else
* @return the mop method name
*/
public static String getMopMethodName(MethodNode method, boolean useThis) {
ClassNode declaringNode = method.getDeclaringClass();
int distance = 0;
for (;declaringNode!=null; declaringNode=declaringNode.getSuperClass()) {
distance++;
}
return (useThis?"this":"super")+"$"+distance+"$"+method.getName();
}
/**
* method to determine if a method is a MOP method. This is done by the
* method name. If the name starts with "this$" or "super$", then it is
* a MOP method
* @param methodName name of the method to test
* @return true if the method is a MOP method
*/
public static boolean isMopMethod(String methodName) {
return methodName.startsWith("this$") ||
methodName.startsWith("super$");
}
protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, buildExceptions(node.getExceptions()));
helper = new BytecodeHelper(cv);
if (!node.isAbstract()) {
Statement code = node.getCode();
if (isConstructor && (code == null || !firstStatementIsSpecialConstructorCall(node))) {
// invokes the super class constructor
cv.visitVarInsn(ALOAD, 0);
cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", "()V");
}
compileStack.init(node.getVariableScope(),node.getParameters(),cv, classNode);
// ensure we save the current (meta) class in a register
(new ClassExpression(classNode)).visit(this);
cv.visitInsn(POP);
(new ClassExpression(ClassHelper.METACLASS_TYPE)).visit(this);
cv.visitInsn(POP);
// handle body
super.visitConstructorOrMethod(node, isConstructor);
if (!outputReturn || node.isVoidMethod()) {
cv.visitInsn(RETURN);
}
compileStack.clear();
// lets do all the exception blocks
for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) {
Runnable runnable = (Runnable) iter.next();
runnable.run();
}
exceptionBlocks.clear();
cv.visitMaxs(0, 0);
}
}
private boolean firstStatementIsSpecialConstructorCall(MethodNode node) {
Statement code = node.getFirstStatement();
if (code == null || !(code instanceof ExpressionStatement)) return false;
Expression expression = ((ExpressionStatement)code).getExpression();
if (!(expression instanceof ConstructorCallExpression)) return false;
ConstructorCallExpression cce = (ConstructorCallExpression) expression;
return cce.isSpecialCall();
}
public void visitConstructor(ConstructorNode node) {
this.constructorNode = node;
this.methodNode = null;
outputReturn = false;
super.visitConstructor(node);
}
public void visitMethod(MethodNode node) {
this.constructorNode = null;
this.methodNode = node;
outputReturn = false;
super.visitMethod(node);
}
public void visitField(FieldNode fieldNode) {
onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
ClassNode t = fieldNode.getType();
cw.visitField(
fieldNode.getModifiers(),
fieldNode.getName(),
BytecodeHelper.getTypeDescription(t),
null, //fieldValue, //br all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
null);
visitAnnotations(fieldNode);
}
public void visitProperty(PropertyNode statement) {
// the verifyer created the field and the setter/getter methods, so here is
// not really something to do
onLineNumber(statement, "visitProperty:" + statement.getField().getName());
this.methodNode = null;
}
// GroovyCodeVisitor interface
//-------------------------------------------------------------------------
// Statements
//-------------------------------------------------------------------------
protected void visitStatement(Statement statement) {
String name = statement.getStatementLabel();
if (name!=null) {
Label label = compileStack.createLocalLabel(name);
cv.visitLabel(label);
}
}
public void visitBlockStatement(BlockStatement block) {
onLineNumber(block, "visitBlockStatement");
visitStatement(block);
compileStack.pushVariableScope(block.getVariableScope());
super.visitBlockStatement(block);
compileStack.pop();
}
public void visitForLoop(ForStatement loop) {
onLineNumber(loop, "visitForLoop");
visitStatement(loop);
compileStack.pushLoop(loop.getVariableScope(),loop.getStatementLabel());
//
// Declare the loop counter.
Variable variable = compileStack.defineVariable(loop.getVariable(),false);
//
// Then get the iterator and generate the loop control
MethodCallExpression iterator = new MethodCallExpression(loop.getCollectionExpression(),"iterator",new ArgumentListExpression());
iterator.visit(this);
final int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.make(java.util.Iterator.class),true);
Label continueLabel = compileStack.getContinueLabel();
Label breakLabel = compileStack.getBreakLabel();
cv.visitLabel(continueLabel);
cv.visitVarInsn(ALOAD, iteratorIdx);
iteratorHasNextMethod.call(cv);
// note: ifeq tests for ==0, a boolean is 0 if it is false
cv.visitJumpInsn(IFEQ, breakLabel);
cv.visitVarInsn(ALOAD, iteratorIdx);
iteratorNextMethod.call(cv);
helper.storeVar(variable);
// Generate the loop body
loop.getLoopBlock().visit(this);
cv.visitJumpInsn(GOTO, continueLabel);
cv.visitLabel(breakLabel);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?