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 }