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