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 public class InlineAdapter extends InstructionAdapter { 029 030 private int nextLocalIndex = 0; 031 private final SourceMapper sourceMapper; 032 033 private boolean isLambdaInlining = false; 034 035 private final List<CatchBlock> blocks = new ArrayList<CatchBlock>(); 036 037 private int nextLocalIndexBeforeInline = -1; 038 039 public InlineAdapter(MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) { 040 super(InlineCodegenUtil.API, mv); 041 nextLocalIndex = localsSize; 042 this.sourceMapper = sourceMapper; 043 } 044 045 @Override 046 public void visitIincInsn(int var, int increment) { 047 super.visitIincInsn(var, increment); 048 updateIndex(var, 1); 049 } 050 051 @Override 052 public void visitVarInsn(int opcode, int var) { 053 super.visitVarInsn(opcode, var); 054 updateIndex(var, (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1)); 055 } 056 057 private void updateIndex(int var, int varSize) { 058 int newIndex = var + varSize; 059 if (newIndex > nextLocalIndex) { 060 nextLocalIndex = newIndex; 061 } 062 } 063 064 public int getNextLocalIndex() { 065 return nextLocalIndex; 066 } 067 068 public void setLambdaInlining(boolean isInlining) { 069 this.isLambdaInlining = isInlining; 070 if (isInlining) { 071 nextLocalIndexBeforeInline = nextLocalIndex; 072 } else { 073 nextLocalIndex = nextLocalIndexBeforeInline; 074 } 075 } 076 077 @Override 078 public void visitTryCatchBlock(Label start, 079 Label end, Label handler, String type) { 080 if(!isLambdaInlining) { 081 blocks.add(new CatchBlock(start, end, handler, type)); 082 } 083 else { 084 super.visitTryCatchBlock(start, end, handler, type); 085 } 086 } 087 088 @Override 089 public void visitLineNumber(int line, Label start) { 090 if (InlineCodegenUtil.GENERATE_SMAP) { 091 sourceMapper.visitLineNumber(mv, line, start); 092 } 093 else { 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(Label start, Label end, Label handler, String type) { 113 this.start = start; 114 this.end = end; 115 this.handler = handler; 116 this.type = type; 117 } 118 } 119 }