Skip to content

Commit 9a6efee

Browse files
Implement BigInt64 and BigUint64 DataView methods
* Implement Dataview: BigInt64 and BigUint64. * Update 262 properties. * Add test cases for signed and unsigned special cases. Co-authored-by: vladimir.zhuravlev <[email protected]>
1 parent 73d739f commit 9a6efee

File tree

3 files changed

+120
-45
lines changed

3 files changed

+120
-45
lines changed

rhino/src/main/java/org/mozilla/javascript/typedarrays/NativeDataView.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package org.mozilla.javascript.typedarrays;
88

9+
import java.math.BigInteger;
910
import org.mozilla.javascript.Context;
1011
import org.mozilla.javascript.LambdaConstructor;
1112
import org.mozilla.javascript.ScriptRuntime;
@@ -81,6 +82,9 @@ public static Object init(Context cx, Scriptable scope, boolean sealed) {
8182
constructor.definePrototypeMethod(scope, "getUint8", 1, NativeDataView::js_getUint8);
8283
constructor.definePrototypeMethod(scope, "getUint16", 1, NativeDataView::js_getUint16);
8384
constructor.definePrototypeMethod(scope, "getUint32", 1, NativeDataView::js_getUint32);
85+
constructor.definePrototypeMethod(scope, "getBigInt64", 1, NativeDataView::js_getBigInt64);
86+
constructor.definePrototypeMethod(
87+
scope, "getBigUint64", 1, NativeDataView::js_getBigUint64);
8488
constructor.definePrototypeMethod(scope, "setFloat32", 2, NativeDataView::js_setFloat32);
8589
constructor.definePrototypeMethod(scope, "setFloat64", 2, NativeDataView::js_setFloat64);
8690
constructor.definePrototypeMethod(scope, "setInt8", 2, NativeDataView::js_setInt8);
@@ -89,6 +93,9 @@ public static Object init(Context cx, Scriptable scope, boolean sealed) {
8993
constructor.definePrototypeMethod(scope, "setUint8", 2, NativeDataView::js_setUint8);
9094
constructor.definePrototypeMethod(scope, "setUint16", 2, NativeDataView::js_setUint16);
9195
constructor.definePrototypeMethod(scope, "setUint32", 2, NativeDataView::js_setUint32);
96+
constructor.definePrototypeMethod(scope, "setBigInt64", 2, NativeDataView::js_setBigInt64);
97+
constructor.definePrototypeMethod(
98+
scope, "setBigUint64", 2, NativeDataView::js_setBigUint64);
9299

93100
if (sealed) {
94101
constructor.sealObject();
@@ -407,6 +414,87 @@ private void js_setFloat(Context cx, Scriptable scope, int bytes, Object[] args)
407414
}
408415
}
409416

417+
private static Object js_getBigInt64(
418+
Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
419+
NativeDataView realThis = realThis(thisObj);
420+
return realThis.js_getBigInt(true, args);
421+
}
422+
423+
private static Object js_getBigUint64(
424+
Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
425+
NativeDataView realThis = realThis(thisObj);
426+
return realThis.js_getBigInt(false, args);
427+
}
428+
429+
private Object js_getBigInt(boolean signed, Object[] args) {
430+
int pos = ScriptRuntime.toIndex(isArg(args, 0) ? args[0] : Undefined.instance);
431+
432+
boolean littleEndian = isArg(args, 1) && ScriptRuntime.toBoolean(args[1]);
433+
434+
if (isDataViewOutOfBounds()) {
435+
throw ScriptRuntime.typeErrorById("msg.dataview.bounds");
436+
}
437+
438+
int viewSize = byteLength;
439+
if ((long) pos + 8 > viewSize) {
440+
throw ScriptRuntime.rangeErrorById("msg.dataview.offset.range");
441+
}
442+
443+
long base = ByteIo.readUint64Primitive(arrayBuffer.buffer, offset + pos, littleEndian);
444+
445+
if (signed) {
446+
// Interpret as signed 64-bit integer
447+
return BigInteger.valueOf(base);
448+
} else {
449+
// Interpret as unsigned 64-bit integer
450+
if (base >= 0L) {
451+
return BigInteger.valueOf(base);
452+
} else {
453+
// Split into two 32-bit parts for proper unsigned conversion
454+
var lsw = BigInteger.valueOf(base & 0xffffffffL);
455+
var msw = BigInteger.valueOf((base >>> 32)).shiftLeft(32);
456+
return msw.add(lsw);
457+
}
458+
}
459+
}
460+
461+
// These two functions are specified separately, and sound like they should behave differently,
462+
// but end up having precisely the same effect, with only the interpretation of the 64 bits in
463+
// an intermediate state differing.
464+
private static Object js_setBigInt64(
465+
Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
466+
NativeDataView realThis = realThis(thisObj);
467+
realThis.js_setBigInt(args);
468+
return Undefined.instance;
469+
}
470+
471+
private static Object js_setBigUint64(
472+
Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
473+
NativeDataView realThis = realThis(thisObj);
474+
realThis.js_setBigInt(args);
475+
return Undefined.instance;
476+
}
477+
478+
private void js_setBigInt(Object[] args) {
479+
int pos = ScriptRuntime.toIndex(isArg(args, 0) ? args[0] : Undefined.instance);
480+
481+
BigInteger val = ScriptRuntime.toBigInt(isArg(args, 1) ? args[1] : Undefined.instance);
482+
483+
boolean littleEndian = isArg(args, 2) && ScriptRuntime.toBoolean(args[2]);
484+
485+
if (isDataViewOutOfBounds()) {
486+
throw ScriptRuntime.typeErrorById("msg.dataview.bounds");
487+
}
488+
489+
int viewSize = byteLength;
490+
if ((long) pos + 8 > viewSize) {
491+
throw ScriptRuntime.rangeErrorById("msg.dataview.offset.range");
492+
}
493+
494+
long base = val.longValue();
495+
ByteIo.writeUint64(arrayBuffer.buffer, offset + pos, base, littleEndian);
496+
}
497+
410498
public boolean isDataViewOutOfBounds() {
411499
if (arrayBuffer.isDetached()) {
412500
return true;

tests/testsrc/jstests/es6/dataview.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,33 @@ load("testsrc/assert.js");
1919
assertEquals(true, DataView.prototype.hasOwnProperty(Symbol.toStringTag));
2020
})();
2121

22+
(function TestBigInt64GetAndSet() {
23+
function t(origVal, expectedSigned, expectedUnsigned) {
24+
const buf = new ArrayBuffer(8);
25+
const v = new DataView(buf);
26+
v.setBigInt64(0, origVal);
27+
const newSignedVal = v.getBigInt64(0);
28+
assertEquals(expectedSigned, newSignedVal);
29+
v.setBigUint64(0, origVal);
30+
const newUnsignedVal = v.getBigUint64(0);
31+
assertEquals(expectedUnsigned, newUnsignedVal);
32+
}
33+
34+
t(0n, 0n, 0n);
35+
t(1n, 1n, 1n);
36+
37+
// A large value that still fits in a signed 64-bit value
38+
t(1234567890123456789n, 1234567890123456789n, 1234567890123456789n);
39+
40+
// Just over a 64-bit signed value, wraps around to -1, fits in unsigned
41+
t(18446744073709551615n, -1n, 18446744073709551615n);
42+
43+
// Very much too large for 64 bits, wraps around
44+
t(9223372036854775807n + 1n, -9223372036854775808n, 9223372036854775808n);
45+
46+
// Wraps around in the other direction,
47+
// when unsigned simply has less precision
48+
t(-9223372036854775808n - 1n, 9223372036854775807n, 9223372036854775807n);
49+
})();
50+
2251
"success";

tests/testsrc/test262.properties

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ built-ins/BigInt 4/75 (5.33%)
687687
built-ins/Boolean 1/51 (1.96%)
688688
proto-from-ctor-realm.js
689689

690-
built-ins/DataView 161/561 (28.7%)
690+
built-ins/DataView 117/561 (20.86%)
691691
prototype/buffer/return-buffer-sab.js {unsupported: [SharedArrayBuffer]}
692692
prototype/buffer/this-has-no-dataview-internal-sab.js {unsupported: [SharedArrayBuffer]}
693693
prototype/byteLength/resizable-array-buffer-auto.js {unsupported: [resizable-arraybuffer]}
@@ -698,37 +698,9 @@ built-ins/DataView 161/561 (28.7%)
698698
prototype/byteOffset/resizable-array-buffer-fixed.js {unsupported: [resizable-arraybuffer]}
699699
prototype/byteOffset/return-byteoffset-sab.js {unsupported: [SharedArrayBuffer]}
700700
prototype/byteOffset/this-has-no-dataview-internal-sab.js {unsupported: [SharedArrayBuffer]}
701-
prototype/getBigInt64/detached-buffer-after-toindex-byteoffset.js
702-
prototype/getBigInt64/index-is-out-of-range.js
703-
prototype/getBigInt64/length.js
704-
prototype/getBigInt64/name.js
705-
prototype/getBigInt64/negative-byteoffset-throws.js
706-
prototype/getBigInt64/not-a-constructor.js
707701
prototype/getBigInt64/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
708-
prototype/getBigInt64/return-abrupt-from-tonumber-byteoffset.js
709-
prototype/getBigInt64/return-value-clean-arraybuffer.js
710-
prototype/getBigInt64/return-values.js
711-
prototype/getBigInt64/return-values-custom-offset.js
712-
prototype/getBigInt64/to-boolean-littleendian.js
713-
prototype/getBigInt64/toindex-byteoffset.js
714-
prototype/getBigInt64/toindex-byteoffset-errors.js
715-
prototype/getBigInt64/toindex-byteoffset-toprimitive.js
716702
prototype/getBigInt64/toindex-byteoffset-wrapped-values.js
717-
prototype/getBigUint64/detached-buffer-after-toindex-byteoffset.js
718-
prototype/getBigUint64/index-is-out-of-range.js
719-
prototype/getBigUint64/length.js
720-
prototype/getBigUint64/name.js
721-
prototype/getBigUint64/negative-byteoffset-throws.js
722-
prototype/getBigUint64/not-a-constructor.js
723703
prototype/getBigUint64/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
724-
prototype/getBigUint64/return-abrupt-from-tonumber-byteoffset.js
725-
prototype/getBigUint64/return-value-clean-arraybuffer.js
726-
prototype/getBigUint64/return-values.js
727-
prototype/getBigUint64/return-values-custom-offset.js
728-
prototype/getBigUint64/to-boolean-littleendian.js
729-
prototype/getBigUint64/toindex-byteoffset.js
730-
prototype/getBigUint64/toindex-byteoffset-errors.js
731-
prototype/getBigUint64/toindex-byteoffset-toprimitive.js
732704
prototype/getBigUint64/toindex-byteoffset-wrapped-values.js
733705
prototype/getFloat16/detached-buffer-after-toindex-byteoffset.js
734706
prototype/getFloat16/index-is-out-of-range.js
@@ -764,24 +736,10 @@ built-ins/DataView 161/561 (28.7%)
764736
prototype/getUint16/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
765737
prototype/getUint32/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
766738
prototype/getUint8/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
767-
prototype/setBigInt64/detached-buffer-after-bigint-value.js
768-
prototype/setBigInt64/detached-buffer-after-toindex-byteoffset.js
769739
prototype/setBigInt64/immutable-buffer.js
770-
prototype/setBigInt64/index-check-before-value-conversion.js
771-
prototype/setBigInt64/index-is-out-of-range.js
772-
prototype/setBigInt64/length.js
773-
prototype/setBigInt64/name.js
774-
prototype/setBigInt64/negative-byteoffset-throws.js
775-
prototype/setBigInt64/not-a-constructor.js
776-
prototype/setBigInt64/range-check-after-value-conversion.js
777740
prototype/setBigInt64/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
778-
prototype/setBigInt64/return-abrupt-from-tobigint-value.js
779-
prototype/setBigInt64/return-abrupt-from-tonumber-byteoffset.js
780-
prototype/setBigInt64/set-values-little-endian-order.js
781-
prototype/setBigInt64/set-values-return-undefined.js
782-
prototype/setBigInt64/to-boolean-littleendian.js
783-
prototype/setBigInt64/toindex-byteoffset.js
784-
prototype/setBigUint64 3/3 (100.0%)
741+
prototype/setBigUint64/immutable-buffer.js
742+
prototype/setBigUint64/resizable-buffer.js {unsupported: [resizable-arraybuffer]}
785743
prototype/setFloat16/detached-buffer-after-number-value.js
786744
prototype/setFloat16/detached-buffer-after-toindex-byteoffset.js
787745
prototype/setFloat16/immutable-buffer.js

0 commit comments

Comments
 (0)