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 }