Packages

o

org.opalj.br.instructions

ClassFileFactory

object ClassFileFactory

Provides helper methods to facilitate the generation of classes. In particular, functionality to create transparent proxy classes is provided.

Source
ClassFileFactory.scala
Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. ClassFileFactory
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. Protected

Value Members

  1. final def !=(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  2. final def ##: Int
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean
    Definition Classes
    AnyRef → Any
  4. final val AlternativeFactoryMethodName: String("$createInstance")

    Alternative name for the factory method of proxy classes created by the Proxy method.

    Alternative name for the factory method of proxy classes created by the Proxy method. This name is only used if the proxified method's name is equal to DefaultFactoryMethodName.

  5. final val DefaultFactoryMethodName: String("$newInstance")

    This is the default name for the factory method of a proxy class that is created by the Proxy method.

    This is the default name for the factory method of a proxy class that is created by the Proxy method. If the name of the method to be proxified is equal to this name, AlternativeFactoryMethodName is used instead.

  6. def DeserializeLambdaProxy(definingType: TypeDeclaration, bootstrapArguments: BootstrapArguments, staticMethodName: String): ClassFile
  7. def Proxy(caller: ObjectType, callerIsInterface: Boolean, definingType: TypeDeclaration, methodName: String, methodDescriptor: MethodDescriptor, receiverType: ObjectType, receiverIsInterface: Boolean, implMethod: MethodCallMethodHandle, invocationInstruction: Opcode, samMethodType: MethodDescriptor, bridgeMethodDescriptors: MethodDescriptors): ClassFile

    Creates a class that acts as a proxy for the specified class.

    Creates a class that acts as a proxy for the specified class. The proxy implements a single method – e.g., as defined by a so-called "Functional Interface" - that calls the specified method; creating a proxy for java.lang.Object's methods is not supported. Additionally, further marker interfaces (e.g., java.io.Serializable) may be implemented.

    The generated class uses the following template:

    class <definingType.objectType>
     extends <definingType.theSuperclassType>
     implements <definingType.theSuperinterfaceTypes> {
    
     private final <ReceiverType> receiver;
    
     // possible additional fields for static parameters
    
     public "<init>"( <ReceiverType> receiver) { // the constructor
         this.receiver = receiver;
     }
    
     public <methodDescriptor.returnType> <methodName> <methodDescriptor.parameterTypes>{
        return/*<= if the return type is not void*/ this.receiver.<receiverMethodName>(<parameters>)
     }
    
     // possibly multiple bridge methods (multiple only in case of altLambdaMetaFactory usages)
    }

    The class, the constructor and the method are public. The field which holds the receiver object is private and final unless the receiver method is static. In this case no receiver field is generated and the constructor does not take an argument of the receiver's type.

    In addition to the receiver field, additional fields holding static parameters are created if all parameters found in methodDescriptor are present, in the same order, at the end of receiverMethodDescriptor's parameters, but receiverMethodDescriptor has more parameters that precede the parameters found in methodDescriptor.

    E.g., given the following two descriptors:

    val methodDescriptor =
     MethodDescriptor(IntegerType, IntegerType)
    val receiverMethodDescriptor =
     MethodDescriptor(IndexedSeq(DoubleType, IntegerType), IntegerType)

    one additional field and constructor parameter of type double will be created. This case occurs for example with Java 8 lambda expressions that capture local variables, which are prepended to the regular parameter list.

    If any of the parameters or the return type of methodDescriptor are generic types, the generated proxy will need to create a bridge method to be valid. Therefore, in these cases, bridgeMethodDescriptor must be specified. It must be identical to methodDescriptor except for all occurrences of generic types, which must be replaced with ObjectType.Object. For example, consider the Java interface java.util.Comparator that defines the generic type T and uses it in its int compare(T, T) method. This would require a bridge method int compare(Object, Object). The appropriate method descriptors for, for example, Comparator<String> would be:

    // Uses "String"
    methodDescriptor =
     MethodDescriptor(IndexedSeq(ObjectType.String, ObjectType.String), IntegerType)
    // Uses "Object"
    bridgeMethodDescriptor =
     MethodDescriptor(IndexedSeq(ObjectType.Object, ObjectType.Object), IntegerType)

    The created class will always have its synthetic access flag set, as well as the VirtualTypeFlag attribute.

    definingType

    The defining type; if the type is Serializable, the interface has to be a direct super interface.

    invocationInstruction

    the opcode of the invocation instruction (INVOKESPECIAL.opcode,INVOKEVIRTUAL.opcode, INVOKESTATIC.opcode,INVOKEINTERFACE.opcode) used to call call the method on the receiver.

    Note

    The used class file version is 52. (StackMapTables are, however, still not required because the code contains no relevant control-flow.)

    ,

    It is expected that methodDescriptor and receiverMethodDescriptor are "compatible", i.e., it would be possible to have the method described by methodDescriptor forward to receiverMethodDescriptor. This requires that for their return types, one of the following statements holds true: - methodDescriptor's return type is VoidType (so no returning is necessary) - receiverMethodDescriptor's return type is assignable to methodDescriptor's (e.g., a "smaller" numerical type, (un)boxable, a subtype, etc) - receiverMethodDescriptor returns Object: in this case, we assume that Object stands for "generic return type" and expect the receiver method to return an object of a type compatible to the forwarder method's return type Additionally, the parameter lists must satisfy one of these conditions: - they are identical - the descriptors have the same numbers of parameters and methodDescriptor's parameter types can be widened/boxed/unboxed to match receiverMethodDescriptor's parameter types - methodDescriptor's first parameter is of the same type as receiverType, and the remaining parameters are compatible to receiverMethodDescriptor's entire parameter list (this is, effectively, an explicit this and occurs for example with references to instance methods: e.g., String::isEmpty, a zero argument method, could be turned into the Predicate method test(String)) - the last n parameters of receiverMethodDescriptor are identical to the parameters of methodDescriptor, where n = methodDescriptor.parametersCount (this is the case if a lambda expression captures local variables) - receiverMethodDescriptor's single parameter is of type Object[] (in this case, methodDescriptor's arguments will be collected into an Object[] prior to forwarding) Examples of compatible method descriptors are:

    // ------------- First Example
    methodDescriptor =
     MethodDescriptor(IntegerType, VoidType)
    receiverMethodDescriptor =
     MethodDescriptor(ObjectType.Integer, VoidType)
     // or MethodDescriptor(ObjectType.Object, ByteType)
    
    // ------------- Second Example
    methodDescriptor =
     MethodDescriptor(ObjectType.String, BooleanType)
    receiverMethodDescriptor =
     MethodDescriptor.JustReturnsBoolean // IF receiverType == ObjectType.String
    
    // ------------- Third Example
    methodDescriptor =
     MethodDescriptor(IndexedSeq(ByteType, ByteType, ObjectType.Integer), IntegerType)
    receiverMethodDescriptor =
     MethodDescriptor(ArrayType.ArrayOfObject, ObjectType.Object) // generic method
    
    // ------------- Fourth Example
    methodDescriptor =
     MethodDescriptor(IntegerType, LongType)
    receiverMethodDescriptor =
     MethodDescriptor(IndexedSeq(ByteType, ByteType, IntegerType), IntegerType)
  8. final val ReceiverFieldName: String("$receiver")

    Name used to store the final receiver object in generated proxy classes.

  9. final def asInstanceOf[T0]: T0
    Definition Classes
    Any
  10. def callSuperDefaultConstructor(theSuperclassType: ObjectType): Array[Instruction]

    Returns the instructions necessary to perform a call to the constructor of the given superclass.

  11. def clone(): AnyRef
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.CloneNotSupportedException]) @native() @IntrinsicCandidate()
  12. def cloneMethodSignature: MethodSignature
  13. def copyParametersToInstanceFields(declaringType: ObjectType, fields: FieldTemplates): Array[Instruction]

    Creates an array of instructions that populates the given fields in declaringType from local variables (constructor parameters).

    Creates an array of instructions that populates the given fields in declaringType from local variables (constructor parameters).

    This method assumes that it creates instructions for a constructor whose parameter list matches the given fields in terms of order and field types.

    It further assumes that none of the fields provided as arguments are static fields, as it would make little sense to initialize static fields through the constructor.

  14. def createBridgeMethod(methodName: String, bridgeMethodDescriptor: MethodDescriptor, targetMethodDescriptor: MethodDescriptor, targetMethodDeclaringType: ObjectType): MethodTemplate

    Creates a bridge method using the given method descriptors, name, and type.

    Creates a bridge method using the given method descriptors, name, and type.

    The bridge method's parameter list and return type are dictated by bridgeMethodDescriptor. This method generates bytecode that invokes the method described by methodName and targetMethodDescriptor on declaringType. If parameters need to be cast before invocation, the appropriate bytecode will be generated as well.

  15. def createConstructor(definingType: TypeDeclaration, fields: FieldTemplates): MethodTemplate

    Creates a public constructor that initializes the given fields.

    Creates a public constructor that initializes the given fields.

    For every Field in fields the constructor will have one parameter of the same type. The parameter list will have the same order as fields. The generated constructor will call the superclass' default constructor; i.e., the type definingType.theSuperclassType has to have a default constructor. Additionally, bytecode is generated to populate the fields from the constructor arguments.

    See also

    callSuperDefaultConstructor

    copyParametersToInstanceFields

  16. def createDeserializeLambdaProxy(caller: ObjectType, callerIsInterface: Boolean): MethodTemplate

    Creates a static proxy method used by the $deserializeLambda$ method.

    Creates a static proxy method used by the $deserializeLambda$ method.

    caller

    The class where the lambda is implemented.

    callerIsInterface

    true if the class is an interface, false if not.

    returns

    The static proxy method relaying the $deserializedLambda$ invocation to the actual class that implements the lambda.

  17. def createFactoryMethod(typeToCreate: ObjectType, fieldTypes: FieldTypes, factoryMethodName: String): MethodTemplate

    Creates a factory method with the appropriate instructions to create and return an instance of typeToCreate.

    Creates a factory method with the appropriate instructions to create and return an instance of typeToCreate.

    typeToCreate must have a constructor with a parameter list that exactly matches fieldTypes. It also must not define a method named factoryMethodName with a parameter list matching fieldTypes.

    See also

    createConstructor

  18. def createField(accessFlags: Int = bi.ACC_PRIVATE.mask | bi.ACC_FINAL.mask, name: String, fieldType: FieldType, attributes: Attributes = NoAttributes): FieldTemplate

    Creates a field of the specified type with the given name.

  19. def createWriteReplaceMethod(definingType: TypeDeclaration, methodName: String, samMethodType: MethodDescriptor, implMethod: MethodCallMethodHandle, instantiatedMethodType: MethodDescriptor, additionalFieldsForStaticParameters: FieldTemplates): MethodTemplate

    Creates the writeReplace method for a lambda proxy class.

    Creates the writeReplace method for a lambda proxy class. It is used to create a SerializedLambda object which holds the serialized lambda.

    The parameters of the SerializedLambda class map are as following: capturingClass = definingType functionalInterfaceClass = definingType.theSuperinterfaceTypes.head (This is the functional interface) functionalInterfaceMethodName = functionalInterfaceMethodName functionalInterfaceMethodSignature = samMethodType.parameterType implMethodKind = implMethod match to REF_ implClass = implMethod.receiverType implMethodName = implMethod.name implMethodSignature = implMethod.methodDescriptor instantiatedMethodType = instantiatedMethodType capturedArgs = methodDescriptor.parameterTypes (factoryParameters, fields in Proxy)

    definingType

    The lambda proxyclass type.

    methodName

    The name of the functional interface method.

    samMethodType

    Includes the method signature for the functional interface method.

    implMethod

    The lambda method inside the class defining the lambda.

    additionalFieldsForStaticParameters

    The static fields that are put into the capturedArgs.

    returns

    A SerializedLambda object containing all information to be able to serialize this lambda.

    See also

    https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/SerializedLambda.html and https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html#altMetafactory-java.lang.invoke.MethodHandles.Lookup-java.lang.String-java.lang.invoke.MethodType-java.lang.Object...-

  20. final def eq(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  21. def equals(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef → Any
  22. def equalsMethodSignature: MethodSignature
  23. def finalizeMethodSignature: MethodSignature
  24. final def getClass(): Class[_ <: AnyRef]
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @IntrinsicCandidate()
  25. def hashCode(): Int
    Definition Classes
    AnyRef → Any
    Annotations
    @native() @IntrinsicCandidate()
  26. def hashCodeMethodSignature: MethodSignature
  27. final def isInstanceOf[T0]: Boolean
    Definition Classes
    Any
  28. def isNewInvokeSpecial(opcode: Opcode, methodName: String): Boolean

    Returns true if the method invocation described by the given Opcode and method name is a "NewInvokeSpecial" invocation (i.e., a reference to a constructor, like so: Object::new).

  29. def isVirtualMethodReference(opcode: Opcode, targetMethodDeclaringType: ObjectType, targetMethodDescriptor: MethodDescriptor, proxyInterfaceMethodDescriptor: MethodDescriptor): Boolean

    Returns true if the given parameters identify a Java 8 method reference to an instance or interface method (i.e., a reference to a virtual method, like so: ArrayList::size or List::size).

    Returns true if the given parameters identify a Java 8 method reference to an instance or interface method (i.e., a reference to a virtual method, like so: ArrayList::size or List::size). In this case, the resulting functional interface's method has one parameter more than the referenced method because the referenced method's implicit this parameter becomes explicit.

  30. final def ne(arg0: AnyRef): Boolean
    Definition Classes
    AnyRef
  31. def nonFinalInterfaceOfObject(): Array[MethodSignature]
  32. final def notify(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @IntrinsicCandidate()
  33. final def notifyAll(): Unit
    Definition Classes
    AnyRef
    Annotations
    @native() @IntrinsicCandidate()
  34. def parameterForwardingInstructions(forwarderMethodDescriptor: MethodDescriptor, receiverMethodDescriptor: MethodDescriptor, variableOffset: Int, staticParameters: Seq[FieldTemplate], definingType: ObjectType): Array[Instruction]

    Generates an array of instructions that fill the operand stack with all parameters required by receiverMethodDescriptor from the parameters of calledMethodDescriptor.

    Generates an array of instructions that fill the operand stack with all parameters required by receiverMethodDescriptor from the parameters of calledMethodDescriptor. For that reason, it is expected that both method descriptors have compatible parameter and return types: i.e., that forwarderMethodDescriptor's parameters can be widened or (un)boxed to fit into receiverMethodDescriptor's parameters, and that receiverMethodDescriptor's return type can be widened or (un)boxed to fit into forwarderMethodDescriptor's return type.

    If receiverMethodDescriptor has more parameters than forwarderMethodDescriptor, the missing parameters must be provided in staticParameters.

    See also

    org.opalj.br.instructions.LoadLocalVariableInstruction

  35. def proxyMethod(definingType: ObjectType, methodName: String, methodDescriptor: MethodDescriptor, staticParameters: Seq[FieldTemplate], receiverType: ObjectType, receiverIsInterface: Boolean, implMethod: MethodCallMethodHandle, invocationInstruction: Opcode): MethodTemplate

    Creates a proxy method with name methodName and descriptor methodDescriptor and the bytecode instructions to execute the method receiverMethod in receiverType.

    Creates a proxy method with name methodName and descriptor methodDescriptor and the bytecode instructions to execute the method receiverMethod in receiverType.

    The methodDescriptors have to be identical in terms of parameter types and have to be compatible w.r.t. the return type.

  36. def returnAndConvertInstructions(toBeReturnedType: FieldType, typeOnStack: FieldType): Array[Instruction]

    Returns the instructions that return a value of type typeToBeReturned, converting typeOnStack to it first if necessary.

    Returns the instructions that return a value of type typeToBeReturned, converting typeOnStack to it first if necessary. If typeOnStack is Object, it will be treated as a generic return type and converted to the required type.

    Annotations
    @throws("if `typeOnStack` is not compatible with `toBeReturnedType` and `typeOnStack` is not `Object`")
  37. final def synchronized[T0](arg0: => T0): T0
    Definition Classes
    AnyRef
  38. def toString(): String
    Definition Classes
    AnyRef → Any
  39. def toStringSignature: MethodSignature
  40. final def wait(arg0: Long, arg1: Int): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  41. final def wait(arg0: Long): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])
  42. final def wait(): Unit
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.InterruptedException])

Deprecated Value Members

  1. def finalize(): Unit
    Attributes
    protected[lang]
    Definition Classes
    AnyRef
    Annotations
    @throws(classOf[java.lang.Throwable]) @Deprecated
    Deprecated

Inherited from AnyRef

Inherited from Any

Ungrouped