• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.bytecode;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.turbine.model.Const;
21 import com.google.turbine.model.Const.IntValue;
22 import com.google.turbine.model.Const.StringValue;
23 import com.google.turbine.model.Const.Value;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 
30 /** A constant pool builder, used when writing class files. */
31 public class ConstantPool {
32 
33   /** The next available constant pool entry. */
34   int nextEntry = 1;
35 
36   private final Map<String, Integer> utf8Pool = new HashMap<>();
37   private final Map<Integer, Integer> classInfoPool = new HashMap<>();
38   private final Map<Integer, Integer> stringPool = new HashMap<>();
39   private final Map<Integer, Integer> integerPool = new HashMap<>();
40   private final Map<Double, Integer> doublePool = new HashMap<>();
41   private final Map<Float, Integer> floatPool = new HashMap<>();
42   private final Map<Long, Integer> longPool = new HashMap<>();
43   private final Map<Integer, Integer> modulePool = new HashMap<>();
44   private final Map<Integer, Integer> packagePool = new HashMap<>();
45 
46   private final List<Entry> constants = new ArrayList<>();
47 
48   /** The ordered list of constant pool entries. */
constants()49   public ImmutableList<Entry> constants() {
50     return ImmutableList.copyOf(constants);
51   }
52 
53   /** The number of constant pool entries the given kind takes up. */
width(Kind kind)54   private static short width(Kind kind) {
55     switch (kind) {
56       case CLASS_INFO:
57       case STRING:
58       case INTEGER:
59       case UTF8:
60       case FLOAT:
61       case MODULE:
62       case PACKAGE:
63         return 1;
64       case LONG:
65       case DOUBLE:
66         // "In retrospect, making 8-byte constants take two constant pool entries
67         // was a poor choice." -- JVMS 4.4.5
68         return 2;
69     }
70     throw new AssertionError(kind);
71   }
72 
73   /** A constant pool entry. */
74   static class Entry {
75     private final Kind kind;
76     private final Value value;
77 
Entry(Kind kind, Value value)78     Entry(Kind kind, Value value) {
79       this.kind = kind;
80       this.value = value;
81     }
82 
83     /** The entry kind. */
kind()84     public Kind kind() {
85       return kind;
86     }
87 
88     /** The entry's value. */
value()89     public Value value() {
90       return value;
91     }
92   }
93 
94   /** Adds a CONSTANT_Class_info entry to the pool. */
classInfo(String value)95   int classInfo(String value) {
96     Objects.requireNonNull(value);
97     int utf8 = utf8(value);
98     if (classInfoPool.containsKey(utf8)) {
99       return classInfoPool.get(utf8);
100     }
101     int index = insert(new Entry(Kind.CLASS_INFO, new IntValue(utf8)));
102     classInfoPool.put(utf8, index);
103     return index;
104   }
105 
106   /** Adds a CONSTANT_Utf8_info entry to the pool. */
utf8(String value)107   int utf8(String value) {
108     Objects.requireNonNull(value);
109     if (utf8Pool.containsKey(value)) {
110       return utf8Pool.get(value);
111     }
112     int index = insert(new Entry(Kind.UTF8, new StringValue(value)));
113     utf8Pool.put(value, index);
114     return index;
115   }
116 
integer(int value)117   int integer(int value) {
118     if (integerPool.containsKey(value)) {
119       return integerPool.get(value);
120     }
121     int index = insert(new Entry(Kind.INTEGER, new Const.IntValue(value)));
122     integerPool.put(value, index);
123     return index;
124   }
125 
longInfo(long value)126   int longInfo(long value) {
127     if (longPool.containsKey(value)) {
128       return longPool.get(value);
129     }
130     int index = insert(new Entry(Kind.LONG, new Const.LongValue(value)));
131     longPool.put(value, index);
132     return index;
133   }
134 
doubleInfo(double value)135   int doubleInfo(double value) {
136     if (doublePool.containsKey(value)) {
137       return doublePool.get(value);
138     }
139     int index = insert(new Entry(Kind.DOUBLE, new Const.DoubleValue(value)));
140     doublePool.put(value, index);
141     return index;
142   }
143 
floatInfo(float value)144   int floatInfo(float value) {
145     if (floatPool.containsKey(value)) {
146       return floatPool.get(value);
147     }
148     int index = insert(new Entry(Kind.FLOAT, new Const.FloatValue(value)));
149     floatPool.put(value, index);
150     return index;
151   }
152 
string(String value)153   int string(String value) {
154     Objects.requireNonNull(value);
155     int utf8 = utf8(value);
156     if (stringPool.containsKey(utf8)) {
157       return stringPool.get(utf8);
158     }
159     int index = insert(new Entry(Kind.STRING, new IntValue(utf8)));
160     stringPool.put(utf8, index);
161     return index;
162   }
163 
164   /** Adds a CONSTANT_Module_info entry to the pool. */
moduleInfo(String value)165   int moduleInfo(String value) {
166     Objects.requireNonNull(value);
167     int utf8 = utf8(value);
168     if (modulePool.containsKey(utf8)) {
169       return modulePool.get(utf8);
170     }
171     int index = insert(new Entry(Kind.MODULE, new IntValue(utf8)));
172     modulePool.put(utf8, index);
173     return index;
174   }
175 
176   /** Adds a CONSTANT_Package_info entry to the pool. */
packageInfo(String value)177   int packageInfo(String value) {
178     Objects.requireNonNull(value);
179     int utf8 = utf8(value);
180     if (packagePool.containsKey(utf8)) {
181       return packagePool.get(utf8);
182     }
183     int index = insert(new Entry(Kind.PACKAGE, new IntValue(utf8)));
184     packagePool.put(utf8, index);
185     return index;
186   }
187 
insert(Entry key)188   private int insert(Entry key) {
189     int entry = nextEntry;
190     constants.add(key);
191     nextEntry += width(key.kind());
192     if ((nextEntry & 0xffff) != nextEntry) {
193       throw new AssertionError("constant pool has more than 2^16 entries");
194     }
195     return entry;
196   }
197 
198   /** Constant pool entry kinds. */
199   enum Kind {
200     CLASS_INFO(7),
201     STRING(8),
202     INTEGER(3),
203     DOUBLE(6),
204     FLOAT(4),
205     LONG(5),
206     UTF8(1),
207     MODULE(19),
208     PACKAGE(20);
209 
210     private final short tag;
211 
Kind(int tag)212     Kind(int tag) {
213       this.tag = (short) tag;
214     }
215 
216     /** The JVMS Table 4.4-A tag. */
tag()217     public short tag() {
218       return tag;
219     }
220   }
221 }
222