ConstantData.java revision 971:c93b6091b11e
1/* 2 * Copyright (c) 2010, 2013, 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 26package jdk.nashorn.internal.codegen; 27 28import java.util.ArrayList; 29import java.util.Arrays; 30import java.util.HashMap; 31import java.util.List; 32import java.util.Map; 33import jdk.nashorn.internal.runtime.PropertyMap; 34 35/** 36 * Manages constants needed by code generation. Objects are maintained in an 37 * interning maps to remove duplicates. 38 */ 39final class ConstantData { 40 /** Constant table. */ 41 final List<Object> constants; 42 43 /** Constant table string interning map. */ 44 final Map<String, Integer> stringMap; 45 46 /** Constant table object interning map. */ 47 final Map<Object, Integer> objectMap; 48 49 private static class ArrayWrapper { 50 private final Object array; 51 private final int hashCode; 52 53 public ArrayWrapper(final Object array) { 54 this.array = array; 55 this.hashCode = calcHashCode(); 56 } 57 58 /** 59 * Calculate a shallow hashcode for the array. 60 * @return Hashcode with elements factored in. 61 */ 62 private int calcHashCode() { 63 final Class<?> cls = array.getClass(); 64 65 if (!cls.getComponentType().isPrimitive()) { 66 return Arrays.hashCode((Object[])array); 67 } else if (cls == double[].class) { 68 return Arrays.hashCode((double[])array); 69 } if (cls == long[].class) { 70 return Arrays.hashCode((long[])array); 71 } if (cls == int[].class) { 72 return Arrays.hashCode((int[])array); 73 } 74 75 throw new AssertionError("ConstantData doesn't support " + cls); 76 } 77 78 @Override 79 public boolean equals(final Object other) { 80 if (!(other instanceof ArrayWrapper)) { 81 return false; 82 } 83 84 final Object otherArray = ((ArrayWrapper)other).array; 85 86 if (array == otherArray) { 87 return true; 88 } 89 90 final Class<?> cls = array.getClass(); 91 92 if (cls == otherArray.getClass()) { 93 if (!cls.getComponentType().isPrimitive()) { 94 return Arrays.equals((Object[])array, (Object[])otherArray); 95 } else if (cls == double[].class) { 96 return Arrays.equals((double[])array, (double[])otherArray); 97 } else if (cls == long[].class) { 98 return Arrays.equals((long[])array, (long[])otherArray); 99 } else if (cls == int[].class) { 100 return Arrays.equals((int[])array, (int[])otherArray); 101 } 102 } 103 104 return false; 105 } 106 107 @Override 108 public int hashCode() { 109 return hashCode; 110 } 111 } 112 113 /** 114 * {@link PropertyMap} wrapper class that provides implementations for the {@code hashCode} and {@code equals} 115 * methods that are based on the map layout. {@code PropertyMap} itself inherits the identity based implementations 116 * from {@code java.lang.Object}. 117 */ 118 private static class PropertyMapWrapper { 119 private final PropertyMap propertyMap; 120 private final int hashCode; 121 122 public PropertyMapWrapper(final PropertyMap map) { 123 this.hashCode = Arrays.hashCode(map.getProperties()); 124 this.propertyMap = map; 125 } 126 127 @Override 128 public int hashCode() { 129 return hashCode; 130 } 131 132 @Override 133 public boolean equals(final Object other) { 134 return other instanceof PropertyMapWrapper && 135 Arrays.equals(propertyMap.getProperties(), ((PropertyMapWrapper) other).propertyMap.getProperties()); 136 } 137 } 138 139 /** 140 * Constructor 141 */ 142 ConstantData() { 143 this.constants = new ArrayList<>(); 144 this.stringMap = new HashMap<>(); 145 this.objectMap = new HashMap<>(); 146 } 147 148 /** 149 * Add a string to the constant data 150 * 151 * @param string the string to add 152 * @return the index in the constant pool that the string was given 153 */ 154 public int add(final String string) { 155 final Integer value = stringMap.get(string); 156 157 if (value != null) { 158 return value.intValue(); 159 } 160 161 constants.add(string); 162 final int index = constants.size() - 1; 163 stringMap.put(string, index); 164 165 return index; 166 } 167 168 /** 169 * Add an object to the constant data 170 * 171 * @param object the string to add 172 * @return the index in the constant pool that the object was given 173 */ 174 public int add(final Object object) { 175 assert object != null; 176 final Object entry; 177 if (object.getClass().isArray()) { 178 entry = new ArrayWrapper(object); 179 } else if (object instanceof PropertyMap) { 180 entry = new PropertyMapWrapper((PropertyMap) object); 181 } else { 182 entry = object; 183 } 184 final Integer value = objectMap.get(entry); 185 186 if (value != null) { 187 return value.intValue(); 188 } 189 190 constants.add(object); 191 final int index = constants.size() - 1; 192 objectMap.put(entry, index); 193 194 return index; 195 } 196 197 Object[] toArray() { 198 return constants.toArray(); 199 } 200} 201