001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.misc.accessors;
019:
020: import java.util.HashMap;
021:
022: import org.apache.harmony.misc.internal.nls.Messages;
023:
024: /**
025: * This class is a performance optimization aid which provides the low-level
026: * access to arrays. It contains the following groups of methods:
027: * <ul>
028: * <li><b>lockArray/lockArrayLong methods </b>- used to lock the memory
029: * location for the primitive type arrays for either short or long amounts of
030: * time such that their contents can be directly accessed in the memory.
031: * Typically, this is used to pass java arrays as arguments to native functions.
032: * One array can not be locked for the short and long period of time
033: * simultaneously.
034: *
035: * <li><b>set/getElement methods </b>- used to read and write individual array
036: * elements bypassing the bounds checks.
037: * <li><b>getArrayBaseOffset/ElementSize methods </b>- used to obtain
038: * information about arrays layout in the memory.
039: * </ul>
040: * The typical implementations of the {@link #lockArrayShort(Object)}and
041: * {@link #lockArrayLong(Object)}methods would instruct a virtual machine that
042: * the given array should stay unmovable for a certain period of time (i.e.
043: * until it is released by {@link LockedArray#release()}call). On virtual
044: * machines which do not support the unmovable arrays for some reason,
045: * functionality of the <code>lockArray/release</code> pair still can be
046: * emulated by copying the array content into the native heap and back. However,
047: * whatever implementation exists, the {@link LockedArray#getAddress()}method
048: * must return the memory location which is applicable for direct memory access
049: * operations, such as the ones provided by {@link MemoryAccessor}class.
050: * <p>
051: * A typical usage example for the locked arrays would look like that:
052: *
053: * <pre>
054: * ArrayAccessor aa = AccessorFactory.getArrayAccessor();
055: * byte[] bytearr = (byte[])aa.createArray(Byte.TYPE, 1024);
056: * ...fill the bytearr ...
057: * LockedArray la = aa.lockArrayShort(bytearr);
058: * int pixmap = x11.XCreateBitmapFromData(display, wnd, la.getAddress(), width,
059: * height);
060: * la.release();
061: * </pre>
062: */
063: public class ArrayAccessor {
064:
065: private static ArrayAccessor instance;
066:
067: static ArrayAccessor getInstance() {
068: if (instance == null) {
069: System.loadLibrary("accessors"); //$NON-NLS-1$
070: instance = new ArrayAccessor();
071: }
072: return instance;
073: }
074:
075: private ArrayAccessor() {
076: }
077:
078: /**
079: * Allocates a primitive type array that will be locked. The purpose of this
080: * method is to give a hint to object allocator that an array will be locked.
081: * This may help to increase the performance on certain virtual machine
082: * implementations.
083: *
084: * @param type
085: * the primitive type class. For example, use the
086: * {@link Integer#TYPE}to specify the array of integers.
087: * @param size
088: * number of elements in the array
089: * @return allocated array
090: */
091: public Object createArray(Class type, int size) {
092: if (type == Boolean.TYPE) {
093: return new boolean[size];
094: }
095: if (type == Byte.TYPE) {
096: return new byte[size];
097: }
098: if (type == Character.TYPE) {
099: return new char[size];
100: }
101: if (type == Short.TYPE) {
102: return new short[size];
103: }
104: if (type == Integer.TYPE) {
105: return new int[size];
106: }
107: if (type == Long.TYPE) {
108: return new long[size];
109: }
110: if (type == Float.TYPE) {
111: return new float[size];
112: }
113: if (type == Double.TYPE) {
114: return new double[size];
115: }
116: // misc.1=Non primitive type {0}
117: throw new IllegalArgumentException(Messages.getString(
118: "misc.1", type)); //$NON-NLS-1$
119: }
120:
121: /**
122: * Internal hash which keeps the record for all locked arrays.
123: */
124: static final HashMap objectLockMap = new HashMap();
125:
126: /**
127: * Allocates and immediately locks a primitive type array for supposedly a
128: * long period of time. The purpose of this method is to give a hint to
129: * object allocator that an array needs to be locked initially. This may
130: * help to increase the performance on certain virtual machine
131: * implementations.
132: *
133: * @param type
134: * the primitive type class. For example, use the
135: * {@link Integer#TYPE}to specify the array of integers.
136: * @param size
137: * number of elements in the array
138: * @return allocated array
139: * @see #lockArrayLong(Object)
140: * @see LockedArray#getAddress()
141: */
142: public LockedArray createLockedArrayLong(Class type, int size) {
143: Object array = createArray(type, size);
144: return lockArrayLong(array);
145: }
146:
147: /**
148: * Allocates and immediately locks a primitive type array for supposedly a
149: * short period of time. The purpose of this method is to give a hint to
150: * object allocator that an array needs to be locked initially. This may
151: * help to increase the performance on certain virtual machine
152: * implementations. Use the {@link LockedArray#release()}method to unlock
153: * the array after use.
154: *
155: * @param type
156: * the primitive type class. For example, use the
157: * {@link Integer#TYPE}to specify the array of integers.
158: * @param size
159: * number of elements in the array
160: * @return allocated array
161: * @see #lockArrayShort(Object)
162: * @see LockedArray#getAddress()
163: */
164: public LockedArray createLockedArrayShort(Class type, int size) {
165: Object array = createArray(type, size);
166: return lockArrayShort(array);
167: }
168:
169: /**
170: * Locks an existing array for supposedly a short period of time.
171: * Typically, this method would instruct a virtual machine that the given
172: * array should stay unmovable for a short period of time, such as one
173: * native library call. This method returns an instance of
174: * {@link LockedArray}object which can be queried for the array memory
175: * location. Use the {@link LockedArray#release()}method to unlock the
176: * array after use.
177: * <p>
178: * Default implementation of this method delegates to the
179: * <code>GetPrimitiveArrayCritical</code> JNI call.
180: * <p>
181: * Please note that synchronization and waiting (including native) must be
182: * avoided between {@link #lockArrayShort(Object)}and
183: * {@link LockedArray#release()}calls. If the array needs to be locked for
184: * a long period of time, it is recommended to use the
185: * {@link #lockArrayLong(Object)}method.
186: *
187: * @see #lockArrayLong(Object)
188: * @see LockedArray#release()
189: * @see LockedArray#getAddress()
190: * @throws RuntimeException
191: * if <code>array</code> is already locked.
192: * @throws NullPointerException
193: * if <code>array</code> is <code>null</code>.
194: * @param array
195: * an array of primitive type to lock
196: * @return locked array object
197: */
198: public LockedArray lockArrayShort(Object array) {
199: return lockArray(array, false);
200: }
201:
202: /**
203: * Locks an existing array for supposedly a long period of time and returns
204: * its location in memory. Typically, this method would instruct a virtual
205: * machine that the given array should stay unmovable for a long period of
206: * time. As a consequence, this method call may be expensive potentially may
207: * reduce GC efficiency. Use the {@link #lockArrayShort(Object)}method in
208: * case the array needs to be locked only for a short period of time. This
209: * method returns an instance of {@link LockedArray}object which can then
210: * be queried for the array memory location. To unlock the array, use the
211: * {@link LockedArray#release()}method.
212: * <p>
213: * Default implementation of this method delegates to the
214: * <code>GetXXXArrayElements</code> JNI call.
215: * <p>
216: *
217: * @see #lockArrayShort(Object)
218: * @see LockedArray#release()
219: * @see LockedArray#getAddress()
220: * @throws RuntimeException
221: * if <code>array</code> is already locked.
222: * @throws NullPointerException
223: * if <code>array</code> is <code>null</code>.
224: * @param array
225: * an array of primitive type to lock
226: * @return locked array object
227: */
228: public LockedArray lockArrayLong(Object array) {
229: return lockArray(array, true);
230: }
231:
232: private static LockedArray lockArray(Object array, boolean longLock) {
233: synchronized (objectLockMap) {
234: if (objectLockMap.get(array) != null) {
235: // misc.2=array is already locked/pinned
236: throw new RuntimeException(Messages.getString("misc.2")); //$NON-NLS-1$
237: }
238: long addr = 0;
239: if (longLock) {
240: if (array instanceof byte[]) {
241: addr = staticPinByteArray((byte[]) array);
242: } else if (array instanceof char[]) {
243: addr = staticPinCharArray((char[]) array);
244: } else if (array instanceof int[]) {
245: addr = staticPinIntArray((int[]) array);
246: } else if (array instanceof short[]) {
247: addr = staticPinShortArray((short[]) array);
248: } else if (array instanceof long[]) {
249: addr = staticPinLongArray((long[]) array);
250: } else if (array instanceof float[]) {
251: addr = staticPinFloatArray((float[]) array);
252: } else if (array instanceof double[]) {
253: addr = staticPinDoubleArray((double[]) array);
254: }
255: } else {
256: addr = staticLockArray(array);
257: }
258: if (addr == 0) {
259: // misc.3=lock failed
260: throw new RuntimeException(Messages.getString("misc.3")); //$NON-NLS-1$
261: }
262: LockedArray la = new LockedArray(array, addr, longLock);
263: objectLockMap.put(array, la);
264: return la;
265: }
266: }
267:
268: static void releaseArray(Object array, long addr, boolean longLock) {
269: synchronized (objectLockMap) {
270: if (longLock) {
271: if (array instanceof byte[]) {
272: staticUnpinByteArray((byte[]) array, addr);
273: } else if (array instanceof char[]) {
274: staticUnpinCharArray((char[]) array, addr);
275: } else if (array instanceof int[]) {
276: staticUnpinIntArray((int[]) array, addr);
277: } else if (array instanceof short[]) {
278: staticUnpinShortArray((short[]) array, addr);
279: } else if (array instanceof long[]) {
280: staticUnpinLongArray((long[]) array, addr);
281: } else if (array instanceof float[]) {
282: staticUnpinFloatArray((float[]) array, addr);
283: } else if (array instanceof double[]) {
284: staticUnpinDoubleArray((double[]) array, addr);
285: }
286: } else {
287: staticUnlockArray(array, addr);
288: }
289: objectLockMap.remove(array);
290: }
291: }
292:
293: static void releaseArrayNoCopy(Object array, long addr,
294: boolean longLock) {
295: synchronized (objectLockMap) {
296: if (longLock) {
297: if (array instanceof byte[]) {
298: staticUnpinByteArrayNoCopy((byte[]) array, addr);
299: } else if (array instanceof char[]) {
300: staticUnpinCharArrayNoCopy((char[]) array, addr);
301: } else if (array instanceof int[]) {
302: staticUnpinIntArrayNoCopy((int[]) array, addr);
303: } else if (array instanceof short[]) {
304: staticUnpinShortArrayNoCopy((short[]) array, addr);
305: } else if (array instanceof long[]) {
306: staticUnpinLongArrayNoCopy((long[]) array, addr);
307: } else if (array instanceof float[]) {
308: staticUnpinFloatArrayNoCopy((float[]) array, addr);
309: } else if (array instanceof double[]) {
310: staticUnpinDoubleArrayNoCopy((double[]) array, addr);
311: }
312: } else {
313: staticUnlockArrayNoCopy(array, addr);
314: }
315: objectLockMap.remove(array);
316: }
317: }
318:
319: /**
320: * Reports the offset of the first element in the storage allocation of a
321: * given array class.
322: *
323: * @param arrayClass
324: * class of array (ex.: byte[].class)
325: * @return the first element location
326: * @see #getArrayElementSize(Class)
327: */
328: public final long getArrayBaseOffset(Class arrayClass) {
329: return 0;
330: }
331:
332: /**
333: * Reports the element size for addressing elements in the storage
334: * allocation of a given array class.
335: *
336: * @param arrayClass
337: * class of array (ex.: byte[].class)
338: * @return element size
339: */
340: public final int getArrayElementSize(Class arrayClass) {
341: if (!arrayClass.isArray()) {
342: // misc.4=not an array Class
343: throw new RuntimeException(Messages.getString("misc.4")); //$NON-NLS-1$
344: }
345: if (arrayClass == byte[].class || arrayClass == boolean[].class) {
346: return 1;
347: }
348: if (arrayClass == char[].class || arrayClass == short[].class) {
349: return 2;
350: }
351: if (arrayClass == int[].class || arrayClass == float[].class) {
352: return 4;
353: }
354: if (arrayClass == long[].class || arrayClass == double[].class) {
355: return 8;
356: }
357: return 4;
358: }
359:
360: /**
361: * Reads a byte element at the given index without bounds check.
362: *
363: * @see #setElement(byte[], int, byte)
364: * @param arr
365: * array those element needs to be read
366: * @param index
367: * element index
368: * @return byte value of the element
369: */
370: public final native byte getElement(byte[] arr, int index);
371:
372: /**
373: * Writes a byte element at the given index without bounds check.
374: *
375: * @see #getElement(byte[], int)
376: * @param arr
377: * array those element needs to be set
378: * @param index
379: * element index
380: * @param value
381: * a byte value to be set
382: */
383: public final native void setElement(byte[] arr, int index,
384: byte value);
385:
386: /**
387: * Reads a boolean element at the given index without bounds check.
388: *
389: * @see #setElement(boolean[], int, boolean)
390: * @param arr
391: * array those element needs to be read
392: * @param index
393: * element index
394: * @return boolean value of the element
395: */
396: public final native boolean getElement(boolean[] arr, int index);
397:
398: /**
399: * Writes a boolean element at the given index without bounds check.
400: *
401: * @see #getElement(boolean[], int)
402: * @param arr
403: * array those element needs to be set
404: * @param index
405: * element index
406: * @param value
407: * a boolean value to be set
408: */
409: public final native void setElement(boolean[] arr, int index,
410: boolean value);
411:
412: /**
413: * Reads a char element at the given index without bounds check.
414: *
415: * @see #setElement(char[], int, char)
416: * @param arr
417: * array those element needs to be read
418: * @param index
419: * element index
420: * @return char value of the element
421: */
422: public final native char getElement(char[] arr, int index);
423:
424: /**
425: * Writes a char element at the given index without bounds check.
426: *
427: * @see #getElement(char[], int)
428: * @param arr
429: * array those element needs to be set
430: * @param index
431: * element index
432: * @param value
433: * a char value to be set
434: */
435: public final native void setElement(char[] arr, int index,
436: char value);
437:
438: /**
439: * Reads a short element at the given index without bounds check.
440: *
441: * @see #setElement(short[], int, short)
442: * @param arr
443: * array those element needs to be read
444: * @param index
445: * element index
446: * @return short value of the element
447: */
448: public final native short getElement(short[] arr, int index);
449:
450: /**
451: * Writes a short element at the given index without bounds check.
452: *
453: * @see #getElement(short[], int)
454: * @param arr
455: * array those element needs to be set
456: * @param index
457: * element index
458: * @param value
459: * a short value to be set
460: */
461: public final native void setElement(short[] arr, int index,
462: short value);
463:
464: /**
465: * Reads a int element at the given index without bounds check.
466: *
467: * @see #setElement(int[], int, int)
468: * @param arr
469: * array those element needs to be read
470: * @param index
471: * element index
472: * @return int value of the element
473: */
474: public final native int getElement(int[] arr, int index);
475:
476: /**
477: * Writes a int element at the given index without bounds check.
478: *
479: * @see #getElement(int[], int)
480: * @param arr
481: * array those element needs to be set
482: * @param index
483: * element index
484: * @param value
485: * a int value to be set
486: */
487: public final native void setElement(int[] arr, int index, int value);
488:
489: /**
490: * Reads a long element at the given index without bounds check.
491: *
492: * @see #setElement(long[], int, long)
493: * @param arr
494: * array those element needs to be read
495: * @param index
496: * element index
497: * @return long value of the element
498: */
499: public final native long getElement(long[] arr, int index);
500:
501: /**
502: * Writes a long element at the given index without bounds check.
503: *
504: * @see #getElement(long[], int)
505: * @param arr
506: * array those element needs to be set
507: * @param index
508: * element index
509: * @param value
510: * a long value to be set
511: */
512: public final native void setElement(long[] arr, int index,
513: long value);
514:
515: /**
516: * Reads a float element at the given index without bounds check.
517: *
518: * @see #setElement(float[], int, float)
519: * @param arr
520: * array those element needs to be read
521: * @param index
522: * element index
523: * @return float value of the element
524: */
525: public final native float getElement(float[] arr, int index);
526:
527: /**
528: * Writes a float element at the given index without bounds check.
529: *
530: * @see #getElement(float[], int)
531: * @param arr
532: * array those element needs to be set
533: * @param index
534: * element index
535: * @param value
536: * a float value to be set
537: */
538: public final native void setElement(float[] arr, int index,
539: float value);
540:
541: /**
542: * Reads a double element at the given index without bounds check.
543: *
544: * @see #setElement(double[], int, double)
545: * @param arr
546: * array those element needs to be read
547: * @param index
548: * element index
549: * @return double value of the element
550: */
551: public final native double getElement(double[] arr, int index);
552:
553: /**
554: * Writes a double element at the given index without bounds check.
555: *
556: * @see #getElement(double[], int)
557: * @param arr
558: * array those element needs to be set
559: * @param index
560: * element index
561: * @param value
562: * a double value to be set
563: */
564: public final native void setElement(double[] arr, int index,
565: double value);
566:
567: /**
568: * Reads an Object element at the given index without bounds check.
569: *
570: * @see #setElement(Object[], int, Object)
571: * @param arr
572: * array those element needs to be read
573: * @param index
574: * element index
575: * @return Object value of the element
576: */
577: public final native Object getElement(Object[] arr, int index);
578:
579: /**
580: * Writes an Object element at the given index without bounds check.
581: *
582: * @see #getElement(Object[], int)
583: * @param arr
584: * array those element needs to be set
585: * @param index
586: * element index
587: * @param value
588: * a Object value to be set
589: */
590: public final native void setElement(Object[] arr, int index,
591: Object value);
592:
593: private static native long staticLockArray(Object array);
594:
595: static native void staticUnlockArray(Object array, long addr);
596:
597: static native void staticUnlockArrayNoCopy(Object array, long addr);
598:
599: private static native long staticPinByteArray(Object array);
600:
601: private static native long staticPinCharArray(Object array);
602:
603: private static native long staticPinShortArray(Object array);
604:
605: private static native long staticPinIntArray(Object array);
606:
607: private static native long staticPinLongArray(Object array);
608:
609: private static native long staticPinFloatArray(Object array);
610:
611: private static native long staticPinDoubleArray(Object array);
612:
613: private static native void staticUnpinByteArray(Object array, long l);
614:
615: private static native void staticUnpinCharArray(Object array, long l);
616:
617: private static native void staticUnpinShortArray(Object array,
618: long l);
619:
620: private static native void staticUnpinIntArray(Object array, long l);
621:
622: private static native void staticUnpinLongArray(Object array, long l);
623:
624: private static native void staticUnpinFloatArray(Object array,
625: long l);
626:
627: private static native void staticUnpinDoubleArray(Object array,
628: long l);
629:
630: private static native void staticUnpinByteArrayNoCopy(Object array,
631: long l);
632:
633: private static native void staticUnpinCharArrayNoCopy(Object array,
634: long l);
635:
636: private static native void staticUnpinShortArrayNoCopy(
637: Object array, long l);
638:
639: private static native void staticUnpinIntArrayNoCopy(Object array,
640: long l);
641:
642: private static native void staticUnpinLongArrayNoCopy(Object array,
643: long l);
644:
645: private static native void staticUnpinFloatArrayNoCopy(
646: Object array, long l);
647:
648: private static native void staticUnpinDoubleArrayNoCopy(
649: Object array, long l);
650:
651: }
|