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 }