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

Thu, 25 Sep 2014 15:53:47 +0200

author
lagergren
date
Thu, 25 Sep 2014 15:53:47 +0200
changeset 1028
d79265f2fa92
parent 1020
9ee8fd4a7266
child 1056
db675278b4d3
permissions
-rw-r--r--

8025435: Optimistic builtins support, implemented initial optimistic versions of push, pop, and charCodeAt
Reviewed-by: hannesw, attila, sundar

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
attila@446 28 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
attila@963 29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
attila@963 30 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
attila@446 31
attila@963 32 import java.nio.ByteBuffer;
attila@963 33 import java.nio.ByteOrder;
lagergren@1028 34
attila@963 35 import jdk.internal.dynalink.CallSiteDescriptor;
attila@963 36 import jdk.internal.dynalink.linker.GuardedInvocation;
attila@963 37 import jdk.internal.dynalink.linker.LinkRequest;
jlaskey@3 38 import jdk.nashorn.internal.objects.annotations.Attribute;
jlaskey@3 39 import jdk.nashorn.internal.objects.annotations.Getter;
jlaskey@3 40 import jdk.nashorn.internal.objects.annotations.ScriptClass;
jlaskey@3 41 import jdk.nashorn.internal.runtime.JSType;
hannesw@380 42 import jdk.nashorn.internal.runtime.PropertyMap;
jlaskey@3 43 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 44 import jdk.nashorn.internal.runtime.ScriptRuntime;
jlaskey@3 45 import jdk.nashorn.internal.runtime.arrays.ArrayData;
attila@963 46 import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
jlaskey@3 47
jlaskey@3 48 @ScriptClass("ArrayBufferView")
jlaskey@3 49 abstract class ArrayBufferView extends ScriptObject {
attila@963 50 private final NativeArrayBuffer buffer;
attila@963 51 private final int byteOffset;
jlaskey@3 52
hannesw@380 53 // initialized by nasgen
hannesw@380 54 private static PropertyMap $nasgenmap$;
hannesw@380 55
sundar@418 56 private ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength, final Global global) {
sundar@771 57 super($nasgenmap$);
attila@963 58
attila@963 59 final int bytesPerElement = bytesPerElement();
attila@963 60
attila@963 61 checkConstructorArgs(buffer.getByteLength(), bytesPerElement, byteOffset, elementLength);
attila@963 62 setProto(getPrototype(global));
attila@963 63
attila@963 64 this.buffer = buffer;
attila@963 65 this.byteOffset = byteOffset;
attila@963 66
attila@963 67 assert byteOffset % bytesPerElement == 0;
attila@963 68 final int start = byteOffset / bytesPerElement;
attila@963 69 final ByteBuffer newNioBuffer = buffer.getNioBuffer().duplicate().order(ByteOrder.nativeOrder());
attila@963 70 final ArrayData data = factory().createArrayData(newNioBuffer, start, start + elementLength);
attila@963 71
attila@963 72 setArray(data);
jlaskey@3 73 }
jlaskey@3 74
attila@963 75 protected ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
sundar@418 76 this(buffer, byteOffset, elementLength, Global.instance());
sundar@418 77 }
sundar@418 78
attila@963 79 private static void checkConstructorArgs(final int byteLength, final int bytesPerElement, final int byteOffset, final int elementLength) {
jlaskey@3 80 if (byteOffset < 0 || elementLength < 0) {
attila@963 81 throw new RuntimeException("byteOffset or length must not be negative, byteOffset=" + byteOffset + ", elementLength=" + elementLength + ", bytesPerElement=" + bytesPerElement);
attila@963 82 } else if (byteOffset + elementLength * bytesPerElement > byteLength) {
attila@963 83 throw new RuntimeException("byteOffset + byteLength out of range, byteOffset=" + byteOffset + ", elementLength=" + elementLength + ", bytesPerElement=" + bytesPerElement);
attila@963 84 } else if (byteOffset % bytesPerElement != 0) {
attila@963 85 throw new RuntimeException("byteOffset must be a multiple of the element size, byteOffset=" + byteOffset + " bytesPerElement=" + bytesPerElement);
jlaskey@3 86 }
jlaskey@3 87 }
jlaskey@3 88
jlaskey@3 89 private int bytesPerElement() {
jlaskey@3 90 return factory().bytesPerElement;
jlaskey@3 91 }
jlaskey@3 92
jlaskey@3 93 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
jlaskey@3 94 public static Object buffer(final Object self) {
attila@963 95 return ((ArrayBufferView)self).buffer;
jlaskey@3 96 }
jlaskey@3 97
jlaskey@3 98 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
attila@963 99 public static int byteOffset(final Object self) {
attila@963 100 return ((ArrayBufferView)self).byteOffset;
jlaskey@3 101 }
jlaskey@3 102
jlaskey@3 103 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
attila@963 104 public static int byteLength(final Object self) {
jlaskey@3 105 final ArrayBufferView view = (ArrayBufferView)self;
attila@963 106 return ((TypedArrayData<?>)view.getArray()).getElementLength() * view.bytesPerElement();
jlaskey@3 107 }
jlaskey@3 108
jlaskey@3 109 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
attila@963 110 public static int length(final Object self) {
jlaskey@3 111 return ((ArrayBufferView)self).elementLength();
jlaskey@3 112 }
jlaskey@3 113
jlaskey@3 114 @Override
jlaskey@3 115 public final Object getLength() {
jlaskey@3 116 return elementLength();
jlaskey@3 117 }
jlaskey@3 118
jlaskey@3 119 private int elementLength() {
attila@963 120 return ((TypedArrayData<?>)getArray()).getElementLength();
jlaskey@3 121 }
jlaskey@3 122
jlaskey@3 123 protected static abstract class Factory {
jlaskey@3 124 final int bytesPerElement;
attila@446 125 final int maxElementLength;
jlaskey@3 126
jlaskey@3 127 public Factory(final int bytesPerElement) {
attila@963 128 this.bytesPerElement = bytesPerElement;
attila@446 129 this.maxElementLength = Integer.MAX_VALUE / bytesPerElement;
jlaskey@3 130 }
jlaskey@3 131
jlaskey@3 132 public final ArrayBufferView construct(final int elementLength) {
attila@963 133 if (elementLength > maxElementLength) {
attila@446 134 throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength));
attila@446 135 }
jlaskey@3 136 return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength);
jlaskey@3 137 }
jlaskey@3 138
jlaskey@3 139 public abstract ArrayBufferView construct(NativeArrayBuffer buffer, int byteOffset, int elementLength);
jlaskey@3 140
attila@963 141 public abstract TypedArrayData<?> createArrayData(ByteBuffer nb, int start, int end);
attila@963 142
attila@963 143 public abstract String getClassName();
jlaskey@3 144 }
jlaskey@3 145
jlaskey@3 146 protected abstract Factory factory();
jlaskey@3 147
sundar@414 148 protected abstract ScriptObject getPrototype(final Global global);
jlaskey@3 149
attila@963 150 @Override
attila@963 151 public final String getClassName() {
attila@963 152 return factory().getClassName();
attila@963 153 }
attila@963 154
jlaskey@3 155 protected boolean isFloatArray() {
jlaskey@3 156 return false;
jlaskey@3 157 }
jlaskey@3 158
attila@963 159 protected static ArrayBufferView constructorImpl(final boolean newObj, final Object[] args, final Factory factory) {
attila@963 160 final Object arg0 = args.length != 0 ? args[0] : 0;
attila@963 161 final ArrayBufferView dest;
attila@963 162 final int length;
attila@963 163
attila@963 164 if (!newObj) {
attila@963 165 throw typeError("constructor.requires.new", factory.getClassName());
attila@963 166 }
attila@963 167
attila@963 168
jlaskey@3 169 if (arg0 instanceof NativeArrayBuffer) {
jlaskey@3 170 // Constructor(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length)
attila@963 171 final NativeArrayBuffer buffer = (NativeArrayBuffer)arg0;
attila@963 172 final int byteOffset = args.length > 1 ? JSType.toInt32(args[1]) : 0;
attila@963 173
jlaskey@3 174 if (args.length > 2) {
jlaskey@3 175 length = JSType.toInt32(args[2]);
jlaskey@3 176 } else {
jlaskey@3 177 if ((buffer.getByteLength() - byteOffset) % factory.bytesPerElement != 0) {
jlaskey@3 178 throw new RuntimeException("buffer.byteLength - byteOffset must be a multiple of the element size");
jlaskey@3 179 }
jlaskey@3 180 length = (buffer.getByteLength() - byteOffset) / factory.bytesPerElement;
jlaskey@3 181 }
attila@963 182
jlaskey@3 183 return factory.construct(buffer, byteOffset, length);
jlaskey@3 184 } else if (arg0 instanceof ArrayBufferView) {
jlaskey@3 185 // Constructor(TypedArray array)
jlaskey@3 186 length = ((ArrayBufferView)arg0).elementLength();
attila@963 187 dest = factory.construct(length);
jlaskey@3 188 } else if (arg0 instanceof NativeArray) {
jlaskey@3 189 // Constructor(type[] array)
hannesw@334 190 length = lengthToInt(((NativeArray) arg0).getArray().length());
attila@963 191 dest = factory.construct(length);
jlaskey@3 192 } else {
attila@963 193 // Constructor(unsigned long length). Treating infinity as 0 is a special case for ArrayBufferView.
attila@963 194 final double dlen = JSType.toNumber(arg0);
attila@963 195 length = lengthToInt(Double.isInfinite(dlen) ? 0L : JSType.toLong(dlen));
jlaskey@3 196 return factory.construct(length);
jlaskey@3 197 }
jlaskey@3 198
attila@963 199 copyElements(dest, length, (ScriptObject)arg0, 0);
attila@963 200
attila@963 201 return dest;
jlaskey@3 202 }
jlaskey@3 203
jlaskey@3 204 protected static Object setImpl(final Object self, final Object array, final Object offset0) {
attila@963 205 final ArrayBufferView dest = (ArrayBufferView)self;
jlaskey@3 206 final int length;
jlaskey@3 207 if (array instanceof ArrayBufferView) {
jlaskey@3 208 // void set(TypedArray array, optional unsigned long offset)
jlaskey@3 209 length = ((ArrayBufferView)array).elementLength();
jlaskey@3 210 } else if (array instanceof NativeArray) {
jlaskey@3 211 // void set(type[] array, optional unsigned long offset)
jlaskey@3 212 length = (int) (((NativeArray) array).getArray().length() & 0x7fff_ffff);
jlaskey@3 213 } else {
jlaskey@3 214 throw new RuntimeException("argument is not of array type");
jlaskey@3 215 }
jlaskey@3 216
attila@963 217 final ScriptObject source = (ScriptObject)array;
jlaskey@3 218 final int offset = JSType.toInt32(offset0); // default=0
jlaskey@3 219
jlaskey@3 220 if (dest.elementLength() < length + offset || offset < 0) {
jlaskey@3 221 throw new RuntimeException("offset or array length out of bounds");
jlaskey@3 222 }
jlaskey@3 223
jlaskey@3 224 copyElements(dest, length, source, offset);
jlaskey@3 225
jlaskey@3 226 return ScriptRuntime.UNDEFINED;
jlaskey@3 227 }
jlaskey@3 228
jlaskey@3 229 private static void copyElements(final ArrayBufferView dest, final int length, final ScriptObject source, final int offset) {
jlaskey@3 230 if (!dest.isFloatArray()) {
jlaskey@3 231 for (int i = 0, j = offset; i < length; i++, j++) {
hannesw@1020 232 dest.set(j, source.getInt(i, INVALID_PROGRAM_POINT), 0);
jlaskey@3 233 }
jlaskey@3 234 } else {
jlaskey@3 235 for (int i = 0, j = offset; i < length; i++, j++) {
hannesw@1020 236 dest.set(j, source.getDouble(i, INVALID_PROGRAM_POINT), 0);
jlaskey@3 237 }
jlaskey@3 238 }
jlaskey@3 239 }
jlaskey@3 240
hannesw@334 241 private static int lengthToInt(final long length) {
hannesw@334 242 if (length > Integer.MAX_VALUE || length < 0) {
hannesw@334 243 throw rangeError("inappropriate.array.buffer.length", JSType.toString(length));
hannesw@334 244 }
attila@963 245 return (int)(length & Integer.MAX_VALUE);
hannesw@334 246 }
hannesw@334 247
sundar@774 248 protected static ScriptObject subarrayImpl(final Object self, final Object begin0, final Object end0) {
attila@963 249 final ArrayBufferView arrayView = (ArrayBufferView)self;
attila@963 250 final int byteOffset = arrayView.byteOffset;
attila@963 251 final int bytesPerElement = arrayView.bytesPerElement();
attila@963 252 final int elementLength = arrayView.elementLength();
attila@963 253 final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength);
attila@963 254 final int end = NativeArrayBuffer.adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : elementLength, elementLength);
attila@963 255 final int length = Math.max(end - begin, 0);
attila@963 256
attila@963 257 assert byteOffset % bytesPerElement == 0;
attila@963 258
attila@963 259 //second is byteoffset
attila@963 260 return arrayView.factory().construct(arrayView.buffer, begin * bytesPerElement + byteOffset, length);
attila@963 261 }
attila@963 262
attila@963 263 @Override
attila@963 264 protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
attila@963 265 final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request);
attila@963 266 if (inv != null) {
attila@963 267 return inv;
attila@963 268 }
attila@963 269 return super.findGetIndexMethod(desc, request);
attila@963 270 }
attila@963 271
attila@963 272 @Override
attila@963 273 protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
attila@963 274 final GuardedInvocation inv = getArray().findFastSetIndexMethod(getArray().getClass(), desc, request);
attila@963 275 if (inv != null) {
attila@963 276 return inv;
attila@963 277 }
attila@963 278 return super.findSetIndexMethod(desc, request);
jlaskey@3 279 }
jlaskey@3 280 }

mercurial