author | hannesw |
Thu, 05 Feb 2015 14:42:14 +0100 | |
changeset 28786 | 679fd2d26470 |
parent 27356 | 2d407b9be8b0 |
child 29534 | f0a6624dce16 |
permissions | -rw-r--r-- |
16147 | 1 |
/* |
16151 | 2 |
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
16147 | 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 |
||
26 |
package jdk.nashorn.internal.runtime; |
|
27 |
||
17513 | 28 |
import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP; |
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
29 |
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
30 |
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; |
16147 | 31 |
|
23767 | 32 |
import java.io.IOException; |
33 |
import java.io.ObjectInputStream; |
|
34 |
import java.io.ObjectOutputStream; |
|
35 |
import java.io.Serializable; |
|
16147 | 36 |
import java.lang.invoke.SwitchPoint; |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
37 |
import java.lang.ref.SoftReference; |
16147 | 38 |
import java.util.Arrays; |
26060 | 39 |
import java.util.BitSet; |
16147 | 40 |
import java.util.Collection; |
41 |
import java.util.HashMap; |
|
42 |
import java.util.Iterator; |
|
43 |
import java.util.NoSuchElementException; |
|
44 |
import java.util.WeakHashMap; |
|
23767 | 45 |
import jdk.nashorn.internal.scripts.JO; |
16147 | 46 |
|
47 |
/** |
|
48 |
* Map of object properties. The PropertyMap is the "template" for JavaScript object |
|
49 |
* layouts. It contains a map with prototype names as keys and {@link Property} instances |
|
50 |
* as values. A PropertyMap is typically passed to the {@link ScriptObject} constructor |
|
51 |
* to form the seed map for the ScriptObject. |
|
52 |
* <p> |
|
53 |
* All property maps are immutable. If a property is added, modified or removed, the mutator |
|
54 |
* will return a new map. |
|
55 |
*/ |
|
23767 | 56 |
public final class PropertyMap implements Iterable<Object>, Serializable { |
16147 | 57 |
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */ |
17513 | 58 |
public static final int NOT_EXTENSIBLE = 0b0000_0001; |
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
59 |
/** Does this map contain valid array keys? */ |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
60 |
public static final int CONTAINS_ARRAY_KEYS = 0b0000_0010; |
17513 | 61 |
|
16147 | 62 |
/** Map status flags. */ |
63 |
private int flags; |
|
64 |
||
65 |
/** Map of properties. */ |
|
23767 | 66 |
private transient PropertyHashMap properties; |
16147 | 67 |
|
17513 | 68 |
/** Number of fields in use. */ |
69 |
private int fieldCount; |
|
70 |
||
71 |
/** Number of fields available. */ |
|
24721
81f70e23cd3b
8036127: Prototype filter needs to be applied to getter guard as well, not just getter
lagergren
parents:
24719
diff
changeset
|
72 |
private final int fieldMaximum; |
16147 | 73 |
|
74 |
/** Length of spill in use. */ |
|
75 |
private int spillLength; |
|
76 |
||
23767 | 77 |
/** Structure class name */ |
78 |
private String className; |
|
79 |
||
16147 | 80 |
/** {@link SwitchPoint}s for gets on inherited properties. */ |
23767 | 81 |
private transient HashMap<String, SwitchPoint> protoGetSwitches; |
16147 | 82 |
|
83 |
/** History of maps, used to limit map duplication. */ |
|
23767 | 84 |
private transient WeakHashMap<Property, SoftReference<PropertyMap>> history; |
16147 | 85 |
|
86 |
/** History of prototypes, used to limit map duplication. */ |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
87 |
private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory; |
16147 | 88 |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
89 |
/** property listeners */ |
23767 | 90 |
private transient PropertyListeners listeners; |
91 |
||
26060 | 92 |
private transient BitSet freeSlots; |
93 |
||
23767 | 94 |
private static final long serialVersionUID = -7041836752008732533L; |
16147 | 95 |
|
96 |
/** |
|
97 |
* Constructor. |
|
98 |
* |
|
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
99 |
* @param properties A {@link PropertyHashMap} with initial contents. |
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
100 |
* @param fieldCount Number of fields in use. |
17513 | 101 |
* @param fieldMaximum Number of fields available. |
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
102 |
* @param spillLength Number of spill slots used. |
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
103 |
* @param containsArrayKeys True if properties contain numeric keys |
16147 | 104 |
*/ |
23767 | 105 |
private PropertyMap(final PropertyHashMap properties, final String className, final int fieldCount, |
106 |
final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) { |
|
17513 | 107 |
this.properties = properties; |
23767 | 108 |
this.className = className; |
17513 | 109 |
this.fieldCount = fieldCount; |
110 |
this.fieldMaximum = fieldMaximum; |
|
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
111 |
this.spillLength = spillLength; |
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
112 |
if (containsArrayKeys) { |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
113 |
setContainsArrayKeys(); |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
114 |
} |
16147 | 115 |
|
116 |
if (Context.DEBUG) { |
|
117 |
count++; |
|
118 |
} |
|
119 |
} |
|
120 |
||
121 |
/** |
|
122 |
* Cloning constructor. |
|
123 |
* |
|
124 |
* @param propertyMap Existing property map. |
|
125 |
* @param properties A {@link PropertyHashMap} with a new set of properties. |
|
126 |
*/ |
|
127 |
private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) { |
|
17513 | 128 |
this.properties = properties; |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
129 |
this.flags = propertyMap.flags; |
17513 | 130 |
this.spillLength = propertyMap.spillLength; |
131 |
this.fieldCount = propertyMap.fieldCount; |
|
132 |
this.fieldMaximum = propertyMap.fieldMaximum; |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
133 |
// We inherit the parent property listeners instance. It will be cloned when a new listener is added. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
134 |
this.listeners = propertyMap.listeners; |
26060 | 135 |
this.freeSlots = propertyMap.freeSlots; |
16147 | 136 |
|
137 |
if (Context.DEBUG) { |
|
138 |
count++; |
|
139 |
clonedCount++; |
|
140 |
} |
|
141 |
} |
|
142 |
||
143 |
/** |
|
17513 | 144 |
* Cloning constructor. |
145 |
* |
|
146 |
* @param propertyMap Existing property map. |
|
147 |
*/ |
|
148 |
private PropertyMap(final PropertyMap propertyMap) { |
|
149 |
this(propertyMap, propertyMap.properties); |
|
150 |
} |
|
151 |
||
23767 | 152 |
private void writeObject(final ObjectOutputStream out) throws IOException { |
153 |
out.defaultWriteObject(); |
|
154 |
out.writeObject(properties.getProperties()); |
|
155 |
} |
|
156 |
||
157 |
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
|
158 |
in.defaultReadObject(); |
|
159 |
||
160 |
final Property[] props = (Property[]) in.readObject(); |
|
161 |
this.properties = EMPTY_HASHMAP.immutableAdd(props); |
|
162 |
||
163 |
assert className != null; |
|
164 |
final Class<?> structure = Context.forStructureClass(className); |
|
24778
2ff5d7041566
8044638: Tidy up Nashorn codebase for code standards
attila
parents:
24769
diff
changeset
|
165 |
for (final Property prop : props) { |
23767 | 166 |
prop.initMethodHandles(structure); |
167 |
} |
|
16147 | 168 |
} |
169 |
||
170 |
/** |
|
171 |
* Public property map allocator. |
|
172 |
* |
|
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
173 |
* <p>It is the caller's responsibility to make sure that {@code properties} does not contain |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
174 |
* properties with keys that are valid array indices.</p> |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
175 |
* |
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
176 |
* @param properties Collection of initial properties. |
24993
b707d46bae40
8046898: Make sure that lazy compilation is the default, remove redundant "enable lazy compilation" flags, added warning message if compile logging is enabled and lazy is switched off. Verified existing test suite code coverage equivalence between lazy and eager.
lagergren
parents:
24778
diff
changeset
|
177 |
* @param className class name |
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
178 |
* @param fieldCount Number of fields in use. |
17513 | 179 |
* @param fieldMaximum Number of fields available. |
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
180 |
* @param spillLength Number of used spill slots. |
16147 | 181 |
* @return New {@link PropertyMap}. |
182 |
*/ |
|
23767 | 183 |
public static PropertyMap newMap(final Collection<Property> properties, final String className, final int fieldCount, final int fieldMaximum, final int spillLength) { |
24721
81f70e23cd3b
8036127: Prototype filter needs to be applied to getter guard as well, not just getter
lagergren
parents:
24719
diff
changeset
|
184 |
final PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties); |
23767 | 185 |
return new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength, false); |
16147 | 186 |
} |
187 |
||
188 |
/** |
|
18855
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
189 |
* Public property map allocator. Used by nasgen generated code. |
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
190 |
* |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
191 |
* <p>It is the caller's responsibility to make sure that {@code properties} does not contain |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
192 |
* properties with keys that are valid array indices.</p> |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
193 |
* |
18855
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
194 |
* @param properties Collection of initial properties. |
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
195 |
* @return New {@link PropertyMap}. |
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
196 |
*/ |
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
197 |
public static PropertyMap newMap(final Collection<Property> properties) { |
24769 | 198 |
return properties == null || properties.isEmpty()? newMap() : newMap(properties, JO.class.getName(), 0, 0, 0); |
18855
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
199 |
} |
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
200 |
|
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
201 |
/** |
16147 | 202 |
* Return a sharable empty map. |
203 |
* |
|
204 |
* @return New empty {@link PropertyMap}. |
|
205 |
*/ |
|
18852
604c1d681b6f
8017084: Use spill properties for large object literals
hannesw
parents:
18618
diff
changeset
|
206 |
public static PropertyMap newMap() { |
23767 | 207 |
return new PropertyMap(EMPTY_HASHMAP, JO.class.getName(), 0, 0, 0, false); |
16147 | 208 |
} |
209 |
||
210 |
/** |
|
211 |
* Return number of properties in the map. |
|
212 |
* |
|
213 |
* @return Number of properties. |
|
214 |
*/ |
|
215 |
public int size() { |
|
216 |
return properties.size(); |
|
217 |
} |
|
218 |
||
219 |
/** |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
220 |
* Get the listeners of this map, or null if none exists |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
221 |
* |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
222 |
* @return the listeners |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
223 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
224 |
public PropertyListeners getListeners() { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
225 |
return listeners; |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
226 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
227 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
228 |
/** |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
229 |
* Add {@code listenerMap} as a listener to this property map for the given {@code key}. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
230 |
* |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
231 |
* @param key the property name |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
232 |
* @param listenerMap the listener map |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
233 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
234 |
public void addListener(final String key, final PropertyMap listenerMap) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
235 |
if (listenerMap != this) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
236 |
// We need to clone listener instance when adding a new listener since we share |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
237 |
// the listeners instance with our parent maps that don't need to see the new listener. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
238 |
listeners = PropertyListeners.addListener(listeners, key, listenerMap); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
239 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
240 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
241 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
242 |
/** |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
243 |
* A new property is being added. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
244 |
* |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
245 |
* @param property The new Property added. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
246 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
247 |
public void propertyAdded(final Property property) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
248 |
invalidateProtoGetSwitchPoint(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
249 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
250 |
listeners.propertyAdded(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
251 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
252 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
253 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
254 |
/** |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
255 |
* An existing property is being deleted. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
256 |
* |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
257 |
* @param property The property being deleted. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
258 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
259 |
public void propertyDeleted(final Property property) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
260 |
invalidateProtoGetSwitchPoint(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
261 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
262 |
listeners.propertyDeleted(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
263 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
264 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
265 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
266 |
/** |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
267 |
* An existing property is being redefined. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
268 |
* |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
269 |
* @param oldProperty The old property |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
270 |
* @param newProperty The new property |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
271 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
272 |
public void propertyModified(final Property oldProperty, final Property newProperty) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
273 |
invalidateProtoGetSwitchPoint(oldProperty); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
274 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
275 |
listeners.propertyModified(oldProperty, newProperty); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
276 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
277 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
278 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
279 |
/** |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
280 |
* The prototype of an object associated with this {@link PropertyMap} is changed. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
281 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
282 |
public void protoChanged() { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
283 |
invalidateAllProtoGetSwitchPoints(); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
284 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
285 |
listeners.protoChanged(); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
286 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
287 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
288 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
289 |
/** |
16147 | 290 |
* Return a SwitchPoint used to track changes of a property in a prototype. |
291 |
* |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
292 |
* @param key Property key. |
16147 | 293 |
* @return A shared {@link SwitchPoint} for the property. |
294 |
*/ |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
295 |
public synchronized SwitchPoint getSwitchPoint(final String key) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
296 |
if (protoGetSwitches == null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
297 |
protoGetSwitches = new HashMap<>(); |
16147 | 298 |
} |
299 |
||
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
300 |
SwitchPoint switchPoint = protoGetSwitches.get(key); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
301 |
if (switchPoint == null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
302 |
switchPoint = new SwitchPoint(); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
303 |
protoGetSwitches.put(key, switchPoint); |
16147 | 304 |
} |
305 |
||
306 |
return switchPoint; |
|
307 |
} |
|
308 |
||
309 |
/** |
|
19619
4085b74056ee
8023368: Instance __proto__ property should exist and be writable.
sundar
parents:
19097
diff
changeset
|
310 |
* Indicate that a prototype property has changed. |
16147 | 311 |
* |
312 |
* @param property {@link Property} to invalidate. |
|
313 |
*/ |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
314 |
synchronized void invalidateProtoGetSwitchPoint(final Property property) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
315 |
if (protoGetSwitches != null) { |
18855
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
316 |
|
16147 | 317 |
final String key = property.getKey(); |
318 |
final SwitchPoint sp = protoGetSwitches.get(key); |
|
319 |
if (sp != null) { |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
320 |
protoGetSwitches.remove(key); |
16147 | 321 |
if (Context.DEBUG) { |
322 |
protoInvalidations++; |
|
323 |
} |
|
324 |
SwitchPoint.invalidateAll(new SwitchPoint[] { sp }); |
|
325 |
} |
|
326 |
} |
|
327 |
} |
|
328 |
||
329 |
/** |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
330 |
* Indicate that proto itself has changed in hierarchy somewhere. |
19619
4085b74056ee
8023368: Instance __proto__ property should exist and be writable.
sundar
parents:
19097
diff
changeset
|
331 |
*/ |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
332 |
synchronized void invalidateAllProtoGetSwitchPoints() { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
333 |
if (protoGetSwitches != null && !protoGetSwitches.isEmpty()) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
334 |
if (Context.DEBUG) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
335 |
protoInvalidations += protoGetSwitches.size(); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
336 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
337 |
SwitchPoint.invalidateAll(protoGetSwitches.values().toArray(new SwitchPoint[protoGetSwitches.values().size()])); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
338 |
protoGetSwitches.clear(); |
19619
4085b74056ee
8023368: Instance __proto__ property should exist and be writable.
sundar
parents:
19097
diff
changeset
|
339 |
} |
4085b74056ee
8023368: Instance __proto__ property should exist and be writable.
sundar
parents:
19097
diff
changeset
|
340 |
} |
4085b74056ee
8023368: Instance __proto__ property should exist and be writable.
sundar
parents:
19097
diff
changeset
|
341 |
|
4085b74056ee
8023368: Instance __proto__ property should exist and be writable.
sundar
parents:
19097
diff
changeset
|
342 |
/** |
16147 | 343 |
* Add a property to the map, re-binding its getters and setters, |
344 |
* if available, to a given receiver. This is typically the global scope. See |
|
345 |
* {@link ScriptObject#addBoundProperties(ScriptObject)} |
|
346 |
* |
|
347 |
* @param property {@link Property} being added. |
|
348 |
* @param bindTo Object to bind to. |
|
349 |
* |
|
350 |
* @return New {@link PropertyMap} with {@link Property} added. |
|
351 |
*/ |
|
18860
e387fde9322a
8014785: Ability to extend global instance by binding properties of another object
sundar
parents:
18855
diff
changeset
|
352 |
PropertyMap addPropertyBind(final AccessorProperty property, final Object bindTo) { |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
353 |
// No need to store bound property in the history as bound properties can't be reused. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
354 |
return addPropertyNoHistory(new AccessorProperty(property, bindTo)); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
355 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
356 |
|
26060 | 357 |
// Get a logical slot index for a property, with spill slot 0 starting at fieldMaximum. |
358 |
private int logicalSlotIndex(final Property property) { |
|
359 |
final int slot = property.getSlot(); |
|
360 |
if (slot < 0) { |
|
361 |
return -1; |
|
362 |
} |
|
363 |
return property.isSpill() ? slot + fieldMaximum : slot; |
|
364 |
} |
|
365 |
||
366 |
// Update boundaries and flags after a property has been added |
|
367 |
private void updateFlagsAndBoundaries(final Property newProperty) { |
|
368 |
if(newProperty.isSpill()) { |
|
369 |
spillLength = Math.max(spillLength, newProperty.getSlot() + 1); |
|
370 |
} else { |
|
371 |
fieldCount = Math.max(fieldCount, newProperty.getSlot() + 1); |
|
372 |
} |
|
373 |
if (isValidArrayIndex(getArrayIndex(newProperty.getKey()))) { |
|
374 |
setContainsArrayKeys(); |
|
375 |
} |
|
376 |
} |
|
377 |
||
378 |
// Update the free slots bitmap for a property that has been deleted and/or added. |
|
379 |
private void updateFreeSlots(final Property oldProperty, final Property newProperty) { |
|
380 |
// Free slots bitset is possibly shared with parent map, so we must clone it before making modifications. |
|
381 |
boolean freeSlotsCloned = false; |
|
382 |
if (oldProperty != null) { |
|
383 |
final int slotIndex = logicalSlotIndex(oldProperty); |
|
384 |
if (slotIndex >= 0) { |
|
385 |
final BitSet newFreeSlots = freeSlots == null ? new BitSet() : (BitSet)freeSlots.clone(); |
|
386 |
assert !newFreeSlots.get(slotIndex); |
|
387 |
newFreeSlots.set(slotIndex); |
|
388 |
freeSlots = newFreeSlots; |
|
389 |
freeSlotsCloned = true; |
|
390 |
} |
|
391 |
} |
|
392 |
if (freeSlots != null && newProperty != null) { |
|
393 |
final int slotIndex = logicalSlotIndex(newProperty); |
|
394 |
if (slotIndex > -1 && freeSlots.get(slotIndex)) { |
|
395 |
final BitSet newFreeSlots = freeSlotsCloned ? freeSlots : ((BitSet)freeSlots.clone()); |
|
396 |
newFreeSlots.clear(slotIndex); |
|
397 |
freeSlots = newFreeSlots.isEmpty() ? null : newFreeSlots; |
|
398 |
} |
|
399 |
} |
|
400 |
} |
|
401 |
||
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
402 |
/** |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
403 |
* Add a property to the map without adding it to the history. This should be used for properties that |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
404 |
* can't be shared such as bound properties, or properties that are expected to be added only once. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
405 |
* |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
406 |
* @param property {@link Property} being added. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
407 |
* @return New {@link PropertyMap} with {@link Property} added. |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
408 |
*/ |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
409 |
public PropertyMap addPropertyNoHistory(final Property property) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
410 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
411 |
listeners.propertyAdded(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
412 |
} |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
413 |
final PropertyHashMap newProperties = properties.immutableAdd(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
414 |
final PropertyMap newMap = new PropertyMap(this, newProperties); |
26060 | 415 |
newMap.updateFlagsAndBoundaries(property); |
416 |
newMap.updateFreeSlots(null, property); |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
417 |
|
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
418 |
return newMap; |
16147 | 419 |
} |
420 |
||
421 |
/** |
|
422 |
* Add a property to the map. Cloning or using an existing map if available. |
|
423 |
* |
|
424 |
* @param property {@link Property} being added. |
|
425 |
* |
|
426 |
* @return New {@link PropertyMap} with {@link Property} added. |
|
427 |
*/ |
|
18617
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
428 |
public PropertyMap addProperty(final Property property) { |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
429 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
430 |
listeners.propertyAdded(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
431 |
} |
16147 | 432 |
PropertyMap newMap = checkHistory(property); |
433 |
||
434 |
if (newMap == null) { |
|
435 |
final PropertyHashMap newProperties = properties.immutableAdd(property); |
|
436 |
newMap = new PropertyMap(this, newProperties); |
|
437 |
addToHistory(property, newMap); |
|
26060 | 438 |
newMap.updateFlagsAndBoundaries(property); |
439 |
newMap.updateFreeSlots(null, property); |
|
16147 | 440 |
} |
441 |
||
442 |
return newMap; |
|
443 |
} |
|
444 |
||
445 |
/** |
|
446 |
* Remove a property from a map. Cloning or using an existing map if available. |
|
447 |
* |
|
448 |
* @param property {@link Property} being removed. |
|
449 |
* |
|
450 |
* @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found. |
|
451 |
*/ |
|
16228 | 452 |
public PropertyMap deleteProperty(final Property property) { |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
453 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
454 |
listeners.propertyDeleted(property); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
455 |
} |
16147 | 456 |
PropertyMap newMap = checkHistory(property); |
457 |
final String key = property.getKey(); |
|
458 |
||
459 |
if (newMap == null && properties.containsKey(key)) { |
|
460 |
final PropertyHashMap newProperties = properties.immutableRemove(key); |
|
26060 | 461 |
final boolean isSpill = property.isSpill(); |
462 |
final int slot = property.getSlot(); |
|
463 |
// If deleted property was last field or spill slot we can make it reusable by reducing field/slot count. |
|
464 |
// Otherwise mark it as free in free slots bitset. |
|
465 |
if (isSpill && slot >= 0 && slot == spillLength - 1) { |
|
466 |
newMap = new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength - 1, containsArrayKeys()); |
|
467 |
newMap.freeSlots = freeSlots; |
|
468 |
} else if (!isSpill && slot >= 0 && slot == fieldCount - 1) { |
|
469 |
newMap = new PropertyMap(newProperties, className, fieldCount - 1, fieldMaximum, spillLength, containsArrayKeys()); |
|
470 |
newMap.freeSlots = freeSlots; |
|
471 |
} else { |
|
472 |
newMap = new PropertyMap(this, newProperties); |
|
473 |
newMap.updateFreeSlots(property, null); |
|
474 |
} |
|
16147 | 475 |
addToHistory(property, newMap); |
476 |
} |
|
477 |
||
478 |
return newMap; |
|
479 |
} |
|
480 |
||
481 |
/** |
|
482 |
* Replace an existing property with a new one. |
|
483 |
* |
|
484 |
* @param oldProperty Property to replace. |
|
485 |
* @param newProperty New {@link Property}. |
|
486 |
* |
|
487 |
* @return New {@link PropertyMap} with {@link Property} replaced. |
|
488 |
*/ |
|
28786 | 489 |
public PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) { |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
490 |
if (listeners != null) { |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
491 |
listeners.propertyModified(oldProperty, newProperty); |
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
492 |
} |
16147 | 493 |
// Add replaces existing property. |
24719 | 494 |
final PropertyHashMap newProperties = properties.immutableReplace(oldProperty, newProperty); |
16147 | 495 |
final PropertyMap newMap = new PropertyMap(this, newProperties); |
496 |
/* |
|
497 |
* See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods. |
|
498 |
* |
|
499 |
* This replaceProperty method is called only for the following three cases: |
|
500 |
* |
|
501 |
* 1. To change flags OR TYPE of an old (cloned) property. We use the same spill slots. |
|
502 |
* 2. To change one UserAccessor property with another - user getter or setter changed via |
|
503 |
* Object.defineProperty function. Again, same spill slots are re-used. |
|
504 |
* 3. Via ScriptObject.setUserAccessors method to set user getter and setter functions |
|
505 |
* replacing the dummy AccessorProperty with null method handles (added during map init). |
|
506 |
* |
|
507 |
* In case (1) and case(2), the property type of old and new property is same. For case (3), |
|
508 |
* the old property is an AccessorProperty and the new one is a UserAccessorProperty property. |
|
509 |
*/ |
|
510 |
||
24721
81f70e23cd3b
8036127: Prototype filter needs to be applied to getter guard as well, not just getter
lagergren
parents:
24719
diff
changeset
|
511 |
final boolean sameType = oldProperty.getClass() == newProperty.getClass(); |
16147 | 512 |
assert sameType || |
24721
81f70e23cd3b
8036127: Prototype filter needs to be applied to getter guard as well, not just getter
lagergren
parents:
24719
diff
changeset
|
513 |
oldProperty instanceof AccessorProperty && |
81f70e23cd3b
8036127: Prototype filter needs to be applied to getter guard as well, not just getter
lagergren
parents:
24719
diff
changeset
|
514 |
newProperty instanceof UserAccessorProperty : |
27307
62ed492cbe63
8062401: User accessors require boxing and do not support optimistic types
hannesw
parents:
26768
diff
changeset
|
515 |
"arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getLocalType() + " => " + newProperty.getLocalType() + "]"; |
16147 | 516 |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
517 |
newMap.flags = flags; |
16147 | 518 |
|
519 |
/* |
|
520 |
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need |
|
521 |
* to add spill count of the newly added UserAccessorProperty property. |
|
522 |
*/ |
|
26060 | 523 |
if (!sameType) { |
524 |
newMap.spillLength = Math.max(spillLength, newProperty.getSlot() + 1); |
|
525 |
newMap.updateFreeSlots(oldProperty, newProperty); |
|
526 |
} |
|
16147 | 527 |
return newMap; |
528 |
} |
|
529 |
||
19097
f544a2ea40ef
8021262: Make nashorn access checks consistent with underlying dynalink
sundar
parents:
18860
diff
changeset
|
530 |
/** |
18617
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
531 |
* Make a new UserAccessorProperty property. getter and setter functions are stored in |
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
532 |
* this ScriptObject and slot values are used in property object. Note that slots |
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
533 |
* are assigned speculatively and should be added to map before adding other |
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
534 |
* properties. |
19097
f544a2ea40ef
8021262: Make nashorn access checks consistent with underlying dynalink
sundar
parents:
18860
diff
changeset
|
535 |
* |
f544a2ea40ef
8021262: Make nashorn access checks consistent with underlying dynalink
sundar
parents:
18860
diff
changeset
|
536 |
* @param key the property name |
f544a2ea40ef
8021262: Make nashorn access checks consistent with underlying dynalink
sundar
parents:
18860
diff
changeset
|
537 |
* @param propertyFlags attribute flags of the property |
f544a2ea40ef
8021262: Make nashorn access checks consistent with underlying dynalink
sundar
parents:
18860
diff
changeset
|
538 |
* @return the newly created UserAccessorProperty |
18617
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
539 |
*/ |
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
540 |
public UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) { |
26060 | 541 |
return new UserAccessorProperty(key, propertyFlags, getFreeSpillSlot()); |
18617
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
542 |
} |
f6fe338f62c3
8008458: Strict functions dont share property map
jlaskey
parents:
18325
diff
changeset
|
543 |
|
16147 | 544 |
/** |
545 |
* Find a property in the map. |
|
546 |
* |
|
547 |
* @param key Key to search for. |
|
548 |
* |
|
549 |
* @return {@link Property} matching key. |
|
550 |
*/ |
|
551 |
public Property findProperty(final String key) { |
|
552 |
return properties.find(key); |
|
553 |
} |
|
554 |
||
555 |
/** |
|
556 |
* Adds all map properties from another map. |
|
557 |
* |
|
558 |
* @param other The source of properties. |
|
559 |
* |
|
560 |
* @return New {@link PropertyMap} with added properties. |
|
561 |
*/ |
|
562 |
public PropertyMap addAll(final PropertyMap other) { |
|
16216
46ed48fd84d3
8007273: Creation of ScriptFunctions can be refactored
hannesw
parents:
16201
diff
changeset
|
563 |
assert this != other : "adding property map to itself"; |
16147 | 564 |
final Property[] otherProperties = other.properties.getProperties(); |
565 |
final PropertyHashMap newProperties = properties.immutableAdd(otherProperties); |
|
566 |
||
567 |
final PropertyMap newMap = new PropertyMap(this, newProperties); |
|
568 |
for (final Property property : otherProperties) { |
|
26060 | 569 |
// This method is only safe to use with non-slotted, native getter/setter properties |
570 |
assert property.getSlot() == -1; |
|
26648
9a64e15eff37
8056978: ClassCastException: cannot cast jdk.nashorn.internal.scripts.JO*
hannesw
parents:
26068
diff
changeset
|
571 |
assert !(isValidArrayIndex(getArrayIndex(property.getKey()))); |
16147 | 572 |
} |
573 |
||
574 |
return newMap; |
|
575 |
} |
|
576 |
||
577 |
/** |
|
578 |
* Return an array of all properties. |
|
579 |
* |
|
580 |
* @return Properties as an array. |
|
581 |
*/ |
|
582 |
public Property[] getProperties() { |
|
583 |
return properties.getProperties(); |
|
584 |
} |
|
585 |
||
586 |
/** |
|
587 |
* Prevents the map from having additional properties. |
|
588 |
* |
|
589 |
* @return New map with {@link #NOT_EXTENSIBLE} flag set. |
|
590 |
*/ |
|
591 |
PropertyMap preventExtensions() { |
|
17513 | 592 |
final PropertyMap newMap = new PropertyMap(this); |
16147 | 593 |
newMap.flags |= NOT_EXTENSIBLE; |
594 |
return newMap; |
|
595 |
} |
|
596 |
||
597 |
/** |
|
598 |
* Prevents properties in map from being modified. |
|
599 |
* |
|
16154
de44634fa4ec
8005782: get rid of javadoc errors, warnings in nashorn build
sundar
parents:
16152
diff
changeset
|
600 |
* @return New map with {@link #NOT_EXTENSIBLE} flag set and properties with |
de44634fa4ec
8005782: get rid of javadoc errors, warnings in nashorn build
sundar
parents:
16152
diff
changeset
|
601 |
* {@link Property#NOT_CONFIGURABLE} set. |
16147 | 602 |
*/ |
603 |
PropertyMap seal() { |
|
17513 | 604 |
PropertyHashMap newProperties = EMPTY_HASHMAP; |
16147 | 605 |
|
606 |
for (final Property oldProperty : properties.getProperties()) { |
|
607 |
newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE)); |
|
608 |
} |
|
609 |
||
610 |
final PropertyMap newMap = new PropertyMap(this, newProperties); |
|
611 |
newMap.flags |= NOT_EXTENSIBLE; |
|
612 |
||
613 |
return newMap; |
|
614 |
} |
|
615 |
||
616 |
/** |
|
617 |
* Prevents properties in map from being modified or written to. |
|
618 |
* |
|
619 |
* @return New map with {@link #NOT_EXTENSIBLE} flag set and properties with |
|
16154
de44634fa4ec
8005782: get rid of javadoc errors, warnings in nashorn build
sundar
parents:
16152
diff
changeset
|
620 |
* {@link Property#NOT_CONFIGURABLE} and {@link Property#NOT_WRITABLE} set. |
16147 | 621 |
*/ |
622 |
PropertyMap freeze() { |
|
17513 | 623 |
PropertyHashMap newProperties = EMPTY_HASHMAP; |
16147 | 624 |
|
24721
81f70e23cd3b
8036127: Prototype filter needs to be applied to getter guard as well, not just getter
lagergren
parents:
24719
diff
changeset
|
625 |
for (final Property oldProperty : properties.getProperties()) { |
16147 | 626 |
int propertyFlags = Property.NOT_CONFIGURABLE; |
627 |
||
628 |
if (!(oldProperty instanceof UserAccessorProperty)) { |
|
629 |
propertyFlags |= Property.NOT_WRITABLE; |
|
630 |
} |
|
631 |
||
632 |
newProperties = newProperties.immutableAdd(oldProperty.addFlags(propertyFlags)); |
|
633 |
} |
|
634 |
||
635 |
final PropertyMap newMap = new PropertyMap(this, newProperties); |
|
636 |
newMap.flags |= NOT_EXTENSIBLE; |
|
637 |
||
638 |
return newMap; |
|
639 |
} |
|
640 |
||
641 |
/** |
|
642 |
* Check for any configurable properties. |
|
643 |
* |
|
644 |
* @return {@code true} if any configurable. |
|
645 |
*/ |
|
646 |
private boolean anyConfigurable() { |
|
647 |
for (final Property property : properties.getProperties()) { |
|
648 |
if (property.isConfigurable()) { |
|
649 |
return true; |
|
650 |
} |
|
651 |
} |
|
652 |
||
653 |
return false; |
|
654 |
} |
|
655 |
||
656 |
/** |
|
657 |
* Check if all properties are frozen. |
|
658 |
* |
|
659 |
* @return {@code true} if all are frozen. |
|
660 |
*/ |
|
661 |
private boolean allFrozen() { |
|
662 |
for (final Property property : properties.getProperties()) { |
|
663 |
// check if it is a data descriptor |
|
664 |
if (!(property instanceof UserAccessorProperty)) { |
|
665 |
if (property.isWritable()) { |
|
666 |
return false; |
|
667 |
} |
|
668 |
} |
|
669 |
if (property.isConfigurable()) { |
|
670 |
return false; |
|
671 |
} |
|
672 |
} |
|
673 |
||
674 |
return true; |
|
675 |
} |
|
676 |
||
677 |
/** |
|
678 |
* Check prototype history for an existing property map with specified prototype. |
|
679 |
* |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
680 |
* @param proto New prototype object. |
16147 | 681 |
* |
682 |
* @return Existing {@link PropertyMap} or {@code null} if not found. |
|
683 |
*/ |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
684 |
private PropertyMap checkProtoHistory(final ScriptObject proto) { |
16147 | 685 |
final PropertyMap cachedMap; |
686 |
if (protoHistory != null) { |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
687 |
final SoftReference<PropertyMap> weakMap = protoHistory.get(proto); |
16147 | 688 |
cachedMap = (weakMap != null ? weakMap.get() : null); |
689 |
} else { |
|
690 |
cachedMap = null; |
|
691 |
} |
|
692 |
||
693 |
if (Context.DEBUG && cachedMap != null) { |
|
694 |
protoHistoryHit++; |
|
695 |
} |
|
696 |
||
697 |
return cachedMap; |
|
698 |
} |
|
699 |
||
700 |
/** |
|
701 |
* Add a map to the prototype history. |
|
702 |
* |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
703 |
* @param newProto Prototype to add (key.) |
16147 | 704 |
* @param newMap {@link PropertyMap} associated with prototype. |
705 |
*/ |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
706 |
private void addToProtoHistory(final ScriptObject newProto, final PropertyMap newMap) { |
16759
ecf99910fc31
8011219: Regression with recent PropertyMap history changes
hannesw
parents:
16758
diff
changeset
|
707 |
if (protoHistory == null) { |
ecf99910fc31
8011219: Regression with recent PropertyMap history changes
hannesw
parents:
16758
diff
changeset
|
708 |
protoHistory = new WeakHashMap<>(); |
ecf99910fc31
8011219: Regression with recent PropertyMap history changes
hannesw
parents:
16758
diff
changeset
|
709 |
} |
16758
4f7379c41907
8011095: PropertyHashMap.rehash() does not grow enough
jlaskey
parents:
16275
diff
changeset
|
710 |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
711 |
protoHistory.put(newProto, new SoftReference<>(newMap)); |
16147 | 712 |
} |
713 |
||
714 |
/** |
|
715 |
* Track the modification of the map. |
|
716 |
* |
|
717 |
* @param property Mapping property. |
|
718 |
* @param newMap Modified {@link PropertyMap}. |
|
719 |
*/ |
|
720 |
private void addToHistory(final Property property, final PropertyMap newMap) { |
|
24763 | 721 |
if (history == null) { |
722 |
history = new WeakHashMap<>(); |
|
723 |
} |
|
16774
745fe7d2536d
8011540: PropertyMap histories should not begin with empty map
jlaskey
parents:
16759
diff
changeset
|
724 |
|
24763 | 725 |
history.put(property, new SoftReference<>(newMap)); |
16147 | 726 |
} |
727 |
||
728 |
/** |
|
729 |
* Check the history for a map that already has the given property added. |
|
730 |
* |
|
731 |
* @param property {@link Property} to add. |
|
732 |
* |
|
733 |
* @return Existing map or {@code null} if not found. |
|
734 |
*/ |
|
735 |
private PropertyMap checkHistory(final Property property) { |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
736 |
|
16147 | 737 |
if (history != null) { |
24727 | 738 |
final SoftReference<PropertyMap> ref = history.get(property); |
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
739 |
final PropertyMap historicMap = ref == null ? null : ref.get(); |
16147 | 740 |
|
741 |
if (historicMap != null) { |
|
742 |
if (Context.DEBUG) { |
|
743 |
historyHit++; |
|
744 |
} |
|
745 |
||
746 |
return historicMap; |
|
747 |
} |
|
748 |
} |
|
749 |
||
750 |
return null; |
|
751 |
} |
|
752 |
||
753 |
/** |
|
24719 | 754 |
* Returns true if the two maps have identical properties in the same order, but allows the properties to differ in |
755 |
* their types. This method is mostly useful for tests. |
|
756 |
* @param otherMap the other map |
|
757 |
* @return true if this map has identical properties in the same order as the other map, allowing the properties to |
|
758 |
* differ in type. |
|
759 |
*/ |
|
760 |
public boolean equalsWithoutType(final PropertyMap otherMap) { |
|
761 |
if (properties.size() != otherMap.properties.size()) { |
|
762 |
return false; |
|
763 |
} |
|
764 |
||
765 |
final Iterator<Property> iter = properties.values().iterator(); |
|
766 |
final Iterator<Property> otherIter = otherMap.properties.values().iterator(); |
|
767 |
||
768 |
while (iter.hasNext() && otherIter.hasNext()) { |
|
769 |
if (!iter.next().equalsWithoutType(otherIter.next())) { |
|
770 |
return false; |
|
771 |
} |
|
772 |
} |
|
773 |
||
774 |
return true; |
|
775 |
} |
|
776 |
||
16147 | 777 |
@Override |
778 |
public String toString() { |
|
779 |
final StringBuilder sb = new StringBuilder(); |
|
780 |
||
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24721
diff
changeset
|
781 |
sb.append(Debug.id(this)); |
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24721
diff
changeset
|
782 |
sb.append(" = {\n"); |
16147 | 783 |
|
24726
34410e0545b1
8037967: Broke the build, by commiting without saving the last review comment
lagergren
parents:
24725
diff
changeset
|
784 |
for (final Property property : getProperties()) { |
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24721
diff
changeset
|
785 |
sb.append('\t'); |
24719 | 786 |
sb.append(property); |
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24721
diff
changeset
|
787 |
sb.append('\n'); |
16147 | 788 |
} |
789 |
||
24725
7bb1f687a852
8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
lagergren
parents:
24721
diff
changeset
|
790 |
sb.append('}'); |
16147 | 791 |
|
792 |
return sb.toString(); |
|
793 |
} |
|
794 |
||
795 |
@Override |
|
796 |
public Iterator<Object> iterator() { |
|
797 |
return new PropertyMapIterator(this); |
|
798 |
} |
|
799 |
||
800 |
/** |
|
21441
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
801 |
* Check if this map contains properties with valid array keys |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
802 |
* |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
803 |
* @return {@code true} if this map contains properties with valid array keys |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
804 |
*/ |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
805 |
public final boolean containsArrayKeys() { |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
806 |
return (flags & CONTAINS_ARRAY_KEYS) != 0; |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
807 |
} |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
808 |
|
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
809 |
/** |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
810 |
* Flag this object as having array keys in defined properties |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
811 |
*/ |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
812 |
private void setContainsArrayKeys() { |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
813 |
flags |= CONTAINS_ARRAY_KEYS; |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
814 |
} |
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
815 |
|
0b98be59e3cb
8026858: Array length does not handle defined properties correctly
hannesw
parents:
19619
diff
changeset
|
816 |
/** |
16147 | 817 |
* Test to see if {@link PropertyMap} is extensible. |
818 |
* |
|
819 |
* @return {@code true} if {@link PropertyMap} can be added to. |
|
820 |
*/ |
|
821 |
boolean isExtensible() { |
|
822 |
return (flags & NOT_EXTENSIBLE) == 0; |
|
823 |
} |
|
824 |
||
825 |
/** |
|
826 |
* Test to see if {@link PropertyMap} is not extensible or any properties |
|
827 |
* can not be modified. |
|
828 |
* |
|
829 |
* @return {@code true} if {@link PropertyMap} is sealed. |
|
830 |
*/ |
|
831 |
boolean isSealed() { |
|
832 |
return !isExtensible() && !anyConfigurable(); |
|
833 |
} |
|
834 |
||
835 |
/** |
|
836 |
* Test to see if {@link PropertyMap} is not extensible or all properties |
|
837 |
* can not be modified. |
|
838 |
* |
|
839 |
* @return {@code true} if {@link PropertyMap} is frozen. |
|
840 |
*/ |
|
841 |
boolean isFrozen() { |
|
842 |
return !isExtensible() && allFrozen(); |
|
843 |
} |
|
26060 | 844 |
|
17513 | 845 |
/** |
26060 | 846 |
* Return a free field slot for this map, or {@code -1} if none is available. |
17513 | 847 |
* |
26060 | 848 |
* @return free field slot or -1 |
17513 | 849 |
*/ |
26060 | 850 |
int getFreeFieldSlot() { |
851 |
if (freeSlots != null) { |
|
852 |
final int freeSlot = freeSlots.nextSetBit(0); |
|
853 |
if (freeSlot > -1 && freeSlot < fieldMaximum) { |
|
854 |
return freeSlot; |
|
855 |
} |
|
856 |
} |
|
857 |
if (fieldCount < fieldMaximum) { |
|
858 |
return fieldCount; |
|
859 |
} |
|
860 |
return -1; |
|
17513 | 861 |
} |
16147 | 862 |
|
863 |
/** |
|
26060 | 864 |
* Get a free spill slot for this map. |
16147 | 865 |
* |
26060 | 866 |
* @return free spill slot |
16147 | 867 |
*/ |
26060 | 868 |
int getFreeSpillSlot() { |
869 |
if (freeSlots != null) { |
|
870 |
final int freeSlot = freeSlots.nextSetBit(fieldMaximum); |
|
871 |
if (freeSlot > -1) { |
|
872 |
return freeSlot - fieldMaximum; |
|
873 |
} |
|
874 |
} |
|
16147 | 875 |
return spillLength; |
876 |
} |
|
877 |
||
878 |
/** |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
879 |
* Return a property map with the same layout that is associated with the new prototype object. |
16147 | 880 |
* |
17513 | 881 |
* @param newProto New prototype object to replace oldProto. |
16147 | 882 |
* @return New {@link PropertyMap} with prototype changed. |
883 |
*/ |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
884 |
public PropertyMap changeProto(final ScriptObject newProto) { |
18855
408663ef8f66
8020015: shared PropertyMaps should not be used without duplication
sundar
parents:
18852
diff
changeset
|
885 |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
886 |
final PropertyMap nextMap = checkProtoHistory(newProto); |
16147 | 887 |
if (nextMap != null) { |
888 |
return nextMap; |
|
889 |
} |
|
890 |
||
891 |
if (Context.DEBUG) { |
|
23084
6c5c02d1023a
8035948: Redesign property listeners for shared classes
hannesw
parents:
21441
diff
changeset
|
892 |
setProtoNewMapCount++; |
16147 | 893 |
} |
17513 | 894 |
|
895 |
final PropertyMap newMap = new PropertyMap(this); |
|
27356
2d407b9be8b0
8062132: Nashorn incorrectly binds this for constructor created by another function
hannesw
parents:
27307
diff
changeset
|
896 |
addToProtoHistory(newProto, newMap); |
16147 | 897 |
|
898 |
return newMap; |
|
899 |
} |
|
900 |
||
901 |
||
902 |
/** |
|
903 |
* {@link PropertyMap} iterator. |
|
904 |
*/ |
|
905 |
private static class PropertyMapIterator implements Iterator<Object> { |
|
906 |
/** Property iterator. */ |
|
907 |
final Iterator<Property> iter; |
|
908 |
||
909 |
/** Current Property. */ |
|
910 |
Property property; |
|
911 |
||
912 |
/** |
|
913 |
* Constructor. |
|
914 |
* |
|
915 |
* @param propertyMap {@link PropertyMap} to iterate over. |
|
916 |
*/ |
|
917 |
PropertyMapIterator(final PropertyMap propertyMap) { |
|
918 |
iter = Arrays.asList(propertyMap.properties.getProperties()).iterator(); |
|
919 |
property = iter.hasNext() ? iter.next() : null; |
|
920 |
skipNotEnumerable(); |
|
921 |
} |
|
922 |
||
923 |
/** |
|
924 |
* Ignore properties that are not enumerable. |
|
925 |
*/ |
|
926 |
private void skipNotEnumerable() { |
|
927 |
while (property != null && !property.isEnumerable()) { |
|
928 |
property = iter.hasNext() ? iter.next() : null; |
|
929 |
} |
|
930 |
} |
|
931 |
||
932 |
@Override |
|
933 |
public boolean hasNext() { |
|
934 |
return property != null; |
|
935 |
} |
|
936 |
||
937 |
@Override |
|
938 |
public Object next() { |
|
939 |
if (property == null) { |
|
940 |
throw new NoSuchElementException(); |
|
941 |
} |
|
942 |
||
943 |
final Object key = property.getKey(); |
|
944 |
property = iter.next(); |
|
945 |
skipNotEnumerable(); |
|
946 |
||
947 |
return key; |
|
948 |
} |
|
949 |
||
950 |
@Override |
|
951 |
public void remove() { |
|
26768
751b0f427090
8025435: Optimistic builtins support, implemented initial optimistic versions of push, pop, and charCodeAt
lagergren
parents:
26648
diff
changeset
|
952 |
throw new UnsupportedOperationException("remove"); |
16147 | 953 |
} |
954 |
} |
|
955 |
||
956 |
/* |
|
957 |
* Debugging and statistics. |
|
958 |
*/ |
|
959 |
||
24719 | 960 |
/** |
961 |
* Debug helper function that returns the diff of two property maps, only |
|
962 |
* displaying the information that is different and in which map it exists |
|
963 |
* compared to the other map. Can be used to e.g. debug map guards and |
|
964 |
* investigate why they fail, causing relink |
|
965 |
* |
|
966 |
* @param map0 the first property map |
|
967 |
* @param map1 the second property map |
|
968 |
* |
|
969 |
* @return property map diff as string |
|
970 |
*/ |
|
971 |
public static String diff(final PropertyMap map0, final PropertyMap map1) { |
|
972 |
final StringBuilder sb = new StringBuilder(); |
|
973 |
||
974 |
if (map0 != map1) { |
|
975 |
sb.append(">>> START: Map diff"); |
|
976 |
boolean found = false; |
|
977 |
||
978 |
for (final Property p : map0.getProperties()) { |
|
979 |
final Property p2 = map1.findProperty(p.getKey()); |
|
980 |
if (p2 == null) { |
|
981 |
sb.append("FIRST ONLY : [" + p + "]"); |
|
982 |
found = true; |
|
983 |
} else if (p2 != p) { |
|
984 |
sb.append("DIFFERENT : [" + p + "] != [" + p2 + "]"); |
|
985 |
found = true; |
|
986 |
} |
|
987 |
} |
|
988 |
||
989 |
for (final Property p2 : map1.getProperties()) { |
|
990 |
final Property p1 = map0.findProperty(p2.getKey()); |
|
991 |
if (p1 == null) { |
|
992 |
sb.append("SECOND ONLY: [" + p2 + "]"); |
|
993 |
found = true; |
|
994 |
} |
|
995 |
} |
|
996 |
||
997 |
//assert found; |
|
998 |
||
999 |
if (!found) { |
|
1000 |
sb.append(map0). |
|
1001 |
append("!="). |
|
1002 |
append(map1); |
|
1003 |
} |
|
1004 |
||
1005 |
sb.append("<<< END: Map diff\n"); |
|
1006 |
} |
|
1007 |
||
1008 |
return sb.toString(); |
|
1009 |
} |
|
1010 |
||
16147 | 1011 |
// counters updated only in debug mode |
1012 |
private static int count; |
|
1013 |
private static int clonedCount; |
|
1014 |
private static int historyHit; |
|
1015 |
private static int protoInvalidations; |
|
1016 |
private static int protoHistoryHit; |
|
1017 |
private static int setProtoNewMapCount; |
|
1018 |
||
1019 |
/** |
|
1020 |
* @return Total number of maps. |
|
1021 |
*/ |
|
1022 |
public static int getCount() { |
|
1023 |
return count; |
|
1024 |
} |
|
1025 |
||
1026 |
/** |
|
1027 |
* @return The number of maps that were cloned. |
|
1028 |
*/ |
|
1029 |
public static int getClonedCount() { |
|
1030 |
return clonedCount; |
|
1031 |
} |
|
1032 |
||
1033 |
/** |
|
1034 |
* @return The number of times history was successfully used. |
|
1035 |
*/ |
|
1036 |
public static int getHistoryHit() { |
|
1037 |
return historyHit; |
|
1038 |
} |
|
1039 |
||
1040 |
/** |
|
1041 |
* @return The number of times prototype changes caused invalidation. |
|
1042 |
*/ |
|
1043 |
public static int getProtoInvalidations() { |
|
1044 |
return protoInvalidations; |
|
1045 |
} |
|
1046 |
||
1047 |
/** |
|
1048 |
* @return The number of times proto history was successfully used. |
|
1049 |
*/ |
|
1050 |
public static int getProtoHistoryHit() { |
|
1051 |
return protoHistoryHit; |
|
1052 |
} |
|
1053 |
||
1054 |
/** |
|
1055 |
* @return The number of times prototypes were modified. |
|
1056 |
*/ |
|
1057 |
public static int getSetProtoNewMapCount() { |
|
1058 |
return setProtoNewMapCount; |
|
1059 |
} |
|
1060 |
} |