Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java @ 18408:2c3666f44855
Truffle: initial commit of object API implementation
author | Andreas Woess <andreas.woess@jku.at> |
---|---|
date | Tue, 18 Nov 2014 23:19:43 +0100 |
parents | |
children | 8d8523ed37e3 |
comparison
equal
deleted
inserted
replaced
18407:f439fdb137a3 | 18408:2c3666f44855 |
---|---|
1 /* | |
2 * Copyright (c) 2013, 2014, 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. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.oracle.truffle.object; | |
24 | |
25 import java.util.*; | |
26 | |
27 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; | |
28 import com.oracle.truffle.api.object.*; | |
29 import com.oracle.truffle.object.Locations.ValueLocation; | |
30 import com.oracle.truffle.object.debug.*; | |
31 | |
32 public abstract class DynamicObjectImpl implements DynamicObject, Cloneable { | |
33 private ShapeImpl shape; | |
34 | |
35 public static final DebugCounter reshapeCount = DebugCounter.create("Reshape count"); | |
36 | |
37 public DynamicObjectImpl(Shape shape) { | |
38 assert shape instanceof ShapeImpl; | |
39 initialize(shape); | |
40 setShape(shape); | |
41 | |
42 if (ObjectStorageOptions.Profile) { | |
43 trackObject(this); | |
44 } | |
45 } | |
46 | |
47 public Object getTypeIdentifier() { | |
48 return getShape(); | |
49 } | |
50 | |
51 public ShapeImpl getShape() { | |
52 return shape; | |
53 } | |
54 | |
55 protected void setShape(Shape shape) { | |
56 assert shape.getLayout().getType().isInstance(this); | |
57 this.shape = (ShapeImpl) shape; | |
58 } | |
59 | |
60 protected abstract void initialize(Shape initialShape); | |
61 | |
62 public final void setShapeAndResize(Shape newShape) { | |
63 setShapeAndResize(getShape(), newShape); | |
64 } | |
65 | |
66 public final void setShapeAndResize(Shape oldShape, Shape newShape) { | |
67 assert getShape() == oldShape : "wrong old shape"; | |
68 if (oldShape != newShape) { | |
69 setShape(newShape); | |
70 resizeStore(oldShape, newShape); | |
71 | |
72 assert checkExtensionArrayInvariants(newShape); | |
73 } | |
74 } | |
75 | |
76 /** | |
77 * Set shape to an immediate child of the current shape, optionally growing the extension array. | |
78 * Typically this would add a single property. Cannot shrink or grow more than one property at a | |
79 * time. | |
80 * | |
81 * @see #setShapeAndResize(Shape, Shape) | |
82 */ | |
83 public final void setShapeAndGrow(Shape oldShape, Shape newShape) { | |
84 assert getShape() == oldShape : "wrong old shape"; | |
85 if (oldShape != newShape) { | |
86 assert checkSetShape(oldShape, newShape); | |
87 | |
88 setShape(newShape); | |
89 growStore(oldShape, newShape); | |
90 | |
91 assert checkExtensionArrayInvariants(newShape); | |
92 } | |
93 } | |
94 | |
95 /** | |
96 * Simpler version of {@link #resizeStore} when the object is only increasing in size. | |
97 */ | |
98 private void growStore(Shape oldShape, Shape newShape) { | |
99 growObjectStore(oldShape, newShape); | |
100 if (((ShapeImpl) newShape).hasPrimitiveArray) { | |
101 growPrimitiveStore(oldShape, newShape); | |
102 } | |
103 } | |
104 | |
105 protected abstract void growObjectStore(Shape oldShape, Shape newShape); | |
106 | |
107 protected abstract void growPrimitiveStore(Shape oldShape, Shape newShape); | |
108 | |
109 private void resizeStore(Shape oldShape, Shape newShape) { | |
110 resizeObjectStore(oldShape, newShape); | |
111 if (((ShapeImpl) newShape).hasPrimitiveArray) { | |
112 resizePrimitiveStore(oldShape, newShape); | |
113 } | |
114 } | |
115 | |
116 protected abstract void resizePrimitiveStore(Shape oldShape, Shape newShape); | |
117 | |
118 protected abstract void resizeObjectStore(Shape oldShape, Shape newShape); | |
119 | |
120 /** | |
121 * Check whether fast transition is valid. | |
122 * | |
123 * @see #setShapeAndGrow | |
124 */ | |
125 private boolean checkSetShape(Shape oldShape, Shape newShape) { | |
126 Shape currentShape = getShape(); | |
127 assert oldShape != newShape : "Wrong old shape assumption?"; | |
128 assert newShape != currentShape : "Redundant shape change? shape=" + currentShape; | |
129 // assert oldShape == currentShape || (oldShape.getLastProperty() == ((EnterpriseLayout) | |
130 // oldShape.getLayout()).getPrimitiveArrayProperty() && oldShape.getParent() == | |
131 // currentShape) : "Out-of-order shape change?" + "\nparentShape=" + currentShape + | |
132 // "\noldShape=" + oldShape + "\nnewShape=" + newShape; | |
133 return true; | |
134 } | |
135 | |
136 /** | |
137 * Check whether the extension arrays are in accordance with the description in the shape. | |
138 */ | |
139 protected abstract boolean checkExtensionArrayInvariants(Shape newShape); | |
140 | |
141 @Override | |
142 protected final DynamicObject clone() { | |
143 try { | |
144 return (DynamicObject) super.clone(); | |
145 } catch (CloneNotSupportedException e) { | |
146 throw new IllegalStateException(); | |
147 } | |
148 } | |
149 | |
150 protected abstract DynamicObject cloneWithShape(Shape currentShape); | |
151 | |
152 void reshapeAfterDelete(final Shape newShape, final Shape deletedParentShape) { | |
153 DynamicObject original = this.cloneWithShape(getShape()); | |
154 setShapeAndResize(newShape); | |
155 copyProperties(original, deletedParentShape); | |
156 } | |
157 | |
158 public final void copyProperties(DynamicObject fromObject, Shape ancestor) { | |
159 Shape fromShape = fromObject.getShape(); | |
160 Shape toShape = getShape(); | |
161 assert toShape.isRelated(ancestor); | |
162 assert toShape.isValid(); | |
163 assert ancestor.isValid(); | |
164 for (; toShape != ancestor; toShape = toShape.getParent()) { | |
165 Property toProperty = toShape.getLastProperty(); | |
166 // assumption: hidden properties won't change and don't need copying | |
167 if (!toProperty.isHidden()) { | |
168 assert fromShape.hasProperty(toProperty.getKey()); | |
169 Property fromProperty = fromShape.getProperty(toProperty.getKey()); | |
170 // copy only if property has a location and it's not the same as the source location | |
171 if (toProperty.getLocation() != null && !(toProperty.getLocation() instanceof ValueLocation) && !toProperty.getLocation().equals(fromProperty.getLocation())) { | |
172 toProperty.setInternal(this, fromProperty.get(fromObject, false)); | |
173 assert toShape.isValid(); | |
174 } | |
175 | |
176 if (fromShape.getLastProperty() == fromProperty) { | |
177 // no property is looked up twice, so we can skip over to parent | |
178 fromShape = fromShape.getParent(); | |
179 } | |
180 } | |
181 } | |
182 } | |
183 | |
184 @TruffleBoundary | |
185 public boolean changeFlags(Object id, int newFlags) { | |
186 Shape oldShape = getShape(); | |
187 Property existing = oldShape.getProperty(id); | |
188 if (existing != null) { | |
189 if (existing.getFlags() != newFlags) { | |
190 Property newProperty = existing.copyWithFlags(newFlags); | |
191 Shape newShape = oldShape.replaceProperty(existing, newProperty); | |
192 this.setShape(newShape); | |
193 } | |
194 return true; | |
195 } else { | |
196 return false; | |
197 } | |
198 } | |
199 | |
200 @TruffleBoundary | |
201 public boolean changeFlags(Object id, FlagsFunction updateFunction) { | |
202 Shape oldShape = getShape(); | |
203 Property existing = oldShape.getProperty(id); | |
204 if (existing != null) { | |
205 Integer newFlags = updateFunction.apply(existing.getFlags()); | |
206 if (newFlags != null && existing.getFlags() != newFlags.intValue()) { | |
207 Property newProperty = existing.copyWithFlags(newFlags); | |
208 Shape newShape = oldShape.replaceProperty(existing, newProperty); | |
209 this.setShape(newShape); | |
210 } | |
211 return true; | |
212 } else { | |
213 return false; | |
214 } | |
215 } | |
216 | |
217 public String debugDump(int level) { | |
218 return debugDump(0, level); | |
219 } | |
220 | |
221 public String debugDump(int level, int levelStop) { | |
222 List<Property> properties = this.getShape().getPropertyListInternal(true); | |
223 StringBuilder sb = new StringBuilder(properties.size() * 10); | |
224 sb.append("{\n"); | |
225 for (Property property : properties) { | |
226 indent(sb, level + 1); | |
227 | |
228 sb.append(property.getKey()); | |
229 sb.append('[').append(property.getLocation()).append(']'); | |
230 Object value = property.get(this, false); | |
231 if (value instanceof DynamicObjectImpl) { | |
232 if (level < levelStop) { | |
233 value = ((DynamicObjectImpl) value).debugDump(level + 1, levelStop); | |
234 } else { | |
235 value = value.toString(); | |
236 } | |
237 } | |
238 sb.append(": "); | |
239 sb.append(value); | |
240 if (property != properties.get(properties.size() - 1)) { | |
241 sb.append(","); | |
242 } | |
243 sb.append("\n"); | |
244 } | |
245 indent(sb, level); | |
246 sb.append("}"); | |
247 return sb.toString(); | |
248 } | |
249 | |
250 private static StringBuilder indent(StringBuilder sb, int level) { | |
251 for (int i = 0; i < level; i++) { | |
252 sb.append(' '); | |
253 } | |
254 return sb; | |
255 } | |
256 | |
257 @Override | |
258 public String toString() { | |
259 return getShape().getObjectType().toString(this); | |
260 } | |
261 | |
262 @Override | |
263 public boolean equals(Object obj) { | |
264 return getShape().getObjectType().equals(this, obj); | |
265 } | |
266 | |
267 @Override | |
268 public int hashCode() { | |
269 return getShape().getObjectType().hashCode(this); | |
270 } | |
271 | |
272 @TruffleBoundary | |
273 public Object get(Object id, Object defaultValue) { | |
274 Property existing = getShape().getProperty(id); | |
275 if (existing != null) { | |
276 return existing.get(this, false); | |
277 } else { | |
278 return defaultValue; | |
279 } | |
280 } | |
281 | |
282 @TruffleBoundary | |
283 public boolean set(Object id, Object value) { | |
284 Property existing = getShape().getProperty(id); | |
285 if (existing != null) { | |
286 existing.setGeneric(this, value, null); | |
287 return true; | |
288 } else { | |
289 return false; | |
290 } | |
291 } | |
292 | |
293 @TruffleBoundary | |
294 public void define(Object id, Object value, int flags) { | |
295 ShapeImpl oldShape = getShape(); | |
296 Property existing = oldShape.getProperty(id); | |
297 if (existing == null) { | |
298 updateShape(); | |
299 oldShape = getShape(); | |
300 Shape newShape = oldShape.addProperty(Property.create(id, oldShape.allocator().locationForValue(value, true, true), flags)); | |
301 updateShape(); | |
302 newShape.getLastProperty().setGeneric(this, value, oldShape, newShape); | |
303 } else { | |
304 defineExisting(id, value, flags, existing, oldShape); | |
305 } | |
306 } | |
307 | |
308 private void defineExisting(Object id, Object value, int flags, Property existing, ShapeImpl oldShape) { | |
309 if (existing.getFlags() == flags) { | |
310 existing.setGeneric(this, value, null); | |
311 } else { | |
312 Property newProperty = Property.create(id, oldShape.getLayout().existingLocationForValue(value, existing.getLocation(), oldShape), flags); | |
313 Shape newShape = oldShape.replaceProperty(existing, newProperty); | |
314 this.setShapeAndResize(newShape); | |
315 newProperty.setInternal(this, value); | |
316 } | |
317 } | |
318 | |
319 @TruffleBoundary | |
320 public void define(Object id, Object value, int flags, LocationFactory locationFactory) { | |
321 ShapeImpl oldShape = getShape(); | |
322 Property existing = oldShape.getProperty(id); | |
323 if (existing == null) { | |
324 updateShape(); | |
325 oldShape = getShape(); | |
326 Shape newShape = oldShape.addProperty(Property.create(id, locationFactory.createLocation(oldShape, value), flags)); | |
327 updateShape(); | |
328 newShape.getLastProperty().setGeneric(this, value, oldShape, newShape); | |
329 } else { | |
330 defineExisting(id, value, flags, existing, oldShape); | |
331 } | |
332 } | |
333 | |
334 @TruffleBoundary | |
335 public boolean delete(Object id) { | |
336 ShapeImpl oldShape = getShape(); | |
337 Property existing = oldShape.getProperty(id); | |
338 if (existing != null) { | |
339 ShapeImpl newShape = oldShape.removeProperty(existing); | |
340 this.reshapeAfterDelete(newShape, ShapeImpl.findCommonAncestor(oldShape, newShape)); | |
341 // TODO ancestor should be the parent of found property's shape | |
342 return true; | |
343 } else { | |
344 return false; | |
345 } | |
346 } | |
347 | |
348 public int size() { | |
349 return getShape().getPropertyCount(); | |
350 } | |
351 | |
352 public boolean isEmpty() { | |
353 return size() == 0; | |
354 } | |
355 | |
356 public final boolean updateShape() { | |
357 return getShape().getLayout().getStrategy().updateShape(this); | |
358 } | |
359 | |
360 private static void trackObject(DynamicObject obj) { | |
361 ShapeProfiler.getInstance().track(obj); | |
362 } | |
363 } |