001 /* 002 * Copyright 2010-2013 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.jet.codegen.inline; 018 019 import org.jetbrains.asm4.Label; 020 import org.jetbrains.asm4.MethodVisitor; 021 import org.jetbrains.asm4.Opcodes; 022 import org.jetbrains.asm4.commons.InstructionAdapter; 023 024 import java.util.ArrayList; 025 import java.util.List; 026 027 public class InlineAdapter extends InstructionAdapter { 028 029 private int nextLocalIndex = 0; 030 031 private boolean isInlining = false; 032 033 private final List<CatchBlock> blocks = new ArrayList<CatchBlock>(); 034 035 private int nextLocalIndexBeforeInline = -1; 036 037 public InlineAdapter(MethodVisitor mv, int localsSize) { 038 super(mv); 039 nextLocalIndex = localsSize; 040 } 041 042 @Override 043 public void visitIincInsn(int var, int increment) { 044 super.visitIincInsn(var, increment); 045 updateIndex(var, 1); 046 } 047 048 @Override 049 public void visitVarInsn(int opcode, int var) { 050 super.visitVarInsn(opcode, var); 051 updateIndex(var, (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1)); 052 } 053 054 private void updateIndex(int var, int varSize) { 055 int newIndex = var + varSize; 056 if (newIndex > nextLocalIndex) { 057 nextLocalIndex = newIndex; 058 } 059 } 060 061 public int getNextLocalIndex() { 062 return nextLocalIndex; 063 } 064 065 public void setInlining(boolean isInlining) { 066 this.isInlining = isInlining; 067 if (isInlining) { 068 nextLocalIndexBeforeInline = nextLocalIndex; 069 } else { 070 nextLocalIndex = nextLocalIndexBeforeInline; 071 } 072 } 073 074 @Override 075 public void visitTryCatchBlock(Label start, 076 Label end, Label handler, String type) { 077 if(!isInlining) { 078 blocks.add(new CatchBlock(start, end, handler, type)); 079 } 080 else { 081 super.visitTryCatchBlock(start, end, handler, type); 082 } 083 } 084 085 @Override 086 public void visitMaxs(int stack, int locals) { 087 for (CatchBlock b : blocks) { 088 super.visitTryCatchBlock(b.start, b.end, b.handler, b.type); 089 } 090 super.visitMaxs(stack, locals); 091 } 092 093 private static class CatchBlock { 094 private final Label start; 095 private final Label end; 096 private final Label handler; 097 private final String type; 098 099 public CatchBlock(Label start, Label end, Label handler, String type) { 100 this.start = start; 101 this.end = end; 102 this.handler = handler; 103 this.type = type; 104 } 105 } 106 }