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.tree.LocalVariableNode;
027 import org.jetbrains.org.objectweb.asm.tree.MethodNode;
028 import org.jetbrains.org.objectweb.asm.util.Textifier;
029 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
030
031 import java.util.ArrayList;
032 import java.util.List;
033
034 public class OptimizationMethodVisitor extends MethodVisitor {
035 private static final int MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE = 5000;
036 private static final MethodTransformer MAIN_METHOD_TRANSFORMER = new RedundantNullCheckMethodTransformer(
037 new RedundantBoxingMethodTransformer(null)
038 );
039
040 private final MethodNode methodNode;
041 private final MethodVisitor delegate;
042
043 public OptimizationMethodVisitor(
044 @NotNull MethodVisitor delegate,
045 int access,
046 @NotNull String name,
047 @NotNull String desc,
048 @Nullable String signature,
049 @Nullable String[] exceptions
050 ) {
051 super(OptimizationUtils.API);
052 this.delegate = delegate;
053 this.methodNode = new MethodNode(access, name, desc, signature, exceptions);
054 this.methodNode.localVariables = new ArrayList<LocalVariableNode>(5);
055 this.mv = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
056 }
057
058 @Override
059 public void visitEnd() {
060 // force mv to calculate maxStack/maxLocals in case it didn't yet done
061 if (methodNode.maxLocals <= 0 || methodNode.maxStack <= 0) {
062 mv.visitMaxs(-1, -1);
063 }
064
065 super.visitEnd();
066
067 if (methodNode.instructions.size() > 0 &&
068 methodNode.instructions.size() <= MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE) {
069 MAIN_METHOD_TRANSFORMER.transform("fake", methodNode);
070 }
071
072 methodNode.accept(new EndIgnoringMethodVisitorDecorator(OptimizationUtils.API, delegate));
073
074
075 // In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
076 // So we just do it here
077 if (methodNode.instructions.size() == 0) {
078 List<LocalVariableNode> localVariables = methodNode.localVariables;
079 // visits local variables
080 int n = localVariables == null ? 0 : localVariables.size();
081 for (int i = 0; i < n; ++i) {
082 localVariables.get(i).accept(delegate);
083 }
084 }
085
086 delegate.visitEnd();
087 }
088
089 /**
090 * You can use it when you need to ignore visit end
091 */
092 private static class EndIgnoringMethodVisitorDecorator extends MethodVisitor {
093 public EndIgnoringMethodVisitorDecorator(int api, @NotNull MethodVisitor mv) {
094 super(api, mv);
095 }
096
097 @Override
098 public void visitEnd() {
099
100 }
101 }
102
103 @Nullable
104 public TraceMethodVisitor getTraceMethodVisitorIfPossible() {
105 TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(new Textifier());
106 try {
107 methodNode.accept(traceMethodVisitor);
108 }
109 catch (Throwable e) {
110 return null;
111 }
112
113 return traceMethodVisitor;
114 }
115 }