1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/* 2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project 3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License. 6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at 7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and 14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License. 15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.tools.layoutlib.create; 18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.objectweb.asm.ClassVisitor; 20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.objectweb.asm.MethodVisitor; 21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.objectweb.asm.Opcodes; 22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.Set; 24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/** 26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * A {@link DelegateClassAdapter} can transform some methods from a class into 27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * delegates that defer the call to an associated delegate class. 28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p/> 29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is used to override specific methods and or all native methods in classes. 30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic class DelegateClassAdapter extends ClassVisitor { 32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** Suffix added to original methods. */ 34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private static final String ORIGINAL_SUFFIX = "_Original"; 35c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta private static final String CONSTRUCTOR = "<init>"; 36c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta private static final String CLASS_INIT = "<clinit>"; 37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 38c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta public static final String ALL_NATIVES = "<<all_natives>>"; 39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final String mClassName; 41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final Set<String> mDelegateMethods; 42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski private final Log mLog; 43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski /** 45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Creates a new {@link DelegateClassAdapter} that can transform some methods 46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * from a class into delegates that defer the call to an associated delegate class. 47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p/> 48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is used to override specific methods and or all native methods in classes. 49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * 50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param log The logger object. Must not be null. 51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param cv the class visitor to which this adapter must delegate calls. 52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param className The internal class name of the class to visit, 53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * e.g. <code>com/android/SomeClass$InnerClass</code>. 54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param delegateMethods The set of method names to modify and/or the 55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * special constant {@link #ALL_NATIVES} to convert all native methods. 56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */ 57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public DelegateClassAdapter(Log log, 58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski ClassVisitor cv, 59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String className, 60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski Set<String> delegateMethods) { 61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski super(Opcodes.ASM4, cv); 62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mLog = log; 63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mClassName = className; 64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mDelegateMethods = delegateMethods; 65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski //---------------------------------- 68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Methods from the ClassAdapter 69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski @Override 71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski public MethodVisitor visitMethod(int access, String name, String desc, 72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski String signature, String[] exceptions) { 73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski boolean isNative = (access & Opcodes.ACC_NATIVE) != 0; 76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) || 78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mDelegateMethods.contains(name); 79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (!useDelegate) { 81c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta // Not creating a delegate for this method, pass it as-is from the reader to the writer. 82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return super.visitMethod(access, name, desc, signature, exceptions); 83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 85c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta if (CONSTRUCTOR.equals(name) || CLASS_INIT.equals(name)) { 86c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta // We don't currently support generating delegates for constructors. 87c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta throw new UnsupportedOperationException( 88c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta String.format( 89c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta "Delegate doesn't support overriding constructor %1$s:%2$s(%3$s)", //$NON-NLS-1$ 90c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta mClassName, name, desc)); 91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski if (isNative) { 94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Remove native flag 95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski access = access & ~Opcodes.ACC_NATIVE; 96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions); 97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 98c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta DelegateMethodAdapter a = new DelegateMethodAdapter( 99c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta mLog, null, mwDelegate, mClassName, name, desc, isStatic); 100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // A native has no code to visit, so we need to generate it directly. 102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski a.generateDelegateCode(); 103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski return mwDelegate; 105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // Given a non-native SomeClass.MethodName(), we want to generate 2 methods: 108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // - A copy of the original method named SomeClass.MethodName_Original(). 109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // The content is the original method as-is from the reader. 110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // - A brand new implementation of SomeClass.MethodName() which calls to a 111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski // non-existing method named SomeClass_Delegate.MethodName(). 112c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta // The implementation of this 'delegate' method is done in layoutlib_bridge. 113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski int accessDelegate = access; 115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski MethodVisitor mwOriginal = super.visitMethod(access, name + ORIGINAL_SUFFIX, 117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski desc, signature, exceptions); 118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski MethodVisitor mwDelegate = super.visitMethod(accessDelegate, name, 119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski desc, signature, exceptions); 120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski 121c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta return new DelegateMethodAdapter( 122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic); 123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski } 124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski} 125