Ejemplo n.º 1
0
def binaryLambda(
    objClass,
    method_name,
    argClass,
    interface=BiConsumer,
    interface_method="accept",
    classname=None,
    return_type="V",  # can be a class too
    as_instance=True
):  # return as an instance when True, as a class when False
    """
     Define a interface<O, A> with an interface_method with body O.method_name(A).
     For example, a BiConsumer with an "accept" method that takes two arguments an has arg1.method_name(arg2) as body.
  """
    if classname is None:
        classname = "asm/loop/%s_%s_%s_%s" % (
            interface.getSimpleName(), objClass.getSimpleName(), method_name,
            argClass.getSimpleName())

    cw = initClass(classname,
                   class_parameters=[("O", objClass), ("A", argClass)],
                   interfaces=[interface],
                   interfaces_parameters={interface: ["O", "A"]})

    mv = initMethod(cw,
                    interface_method,
                    argument_classes=[objClass, argClass],
                    return_type=return_type)
    mv.visitCode()
    # implement Obj.method_name(Arg)
    mv.visitVarInsn(Opcodes.ALOAD,
                    1)  # The first argument of the interface_method
    mv.visitVarInsn(Opcodes.ALOAD,
                    2)  # The second argument of the interface_method
    # Use the first loaded object as the object onto which to invoke method_name
    # and the second loaded object as its argument, so Obj.method_name(Arg)
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                       objClass.getName().replace(".", "/"), method_name,
                       "(L%s;)V" % argClass.getName().replace(".", "/"), False)
    mv.visitInsn(Opcodes.RETURN)
    mv.visitMaxs(2, 3)
    mv.visitEnd()

    # The interface_method was from an interface, so add a bridge method that checks casts
    initMethodObj(cw,
                  classname,
                  interface_method,
                  argument_classes=[objClass, argClass],
                  return_type=return_type)

    cw.visitEnd()

    lambdaClass = CustomClassLoader().defineClass(classname, cw.toByteArray())
    return lambdaClass.newInstance() if as_instance else lambdaClass
Ejemplo n.º 2
0
def defineBiConsumerTypeSet2(imglib2Type,
                             classname=None,
                             return_type="V"):  # can be a class too
    """ Exactly the same as defineBiConsumerTypeSet but using lib.asm library functions to cut to the chase. """
    if classname is None:
        classname = "asm/loop/BiConsumer_%s_set" % imglib2Type.getSimpleName()

    cw = initClass(classname,
                   class_parameters=[("T", imglib2Type)],
                   interfaces=[BiConsumer],
                   interfaces_parameters={BiConsumer: ["T", "T"]})

    mv = initMethod(cw,
                    "accept",
                    argument_classes=[imglib2Type, imglib2Type],
                    return_type=return_type)
    mv.visitCode()
    # implement t2.set(t1)
    mv.visitVarInsn(Opcodes.ALOAD, 2)  # load second argument first
    mv.visitVarInsn(Opcodes.ALOAD, 1)  # then load the first argument
    # Use the first loaded object as the object onto which to invoke "set", and the second loaded object as its argument, so t2.set(t1)
    typeClassname = imglib2Type.getName().replace(".", "/")
    mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, typeClassname, "set",
                       "(L%s;)V" % typeClassname, False)
    mv.visitInsn(Opcodes.RETURN)
    mv.visitMaxs(2, 3)
    mv.visitEnd()

    # The "accept" method was from an interface, so add a bridge method that checks casts
    initMethodObj(cw,
                  classname,
                  "accept",
                  argument_classes=[imglib2Type, imglib2Type],
                  return_type=return_type)

    cw.visitEnd()

    loader = CustomClassLoader()
    biconsumerClass = loader.defineClass(classname, cw.toByteArray())
    return biconsumerClass
