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