public MethodVisitor visitMethod(
      final int access, final String name, String desc, String signature, String[] exceptions) {
    final MethodVisitor methodvisitor = cv.visitMethod(access, name, desc, signature, exceptions);

    // patch static initializer
    if ((access & ACC_STATIC) != 0 && name.equals("<clinit>")) {
      myHasStaticInitializer = true;

      return new MethodVisitor(Opcodes.ASM5, methodvisitor) {
        public void visitCode() {
          super.visitCode();
          patchStaticInitializer(mv);
        }
      };
    }

    final Type[] argTypes = Type.getArgumentTypes(desc);
    final Type returnType = Type.getReturnType(desc);

    // don't dig through the whole method if there's nothing to do in it
    if (isStringType(returnType)) {
      return new InstrumentationAdapter(this, methodvisitor, argTypes, returnType, access, name);
    } else {
      for (Type type : argTypes) {
        if (isStringType(type)) {
          return new InstrumentationAdapter(
              this, methodvisitor, argTypes, returnType, access, name);
        }
      }
    }

    return methodvisitor;
  }
 public MethodVisitor visitMethod(
     int access, String name, String desc, String signature, String[] exceptions) {
   Type[] args = Type.getArgumentTypes(desc);
   Type returnType = Type.getReturnType(desc);
   int startParameter = getStartParameterIndex(name);
   MethodVisitor v = cv.visitMethod(access, name, desc, signature, exceptions);
   return new MyMethodAdapter(this, v, args, returnType, access, startParameter, name);
 }
 private static String parseMethodViaDescription(
     final String desc, final PsiMethodStubImpl stub, final List<String> args) {
   final String returnType = getTypeText(Type.getReturnType(desc));
   final Type[] argTypes = Type.getArgumentTypes(desc);
   for (Type argType : argTypes) {
     args.add(getTypeText(argType));
   }
   new PsiTypeParameterListStubImpl(stub);
   return returnType;
 }
Exemplo n.º 4
0
 private void unwrapResult(final MethodVisitor mv, final String desc) {
   Type returnType = Type.getReturnType(desc);
   if (returnType == Type.VOID_TYPE) {
     mv.visitInsn(POP);
     mv.visitInsn(RETURN);
   } else {
     if (isPrimitive(returnType)) {
       BytecodeHelper.unbox(mv, ClassHelper.make(returnType.getClassName()));
     } else {
       mv.visitTypeInsn(CHECKCAST, returnType.getInternalName());
     }
     mv.visitInsn(getReturnInsn(returnType));
   }
 }
Exemplo n.º 5
0
  @NotNull
  public MethodNode prepareNode(@NotNull MethodNode node) {
    final int capturedParamsSize = parameters.getCaptured().size();
    final int realParametersSize = parameters.getReal().size();
    Type[] types = Type.getArgumentTypes(node.desc);
    Type returnType = Type.getReturnType(node.desc);

    ArrayList<Type> capturedTypes = parameters.getCapturedTypes();
    Type[] allTypes =
        ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()]));

    node.instructions.resetLabels();
    MethodNode transformedNode =
        new MethodNode(
            InlineCodegenUtil.API,
            node.access,
            node.name,
            Type.getMethodDescriptor(returnType, allTypes),
            node.signature,
            null) {

          private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda();

          private int getNewIndex(int var) {
            return var + (var < realParametersSize ? 0 : capturedParamsSize);
          }

          @Override
          public void visitVarInsn(int opcode, int var) {
            super.visitVarInsn(opcode, getNewIndex(var));
          }

          @Override
          public void visitIincInsn(int var, int increment) {
            super.visitIincInsn(getNewIndex(var), increment);
          }

          @Override
          public void visitMaxs(int maxStack, int maxLocals) {
            super.visitMaxs(maxStack, maxLocals + capturedParamsSize);
          }

          @Override
          public void visitLineNumber(int line, @NotNull Label start) {
            if (isInliningLambda) {
              super.visitLineNumber(line, start);
            }
          }

          @Override
          public void visitLocalVariable(
              @NotNull String name,
              @NotNull String desc,
              String signature,
              @NotNull Label start,
              @NotNull Label end,
              int index) {
            if (isInliningLambda) {
              super.visitLocalVariable(name, desc, signature, start, end, getNewIndex(index));
            }
          }
        };

    node.accept(transformedNode);

    transformCaptured(transformedNode);

    return transformedNode;
  }