Ejemplo n.º 3
0
def nthLambda(
    objClass,
    method_name,
    argClasses,  # a list, can be empty, max 14 elements
    interface,  # the interface with at least one generic type for objClass
    interface_method,  # with as many arguments as argClasses
    classname=None,
    return_type="V",  # can be a class too
    as_instance=True
):  # return as an instance when True, as a class when False
    """
     Define an interface<O, A1, A2, ...> with an interface_method with body O.method_name(A1, A2, ...).
     For example, a BiConsumer with an "accept(O arg1, A1 arg2)" method that takes two arguments an has arg1.method_name(arg2) as body.
     
     objClass: the class of the object onto which to invoke the method of name method_name with arguments of class as in argClasses.
     method_name: the name of the method to invoke on the objClass instance passed as the first argument of the interface method.
     argClasses: list of classes for the arguments of the method of method_name in objClass.
     interface: the class of the interface to implement with as many generic parameters as 1 + len(argClasses), e.g., BiConsumer<O, A>.
     interface_method: the name of the method to implement for the interface, e.g., "accept" for BiConsumer.
     classname: the name of the class to create implementing the interface. Will be autogenerated when None.
     return_type: return type of the interface method; defaults to "V" (void), can also be a class.
     as_instance: when True (default), return a new instance of the newly created class, otherwise return the class. 
  """
    if classname is None:
        classname = "asm/loop/%s_%s_%s_%s" % (
            interface.getSimpleName(), objClass.getSimpleName(), method_name,
            "_".join(argClass.getSimpleName() for argClass in argClasses))

    if len(argClasses) > 14:
        print "ERROR: nthLambda can't have more han 13 argClasses."
        return None

    parameters = [("O", objClass)] + zip("ABCDEFGHIJKLMN", argClasses)
    cw = initClass(classname,
                   class_parameters=parameters,
                   interfaces=[interface],
                   interfaces_parameters={
                       interface: [letter for letter, _ in parameters]
                   })

    mv = initMethod(cw,
                    interface_method,
                    argument_classes=[objClass] + argClasses,
                    return_type=return_type)
    mv.visitCode()
    # implement Obj.method_name(Arg1, Arg2, ...)
    for i in xrange(1, 1 + len(argClasses) + 1):
        mv.visitVarInsn(Opcodes.ALOAD, i)  # 1-based
    # Use the first loaded object as the object onto which to invoke method_name
    # and the second loaded object as its argument, so Obj.method_name(Arg)
    mv.visitMethodInsn(
        Opcodes.INVOKEVIRTUAL,
        objClass.getName().replace(".", "/"), method_name,
        "(%s)V" % "".join("L%s;" % argClass.getName().replace(".", "/")
                          for argClass in argClasses), False)
    mv.visitInsn(Opcodes.RETURN)
    mv.visitMaxs(1 + len(argClasses), 2 + len(argClasses))
    mv.visitEnd()

    # The interface_method was from an interface, so add a bridge method that checks casts
    initMethodObj(cw,
                  classname,
                  interface_method,
                  argument_classes=[objClass] + argClasses,
                  return_type=return_type)

    cw.visitEnd()

    lambdaClass = CustomClassLoader().defineClass(classname, cw.toByteArray())
    return lambdaClass.newInstance() if as_instance else lambdaClass
Ejemplo n.º 4
0
c.visitVarInsn(Opcodes.ALOAD, 0)
c.visitVarInsn(Opcodes.ALOAD, 1)
field = {
    "classname": "my/UnsignedByteToFloatAccess",
    "name": "sampler",
    "descriptor": "Lnet/imglib2/Sampler;"
}
c.visitFieldInsn(Opcodes.PUTFIELD, field["classname"], field["name"],
                 field["descriptor"])
c.visitInsn(Opcodes.RETURN)
c.visitMaxs(2, 2)
c.visitEnd()

# Declare getValue and setValue methods
gv = initMethod(facc,
                "getValue",
                access=Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,
                descriptor="(I)F")
gv.visitVarInsn(Opcodes.ALOAD, 0)
gv.visitFieldInsn(Opcodes.GETFIELD, field["classname"], field["name"],
                  field["descriptor"])
gv.visitMethodInsn(
    Opcodes.INVOKEINTERFACE,
    Type.getInternalName(Sampler),
    "get",
    "()L%s;" % Type.getInternalName(Object),  # isn't this weird? Why Object?
    True)
gv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(UnsignedByteType))
gv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                   Type.getInternalName(UnsignedByteType), "getRealFloat",
                   "()F", False)
