summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-07-24 23:30:27 -0500
committerBrian Smith <brian@dbsoft.org>2023-07-24 23:30:27 -0500
commitedacbbd96538a60495dd50010b5549defc1ea35c (patch)
treecce9a88046cf1ddccc37bebc7cb11fb0ec1e0e71
parentb4ddadd8b98a83e833eb01223dbb3858955e868d (diff)
downloaduxp-edacbbd96538a60495dd50010b5549defc1ea35c.tar.gz
Issue #2026 - Part 1 - Implement BigInt64 and BigUint64Array.
https://bugzilla.mozilla.org/show_bug.cgi?id=1456569
-rw-r--r--js/public/Class.h2
-rw-r--r--js/src/builtin/Object.cpp4
-rw-r--r--js/src/builtin/TypedArray.js26
-rw-r--r--js/src/builtin/TypedObject.h22
-rw-r--r--js/src/builtin/TypedObjectConstants.h10
-rw-r--r--js/src/jit/BaselineIC.cpp3
-rw-r--r--js/src/jit/IonTypes.h31
-rw-r--r--js/src/jit/MIR.cpp9
-rw-r--r--js/src/jit/MIR.h3
-rw-r--r--js/src/jit/MacroAssembler-inl.h4
-rw-r--r--js/src/jit/MacroAssembler.cpp17
-rw-r--r--js/src/jit/RangeAnalysis.cpp2
-rw-r--r--js/src/jit/x64/CodeGenerator-x64.cpp2
-rw-r--r--js/src/jit/x64/Lowering-x64.cpp2
-rw-r--r--js/src/jit/x64/MacroAssembler-x64.cpp6
-rw-r--r--js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp2
-rw-r--r--js/src/jit/x86/Lowering-x86.cpp2
-rw-r--r--js/src/jit/x86/MacroAssembler-x86.cpp6
-rw-r--r--js/src/jsarray.cpp7
-rw-r--r--js/src/jsfriendapi.h76
-rw-r--r--js/src/jsobj.cpp8
-rw-r--r--js/src/jsprototypes.h2
-rw-r--r--js/src/vm/ArrayBufferObject.h16
-rw-r--r--js/src/vm/BigIntType.cpp16
-rw-r--r--js/src/vm/BigIntType.h2
-rw-r--r--js/src/vm/CommonPropertyNames.h2
-rw-r--r--js/src/vm/GlobalObject.h30
-rw-r--r--js/src/vm/NativeObject-inl.h11
-rw-r--r--js/src/vm/NativeObject.cpp53
-rw-r--r--js/src/vm/NativeObject.h5
-rw-r--r--js/src/vm/ObjectGroup.cpp2
-rw-r--r--js/src/vm/SelfHosting.cpp47
-rw-r--r--js/src/vm/StructuredClone.cpp13
-rw-r--r--js/src/vm/TypedArrayCommon.h103
-rw-r--r--js/src/vm/TypedArrayObject.cpp454
-rw-r--r--js/src/vm/TypedArrayObject.h20
36 files changed, 788 insertions, 232 deletions
diff --git a/js/public/Class.h b/js/public/Class.h
index 8aeacdc541..40885e6082 100644
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -913,7 +913,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
- (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 50)
+ (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 52)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index 388af28f26..f4353480ba 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -842,7 +842,9 @@ EnumerableOwnProperties(JSContext* cx, const JS::CallArgs& args, EnumerableOwnPr
if (obj->is<NativeObject>()) {
HandleNativeObject nobj = obj.as<NativeObject>();
if (JSID_IS_INT(id) && nobj->containsDenseElement(JSID_TO_INT(id))) {
- value = nobj->getDenseOrTypedArrayElement(JSID_TO_INT(id));
+ if(!nobj->getDenseOrTypedArrayElement<CanGC>(cx, JSID_TO_INT(id), &value)) {
+ return false;
+ }
} else {
shape = nobj->lookup(cx, id);
if (!shape || !(shape->attributes() & JSPROP_ENUMERATE))
diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js
index 22023aa7ca..57f6d738ca 100644
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -879,7 +879,7 @@ function SetFromNonTypedArray(target, array, targetOffset, targetLength, targetB
// Steps 12-15, 21, 23-24.
while (targetOffset < limitOffset) {
// Steps 24a-c.
- var kNumber = ToNumber(src[k]);
+ var kNumber = ToNumeric(src[k]);
// Step 24d. This explicit check will be unnecessary when we implement
// throw-on-getting/setting-element-in-detached-buffer semantics.
@@ -1098,6 +1098,30 @@ function TypedArrayCompare(x, y) {
return Number_isNaN(y) ? -1 : 0;
}
+// https://tc39.github.io/proposal-bigint/#sec-%typedarray%.prototype.sort
+// TypedArray SortCompare specialization for BigInt values.
+function TypedArrayCompareBigInt(x, y) {
+ // Step 1.
+ // eslint-disable-next-line valid-typeof
+ assert(typeof x === "bigint" && typeof y === "bigint",
+ "x and y are not BigInts.");
+
+ // Step 2 (Implemented in TypedArraySort).
+
+ // Step 6.
+ if (x < y)
+ return -1;
+
+ // Step 7.
+ if (x > y)
+ return 1;
+
+ // Steps 3-5, 8-9 (Not applicable when sorting BigInt values).
+
+ // Step 10.
+ return 0;
+}
+
// TypedArray SortCompare specialization for integer values.
function TypedArrayCompareInt(x, y) {
// Step 1.
diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h
index 83700001d4..9318a0f795 100644
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -245,6 +245,10 @@ class ScalarTypeDescr : public SimpleTypeDescr
"TypedObjectConstants.h must be consistent with Scalar::Type");
static_assert(Scalar::Uint32 == JS_SCALARTYPEREPR_UINT32,
"TypedObjectConstants.h must be consistent with Scalar::Type");
+ static_assert(Scalar::BigInt64 == JS_SCALARTYPEREPR_BIGINT64,
+ "TypedObjectConstants.h must be consistent with Scalar::Type");
+ static_assert(Scalar::BigUint64 == JS_SCALARTYPEREPR_BIGUINT64,
+ "TypedObjectConstants.h must be consistent with Scalar::Type");
static_assert(Scalar::Float32 == JS_SCALARTYPEREPR_FLOAT32,
"TypedObjectConstants.h must be consistent with Scalar::Type");
static_assert(Scalar::Float64 == JS_SCALARTYPEREPR_FLOAT64,
@@ -270,14 +274,16 @@ class ScalarTypeDescr : public SimpleTypeDescr
// unique C representation. In particular, omits Uint8Clamped since it
// is just a Uint8.
#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_) \
- macro_(Scalar::Int8, int8_t, int8) \
- macro_(Scalar::Uint8, uint8_t, uint8) \
- macro_(Scalar::Int16, int16_t, int16) \
- macro_(Scalar::Uint16, uint16_t, uint16) \
- macro_(Scalar::Int32, int32_t, int32) \
- macro_(Scalar::Uint32, uint32_t, uint32) \
- macro_(Scalar::Float32, float, float32) \
- macro_(Scalar::Float64, double, float64)
+ macro_(Scalar::Int8, int8_t, int8) \
+ macro_(Scalar::Uint8, uint8_t, uint8) \
+ macro_(Scalar::Int16, int16_t, int16) \
+ macro_(Scalar::Uint16, uint16_t, uint16) \
+ macro_(Scalar::Int32, int32_t, int32) \
+ macro_(Scalar::Uint32, uint32_t, uint32) \
+ macro_(Scalar::Float32, float, float32) \
+ macro_(Scalar::Float64, double, float64) \
+ macro_(Scalar::BigInt64, int64_t, bigint64) \
+ macro_(Scalar::BigUint64, uint64_t, biguint64)
// Must be in same order as the enum ScalarTypeDescr::Type:
#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_) \
diff --git a/js/src/builtin/TypedObjectConstants.h b/js/src/builtin/TypedObjectConstants.h
index a28c9159a5..aa930d29bb 100644
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -88,10 +88,12 @@
#define JS_SCALARTYPEREPR_FLOAT32 6
#define JS_SCALARTYPEREPR_FLOAT64 7
#define JS_SCALARTYPEREPR_UINT8_CLAMPED 8
-#define JS_SCALARTYPEREPR_FLOAT32X4 11
-#define JS_SCALARTYPEREPR_INT8X16 12
-#define JS_SCALARTYPEREPR_INT16X8 13
-#define JS_SCALARTYPEREPR_INT32X4 14
+#define JS_SCALARTYPEREPR_BIGINT64 9
+#define JS_SCALARTYPEREPR_BIGUINT64 10
+#define JS_SCALARTYPEREPR_FLOAT32X4 13
+#define JS_SCALARTYPEREPR_INT8X16 14
+#define JS_SCALARTYPEREPR_INT16X8 15
+#define JS_SCALARTYPEREPR_INT32X4 16
// These constants are for use exclusively in JS code. In C++ code,
// prefer ReferenceTypeRepresentation::TYPE_ANY etc, which allows
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index 2827f4b1d5..600b56d096 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -3204,6 +3204,9 @@ StoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type, Addres
} else {
masm.jump(failure);
}
+ } else if (type == Scalar::BigInt64 || type == Scalar::BigUint64) {
+ // FIXME: https://bugzil.la/1536703
+ masm.jump(failure);
} else {
Label notInt32;
masm.branchTestInt32(Assembler::NotEqual, value, &notInt32);
diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h
index c9714343dc..50b09cc30e 100644
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -724,34 +724,9 @@ ScalarTypeToMIRType(Scalar::Type type)
return MIRType::Int16x8;
case Scalar::Int32x4:
return MIRType::Int32x4;
- case Scalar::MaxTypedArrayViewType:
- break;
- }
- MOZ_CRASH("unexpected SIMD kind");
-}
-
-static inline unsigned
-ScalarTypeToLength(Scalar::Type type)
-{
- switch (type) {
- case Scalar::Int8:
- case Scalar::Uint8:
- case Scalar::Int16:
- case Scalar::Uint16:
- case Scalar::Int32:
- case Scalar::Uint32:
- case Scalar::Int64:
- case Scalar::Float32:
- case Scalar::Float64:
- case Scalar::Uint8Clamped:
- return 1;
- case Scalar::Float32x4:
- case Scalar::Int32x4:
- return 4;
- case Scalar::Int16x8:
- return 8;
- case Scalar::Int8x16:
- return 16;
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
+ MOZ_CRASH("NYI");
case Scalar::MaxTypedArrayViewType:
break;
}
diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
index 63ff8f7201..2264bed4f2 100644
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -6005,7 +6005,14 @@ jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
return false;
*arrayType = types->getTypedArrayType(constraints);
- return *arrayType != Scalar::MaxTypedArrayViewType;
+
+ // FIXME: https://bugzil.la/1536699
+ if (*arrayType == Scalar::MaxTypedArrayViewType ||
+ Scalar::isBigIntType(*arrayType)) {
+ return false;
+ }
+
+ return true;
}
bool
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 6a2adc9622..72c5214845 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -14443,6 +14443,9 @@ MIRTypeForTypedArrayRead(Scalar::Type arrayType, bool observedDouble)
return MIRType::Float32;
case Scalar::Float64:
return MIRType::Double;
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
+ return MIRType::BigInt;
default:
break;
}
diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h
index 336b9e2df8..98316eb643 100644
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -644,7 +644,7 @@ void
MacroAssembler::canonicalizeFloatIfDeterministic(FloatRegister reg)
{
#ifdef JS_MORE_DETERMINISTIC
- // See the comment in TypedArrayObjectTemplate::getIndexValue.
+ // See the comment in TypedArrayObjectTemplate::getElement.
canonicalizeFloat(reg);
#endif // JS_MORE_DETERMINISTIC
}
@@ -662,7 +662,7 @@ void
MacroAssembler::canonicalizeDoubleIfDeterministic(FloatRegister reg)
{
#ifdef JS_MORE_DETERMINISTIC
- // See the comment in TypedArrayObjectTemplate::getIndexValue.
+ // See the comment in TypedArrayObjectTemplate::getElement.
canonicalizeDouble(reg);
#endif // JS_MORE_DETERMINISTIC
}
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index fdbcc9f23c..07f7b6fdcd 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -345,6 +345,11 @@ MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T& src, AnyRegi
branchTest32(Assembler::Signed, dest.gpr(), dest.gpr(), fail);
}
break;
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
+ // FIXME: https://bugzil.la/1536702
+ jump(fail);
+ break;
case Scalar::Float32:
loadFloat32(src, dest.fpu());
canonicalizeFloat(dest.fpu());
@@ -447,17 +452,25 @@ MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T& src, const V
tagValue(JSVAL_TYPE_INT32, temp, dest);
}
break;
- case Scalar::Float32:
+ case Scalar::Float32: {
loadFromTypedArray(arrayType, src, AnyRegister(ScratchFloat32Reg), dest.scratchReg(),
nullptr);
convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
boxDouble(ScratchDoubleReg, dest);
break;
- case Scalar::Float64:
+ }
+ case Scalar::Float64: {
loadFromTypedArray(arrayType, src, AnyRegister(ScratchDoubleReg), dest.scratchReg(),
nullptr);
boxDouble(ScratchDoubleReg, dest);
break;
+ }
+ // FIXME: https://bugzil.la/1536702
+ case Scalar::BigInt64:
+ case Scalar::BigUint64: {
+ jump(fail);
+ break;
+ }
default:
MOZ_CRASH("Invalid typed array type");
}
diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp
index b5f617ce32..52c737e677 100644
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1780,6 +1780,8 @@ GetTypedArrayRange(TempAllocator& alloc, Scalar::Type type)
case Scalar::Int32:
return Range::NewInt32Range(alloc, INT32_MIN, INT32_MAX);
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Int64:
case Scalar::Float32:
case Scalar::Float64:
diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp
index 9dea005abb..3f4052f51d 100644
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -445,6 +445,8 @@ CodeGeneratorX64::wasmStore(const wasm::MemoryAccessDesc& access, const LAllocat
case Scalar::Int16x8:
case Scalar::Int32x4:
case Scalar::Uint8Clamped:
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
}
diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp
index db92d8dac5..4aebe05af2 100644
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -239,6 +239,8 @@ LIRGeneratorX64::visitWasmStore(MWasmStore* ins)
case Scalar::Int32x4:
valueAlloc = useRegisterAtStart(value);
break;
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp
index 759977bac1..1fab669d2b 100644
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -713,6 +713,8 @@ MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr,
break;
case Scalar::Int64:
MOZ_CRASH("int64 loads must use load64");
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
@@ -759,6 +761,8 @@ MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAdd
case Scalar::Int16x8:
case Scalar::Int32x4:
MOZ_CRASH("non-int64 loads should use load()");
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
@@ -822,6 +826,8 @@ MacroAssembler::wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister valu
MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial store");
storeUnalignedSimd128Int(value.fpu(), dstAddr);
break;
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
index 3111ae4c92..5ec00da849 100644
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -402,6 +402,8 @@ CodeGeneratorX86Shared::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTyp
case Scalar::Int8x16:
case Scalar::Int16x8:
case Scalar::Int32x4:
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
case Scalar::Float32:
diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp
index ad3dd8afcb..27859c0772 100644
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -326,6 +326,8 @@ LIRGeneratorX86::visitWasmStore(MWasmStore* ins)
add(lir, ins);
return;
}
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp
index aef460e2f4..9962b9c594 100644
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -616,6 +616,8 @@ MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr,
vmovdquWithPatch(srcAddr, out.fpu());
break;
case Scalar::Int64:
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected type");
@@ -727,6 +729,8 @@ MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAdd
case Scalar::Int16x8:
case Scalar::Int32x4:
MOZ_CRASH("non-int64 loads should use load()");
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Uint8Clamped:
case Scalar::MaxTypedArrayViewType:
MOZ_CRASH("unexpected array type");
@@ -790,6 +794,8 @@ MacroAssembler::wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister valu
case Scalar::Int64:
MOZ_CRASH("Should be handled in storeI64.");
case Scalar::MaxTypedArrayViewType:
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
MOZ_CRASH("unexpected type");
}
append(wasm::MemoryPatch(size()));
diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp
index cc0fcbebd9..4f5c717be5 100644
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -376,6 +376,13 @@ js::GetElements(JSContext* cx, HandleObject aobj, uint32_t length, Value* vp)
}
}
+ if (aobj->is<TypedArrayObject>()) {
+ Handle<TypedArrayObject*> typedArray = aobj.as<TypedArrayObject>();
+ if (typedArray->length() == length) {
+ return TypedArrayObject::getElements(cx, typedArray, vp);
+ }
+ }
+
if (js::GetElementsOp op = aobj->getOpsGetElements()) {
ElementAdder adder(cx, vp, length, ElementAdder::GetElement);
return op(cx, aobj, 0, length, &adder);
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index 6a13d4343c..6a873e15da 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1467,12 +1467,15 @@ GetSCOffset(JSStructuredCloneWriter* writer);
namespace Scalar {
-/**
- * Scalar types that can appear in typed arrays and typed objects. The enum
- * values must to be kept in sync with the JS_SCALARTYPEREPR_ constants, as
- * well as the TypedArrayObject::classes and TypedArrayObject::protoClasses
- * definitions.
- */
+// Scalar types that can appear in typed arrays and typed objects.
+// The enum values must be kept in sync with:
+// * the JS_SCALARTYPEREPR constants
+// * the TYPEDARRAY_KIND constants
+// * the SCTAG_TYPED_ARRAY constants
+// * JS_FOR_EACH_TYPEDARRAY
+// * JS_FOR_PROTOTYPES_
+// * JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE
+// * JIT compilation
enum Type {
Int8 = 0,
Uint8,
@@ -1489,6 +1492,9 @@ enum Type {
*/
Uint8Clamped,
+ BigInt64,
+ BigUint64,
+
/**
* Types that don't have their own TypedArray equivalent, for now.
*/
@@ -1518,6 +1524,8 @@ byteSize(Type atype)
return 4;
case Int64:
case Float64:
+ case BigInt64:
+ case BigUint64:
return 8;
case Int8x16:
case Int16x8:
@@ -1539,6 +1547,7 @@ isSignedIntType(Type atype) {
case Int8x16:
case Int16x8:
case Int32x4:
+ case BigInt64:
return true;
case Uint8:
case Uint8Clamped:
@@ -1547,12 +1556,39 @@ isSignedIntType(Type atype) {
case Float32:
case Float64:
case Float32x4:
+ case BigUint64:
return false;
default:
MOZ_CRASH("invalid scalar type");
}
}
+static inline bool isBigIntType(Type atype) {
+ switch (atype) {
+ case BigInt64:
+ case BigUint64:
+ return true;
+ case Int8:
+ case Int16:
+ case Int32:
+ case Int64:
+ case Uint8:
+ case Uint8Clamped:
+ case Uint16:
+ case Uint32:
+ case Float32:
+ case Float64:
+ case Int8x16:
+ case Int16x8:
+ case Int32x4:
+ case Float32x4:
+ return false;
+ case MaxTypedArrayViewType:
+ break;
+ }
+ MOZ_CRASH("invalid scalar type");
+}
+
static inline bool
isSimdType(Type atype) {
switch (atype) {
@@ -1566,6 +1602,8 @@ isSimdType(Type atype) {
case Int64:
case Float32:
case Float64:
+ case BigInt64:
+ case BigUint64:
return false;
case Int8x16:
case Int16x8:
@@ -1598,6 +1636,8 @@ scalarByteSize(Type atype) {
case Int64:
case Float32:
case Float64:
+ case BigInt64:
+ case BigUint64:
case MaxTypedArrayViewType:
break;
}
@@ -1628,6 +1668,10 @@ JS_NewInt32Array(JSContext* cx, uint32_t nelements);
extern JS_FRIEND_API(JSObject*)
JS_NewUint32Array(JSContext* cx, uint32_t nelements);
extern JS_FRIEND_API(JSObject*)
+JS_NewBigInt64Array(JSContext* cx, int32_t nelements);
+extern JS_FRIEND_API(JSObject*)
+JS_NewBigUint64Array(JSContext* cx, int32_t nelements);
+extern JS_FRIEND_API(JSObject*)
JS_NewFloat32Array(JSContext* cx, uint32_t nelements);
extern JS_FRIEND_API(JSObject*)
JS_NewFloat64Array(JSContext* cx, uint32_t nelements);
@@ -1655,6 +1699,10 @@ JS_NewInt32ArrayFromArray(JSContext* cx, JS::HandleObject array);
extern JS_FRIEND_API(JSObject*)
JS_NewUint32ArrayFromArray(JSContext* cx, JS::HandleObject array);
extern JS_FRIEND_API(JSObject*)
+JS_NewBigInt64ArrayWithBuffer(JSContext* cx, JS::HandleObject array);
+extern JS_FRIEND_API(JSObject*)
+JS_NewBigUint64ArrayWithBuffer(JSContext* cx, JS::HandleObject array);
+extern JS_FRIEND_API(JSObject*)
JS_NewFloat32ArrayFromArray(JSContext* cx, JS::HandleObject array);
extern JS_FRIEND_API(JSObject*)
JS_NewFloat64ArrayFromArray(JSContext* cx, JS::HandleObject array);
@@ -1688,6 +1736,12 @@ extern JS_FRIEND_API(JSObject*)
JS_NewUint32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
uint32_t byteOffset, int32_t length);
extern JS_FRIEND_API(JSObject*)
+JS_NewBigInt64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
+ uint32_t byteOffset, int32_t length);
+extern JS_FRIEND_API(JSObject*)
+JS_NewBigUint64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
+ uint32_t byteOffset, int32_t length);
+extern JS_FRIEND_API(JSObject*)
JS_NewFloat32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
uint32_t byteOffset, int32_t length);
extern JS_FRIEND_API(JSObject*)
@@ -1747,6 +1801,10 @@ JS_IsInt32Array(JSObject* obj);
extern JS_FRIEND_API(bool)
JS_IsUint32Array(JSObject* obj);
extern JS_FRIEND_API(bool)
+JS_IsBigInt64Array(JSObject* obj);
+extern JS_FRIEND_API(bool)
+JS_IsBigUint64Array(JSObject* obj);
+extern JS_FRIEND_API(bool)
JS_IsFloat32Array(JSObject* obj);
extern JS_FRIEND_API(bool)
JS_IsFloat64Array(JSObject* obj);
@@ -1784,6 +1842,10 @@ UnwrapInt32Array(JSObject* obj);
extern JS_FRIEND_API(JSObject*)
UnwrapUint32Array(JSObject* obj);
extern JS_FRIEND_API(JSObject*)
+UnwrapBigInt64Array(JSObject* obj);
+extern JS_FRIEND_API(JSObject*)
+UnwrapBigUint64Array(JSObject* obj);
+extern JS_FRIEND_API(JSObject*)
UnwrapFloat32Array(JSObject* obj);
extern JS_FRIEND_API(JSObject*)
UnwrapFloat64Array(JSObject* obj);
@@ -1807,6 +1869,8 @@ extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr;
extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr;
extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr;
extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) BigInt64ArrayClassPtr;
+extern JS_FRIEND_DATA(const Class* const) BigUint64ArrayClassPtr;
extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr;
extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr;
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index d0f9430bc8..730805e038 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2356,15 +2356,15 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Property
}
static inline bool
-NativeGetPureInline(NativeObject* pobj, jsid id, PropertyResult prop, Value* vp)
+NativeGetPureInline(NativeObject* pobj, jsid id, PropertyResult prop, Value* vp,
+ ExclusiveContext* cx)
{
if (prop.isDenseOrTypedArrayElement()) {
// For simplicity we ignore the TypedArray with string index case.
if (!JSID_IS_INT(id))
return false;
- *vp = pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id));
- return true;
+ return pobj->getDenseOrTypedArrayElement<NoGC>(cx, JSID_TO_INT(id), vp);
}
// Fail if we have a custom getter.
@@ -2395,7 +2395,7 @@ js::GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp)
return true;
}
- return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
+ return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp, cx);
}
static inline bool
diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h
index 75168d37ef..34f835bc1d 100644
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -91,6 +91,8 @@
real(Float32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
real(Float64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
real(Uint8ClampedArray, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
+ real(BigInt64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(BigInt64)) \
+ real(BigUint64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(BigUint64)) \
real(BigInt, InitViaClassSpec, OCLASP(BigInt)) \
real(Proxy, InitProxyClass, js::ProxyClassPtr) \
real(WeakMap, InitWeakMapClass, OCLASP(WeakMap)) \
diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h
index 87dce34ba1..4ff7962cfb 100644
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -463,9 +463,11 @@ struct uint8_clamped {
explicit uint8_clamped(uint8_t x) { *this = x; }
explicit uint8_clamped(uint16_t x) { *this = x; }
explicit uint8_clamped(uint32_t x) { *this = x; }
+ explicit uint8_clamped(uint64_t x) { *this = x; }
explicit uint8_clamped(int8_t x) { *this = x; }
explicit uint8_clamped(int16_t x) { *this = x; }
explicit uint8_clamped(int32_t x) { *this = x; }
+ explicit uint8_clamped(int64_t x) { *this = x; }
explicit uint8_clamped(double x) { *this = x; }
uint8_clamped& operator=(const uint8_clamped& x) = default;
@@ -485,6 +487,11 @@ struct uint8_clamped {
return *this;
}
+ uint8_clamped& operator=(uint64_t x) {
+ val = (x > 255) ? 255 : uint8_t(x);
+ return *this;
+ }
+
uint8_clamped& operator=(int8_t x) {
val = (x >= 0) ? uint8_t(x) : 0;
return *this;
@@ -508,6 +515,15 @@ struct uint8_clamped {
return *this;
}
+ uint8_clamped& operator=(int64_t x) {
+ val = (x >= 0)
+ ? ((x < 255)
+ ? uint8_t(x)
+ : 255)
+ : 0;
+ return *this;
+ }
+
uint8_clamped& operator=(const double x) {
val = uint8_t(ClampDoubleToUint8(x));
return *this;
diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp
index 7b8375526f..44bb1923f7 100644
--- a/js/src/vm/BigIntType.cpp
+++ b/js/src/vm/BigIntType.cpp
@@ -2626,6 +2626,22 @@ BigInt* js::ToBigInt(ExclusiveContext* cx, HandleValue val) {
return nullptr;
}
+JS::Result<int64_t> js::ToBigInt64(JSContext* cx, HandleValue v) {
+ BigInt* bi = ToBigInt(cx, v);
+ if (!bi) {
+ return cx->alreadyReportedError();
+ }
+ return BigInt::toInt64(bi);
+}
+
+JS::Result<uint64_t> js::ToBigUint64(JSContext* cx, HandleValue v) {
+ BigInt* bi = ToBigInt(cx, v);
+ if (!bi) {
+ return cx->alreadyReportedError();
+ }
+ return BigInt::toUint64(bi);
+}
+
double BigInt::numberValue(BigInt* x) {
if (x->isZero()) {
return 0.0;
diff --git a/js/src/vm/BigIntType.h b/js/src/vm/BigIntType.h
index 0ccba99634..7cdd757994 100644
--- a/js/src/vm/BigIntType.h
+++ b/js/src/vm/BigIntType.h
@@ -358,6 +358,8 @@ namespace js {
extern JSAtom* BigIntToAtom(js::ExclusiveContext* cx, JS::HandleBigInt bi);
extern JS::BigInt* NumberToBigInt(js::ExclusiveContext* cx, double d);
+extern JS::Result<int64_t> ToBigInt64(JSContext* cx, JS::Handle<JS::Value> v);
+extern JS::Result<uint64_t> ToBigUint64(JSContext* cx, JS::Handle<JS::Value> v);
// Parse a BigInt from a string, using the method specified for StringToBigInt.
// Used by the BigInt constructor among other places.
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index efbd8a5323..f05a4db9be 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -36,6 +36,8 @@
macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
macro(async, async, "async") \
macro(await, await, "await") \
+ macro(bigint64, bigint64, "bigint64") \
+ macro(biguint64, biguint64, "biguint64") \
macro(Bool8x16, Bool8x16, "Bool8x16") \
macro(Bool16x8, Bool16x8, "Bool16x8") \
macro(Bool32x4, Bool32x4, "Bool32x4") \
diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h
index 1e10fe5da3..c4d9cf7287 100644
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -82,6 +82,8 @@ class GlobalObject : public NativeObject
FROM_BUFFER_INT16,
FROM_BUFFER_UINT32,
FROM_BUFFER_INT32,
+ FROM_BUFFER_UINT64,
+ FROM_BUFFER_INT64,
FROM_BUFFER_FLOAT32,
FROM_BUFFER_FLOAT64,
FROM_BUFFER_UINT8CLAMPED,
@@ -959,6 +961,20 @@ GlobalObject::setCreateArrayFromBuffer<int32_t>(Handle<JSFunction*> fun)
template<>
inline void
+GlobalObject::setCreateArrayFromBuffer<uint64_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_UINT64, fun);
+}
+
+template<>
+inline void
+GlobalObject::setCreateArrayFromBuffer<int64_t>(Handle<JSFunction*> fun)
+{
+ setCreateArrayFromBufferHelper(FROM_BUFFER_INT64, fun);
+}
+
+template<>
+inline void
GlobalObject::setCreateArrayFromBuffer<float>(Handle<JSFunction*> fun)
{
setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT32, fun);
@@ -1022,6 +1038,20 @@ GlobalObject::createArrayFromBuffer<int32_t>() const
template<>
inline Value
+GlobalObject::createArrayFromBuffer<uint64_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_UINT64);
+}
+
+template<>
+inline Value
+GlobalObject::createArrayFromBuffer<int64_t>() const
+{
+ return createArrayFromBufferHelper(FROM_BUFFER_INT64);
+}
+
+template<>
+inline Value
GlobalObject::createArrayFromBuffer<float>() const
{
return createArrayFromBufferHelper(FROM_BUFFER_FLOAT32);
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
index 69976bc462..1fa5cbd10e 100644
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -239,12 +239,15 @@ NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t
return DenseElementResult::Success;
}
-inline Value
-NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
+template <AllowGC allowGC>
+inline bool
+NativeObject::getDenseOrTypedArrayElement(ExclusiveContext* cx, uint32_t idx,
+ typename MaybeRooted<Value, allowGC>::MutableHandleType val)
{
if (is<TypedArrayObject>())
- return as<TypedArrayObject>().getElement(idx);
- return getDenseElement(idx);
+ return as<TypedArrayObject>().getElement<allowGC>(cx, idx, val);
+ val.set(getDenseElement(idx));
+ return true;
}
/* static */ inline NativeObject*
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index a6bb9826ee..d21f88b15e 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -20,6 +20,7 @@
#include "vm/ArrayObject-inl.h"
#include "vm/EnvironmentObject-inl.h"
#include "vm/Shape-inl.h"
+#include "vm/TypedArrayObject.h"
using namespace js;
@@ -1283,8 +1284,7 @@ GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId
Handle<PropertyResult> prop, MutableHandleValue vp)
{
if (prop.isDenseOrTypedArrayElement()) {
- vp.set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
- return true;
+ return obj->getDenseOrTypedArrayElement<CanGC>(cx, JSID_TO_INT(id), vp);
}
if (!cx->shouldBeJSContext())
return false;
@@ -1814,7 +1814,9 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle
desc.attributesRef() &= ~JSPROP_SHARED;
if (prop.isDenseOrTypedArrayElement()) {
- desc.value().set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
+ if (!obj->getDenseOrTypedArrayElement<CanGC>(cx, JSID_TO_INT(id), desc.value())) {
+ return false;
+ }
} else {
RootedShape shape(cx, prop.shape());
if (!NativeGetExistingProperty(cx, obj, obj, shape, desc.value()))
@@ -2110,8 +2112,7 @@ NativeGetPropertyInline(JSContext* cx,
// Steps 5-8. Special case for dense elements because
// GetExistingProperty doesn't support those.
if (prop.isDenseOrTypedArrayElement()) {
- vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
- return true;
+ return pobj->template getDenseOrTypedArrayElement<allowGC>(cx, JSID_TO_INT(id), vp);
}
typename MaybeRooted<Shape*, allowGC>::RootType shape(cx, prop.shape());
@@ -2365,38 +2366,6 @@ SetNonexistentProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue re
}
/*
- * Set an existing own property obj[index] that's a dense element or typed
- * array element.
- */
-static bool
-SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
- ObjectOpResult& result)
-{
- if (obj->is<TypedArrayObject>()) {
- double d;
- if (!ToNumber(cx, v, &d))
- return false;
-
- // Silently do nothing for out-of-bounds sets, for consistency with
- // current behavior. (ES6 currently says to throw for this in
- // strict mode code, so we may eventually need to change.)
- uint32_t len = obj->as<TypedArrayObject>().length();
- if (index < len)
- TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
- return result.succeed();
- }
-
- if (WouldDefinePastNonwritableLength(obj, index))
- return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
-
- if (!obj->maybeCopyElementsForWrite(cx))
- return false;
-
- obj->setDenseElementWithType(cx, index, v);
- return result.succeed();
-}
-
-/*
* Finish the assignment `receiver[id] = v` when an existing property (shape)
* has been found on a native object (pobj). This implements ES6 draft rev 32
* (2015 Feb 2) 9.1.9 steps 5 and 6.
@@ -2416,8 +2385,14 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
return result.fail(JSMSG_READ_ONLY);
// Pure optimization for the common case:
- if (receiver.isObject() && pobj == &receiver.toObject())
- return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), v, result);
+ if (receiver.isObject() && pobj == &receiver.toObject()) {
+ uint32_t index = JSID_TO_INT(id);
+
+ if (pobj->is<TypedArrayObject>()) {
+ Rooted<TypedArrayObject*> tobj(cx, &pobj->as<TypedArrayObject>());
+ return SetTypedArrayElement(cx, tobj, index, v, result);
+ }
+ }
// Steps 5.b-f.
return SetPropertyByDefining(cx, id, v, receiver, result);
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
index c5865caa03..86977d109f 100644
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -18,6 +18,7 @@
#include "gc/Barrier.h"
#include "gc/Heap.h"
#include "gc/Marking.h"
+#include "js/RootingAPI.h"
#include "js/Value.h"
#include "vm/Shape.h"
#include "vm/ShapedObject.h"
@@ -1088,7 +1089,9 @@ class NativeObject : public ShapedObject
static inline void removeDenseElementForSparseIndex(ExclusiveContext* cx,
HandleNativeObject obj, uint32_t index);
- inline Value getDenseOrTypedArrayElement(uint32_t idx);
+ template <AllowGC allowGC> inline bool
+ getDenseOrTypedArrayElement(ExclusiveContext* cx, uint32_t idx,
+ typename MaybeRooted<Value, allowGC>::MutableHandleType val);
void copyDenseElements(uint32_t dstStart, const Value* src, uint32_t count) {
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index 741531f015..408e346608 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -686,6 +686,8 @@ GetClassForProtoKey(JSProtoKey key)
case JSProto_Float32Array:
case JSProto_Float64Array:
case JSProto_Uint8ClampedArray:
+ case JSProto_BigInt64Array:
+ case JSProto_BigUint64Array:
return &TypedArrayObject::classes[key - JSProto_Int8Array];
case JSProto_ArrayBuffer:
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index de497d02e1..e73e55d9a0 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -44,6 +44,7 @@
#include "jit/InlinableNatives.h"
#include "js/CharacterEncoding.h"
#include "js/Date.h"
+#include "vm/BigIntType.h"
#include "vm/Compression.h"
#include "vm/GeneratorObject.h"
#include "vm/Interpreter.h"
@@ -1182,6 +1183,18 @@ intrinsic_IsFloat32TypedArray(JSContext* cx, unsigned argc, Value* vp)
}
static bool
+intrinsic_IsBigInt64TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::BigInt64);
+}
+
+static bool
+intrinsic_IsBigUint64TypedArray(JSContext* cx, unsigned argc, Value* vp)
+{
+ return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::BigUint64);
+}
+
+static bool
intrinsic_TypedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
@@ -1521,6 +1534,14 @@ struct DisjointElements
CopyValues(dest, src.cast<double*>(), count);
return;
+ case Scalar::BigInt64:
+ CopyValues(dest, src.cast<int64_t*>(), count);
+ return;
+
+ case Scalar::BigUint64:
+ CopyValues(dest, src.cast<uint64_t*>(), count);
+ return;
+
case Scalar::Uint8Clamped:
CopyValues(dest, src.cast<uint8_clamped*>(), count);
return;
@@ -1579,6 +1600,16 @@ CopyToDisjointArray(TypedArrayObject* target, uint32_t targetOffset, SharedMem<v
break;
}
+ case Scalar::BigInt64: {
+ DisjointElements::copy(dest.cast<int64_t*>(), src, srcType, count);
+ break;
+ }
+
+ case Scalar::BigUint64: {
+ DisjointElements::copy(dest.cast<uint64_t*>(), src, srcType, count);
+ break;
+ }
+
case Scalar::Uint8Clamped: {
DisjointElements::copy(dest.cast<uint8_clamped*>(), src, srcType, count);
break;
@@ -2164,6 +2195,18 @@ intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+static bool intrinsic_ToBigInt(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ BigInt* res = ToBigInt(cx, args[0]);
+ if (!res) {
+ return false;
+ }
+ args.rval().setBigInt(res);
+ return true;
+}
+
// The self-hosting global isn't initialized with the normal set of builtins.
// Instead, individual C++-implemented functions that're required by
// self-hosted code are defined as global functions. Accessing these
@@ -2399,6 +2442,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("IsUint32TypedArray", intrinsic_IsUint32TypedArray, 1,0),
JS_FN("IsInt32TypedArray", intrinsic_IsInt32TypedArray, 1,0),
JS_FN("IsFloat32TypedArray", intrinsic_IsFloat32TypedArray, 1,0),
+ JS_FN("IsBigInt64TypedArray", intrinsic_IsBigInt64TypedArray, 1,0),
+ JS_FN("IsBigUint64TypedArray", intrinsic_IsBigUint64TypedArray, 1,0),
JS_INLINABLE_FN("IsTypedArray",
intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1,0,
IntrinsicIsTypedArray),
@@ -2591,6 +2636,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallPromiseMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2, 0),
JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
+ JS_FN("ToBigInt", intrinsic_ToBigInt, 1, 0),
+
JS_FS_END
};
diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
index ac73df30e6..e99cfe8f71 100644
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -121,7 +121,8 @@ enum StructuredDataType : uint32_t {
SCTAG_TYPED_ARRAY_V1_FLOAT32 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Float32,
SCTAG_TYPED_ARRAY_V1_FLOAT64 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Float64,
SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8Clamped,
- SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::MaxTypedArrayViewType - 1,
+ // BigInt64 and BigUint64 are not supported in the v1 format.
+ SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED,
/*
* Define a separate range of numbers for Transferable-only tags, since
@@ -1808,7 +1809,7 @@ bool
JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp,
bool v1Read)
{
- if (arrayType > Scalar::Uint8Clamped) {
+ if (arrayType > (v1Read ? Scalar::Uint8Clamped : Scalar::BigUint64)) {
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
"unhandled typed array element type");
return false;
@@ -1872,6 +1873,12 @@ JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, Mut
case Scalar::Uint8Clamped:
obj = JS_NewUint8ClampedArrayWithBuffer(context(), buffer, byteOffset, nelems);
break;
+ case Scalar::BigInt64:
+ obj = JS_NewBigInt64ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
+ case Scalar::BigUint64:
+ obj = JS_NewBigUint64ArrayWithBuffer(context(), buffer, byteOffset, nelems);
+ break;
default:
MOZ_CRASH("Can't happen: arrayType range checked above");
}
@@ -2007,6 +2014,8 @@ JSStructuredCloneReader::readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems,
case Scalar::Float32:
return in.readArray((uint32_t*) buffer.dataPointer(), nelems);
case Scalar::Float64:
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
return in.readArray((uint64_t*) buffer.dataPointer(), nelems);
default:
MOZ_CRASH("Can't happen: arrayType range checked by caller");
diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h
index eb7b94f109..8e66587a1e 100644
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -112,6 +112,20 @@ ConvertNumber<uint32_t, float>(float src)
return JS::ToUint32(src);
}
+template <>
+inline int64_t
+ConvertNumber<int64_t, float>(float src)
+{
+ return JS::ToInt64(src);
+}
+
+template <>
+inline uint64_t
+ConvertNumber<uint64_t, float>(float src)
+{
+ return JS::ToUint64(src);
+}
+
template<> inline int8_t
ConvertNumber<int8_t, double>(double src)
{
@@ -160,6 +174,20 @@ ConvertNumber<uint32_t, double>(double src)
return JS::ToUint32(src);
}
+template <>
+inline int64_t
+ConvertNumber<int64_t, double>(double src)
+{
+ return JS::ToInt64(src);
+}
+
+template <>
+inline uint64_t
+ConvertNumber<uint64_t, double>(double src)
+{
+ return JS::ToUint64(src);
+}
+
template<typename To, typename From>
inline To
ConvertNumber(From src)
@@ -178,6 +206,8 @@ template<> struct TypeIDOfType<int16_t> { static const Scalar::Type id = Scalar:
template<> struct TypeIDOfType<uint16_t> { static const Scalar::Type id = Scalar::Uint16; };
template<> struct TypeIDOfType<int32_t> { static const Scalar::Type id = Scalar::Int32; };
template<> struct TypeIDOfType<uint32_t> { static const Scalar::Type id = Scalar::Uint32; };
+template<> struct TypeIDOfType<int64_t> { static const Scalar::Type id = Scalar::BigInt64; };
+template<> struct TypeIDOfType<uint64_t> { static const Scalar::Type id = Scalar::BigUint64; };
template<> struct TypeIDOfType<float> { static const Scalar::Type id = Scalar::Float32; };
template<> struct TypeIDOfType<double> { static const Scalar::Type id = Scalar::Float64; };
template<> struct TypeIDOfType<uint8_clamped> { static const Scalar::Type id = Scalar::Uint8Clamped; };
@@ -355,6 +385,18 @@ class ElementSpecific
Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
break;
}
+ case Scalar::BigInt64: {
+ SharedMem<int64_t*> src = data.cast<int64_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
+ case Scalar::BigUint64: {
+ SharedMem<uint64_t*> src = data.cast<uint64_t*>();
+ for (uint32_t i = 0; i < count; ++i)
+ Ops::store(dest++, ConvertNumber<T>(Ops::load(src++)));
+ break;
+ }
case Scalar::Float32: {
SharedMem<JS_VOLATILE_ARM float*> src = data.cast<JS_VOLATILE_ARM float*>();
for (uint32_t i = 0; i < count; ++i)
@@ -399,12 +441,12 @@ class ElementSpecific
SharedMem<T*> dest =
target->template as<TypedArrayObject>().viewDataEither().template cast<T*>() + offset;
- MOZ_ASSERT(!canConvertInfallibly(MagicValue(JS_ELEMENTS_HOLE)),
+ MOZ_ASSERT(!canConvertInfallibly(MagicValue(JS_ELEMENTS_HOLE), target->type()),
"the following loop must abort on holes");
const Value* srcValues = source->as<NativeObject>().getDenseElements();
for (; i < bound; i++) {
- if (!canConvertInfallibly(srcValues[i]))
+ if (!canConvertInfallibly(srcValues[i], target->type()))
break;
Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
}
@@ -459,7 +501,7 @@ class ElementSpecific
const Value* srcValues = source->getDenseElements();
for (; i < len; i++) {
- if (!canConvertInfallibly(srcValues[i]))
+ if (!canConvertInfallibly(srcValues[i], target->type()))
break;
Ops::store(dest + i, infallibleValueToNative(srcValues[i]));
}
@@ -568,6 +610,18 @@ class ElementSpecific
Ops::store(dest++, ConvertNumber<T>(*src++));
break;
}
+ case Scalar::BigInt64: {
+ int64_t* src = static_cast<int64_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
+ case Scalar::BigUint64: {
+ uint64_t* src = static_cast<uint64_t*>(data);
+ for (uint32_t i = 0; i < len; ++i)
+ Ops::store(dest++, ConvertNumber<T>(*src++));
+ break;
+ }
case Scalar::Float32: {
float* src = static_cast<float*>(data);
for (uint32_t i = 0; i < len; ++i)
@@ -589,8 +643,11 @@ class ElementSpecific
}
static bool
- canConvertInfallibly(const Value& v)
+ canConvertInfallibly(const Value& v, Scalar::Type type)
{
+ if (type == Scalar::BigInt64 || type == Scalar::BigUint64) {
+ return false;
+ }
return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined();
}
@@ -615,11 +672,21 @@ class ElementSpecific
{
MOZ_ASSERT(!v.isMagic());
- if (MOZ_LIKELY(canConvertInfallibly(v))) {
+ if (MOZ_LIKELY(canConvertInfallibly(v, TypeIDOfType<T>::id))) {
*result = infallibleValueToNative(v);
return true;
}
+ if (std::is_same<T, int64_t>::value) {
+ JS_TRY_VAR_OR_RETURN_FALSE(cx, *result, ToBigInt64(cx, v));
+ return true;
+ }
+
+ if (std::is_same<T, uint64_t>::value) {
+ JS_TRY_VAR_OR_RETURN_FALSE(cx, *result, ToBigUint64(cx, v));
+ return true;
+ }
+
double d;
MOZ_ASSERT(v.isString() || v.isObject() || v.isSymbol());
if (!(v.isString() ? StringToNumber(cx, v.toString(), &d) : ToNumber(cx, v, &d)))
@@ -668,6 +735,8 @@ class TypedArrayMethods
typedef typename SomeTypedArray::template OfType<uint16_t>::Type Uint16ArrayType;
typedef typename SomeTypedArray::template OfType<int32_t>::Type Int32ArrayType;
typedef typename SomeTypedArray::template OfType<uint32_t>::Type Uint32ArrayType;
+ typedef typename SomeTypedArray::template OfType<int64_t>::Type BigInt64ArrayType;
+ typedef typename SomeTypedArray::template OfType<uint64_t>::Type BigUint64ArrayType;
typedef typename SomeTypedArray::template OfType<float>::Type Float32ArrayType;
typedef typename SomeTypedArray::template OfType<double>::Type Float64ArrayType;
typedef typename SomeTypedArray::template OfType<uint8_clamped>::Type Uint8ClampedArrayType;
@@ -759,6 +828,14 @@ class TypedArrayMethods
if (isShared)
return ElementSpecific<Uint32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::BigInt64:
+ if (isShared)
+ return ElementSpecific<BigInt64ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<BigInt64ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
+ case Scalar::BigUint64:
+ if (isShared)
+ return ElementSpecific<BigUint64ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
+ return ElementSpecific<BigUint64ArrayType, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
case Scalar::Float32:
if (isShared)
return ElementSpecific<Float32ArrayType, SharedOps>::setFromTypedArray(cx, target, source, offset);
@@ -816,6 +893,14 @@ class TypedArrayMethods
if (isShared)
return ElementSpecific<Uint32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
return ElementSpecific<Uint32ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::BigInt64:
+ if (isShared)
+ return ElementSpecific<BigInt64ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<BigInt64ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ case Scalar::BigUint64:
+ if (isShared)
+ return ElementSpecific<BigUint64ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
+ return ElementSpecific<BigUint64ArrayType, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
case Scalar::Float32:
if (isShared)
return ElementSpecific<Float32ArrayType, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
@@ -870,6 +955,14 @@ class TypedArrayMethods
if (isShared)
return ElementSpecific<Uint32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
return ElementSpecific<Uint32ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::BigInt64:
+ if (isShared)
+ return ElementSpecific<BigInt64ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<BigInt64ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
+ case Scalar::BigUint64:
+ if (isShared)
+ return ElementSpecific<BigUint64ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
+ return ElementSpecific<BigUint64ArrayType, UnsharedOps>::initFromIterablePackedArray(cx, target, source);
case Scalar::Float32:
if (isShared)
return ElementSpecific<Float32ArrayType, SharedOps>::initFromIterablePackedArray(cx, target, source);
diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
index ac93ec9b14..28e4090eb8 100644
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -65,6 +65,33 @@ using JS::ToUint32;
* the subclasses.
*/
+bool TypedArrayObject::convertForSideEffect(JSContext* cx, HandleValue v) const
+{
+ switch (type()) {
+ case Scalar::BigInt64:
+ case Scalar::BigUint64: {
+ return ToBigInt(cx, v) != nullptr;
+ }
+ case Scalar::Int8:
+ case Scalar::Uint8:
+ case Scalar::Int16:
+ case Scalar::Uint16:
+ case Scalar::Int32:
+ case Scalar::Uint32:
+ case Scalar::Float32:
+ case Scalar::Float64:
+ case Scalar::Uint8Clamped: {
+ double ignore;
+ return ToNumber(cx, v, &ignore);
+ }
+ case Scalar::MaxTypedArrayViewType:
+ case Scalar::Int64:
+ MOZ_CRASH("Unsupported TypedArray type");
+ }
+ MOZ_ASSERT_UNREACHABLE("Invalid scalar type");
+ return false;
+}
+
/* static */ int
TypedArrayObject::lengthOffset()
{
@@ -414,30 +441,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return v.isObject() && v.toObject().hasClass(instanceClass());
}
- static void
- setIndexValue(TypedArrayObject& tarray, uint32_t index, double d)
- {
- // If the array is an integer array, we only handle up to
- // 32-bit ints from this point on. if we want to handle
- // 64-bit ints, we'll need some changes.
-
- // Assign based on characteristics of the destination type
- if (ArrayTypeIsFloatingPoint()) {
- setIndex(tarray, index, NativeType(d));
- } else if (ArrayTypeIsUnsigned()) {
- MOZ_ASSERT(sizeof(NativeType) <= 4);
- uint32_t n = ToUint32(d);
- setIndex(tarray, index, NativeType(n));
- } else if (ArrayTypeID() == Scalar::Uint8Clamped) {
- // The uint8_clamped type has a special rounding converter
- // for doubles.
- setIndex(tarray, index, NativeType(d));
- } else {
- MOZ_ASSERT(sizeof(NativeType) <= 4);
- int32_t n = ToInt32(d);
- setIndex(tarray, index, NativeType(n));
- }
- }
+ static bool convertValue(JSContext* cx, HandleValue v, NativeType* result);
static TypedArrayObject*
makeProtoInstance(JSContext* cx, HandleObject proto, AllocKind allocKind)
@@ -1001,9 +1005,128 @@ class TypedArrayObjectTemplate : public TypedArrayObject
jit::AtomicOperations::storeSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>() + index, val);
}
- static Value getIndexValue(JSObject* tarray, uint32_t index);
+ static bool getElement(ExclusiveContext* cx, TypedArrayObject* tarray, uint32_t index, MutableHandleValue val);
+ static bool getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp);
+
+ static bool setElement(JSContext* cx, Handle<TypedArrayObject*> obj, uint64_t index, HandleValue v,
+ ObjectOpResult& result);
+ static bool defineElement(JSContext* cx, HandleObject obj, uint64_t index, HandleValue v,
+ ObjectOpResult& result);
};
+template <typename NativeType>
+bool TypedArrayObjectTemplate<NativeType>::convertValue(JSContext* cx, HandleValue v, NativeType* result)
+{
+ double d;
+ if (!ToNumber(cx, v, &d)) {
+ return false;
+ }
+
+#ifdef JS_MORE_DETERMINISTIC
+ // See the comment in ElementSpecific::doubleToNative.
+ d = JS::CanonicalizeNaN(d);
+#endif
+
+ // Assign based on characteristics of the destination type
+ if (ArrayTypeIsFloatingPoint()) {
+ *result = NativeType(d);
+ } else if (ArrayTypeIsUnsigned()) {
+ MOZ_ASSERT(sizeof(NativeType) <= 4);
+ uint32_t n = ToUint32(d);
+ *result = NativeType(n);
+ } else if (ArrayTypeID() == Scalar::Uint8Clamped) {
+ // The uint8_clamped type has a special rounding converter
+ // for doubles.
+ *result = NativeType(d);
+ } else {
+ MOZ_ASSERT(sizeof(NativeType) <= 4);
+ int32_t n = ToInt32(d);
+ *result = NativeType(n);
+ }
+ return true;
+}
+
+template <>
+bool TypedArrayObjectTemplate<int64_t>::convertValue(JSContext* cx, HandleValue v, int64_t* result)
+{
+ JS_TRY_VAR_OR_RETURN_FALSE(cx, *result, ToBigInt64(cx, v));
+ return true;
+}
+
+template <>
+bool TypedArrayObjectTemplate<uint64_t>::convertValue(JSContext* cx, HandleValue v, uint64_t* result)
+{
+ JS_TRY_VAR_OR_RETURN_FALSE(cx, *result, ToBigUint64(cx, v));
+ return true;
+}
+
+// https://tc39.github.io/proposal-bigint/#sec-integerindexedelementset
+// 7.8 IntegerIndexedElementSet ( O, index, value )
+template <typename NativeType>
+/* static */ bool TypedArrayObjectTemplate<NativeType>::setElement(
+ JSContext* cx, Handle<TypedArrayObject*> obj, uint64_t index, HandleValue v,
+ ObjectOpResult& result)
+{
+ // Steps 1-2 are enforced by the caller.
+
+ // Steps 3-6.
+ NativeType nativeValue;
+ if (!convertValue(cx, v, &nativeValue)) {
+ return false;
+ }
+
+ // Step 8.
+ if (obj->hasDetachedBuffer()) {
+ return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
+ }
+
+ // Steps 9-10 are enforced by the caller.
+
+ // Step 11.
+ uint32_t length = obj->length();
+
+ // Step 12.
+ if (index >= length) {
+ return result.failSoft(JSMSG_BAD_INDEX);
+ }
+
+ // Steps 7, 13-16.
+ TypedArrayObjectTemplate<NativeType>::setIndex(*obj, index, nativeValue);
+
+ // Step 17.
+ return result.succeed();
+}
+
+// Version of IntegerIndexedElementSet with no length check, used in
+// [[DefineOwnProperty]]
+template <typename NativeType>
+/* static */ bool TypedArrayObjectTemplate<NativeType>::defineElement(
+ JSContext* cx, HandleObject obj, uint64_t index, HandleValue v,
+ ObjectOpResult& result)
+{
+ // Steps 1-2 are enforced by the caller.
+
+ // Steps 3-6.
+ NativeType nativeValue;
+ if (!convertValue(cx, v, &nativeValue)) {
+ return false;
+ }
+
+ // Step 8.
+ if (obj->as<TypedArrayObject>().hasDetachedBuffer()) {
+ return result.fail(JSMSG_TYPED_ARRAY_DETACHED);
+ }
+
+ // Steps 9-12 are enforced by the caller.
+
+ // Steps 7, 13-16.
+ TypedArrayObjectTemplate<NativeType>::setIndex(obj->as<TypedArrayObject>(),
+ index, nativeValue);
+
+ // Step 17.
+ return result.succeed();
+}
+
#define CREATE_TYPE_FOR_TYPED_ARRAY(T, N) \
typedef TypedArrayObjectTemplate<T> N##Array;
JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPE_FOR_TYPED_ARRAY)
@@ -1240,6 +1363,13 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
}
}
+ // BigInt proposal 7.24, step 19.c.
+ if (Scalar::isBigIntType(ArrayTypeID()) !=
+ Scalar::isBigIntType(srcArray->type())) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_BIGINT);
+ return nullptr;
+ }
+
// Steps 3-4 (remaining part), 18-21.
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, elementLength, proto));
if (!obj)
@@ -1584,40 +1714,43 @@ ArrayBufferObject::createTypedArrayFromBuffer(JSContext* cx, unsigned argc, Valu
return CallNonGenericMethod<IsAnyArrayBuffer, createTypedArrayFromBufferImpl<T> >(cx, args);
}
-// this default implementation is only valid for integer types
-// less than 32-bits in size.
+// This default implementation is only valid for integer types less
+// than 32-bits in size.
template<typename NativeType>
-Value
-TypedArrayObjectTemplate<NativeType>::getIndexValue(JSObject* tarray, uint32_t index)
+bool
+TypedArrayObjectTemplate<NativeType>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
{
static_assert(sizeof(NativeType) < 4,
"this method must only handle NativeType values that are "
"always exact int32_t values");
- return Int32Value(getIndex(tarray, index));
+ *vp = Int32Value(getIndex(tarray, index));
+ return true;
}
namespace {
-// and we need to specialize for 32-bit integers and floats
+// We need to specialize for floats and other integer types.
template<>
-Value
-TypedArrayObjectTemplate<int32_t>::getIndexValue(JSObject* tarray, uint32_t index)
+bool
+TypedArrayObjectTemplate<int32_t>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
{
- return Int32Value(getIndex(tarray, index));
+ *vp = Int32Value(getIndex(tarray, index));
+ return true;
}
template<>
-Value
-TypedArrayObjectTemplate<uint32_t>::getIndexValue(JSObject* tarray, uint32_t index)
+bool
+TypedArrayObjectTemplate<uint32_t>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
{
uint32_t val = getIndex(tarray, index);
- return NumberValue(val);
+ *vp = NumberValue(val);
+ return true;
}
template<>
-Value
-TypedArrayObjectTemplate<float>::getIndexValue(JSObject* tarray, uint32_t index)
+bool
+TypedArrayObjectTemplate<float>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
{
float val = getIndex(tarray, index);
double dval = val;
@@ -1632,12 +1765,13 @@ TypedArrayObjectTemplate<float>::getIndexValue(JSObject* tarray, uint32_t index)
* This could be removed for platforms/compilers known to convert a 32-bit
* non-canonical nan to a 64-bit canonical nan.
*/
- return DoubleValue(CanonicalizeNaN(dval));
+ *vp = DoubleValue(CanonicalizeNaN(dval));
+ return true;
}
template<>
-Value
-TypedArrayObjectTemplate<double>::getIndexValue(JSObject* tarray, uint32_t index)
+bool
+TypedArrayObjectTemplate<double>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
{
double val = getIndex(tarray, index);
@@ -1648,9 +1782,60 @@ TypedArrayObjectTemplate<double>::getIndexValue(JSObject* tarray, uint32_t index
* confuse the engine into interpreting a double-typed jsval as an
* object-typed jsval.
*/
- return DoubleValue(CanonicalizeNaN(val));
+ *vp = DoubleValue(CanonicalizeNaN(val));
+ return true;
+}
+
+template <>
+bool
+TypedArrayObjectTemplate<int64_t>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
+{
+ return false;
}
+template <>
+bool
+TypedArrayObjectTemplate<uint64_t>::getElementPure(TypedArrayObject* tarray, uint32_t index, Value* vp)
+{
+ return false;
+}
+} /* anonymous namespace */
+
+namespace {
+
+template <typename NativeType>
+bool TypedArrayObjectTemplate<NativeType>::getElement(ExclusiveContext* cx, TypedArrayObject* tarray, uint32_t index,
+ MutableHandleValue val)
+{
+ MOZ_ALWAYS_TRUE(getElementPure(tarray, index, val.address()));
+ return true;
+}
+
+template <>
+bool TypedArrayObjectTemplate<int64_t>::getElement(ExclusiveContext* cx, TypedArrayObject* tarray, uint32_t index,
+ MutableHandleValue val)
+{
+ int64_t n = getIndex(tarray, index);
+ BigInt* res = BigInt::createFromInt64(cx, n);
+ if (!res) {
+ return false;
+ }
+ val.setBigInt(res);
+ return true;
+}
+
+template <>
+bool TypedArrayObjectTemplate<uint64_t>::getElement(ExclusiveContext* cx, TypedArrayObject* tarray, uint32_t index,
+ MutableHandleValue val)
+{
+ uint64_t n = getIndex(tarray, index);
+ BigInt* res = BigInt::createFromUint64(cx, n);
+ if (!res) {
+ return false;
+ }
+ val.setBigInt(res);
+ return true;
+}
} /* anonymous namespace */
static NewObjectKind
@@ -2544,28 +2729,17 @@ DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp)
return CallNonGenericMethod<is, setFloat64Impl>(cx, args);
}
-Value
-TypedArrayObject::getElement(uint32_t index)
+namespace js {
+
+template <>
+bool TypedArrayObject::getElement<CanGC>(ExclusiveContext* cx, uint32_t index, MutableHandleValue val)
{
switch (type()) {
- case Scalar::Int8:
- return Int8Array::getIndexValue(this, index);
- case Scalar::Uint8:
- return Uint8Array::getIndexValue(this, index);
- case Scalar::Int16:
- return Int16Array::getIndexValue(this, index);
- case Scalar::Uint16:
- return Uint16Array::getIndexValue(this, index);
- case Scalar::Int32:
- return Int32Array::getIndexValue(this, index);
- case Scalar::Uint32:
- return Uint32Array::getIndexValue(this, index);
- case Scalar::Float32:
- return Float32Array::getIndexValue(this, index);
- case Scalar::Float64:
- return Float64Array::getIndexValue(this, index);
- case Scalar::Uint8Clamped:
- return Uint8ClampedArray::getIndexValue(this, index);
+#define GET_ELEMENT(T, N) \
+ case Scalar::N: \
+ return N##Array::getElement(cx, this, index, val);
+ JS_FOR_EACH_TYPED_ARRAY(GET_ELEMENT)
+#undef GET_ELEMENT
case Scalar::Int64:
case Scalar::Float32x4:
case Scalar::Int8x16:
@@ -2578,44 +2752,23 @@ TypedArrayObject::getElement(uint32_t index)
MOZ_CRASH("Unknown TypedArray type");
}
-void
-TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
-{
- MOZ_ASSERT(index < obj.length());
+template <>
+bool TypedArrayObject::getElement<NoGC>(
+ ExclusiveContext* cx, uint32_t index,
+ typename MaybeRooted<Value, NoGC>::MutableHandleType vp) {
+ return getElementPure(index, vp.address());
+}
-#ifdef JS_MORE_DETERMINISTIC
- // See the comment in ElementSpecific::doubleToNative.
- d = JS::CanonicalizeNaN(d);
-#endif
+} // namespace js
- switch (obj.type()) {
- case Scalar::Int8:
- Int8Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Uint8:
- Uint8Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Uint8Clamped:
- Uint8ClampedArray::setIndexValue(obj, index, d);
- return;
- case Scalar::Int16:
- Int16Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Uint16:
- Uint16Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Int32:
- Int32Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Uint32:
- Uint32Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Float32:
- Float32Array::setIndexValue(obj, index, d);
- return;
- case Scalar::Float64:
- Float64Array::setIndexValue(obj, index, d);
- return;
+bool TypedArrayObject::getElementPure(uint32_t index, Value* vp)
+{
+ switch (type()) {
+#define GET_ELEMENT_PURE(T, N) \
+ case Scalar::N: \
+ return N##Array::getElementPure(this, index, vp);
+ JS_FOR_EACH_TYPED_ARRAY(GET_ELEMENT_PURE)
+#undef GET_ELEMENT
case Scalar::Int64:
case Scalar::Float32x4:
case Scalar::Int8x16:
@@ -2628,6 +2781,38 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
MOZ_CRASH("Unknown TypedArray type");
}
+/* static */
+bool TypedArrayObject::getElements(JSContext* cx, Handle<TypedArrayObject*> tarray, Value* vp)
+{
+ uint32_t length = tarray->length();
+ MOZ_ASSERT_IF(length > 0, !tarray->hasDetachedBuffer());
+
+ switch (tarray->type()) {
+#define GET_ELEMENTS(T, N) \
+ case Scalar::N: \
+ for (uint32_t i = 0; i < length; ++i, ++vp) { \
+ if (!N##Array::getElement(cx, tarray, i, \
+ MutableHandleValue::fromMarkedLocation(vp))) { \
+ return false; \
+ } \
+ } \
+ return true;
+ JS_FOR_EACH_TYPED_ARRAY(GET_ELEMENTS)
+#undef GET_ELEMENTS
+ default:
+ MOZ_CRASH("Unknown TypedArray type");
+ case Scalar::MaxTypedArrayViewType:
+ case Scalar::Int64:
+ case Scalar::Float32x4:
+ case Scalar::Int8x16:
+ case Scalar::Int16x8:
+ case Scalar::Int32x4:
+ break;
+ }
+
+ MOZ_CRASH("Unknown TypedArray type");
+}
+
/***
*** JS impl
***/
@@ -2680,6 +2865,8 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32, int32_t)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint32, uint32_t)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32, float)
IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(BigInt64, int64_t)
+IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(BigUint64, uint64_t)
#define IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Name, ExternalType, InternalType) \
JS_FRIEND_API(JSObject*) JS_GetObjectAs ## Name ## Array(JSObject* obj, \
@@ -2711,6 +2898,8 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(BigInt64, int64_t, int64_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(BigUint64, uint32_t, uint64_t)
static const ClassOps TypedArrayClassOps = {
nullptr, /* addProperty */
@@ -2748,7 +2937,9 @@ static const JSPropertySpec static_prototype_properties[Scalar::MaxTypedArrayVie
IMPL_TYPED_ARRAY_PROPERTIES(Uint32),
IMPL_TYPED_ARRAY_PROPERTIES(Float32),
IMPL_TYPED_ARRAY_PROPERTIES(Float64),
- IMPL_TYPED_ARRAY_PROPERTIES(Uint8Clamped)
+ IMPL_TYPED_ARRAY_PROPERTIES(Uint8Clamped),
+ IMPL_TYPED_ARRAY_PROPERTIES(BigInt64),
+ IMPL_TYPED_ARRAY_PROPERTIES(BigUint64)
};
#define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \
@@ -2772,7 +2963,9 @@ static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType]
IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),
IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),
IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),
- IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)
+ IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(BigInt64),
+ IMPL_TYPED_ARRAY_CLASS_SPEC(BigUint64)
};
#define IMPL_TYPED_ARRAY_CLASS(_type) \
@@ -2798,7 +2991,9 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
IMPL_TYPED_ARRAY_CLASS(Uint32),
IMPL_TYPED_ARRAY_CLASS(Float32),
IMPL_TYPED_ARRAY_CLASS(Float64),
- IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)
+ IMPL_TYPED_ARRAY_CLASS(Uint8Clamped),
+ IMPL_TYPED_ARRAY_CLASS(BigInt64),
+ IMPL_TYPED_ARRAY_CLASS(BigUint64)
};
#define IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(_type) \
@@ -2822,7 +3017,9 @@ static const ClassSpec TypedArrayObjectProtoClassSpecs[Scalar::MaxTypedArrayView
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint32),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float32),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float64),
- IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8Clamped)
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8Clamped),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(BigInt64),
+ IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(BigUint64)
};
// The various typed array prototypes are supposed to 1) be normal objects,
@@ -2856,7 +3053,9 @@ const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),
IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),
IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),
- IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)
+ IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(BigInt64),
+ IMPL_TYPED_ARRAY_PROTO_CLASS(BigUint64)
};
/* static */ bool
@@ -3112,6 +3311,25 @@ js::StringIsTypedArrayIndex(const char16_t* s, size_t length, uint64_t* indexp);
template bool
js::StringIsTypedArrayIndex(const Latin1Char* s, size_t length, uint64_t* indexp);
+bool js::SetTypedArrayElement(JSContext* cx, Handle<TypedArrayObject*> obj,
+ uint64_t index, HandleValue v, ObjectOpResult& result)
+{
+ TypedArrayObject* tobj = &obj->as<TypedArrayObject>();
+
+ switch (tobj->type()) {
+#define SET_TYPED_ARRAY_ELEMENT(T, N) \
+ case Scalar::N: \
+ return TypedArrayObjectTemplate<T>::setElement(cx, obj, index, v, result);
+ JS_FOR_EACH_TYPED_ARRAY(SET_TYPED_ARRAY_ELEMENT)
+#undef SET_TYPED_ARRAY_ELEMENT
+ case Scalar::MaxTypedArrayViewType:
+ case Scalar::Int64:
+ break;
+ }
+
+ MOZ_CRASH("Unsupported TypedArray type");
+}
+
/* ES6 draft rev 34 (2015 Feb 20) 9.4.5.3 [[DefineOwnProperty]] step 3.c. */
bool
js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
@@ -3147,22 +3365,18 @@ js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
// Step x.
if (desc.hasValue()) {
- // The following step numbers refer to 9.4.5.9
- // IntegerIndexedElementSet.
-
- // Steps 1-2 are enforced by the caller.
-
- // Step 3.
- double numValue;
- if (!ToNumber(cx, desc.value(), &numValue))
- return false;
-
- // Steps 4-5, 8-9.
- if (obj->as<TypedArrayObject>().hasDetachedBuffer())
- return result.fail(JSMSG_TYPED_ARRAY_DETACHED);
-
- // Steps 10-16.
- TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, numValue);
+ TypedArrayObject* tobj = &obj->as<TypedArrayObject>();
+ switch (tobj->type()) {
+#define DEFINE_TYPED_ARRAY_ELEMENT(T, N) \
+ case Scalar::N: \
+ return TypedArrayObjectTemplate<T>::defineElement(cx, obj, index, \
+ desc.value(), result);
+ JS_FOR_EACH_TYPED_ARRAY(DEFINE_TYPED_ARRAY_ELEMENT)
+#undef DEFINE_TYPED_ARRAY_ELEMENT
+ case Scalar::MaxTypedArrayViewType:
+ case Scalar::Int64:
+ break;
+ }
}
// Step xii.
diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h
index 196d347075..06aaea0617 100644
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -24,7 +24,9 @@
macro(uint32_t, Uint32) \
macro(float, Float32) \
macro(double, Float64) \
- macro(uint8_clamped, Uint8Clamped)
+ macro(uint8_clamped, Uint8Clamped) \
+ macro(int64_t, BigInt64) \
+ macro(uint64_t, BigUint64)
typedef struct JSProperty JSProperty;
@@ -183,8 +185,12 @@ class TypedArrayObject : public NativeObject
void assertZeroLengthArrayData() const {};
#endif
- Value getElement(uint32_t index);
- static void setElement(TypedArrayObject& obj, uint32_t index, double d);
+ template <AllowGC allowGC>
+ bool getElement(ExclusiveContext* cx, uint32_t index,
+ typename MaybeRooted<Value, allowGC>::MutableHandleType val);
+ bool getElementPure(uint32_t index, Value* vp);
+
+ static bool getElements(JSContext* cx, Handle<TypedArrayObject*> tarray, Value* vp);
void notifyBufferDetached(JSContext* cx, void* newData);
@@ -306,6 +312,8 @@ class TypedArrayObject : public NativeObject
static bool is(HandleValue v);
static bool set(JSContext* cx, unsigned argc, Value* vp);
+
+ bool convertForSideEffect(JSContext* cx, HandleValue v) const;
};
MOZ_MUST_USE bool TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp);
@@ -373,6 +381,10 @@ IsTypedArrayIndex(jsid id, uint64_t* indexp)
return StringIsTypedArrayIndex(s, length, indexp);
}
+bool SetTypedArrayElement(JSContext* cx, Handle<TypedArrayObject*> obj,
+ uint64_t index, HandleValue v,
+ ObjectOpResult& result);
+
/*
* Implements [[DefineOwnProperty]] for TypedArrays when the property
* key is a TypedArray index.
@@ -396,6 +408,8 @@ TypedArrayShift(Scalar::Type viewType)
case Scalar::Uint32:
case Scalar::Float32:
return 2;
+ case Scalar::BigInt64:
+ case Scalar::BigUint64:
case Scalar::Int64:
case Scalar::Float64:
return 3;