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 }