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