IntArrayData.java revision 1179:2b9af466a49d
1234949Sbapt/*
2234949Sbapt * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3234949Sbapt * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4234949Sbapt *
5234949Sbapt * This code is free software; you can redistribute it and/or modify it
6234949Sbapt * under the terms of the GNU General Public License version 2 only, as
7234949Sbapt * published by the Free Software Foundation.  Oracle designates this
8234949Sbapt * particular file as subject to the "Classpath" exception as provided
9234949Sbapt * by Oracle in the LICENSE file that accompanied this code.
10234949Sbapt *
11234949Sbapt * This code is distributed in the hope that it will be useful, but WITHOUT
12234949Sbapt * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13234949Sbapt * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14234949Sbapt * version 2 for more details (a copy is included in the LICENSE file that
15234949Sbapt * accompanied this code).
16234949Sbapt *
17234949Sbapt * You should have received a copy of the GNU General Public License version
18234949Sbapt * 2 along with this work; if not, write to the Free Software Foundation,
19234949Sbapt * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20234949Sbapt *
21234949Sbapt * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22234949Sbapt * or visit www.oracle.com if you need additional information or have any
23234949Sbapt * questions.
24234949Sbapt */
25234949Sbapt
26234949Sbaptpackage jdk.nashorn.internal.runtime.arrays;
27234949Sbapt
28234949Sbaptimport static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
29234949Sbapt
30234949Sbaptimport java.lang.invoke.MethodHandle;
31234949Sbaptimport java.lang.invoke.MethodHandles;
32234949Sbaptimport java.util.Arrays;
33234949Sbaptimport jdk.nashorn.internal.runtime.JSType;
34234949Sbaptimport jdk.nashorn.internal.runtime.ScriptRuntime;
35234949Sbapt
36234949Sbapt/**
37234949Sbapt * Implementation of {@link ArrayData} as soon as an int has been
38234949Sbapt * written to the array. This is the default data for new arrays
39234949Sbapt */
40234949Sbaptfinal class IntArrayData extends ContinuousArrayData implements IntElements {
41234949Sbapt    /**
42234949Sbapt     * The wrapped array
43234949Sbapt     */
44234949Sbapt    private int[] array;
45234949Sbapt
46234949Sbapt    IntArrayData() {
47234949Sbapt        this(new int[ArrayData.CHUNK_SIZE], 0);
48234949Sbapt    }
49234949Sbapt
50234949Sbapt    IntArrayData(final int length) {
51234949Sbapt        super(length);
52234949Sbapt        this.array  = new int[ArrayData.nextSize(length)];
53234949Sbapt    }
54234949Sbapt
55234949Sbapt    /**
56234949Sbapt     * Constructor
57234949Sbapt     * @param array an int array
58234949Sbapt     * @param length a length, not necessarily array.length
59234949Sbapt     */
60234949Sbapt    IntArrayData(final int[] array, final int length) {
61234949Sbapt        super(length);
62234949Sbapt        assert array == null || array.length >= length;
63234949Sbapt        this.array = array;
64234949Sbapt    }
65234949Sbapt
66234949Sbapt    @Override
67234949Sbapt    public final Class<?> getElementType() {
68234949Sbapt        return int.class;
69234949Sbapt    }
70234949Sbapt
71234949Sbapt    @Override
72234949Sbapt    public final Class<?> getBoxedElementType() {
73234949Sbapt        return Integer.class;
74234949Sbapt    }
75234949Sbapt
76234949Sbapt    @Override
77234949Sbapt    public final int getElementWeight() {
78234949Sbapt        return 1;
79234949Sbapt    }
80234949Sbapt
81234949Sbapt    @Override
82234949Sbapt    public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
83234949Sbapt        return otherData;
84234949Sbapt    }
85234949Sbapt
86234949Sbapt    private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
87234949Sbapt    private static final MethodHandle SET_ELEM     = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
88234949Sbapt
89234949Sbapt    @Override
90234949Sbapt    public Object[] asObjectArray() {
91234949Sbapt        return toObjectArray(true);
92234949Sbapt    }
93234949Sbapt
94264803Sbapt    @SuppressWarnings("unused")
95264803Sbapt    private int getElem(final int index) {
96234949Sbapt        if (has(index)) {
97234949Sbapt            return array[index];
98234949Sbapt        }
99264803Sbapt        throw new ClassCastException();
100264803Sbapt    }
101234949Sbapt
102234949Sbapt    @SuppressWarnings("unused")
103234949Sbapt    private void setElem(final int index, final int elem) {
104234949Sbapt        if (hasRoomFor(index)) {
105234949Sbapt            array[index] = elem;
106234949Sbapt            return;
107234949Sbapt        }
108234949Sbapt        throw new ClassCastException();
109234949Sbapt    }
110234949Sbapt
111234949Sbapt    @Override
112234949Sbapt    public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
113234949Sbapt        return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint);
114234949Sbapt    }
115234949Sbapt
116234949Sbapt    @Override
117234949Sbapt    public MethodHandle getElementSetter(final Class<?> elementType) {
118234949Sbapt        return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null;
119234949Sbapt    }
120234949Sbapt
121234949Sbapt    @Override
122234949Sbapt    public IntArrayData copy() {
123234949Sbapt        return new IntArrayData(array.clone(), (int)length());
124234949Sbapt    }
125234949Sbapt
126234949Sbapt    @Override
127234949Sbapt    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] = Integer.valueOf(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) {
186            return this;
187        } else if (type == Long.class) {
188            return convertToLong();
189        } else if (type == Double.class) {
190            return convertToDouble();
191        } else {
192            assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive());
193            return convertToObject();
194        }
195    }
196
197    @Override
198    public void shiftLeft(final int by) {
199        System.arraycopy(array, by, array, 0, array.length - by);
200    }
201
202    @Override
203    public ArrayData shiftRight(final int by) {
204        final ArrayData newData = ensure(by + length() - 1);
205        if (newData != this) {
206            newData.shiftRight(by);
207            return newData;
208        }
209        System.arraycopy(array, 0, array, by, array.length - by);
210
211        return this;
212    }
213
214    @Override
215    public ArrayData ensure(final long safeIndex) {
216        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
217            return new SparseArrayData(this, safeIndex + 1);
218        }
219        final int alen = array.length;
220        if (safeIndex >= alen) {
221            final int newLength = ArrayData.nextSize((int)safeIndex);
222            array = Arrays.copyOf(array, newLength);
223        }
224        if (safeIndex >= length()) {
225            setLength(safeIndex + 1);
226        }
227        return this;
228    }
229
230    @Override
231    public ArrayData shrink(final long newLength) {
232        Arrays.fill(array, (int)newLength, array.length, 0);
233        return this;
234    }
235
236    @Override
237    public ArrayData set(final int index, final Object value, final boolean strict) {
238        if (JSType.isRepresentableAsInt(value)) {
239            return set(index, JSType.toInt32(value), strict);
240        } else if (value == ScriptRuntime.UNDEFINED) {
241            return new UndefinedArrayFilter(this).set(index, value, strict);
242        }
243
244        final ArrayData newData = convert(value == null ? Object.class : value.getClass());
245        return newData.set(index, value, strict);
246    }
247
248    @Override
249    public ArrayData set(final int index, final int value, final boolean strict) {
250        array[index] = value;
251        setLength(Math.max(index + 1, length()));
252
253        return this;
254    }
255
256    @Override
257    public ArrayData set(final int index, final long value, final boolean strict) {
258        if (JSType.isRepresentableAsInt(value)) {
259            array[index] = JSType.toInt32(value);
260            setLength(Math.max(index + 1, length()));
261            return this;
262        }
263
264        return convert(Long.class).set(index, value, strict);
265    }
266
267    @Override
268    public ArrayData set(final int index, final double value, final boolean strict) {
269        if (JSType.isRepresentableAsInt(value)) {
270            array[index] = (int)(long)value;
271            setLength(Math.max(index + 1, length()));
272            return this;
273        }
274
275        return convert(Double.class).set(index, value, strict);
276    }
277
278    @Override
279    public int getInt(final int index) {
280        return array[index];
281    }
282
283    @Override
284    public int getIntOptimistic(final int index, final int programPoint) {
285        return array[index];
286    }
287
288    @Override
289    public long getLong(final int index) {
290        return array[index];
291    }
292
293    @Override
294    public long getLongOptimistic(final int index, final int programPoint) {
295        return array[index];
296    }
297
298    @Override
299    public double getDouble(final int index) {
300        return array[index];
301    }
302
303    @Override
304    public double getDoubleOptimistic(final int index, final int programPoint) {
305        return array[index];
306    }
307
308    @Override
309    public Object getObject(final int index) {
310        return array[index];
311    }
312
313    @Override
314    public boolean has(final int index) {
315        return 0 <= index && index < length();
316    }
317
318    @Override
319    public ArrayData delete(final int index) {
320        return new DeletedRangeArrayFilter(this, index, index);
321    }
322
323    @Override
324    public ArrayData delete(final long fromIndex, final long toIndex) {
325        return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
326    }
327
328    @Override
329    public Object pop() {
330        final int len = (int)length();
331        if (len == 0) {
332            return ScriptRuntime.UNDEFINED;
333        }
334
335        final int newLength = len - 1;
336        final int elem = array[newLength];
337        array[newLength] = 0;
338        setLength(newLength);
339
340        return elem;
341    }
342
343    @Override
344    public ArrayData slice(final long from, final long to) {
345        return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from)));
346    }
347
348    @Override
349    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
350        final long oldLength = length();
351        final long newLength = oldLength - removed + added;
352        if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
353            throw new UnsupportedOperationException();
354        }
355        final ArrayData returnValue = removed == 0 ?
356                EMPTY_ARRAY :
357                new IntArrayData(
358                        Arrays.copyOfRange(
359                                array,
360                                start,
361                                start + removed),
362                        removed);
363
364        if (newLength != oldLength) {
365            final int[] newArray;
366
367            if (newLength > array.length) {
368                newArray = new int[ArrayData.nextSize((int)newLength)];
369                System.arraycopy(array, 0, newArray, 0, start);
370            } else {
371                newArray = array;
372            }
373
374            System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
375            array = newArray;
376            setLength(newLength);
377        }
378
379        return returnValue;
380    }
381
382    @Override
383    public long fastPush(final int arg) {
384        final int len = (int)length();
385        if (len == array.length) {
386            array = Arrays.copyOf(array, nextSize(len));
387        }
388        array[len] = arg;
389        return increaseLength();
390    }
391
392    //length must not be zero
393    @Override
394    public int fastPopInt() {
395        if (length() == 0) {
396            throw new ClassCastException(); //relink
397        }
398        final int newLength = (int)decreaseLength();
399        final int elem = array[newLength];
400        array[newLength] = 0;
401        return elem;
402    }
403
404    @Override
405    public long fastPopLong() {
406        return fastPopInt();
407    }
408
409    @Override
410    public double fastPopDouble() {
411        return fastPopInt();
412    }
413
414    @Override
415    public Object fastPopObject() {
416        return fastPopInt();
417    }
418
419    @Override
420    public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
421        final int   otherLength = (int)otherData.length();
422        final int   thisLength  = (int)length();
423        assert otherLength > 0 && thisLength > 0;
424
425        final int[] otherArray  = ((IntArrayData)otherData).array;
426        final int   newLength   = otherLength + thisLength;
427        final int[] newArray    = new int[ArrayData.alignUp(newLength)];
428
429        System.arraycopy(array, 0, newArray, 0, thisLength);
430        System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
431
432        return new IntArrayData(newArray, newLength);
433    }
434
435    @Override
436    public String toString() {
437        assert length() <= array.length : length() + " > " + array.length;
438        return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
439    }
440}
441