Package com.dragome.compiler.invokedynamic

Source Code of com.dragome.compiler.invokedynamic.InvokeDynamicBackporter$InvokeDynamicInsnConvertingMethodVisitor

/*******************************************************************************
* Copyright (c) 2011-2014 Fernando Petrola
*
* This file is part of Dragome SDK.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
******************************************************************************/

package com.dragome.compiler.invokedynamic;

import static org.objectweb.asm.Opcodes.INVOKESTATIC;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;

import com.dragome.commons.compiler.BytecodeTransformer;

public class InvokeDynamicBackporter implements BytecodeTransformer
{
  public static byte[] transform(byte[] bytecode)
  {
    ClassNode classNode= new ClassNode(Opcodes.ASM5);
    InvokeDynamicConverter invokeDynamicConverter= new InvokeDynamicConverter(classNode);
    new ClassReader(bytecode).accept(invokeDynamicConverter, 0);
    ClassWriter cw= new ClassWriter(ClassWriter.COMPUTE_MAXS);
    classNode.accept(cw);
    return cw.toByteArray();
  }

  private static class InvokeDynamicConverter extends ClassVisitor
  {
    private int classAccess;
    private String className;

    public InvokeDynamicConverter(ClassVisitor next)
    {
      super(Opcodes.ASM5, next);
    }

    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
    {
      super.visit(version, access, name, signature, superName, interfaces);
      this.classAccess= access;
      this.className= name;
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions)
    {
      if (isBridgeMethodOnInterface(access))
      {
        return null;
      }
      if (isNonAbstractMethodOnInterface(access) && !isClassInitializerMethod(name, desc, access))
      {
        //        System.out.println("WARNING: Method '" + name + "' of interface '" + className + "' is non-abstract! " + "This will probably fail to run on Java 7 and below. " + "If you get this warning _without_ using Java 8's default methods, " + "please report a bug at https://github.com/orfjackal/retrolambda/issues " + "together with an SSCCE (http://www.sscce.org/)");
      }
      MethodVisitor mv= super.visitMethod(access, name, desc, signature, exceptions);
      return new InvokeDynamicInsnConvertingMethodVisitor(api, mv, className);
    }

    private boolean isBridgeMethodOnInterface(int methodAccess)
    {
      return Flags.hasFlag(classAccess, Opcodes.ACC_INTERFACE) && Flags.hasFlag(methodAccess, Opcodes.ACC_BRIDGE);
    }

    private boolean isNonAbstractMethodOnInterface(int methodAccess)
    {
      return Flags.hasFlag(classAccess, Opcodes.ACC_INTERFACE) && !Flags.hasFlag(methodAccess, Opcodes.ACC_ABSTRACT);
    }

    private static boolean isClassInitializerMethod(String name, String desc, int methodAccess)
    {
      return name.equals("<clinit>") && desc.equals("()V") && Flags.hasFlag(methodAccess, Opcodes.ACC_STATIC);
    }
  }

  private static class InvokeDynamicInsnConvertingMethodVisitor extends MethodVisitor
  {
    private final String myClassName;

    public InvokeDynamicInsnConvertingMethodVisitor(int api, MethodVisitor mv, String myClassName)
    {
      super(api, mv);
      this.myClassName= myClassName;
    }

    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs)
    {
      backportLambda(name, Type.getType(desc), bsm, bsmArgs);
    }

    private void backportLambda(String invokedName, Type invokedType, Handle bsm, Object[] bsmArgs)
    {
      Type[] argumentTypes= Type.getArgumentTypes(invokedType.toString());
      Type returnType= Type.getReturnType(invokedType.toString());
      String returnTypeName= returnType.getClassName();

      int length= argumentTypes.length;

      createArrayWithParameters(length, argumentTypes);

      this.visitLdcInsn(myClassName);
      this.visitLdcInsn(invokedName);
      this.visitLdcInsn(returnTypeName);
      this.visitLdcInsn(invokedType.toString());
      this.visitLdcInsn(bsmArgs[1].toString());

      this.visitVarInsn(Opcodes.ALOAD, 20);
      this.visitLdcInsn(bsm.getTag() == 5 ? "virtual" : "static");

      String runnableSignature= "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;";
      this.visitMethodInsn(INVOKESTATIC, "com/dragome/utils/DragomeCallsiteFactory", "create", runnableSignature, false);
    }

    private void createArrayWithParameters(int parametersCount, Type[] argumentTypes)
    {
      this.visitIntInsn(Opcodes.BIPUSH, parametersCount);
      this.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
      this.visitVarInsn(Opcodes.ASTORE, 20);

      for (int i= parametersCount - 1; i >= 0; i--)
      {
        convertPrimitive(argumentTypes[i], i);
        this.visitVarInsn(Opcodes.ASTORE, 21);
        this.visitVarInsn(Opcodes.ALOAD, 20);
        this.visitIntInsn(Opcodes.BIPUSH, i);
        this.visitVarInsn(Opcodes.ALOAD, 21);
        this.visitInsn(Opcodes.AASTORE);
      }
    }

    private void convertPrimitive(Object tp, int i)
    {
      if (tp.equals(Type.BOOLEAN_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
      }
      else if (tp.equals(Type.BYTE_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
      }
      else if (tp.equals(Type.CHAR_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
      }
      else if (tp.equals(Type.SHORT_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
      }
      else if (tp.equals(Type.INT_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
      }
      else if (tp.equals(Type.LONG_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
        i++;
      }
      else if (tp.equals(Type.FLOAT_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
      }
      else if (tp.equals(Type.DOUBLE_TYPE))
      {
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
        i++;
      }
      //      else
      //        mv.visitVarInsn(Opcodes.ALOAD, i);
    }
  }

  public byte[] transform(String className, byte[] bytecode)
  {
    return transform(bytecode);
  }

  public boolean requiresTransformation(String className)
  {
    return true;
  }
}
TOP

Related Classes of com.dragome.compiler.invokedynamic.InvokeDynamicBackporter$InvokeDynamicInsnConvertingMethodVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.