001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.transform.inlining.weaver;
008:
009: import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
010: import org.codehaus.aspectwerkz.reflect.ClassInfo;
011: import org.codehaus.aspectwerkz.transform.Context;
012: import org.codehaus.aspectwerkz.transform.TransformationConstants;
013: import org.codehaus.aspectwerkz.transform.TransformationUtil;
014: import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
015: import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
016: import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
017: import org.objectweb.asm.Attribute;
018: import org.objectweb.asm.ClassAdapter;
019: import org.objectweb.asm.ClassVisitor;
020: import org.objectweb.asm.CodeVisitor;
021: import org.objectweb.asm.Type;
022:
023: import java.util.Set;
024:
025: /**
026: * Adds a "proxy method" to the <tt><clinit></tt> that matches an
027: * <tt>staticinitialization</tt> pointcut as well as prefixing the "original method"
028: * (see {@link org.codehaus.aspectwerkz.transform.TransformationUtil#getPrefixedOriginalClinitName(String)}).
029: * <br/>
030: *
031: * @author <a href="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
032: */
033: public class StaticInitializationVisitor extends ClassAdapter implements
034: TransformationConstants {
035:
036: private final ContextImpl m_ctx;
037: private String m_declaringTypeName;
038: private final Set m_addedMethods;
039:
040: /**
041: * Creates a new class adapter.
042: *
043: * @param cv
044: * @param ctx
045: * @param addedMethods already added methods by AW
046: */
047: public StaticInitializationVisitor(final ClassVisitor cv,
048: final Context ctx, final Set addedMethods) {
049: super (cv);
050: m_ctx = (ContextImpl) ctx;
051: m_addedMethods = addedMethods;
052: }
053:
054: /**
055: * Visits the class.
056: *
057: * @param access
058: * @param name
059: * @param superName
060: * @param interfaces
061: * @param sourceFile
062: */
063: public void visit(final int version, final int access,
064: final String name, final String super Name,
065: final String[] interfaces, final String sourceFile) {
066: m_declaringTypeName = name;
067: super .visit(version, access, name, super Name, interfaces,
068: sourceFile);
069: }
070:
071: /**
072: * Visits the methods.
073: *
074: * @param access
075: * @param name
076: * @param desc
077: * @param exceptions
078: * @param attrs
079: * @return
080: */
081: public CodeVisitor visitMethod(final int access, final String name,
082: final String desc, final String[] exceptions,
083: final Attribute attrs) {
084: if (!CLINIT_METHOD_NAME.equals(name)) {
085: return super .visitMethod(access, name, desc, exceptions,
086: attrs);
087: }
088:
089: String prefixedOriginalName = TransformationUtil
090: .getPrefixedOriginalClinitName(m_declaringTypeName);
091: if (m_addedMethods.contains(AlreadyAddedMethodAdapter
092: .getMethodKey(prefixedOriginalName,
093: CLINIT_METHOD_SIGNATURE))) {
094: return super .visitMethod(access, name, desc, exceptions,
095: attrs);
096: }
097:
098: m_ctx.markAsAdvised();
099:
100: // create the proxy for the original method
101: createProxyMethod(access, name, desc, exceptions, attrs);
102:
103: // prefix the original method
104: return cv.visitMethod(access + ACC_PUBLIC,
105: prefixedOriginalName, desc, exceptions, attrs);
106: }
107:
108: /**
109: * Creates the "proxy method", e.g. the method that has the same name and
110: * signature as the original method but a completely other implementation.
111: *
112: * @param access
113: * @param name
114: * @param desc
115: * @param exceptions
116: * @param attrs
117: */
118: private void createProxyMethod(final int access, final String name,
119: final String desc, final String[] exceptions,
120: final Attribute attrs) {
121: CodeVisitor mv = cv.visitMethod(access, name, desc, exceptions,
122: attrs);
123:
124: //caller instance is null
125: mv.visitInsn(ACONST_NULL);
126:
127: int joinPointHash = AsmHelper.calculateMethodHash(name, desc);
128: String joinPointClassName = TransformationUtil
129: .getJoinPointClassName(m_declaringTypeName, name, desc,
130: m_declaringTypeName,
131: JoinPointType.STATIC_INITIALIZATION_INT,
132: joinPointHash);
133:
134: mv.visitMethodInsn(INVOKESTATIC, joinPointClassName,
135: INVOKE_METHOD_NAME, TransformationUtil
136: .getInvokeSignatureForCodeJoinPoints(access,
137: desc, m_declaringTypeName,
138: m_declaringTypeName));
139:
140: AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
141: mv.visitMaxs(0, 0);
142:
143: // emit the joinpoint
144: m_ctx.addEmittedJoinPoint(new EmittedJoinPoint(
145: JoinPointType.STATIC_INITIALIZATION_INT,
146: m_declaringTypeName, name, desc, access,
147: m_declaringTypeName, name, desc, access, joinPointHash,
148: joinPointClassName, EmittedJoinPoint.NO_LINE_NUMBER));
149: }
150: }
|