NativeArrayBuffer.java revision 1090:4df3417e1a6e
1169689Skan/*
2169689Skan * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3169689Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169689Skan *
5169689Skan * This code is free software; you can redistribute it and/or modify it
6169689Skan * under the terms of the GNU General Public License version 2 only, as
7169689Skan * published by the Free Software Foundation.  Oracle designates this
8169689Skan * particular file as subject to the "Classpath" exception as provided
9169689Skan * by Oracle in the LICENSE file that accompanied this code.
10169689Skan *
11169689Skan * This code is distributed in the hope that it will be useful, but WITHOUT
12169689Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13169689Skan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14169689Skan * version 2 for more details (a copy is included in the LICENSE file that
15169689Skan * accompanied this code).
16169689Skan *
17169689Skan * You should have received a copy of the GNU General Public License version
18169689Skan * 2 along with this work; if not, write to the Free Software Foundation,
19169689Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20169689Skan *
21169689Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22169689Skan * or visit www.oracle.com if you need additional information or have any
23169689Skan * questions.
24169689Skan */
25169689Skan
26169689Skanpackage jdk.nashorn.internal.objects;
27169689Skan
28169689Skanimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
29169689Skanimport java.nio.ByteBuffer;
30169689Skanimport jdk.nashorn.internal.objects.annotations.Attribute;
31169689Skanimport jdk.nashorn.internal.objects.annotations.Constructor;
32169689Skanimport jdk.nashorn.internal.objects.annotations.Function;
33169689Skanimport jdk.nashorn.internal.objects.annotations.Getter;
34169689Skanimport jdk.nashorn.internal.objects.annotations.ScriptClass;
35169689Skanimport jdk.nashorn.internal.objects.annotations.SpecializedFunction;
36169689Skanimport jdk.nashorn.internal.objects.annotations.Where;
37169689Skanimport jdk.nashorn.internal.runtime.JSType;
38169689Skanimport jdk.nashorn.internal.runtime.PropertyMap;
39169689Skanimport jdk.nashorn.internal.runtime.ScriptObject;
40169689Skanimport jdk.nashorn.internal.runtime.ScriptRuntime;
41169689Skan
42169689Skan/**
43169689Skan * NativeArrayBuffer - ArrayBuffer as described in the JS typed
44169689Skan * array spec
45169689Skan */
46169689Skan@ScriptClass("ArrayBuffer")
47169689Skanpublic final class NativeArrayBuffer extends ScriptObject {
48169689Skan    private final ByteBuffer nb;
49169689Skan
50169689Skan    // initialized by nasgen
51169689Skan    private static PropertyMap $nasgenmap$;
52169689Skan
53169689Skan    /**
54169689Skan     * Constructor
55169689Skan     * @param nb native byte buffer to wrap
56169689Skan     * @param global global instance
57169689Skan     */
58169689Skan    protected NativeArrayBuffer(final ByteBuffer nb, final Global global) {
59169689Skan        super(global.getArrayBufferPrototype(), $nasgenmap$);
60169689Skan        this.nb = nb;
61169689Skan    }
62169689Skan
63169689Skan    /**
64169689Skan     * Constructor
65169689Skan     * @param nb native byte buffer to wrap
66169689Skan     */
67169689Skan    protected NativeArrayBuffer(final ByteBuffer nb) {
68169689Skan        this(nb, Global.instance());
69169689Skan    }
70169689Skan
71169689Skan    /**
72169689Skan     * Constructor
73169689Skan     * @param byteLength byteLength for buffer
74169689Skan     */
75169689Skan    protected NativeArrayBuffer(final int byteLength) {
76169689Skan        this(ByteBuffer.allocateDirect(byteLength));
77169689Skan    }
78169689Skan
79169689Skan    /**
80169689Skan     * Clone constructor
81169689Skan     * Used only for slice
82169689Skan     * @param other original buffer
83169689Skan     * @param begin begin byte index
84169689Skan     * @param end   end byte index
85169689Skan     */
86169689Skan    protected NativeArrayBuffer(final NativeArrayBuffer other, final int begin, final int end) {
87169689Skan        this(cloneBuffer(other.getNioBuffer(), begin, end));
88169689Skan    }
89169689Skan
90169689Skan    /**
91169689Skan     * Constructor
92169689Skan     * @param newObj is this invoked with new
93169689Skan     * @param self   self reference
94169689Skan     * @param args   arguments to constructor
95169689Skan     * @return new NativeArrayBuffer
96169689Skan     */
97169689Skan    @Constructor(arity = 1)
98169689Skan    public static NativeArrayBuffer constructor(final boolean newObj, final Object self, final Object... args) {
99169689Skan        if (!newObj) {
100169689Skan            throw typeError("constructor.requires.new", "ArrayBuffer");
101169689Skan        }
102169689Skan
103169689Skan        if (args.length == 0) {
104169689Skan            throw new RuntimeException("missing length argument");
105169689Skan        }
106169689Skan
107169689Skan        return new NativeArrayBuffer(JSType.toInt32(args[0]));
108169689Skan    }
109169689Skan
110169689Skan    private static ByteBuffer cloneBuffer(final ByteBuffer original, final int begin, final int end) {
111169689Skan        final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity());
112169689Skan        original.rewind();//copy from the beginning
113169689Skan        clone.put(original);
114169689Skan        original.rewind();
115169689Skan        clone.flip();
116169689Skan        clone.position(begin);
117169689Skan        clone.limit(end);
118169689Skan        return clone.slice();
119169689Skan    }
120169689Skan
121169689Skan    ByteBuffer getNioBuffer() {
122169689Skan        return nb;
123169689Skan    }
124169689Skan
125169689Skan    @Override
126169689Skan    public String getClassName() {
127169689Skan        return "ArrayBuffer";
128169689Skan    }
129169689Skan
130169689Skan    /**
131169689Skan     * Byte length for native array buffer
132169689Skan     * @param self native array buffer
133169689Skan     * @return byte length
134169689Skan     */
135169689Skan    @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
136169689Skan    public static int byteLength(final Object self) {
137169689Skan        return ((NativeArrayBuffer)self).getByteLength();
138169689Skan    }
139169689Skan
140169689Skan    /**
141169689Skan     * Returns true if an object is an ArrayBufferView
142169689Skan     *
143169689Skan     * @param self self
144169689Skan     * @param obj  object to check
145169689Skan     *
146169689Skan     * @return true if obj is an ArrayBufferView
147169689Skan     */
148169689Skan    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
149169689Skan    public static boolean isView(final Object self, final Object obj) {
150169689Skan        return obj instanceof ArrayBufferView;
151169689Skan    }
152169689Skan
153169689Skan    /**
154169689Skan     * Slice function
155169689Skan     * @param self   native array buffer
156169689Skan     * @param begin0 start byte index
157169689Skan     * @param end0   end byte index
158169689Skan     * @return new array buffer, sliced
159169689Skan     */
160169689Skan    @Function(attributes = Attribute.NOT_ENUMERABLE)
161169689Skan    public static NativeArrayBuffer slice(final Object self, final Object begin0, final Object end0) {
162169689Skan        final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self;
163169689Skan        final int               byteLength  = arrayBuffer.getByteLength();
164169689Skan        final int               begin       = adjustIndex(JSType.toInt32(begin0), byteLength);
165169689Skan        final int               end         = adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : byteLength, byteLength);
166169689Skan        return new NativeArrayBuffer(arrayBuffer, begin, Math.max(end, begin));
167169689Skan    }
168169689Skan
169169689Skan    /**
170169689Skan     * Specialized slice function
171169689Skan     * @param self   native array buffer
172169689Skan     * @param begin  start byte index
173169689Skan     * @param end    end byte index
174169689Skan     * @return new array buffer, sliced
175169689Skan     */
176169689Skan    @SpecializedFunction
177169689Skan    public static Object slice(final Object self, final int begin, final int end) {
178169689Skan        final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self;
179169689Skan        final int byteLength  = arrayBuffer.getByteLength();
180169689Skan        return new NativeArrayBuffer(arrayBuffer, adjustIndex(begin, byteLength), Math.max(adjustIndex(end, byteLength), begin));
181169689Skan    }
182169689Skan
183169689Skan    /**
184169689Skan     * Specialized slice function
185169689Skan     * @param self   native array buffer
186169689Skan     * @param begin  start byte index
187169689Skan     * @return new array buffer, sliced
188169689Skan     */
189169689Skan    @SpecializedFunction
190169689Skan    public static Object slice(final Object self, final int begin) {
191169689Skan        return slice(self, begin, ((NativeArrayBuffer)self).getByteLength());
192169689Skan    }
193169689Skan
194169689Skan    /**
195169689Skan     * If index is negative, it refers to an index from the end of the array, as
196169689Skan     * opposed to from the beginning. The index is clamped to the valid index
197169689Skan     * range for the array.
198169689Skan     *
199169689Skan     * @param index  The index.
200169689Skan     * @param length The length of the array.
201169689Skan     * @return valid index index in the range [0, length).
202169689Skan     */
203169689Skan    static int adjustIndex(final int index, final int length) {
204169689Skan        return index < 0 ? clamp(index + length, length) : clamp(index, length);
205169689Skan    }
206169689Skan
207169689Skan    /**
208169689Skan     * Clamp index into the range [0, length).
209169689Skan     */
210169689Skan    private static int clamp(final int index, final int length) {
211169689Skan        if (index < 0) {
212169689Skan            return 0;
213169689Skan        } else if (index > length) {
214169689Skan            return length;
215169689Skan        }
216169689Skan        return index;
217169689Skan    }
218169689Skan
219169689Skan    int getByteLength() {
220169689Skan        return nb.limit();
221169689Skan    }
222169689Skan
223169689Skan    ByteBuffer getBuffer() {
224169689Skan       return nb;
225169689Skan    }
226169689Skan
227169689Skan    ByteBuffer getBuffer(final int offset) {
228169689Skan        return (ByteBuffer)nb.duplicate().position(offset);
229169689Skan    }
230169689Skan
231169689Skan    ByteBuffer getBuffer(final int offset, final int length) {
232169689Skan        return (ByteBuffer)getBuffer(offset).limit(length);
233169689Skan    }
234169689Skan}
235169689Skan