comparison graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/runtime/ObjectLayoutTests.java @ 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents
children
comparison
equal deleted inserted replaced
13513:64a23ce736a0 13514:0fbee3eb71f0
1 /*
2 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
3 * code is released under a tri EPL/GPL/LGPL license. You can use it,
4 * redistribute it and/or modify it under the terms of the:
5 *
6 * Eclipse Public License version 1.0
7 * GNU General Public License version 2
8 * GNU Lesser General Public License version 2.1
9 */
10 package com.oracle.truffle.ruby.test.runtime;
11
12 import org.junit.*;
13
14 import com.oracle.truffle.ruby.runtime.*;
15 import com.oracle.truffle.ruby.runtime.core.*;
16 import com.oracle.truffle.ruby.runtime.objects.*;
17
18 import static org.junit.Assert.*;
19
20 /**
21 * Test the object layout classes.
22 */
23 public class ObjectLayoutTests {
24
25 @Test
26 public void testNewInstanceVariable() {
27 final RubyContext context = new RubyContext(null);
28
29 // Create a class and an instance
30
31 final RubyClass classA = new RubyClass(context, null, null, null, "A");
32 final ObjectLayout layoutClassA = classA.getObjectLayoutForInstances();
33
34 final RubyBasicObject objectA = new RubyBasicObject(classA);
35 final ObjectLayout layoutObjectA = objectA.getObjectLayout();
36
37 // Add an instance variable to the instance
38
39 objectA.setInstanceVariable("foo", 14);
40
41 // That should have changed the layout of the class
42
43 assertNotSame(layoutClassA, classA.getObjectLayoutForInstances());
44
45 // If we notify the object, it should also change the layout of that
46
47 objectA.updateLayout();
48 assertNotSame(layoutObjectA, objectA.getObjectLayout());
49
50 // We should be able to find that instance variable as a storage location in the class
51
52 assertNotNull(classA.getObjectLayoutForInstances().findStorageLocation("foo"));
53
54 // We should be able to read that value back out
55
56 assertEquals(14, objectA.getInstanceVariable("foo"));
57 }
58
59 @Test
60 public void testOverflowPrimitives() {
61 final RubyContext context = new RubyContext(null);
62
63 // Create a class and an instance
64
65 final RubyClass classA = new RubyClass(context, null, null, null, "A");
66 final RubyBasicObject objectA = new RubyBasicObject(classA);
67
68 // Add many more Fixnums that we have space for primitives
69
70 final int count = 100;
71
72 for (int n = 0; n < count; n++) {
73 objectA.setInstanceVariable("foo" + n, n);
74 }
75
76 // We should be able to read them back out
77
78 for (int n = 0; n < count; n++) {
79 assertEquals(n, objectA.getInstanceVariable("foo" + n));
80 }
81 }
82
83 @Test
84 public void testGeneralisation() {
85 final RubyContext context = new RubyContext(null);
86
87 // Create a class and two instances
88
89 final RubyClass classA = new RubyClass(context, null, null, null, "A");
90 final RubyBasicObject object1 = new RubyBasicObject(classA);
91 final RubyBasicObject object2 = new RubyBasicObject(classA);
92
93 // Set an instance variable to be a Fixnum in object 1
94
95 object1.setInstanceVariable("foo", 14);
96
97 // We should be able to read that instance variable back, and it should still be a Fixnum
98
99 assertEquals(14, object1.getInstanceVariable("foo"));
100 assertSame(Integer.class, object1.getInstanceVariable("foo").getClass());
101
102 // The underlying instance store should be Fixnum
103
104 assertSame(FixnumStorageLocation.class, object1.getObjectLayout().findStorageLocation("foo").getClass());
105
106 /*
107 * The same instance variable in object 2 should be Nil. Note that this requires that we
108 * realise that even though the instance variable is known about in the layout of object 2,
109 * and we are using a primitive int to hold it, that it hasn't been set and is actually Nil.
110 * We don't want it to appear as 0.
111 */
112
113 assertSame(NilPlaceholder.INSTANCE, object2.getInstanceVariable("foo"));
114
115 /*
116 * We should be able to set the same instance variable in object 2 to also be a Fixnum
117 * without changing the layout.
118 */
119
120 final ObjectLayout objectLayout2 = object2.getObjectLayout();
121 object2.setInstanceVariable("foo", 2);
122 assertEquals(2, object2.getInstanceVariable("foo"));
123 assertSame(Integer.class, object2.getInstanceVariable("foo").getClass());
124 assertSame(objectLayout2, object2.getObjectLayout());
125
126 // Set the instance variable in object 2 to be a Float
127
128 object2.setInstanceVariable("foo", 2.25);
129
130 // We should be able to read that instance variable back, and it should still be a Fixnum
131
132 assertEquals(2.25, object2.getInstanceVariable("foo"));
133 assertSame(Double.class, object2.getInstanceVariable("foo").getClass());
134
135 // Object 1 should give still think the instance variable is a Fixnum
136
137 assertEquals(14, object1.getInstanceVariable("foo"));
138 assertSame(Integer.class, object1.getInstanceVariable("foo").getClass());
139
140 // The underlying instance store in both objects should now be Object
141
142 assertSame(ObjectStorageLocation.class, object1.getObjectLayout().findStorageLocation("foo").getClass());
143 assertSame(ObjectStorageLocation.class, object2.getObjectLayout().findStorageLocation("foo").getClass());
144
145 }
146
147 @Test
148 public void testSubclasses() {
149 final RubyContext context = new RubyContext(null);
150
151 // Create two classes, A, and a subclass, B, and an instance of each
152
153 final RubyClass classA = new RubyClass(context, null, null, null, "A");
154 final RubyClass classB = new RubyClass(context, null, null, classA, "B");
155
156 ObjectLayout layoutClassA = classA.getObjectLayoutForInstances();
157 ObjectLayout layoutClassB = classA.getObjectLayoutForInstances();
158
159 final RubyBasicObject objectA = new RubyBasicObject(classA);
160 final RubyBasicObject objectB = new RubyBasicObject(classB);
161
162 ObjectLayout layoutObjectA = objectA.getObjectLayout();
163 ObjectLayout layoutObjectB = objectB.getObjectLayout();
164
165 // Add an instance variable to the instance of A
166
167 objectA.setInstanceVariable("foo", 14);
168
169 // That should have changed the layout of both classes
170
171 assertNotSame(layoutClassA, classA.getObjectLayoutForInstances());
172 assertNotSame(layoutClassB, classB.getObjectLayoutForInstances());
173
174 layoutClassA = classA.getObjectLayoutForInstances();
175 layoutClassB = classA.getObjectLayoutForInstances();
176
177 // If we notify the objects, both of them should have changed layouts
178
179 objectA.updateLayout();
180 objectB.updateLayout();
181 assertNotSame(layoutObjectA, objectA.getObjectLayout());
182 assertNotSame(layoutObjectB, objectB.getObjectLayout());
183
184 layoutObjectA = objectA.getObjectLayout();
185 layoutObjectB = objectB.getObjectLayout();
186
187 // We should be able to find that instance variable as a storage location in both classes
188
189 assertNotNull(classA.getObjectLayoutForInstances().findStorageLocation("foo"));
190 assertNotNull(classB.getObjectLayoutForInstances().findStorageLocation("foo"));
191
192 // We should be able to read that value back out
193
194 assertEquals(14, objectA.getInstanceVariable("foo"));
195
196 // Add an instance variable to the instance of B
197
198 objectB.setInstanceVariable("bar", 2);
199
200 // This should not have changed the layout of A or the instance of A
201
202 assertSame(layoutClassA, classA.getObjectLayoutForInstances());
203 assertSame(layoutObjectA, objectA.getObjectLayout());
204
205 // But the layout of B and the instance of B should have changed
206
207 assertNotSame(layoutClassB, classB.getObjectLayoutForInstances());
208
209 objectB.updateLayout();
210 assertNotSame(layoutObjectB, objectB.getObjectLayout());
211
212 // We should be able to find the new instance variable in the instance of B but not A
213
214 assertNull(classA.getObjectLayoutForInstances().findStorageLocation("bar"));
215 assertNotNull(classB.getObjectLayoutForInstances().findStorageLocation("bar"));
216
217 // We should be able to read that value back out
218
219 assertEquals(2, objectB.getInstanceVariable("bar"));
220 }
221
222 @Test
223 public void testPerObjectInstanceVariables() {
224 final RubyContext context = new RubyContext(null);
225
226 // Create a class and an instance
227
228 final RubyClass classA = new RubyClass(context, context.getCoreLibrary().getClassClass(), null, null, "A");
229 final RubyBasicObject objectA = new RubyBasicObject(classA);
230
231 ObjectLayout layoutClassA = classA.getObjectLayoutForInstances();
232 ObjectLayout layoutObjectA = objectA.getObjectLayout();
233
234 // Add an instance variable to the instance of A
235
236 objectA.setInstanceVariable("foo", 2);
237
238 // That should have changed the layout of the class and the object
239
240 assertNotSame(layoutClassA, classA.getObjectLayoutForInstances());
241 assertNotSame(layoutObjectA, objectA.getObjectLayout());
242 layoutClassA = classA.getObjectLayoutForInstances();
243 layoutObjectA = classA.getObjectLayout();
244
245 // We should be able to read the value back out
246
247 assertEquals(2, objectA.getInstanceVariable("foo"));
248
249 /*
250 * Switch object A to having a private object layout, as would be done by calls such as
251 * instance_variable_set.
252 */
253
254 objectA.switchToPrivateLayout();
255
256 // Set an instance variable on object A
257
258 objectA.setInstanceVariable("bar", 14);
259
260 // The layout of object A, however, should have changed
261
262 // CS: it hasn't changed because it's still null
263 // assertNotSame(layoutObjectA, objectA.getObjectLayout());
264
265 // We should be able to read the value back out
266
267 assertEquals(14, objectA.getInstanceVariable("bar"));
268
269 /*
270 * We should also be able to read the first variable back out, even though we've switched to
271 * private layout since then.
272 */
273
274 assertEquals(2, objectA.getInstanceVariable("foo"));
275 }
276
277 }