001 /* 002 * Copyright 2010-2014 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.codegen.optimization; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.jet.codegen.inline.InlineCodegenUtil; 022 import org.jetbrains.jet.codegen.optimization.boxing.RedundantBoxingMethodTransformer; 023 import org.jetbrains.jet.codegen.optimization.boxing.RedundantNullCheckMethodTransformer; 024 import org.jetbrains.jet.codegen.optimization.transformer.MethodTransformer; 025 import org.jetbrains.org.objectweb.asm.MethodVisitor; 026 import org.jetbrains.org.objectweb.asm.Opcodes; 027 import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode; 028 import org.jetbrains.org.objectweb.asm.tree.MethodNode; 029 import org.jetbrains.org.objectweb.asm.util.Textifier; 030 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; 031 032 import java.util.ArrayList; 033 import java.util.List; 034 035 public class OptimizationMethodVisitor extends MethodVisitor { 036 private static final int MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE = 5000; 037 private static final MethodTransformer MAIN_METHOD_TRANSFORMER = new RedundantNullCheckMethodTransformer( 038 new RedundantBoxingMethodTransformer(null) 039 ); 040 041 private final MethodNode methodNode; 042 private final MethodVisitor delegate; 043 044 public OptimizationMethodVisitor( 045 @NotNull MethodVisitor delegate, 046 int access, 047 @NotNull String name, 048 @NotNull String desc, 049 @Nullable String signature, 050 @Nullable String[] exceptions 051 ) { 052 super(Opcodes.ASM5); 053 this.delegate = delegate; 054 this.methodNode = new MethodNode(access, name, desc, signature, exceptions); 055 this.methodNode.localVariables = new ArrayList<LocalVariableNode>(5); 056 this.mv = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode); 057 } 058 059 @Override 060 public void visitEnd() { 061 // force mv to calculate maxStack/maxLocals in case it didn't yet done 062 if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) { 063 mv.visitMaxs(-1, -1); 064 } 065 066 super.visitEnd(); 067 068 if (methodNode.instructions.size() > 0 && 069 methodNode.instructions.size() <= MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE) { 070 MAIN_METHOD_TRANSFORMER.transform("fake", methodNode); 071 } 072 073 methodNode.accept(new EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate)); 074 075 076 // In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate 077 // So we just do it here 078 if (methodNode.instructions.size() == 0) { 079 List<LocalVariableNode> localVariables = methodNode.localVariables; 080 // visits local variables 081 int n = localVariables == null ? 0 : localVariables.size(); 082 for (int i = 0; i < n; ++i) { 083 localVariables.get(i).accept(delegate); 084 } 085 } 086 087 delegate.visitEnd(); 088 } 089 090 /** 091 * You can use it when you need to ignore visit end 092 */ 093 private static class EndIgnoringMethodVisitorDecorator extends MethodVisitor { 094 public EndIgnoringMethodVisitorDecorator(int api, @NotNull MethodVisitor mv) { 095 super(api, mv); 096 } 097 098 @Override 099 public void visitEnd() { 100 101 } 102 } 103 104 @Nullable 105 public TraceMethodVisitor getTraceMethodVisitorIfPossible() { 106 TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(new Textifier()); 107 try { 108 methodNode.accept(traceMethodVisitor); 109 } 110 catch (Throwable e) { 111 return null; 112 } 113 114 return traceMethodVisitor; 115 } 116 }