• 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 
44   private final List<Entry> constants = new ArrayList<>();
45 
46   /** The ordered list of constant pool entries. */
constants()47   public ImmutableList<Entry> constants() {
48     return ImmutableList.copyOf(constants);
49   }
50 
51   /** The number of constant pool entries the given kind takes up. */
width(Kind kind)52   private static short width(Kind kind) {
53     switch (kind) {
54       case CLASS_INFO:
55       case STRING:
56       case INTEGER:
57       case UTF8:
58       case FLOAT:
59         return 1;
60       case LONG:
61       case DOUBLE:
62         // "In retrospect, making 8-byte constants take two constant pool entries
63         // was a poor choice." -- JVMS 4.4.5
64         return 2;
65       default:
66         throw new AssertionError(kind);
67     }
68   }
69 
70   /** A constant pool entry. */
71   static class Entry {
72     private final Kind kind;
73     private final Value value;
74 
Entry(Kind kind, Value value)75     Entry(Kind kind, Value value) {
76       this.kind = kind;
77       this.value = value;
78     }
79 
80     /** The entry kind. */
kind()81     public Kind kind() {
82       return kind;
83     }
84 
85     /** The entry's value. */
value()86     public Value value() {
87       return value;
88     }
89   }
90 
91   /** Adds a CONSTANT_Class_info entry to the pool. */
classInfo(String value)92   int classInfo(String value) {
93     Objects.requireNonNull(value);
94     int utf8 = utf8(value);
95     if (classInfoPool.containsKey(utf8)) {
96       return classInfoPool.get(utf8);
97     }
98     int index = insert(new Entry(Kind.CLASS_INFO, new IntValue(utf8)));
99     classInfoPool.put(utf8, index);
100     return index;
101   }
102 
103   /** Adds a CONSTANT_Utf8_info entry to the pool. */
utf8(String value)104   int utf8(String value) {
105     Objects.requireNonNull(value);
106     if (utf8Pool.containsKey(value)) {
107       return utf8Pool.get(value);
108     }
109     int index = insert(new Entry(Kind.UTF8, new StringValue(value)));
110     utf8Pool.put(value, index);
111     return index;
112   }
113 
integer(int value)114   int integer(int value) {
115     if (integerPool.containsKey(value)) {
116       return integerPool.get(value);
117     }
118     int index = insert(new Entry(Kind.INTEGER, new Const.IntValue(value)));
119     integerPool.put(value, index);
120     return index;
121   }
122 
longInfo(long value)123   int longInfo(long value) {
124     if (longPool.containsKey(value)) {
125       return longPool.get(value);
126     }
127     int index = insert(new Entry(Kind.LONG, new Const.LongValue(value)));
128     longPool.put(value, index);
129     return index;
130   }
131 
doubleInfo(double value)132   int doubleInfo(double value) {
133     if (doublePool.containsKey(value)) {
134       return doublePool.get(value);
135     }
136     int index = insert(new Entry(Kind.DOUBLE, new Const.DoubleValue(value)));
137     doublePool.put(value, index);
138     return index;
139   }
140 
floatInfo(float value)141   int floatInfo(float value) {
142     if (floatPool.containsKey(value)) {
143       return floatPool.get(value);
144     }
145     int index = insert(new Entry(Kind.FLOAT, new Const.FloatValue(value)));
146     floatPool.put(value, index);
147     return index;
148   }
149 
string(String value)150   int string(String value) {
151     Objects.requireNonNull(value);
152     int utf8 = utf8(value);
153     if (stringPool.containsKey(utf8)) {
154       return stringPool.get(utf8);
155     }
156     int index = insert(new Entry(Kind.STRING, new IntValue(utf8)));
157     stringPool.put(utf8, index);
158     return index;
159   }
160 
insert(Entry key)161   private int insert(Entry key) {
162     int entry = nextEntry;
163     constants.add(key);
164     nextEntry += width(key.kind());
165     if ((nextEntry & 0xffff) != nextEntry) {
166       throw new AssertionError("constant pool has more than 2^16 entries");
167     }
168     return entry;
169   }
170 
171   /** Constant pool entry kinds. */
172   enum Kind {
173     CLASS_INFO(7),
174     STRING(8),
175     INTEGER(3),
176     DOUBLE(6),
177     FLOAT(4),
178     LONG(5),
179     UTF8(1);
180 
181     private final short tag;
182 
Kind(int tag)183     Kind(int tag) {
184       this.tag = (short) tag;
185     }
186 
187     /** The JVMS Table 4.4-A tag. */
tag()188     public short tag() {
189       return tag;
190     }
191   }
192 }
193