KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > object > bytecode > hook > impl > ArrayManager


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tc.object.bytecode.hook.impl;
6
7 import com.tc.object.TCObject;
8 import com.tc.object.util.IdentityWeakHashMap;
9 import com.tc.util.Assert;
10
11 import java.util.HashMap JavaDoc;
12 import java.util.Map JavaDoc;
13
14 /**
15  * Global array manager. The basic purpose of this class to maintain the relationship to DSO managed arrays to their
16  * respective TCObject
17  */

18 public class ArrayManager {
19
20   // some day we might want to make this stuff externally configurable
21
private final static int CACHE_DEPTH = 2;
22   private final static int NUM_MAPS = 32;
23   private final static int INITIAL_CAPACITY = 25000;
24   private final static float LOAD_FACTOR = 0.75F;
25
26   private static final Map[] maps = new Map[NUM_MAPS];
27   private static final Map primClasses = new HashMap();
28   private static final Object JavaDoc[] keys = new Object JavaDoc[NUM_MAPS * CACHE_DEPTH];
29   private static final TCObject[] values = new TCObject[NUM_MAPS * CACHE_DEPTH];
30
31   static {
32     for (int i = 0; i < maps.length; i++) {
33       maps[i] = new IdentityWeakHashMap(INITIAL_CAPACITY, LOAD_FACTOR);
34     }
35   }
36
37   private ArrayManager() {
38     // not to be instantiated
39
}
40
41   public static void register(Object JavaDoc array, TCObject tco) {
42     if ((array == null) || (tco == null)) { throw new NullPointerException JavaDoc(); }
43
44     final int index = array.hashCode() % NUM_MAPS;
45     final Map map = maps[index];
46     final int start = index * CACHE_DEPTH;
47     final int end = start + CACHE_DEPTH;
48     final Object JavaDoc prev;
49
50     synchronized (map) {
51       for (int i = start; i < end; i++) {
52         if (keys[i] == array) {
53           values[i] = tco;
54           break;
55         }
56       }
57
58       prev = map.put(array, tco);
59     }
60     if (prev != null) { throw new AssertionError JavaDoc("replaced mapping for " + array); }
61   }
62
63   public static TCObject getObject(Object JavaDoc array) {
64     final int hash = array.hashCode();
65     final int index = hash % NUM_MAPS;
66     final Map map = maps[index];
67     final int start = index * CACHE_DEPTH;
68     final int end = start + CACHE_DEPTH;
69
70     synchronized (map) {
71       for (int i = start; i < end; i++) {
72         if (keys[i] == array) { return values[i]; }
73       }
74
75       int evict = start + (hash % CACHE_DEPTH);
76       TCObject rv = (TCObject) map.get(array);
77       keys[evict] = array;
78       values[evict] = rv;
79       return rv;
80     }
81   }
82
83   public static TCObject getCloneObject(Object JavaDoc array) {
84     return getObject(array);
85   }
86
87   // For java.lang.reflect.Array.get()
88
public static Object JavaDoc get(Object JavaDoc array, int index) {
89     if (array == null) throw new NullPointerException JavaDoc();
90
91     if (array instanceof boolean[]) return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
92     if (array instanceof byte[]) return new Byte JavaDoc(((byte[]) array)[index]);
93     if (array instanceof char[]) return new Character JavaDoc(((char[]) array)[index]);
94     if (array instanceof short[]) return new Short JavaDoc(((short[]) array)[index]);
95     if (array instanceof int[]) return new Integer JavaDoc(((int[]) array)[index]);
96     if (array instanceof long[]) return new Long JavaDoc(((long[]) array)[index]);
97     if (array instanceof float[]) return new Float JavaDoc(((float[]) array)[index]);
98     if (array instanceof double[]) return new Double JavaDoc(((double[]) array)[index]);
99
100     if (array instanceof Object JavaDoc[]) {
101       TCObject tco = getObject(array);
102       if (tco != null) {
103         synchronized (tco.getResolveLock()) {
104           tco.resolveArrayReference(index);
105           return ((Object JavaDoc[]) array)[index];
106         }
107       } else {
108         return ((Object JavaDoc[]) array)[index];
109       }
110     }
111
112     throw new IllegalArgumentException JavaDoc("Not an array type: " + array.getClass().getName());
113
114   }
115
116   public static void objectArrayChanged(Object JavaDoc[] array, int index, Object JavaDoc value) {
117     Object JavaDoc existingObj = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
118
if (false && existingObj != existingObj) Assert.fail(); // silence compiler warning
119

120     TCObject tco = getObject(array);
121     if (tco != null) {
122       tco.objectFieldChanged(array.getClass().getName(), null, value, index);
123     }
124     array[index] = value;
125   }
126
127   public static void shortArrayChanged(short[] array, int index, short value) {
128     short existingVal = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
129
if (false && existingVal != existingVal) Assert.fail(); // silence compiler warning
130

131     TCObject tco = getObject(array);
132     if (tco != null) {
133       tco.shortFieldChanged(null, null, value, index);
134     }
135     array[index] = value;
136   }
137
138   public static void longArrayChanged(long[] array, int index, long value) {
139     long existingVal = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
140
if (false && existingVal != existingVal) Assert.fail(); // silence compiler warning
141

142     TCObject tco = getObject(array);
143     if (tco != null) {
144       tco.longFieldChanged(null, null, value, index);
145     }
146     array[index] = value;
147   }
148
149   public static void intArrayChanged(int[] array, int index, int value) {
150     int existingVal = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
151
if (false && existingVal != existingVal) Assert.fail(); // silence compiler warning
152

153     TCObject tco = getObject(array);
154     if (tco != null) {
155       tco.intFieldChanged(null, null, value, index);
156     }
157     array[index] = value;
158   }
159
160   public static void floatArrayChanged(float[] array, int index, float value) {
161     float existingVal = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
162
if (false && existingVal != existingVal) Assert.fail(); // silence compiler warning
163

164     TCObject tco = getObject(array);
165     if (tco != null) {
166       tco.floatFieldChanged(null, null, value, index);
167     }
168     array[index] = value;
169   }
170
171   public static void doubleArrayChanged(double[] array, int index, double value) {
172     double existingVal = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
173
if (false && existingVal != existingVal) Assert.fail(); // silence compiler warning
174

175     TCObject tco = getObject(array);
176     if (tco != null) {
177       tco.doubleFieldChanged(null, null, value, index);
178     }
179     array[index] = value;
180   }
181
182   public static void charArrayChanged(char[] array, int index, char value) {
183     char existingVal = array[index]; // do array operation first (fail fast, NPE and array index out of bounds)
184
if (false && existingVal != existingVal) Assert.fail(); // silence compiler warning
185

186     TCObject tco = getObject(array);
187     if (tco != null) {
188       tco.charFieldChanged(null, null, value, index);
189     }
190     array[index] = value;
191   }
192
193   public static void byteOrBooleanArrayChanged(Object JavaDoc array, int index, byte value) {
194     if (array == null) { throw new NullPointerException JavaDoc(); }
195
196     // Hack to deal with the fact that booleans and bytes are treated the same in bytecode
197
if (array.getClass().getComponentType().equals(Boolean.TYPE)) {
198       boolean[] booleanArray = (boolean[]) array;
199       boolean existingBooleanVal = booleanArray[index]; // do array operation first (fail fast, NPE and array index out
200
// of bounds)
201
if (false && existingBooleanVal != existingBooleanVal) Assert.fail(); // silence compiler warning
202
boolean booleanValue = value == 1;
203
204       TCObject tco = getObject(array);
205       if (tco != null) {
206         tco.booleanFieldChanged(null, null, booleanValue, index);
207       }
208       booleanArray[index] = booleanValue;
209     } else {
210       byte[] byteArray = (byte[]) array;
211       byte existingByteVal = byteArray[index]; // do array operation first (fail fast, NPE and array index out of
212
// bounds)
213
if (false && existingByteVal != existingByteVal) Assert.fail(); // silence compiler warning
214

215       TCObject tco = getObject(array);
216       if (tco != null) {
217         tco.byteFieldChanged(null, null, value, index);
218       }
219       byteArray[index] = value;
220     }
221   }
222
223   public static void arraycopy(final Object JavaDoc src, final int srcPos, final Object JavaDoc dest, final int destPos,
224                                final int length) {
225     // preserve behavior of System.arraycopy()
226
if ((src == null) || (dest == null)) { throw new NullPointerException JavaDoc(); }
227
228     TCObject tcDest = getObject(dest);
229     Class JavaDoc destType = dest.getClass().getComponentType();
230     if (destType == null) { throw new ArrayStoreException JavaDoc(); }
231
232     boolean isDestPrimitive = destType.isPrimitive();
233
234     // copying into a primitive non-managed array doesn't need any special treatment (even if the source array is
235
// managed. If the source array is managed and non-primitive, you'll get an ArrayStoreException as expected)
236
if (isDestPrimitive && tcDest == null) {
237       System.arraycopy(src, srcPos, dest, destPos, length);
238       return;
239     }
240
241     // avoid this lookup if we returned above
242
TCObject tcSrc = getObject(src);
243
244     if ((tcDest != null) || (tcSrc != null)) {
245
246       Class JavaDoc srcType = src.getClass().getComponentType();
247       if (srcType == null) { throw new ArrayStoreException JavaDoc(); }
248       boolean isSrcPrimitive = srcType.isPrimitive();
249
250       if (isDestPrimitive) {
251         int destCode = getCodeForType(destType);
252
253         // Check if both arrays have the same primitive types. If not, throw an ArrayStoreException.
254
if (isSrcPrimitive) {
255           int srcCode = getCodeForType(srcType);
256           if (srcCode != destCode) { throw new ArrayStoreException JavaDoc(); }
257         } else {
258           throw new ArrayStoreException JavaDoc();
259         }
260
261         switch (destCode) {
262           case BOOLEAN:
263             booleanArrayCopy((boolean[]) src, srcPos, (boolean[]) dest, destPos, length, tcDest);
264             break;
265           case BYTE:
266             byteArrayCopy((byte[]) src, srcPos, (byte[]) dest, destPos, length, tcDest);
267             break;
268           case CHAR:
269             charArrayCopy((char[]) src, srcPos, (char[]) dest, destPos, length, tcDest);
270             break;
271           case DOUBLE:
272             doubleArrayCopy((double[]) src, srcPos, (double[]) dest, destPos, length, tcDest);
273             break;
274           case FLOAT:
275             floatArrayCopy((float[]) src, srcPos, (float[]) dest, destPos, length, tcDest);
276             break;
277           case INT:
278             intArrayCopy((int[]) src, srcPos, (int[]) dest, destPos, length, tcDest);
279             break;
280           case LONG:
281             longArrayCopy((long[]) src, srcPos, (long[]) dest, destPos, length, tcDest);
282             break;
283           case SHORT:
284             shortArrayCopy((short[]) src, srcPos, (short[]) dest, destPos, length, tcDest);
285             break;
286           default:
287             throw Assert.failure("unexpected type code: " + destCode);
288         }
289       } else {
290         if (isSrcPrimitive) { throw new ArrayStoreException JavaDoc(); }
291
292         Object JavaDoc[] destArray = (Object JavaDoc[]) dest;
293         Object JavaDoc[] srcArray = (Object JavaDoc[]) src;
294
295         if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > srcArray.length)
296             || (destPos + length > destArray.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
297
298         Object JavaDoc[] l2subset = new Object JavaDoc[length];
299
300         if (tcSrc != null) {
301           synchronized (tcSrc.getResolveLock()) {
302             for (int i = 0; i < length; i++) {
303               tcSrc.resolveArrayReference(srcPos + i);
304               // this read of the source array MUST be performed under the resolve lock
305
l2subset[i] = srcArray[srcPos + i];
306             }
307           }
308         } else {
309           System.arraycopy(src, srcPos, l2subset, 0, length);
310         }
311
312         int actualLength = length;
313         // validate the assignments if necessary, potentially discovering that only a partial copy is legel
314
if (!destType.isAssignableFrom(srcType)) {
315           for (int i = 0, n = l2subset.length; i < n; i++) {
316             Object JavaDoc srcVal = l2subset[i];
317             if (srcVal != null) {
318               if (!destType.isAssignableFrom(srcVal.getClass())) {
319                 actualLength = i;
320                 break;
321               }
322             }
323           }
324         }
325
326         // make a second copy because the l2subset can be mutated (refs --> ObjectID)
327
Object JavaDoc[] localSubset = new Object JavaDoc[actualLength];
328         System.arraycopy(l2subset, 0, localSubset, 0, actualLength);
329
330         if (tcDest != null && actualLength > 0) {
331           tcDest.objectArrayChanged(destPos, l2subset, actualLength);
332         }
333
334         // only mutate the local array once DSO has a chance to throw portability and TXN exceptions (above)
335
System.arraycopy(localSubset, 0, dest, destPos, actualLength);
336
337         if (actualLength != length) { throw new ArrayStoreException JavaDoc(); }
338
339       }
340     } else {
341       // no managed arrays in the mix, just do a regular arraycopy
342
System.arraycopy(src, srcPos, dest, destPos, length);
343     }
344   }
345
346   private static int getCodeForType(Class JavaDoc type) {
347     Integer JavaDoc code = (Integer JavaDoc) primClasses.get(type);
348     if (code == null) { throw new RuntimeException JavaDoc("No code for type " + type); }
349     return code.intValue();
350   }
351
352   private static void booleanArrayCopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length,
353                                        TCObject tcDest) {
354     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
355         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
356
357     boolean[] l2subset = new boolean[length];
358     System.arraycopy(src, srcPos, l2subset, 0, length);
359     tcDest.primitiveArrayChanged(destPos, l2subset, length);
360
361     // don't mutate local objects until DSO accepts/records the change (above)
362
System.arraycopy(l2subset, 0, dest, destPos, length);
363   }
364
365   private static void byteArrayCopy(byte[] src, int srcPos, byte[] dest, int destPos, int length, TCObject tcDest) {
366     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
367         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
368
369     byte[] l2subset = new byte[length];
370     System.arraycopy(src, srcPos, l2subset, 0, length);
371     tcDest.primitiveArrayChanged(destPos, l2subset, length);
372
373     // don't mutate local objects until DSO accepts/records the change (above)
374
System.arraycopy(l2subset, 0, dest, destPos, length);
375   }
376
377   public static void charArrayCopy(char[] src, int srcPos, char[] dest, int destPos, int length, TCObject tcDest) {
378     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
379         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
380
381     char[] l2subset = new char[length];
382     System.arraycopy(src, srcPos, l2subset, 0, length);
383     tcDest.primitiveArrayChanged(destPos, l2subset, length);
384
385     // don't mutate local objects until DSO accepts/records the change (above)
386
System.arraycopy(l2subset, 0, dest, destPos, length);
387   }
388
389   private static void doubleArrayCopy(double[] src, int srcPos, double[] dest, int destPos, int length, TCObject tcDest) {
390     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
391         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
392
393     double[] l2subset = new double[length];
394     System.arraycopy(src, srcPos, l2subset, 0, length);
395     tcDest.primitiveArrayChanged(destPos, l2subset, length);
396
397     // don't mutate local objects until DSO accepts/records the change (above)
398
System.arraycopy(l2subset, 0, dest, destPos, length);
399   }
400
401   private static void floatArrayCopy(float[] src, int srcPos, float[] dest, int destPos, int length, TCObject tcDest) {
402     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
403         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
404
405     float[] l2subset = new float[length];
406     System.arraycopy(src, srcPos, l2subset, 0, length);
407     tcDest.primitiveArrayChanged(destPos, l2subset, length);
408
409     // don't mutate local objects until DSO accepts/records the change (above)
410
System.arraycopy(l2subset, 0, dest, destPos, length);
411   }
412
413   private static void intArrayCopy(int[] src, int srcPos, int[] dest, int destPos, int length, TCObject tcDest) {
414     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
415         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
416
417     int[] l2subset = new int[length];
418     System.arraycopy(src, srcPos, l2subset, 0, length);
419     tcDest.primitiveArrayChanged(destPos, l2subset, length);
420
421     // don't mutate local objects until DSO accepts/records the change (above)
422
System.arraycopy(l2subset, 0, dest, destPos, length);
423   }
424
425   private static void longArrayCopy(long[] src, int srcPos, long[] dest, int destPos, int length, TCObject tcDest) {
426     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
427         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
428
429     long[] l2subset = new long[length];
430     System.arraycopy(src, srcPos, l2subset, 0, length);
431     tcDest.primitiveArrayChanged(destPos, l2subset, length);
432
433     // don't mutate local objects until DSO accepts/records the change (above)
434
System.arraycopy(l2subset, 0, dest, destPos, length);
435   }
436
437   private static void shortArrayCopy(short[] src, int srcPos, short[] dest, int destPos, int length, TCObject tcDest) {
438     if ((srcPos < 0) || (destPos < 0) || (length < 0) || (srcPos + length > src.length)
439         || (destPos + length > dest.length)) throw new ArrayIndexOutOfBoundsException JavaDoc();
440
441     short[] l2subset = new short[length];
442     System.arraycopy(src, srcPos, l2subset, 0, length);
443     tcDest.primitiveArrayChanged(destPos, l2subset, length);
444
445     // don't mutate local objects until DSO accepts/records the change (above)
446
System.arraycopy(l2subset, 0, dest, destPos, length);
447   }
448
449   private static final int BOOLEAN = 1;
450   private static final int BYTE = 2;
451   private static final int CHAR = 3;
452   private static final int DOUBLE = 4;
453   private static final int FLOAT = 5;
454   private static final int INT = 6;
455   private static final int LONG = 7;
456   private static final int SHORT = 8;
457
458   static {
459     primClasses.put(Boolean.TYPE, new Integer JavaDoc(BOOLEAN));
460     primClasses.put(Byte.TYPE, new Integer JavaDoc(BYTE));
461     primClasses.put(Character.TYPE, new Integer JavaDoc(CHAR));
462     primClasses.put(Double.TYPE, new Integer JavaDoc(DOUBLE));
463     primClasses.put(Float.TYPE, new Integer JavaDoc(FLOAT));
464     primClasses.put(Integer.TYPE, new Integer JavaDoc(INT));
465     primClasses.put(Long.TYPE, new Integer JavaDoc(LONG));
466     primClasses.put(Short.TYPE, new Integer JavaDoc(SHORT));
467   }
468
469 }
470
Popular Tags