gv.visitInsn(Opcodes.FRETURN)  # native float return
Ejemplo n.º 5
0
def defineSamplerConverter(
        fromType,
        toType,
        classname="",
        toAccess=None,
        fromMethod="getRealFloat",
        fromMethodReturnType="F",  # F: native float; if a class, use: "L%s;" % Type.getInternalName(TheClass)
        toMethod="setReal",
        toMethodArgType="F"):  # F: native float
    """ A class implementing SamplerConverter, in asm for high-performance (25x jython's speed).

      fromType: the source type to convert like e.g. UnsignedByteType.
      toType: the target type, like e.g. FloatType.
      classname: optional, the fully qualified name for the new class implementing SamplerConverter.
      fromMethod: the name of the fromType class method to use for getting its value.
                  Defaults to "getRealFloat" from the RealType interface.
      fromMethodReturnType: a single letter, like:
        'F': float, 'D': double, 'C': char, 'B': byte, 'Z': boolean, 'S': short, 'I': integer, 'J': long
        See: https://gitlab.ow2.org/asm/asm/blob/master/asm/src/main/java/org/objectweb/asm/Frame.java
      toMethod: the name of the toType class method for setting the value.
                Defaults to "setReal" from the RealType interface.
      toMethodArgType: a single letter, like:
        'F': float, 'D': double, 'C': char, 'B': byte, 'Z': boolean, 'S': short, 'I': integer, 'J': long
      toAccess: the interface to implement, such as FloatAccess. Optional, will be guessed. """

    if toAccess is None:
        toTypeName = toType.getSimpleName()
        name = toTypeName[0:toTypeName.rfind("Type")]
        if name.startswith("Unsigned"):
            name = name[8:]
        toAccessName = "net.imglib2.img.basictypeaccess.%sAccess" % name
        toAccess = CustomClassLoader().loadClass(
            "net.imglib2.img.basictypeaccess.%sAccess" % name)

    if "" == classname:
        classname = "asm/converters/%sTo%sSamplerConverter" % (
            fromType.getSimpleName(), toType.getSimpleName())

    access_classname = "asm/converters/%sTo%sAccess" % (
        fromType.getSimpleName(), toType.getSimpleName())

    # First *Access class like e.g. FloatAccess
    facc = initClass(access_classname,
                     access=Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,
                     interfaces=[toAccess],
                     interfaces_parameters={},
                     with_default_constructor=False)

    # private final "sampler" field
    f = facc.visitField(
        Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "sampler",
        "L%s;" % Type.getInternalName(Sampler),
        "L%s<+L%s;>;" % tuple(imap(Type.getInternalName,
                                   (Sampler, fromType))), None)

    # The constructor has to initialize the field "sampler"
    c = initConstructor(facc,
                        descriptor="(Lnet/imglib2/Sampler;)V",
                        signature="(Lnet/imglib2/Sampler<+L%s;>;)V" %
                        Type.getInternalName(fromType))
    # The 'c' constructor already invoked <init>
    # Now onto the rest of the constructor body:
    c.visitVarInsn(Opcodes.ALOAD, 0)
    c.visitVarInsn(Opcodes.ALOAD, 1)
    field = {
        "classname": access_classname,
        "name": "sampler",
        "descriptor": "Lnet/imglib2/Sampler;"
    }
    c.visitFieldInsn(Opcodes.PUTFIELD, field["classname"], field["name"],
                     field["descriptor"])
    c.visitInsn(Opcodes.RETURN)
    c.visitMaxs(2, 2)
    c.visitEnd()

    # Declare getValue and setValue methods
    gv = initMethod(facc,
                    "getValue",
                    access=Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,
                    descriptor="(I)%s" %
                    toMethodArgType)  # e.g. "F" for native float
    gv.visitVarInsn(Opcodes.ALOAD, 0)
    gv.visitFieldInsn(Opcodes.GETFIELD, field["classname"], field["name"],
                      field["descriptor"])
    gv.visitMethodInsn(
        Opcodes.INVOKEINTERFACE,
        Type.getInternalName(Sampler),
        "get",
        "()L%s;" %
        Type.getInternalName(Object),  # isn't this weird? Why Object?
        True)
    gv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(fromType))
    print Type.getInternalName(fromType), fromMethod, fromMethodReturnType
    gv.visitMethodInsn(
        Opcodes.INVOKEVIRTUAL,
        Type.getInternalName(fromType),
        fromMethod,  # e.g. getRealFloat
        "()%s" % fromMethodReturnType,  # e.g. F for native float
        False)
    # Figure out the return and the loading instructions: primitive or object class
    # (NOTE: will not work for array, that starts with '[')
    if fromMethodReturnType in ["F", "D"]:  # 'F' for float, 'D' for double
        ret = fromMethodReturnType + "RETURN"
        load = fromMethodReturnType + "LOAD"
    elif 'J' == fromMethodReturnType:  # 'J' is for long
        ret = "LRETURN"
        load = "LLOAD"
    elif fromMethodReturnType in [
            "S", "I", "B", "C", "Z"
    ]:  # 'C': char, 'B': byte, 'Z', boolean, 'S', short, 'I': integer
        ret = "IRETURN"
        load = "ILOAD"
    else:
        ret = "ARETURN"  # object class
        load = "ALOAD"
    gv.visitInsn(Opcodes.__getattribute__(
        Opcodes, ret)._doget(Opcodes))  # Opcodes.FRETURN: native float return
    gv.visitMaxs(1, 2)
    gv.visitEnd()

    sv = initMethod(facc,
                    "setValue",
                    access=Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,
                    descriptor="(I%s)V" %
                    toMethodArgType)  # e.g. "F" for native float
    sv.visitVarInsn(Opcodes.ALOAD, 0)
    sv.visitFieldInsn(Opcodes.GETFIELD, field["classname"], field["name"],
                      field["descriptor"])
    sv.visitMethodInsn(
        Opcodes.INVOKEINTERFACE,
        Type.getInternalName(Sampler),
        "get",
        "()L%s;" %
        Type.getInternalName(Object),  # isn't this weird? Why Object?
        True)
    sv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(fromType))
    sv.visitVarInsn(
        Opcodes.__getattribute__(Opcodes, load)._doget(Opcodes),
        2)  # e.g. Opcodes.FLOAD
    sv.visitMethodInsn(
        Opcodes.INVOKEVIRTUAL,
        Type.getInternalName(fromType),
        toMethod,  # e.g. setReal
        "(%s)V" % toMethodArgType,  # e.g. 'F' for native float
        False)
    sv.visitInsn(Opcodes.RETURN)
    sv.visitMaxs(2, 3)
    sv.visitEnd()

    # The SamplerConverter outer class
    cw = initClass(
        classname,
        interfaces=[SamplerConverter],
        interfaces_parameters={SamplerConverter: [fromType, toType]})

    # In the signature, the + sign is for e.g. <? extends UnignedByteType>
    # Here, the signature is the same as the descriptor, but with parameter types
    # descriptor="(Lnet/imglib2/Sampler;)Lnet/imglib2/type/numeric/real/FloatType;"
    # signature="(Lnet/imglib2/Sampler<+Lnet/imglib2/type/numeric/integer/UnsignedByteType;>;)Lnet/imglib2/type/numeric/real/FloatType;",
    m = initMethod(
        cw,
        "convert",
        argument_classes=[Sampler],
        argument_parameters=[fromType],
        argument_prefixes=['+'],  # '+' means: <? extends UnsignedByteType>
        return_type=toType)

    m.visitCode()
    m.visitTypeInsn(Opcodes.NEW, Type.getInternalName(toType))
    m.visitInsn(Opcodes.DUP)
    m.visitTypeInsn(Opcodes.NEW, access_classname)
    m.visitInsn(Opcodes.DUP)
    m.visitVarInsn(Opcodes.ALOAD, 1)
    m.visitMethodInsn(
        Opcodes.INVOKESPECIAL,  # invoke new
        access_classname,
        "<init>",  # constructor
        "(L%s;)V" % Type.getInternalName(Sampler),
        False)
    m.visitMethodInsn(
        Opcodes.
        INVOKESPECIAL,  # create new toType with the *Access as argument
        Type.getInternalName(toType),
        "<init>",  # constructor
        "(L%s;)V" % Type.getInternalName(toAccess),
        False)
    m.visitInsn(
        Opcodes.ARETURN)  # ARETURN: return the object at the top of the stack
    m.visitMaxs(
        5, 2
    )  # 5 stack slots: the two NEW calls, 1 ALOAD, 2 DUP (I think). And 2 local variables: this, and a method argument.
    m.visitEnd()

    # If bridge is not defined, the above 'convert' method cannot be invoked: would fail with AbstractMethodException
    # To be fair, the TextWriter on the compiled java version of this class did use the bridge.
    # The surprising bit is that, in test_asm_class_generation.py, the bridge is not necessary
    # even though the class is rather similar overall.
    bridge = cw.visitMethod(
        Opcodes.ACC_PUBLIC | Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE,
        "convert",
        "(L%s;)L%s;" % tuple(imap(Type.getInternalName,
                                  (Sampler, Object))), None, None)
    bridge.visitCode()
    bridge.visitVarInsn(Opcodes.ALOAD, 0)
    bridge.visitVarInsn(Opcodes.ALOAD, 1)
    bridge.visitMethodInsn(
        Opcodes.INVOKEVIRTUAL,
        classname,
        "convert",
        "(L%s;)L%s;" % tuple(imap(Type.getInternalName,
                                  (Sampler, toType))),  # descriptor
        False)
    bridge.visitInsn(Opcodes.ARETURN)
    bridge.visitMaxs(2, 2)
    bridge.visitEnd()

    # Load both classes
    loader = CustomClassLoader()
    accessClass = loader.defineClass(access_classname, facc.toByteArray())
    samplerClass = loader.defineClass(classname, cw.toByteArray())

    return samplerClass