javap/src/main/java/org/apidesign/javap/StackMapIterator.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 05 Feb 2013 08:48:23 +0100
branchemul
changeset 667 5866e89ef568
parent 307 eaf4e8387065
permissions -rw-r--r--
Test can specify multiple HTTP resources
     1 /*
     2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package org.apidesign.javap;
    27 
    28 import static org.apidesign.javap.RuntimeConstants.ITEM_Integer;
    29 import static org.apidesign.javap.RuntimeConstants.ITEM_Float;
    30 import static org.apidesign.javap.RuntimeConstants.ITEM_Double;
    31 import static org.apidesign.javap.RuntimeConstants.ITEM_Long;
    32 import static org.apidesign.javap.RuntimeConstants.ITEM_Object;
    33 
    34 public final class StackMapIterator {
    35     private final StackMapTableData[] stackMapTable;
    36     private final TypeArray argTypes;
    37     private final TypeArray localTypes;
    38     private final TypeArray stackTypes;
    39 
    40     private int nextFrameIndex;
    41     private int lastFrameByteCodeOffset;
    42 
    43     private int byteCodeOffset;
    44 
    45     StackMapIterator(final MethodData methodData) {
    46         this(methodData.getStackMapTable(),
    47              methodData.getInternalSig(),
    48              methodData.isStatic());
    49     }
    50 
    51     StackMapIterator(final StackMapTableData[] stackMapTable,
    52                      final String methodSignature,
    53                      final boolean isStaticMethod) {
    54         this.stackMapTable = (stackMapTable != null)
    55                                  ? stackMapTable
    56                                  : new StackMapTableData[0];
    57 
    58         argTypes = getArgTypes(methodSignature, isStaticMethod);
    59         localTypes = new TypeArray();
    60         stackTypes = new TypeArray();
    61 
    62         localTypes.addAll(argTypes);
    63 
    64         lastFrameByteCodeOffset = -1;
    65         advanceBy(0);
    66     }
    67 
    68     public String getFrameAsString() {
    69         return (nextFrameIndex == 0)
    70                    ? StackMapTableData.toString("INITIAL", 0, null, null)
    71                    : stackMapTable[nextFrameIndex - 1].toString();
    72     }
    73 
    74     public int getFrameIndex() {
    75         return nextFrameIndex;
    76     }
    77 
    78     public TypeArray getFrameStack() {
    79         return stackTypes;
    80     }
    81 
    82     public TypeArray getFrameLocals() {
    83         return localTypes;
    84     }
    85 
    86     public TypeArray getArguments() {
    87         return argTypes;
    88     }
    89 
    90     public void advanceBy(final int numByteCodes) {
    91         if (numByteCodes < 0) {
    92             throw new IllegalStateException("Forward only iterator");
    93         }
    94 
    95         byteCodeOffset += numByteCodes;
    96         while ((nextFrameIndex < stackMapTable.length)
    97                     && ((byteCodeOffset - lastFrameByteCodeOffset)
    98                             >= (stackMapTable[nextFrameIndex].offsetDelta
    99                                     + 1))) {
   100             final StackMapTableData nextFrame = stackMapTable[nextFrameIndex];
   101 
   102             lastFrameByteCodeOffset += nextFrame.offsetDelta + 1;
   103             nextFrame.applyTo(localTypes, stackTypes);
   104 
   105             ++nextFrameIndex;
   106         }
   107     }
   108 
   109     public void advanceTo(final int nextByteCodeOffset) {
   110         advanceBy(nextByteCodeOffset - byteCodeOffset);
   111     }
   112 
   113     private static TypeArray getArgTypes(final String methodSignature,
   114                                          final boolean isStaticMethod) {
   115         final TypeArray argTypes = new TypeArray();
   116 
   117         if (!isStaticMethod) {
   118             argTypes.add(ITEM_Object);
   119         }
   120 
   121         if (methodSignature.charAt(0) != '(') {
   122             throw new IllegalArgumentException("Invalid method signature");
   123         }
   124 
   125         final int length = methodSignature.length();
   126         boolean skipType = false;
   127         int argType;
   128         for (int i = 1; i < length; ++i) {
   129             switch (methodSignature.charAt(i)) {
   130                 case 'B':
   131                 case 'C':
   132                 case 'S':
   133                 case 'Z':
   134                 case 'I':
   135                     argType = ITEM_Integer;
   136                     break;
   137                 case 'J':
   138                     argType = ITEM_Long;
   139                     break;
   140                 case 'F':
   141                     argType = ITEM_Float;
   142                     break;
   143                 case 'D':
   144                     argType = ITEM_Double;
   145                     break;
   146                 case 'L': {
   147                     i = methodSignature.indexOf(';', i + 1);
   148                     if (i == -1) {
   149                         throw new IllegalArgumentException(
   150                                       "Invalid method signature");
   151                     }
   152                     argType = ITEM_Object;
   153                     break;
   154                 }
   155                 case ')':
   156                     // not interested in the return value type
   157                     return argTypes;
   158                 case '[':
   159                     if (!skipType) {
   160                         argTypes.add(ITEM_Object);
   161                         skipType = true;
   162                     }
   163                     continue;
   164 
   165                 default:
   166                     throw new IllegalArgumentException(
   167                                   "Invalid method signature");
   168             }
   169 
   170             if (!skipType) {
   171                 argTypes.add(argType);
   172             } else {
   173                 skipType = false;
   174             }
   175         }
   176 
   177         return argTypes;
   178     }
   179 }