Exemplo n.º 6
0
  /**
   * Creates the "proxy method", e.g. the method that has the same name and signature as the
   * original method but a completely other implementation.
   *
   * @param access
   * @param name
   * @param desc
   * @param signature
   * @param exceptions
   * @param methodInfo
   * @return the method visitor
   */
  private MethodVisitor createProxyMethod(
      final int access,
      final String name,
      final String desc,
      final String signature,
      final String[] exceptions,
      final MethodInfo methodInfo) {
    MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);

    // load "this" ie callee if target method is not static
    if (!Modifier.isStatic(access)) {
      mv.visitVarInsn(ALOAD, 0);
    }
    // load args
    AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
    // load "this" ie caller or null if method is static
    if (Modifier.isStatic(access)) {
      mv.visitInsn(ACONST_NULL);
    } else {
      mv.visitVarInsn(ALOAD, 0);
    }

    int joinPointHash = AsmHelper.calculateMethodHash(name, desc);
    String joinPointClassName =
        TransformationUtil.getJoinPointClassName(
            m_declaringTypeName,
            name,
            desc,
            m_declaringTypeName,
            JoinPointType.METHOD_EXECUTION_INT,
            joinPointHash);

    // TODO: should we provide some sort of option to do JITgen when weaving instead of when loading
    // ?
    // use case: offline full packaging and alike

    mv.visitMethodInsn(
        INVOKESTATIC,
        joinPointClassName,
        INVOKE_METHOD_NAME,
        TransformationUtil.getInvokeSignatureForCodeJoinPoints(
            access, desc, m_declaringTypeName, m_declaringTypeName));

    AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));
    mv.visitMaxs(0, 0);

    // emit the joinpoint
    m_ctx.addEmittedJoinPoint(
        new EmittedJoinPoint(
            JoinPointType.METHOD_EXECUTION_INT,
            m_declaringTypeName,
            name,
            desc,
            access,
            m_declaringTypeName,
            name,
            desc,
            access,
            joinPointHash,
            joinPointClassName,
            EmittedJoinPoint.NO_LINE_NUMBER));

    return mv;
  }
