NativeArrayBuffer.java revision 1269:71a4e37769f8
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; 31 32import jdk.nashorn.internal.objects.annotations.Attribute; 33import jdk.nashorn.internal.objects.annotations.Constructor; 34import jdk.nashorn.internal.objects.annotations.Function; 35import jdk.nashorn.internal.objects.annotations.Getter; 36import jdk.nashorn.internal.objects.annotations.ScriptClass; 37import jdk.nashorn.internal.objects.annotations.SpecializedFunction; 38import jdk.nashorn.internal.objects.annotations.Where; 39import jdk.nashorn.internal.runtime.JSType; 40import jdk.nashorn.internal.runtime.PropertyMap; 41import jdk.nashorn.internal.runtime.ScriptObject; 42import jdk.nashorn.internal.runtime.ScriptRuntime; 43 44/** 45 * NativeArrayBuffer - ArrayBuffer as described in the JS typed 46 * array spec 47 */ 48@ScriptClass("ArrayBuffer") 49public 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 return new NativeArrayBuffer(0); 107 } 108 109 return new NativeArrayBuffer(JSType.toInt32(args[0])); 110 } 111 112 private static ByteBuffer cloneBuffer(final ByteBuffer original, final int begin, final int end) { 113 final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity()); 114 original.rewind();//copy from the beginning 115 clone.put(original); 116 original.rewind(); 117 clone.flip(); 118 clone.position(begin); 119 clone.limit(end); 120 return clone.slice(); 121 } 122 123 ByteBuffer getNioBuffer() { 124 return nb; 125 } 126 127 @Override 128 public String getClassName() { 129 return "ArrayBuffer"; 130 } 131 132 /** 133 * Byte length for native array buffer 134 * @param self native array buffer 135 * @return byte length 136 */ 137 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE) 138 public static int byteLength(final Object self) { 139 return ((NativeArrayBuffer)self).getByteLength(); 140 } 141 142 /** 143 * Returns true if an object is an ArrayBufferView 144 * 145 * @param self self 146 * @param obj object to check 147 * 148 * @return true if obj is an ArrayBufferView 149 */ 150 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 151 public static boolean isView(final Object self, final Object obj) { 152 return obj instanceof ArrayBufferView; 153 } 154 155 /** 156 * Slice function 157 * @param self native array buffer 158 * @param begin0 start byte index 159 * @param end0 end byte index 160 * @return new array buffer, sliced 161 */ 162 @Function(attributes = Attribute.NOT_ENUMERABLE) 163 public static NativeArrayBuffer slice(final Object self, final Object begin0, final Object end0) { 164 final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self; 165 final int byteLength = arrayBuffer.getByteLength(); 166 final int begin = adjustIndex(JSType.toInt32(begin0), byteLength); 167 final int end = adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : byteLength, byteLength); 168 return new NativeArrayBuffer(arrayBuffer, begin, Math.max(end, begin)); 169 } 170 171 /** 172 * Specialized slice function 173 * @param self native array buffer 174 * @param begin start byte index 175 * @param end end byte index 176 * @return new array buffer, sliced 177 */ 178 @SpecializedFunction 179 public static Object slice(final Object self, final int begin, final int end) { 180 final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self; 181 final int byteLength = arrayBuffer.getByteLength(); 182 return new NativeArrayBuffer(arrayBuffer, adjustIndex(begin, byteLength), Math.max(adjustIndex(end, byteLength), begin)); 183 } 184 185 /** 186 * Specialized slice function 187 * @param self native array buffer 188 * @param begin start byte index 189 * @return new array buffer, sliced 190 */ 191 @SpecializedFunction 192 public static Object slice(final Object self, final int begin) { 193 return slice(self, begin, ((NativeArrayBuffer)self).getByteLength()); 194 } 195 196 /** 197 * If index is negative, it refers to an index from the end of the array, as 198 * opposed to from the beginning. The index is clamped to the valid index 199 * range for the array. 200 * 201 * @param index The index. 202 * @param length The length of the array. 203 * @return valid index index in the range [0, length). 204 */ 205 static int adjustIndex(final int index, final int length) { 206 return index < 0 ? clamp(index + length, length) : clamp(index, length); 207 } 208 209 /** 210 * Clamp index into the range [0, length). 211 */ 212 private static int clamp(final int index, final int length) { 213 if (index < 0) { 214 return 0; 215 } else if (index > length) { 216 return length; 217 } 218 return index; 219 } 220 221 int getByteLength() { 222 return nb.limit(); 223 } 224 225 ByteBuffer getBuffer() { 226 return nb; 227 } 228 229 ByteBuffer getBuffer(final int offset) { 230 return (ByteBuffer)nb.duplicate().position(offset); 231 } 232 233 ByteBuffer getBuffer(final int offset, final int length) { 234 return (ByteBuffer)getBuffer(offset).limit(length); 235 } 236} 237