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