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