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.annotations.Nullable;
021    import org.jetbrains.org.objectweb.asm.Label;
022    import org.jetbrains.org.objectweb.asm.MethodVisitor;
023    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
024    
025    import java.util.ArrayList;
026    import java.util.List;
027    
028    import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getLoadStoreArgSize;
029    
030    public class InlineAdapter extends InstructionAdapter {
031        private final SourceMapper sourceMapper;
032        private final List<CatchBlock> blocks = new ArrayList<CatchBlock>();
033    
034        private boolean isLambdaInlining = false;
035        private int nextLocalIndex = 0;
036        private int nextLocalIndexBeforeInline = -1;
037    
038        public InlineAdapter(@NotNull MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
039            super(InlineCodegenUtil.API, mv);
040            this.nextLocalIndex = localsSize;
041            this.sourceMapper = sourceMapper;
042        }
043    
044        @Override
045        public void visitIincInsn(int var, int increment) {
046            super.visitIincInsn(var, increment);
047            updateIndex(var, 1);
048        }
049    
050        @Override
051        public void visitVarInsn(int opcode, int var) {
052            super.visitVarInsn(opcode, var);
053            updateIndex(var, getLoadStoreArgSize(opcode));
054        }
055    
056        private void updateIndex(int var, int varSize) {
057            int newIndex = var + varSize;
058            if (newIndex > nextLocalIndex) {
059                nextLocalIndex = newIndex;
060            }
061        }
062    
063        public int getNextLocalIndex() {
064            return nextLocalIndex;
065        }
066    
067        public void setLambdaInlining(boolean isInlining) {
068            this.isLambdaInlining = isInlining;
069            if (isInlining) {
070                nextLocalIndexBeforeInline = nextLocalIndex;
071            }
072            else {
073                nextLocalIndex = nextLocalIndexBeforeInline;
074            }
075        }
076    
077        @Override
078        public void visitTryCatchBlock(@NotNull Label start, @NotNull Label end, @NotNull Label handler, @Nullable String type) {
079            if (!isLambdaInlining) {
080                blocks.add(new CatchBlock(start, end, handler, type));
081            }
082            else {
083                super.visitTryCatchBlock(start, end, handler, type);
084            }
085        }
086    
087        @Override
088        public void visitLineNumber(int line, @NotNull Label start) {
089            if (InlineCodegenUtil.GENERATE_SMAP) {
090                line = sourceMapper.mapLineNumber(line);
091            }
092            //skip not mapped lines
093            if (line >= 0) {
094                super.visitLineNumber(line, start);
095            }
096        }
097    
098        @Override
099        public void visitMaxs(int stack, int locals) {
100            for (CatchBlock b : blocks) {
101                super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
102            }
103            super.visitMaxs(stack, locals);
104        }
105    
106        private static class CatchBlock {
107            private final Label start;
108            private final Label end;
109            private final Label handler;
110            private final String type;
111    
112            public CatchBlock(@NotNull Label start, @NotNull Label end, @NotNull Label handler, @Nullable String type) {
113                this.start = start;
114                this.end = end;
115                this.handler = handler;
116                this.type = type;
117            }
118        }
119    }