lubomir@221: /* lubomir@221: * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. lubomir@221: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. lubomir@221: * lubomir@221: * This code is free software; you can redistribute it and/or modify it lubomir@221: * under the terms of the GNU General Public License version 2 only, as lubomir@221: * published by the Free Software Foundation. Oracle designates this lubomir@221: * particular file as subject to the "Classpath" exception as provided lubomir@221: * by Oracle in the LICENSE file that accompanied this code. lubomir@221: * lubomir@221: * This code is distributed in the hope that it will be useful, but WITHOUT lubomir@221: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or lubomir@221: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License lubomir@221: * version 2 for more details (a copy is included in the LICENSE file that lubomir@221: * accompanied this code). lubomir@221: * lubomir@221: * You should have received a copy of the GNU General Public License version lubomir@221: * 2 along with this work; if not, write to the Free Software Foundation, lubomir@221: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. lubomir@221: * lubomir@221: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA lubomir@221: * or visit www.oracle.com if you need additional information or have any lubomir@221: * questions. lubomir@221: */ lubomir@221: lubomir@221: package org.apidesign.javap; lubomir@221: lubomir@307: import static org.apidesign.javap.RuntimeConstants.ITEM_Integer; lubomir@307: import static org.apidesign.javap.RuntimeConstants.ITEM_Float; lubomir@307: import static org.apidesign.javap.RuntimeConstants.ITEM_Double; lubomir@307: import static org.apidesign.javap.RuntimeConstants.ITEM_Long; lubomir@307: import static org.apidesign.javap.RuntimeConstants.ITEM_Object; lubomir@307: lubomir@221: public final class StackMapIterator { lubomir@221: private final StackMapTableData[] stackMapTable; lubomir@307: private final TypeArray argTypes; lubomir@281: private final TypeArray localTypes; lubomir@281: private final TypeArray stackTypes; lubomir@221: lubomir@221: private int nextFrameIndex; lubomir@221: private int lastFrameByteCodeOffset; lubomir@221: lubomir@221: private int byteCodeOffset; lubomir@221: lubomir@307: StackMapIterator(final MethodData methodData) { lubomir@307: this(methodData.getStackMapTable(), lubomir@307: methodData.getInternalSig(), lubomir@307: methodData.isStatic()); lubomir@307: } lubomir@307: lubomir@307: StackMapIterator(final StackMapTableData[] stackMapTable, lubomir@307: final String methodSignature, lubomir@307: final boolean isStaticMethod) { lubomir@221: this.stackMapTable = (stackMapTable != null) lubomir@221: ? stackMapTable lubomir@221: : new StackMapTableData[0]; lubomir@281: lubomir@307: argTypes = getArgTypes(methodSignature, isStaticMethod); lubomir@281: localTypes = new TypeArray(); lubomir@281: stackTypes = new TypeArray(); lubomir@307: lubomir@307: localTypes.addAll(argTypes); lubomir@307: lubomir@281: lastFrameByteCodeOffset = -1; lubomir@221: advanceBy(0); lubomir@221: } lubomir@221: lubomir@221: public String getFrameAsString() { lubomir@307: return (nextFrameIndex == 0) lubomir@307: ? StackMapTableData.toString("INITIAL", 0, null, null) lubomir@307: : stackMapTable[nextFrameIndex - 1].toString(); lubomir@221: } lubomir@221: lubomir@221: public int getFrameIndex() { lubomir@221: return nextFrameIndex; lubomir@221: } lubomir@221: lubomir@281: public TypeArray getFrameStack() { lubomir@281: return stackTypes; lubomir@221: } lubomir@221: lubomir@307: public TypeArray getFrameLocals() { lubomir@307: return localTypes; lubomir@307: } lubomir@307: lubomir@307: public TypeArray getArguments() { lubomir@307: return argTypes; lubomir@307: } lubomir@307: lubomir@221: public void advanceBy(final int numByteCodes) { lubomir@221: if (numByteCodes < 0) { lubomir@221: throw new IllegalStateException("Forward only iterator"); lubomir@221: } lubomir@221: lubomir@221: byteCodeOffset += numByteCodes; lubomir@221: while ((nextFrameIndex < stackMapTable.length) lubomir@221: && ((byteCodeOffset - lastFrameByteCodeOffset) lubomir@221: >= (stackMapTable[nextFrameIndex].offsetDelta lubomir@221: + 1))) { lubomir@281: final StackMapTableData nextFrame = stackMapTable[nextFrameIndex]; lubomir@281: lubomir@281: lastFrameByteCodeOffset += nextFrame.offsetDelta + 1; lubomir@281: nextFrame.applyTo(localTypes, stackTypes); lubomir@281: lubomir@221: ++nextFrameIndex; lubomir@221: } lubomir@221: } lubomir@221: lubomir@221: public void advanceTo(final int nextByteCodeOffset) { lubomir@221: advanceBy(nextByteCodeOffset - byteCodeOffset); lubomir@221: } lubomir@221: lubomir@307: private static TypeArray getArgTypes(final String methodSignature, lubomir@307: final boolean isStaticMethod) { lubomir@307: final TypeArray argTypes = new TypeArray(); lubomir@307: lubomir@307: if (!isStaticMethod) { lubomir@307: argTypes.add(ITEM_Object); lubomir@307: } lubomir@307: lubomir@307: if (methodSignature.charAt(0) != '(') { lubomir@307: throw new IllegalArgumentException("Invalid method signature"); lubomir@307: } lubomir@307: lubomir@307: final int length = methodSignature.length(); lubomir@472: boolean skipType = false; lubomir@307: int argType; lubomir@307: for (int i = 1; i < length; ++i) { lubomir@307: switch (methodSignature.charAt(i)) { lubomir@307: case 'B': lubomir@307: case 'C': lubomir@307: case 'S': lubomir@307: case 'Z': lubomir@307: case 'I': lubomir@307: argType = ITEM_Integer; lubomir@307: break; lubomir@307: case 'J': lubomir@307: argType = ITEM_Long; lubomir@307: break; lubomir@307: case 'F': lubomir@307: argType = ITEM_Float; lubomir@307: break; lubomir@307: case 'D': lubomir@307: argType = ITEM_Double; lubomir@307: break; lubomir@307: case 'L': { lubomir@307: i = methodSignature.indexOf(';', i + 1); lubomir@307: if (i == -1) { lubomir@307: throw new IllegalArgumentException( lubomir@307: "Invalid method signature"); lubomir@307: } lubomir@307: argType = ITEM_Object; lubomir@307: break; lubomir@307: } lubomir@307: case ')': lubomir@307: // not interested in the return value type lubomir@307: return argTypes; lubomir@307: case '[': lubomir@472: if (!skipType) { lubomir@307: argTypes.add(ITEM_Object); lubomir@472: skipType = true; lubomir@307: } lubomir@307: continue; lubomir@307: lubomir@307: default: lubomir@307: throw new IllegalArgumentException( lubomir@307: "Invalid method signature"); lubomir@307: } lubomir@307: lubomir@472: if (!skipType) { lubomir@307: argTypes.add(argType); lubomir@307: } else { lubomir@472: skipType = false; lubomir@307: } lubomir@307: } lubomir@307: lubomir@307: return argTypes; lubomir@221: } lubomir@221: }