All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jodd.proxetta.asm.package-info Maven / Gradle / Ivy

// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

/**
 * 

* This package assembles proxy classes. You will probably like to keep out from this code:) *

*

Replacements and modification rules

*

* During creation of proxy methods, several replacement and modification happens in order to produce valid proxy subclass. * Here is the list of all such rules. *

*

Add all constructors [A1]

*

* Proxy subclass must contain all constructors as target subclass. New constructors simply * delegates invocation to the super class. All constructor annotations are copied. *

*

Add the last method in chain [A2]

*

* Last method in proxy chain is the one that simply delegates the invocation to the target method in super class. *

*

Add all type annotations [A3]

*

* Proxy subclass must contain all type annotations as the target one. *

*

Copy all annotations to the first method in proxy method chain [A4]

*

* Proxy methods must contain all type annotations as the target one. *

*

Fix the offset of local variables [F1]

*

* Offset of all local variables has to be incremented by the size of target method argument list. * Size of arguments list is the number of 32bit words used by arguments on stack, which means that * all types has length of 1 word, except Long and Double that weight 2 words * (or one dword). *

*
*
 * iconst_1
 * istore_1
 * 
*
*
*
 * iconst_1
 * istore_13
 * 
*
*

* Here is the order of local variables:

*
    *
  • 0 - always 'this'
  • *
  • arguments (if exist)
  • *
  • locals (if exist)
  • *
*

* Therefore, index 0 is left as it is and offset will not be added to it. *

*
*

Replace ProxyTarget.argsCount [R2]

*

* Call to ProxyTarget.argsCount() has to be replaces with hardcoded arguments count. * Method call is simply replaces with appropriate load instruction: iload_n where n is in [0. 5]; * bipush n where n is in byte range; or sipush n when n is in integer range. *

*
*

Replace ProxyTarget.getArgType [R3]

*

* Call to ProxyTarget.getArgType(int ) has to be replaces with hardcoded argument Class, where argument * index is provided as an argument for ProxyTarget.getArgType(int ). * Method call is replaced with getClass() call on specified argument. If argument is an primitive * then method is replaced with reading the TYPE attribute of appropriate wrapper. *

*

* One caveat: opcode for pushing argument offset to stack is not removed from the bytecode, * due to performance issues of class creation. Instead, this value is poped from the stack before method call is replaced. * It is assumed that this value is an integer. *

*
*
 * iconst_1
 * invokestatic package/ProxyTarget.getArgClass
 * astore_1
 * iconst_2
 * invokestatic package/ProxyTarget.getArgClass
 * astore_2
 * 
*
*
*
 * (iconst_1
 * pop)
 * aload_1
 * invokevirtual java/lang/Object.getClass
 * astore 13
 * (iconst_2
 * pop)
 * getstatic java/lang/Byte.TYPE
 * astore 14
 * 
*
*
*

Replace ProxyTarget.getArg [R4]

*

* Call to ProxyTarget.getArg(int ) has to be replaces with hardcoded argument value, where * index is provided as an argument for ProxyTarget.getArg(int ). * If argument is a primitive, its wrapper object will be created. *

*
*
 * iconst_1
 * invokestatic package/ProxyTarget.getArg
 * astore_1
 * bipush 6
 * invokestatic package/ProxyTarget.getArg
 * astore_3
 * 
*
*
*
 * aload_1
 * astore_13
 * lload 6
 * invokestatic java/lang/Long.<init>
 * astore 14
 * 
*
*
*

Replace ProxyTarget.setArg [R5]

*

* Call to ProxyTarget.setArg(Object, int ) has to be replaces with hardcoded setting of the argument value, * where index is provided as an argument for ProxyTarget.setArg(Object, int ). * If argument is a primitive, its wrapper object must be provided. *

*

Replace ProxyTarget.createArgsArray [R6]

*

* Call to ProxyTarget.createArgsArray() has to be replaces with hardcoded creation of an object array, * where elements are target method arguments. Primitive arguments are wrapped. *

*

Replace ProxyTarget.invoke [R7]

*

* Call to ProxyTarget.invokeAndGetResult() has to be replaced with call to super target method. Since target methods * may have one or more arguments, it is required to push all arguments to the stack prior to call of super target method. * Note that aload_0 is always the first instruction (load this), no matter how many arguments there are. *

*
*
 * invokestatic package/ProxyTarget.invoke
 * 
*
*
*
 * aload_0
 * aload_1
 * iload_2
 * ...
 * invokespecial package/Target.method
 * 
*
*

* Situation here is a bit more complicated since return value must be provided, so the following fixes has to be * applied, too. *

*

Fix POP for ProxyTarget.invoke [F3]

*

* When ProxyTarget.invoke() is invoked without assignment, POP/POP2 instruction * is added afterwards, to remove the value from the stack. For targets that do not return void, this opcode * has to be fixed, i.e. removed. (Fact is that targets that return void, do not have POP:). *

*

Fix return value and Fix ASTORE for ProxyTarget.invoke [F4]

*

* When ProxyTarget.invoke() is invoked with assignment, xSTORE instruction * is added afterwards, to assign return value to a local variable. Therefore, it has to be loaded again on stack * before return. *

*

Creates all return values, performs casting for small types.

*

Replace ProxyTarget.getTargetClass [R9]

*

* Returns the target class. *

*

Replace ProxyTarget.getTargetMethodName [R10]

*

* Returns target method name. *

*

Replace ProxyTarget.getReturnType [R11]

*

* Returns return type of the target method or null if metod returns void. *

*

Fix field access [F5]

*

* Access to advice's fields has to be replaced with access to local fields. In relation with [A5]. *

*

Copy advice's fields to proxy [A5]

*

* All fields from advice has to be copied to proxy, with proxy index added to the name, to prevent duplicate names. *

*

Copy and fix advice static constructor [A6/F6]

*

* Static block of an advice should be copied to the proxy, with fixed field access (see F5). *

*

Copy and fix advices default constructors [A7/F7]

*

* Advice's constructor will be copied to regular methods, except first two instructions (calling super constructor) will be * ignored. Field access will be fixed (see F5). *

*/ package jodd.proxetta.asm;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy