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 }