src/jdk/nashorn/internal/objects/ArrayBufferView.java

Fri, 07 Jun 2013 17:44:25 +0200

author
hannesw
date
Fri, 07 Jun 2013 17:44:25 +0200
changeset 334
918a986b0478
parent 290
6fc7b51e83d6
child 380
80c66d3fd872
permissions
-rw-r--r--

8012291: NativeArray is inconsistent in using long for length and index in some places and int for the same in other places
Reviewed-by: lagergren, jlaskey

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.objects;
jlaskey@3 27
jlaskey@3 28 import jdk.nashorn.internal.objects.annotations.Attribute;
jlaskey@3 29 import jdk.nashorn.internal.objects.annotations.Getter;
jlaskey@3 30 import jdk.nashorn.internal.objects.annotations.ScriptClass;
jlaskey@3 31 import jdk.nashorn.internal.runtime.JSType;
jlaskey@3 32 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 33 import jdk.nashorn.internal.runtime.ScriptRuntime;
jlaskey@3 34 import jdk.nashorn.internal.runtime.arrays.ArrayData;
jlaskey@3 35
hannesw@334 36 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
hannesw@334 37
jlaskey@3 38 @ScriptClass("ArrayBufferView")
jlaskey@3 39 abstract class ArrayBufferView extends ScriptObject {
jlaskey@3 40
jlaskey@3 41 ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
jlaskey@3 42 checkConstructorArgs(buffer, byteOffset, elementLength);
jlaskey@3 43 this.setProto(getPrototype());
jlaskey@3 44 this.setArray(factory().createArrayData(buffer, byteOffset, elementLength));
jlaskey@3 45 }
jlaskey@3 46
jlaskey@3 47 private void checkConstructorArgs(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
jlaskey@3 48 if (byteOffset < 0 || elementLength < 0) {
jlaskey@3 49 throw new RuntimeException("byteOffset or length must not be negative");
jlaskey@3 50 }
jlaskey@3 51 if (byteOffset + elementLength * bytesPerElement() > buffer.getByteLength()) {
jlaskey@3 52 throw new RuntimeException("byteOffset + byteLength out of range");
jlaskey@3 53 }
jlaskey@3 54 if (byteOffset % bytesPerElement() != 0) {
jlaskey@3 55 throw new RuntimeException("byteOffset must be a multiple of the element size");
jlaskey@3 56 }
jlaskey@3 57 }
jlaskey@3 58
jlaskey@3 59 private int bytesPerElement() {
jlaskey@3 60 return factory().bytesPerElement;
jlaskey@3 61 }
jlaskey@3 62
jlaskey@3 63 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
jlaskey@3 64 public static Object buffer(final Object self) {
jlaskey@3 65 return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).buffer;
jlaskey@3 66 }
jlaskey@3 67
jlaskey@3 68 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
jlaskey@3 69 public static Object byteOffset(final Object self) {
jlaskey@3 70 return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).byteOffset;
jlaskey@3 71 }
jlaskey@3 72
jlaskey@3 73 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
jlaskey@3 74 public static Object byteLength(final Object self) {
jlaskey@3 75 final ArrayBufferView view = (ArrayBufferView)self;
jlaskey@3 76 return ((ArrayDataImpl)view.getArray()).elementLength * view.bytesPerElement();
jlaskey@3 77 }
jlaskey@3 78
jlaskey@3 79 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
jlaskey@3 80 public static Object length(final Object self) {
jlaskey@3 81 return ((ArrayBufferView)self).elementLength();
jlaskey@3 82 }
jlaskey@3 83
jlaskey@3 84 @Override
jlaskey@3 85 public final Object getLength() {
jlaskey@3 86 return elementLength();
jlaskey@3 87 }
jlaskey@3 88
jlaskey@3 89 private int elementLength() {
jlaskey@3 90 return ((ArrayDataImpl)getArray()).elementLength;
jlaskey@3 91 }
jlaskey@3 92
jlaskey@3 93 protected static abstract class ArrayDataImpl extends ArrayData {
jlaskey@3 94 protected final NativeArrayBuffer buffer;
jlaskey@3 95 protected final int byteOffset;
jlaskey@3 96 private final int elementLength;
jlaskey@3 97
jlaskey@3 98 protected ArrayDataImpl(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
jlaskey@3 99 super(elementLength);
jlaskey@3 100 this.buffer = buffer;
jlaskey@3 101 this.byteOffset = byteOffset;
jlaskey@3 102 this.elementLength = elementLength;
jlaskey@3 103 }
jlaskey@3 104
jlaskey@3 105 @Override
jlaskey@3 106 public Object[] asObjectArray() {
jlaskey@3 107 final Object[] array = new Object[elementLength];
jlaskey@3 108 for (int i = 0; i < elementLength; i++) {
jlaskey@3 109 array[i] = getObjectImpl(i);
jlaskey@3 110 }
jlaskey@3 111 return array;
jlaskey@3 112 }
jlaskey@3 113
jlaskey@3 114 @Override
jlaskey@3 115 public ArrayData ensure(final long safeIndex) {
jlaskey@3 116 return this;
jlaskey@3 117 }
jlaskey@3 118
jlaskey@3 119 @Override
jlaskey@3 120 public void setLength(final long length) {
jlaskey@3 121 //empty?
jlaskey@3 122 //TODO is this right?
jlaskey@3 123 }
jlaskey@3 124
jlaskey@3 125 @Override
jlaskey@3 126 public ArrayData shrink(final long newLength) {
jlaskey@3 127 return this;
jlaskey@3 128 }
jlaskey@3 129
jlaskey@3 130 @Override
jlaskey@3 131 public ArrayData set(final int index, final Object value, final boolean strict) {
jlaskey@3 132 if (has(index)) {
jlaskey@3 133 setImpl(index, value);
jlaskey@3 134 }
jlaskey@3 135 return this;
jlaskey@3 136 }
jlaskey@3 137
jlaskey@3 138 @Override
jlaskey@3 139 public ArrayData set(final int index, final int value, final boolean strict) {
jlaskey@3 140 if (has(index)) {
jlaskey@3 141 setImpl(index, value);
jlaskey@3 142 }
jlaskey@3 143 return this;
jlaskey@3 144 }
jlaskey@3 145
jlaskey@3 146 @Override
jlaskey@3 147 public ArrayData set(final int index, final long value, final boolean strict) {
jlaskey@3 148 if (has(index)) {
jlaskey@3 149 setImpl(index, value);
jlaskey@3 150 }
jlaskey@3 151 return this;
jlaskey@3 152 }
jlaskey@3 153
jlaskey@3 154 @Override
jlaskey@3 155 public ArrayData set(final int index, final double value, final boolean strict) {
jlaskey@3 156 if (has(index)) {
jlaskey@3 157 setImpl(index, value);
jlaskey@3 158 }
jlaskey@3 159 return this;
jlaskey@3 160 }
jlaskey@3 161
jlaskey@3 162 @Override
jlaskey@3 163 public int getInt(final int index) {
jlaskey@3 164 return getIntImpl(index);
jlaskey@3 165 }
jlaskey@3 166
jlaskey@3 167 @Override
jlaskey@3 168 public long getLong(final int index) {
jlaskey@3 169 return getLongImpl(index);
jlaskey@3 170 }
jlaskey@3 171
jlaskey@3 172 @Override
jlaskey@3 173 public double getDouble(final int index) {
jlaskey@3 174 return getDoubleImpl(index);
jlaskey@3 175 }
jlaskey@3 176
jlaskey@3 177 @Override
jlaskey@3 178 public Object getObject(final int index) {
jlaskey@3 179 return getObjectImpl(index);
jlaskey@3 180 }
jlaskey@3 181
jlaskey@3 182 @Override
jlaskey@3 183 public boolean has(final int index) {
jlaskey@3 184 return index >= 0 && index < elementLength;
jlaskey@3 185 }
jlaskey@3 186
jlaskey@3 187 @Override
jlaskey@3 188 public boolean canDelete(final int index, final boolean strict) {
jlaskey@3 189 return false;
jlaskey@3 190 }
jlaskey@3 191
jlaskey@3 192 @Override
jlaskey@3 193 public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
jlaskey@3 194 return false;
jlaskey@3 195 }
jlaskey@3 196
jlaskey@3 197 @Override
jlaskey@3 198 public ArrayData delete(final int index) {
jlaskey@3 199 return this;
jlaskey@3 200 }
jlaskey@3 201
jlaskey@3 202 @Override
jlaskey@3 203 public ArrayData delete(final long fromIndex, final long toIndex) {
jlaskey@3 204 return this;
jlaskey@3 205 }
jlaskey@3 206
jlaskey@3 207 @Override
jlaskey@3 208 protected ArrayData convert(final Class<?> type) {
jlaskey@3 209 return this;
jlaskey@3 210 }
jlaskey@3 211
jlaskey@3 212 @Override
jlaskey@3 213 public void shiftLeft(final int by) {
jlaskey@3 214 throw new UnsupportedOperationException();
jlaskey@3 215 }
jlaskey@3 216
jlaskey@3 217 @Override
jlaskey@3 218 public ArrayData shiftRight(final int by) {
jlaskey@3 219 throw new UnsupportedOperationException();
jlaskey@3 220 }
jlaskey@3 221
jlaskey@3 222 @Override
jlaskey@3 223 public Object pop() {
jlaskey@3 224 throw new UnsupportedOperationException();
jlaskey@3 225 }
jlaskey@3 226
jlaskey@3 227 @Override
jlaskey@3 228 public ArrayData slice(final long from, final long to) {
jlaskey@3 229 throw new UnsupportedOperationException();
jlaskey@3 230 }
jlaskey@3 231
jlaskey@3 232 protected abstract int getIntImpl(int key);
jlaskey@3 233
jlaskey@3 234 protected long getLongImpl(final int key) {
jlaskey@3 235 return getIntImpl(key);
jlaskey@3 236 }
jlaskey@3 237
jlaskey@3 238 protected double getDoubleImpl(final int key) {
jlaskey@3 239 return getIntImpl(key);
jlaskey@3 240 }
jlaskey@3 241
jlaskey@3 242 protected Object getObjectImpl(final int key) {
jlaskey@3 243 return getIntImpl(key);
jlaskey@3 244 }
jlaskey@3 245
jlaskey@3 246 protected abstract void setImpl(int key, int value);
jlaskey@3 247
jlaskey@3 248 protected void setImpl(final int key, final long value) {
jlaskey@3 249 setImpl(key, (int)value);
jlaskey@3 250 }
jlaskey@3 251
jlaskey@3 252 protected void setImpl(final int key, final double value) {
jlaskey@3 253 setImpl(key, JSType.toInt32(value));
jlaskey@3 254 }
jlaskey@3 255
jlaskey@3 256 protected void setImpl(final int key, final Object value) {
jlaskey@3 257 setImpl(key, JSType.toInt32(value));
jlaskey@3 258 }
jlaskey@3 259
jlaskey@3 260 protected abstract int byteIndex(int index);
jlaskey@3 261 }
jlaskey@3 262
jlaskey@3 263 protected static abstract class Factory {
jlaskey@3 264 final int bytesPerElement;
jlaskey@3 265
jlaskey@3 266 public Factory(final int bytesPerElement) {
jlaskey@3 267 this.bytesPerElement = bytesPerElement;
jlaskey@3 268 }
jlaskey@3 269
jlaskey@3 270 public final ArrayBufferView construct(final int elementLength) {
jlaskey@3 271 return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength);
jlaskey@3 272 }
jlaskey@3 273
jlaskey@3 274 public abstract ArrayBufferView construct(NativeArrayBuffer buffer, int byteOffset, int elementLength);
jlaskey@3 275
jlaskey@3 276 public abstract ArrayData createArrayData(NativeArrayBuffer buffer, int byteOffset, int elementLength);
jlaskey@3 277 }
jlaskey@3 278
jlaskey@3 279 protected abstract Factory factory();
jlaskey@3 280
jlaskey@3 281 protected abstract ScriptObject getPrototype();
jlaskey@3 282
jlaskey@3 283 protected boolean isFloatArray() {
jlaskey@3 284 return false;
jlaskey@3 285 }
jlaskey@3 286
jlaskey@3 287 protected static ArrayBufferView constructorImpl(final Object[] args, final Factory factory) {
jlaskey@3 288 final Object arg0 = args.length != 0 ? args[0] : 0;
jlaskey@3 289 final ArrayBufferView dst;
jlaskey@3 290 final int length;
jlaskey@3 291 if (arg0 instanceof NativeArrayBuffer) {
jlaskey@3 292 // Constructor(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length)
jlaskey@3 293 final NativeArrayBuffer buffer = (NativeArrayBuffer) arg0;
jlaskey@3 294 final int byteOffset = args.length > 1 ? JSType.toInt32(args[1]) : 0;
jlaskey@3 295 if (args.length > 2) {
jlaskey@3 296 length = JSType.toInt32(args[2]);
jlaskey@3 297 } else {
jlaskey@3 298 if ((buffer.getByteLength() - byteOffset) % factory.bytesPerElement != 0) {
jlaskey@3 299 throw new RuntimeException("buffer.byteLength - byteOffset must be a multiple of the element size");
jlaskey@3 300 }
jlaskey@3 301 length = (buffer.getByteLength() - byteOffset) / factory.bytesPerElement;
jlaskey@3 302 }
jlaskey@3 303 return factory.construct(buffer, byteOffset, length);
jlaskey@3 304 } else if (arg0 instanceof ArrayBufferView) {
jlaskey@3 305 // Constructor(TypedArray array)
jlaskey@3 306 length = ((ArrayBufferView)arg0).elementLength();
jlaskey@3 307 dst = factory.construct(length);
jlaskey@3 308 } else if (arg0 instanceof NativeArray) {
jlaskey@3 309 // Constructor(type[] array)
hannesw@334 310 length = lengthToInt(((NativeArray) arg0).getArray().length());
jlaskey@3 311 dst = factory.construct(length);
jlaskey@3 312 } else {
jlaskey@3 313 // Constructor(unsigned long length)
hannesw@334 314 length = lengthToInt(JSType.toInt64(arg0));
jlaskey@3 315 return factory.construct(length);
jlaskey@3 316 }
jlaskey@3 317
jlaskey@3 318 copyElements(dst, length, (ScriptObject)arg0, 0);
jlaskey@3 319 return dst;
jlaskey@3 320 }
jlaskey@3 321
jlaskey@3 322 protected static Object setImpl(final Object self, final Object array, final Object offset0) {
jlaskey@3 323 final ArrayBufferView dest = ((ArrayBufferView)self);
jlaskey@3 324 final int length;
jlaskey@3 325 if (array instanceof ArrayBufferView) {
jlaskey@3 326 // void set(TypedArray array, optional unsigned long offset)
jlaskey@3 327 length = ((ArrayBufferView)array).elementLength();
jlaskey@3 328 } else if (array instanceof NativeArray) {
jlaskey@3 329 // void set(type[] array, optional unsigned long offset)
jlaskey@3 330 length = (int) (((NativeArray) array).getArray().length() & 0x7fff_ffff);
jlaskey@3 331 } else {
jlaskey@3 332 throw new RuntimeException("argument is not of array type");
jlaskey@3 333 }
jlaskey@3 334
jlaskey@3 335 final ScriptObject source = (ScriptObject) array;
jlaskey@3 336 final int offset = JSType.toInt32(offset0); // default=0
jlaskey@3 337
jlaskey@3 338 if (dest.elementLength() < length + offset || offset < 0) {
jlaskey@3 339 throw new RuntimeException("offset or array length out of bounds");
jlaskey@3 340 }
jlaskey@3 341
jlaskey@3 342 copyElements(dest, length, source, offset);
jlaskey@3 343
jlaskey@3 344 return ScriptRuntime.UNDEFINED;
jlaskey@3 345 }
jlaskey@3 346
jlaskey@3 347 private static void copyElements(final ArrayBufferView dest, final int length, final ScriptObject source, final int offset) {
jlaskey@3 348 if (!dest.isFloatArray()) {
jlaskey@3 349 for (int i = 0, j = offset; i < length; i++, j++) {
jlaskey@3 350 dest.set(j, source.getInt(i), false);
jlaskey@3 351 }
jlaskey@3 352 } else {
jlaskey@3 353 for (int i = 0, j = offset; i < length; i++, j++) {
jlaskey@3 354 dest.set(j, source.getDouble(i), false);
jlaskey@3 355 }
jlaskey@3 356 }
jlaskey@3 357 }
jlaskey@3 358
hannesw@334 359 private static int lengthToInt(final long length) {
hannesw@334 360 if (length > Integer.MAX_VALUE || length < 0) {
hannesw@334 361 throw rangeError("inappropriate.array.buffer.length", JSType.toString(length));
hannesw@334 362 }
hannesw@334 363 return (int) (length & Integer.MAX_VALUE);
hannesw@334 364 }
hannesw@334 365
jlaskey@3 366 protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) {
jlaskey@3 367 final ArrayBufferView arrayView = ((ArrayBufferView)self);
jlaskey@3 368 final int elementLength = arrayView.elementLength();
jlaskey@3 369 final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength);
jlaskey@3 370 final int end = NativeArrayBuffer.adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : elementLength, elementLength);
jlaskey@3 371 final ArrayDataImpl arrayData = (ArrayDataImpl)arrayView.getArray();
jlaskey@3 372 return arrayView.factory().construct(arrayData.buffer, arrayData.byteIndex(begin), Math.max(end - begin, 0));
jlaskey@3 373 }
jlaskey@3 374 }

mercurial