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