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.inline;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.org.objectweb.asm.Label;
021    import org.jetbrains.org.objectweb.asm.MethodVisitor;
022    import org.jetbrains.org.objectweb.asm.Opcodes;
023    import org.jetbrains.org.objectweb.asm.Type;
024    
025    public class MaxLocalsCalculator extends MethodVisitor {
026    
027        private int maxLocals;
028    
029        public MaxLocalsCalculator(int api, int access, String descriptor, MethodVisitor mv) {
030            super(api, mv);
031    
032            // updates maxLocals
033            int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
034            if ((access & Opcodes.ACC_STATIC) != 0) {
035                --size;
036            }
037    
038            maxLocals = size;
039        }
040    
041        @Override
042        public void visitVarInsn(int opcode, int var) {
043            int n;
044            if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD ||
045                opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
046                n = var + 2;
047            }
048            else {
049                n = var + 1;
050            }
051            updateMaxLocals(n);
052    
053            super.visitVarInsn(opcode, var);
054        }
055    
056        @Override
057        public void visitIincInsn(int var, int increment) {
058            updateMaxLocals(var + 1);
059    
060            super.visitIincInsn(var, increment);
061        }
062    
063        @Override
064        public void visitLocalVariable(
065                @NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index
066        ) {
067            // updates max locals
068            char c = desc.charAt(0);
069            int n = index + (c == 'J' || c == 'D' ? 2 : 1);
070            updateMaxLocals(n);
071    
072            super.visitLocalVariable(name, desc, signature, start, end, index);
073        }
074    
075        @Override
076        public void visitMaxs(int maxStack, int maxLocals) {
077            super.visitMaxs(maxStack, this.maxLocals);
078        }
079    
080        public int getMaxLocals() {
081            return maxLocals;
082        }
083    
084        private void updateMaxLocals(int nextFreeSlotNumber) {
085            if (nextFreeSlotNumber > maxLocals) {
086                maxLocals = nextFreeSlotNumber;
087            }
088        }
089    
090    }