File: ConstantPoolReader.java

package info (click to toggle)
turbine-java 0.1-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 4,556 kB
  • sloc: java: 37,940; xml: 354; makefile: 7
file content (174 lines) | stat: -rw-r--r-- 6,101 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.turbine.bytecode;

import com.google.common.io.ByteArrayDataInput;
import com.google.turbine.model.Const;

/** A JVMS ยง4.4 constant pool reader. */
public class ConstantPoolReader {

  // JVMS table 4.3
  static final int CONSTANT_CLASS = 7;
  static final int CONSTANT_FIELDREF = 9;
  static final int CONSTANT_METHODREF = 10;
  static final int CONSTANT_INTERFACE_METHODREF = 11;
  static final int CONSTANT_STRING = 8;
  static final int CONSTANT_INTEGER = 3;
  static final int CONSTANT_FLOAT = 4;
  static final int CONSTANT_LONG = 5;
  static final int CONSTANT_DOUBLE = 6;
  static final int CONSTANT_NAME_AND_TYPE = 12;
  static final int CONSTANT_UTF8 = 1;
  static final int CONSTANT_METHOD_HANDLE = 15;
  static final int CONSTANT_METHOD_TYPE = 16;
  static final int CONSTANT_DYNAMIC = 17;
  static final int CONSTANT_INVOKE_DYNAMIC = 18;
  static final int CONSTANT_MODULE = 19;
  static final int CONSTANT_PACKAGE = 20;

  /** A table that maps constant pool entries to byte offsets in {@link #byteReader}. */
  private final int[] constantPool;

  /** The constant pool data. */
  private final ByteReader byteReader;

  private ConstantPoolReader(int[] constantPool, ByteReader byteReader) {
    this.constantPool = constantPool;
    this.byteReader = byteReader;
  }

  /**
   * Skips over all constant pool entries, saving the byte offset of each index so it can be read
   * later if it's needed.
   */
  public static ConstantPoolReader readConstantPool(ByteReader reader) {
    int constantPoolCount = reader.u2();
    int[] constantPool = new int[constantPoolCount - 1];
    for (int i = 0; i < constantPoolCount - 1; ) {
      constantPool[i] = reader.pos();
      i += skipConstantPool(reader);
    }
    return new ConstantPoolReader(constantPool, reader);
  }

  /** Skips over the data for a single constant pool entry and returns the size of the entry. */
  private static int skipConstantPool(ByteReader reader) {
    int tag = reader.u1();
    switch (tag) {
      case CONSTANT_CLASS:
      case CONSTANT_METHOD_TYPE:
      case CONSTANT_STRING:
      case CONSTANT_MODULE:
      case CONSTANT_PACKAGE:
        reader.skip(2);
        return 1;
      case CONSTANT_DOUBLE:
      case CONSTANT_LONG:
        reader.skip(8);
        // "In retrospect, making 8-byte constants take two constant pool entries
        // was a poor choice." -- JVMS 4.4.5
        return 2;
      case CONSTANT_FIELDREF:
      case CONSTANT_METHODREF:
      case CONSTANT_INTERFACE_METHODREF:
      case CONSTANT_INTEGER:
      case CONSTANT_FLOAT:
      case CONSTANT_NAME_AND_TYPE:
      case CONSTANT_DYNAMIC:
      case CONSTANT_INVOKE_DYNAMIC:
        reader.skip(4);
        return 1;
      case CONSTANT_UTF8:
        reader.skip(reader.u2());
        return 1;
      case CONSTANT_METHOD_HANDLE:
        reader.skip(3);
        return 1;
      default:
        throw new AssertionError(String.format("bad constant pool tag: 0x%x", tag));
    }
  }

  /** Reads the CONSTANT_Class_info at the given index. */
  public String classInfo(int index) {
    ByteArrayDataInput reader = byteReader.seek(constantPool[index - 1]);
    byte tag = reader.readByte();
    if (tag != CONSTANT_CLASS) {
      throw new AssertionError(String.format("bad tag: %x", tag));
    }
    int nameIndex = reader.readUnsignedShort();
    return utf8(nameIndex);
  }

  /** Reads the CONSTANT_Utf8_info at the given index. */
  public String utf8(int index) {
    ByteArrayDataInput reader = byteReader.seek(constantPool[index - 1]);
    byte tag = reader.readByte();
    if (tag != CONSTANT_UTF8) {
      throw new AssertionError(String.format("bad tag: %x", tag));
    }
    return reader.readUTF();
  }

  /** Reads the CONSTANT_Module_info at the given index. */
  public String moduleInfo(int index) {
    ByteArrayDataInput reader = byteReader.seek(constantPool[index - 1]);
    byte tag = reader.readByte();
    if (tag != CONSTANT_MODULE) {
      throw new AssertionError(String.format("bad tag: %x", tag));
    }
    int nameIndex = reader.readUnsignedShort();
    return utf8(nameIndex);
  }

  /** Reads the CONSTANT_Package_info at the given index. */
  public String packageInfo(int index) {
    ByteArrayDataInput reader = byteReader.seek(constantPool[index - 1]);
    byte tag = reader.readByte();
    if (tag != CONSTANT_PACKAGE) {
      throw new AssertionError(String.format("bad tag: %x", tag));
    }
    int nameIndex = reader.readUnsignedShort();
    return utf8(nameIndex);
  }

  /**
   * Reads a constant value at the given index, which must be one of CONSTANT_String_info,
   * CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info, or CONSTANT_Double_info.
   */
  Const.Value constant(int index) {
    ByteArrayDataInput reader = byteReader.seek(constantPool[index - 1]);
    byte tag = reader.readByte();
    switch (tag) {
      case CONSTANT_LONG:
        return new Const.LongValue(reader.readLong());
      case CONSTANT_FLOAT:
        return new Const.FloatValue(reader.readFloat());
      case CONSTANT_DOUBLE:
        return new Const.DoubleValue(reader.readDouble());
      case CONSTANT_INTEGER:
        return new Const.IntValue(reader.readInt());
      case CONSTANT_STRING:
        return new Const.StringValue(utf8(reader.readUnsignedShort()));
      case CONSTANT_UTF8:
        return new Const.StringValue(reader.readUTF());
      default:
        throw new AssertionError(String.format("bad tag: %x", tag));
    }
  }
}