IntArrayData.java revision 1350:3cb11f4d617e
190075Sobrien/*
2132718Skan * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
390075Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4132718Skan *
590075Sobrien * This code is free software; you can redistribute it and/or modify it
6132718Skan * under the terms of the GNU General Public License version 2 only, as
790075Sobrien * published by the Free Software Foundation.  Oracle designates this
890075Sobrien * particular file as subject to the "Classpath" exception as provided
990075Sobrien * by Oracle in the LICENSE file that accompanied this code.
1090075Sobrien *
11132718Skan * This code is distributed in the hope that it will be useful, but WITHOUT
1290075Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1390075Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1490075Sobrien * version 2 for more details (a copy is included in the LICENSE file that
1590075Sobrien * accompanied this code).
1690075Sobrien *
17132718Skan * You should have received a copy of the GNU General Public License version
18169689Skan * 2 along with this work; if not, write to the Free Software Foundation,
19169689Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2090075Sobrien *
2190075Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2290075Sobrien * or visit www.oracle.com if you need additional information or have any
2396263Sobrien * questions.
2496263Sobrien */
2596263Sobrien
2696263Sobrienpackage jdk.nashorn.internal.runtime.arrays;
2796263Sobrien
2896263Sobrienimport static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
2996263Sobrien
3096263Sobrienimport java.lang.invoke.MethodHandle;
3196263Sobrienimport java.lang.invoke.MethodHandles;
3296263Sobrienimport java.util.Arrays;
33132718Skanimport jdk.nashorn.internal.runtime.JSType;
34132718Skanimport jdk.nashorn.internal.runtime.ScriptRuntime;
35132718Skan
36132718Skan/**
37169689Skan * Implementation of {@link ArrayData} as soon as an int has been
38132718Skan * written to the array. This is the default data for new arrays
39132718Skan */
40132718Skanfinal class IntArrayData extends ContinuousArrayData implements IntElements {
41132718Skan    /**
42132718Skan     * The wrapped array
43132718Skan     */
44132718Skan    private int[] array;
45
46    IntArrayData() {
47        this(new int[ArrayData.CHUNK_SIZE], 0);
48    }
49
50    IntArrayData(final int length) {
51        super(length);
52        this.array  = new int[ArrayData.nextSize(length)];
53    }
54
55    /**
56     * Constructor
57     * @param array an int array
58     * @param length a length, not necessarily array.length
59     */
60    IntArrayData(final int[] array, final int length) {
61        super(length);
62        assert array == null || array.length >= length;
63        this.array = array;
64    }
65
66    @Override
67    public final Class<?> getElementType() {
68        return int.class;
69    }
70
71    @Override
72    public final Class<?> getBoxedElementType() {
73        return Integer.class;
74    }
75
76    @Override
77    public final int getElementWeight() {
78        return 1;
79    }
80
81    @Override
82    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
83        return otherData;
84    }
85
86    private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
87    private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
88
89    @Override
90    public Object[] asObjectArray() {
91        return toObjectArray(true);
92    }
93
94    @SuppressWarnings("unused")
95    private int getElem(final int index) {
96        if (has(index)) {
97            return array[index];
98        }
99        throw new ClassCastException();
100    }
101
102    @SuppressWarnings("unused")
103    private void setElem(final int index, final int elem) {
104        if (hasRoomFor(index)) {
105            array[index] = elem;
106            return;
107        }
108        throw new ClassCastException();
109    }
110
111    @Override
112    public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
113        return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint);
114    }
115
116    @Override
117    public MethodHandle getElementSetter(final Class<?> elementType) {
118        return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null;
119    }
120
121    @Override
122    public IntArrayData copy() {
123        return new IntArrayData(array.clone(), (int)length());
124    }
125
126    @Override
127    public Object asArrayOfType(final Class<?> componentType) {
128        if (componentType == int.class) {
129            final int len = (int)length();
130            return array.length == len ? array.clone() : Arrays.copyOf(array, len);
131        }
132        return super.asArrayOfType(componentType);
133    }
134
135    private Object[] toObjectArray(final boolean trim) {
136        assert length() <= array.length : "length exceeds internal array size";
137        final int len = (int)length();
138        final Object[] oarray = new Object[trim ? len : array.length];
139
140        for (int index = 0; index < len; index++) {
141            oarray[index] = array[index];
142        }
143
144        return oarray;
145    }
146
147    private double[] toDoubleArray() {
148        assert length() <= array.length : "length exceeds internal array size";
149        final int len = (int)length();
150        final double[] darray = new double[array.length];
151
152        for (int index = 0; index < len; index++) {
153            darray[index] = array[index];
154        }
155
156        return darray;
157    }
158
159    private long[] toLongArray() {
160        assert length() <= array.length : "length exceeds internal array size";
161        final int len = (int)length();
162        final long[] larray = new long[array.length];
163
164        for (int index = 0; index < len; index++) {
165            larray[index] = array[index];
166        }
167
168        return larray;
169    }
170
171    private LongArrayData convertToLong() {
172        return new LongArrayData(toLongArray(), (int)length());
173    }
174
175    private NumberArrayData convertToDouble() {
176        return new NumberArrayData(toDoubleArray(), (int)length());
177    }
178
179    private ObjectArrayData convertToObject() {
180        return new ObjectArrayData(toObjectArray(false), (int)length());
181    }
182
183    @Override
184    public ArrayData convert(final Class<?> type) {
185        if (type == Integer.class || type == Byte.class || type == Short.class) {
186            return this;
187        } else if (type == Long.class) {
188            return convertToLong();
189        } else if (type == Double.class || type == Float.class) {
190            return convertToDouble();
191        } else {
192            return convertToObject();
193        }
194    }
195
196    @Override
197    public void shiftLeft(final int by) {
198        System.arraycopy(array, by, array, 0, array.length - by);
199    }
200
201    @Override
202    public ArrayData shiftRight(final int by) {
203        final ArrayData newData = ensure(by + length() - 1);
204        if (newData != this) {
205            newData.shiftRight(by);
206            return newData;
207        }
208        System.arraycopy(array, 0, array, by, array.length - by);
209
210        return this;
211    }
212
213    @Override
214    public ArrayData ensure(final long safeIndex) {
215        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
216            return new SparseArrayData(this, safeIndex + 1);
217        }
218        final int alen = array.length;
219        if (safeIndex >= alen) {
220            final int newLength = ArrayData.nextSize((int)safeIndex);
221            array = Arrays.copyOf(array, newLength);
222        }
223        if (safeIndex >= length()) {
224            setLength(safeIndex + 1);
225        }
226        return this;
227    }
228
229    @Override
230    public ArrayData shrink(final long newLength) {
231        Arrays.fill(array, (int)newLength, array.length, 0);
232        return this;
233    }
234
235    @Override
236    public ArrayData set(final int index, final Object value, final boolean strict) {
237        if (JSType.isRepresentableAsInt(value)) {
238            return set(index, JSType.toInt32(value), strict);
239        } else if (value == ScriptRuntime.UNDEFINED) {
240            return new UndefinedArrayFilter(this).set(index, value, strict);
241        }
242
243        final ArrayData newData = convert(value == null ? Object.class : value.getClass());
244        return newData.set(index, value, strict);
245    }
246
247    @Override
248    public ArrayData set(final int index, final int value, final boolean strict) {
249        array[index] = value;
250        setLength(Math.max(index + 1, length()));
251
252        return this;
253    }
254
255    @Override
256    public ArrayData set(final int index, final long value, final boolean strict) {
257        if (JSType.isRepresentableAsInt(value)) {
258            array[index] = JSType.toInt32(value);
259            setLength(Math.max(index + 1, length()));
260            return this;
261        }
262
263        return convert(Long.class).set(index, value, strict);
264    }
265
266    @Override
267    public ArrayData set(final int index, final double value, final boolean strict) {
268        if (JSType.isRepresentableAsInt(value)) {
269            array[index] = (int)(long)value;
270            setLength(Math.max(index + 1, length()));
271            return this;
272        }
273
274        return convert(Double.class).set(index, value, strict);
275    }
276
277    @Override
278    public int getInt(final int index) {
279        return array[index];
280    }
281
282    @Override
283    public int getIntOptimistic(final int index, final int programPoint) {
284        return array[index];
285    }
286
287    @Override
288    public long getLong(final int index) {
289        return array[index];
290    }
291
292    @Override
293    public long getLongOptimistic(final int index, final int programPoint) {
294        return array[index];
295    }
296
297    @Override
298    public double getDouble(final int index) {
299        return array[index];
300    }
301
302    @Override
303    public double getDoubleOptimistic(final int index, final int programPoint) {
304        return array[index];
305    }
306
307    @Override
308    public Object getObject(final int index) {
309        return array[index];
310    }
311
312    @Override
313    public boolean has(final int index) {
314        return 0 <= index && index < length();
315    }
316
317    @Override
318    public ArrayData delete(final int index) {
319        return new DeletedRangeArrayFilter(this, index, index);
320    }
321
322    @Override
323    public ArrayData delete(final long fromIndex, final long toIndex) {
324        return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
325    }
326
327    @Override
328    public Object pop() {
329        final int len = (int)length();
330        if (len == 0) {
331            return ScriptRuntime.UNDEFINED;
332        }
333
334        final int newLength = len - 1;
335        final int elem = array[newLength];
336        array[newLength] = 0;
337        setLength(newLength);
338
339        return elem;
340    }
341
342    @Override
343    public ArrayData slice(final long from, final long to) {
344        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from)));
345    }
346
347    @Override
348    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
349        final long oldLength = length();
350        final long newLength = oldLength - removed + added;
351        if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
352            throw new UnsupportedOperationException();
353        }
354        final ArrayData returnValue = removed == 0 ?
355                EMPTY_ARRAY :
356                new IntArrayData(
357                        Arrays.copyOfRange(
358                                array,
359                                start,
360                                start + removed),
361                        removed);
362
363        if (newLength != oldLength) {
364            final int[] newArray;
365
366            if (newLength > array.length) {
367                newArray = new int[ArrayData.nextSize((int)newLength)];
368                System.arraycopy(array, 0, newArray, 0, start);
369            } else {
370                newArray = array;
371            }
372
373            System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
374            array = newArray;
375            setLength(newLength);
376        }
377
378        return returnValue;
379    }
380
381    @Override
382    public long fastPush(final int arg) {
383        final int len = (int)length();
384        if (len == array.length) {
385            array = Arrays.copyOf(array, nextSize(len));
386        }
387        array[len] = arg;
388        return increaseLength();
389    }
390
391    //length must not be zero
392    @Override
393    public int fastPopInt() {
394        if (length() == 0) {
395            throw new ClassCastException(); //relink
396        }
397        final int newLength = (int)decreaseLength();
398        final int elem = array[newLength];
399        array[newLength] = 0;
400        return elem;
401    }
402
403    @Override
404    public long fastPopLong() {
405        return fastPopInt();
406    }
407
408    @Override
409    public double fastPopDouble() {
410        return fastPopInt();
411    }
412
413    @Override
414    public Object fastPopObject() {
415        return fastPopInt();
416    }
417
418    @Override
419    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
420        final int   otherLength = (int)otherData.length();
421        final int   thisLength  = (int)length();
422        assert otherLength > 0 && thisLength > 0;
423
424        final int[] otherArray  = ((IntArrayData)otherData).array;
425        final int   newLength   = otherLength + thisLength;
426        final int[] newArray    = new int[ArrayData.alignUp(newLength)];
427
428        System.arraycopy(array, 0, newArray, 0, thisLength);
429        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
430
431        return new IntArrayData(newArray, newLength);
432    }
433
434    @Override
435    public String toString() {
436        assert length() <= array.length : length() + " > " + array.length;
437        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
438    }
439}
440