Exemplo n.º 7
0
 @Override
 public MethodVisitor visitMethod(
     final int access,
     final String name,
     final String desc,
     final String signature,
     final String[] exceptions) {
   Object key = Arrays.asList(name, desc);
   if (visitedMethods.contains(key)) return EMPTY_VISITOR;
   if (Modifier.isPrivate(access)
       || Modifier.isNative(access)
       || ((access & ACC_SYNTHETIC) != 0)) {
     // do not generate bytecode for private methods
     return EMPTY_VISITOR;
   }
   int accessFlags = access;
   visitedMethods.add(key);
   if ((objectDelegateMethods.contains(name)
           || delegatedClosures.containsKey(name)
           || (!"<init>".equals(name) && hasWildcard))
       && !Modifier.isStatic(access)
       && !Modifier.isFinal(access)) {
     if (!GROOVYOBJECT_METHOD_NAMESS.contains(name)) {
       if (Modifier.isAbstract(access)) {
         // prevents the proxy from being abstract
         accessFlags -= ACC_ABSTRACT;
       }
       if (delegatedClosures.containsKey(name) || (!"<init>".equals(name) && hasWildcard)) {
         delegatedClosures.put(name, Boolean.TRUE);
         return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags);
       }
       if (generateDelegateField && objectDelegateMethods.contains(name)) {
         return makeDelegateCall(name, desc, signature, exceptions, accessFlags);
       }
       delegatedClosures.put(name, Boolean.TRUE);
       return makeDelegateToClosureCall(name, desc, signature, exceptions, accessFlags);
     }
   } else if ("<init>".equals(name)
       && (Modifier.isPublic(access) || Modifier.isProtected(access))) {
     return createConstructor(access, name, desc, signature, exceptions);
   } else if (Modifier.isAbstract(access) && !GROOVYOBJECT_METHOD_NAMESS.contains(name)) {
     accessFlags -= ACC_ABSTRACT;
     MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions);
     mv.visitCode();
     Type[] args = Type.getArgumentTypes(desc);
     if (emptyBody) {
       Type returnType = Type.getReturnType(desc);
       if (returnType == Type.VOID_TYPE) {
         mv.visitInsn(RETURN);
       } else {
         int loadIns = getLoadInsn(returnType);
         switch (loadIns) {
           case ILOAD:
             mv.visitInsn(ICONST_0);
             break;
           case LLOAD:
             mv.visitInsn(LCONST_0);
             break;
           case FLOAD:
             mv.visitInsn(FCONST_0);
             break;
           case DLOAD:
             mv.visitInsn(DCONST_0);
             break;
           default:
             mv.visitInsn(ACONST_NULL);
         }
         mv.visitInsn(getReturnInsn(returnType));
         mv.visitMaxs(2, registerLen(args) + 1);
       }
     } else {
       // for compatibility with the legacy proxy generator, we should throw an
       // UnsupportedOperationException
       // instead of an AbtractMethodException
       mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
       mv.visitInsn(DUP);
       mv.visitMethodInsn(
           INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "()V");
       mv.visitInsn(ATHROW);
       mv.visitMaxs(2, registerLen(args) + 1);
     }
     mv.visitEnd();
   }
   return EMPTY_VISITOR;
 }
  @NotNull
  public InlineResult doTransform(
      @NotNull AnonymousObjectGeneration anonymousObjectGen,
      @NotNull FieldRemapper parentRemapper) {
    final List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>();
    ClassBuilder classBuilder = createClassBuilder();
    final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();

    reader.accept(
        new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
          @Override
          public void visit(
              int version,
              int access,
              @NotNull String name,
              String signature,
              String superName,
              String[] interfaces) {
            InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name);
            super.visit(version, access, name, signature, superName, interfaces);
          }

          @Override
          public void visitInnerClass(
              @NotNull String name, String outerName, String innerName, int access) {
            innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access));
          }

          @Override
          public MethodVisitor visitMethod(
              int access,
              @NotNull String name,
              @NotNull String desc,
              String signature,
              String[] exceptions) {
            MethodNode node = new MethodNode(access, name, desc, signature, exceptions);
            if (name.equals("<init>")) {
              if (constructor != null)
                throw new RuntimeException(
                    "Lambda, SAM or anonymous object should have only one constructor");

              constructor = node;
            } else {
              methodsToTransform.add(node);
            }
            return node;
          }

          @Override
          public FieldVisitor visitField(
              int access,
              @NotNull String name,
              @NotNull String desc,
              String signature,
              Object value) {
            addUniqueField(name);
            if (InlineCodegenUtil.isCapturedFieldName(name)) {
              return null;
            } else {
              return super.visitField(access, name, desc, signature, value);
            }
          }

          @Override
          public void visitSource(String source, String debug) {
            sourceInfo = source;
            debugInfo = debug;
          }

          @Override
          public void visitEnd() {}
        },
        ClassReader.SKIP_FRAMES);

    if (!inliningContext.isInliningLambda) {
      if (debugInfo != null && !debugInfo.isEmpty()) {
        sourceMapper = SourceMapper.Companion.createFromSmap(SMAPParser.parse(debugInfo));
      } else {
        // seems we can't do any clever mapping cause we don't know any about original class name
        sourceMapper = IdenticalSourceMapper.INSTANCE;
      }
      if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) {
        classBuilder.visitSource(sourceInfo, debugInfo);
      }
    } else {
      if (sourceInfo != null) {
        classBuilder.visitSource(sourceInfo, debugInfo);
      }
      sourceMapper = IdenticalSourceMapper.INSTANCE;
    }

    ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
    ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder();
    List<CapturedParamInfo> additionalFakeParams =
        extractParametersMappingAndPatchConstructor(
            constructor,
            allCapturedParamBuilder,
            constructorParamBuilder,
            anonymousObjectGen,
            parentRemapper);
    List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();

    for (MethodNode next : methodsToTransform) {
      MethodVisitor deferringVisitor = newMethod(classBuilder, next);
      InlineResult funResult =
          inlineMethodAndUpdateGlobalResult(
              anonymousObjectGen,
              parentRemapper,
              deferringVisitor,
              next,
              allCapturedParamBuilder,
              false);

      Type returnType = Type.getReturnType(next.desc);
      if (!AsmUtil.isPrimitive(returnType)) {
        String oldFunReturnType = returnType.getInternalName();
        String newFunReturnType = funResult.getChangedTypes().get(oldFunReturnType);
        if (newFunReturnType != null) {
          inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType);
        }
      }
      deferringMethods.add(deferringVisitor);
    }

    for (MethodVisitor method : deferringMethods) {
      method.visitEnd();
    }

    generateConstructorAndFields(
        classBuilder,
        allCapturedParamBuilder,
        constructorParamBuilder,
        anonymousObjectGen,
        parentRemapper,
        additionalFakeParams);

    SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder);

    ClassVisitor visitor = classBuilder.getVisitor();
    for (InnerClassNode node : innerClassNodes) {
      visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access);
    }

    writeOuterInfo(visitor);

    classBuilder.done();

    anonymousObjectGen.setNewLambdaType(newLambdaType);
    return transformationResult;
  }
  @Override
  public MethodVisitor visitMethod(
      final int access, final String name, String desc, String signature, String[] exceptions) {
    if ((access & Opcodes.ACC_BRIDGE) != 0) {
      return new FailSafeMethodVisitor(
          Opcodes.API_VERSION, super.visitMethod(access, name, desc, signature, exceptions));
    }

    final Type[] args = Type.getArgumentTypes(desc);
    final Type returnType = Type.getReturnType(desc);
    final MethodVisitor v = cv.visitMethod(access, name, desc, signature, exceptions);
    final Map<Integer, String> paramNames = myMethodParamNames.get(myClassName + '.' + name + desc);
    return new FailSafeMethodVisitor(Opcodes.API_VERSION, v) {
      private final Map<Integer, NotNullState> myNotNullParams =
          new LinkedHashMap<Integer, NotNullState>();
      private int mySyntheticCount = 0;
      private NotNullState myMethodNotNull;
      private Label myStartGeneratedCodeLabel;

      private AnnotationVisitor collectNotNullArgs(
          AnnotationVisitor base, final NotNullState state) {
        return new AnnotationVisitor(Opcodes.API_VERSION, base) {
          @Override
          public void visit(String methodName, Object o) {
            if (ANNOTATION_DEFAULT_METHOD.equals(methodName) && !((String) o).isEmpty()) {
              state.message = (String) o;
            } else if ("exception".equals(methodName)
                && o instanceof Type
                && !((Type) o).getClassName().equals(Exception.class.getName())) {
              state.exceptionType = ((Type) o).getInternalName();
            }
            super.visit(methodName, o);
          }
        };
      }

      public AnnotationVisitor visitParameterAnnotation(
          final int parameter, final String anno, final boolean visible) {
        AnnotationVisitor av = mv.visitParameterAnnotation(parameter, anno, visible);
        if (isReferenceType(args[parameter]) && anno.equals(NOT_NULL_TYPE)) {
          NotNullState state = new NotNullState(IAE_CLASS_NAME);
          myNotNullParams.put(new Integer(parameter), state);
          av = collectNotNullArgs(av, state);
        } else if (anno.equals(SYNTHETIC_TYPE)) {
          // see http://forge.ow2.org/tracker/?aid=307392&group_id=23&atid=100023&func=detail
          mySyntheticCount++;
        }

        return av;
      }

      @Override
      public AnnotationVisitor visitAnnotation(String anno, boolean isRuntime) {
        AnnotationVisitor av = mv.visitAnnotation(anno, isRuntime);
        if (isReferenceType(returnType) && anno.equals(NOT_NULL_TYPE)) {
          myMethodNotNull = new NotNullState(ISE_CLASS_NAME);
          av = collectNotNullArgs(av, myMethodNotNull);
        }

        return av;
      }

      @Override
      public void visitCode() {
        if (myNotNullParams.size() > 0) {
          myStartGeneratedCodeLabel = new Label();
          mv.visitLabel(myStartGeneratedCodeLabel);
        }
        for (Map.Entry<Integer, NotNullState> entry : myNotNullParams.entrySet()) {
          Integer param = entry.getKey();
          int var = ((access & ACC_STATIC) == 0) ? 1 : 0;
          for (int i = 0; i < param; ++i) {
            var += args[i].getSize();
          }
          mv.visitVarInsn(ALOAD, var);

          Label end = new Label();
          mv.visitJumpInsn(IFNONNULL, end);

          NotNullState state = entry.getValue();
          String paramName = paramNames == null ? null : paramNames.get(param);
          String descrPattern =
              state.message != null
                  ? state.message
                  : paramName != null ? NULL_ARG_MESSAGE_NAMED : NULL_ARG_MESSAGE_INDEXED;
          String[] args =
              state.message != null
                  ? EMPTY_STRING_ARRAY
                  : new String[] {
                    paramName != null ? paramName : String.valueOf(param - mySyntheticCount),
                    myClassName,
                    name
                  };
          reportError(state.exceptionType, end, descrPattern, args);
        }
      }

      @Override
      public void visitLocalVariable(
          String name, String desc, String signature, Label start, Label end, int index) {
        final boolean isStatic = (access & ACC_STATIC) != 0;
        final boolean isParameterOrThisRef = isStatic ? index < args.length : index <= args.length;
        final Label label =
            (isParameterOrThisRef && myStartGeneratedCodeLabel != null)
                ? myStartGeneratedCodeLabel
                : start;
        mv.visitLocalVariable(name, desc, signature, label, end, index);
      }

      @Override
      public void visitInsn(int opcode) {
        if (opcode == ARETURN) {
          if (myMethodNotNull != null) {
            mv.visitInsn(DUP);
            final Label skipLabel = new Label();
            mv.visitJumpInsn(IFNONNULL, skipLabel);
            String descrPattern =
                myMethodNotNull.message != null ? myMethodNotNull.message : NULL_RESULT_MESSAGE;
            String[] args =
                myMethodNotNull.message != null
                    ? EMPTY_STRING_ARRAY
                    : new String[] {myClassName, name};
            reportError(myMethodNotNull.exceptionType, skipLabel, descrPattern, args);
          }
        }

        mv.visitInsn(opcode);
      }

      private void reportError(
          final String exceptionClass,
          final Label end,
          final String descrPattern,
          final String[] args) {
        myAuxGenerator.reportError(mv, myClassName, exceptionClass, descrPattern, args);

        mv.visitLabel(end);

        myIsModification = true;
        processPostponedErrors();
      }

      @Override
      public void visitMaxs(final int maxStack, final int maxLocals) {
        try {
          super.visitMaxs(maxStack, maxLocals);
        } catch (Throwable e) {
          //noinspection SpellCheckingInspection
          registerError(name, "visitMaxs", e);
        }
      }
    };
  }