1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.runtime.arrays;
27
28import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
29import java.lang.reflect.Array;
30import jdk.nashorn.internal.runtime.BitVector;
31import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
32
33/**
34 * This filter handles the presence of undefined array elements.
35 */
36final class UndefinedArrayFilter extends ArrayFilter {
37    /** Bit vector tracking undefined slots. */
38    private final BitVector undefined;
39
40    UndefinedArrayFilter(final ArrayData underlying) {
41        super(underlying);
42        this.undefined = new BitVector(underlying.length());
43    }
44
45    @Override
46    public ArrayData copy() {
47        final UndefinedArrayFilter copy = new UndefinedArrayFilter(underlying.copy());
48        copy.getUndefined().copy(undefined);
49        return copy;
50    }
51
52    @Override
53    public Object[] asObjectArray() {
54        final Object[] value = super.asObjectArray();
55
56        for (int i = 0; i < value.length; i++) {
57            if (undefined.isSet(i)) {
58                value[i] = UNDEFINED;
59            }
60        }
61
62        return value;
63    }
64
65    @Override
66    public Object asArrayOfType(final Class<?> componentType) {
67        final Object value = super.asArrayOfType(componentType);
68        final Object undefValue = convertUndefinedValue(componentType);
69        final int l = Array.getLength(value);
70        for (int i = 0; i < l; i++) {
71            if (undefined.isSet(i)) {
72                Array.set(value, i,undefValue);
73            }
74        }
75
76        return value;
77    }
78
79    @Override
80    public ArrayData shiftLeft(final int by) {
81        super.shiftLeft(by);
82        undefined.shiftLeft(by, length());
83        return this;
84    }
85
86    @Override
87    public ArrayData shiftRight(final int by) {
88        super.shiftRight(by);
89        undefined.shiftRight(by, length());
90        return this;
91    }
92
93    @Override
94    public ArrayData ensure(final long safeIndex) {
95        if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
96            return new SparseArrayData(this, safeIndex + 1);
97        }
98
99        super.ensure(safeIndex);
100        undefined.resize(length());
101
102        return this;
103    }
104
105    @Override
106    public ArrayData shrink(final long newLength) {
107        super.shrink(newLength);
108        undefined.resize(length());
109        return this;
110    }
111
112    @Override
113    public ArrayData set(final int index, final Object value, final boolean strict) {
114        undefined.clear(index);
115
116        if (value == UNDEFINED) {
117            undefined.set(index);
118            return this;
119        }
120
121        return super.set(index, value, strict);
122    }
123
124    @Override
125    public ArrayData set(final int index, final int value, final boolean strict) {
126        undefined.clear(index);
127
128        return super.set(index, value, strict);
129    }
130
131    @Override
132    public ArrayData set(final int index, final double value, final boolean strict) {
133        undefined.clear(index);
134
135        return super.set(index, value, strict);
136    }
137
138    @Override
139    public int getInt(final int index) {
140        if (undefined.isSet(index)) {
141            return 0;
142        }
143
144        return super.getInt(index);
145    }
146
147    @Override
148    public int getIntOptimistic(final int index, final int programPoint) {
149        if (undefined.isSet(index)) {
150            throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
151        }
152
153        return super.getIntOptimistic(index, programPoint);
154    }
155
156    @Override
157    public double getDouble(final int index) {
158        if (undefined.isSet(index)) {
159            return Double.NaN;
160        }
161
162        return super.getDouble(index);
163    }
164
165    @Override
166    public double getDoubleOptimistic(final int index, final int programPoint) {
167        if (undefined.isSet(index)) {
168            throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
169        }
170
171        return super.getDoubleOptimistic(index, programPoint);
172    }
173
174    @Override
175    public Object getObject(final int index) {
176        if (undefined.isSet(index)) {
177            return UNDEFINED;
178        }
179
180        return super.getObject(index);
181    }
182
183    @Override
184    public ArrayData delete(final int index) {
185        undefined.clear(index);
186
187        return super.delete(index);
188    }
189
190    @Override
191    public Object pop() {
192        final long index = length() - 1;
193
194        if (super.has((int)index)) {
195            final boolean isUndefined = undefined.isSet(index);
196            final Object value = super.pop();
197
198            return isUndefined ? UNDEFINED : value;
199        }
200
201        return super.pop();
202    }
203
204    @Override
205    public ArrayData slice(final long from, final long to) {
206        final ArrayData newArray = underlying.slice(from, to);
207        final UndefinedArrayFilter newFilter = new UndefinedArrayFilter(newArray);
208        newFilter.getUndefined().copy(undefined);
209        newFilter.getUndefined().shiftLeft(from, newFilter.length());
210
211        return newFilter;
212    }
213
214    private BitVector getUndefined() {
215        return undefined;
216    }
217}
218