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    public class InlineAdapter extends InstructionAdapter {
029    
030        private int nextLocalIndex = 0;
031        private final SourceMapper sourceMapper;
032    
033        private boolean isLambdaInlining = false;
034    
035        private final List<CatchBlock> blocks = new ArrayList<CatchBlock>();
036    
037        private int nextLocalIndexBeforeInline = -1;
038    
039        public InlineAdapter(MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
040            super(InlineCodegenUtil.API, mv);
041            nextLocalIndex = localsSize;
042            this.sourceMapper = sourceMapper;
043        }
044    
045        @Override
046        public void visitIincInsn(int var, int increment) {
047            super.visitIincInsn(var, increment);
048            updateIndex(var, 1);
049        }
050    
051        @Override
052        public void visitVarInsn(int opcode, int var) {
053            super.visitVarInsn(opcode, var);
054            updateIndex(var, (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1));
055        }
056    
057        private void updateIndex(int var, int varSize) {
058            int newIndex = var + varSize;
059            if (newIndex > nextLocalIndex) {
060                nextLocalIndex = newIndex;
061            }
062        }
063    
064        public int getNextLocalIndex() {
065            return nextLocalIndex;
066        }
067    
068        public void setLambdaInlining(boolean isInlining) {
069            this.isLambdaInlining = isInlining;
070            if (isInlining) {
071                nextLocalIndexBeforeInline = nextLocalIndex;
072            } else {
073                nextLocalIndex = nextLocalIndexBeforeInline;
074            }
075        }
076    
077        @Override
078        public void visitTryCatchBlock(Label start,
079                Label end, Label handler, String type) {
080            if(!isLambdaInlining) {
081                blocks.add(new CatchBlock(start, end, handler, type));
082            }
083            else {
084                super.visitTryCatchBlock(start, end, handler, type);
085            }
086        }
087    
088        @Override
089        public void visitLineNumber(int line, Label start) {
090            if (InlineCodegenUtil.GENERATE_SMAP) {
091                sourceMapper.visitLineNumber(mv, line, start);
092            }
093            else {
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(Label start, Label end, Label handler, String type) {
113                this.start = start;
114                this.end = end;
115                this.handler = handler;
116                this.type = type;
117            }
118        }
119    }