NativeDataView.java revision 1354:a5e202d6eb99
1/*
2 * Copyright (c) 2014, 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.rangeError;
29import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
31
32import java.nio.ByteBuffer;
33import java.nio.ByteOrder;
34import jdk.nashorn.internal.objects.annotations.Attribute;
35import jdk.nashorn.internal.objects.annotations.Constructor;
36import jdk.nashorn.internal.objects.annotations.Function;
37import jdk.nashorn.internal.objects.annotations.Property;
38import jdk.nashorn.internal.objects.annotations.ScriptClass;
39import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
40import jdk.nashorn.internal.runtime.JSType;
41import jdk.nashorn.internal.runtime.PropertyMap;
42import jdk.nashorn.internal.runtime.ScriptObject;
43import jdk.nashorn.internal.runtime.ScriptRuntime;
44
45/**
46 * <p>
47 * DataView builtin constructor. Based on the specification here:
48 * http://www.khronos.org/registry/typedarray/specs/latest/#8
49 * </p>
50 * <p>
51 * An ArrayBuffer is a useful object for representing an arbitrary chunk of data.
52 * In many cases, such data will be read from disk or from the network, and will
53 * not follow the alignment restrictions that are imposed on the typed array views
54 * described earlier. In addition, the data will often be heterogeneous in nature
55 * and have a defined byte order. The DataView view provides a low-level interface
56 * for reading such data from and writing it to an ArrayBuffer.
57 * </p>
58 * <p>
59 * Regardless of the host computer's endianness, DataView reads or writes values
60 * to or from main memory with a specified endianness: big or little.
61 * </p>
62 */
63@ScriptClass("DataView")
64public class NativeDataView extends ScriptObject {
65    // initialized by nasgen
66    private static PropertyMap $nasgenmap$;
67
68    // inherited ArrayBufferView properties
69
70    /**
71     * Underlying ArrayBuffer storage object
72     */
73    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
74    public final Object buffer;
75
76    /**
77     * The offset in bytes from the start of the ArrayBuffer
78     */
79    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
80    public final int byteOffset;
81
82    /**
83     * The number of bytes from the offset that this DataView will reference
84     */
85    @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
86    public final int byteLength;
87
88    // underlying ByteBuffer
89    private final ByteBuffer buf;
90
91    private NativeDataView(final NativeArrayBuffer arrBuf) {
92        this(arrBuf, arrBuf.getBuffer(), 0);
93    }
94
95    private NativeDataView(final NativeArrayBuffer arrBuf, final int offset) {
96        this(arrBuf, bufferFrom(arrBuf, offset), offset);
97    }
98
99    private NativeDataView(final NativeArrayBuffer arrBuf, final int offset, final int length) {
100        this(arrBuf, bufferFrom(arrBuf, offset, length), offset, length);
101    }
102
103    private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset) {
104       this(arrBuf, buf, offset, buf.capacity() - offset);
105    }
106
107    private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) {
108        super(Global.instance().getDataViewPrototype(), $nasgenmap$);
109        this.buffer     = arrBuf;
110        this.byteOffset = offset;
111        this.byteLength = length;
112        this.buf        = buf;
113    }
114
115    /**
116     * Create a new DataView object using the passed ArrayBuffer for its
117     * storage. Optional byteOffset and byteLength can be used to limit the
118     * section of the buffer referenced. The byteOffset indicates the offset in
119     * bytes from the start of the ArrayBuffer, and the byteLength is the number
120     * of bytes from the offset that this DataView will reference. If both
121     * byteOffset and byteLength are omitted, the DataView spans the entire
122     * ArrayBuffer range. If the byteLength is omitted, the DataView extends from
123     * the given byteOffset until the end of the ArrayBuffer.
124     *
125     * If the given byteOffset and byteLength references an area beyond the end
126     * of the ArrayBuffer an exception is raised.
127
128     * @param newObj if this constructor was invoked with 'new' or not
129     * @param self   constructor function object
130     * @param args   arguments to the constructor
131     * @return newly constructed DataView object
132     */
133    @Constructor(arity = 1)
134    public static NativeDataView constructor(final boolean newObj, final Object self, final Object... args) {
135        if (args.length == 0 || !(args[0] instanceof NativeArrayBuffer)) {
136            throw typeError("not.an.arraybuffer.in.dataview");
137        }
138
139        final NativeArrayBuffer arrBuf = (NativeArrayBuffer)args[0];
140        switch (args.length) {
141        case 1:
142            return new NativeDataView(arrBuf);
143        case 2:
144            return new NativeDataView(arrBuf, JSType.toInt32(args[1]));
145        default:
146            return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2]));
147        }
148    }
149
150    /**
151     * Specialized version of DataView constructor
152     *
153     * @param newObj if this constructor was invoked with 'new' or not
154     * @param self   constructor function object
155     * @param arrBuf underlying ArrayBuffer storage object
156     * @param offset offset in bytes from the start of the ArrayBuffer
157     * @return newly constructed DataView object
158     */
159    @SpecializedFunction(isConstructor=true)
160    public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) {
161        if (!(arrBuf instanceof NativeArrayBuffer)) {
162            throw typeError("not.an.arraybuffer.in.dataview");
163        }
164        return new NativeDataView((NativeArrayBuffer) arrBuf, offset);
165    }
166
167    /**
168     * Specialized version of DataView constructor
169     *
170     * @param newObj if this constructor was invoked with 'new' or not
171     * @param self   constructor function object
172     * @param arrBuf underlying ArrayBuffer storage object
173     * @param offset in bytes from the start of the ArrayBuffer
174     * @param length is the number of bytes from the offset that this DataView will reference
175     * @return newly constructed DataView object
176     */
177    @SpecializedFunction(isConstructor=true)
178    public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) {
179        if (!(arrBuf instanceof NativeArrayBuffer)) {
180            throw typeError("not.an.arraybuffer.in.dataview");
181        }
182        return new NativeDataView((NativeArrayBuffer) arrBuf, offset, length);
183    }
184
185    // Gets the value of the given type at the specified byte offset
186    // from the start of the view. There is no alignment constraint;
187    // multi-byte values may be fetched from any offset.
188    //
189    // For multi-byte values, the optional littleEndian argument
190    // indicates whether a big-endian or little-endian value should be
191    // read. If false or undefined, a big-endian value is read.
192    //
193    // These methods raise an exception if they would read
194    // beyond the end of the view.
195
196    /**
197     * Get 8-bit signed int from given byteOffset
198     *
199     * @param self DataView object
200     * @param byteOffset byte offset to read from
201     * @return 8-bit signed int value at the byteOffset
202     */
203    @Function(attributes = Attribute.NOT_ENUMERABLE)
204    public static int getInt8(final Object self, final Object byteOffset) {
205        try {
206            return getBuffer(self).get(JSType.toInt32(byteOffset));
207        } catch (final IllegalArgumentException iae) {
208            throw rangeError(iae, "dataview.offset");
209        }
210    }
211
212    /**
213     * Get 8-bit signed int from given byteOffset
214     *
215     * @param self DataView object
216     * @param byteOffset byte offset to read from
217     * @return 8-bit signed int value at the byteOffset
218     */
219    @SpecializedFunction
220    public static int getInt8(final Object self, final int byteOffset) {
221        try {
222            return getBuffer(self).get(byteOffset);
223        } catch (final IllegalArgumentException iae) {
224            throw rangeError(iae, "dataview.offset");
225        }
226    }
227
228    /**
229     * Get 8-bit unsigned int from given byteOffset
230     *
231     * @param self DataView object
232     * @param byteOffset byte offset to read from
233     * @return 8-bit unsigned int value at the byteOffset
234     */
235    @Function(attributes = Attribute.NOT_ENUMERABLE)
236    public static int getUint8(final Object self, final Object byteOffset) {
237        try {
238            return 0xFF & getBuffer(self).get(JSType.toInt32(byteOffset));
239        } catch (final IllegalArgumentException iae) {
240            throw rangeError(iae, "dataview.offset");
241        }
242    }
243
244    /**
245     * Get 8-bit unsigned int from given byteOffset
246     *
247     * @param self DataView object
248     * @param byteOffset byte offset to read from
249     * @return 8-bit unsigned int value at the byteOffset
250     */
251    @SpecializedFunction
252    public static int getUint8(final Object self, final int byteOffset) {
253        try {
254            return 0xFF & getBuffer(self).get(byteOffset);
255        } catch (final IllegalArgumentException iae) {
256            throw rangeError(iae, "dataview.offset");
257        }
258    }
259
260    /**
261     * Get 16-bit signed int from given byteOffset
262     *
263     * @param self DataView object
264     * @param byteOffset byte offset to read from
265     * @param littleEndian (optional) flag indicating whether to read in little endian order
266     * @return 16-bit signed int value at the byteOffset
267     */
268    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
269    public static int getInt16(final Object self, final Object byteOffset, final Object littleEndian) {
270        try {
271            return getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset));
272        } catch (final IllegalArgumentException iae) {
273            throw rangeError(iae, "dataview.offset");
274        }
275    }
276
277    /**
278     * Get 16-bit signed int from given byteOffset
279     *
280     * @param self DataView object
281     * @param byteOffset byte offset to read from
282     * @return 16-bit signed int value at the byteOffset
283     */
284    @SpecializedFunction
285    public static int getInt16(final Object self, final int byteOffset) {
286        try {
287            return getBuffer(self, false).getShort(byteOffset);
288        } catch (final IllegalArgumentException iae) {
289            throw rangeError(iae, "dataview.offset");
290        }
291    }
292
293    /**
294     * Get 16-bit signed int from given byteOffset
295     *
296     * @param self DataView object
297     * @param byteOffset byte offset to read from
298     * @param littleEndian (optional) flag indicating whether to read in little endian order
299     * @return 16-bit signed int value at the byteOffset
300     */
301    @SpecializedFunction
302    public static int getInt16(final Object self, final int byteOffset, final boolean littleEndian) {
303        try {
304            return getBuffer(self, littleEndian).getShort(byteOffset);
305        } catch (final IllegalArgumentException iae) {
306            throw rangeError(iae, "dataview.offset");
307        }
308    }
309
310    /**
311     * Get 16-bit unsigned int from given byteOffset
312     *
313     * @param self DataView object
314     * @param byteOffset byte offset to read from
315     * @param littleEndian (optional) flag indicating whether to read in little endian order
316     * @return 16-bit unsigned int value at the byteOffset
317     */
318    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
319    public static int getUint16(final Object self, final Object byteOffset, final Object littleEndian) {
320        try {
321            return 0xFFFF & getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset));
322        } catch (final IllegalArgumentException iae) {
323            throw rangeError(iae, "dataview.offset");
324        }
325    }
326
327    /**
328     * Get 16-bit unsigned int from given byteOffset
329     *
330     * @param self DataView object
331     * @param byteOffset byte offset to read from
332     * @return 16-bit unsigned int value at the byteOffset
333     */
334    @SpecializedFunction
335    public static int getUint16(final Object self, final int byteOffset) {
336        try {
337            return 0xFFFF & getBuffer(self, false).getShort(byteOffset);
338        } catch (final IllegalArgumentException iae) {
339            throw rangeError(iae, "dataview.offset");
340        }
341    }
342
343    /**
344     * Get 16-bit unsigned int from given byteOffset
345     *
346     * @param self DataView object
347     * @param byteOffset byte offset to read from
348     * @param littleEndian (optional) flag indicating whether to read in little endian order
349     * @return 16-bit unsigned int value at the byteOffset
350     */
351    @SpecializedFunction
352    public static int getUint16(final Object self, final int byteOffset, final boolean littleEndian) {
353        try {
354            return 0xFFFF & getBuffer(self, littleEndian).getShort(byteOffset);
355        } catch (final IllegalArgumentException iae) {
356            throw rangeError(iae, "dataview.offset");
357        }
358    }
359
360    /**
361     * Get 32-bit signed int from given byteOffset
362     *
363     * @param self DataView object
364     * @param byteOffset byte offset to read from
365     * @param littleEndian (optional) flag indicating whether to read in little endian order
366     * @return 32-bit signed int value at the byteOffset
367     */
368    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
369    public static int getInt32(final Object self, final Object byteOffset, final Object littleEndian) {
370        try {
371            return getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset));
372        } catch (final IllegalArgumentException iae) {
373            throw rangeError(iae, "dataview.offset");
374        }
375    }
376
377    /**
378     * Get 32-bit signed int from given byteOffset
379     *
380     * @param self DataView object
381     * @param byteOffset byte offset to read from
382     * @return 32-bit signed int value at the byteOffset
383     */
384    @SpecializedFunction
385    public static int getInt32(final Object self, final int byteOffset) {
386        try {
387            return getBuffer(self, false).getInt(byteOffset);
388        } catch (final IllegalArgumentException iae) {
389            throw rangeError(iae, "dataview.offset");
390        }
391    }
392
393    /**
394     * Get 32-bit signed int from given byteOffset
395     *
396     * @param self DataView object
397     * @param byteOffset byte offset to read from
398     * @param littleEndian (optional) flag indicating whether to read in little endian order
399     * @return 32-bit signed int value at the byteOffset
400     */
401    @SpecializedFunction
402    public static int getInt32(final Object self, final int byteOffset, final boolean littleEndian) {
403        try {
404            return getBuffer(self, littleEndian).getInt(byteOffset);
405        } catch (final IllegalArgumentException iae) {
406            throw rangeError(iae, "dataview.offset");
407        }
408    }
409
410    /**
411     * Get 32-bit unsigned int from given byteOffset
412     *
413     * @param self DataView object
414     * @param byteOffset byte offset to read from
415     * @param littleEndian (optional) flag indicating whether to read in little endian order
416     * @return 32-bit unsigned int value at the byteOffset
417     */
418    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
419    public static long getUint32(final Object self, final Object byteOffset, final Object littleEndian) {
420        try {
421            return 0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset));
422        } catch (final IllegalArgumentException iae) {
423            throw rangeError(iae, "dataview.offset");
424        }
425    }
426
427    /**
428     * Get 32-bit unsigned int from given byteOffset
429     *
430     * @param self DataView object
431     * @param byteOffset byte offset to read from
432     * @return 32-bit unsigned int value at the byteOffset
433     */
434    @SpecializedFunction
435    public static long getUint32(final Object self, final int byteOffset) {
436        try {
437            return JSType.toUint32(getBuffer(self, false).getInt(JSType.toInt32(byteOffset)));
438        } catch (final IllegalArgumentException iae) {
439            throw rangeError(iae, "dataview.offset");
440        }
441    }
442
443    /**
444     * Get 32-bit unsigned int from given byteOffset
445     *
446     * @param self DataView object
447     * @param byteOffset byte offset to read from
448     * @param littleEndian (optional) flag indicating whether to read in little endian order
449     * @return 32-bit unsigned int value at the byteOffset
450     */
451    @SpecializedFunction
452    public static long getUint32(final Object self, final int byteOffset, final boolean littleEndian) {
453        try {
454            return JSType.toUint32(getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)));
455        } catch (final IllegalArgumentException iae) {
456            throw rangeError(iae, "dataview.offset");
457        }
458    }
459
460    /**
461     * Get 32-bit float value from given byteOffset
462     *
463     * @param self DataView object
464     * @param byteOffset byte offset to read from
465     * @param littleEndian (optional) flag indicating whether to read in little endian order
466     * @return 32-bit float value at the byteOffset
467     */
468    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
469    public static double getFloat32(final Object self, final Object byteOffset, final Object littleEndian) {
470        try {
471            return getBuffer(self, littleEndian).getFloat(JSType.toInt32(byteOffset));
472        } catch (final IllegalArgumentException iae) {
473            throw rangeError(iae, "dataview.offset");
474        }
475    }
476
477    /**
478     * Get 32-bit float value from given byteOffset
479     *
480     * @param self DataView object
481     * @param byteOffset byte offset to read from
482     * @return 32-bit float value at the byteOffset
483     */
484    @SpecializedFunction
485    public static double getFloat32(final Object self, final int byteOffset) {
486        try {
487            return getBuffer(self, false).getFloat(byteOffset);
488        } catch (final IllegalArgumentException iae) {
489            throw rangeError(iae, "dataview.offset");
490        }
491    }
492
493    /**
494     * Get 32-bit float value from given byteOffset
495     *
496     * @param self DataView object
497     * @param byteOffset byte offset to read from
498     * @param littleEndian (optional) flag indicating whether to read in little endian order
499     * @return 32-bit float value at the byteOffset
500     */
501    @SpecializedFunction
502    public static double getFloat32(final Object self, final int byteOffset, final boolean littleEndian) {
503        try {
504            return getBuffer(self, littleEndian).getFloat(byteOffset);
505        } catch (final IllegalArgumentException iae) {
506            throw rangeError(iae, "dataview.offset");
507        }
508    }
509
510    /**
511     * Get 64-bit float value from given byteOffset
512     *
513     * @param self DataView object
514     * @param byteOffset byte offset to read from
515     * @param littleEndian (optional) flag indicating whether to read in little endian order
516     * @return 64-bit float value at the byteOffset
517     */
518    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
519    public static double getFloat64(final Object self, final Object byteOffset, final Object littleEndian) {
520        try {
521            return getBuffer(self, littleEndian).getDouble(JSType.toInt32(byteOffset));
522        } catch (final IllegalArgumentException iae) {
523            throw rangeError(iae, "dataview.offset");
524        }
525    }
526
527    /**
528     * Get 64-bit float value from given byteOffset
529     *
530     * @param self DataView object
531     * @param byteOffset byte offset to read from
532     * @return 64-bit float value at the byteOffset
533     */
534    @SpecializedFunction
535    public static double getFloat64(final Object self, final int byteOffset) {
536        try {
537            return getBuffer(self, false).getDouble(byteOffset);
538        } catch (final IllegalArgumentException iae) {
539            throw rangeError(iae, "dataview.offset");
540        }
541    }
542
543    /**
544     * Get 64-bit float value from given byteOffset
545     *
546     * @param self DataView object
547     * @param byteOffset byte offset to read from
548     * @param littleEndian (optional) flag indicating whether to read in little endian order
549     * @return 64-bit float value at the byteOffset
550     */
551    @SpecializedFunction
552    public static double getFloat64(final Object self, final int byteOffset, final boolean littleEndian) {
553        try {
554            return getBuffer(self, littleEndian).getDouble(byteOffset);
555        } catch (final IllegalArgumentException iae) {
556            throw rangeError(iae, "dataview.offset");
557        }
558    }
559
560    // Stores a value of the given type at the specified byte offset
561    // from the start of the view. There is no alignment constraint;
562    // multi-byte values may be stored at any offset.
563    //
564    // For multi-byte values, the optional littleEndian argument
565    // indicates whether the value should be stored in big-endian or
566    // little-endian byte order. If false or undefined, the value is
567    // stored in big-endian byte order.
568    //
569    // These methods raise an exception if they would write
570    // beyond the end of the view.
571
572    /**
573     * Set 8-bit signed int at the given byteOffset
574     *
575     * @param self DataView object
576     * @param byteOffset byte offset to read from
577     * @param value byte value to set
578     * @return undefined
579     */
580    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
581    public static Object setInt8(final Object self, final Object byteOffset, final Object value) {
582        try {
583            getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value));
584            return UNDEFINED;
585        } catch (final IllegalArgumentException iae) {
586            throw rangeError(iae, "dataview.offset");
587        }
588    }
589
590    /**
591     * Set 8-bit signed int at the given byteOffset
592     *
593     * @param self DataView object
594     * @param byteOffset byte offset to read from
595     * @param value byte value to set
596     * @return undefined
597     */
598    @SpecializedFunction
599    public static Object setInt8(final Object self, final int byteOffset, final int value) {
600        try {
601            getBuffer(self).put(byteOffset, (byte)value);
602            return UNDEFINED;
603        } catch (final IllegalArgumentException iae) {
604            throw rangeError(iae, "dataview.offset");
605        }
606    }
607
608    /**
609     * Set 8-bit unsigned int at the given byteOffset
610     *
611     * @param self DataView object
612     * @param byteOffset byte offset to write at
613     * @param value byte value to set
614     * @return undefined
615     */
616    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
617    public static Object setUint8(final Object self, final Object byteOffset, final Object value) {
618        try {
619            getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value));
620            return UNDEFINED;
621        } catch (final IllegalArgumentException iae) {
622            throw rangeError(iae, "dataview.offset");
623        }
624    }
625
626    /**
627     * Set 8-bit unsigned int at the given byteOffset
628     *
629     * @param self DataView object
630     * @param byteOffset byte offset to write at
631     * @param value byte value to set
632     * @return undefined
633     */
634    @SpecializedFunction
635    public static Object setUint8(final Object self, final int byteOffset, final int value) {
636        try {
637            getBuffer(self).put(byteOffset, (byte)value);
638            return UNDEFINED;
639        } catch (final IllegalArgumentException iae) {
640            throw rangeError(iae, "dataview.offset");
641        }
642    }
643
644    /**
645     * Set 16-bit signed int at the given byteOffset
646     *
647     * @param self DataView object
648     * @param byteOffset byte offset to write at
649     * @param value short value to set
650     * @param littleEndian (optional) flag indicating whether to write in little endian order
651     * @return undefined
652     */
653    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
654    public static Object setInt16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
655        try {
656            getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value));
657            return UNDEFINED;
658        } catch (final IllegalArgumentException iae) {
659            throw rangeError(iae, "dataview.offset");
660        }
661    }
662
663    /**
664     * Set 16-bit signed int at the given byteOffset
665     *
666     * @param self DataView object
667     * @param byteOffset byte offset to write at
668     * @param value short value to set
669     * @return undefined
670     */
671    @SpecializedFunction
672    public static Object setInt16(final Object self, final int byteOffset, final int value) {
673        try {
674            getBuffer(self, false).putShort(byteOffset, (short)value);
675            return UNDEFINED;
676        } catch (final IllegalArgumentException iae) {
677            throw rangeError(iae, "dataview.offset");
678        }
679    }
680
681    /**
682     * Set 16-bit signed int at the given byteOffset
683     *
684     * @param self DataView object
685     * @param byteOffset byte offset to write at
686     * @param value short value to set
687     * @param littleEndian (optional) flag indicating whether to write in little endian order
688     * @return undefined
689     */
690    @SpecializedFunction
691    public static Object setInt16(final Object self, final int byteOffset, final int value, final boolean littleEndian) {
692        try {
693            getBuffer(self, littleEndian).putShort(byteOffset, (short)value);
694            return UNDEFINED;
695        } catch (final IllegalArgumentException iae) {
696            throw rangeError(iae, "dataview.offset");
697        }
698    }
699
700    /**
701     * Set 16-bit unsigned int at the given byteOffset
702     *
703     * @param self DataView object
704     * @param byteOffset byte offset to write at
705     * @param value short value to set
706     * @param littleEndian (optional) flag indicating whether to write in little endian order
707     * @return undefined
708     */
709    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
710    public static Object setUint16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
711        try {
712            getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value));
713            return UNDEFINED;
714        } catch (final IllegalArgumentException iae) {
715            throw rangeError(iae, "dataview.offset");
716        }
717    }
718
719    /**
720     * Set 16-bit unsigned int at the given byteOffset
721     *
722     * @param self DataView object
723     * @param byteOffset byte offset to write at
724     * @param value short value to set
725     * @return undefined
726     */
727    @SpecializedFunction
728    public static Object setUint16(final Object self, final int byteOffset, final int value) {
729        try {
730            getBuffer(self, false).putShort(byteOffset, (short)value);
731            return UNDEFINED;
732        } catch (final IllegalArgumentException iae) {
733            throw rangeError(iae, "dataview.offset");
734        }
735    }
736
737    /**
738     * Set 16-bit unsigned int at the given byteOffset
739     *
740     * @param self DataView object
741     * @param byteOffset byte offset to write at
742     * @param value short value to set
743     * @param littleEndian (optional) flag indicating whether to write in little endian order
744     * @return undefined
745     */
746    @SpecializedFunction
747    public static Object setUint16(final Object self, final int byteOffset, final int value, final boolean littleEndian) {
748        try {
749            getBuffer(self, littleEndian).putShort(byteOffset, (short)value);
750            return UNDEFINED;
751        } catch (final IllegalArgumentException iae) {
752            throw rangeError(iae, "dataview.offset");
753        }
754    }
755
756    /**
757     * Set 32-bit signed int at the given byteOffset
758     *
759     * @param self DataView object
760     * @param byteOffset byte offset to write at
761     * @param value int value to set
762     * @param littleEndian (optional) flag indicating whether to write in little endian order
763     * @return undefined
764     */
765    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
766    public static Object setInt32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
767        try {
768            getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), JSType.toInt32(value));
769            return UNDEFINED;
770        } catch (final IllegalArgumentException iae) {
771            throw rangeError(iae, "dataview.offset");
772        }
773    }
774
775    /**
776     * Set 32-bit signed int at the given byteOffset
777     *
778     * @param self DataView object
779     * @param byteOffset byte offset to write at
780     * @param value int value to set
781     * @return undefined
782     */
783    @SpecializedFunction
784    public static Object setInt32(final Object self, final int byteOffset, final int value) {
785        try {
786            getBuffer(self, false).putInt(byteOffset, value);
787            return UNDEFINED;
788        } catch (final IllegalArgumentException iae) {
789            throw rangeError(iae, "dataview.offset");
790        }
791    }
792
793    /**
794     * Set 32-bit signed int at the given byteOffset
795     *
796     * @param self DataView object
797     * @param byteOffset byte offset to write at
798     * @param value int value to set
799     * @param littleEndian (optional) flag indicating whether to write in little endian order
800     * @return undefined
801     */
802    @SpecializedFunction
803    public static Object setInt32(final Object self, final int byteOffset, final int value, final boolean littleEndian) {
804        try {
805            getBuffer(self, littleEndian).putInt(byteOffset, value);
806            return UNDEFINED;
807        } catch (final IllegalArgumentException iae) {
808            throw rangeError(iae, "dataview.offset");
809        }
810    }
811
812    /**
813     * Set 32-bit unsigned int at the given byteOffset
814     *
815     * @param self DataView object
816     * @param byteOffset byte offset to write at
817     * @param value int value to set
818     * @param littleEndian (optional) flag indicating whether to write in little endian order
819     * @return undefined
820     */
821    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
822    public static Object setUint32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
823        try {
824            getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toUint32(value));
825            return UNDEFINED;
826        } catch (final IllegalArgumentException iae) {
827            throw rangeError(iae, "dataview.offset");
828        }
829    }
830
831    /**
832     * Set 32-bit unsigned int at the given byteOffset
833     *
834     * @param self DataView object
835     * @param byteOffset byte offset to write at
836     * @param value int value to set
837     * @return undefined
838     */
839    @SpecializedFunction
840    public static Object setUint32(final Object self, final int byteOffset, final long value) {
841        try {
842            getBuffer(self, false).putInt(byteOffset, (int)value);
843            return UNDEFINED;
844        } catch (final IllegalArgumentException iae) {
845            throw rangeError(iae, "dataview.offset");
846        }
847    }
848
849    /**
850     * Set 32-bit unsigned int at the given byteOffset
851     *
852     * @param self DataView object
853     * @param byteOffset byte offset to write at
854     * @param value int value to set
855     * @param littleEndian (optional) flag indicating whether to write in little endian order
856     * @return undefined
857     */
858    @SpecializedFunction
859    public static Object setUint32(final Object self, final int byteOffset, final long value, final boolean littleEndian) {
860        try {
861            getBuffer(self, littleEndian).putInt(byteOffset, (int)value);
862            return UNDEFINED;
863        } catch (final IllegalArgumentException iae) {
864            throw rangeError(iae, "dataview.offset");
865        }
866    }
867
868    /**
869     * Set 32-bit float at the given byteOffset
870     *
871     * @param self DataView object
872     * @param byteOffset byte offset to write at
873     * @param value float value to set
874     * @param littleEndian (optional) flag indicating whether to write in little endian order
875     * @return undefined
876     */
877    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
878    public static Object setFloat32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
879        try {
880            getBuffer(self, littleEndian).putFloat((int)JSType.toUint32(byteOffset), (float)JSType.toNumber(value));
881            return UNDEFINED;
882        } catch (final IllegalArgumentException iae) {
883            throw rangeError(iae, "dataview.offset");
884        }
885    }
886
887    /**
888     * Set 32-bit float at the given byteOffset
889     *
890     * @param self DataView object
891     * @param byteOffset byte offset to write at
892     * @param value float value to set
893     * @return undefined
894     */
895    @SpecializedFunction
896    public static Object setFloat32(final Object self, final int byteOffset, final double value) {
897        try {
898            getBuffer(self, false).putFloat(byteOffset, (float)value);
899            return UNDEFINED;
900        } catch (final IllegalArgumentException iae) {
901            throw rangeError(iae, "dataview.offset");
902        }
903    }
904
905    /**
906     * Set 32-bit float at the given byteOffset
907     *
908     * @param self DataView object
909     * @param byteOffset byte offset to write at
910     * @param value float value to set
911     * @param littleEndian (optional) flag indicating whether to write in little endian order
912     * @return undefined
913     */
914    @SpecializedFunction
915    public static Object setFloat32(final Object self, final int byteOffset, final double value, final boolean littleEndian) {
916        try {
917            getBuffer(self, littleEndian).putFloat(byteOffset, (float)value);
918            return UNDEFINED;
919        } catch (final IllegalArgumentException iae) {
920            throw rangeError(iae, "dataview.offset");
921        }
922    }
923
924    /**
925     * Set 64-bit float at the given byteOffset
926     *
927     * @param self DataView object
928     * @param byteOffset byte offset to write at
929     * @param value double value to set
930     * @param littleEndian (optional) flag indicating whether to write in little endian order
931     * @return undefined
932     */
933    @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
934    public static Object setFloat64(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
935        try {
936            getBuffer(self, littleEndian).putDouble((int)JSType.toUint32(byteOffset), JSType.toNumber(value));
937            return UNDEFINED;
938        } catch (final IllegalArgumentException iae) {
939            throw rangeError(iae, "dataview.offset");
940        }
941    }
942
943    /**
944     * Set 64-bit float at the given byteOffset
945     *
946     * @param self DataView object
947     * @param byteOffset byte offset to write at
948     * @param value double value to set
949     * @return undefined
950     */
951    @SpecializedFunction
952    public static Object setFloat64(final Object self, final int byteOffset, final double value) {
953        try {
954            getBuffer(self, false).putDouble(byteOffset, value);
955            return UNDEFINED;
956        } catch (final IllegalArgumentException iae) {
957            throw rangeError(iae, "dataview.offset");
958        }
959    }
960
961    /**
962     * Set 64-bit float at the given byteOffset
963     *
964     * @param self DataView object
965     * @param byteOffset byte offset to write at
966     * @param value double value to set
967     * @param littleEndian (optional) flag indicating whether to write in little endian order
968     * @return undefined
969     */
970    @SpecializedFunction
971    public static Object setFloat64(final Object self, final int byteOffset, final double value, final boolean littleEndian) {
972        try {
973            getBuffer(self, littleEndian).putDouble(byteOffset, value);
974            return UNDEFINED;
975        } catch (final IllegalArgumentException iae) {
976            throw rangeError(iae, "dataview.offset");
977        }
978    }
979
980    // internals only below this point
981    private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset) {
982        try {
983            return nab.getBuffer(offset);
984        } catch (final IllegalArgumentException iae) {
985            throw rangeError(iae, "dataview.constructor.offset");
986        }
987    }
988
989    private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset, final int length) {
990        try {
991            return nab.getBuffer(offset, length);
992        } catch (final IllegalArgumentException iae) {
993            throw rangeError(iae, "dataview.constructor.offset");
994        }
995    }
996
997    private static NativeDataView checkSelf(final Object self) {
998        if (!(self instanceof NativeDataView)) {
999            throw typeError("not.an.arraybuffer.in.dataview", ScriptRuntime.safeToString(self));
1000        }
1001        return (NativeDataView)self;
1002    }
1003
1004    private static ByteBuffer getBuffer(final Object self) {
1005        return checkSelf(self).buf;
1006    }
1007
1008    private static ByteBuffer getBuffer(final Object self, final Object littleEndian) {
1009        return getBuffer(self, JSType.toBoolean(littleEndian));
1010    }
1011
1012    private static ByteBuffer getBuffer(final Object self, final boolean littleEndian) {
1013        return getBuffer(self).order(littleEndian? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
1014    }
1015}
1016