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 26 package jdk.nashorn.internal.objects; 27 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 29 30 import java.nio.ByteBuffer; 31 32 import jdk.nashorn.internal.objects.annotations.Attribute; 33 import jdk.nashorn.internal.objects.annotations.Constructor; 34 import jdk.nashorn.internal.objects.annotations.Function; 35 import jdk.nashorn.internal.objects.annotations.Getter; 36 import jdk.nashorn.internal.objects.annotations.ScriptClass; 37 import jdk.nashorn.internal.objects.annotations.SpecializedFunction; 38 import jdk.nashorn.internal.objects.annotations.Where; 39 import jdk.nashorn.internal.runtime.JSType; 40 import jdk.nashorn.internal.runtime.PropertyMap; 41 import jdk.nashorn.internal.runtime.ScriptObject; 42 import jdk.nashorn.internal.runtime.ScriptRuntime; 43 44 /** 45 * NativeArrayBuffer - ArrayBuffer as described in the JS typed 46 * array spec 47 */ 48 @ScriptClass("ArrayBuffer") 49 public final class NativeArrayBuffer extends ScriptObject { 50 private final ByteBuffer nb; 51 52 // initialized by nasgen 53 private static PropertyMap $nasgenmap$; 54 55 /** 56 * Constructor 57 * @param nb native byte buffer to wrap 58 * @param global global instance 59 */ 60 protected NativeArrayBuffer(final ByteBuffer nb, final Global global) { 61 super(global.getArrayBufferPrototype(), $nasgenmap$); 62 this.nb = nb; 63 } 64 65 /** 66 * Constructor 67 * @param nb native byte buffer to wrap 68 */ 69 protected NativeArrayBuffer(final ByteBuffer nb) { 70 this(nb, Global.instance()); 71 } 72 73 /** 74 * Constructor 75 * @param byteLength byteLength for buffer 76 */ 77 protected NativeArrayBuffer(final int byteLength) { 78 this(ByteBuffer.allocateDirect(byteLength)); 79 } 80 81 /** 82 * Clone constructor 83 * Used only for slice 84 * @param other original buffer 85 * @param begin begin byte index 86 * @param end end byte index 87 */ 88 protected NativeArrayBuffer(final NativeArrayBuffer other, final int begin, final int end) { 89 this(cloneBuffer(other.getNioBuffer(), begin, end)); 90 } 91 92 /** 93 * Constructor 94 * @param newObj is this invoked with new 95 * @param self self reference 96 * @param args arguments to constructor 97 * @return new NativeArrayBuffer 98 */ 99 @Constructor(arity = 1) 100 public static NativeArrayBuffer constructor(final boolean newObj, final Object self, final Object... args) { 101 if (!newObj) { 102 throw typeError("constructor.requires.new", "ArrayBuffer"); 103 } 104 105 if (args.length == 0) { 106 //For ES6 rev28+ we should throw a TypeError here. None of the other runtimes 107 //currently do it, though, so I have chosen to not implement that for now. 108 return new NativeArrayBuffer(0); 109 } 110 111 return new NativeArrayBuffer(JSType.toInt32(args[0])); 112 } 113 114 private static ByteBuffer cloneBuffer(final ByteBuffer original, final int begin, final int end) { 115 final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity()); 116 original.rewind();//copy from the beginning 117 clone.put(original); 118 original.rewind(); 119 clone.flip(); 120 clone.position(begin); 121 clone.limit(end); 122 return clone.slice(); 123 } 124 125 ByteBuffer getNioBuffer() { 126 return nb; 127 } 128 129 @Override 130 public String getClassName() { 131 return "ArrayBuffer"; 132 } 133 134 /** 135 * Byte length for native array buffer 136 * @param self native array buffer 137 * @return byte length 138 */ 139 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) 140 public static int byteLength(final Object self) { 141 return ((NativeArrayBuffer)self).getByteLength(); 142 } 143 144 /** 145 * Returns true if an object is an ArrayBufferView 146 * 147 * @param self self 148 * @param obj object to check 149 * 150 * @return true if obj is an ArrayBufferView 151 */ 152 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 153 public static boolean isView(final Object self, final Object obj) { 154 return obj instanceof ArrayBufferView; 155 } 156 157 /** 158 * Slice function 159 * @param self native array buffer 160 * @param begin0 start byte index 161 * @param end0 end byte index 162 * @return new array buffer, sliced 163 */ 164 @Function(attributes = Attribute.NOT_ENUMERABLE) 165 public static NativeArrayBuffer slice(final Object self, final Object begin0, final Object end0) { 166 final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self; 167 final int byteLength = arrayBuffer.getByteLength(); 168 final int begin = adjustIndex(JSType.toInt32(begin0), byteLength); 169 final int end = adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : byteLength, byteLength); 170 return new NativeArrayBuffer(arrayBuffer, begin, Math.max(end, begin)); 171 } 172 173 /** 174 * Specialized slice function 175 * @param self native array buffer 176 * @param begin start byte index 177 * @param end end byte index 178 * @return new array buffer, sliced 179 */ 180 @SpecializedFunction 181 public static Object slice(final Object self, final int begin, final int end) { 182 final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self; 183 final int byteLength = arrayBuffer.getByteLength(); 184 return new NativeArrayBuffer(arrayBuffer, adjustIndex(begin, byteLength), Math.max(adjustIndex(end, byteLength), begin)); 185 } 186 187 /** 188 * Specialized slice function 189 * @param self native array buffer 190 * @param begin start byte index 191 * @return new array buffer, sliced 192 */ 193 @SpecializedFunction 194 public static Object slice(final Object self, final int begin) { 195 return slice(self, begin, ((NativeArrayBuffer)self).getByteLength()); 196 } 197 198 /** 199 * If index is negative, it refers to an index from the end of the array, as 200 * opposed to from the beginning. The index is clamped to the valid index 201 * range for the array. 202 * 203 * @param index The index. 204 * @param length The length of the array. 205 * @return valid index index in the range [0, length). 206 */ 207 static int adjustIndex(final int index, final int length) { 208 return index < 0 ? clamp(index + length, length) : clamp(index, length); 209 } 210 211 /** 212 * Clamp index into the range [0, length). 213 */ 214 private static int clamp(final int index, final int length) { 215 if (index < 0) { 216 return 0; 217 } else if (index > length) { 218 return length; 219 } 220 return index; 221 } 222 223 int getByteLength() { 224 return nb.limit(); 225 } 226 227 ByteBuffer getBuffer() { 228 return nb; 229 } 230 231 ByteBuffer getBuffer(final int offset) { 232 return (ByteBuffer)nb.duplicate().position(offset); 233 } 234 235 ByteBuffer getBuffer(final int offset, final int length) { 236 return (ByteBuffer)getBuffer(offset).limit(length); 237 } 238 }