001    /*
002     * Copyright 2010-2015 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.kotlin.codegen.optimization;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.codegen.TransformationMethodVisitor;
022    import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer;
023    import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantCoercionToUnitTransformer;
024    import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantNullCheckMethodTransformer;
025    import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
026    import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
027    import org.jetbrains.org.objectweb.asm.MethodVisitor;
028    import org.jetbrains.org.objectweb.asm.tree.MethodNode;
029    
030    public class OptimizationMethodVisitor extends TransformationMethodVisitor {
031        private static final int MEMORY_LIMIT_BY_METHOD_MB = 50;
032    
033        private static final MethodTransformer MANDATORY_METHOD_TRANSFORMER = new FixStackWithLabelNormalizationMethodTransformer();
034    
035        private static final MethodTransformer[] OPTIMIZATION_TRANSFORMERS = new MethodTransformer[] {
036                new RedundantNullCheckMethodTransformer(),
037                new RedundantBoxingMethodTransformer(),
038                new RedundantCoercionToUnitTransformer(),
039                new DeadCodeEliminationMethodTransformer(),
040                new RedundantGotoMethodTransformer(),
041                new RedundantNopsCleanupMethodTransformer()
042        };
043    
044        private final boolean disableOptimization;
045    
046        public OptimizationMethodVisitor(
047                @NotNull MethodVisitor delegate,
048                boolean disableOptimization,
049                int access,
050                @NotNull String name,
051                @NotNull String desc,
052                @Nullable String signature,
053                @Nullable String[] exceptions
054        ) {
055            super(delegate, access, name, desc, signature, exceptions);
056            this.disableOptimization = disableOptimization;
057        }
058    
059        @Override
060        protected void performTransformations(@NotNull MethodNode methodNode) {
061            MANDATORY_METHOD_TRANSFORMER.transform("fake", methodNode);
062            if (canBeOptimized(methodNode) && !disableOptimization) {
063                for (MethodTransformer transformer : OPTIMIZATION_TRANSFORMERS) {
064                    transformer.transform("fake", methodNode);
065                }
066            }
067            UtilKt.prepareForEmitting(methodNode);
068        }
069    
070        private static boolean canBeOptimized(@NotNull MethodNode node) {
071            int totalFramesSizeMb = node.instructions.size() * (node.maxLocals + node.maxStack) / (1024 * 1024);
072            return totalFramesSizeMb < MEMORY_LIMIT_BY_METHOD_MB;
073        }
074    }