mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-25 16:47:29 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
65de5a7185
57 changed files with 1144 additions and 341 deletions
|
|
@ -2509,6 +2509,10 @@ var Debugger =
|
|||
|
||||
var Attribute = _require9.Attribute;
|
||||
|
||||
var _require23 = __webpack_require__(460);
|
||||
|
||||
var BigInt = _require23.BigInt;
|
||||
|
||||
var _require10 = __webpack_require__(47);
|
||||
|
||||
var DateTime = _require10.DateTime;
|
||||
|
|
@ -2565,7 +2569,7 @@ var Debugger =
|
|||
// XXX there should be a way for extensions to register a new
|
||||
// or modify an existing rep.
|
||||
|
||||
var reps = [RegExp, StyleSheet, Event, DateTime, TextNode, Attribute, Func, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, GripArray, GripMap, Grip, Undefined, Null, StringRep, Number, SymbolRep];
|
||||
var reps = [RegExp, StyleSheet, Event, DateTime, TextNode, Attribute, Func, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, GripArray, GripMap, Grip, Undefined, Null, StringRep, Number, BigInt, SymbolRep];
|
||||
|
||||
/**
|
||||
* Generic rep that is using for rendering native JS types or an object.
|
||||
|
|
@ -2605,10 +2609,12 @@ var Debugger =
|
|||
var defaultRep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Obj;
|
||||
|
||||
var type = typeof object;
|
||||
if (type == "object" && object instanceof String) {
|
||||
type = "string";
|
||||
} else if (type == "object" && object.type === "symbol") {
|
||||
type = "symbol";
|
||||
if (type == "object") {
|
||||
if (object instanceof String) {
|
||||
type = "string";
|
||||
} else if (["symbol", "BigInt"].includes(object.type)) {
|
||||
type = object.type;
|
||||
}
|
||||
}
|
||||
|
||||
if (isGrip(object)) {
|
||||
|
|
@ -58325,6 +58331,59 @@ var Debugger =
|
|||
setBundle
|
||||
};
|
||||
|
||||
/***/ },
|
||||
/* 460 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Make this available to both AMD and CJS environments
|
||||
|
||||
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
|
||||
// Dependencies
|
||||
var React = __webpack_require__(2);
|
||||
|
||||
// Shortcuts
|
||||
var span = React.DOM.span;
|
||||
|
||||
/**
|
||||
* Renders a number
|
||||
*/
|
||||
|
||||
var BigInt = React.createClass({
|
||||
displayName: "BigInt",
|
||||
|
||||
propTypes: {
|
||||
object: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let {object} = this.props;
|
||||
let {text} = object;
|
||||
|
||||
return span({ className: "objectBox objectBox-number" }, `${text}n`);
|
||||
}
|
||||
});
|
||||
|
||||
function supportsObject(object, type) {
|
||||
return type == "BigInt";
|
||||
}
|
||||
|
||||
// Exports from this module
|
||||
|
||||
exports.BigInt = {
|
||||
rep: BigInt,
|
||||
supportsObject: supportsObject
|
||||
};
|
||||
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||||
|
||||
|
||||
/***/ }
|
||||
/******/ ]);
|
||||
//# sourceMappingURL=bundle.js.map
|
||||
|
|
|
|||
48
devtools/client/shared/components/reps/big-int.js
Normal file
48
devtools/client/shared/components/reps/big-int.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Make this available to both AMD and CJS environments
|
||||
define(function (require, exports, module) {
|
||||
// Dependencies
|
||||
const React = require("devtools/client/shared/vendor/react");
|
||||
|
||||
// Shortcuts
|
||||
const { span } = React.DOM;
|
||||
|
||||
/**
|
||||
* Renders a BigInt
|
||||
*/
|
||||
const BigInt = React.createClass({
|
||||
displayName: "BigInt",
|
||||
|
||||
propTypes: {
|
||||
object: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let {object} = this.props;
|
||||
let {text} = object;
|
||||
|
||||
return (
|
||||
span({className: "objectBox objectBox-number"},
|
||||
`${text}n`
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function supportsObject(object, type) {
|
||||
return (type == "BigInt");
|
||||
}
|
||||
|
||||
// Exports from this module
|
||||
|
||||
exports.BigInt = {
|
||||
rep: BigInt,
|
||||
supportsObject: supportsObject
|
||||
};
|
||||
});
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
DevToolsModules(
|
||||
'array.js',
|
||||
'attribute.js',
|
||||
'big-int.js',
|
||||
'caption.js',
|
||||
'comment-node.js',
|
||||
'date-time.js',
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ define(function (require, exports, module) {
|
|||
|
||||
// DOM types (grips)
|
||||
const { Attribute } = require("./attribute");
|
||||
const { BigInt } = require("./big-int");
|
||||
const { DateTime } = require("./date-time");
|
||||
const { Document } = require("./document");
|
||||
const { Event } = require("./event");
|
||||
|
|
@ -70,6 +71,7 @@ define(function (require, exports, module) {
|
|||
Null,
|
||||
StringRep,
|
||||
Number,
|
||||
BigInt,
|
||||
SymbolRep,
|
||||
InfinityRep,
|
||||
NaNRep,
|
||||
|
|
@ -111,10 +113,12 @@ define(function (require, exports, module) {
|
|||
*/
|
||||
function getRep(object, defaultRep = Obj) {
|
||||
let type = typeof object;
|
||||
if (type == "object" && object instanceof String) {
|
||||
type = "string";
|
||||
} else if (object && type == "object" && object.type) {
|
||||
type = object.type;
|
||||
if (type == "object") {
|
||||
if (object instanceof String) {
|
||||
type = "string";
|
||||
} else if (["symbol", "BigInt"].includes(object.type)) {
|
||||
type = object.type;
|
||||
}
|
||||
}
|
||||
|
||||
if (isGrip(object)) {
|
||||
|
|
|
|||
|
|
@ -3236,14 +3236,6 @@ VariablesView.prototype.isOverridden = function (aItem) {
|
|||
* The variable's descriptor.
|
||||
*/
|
||||
VariablesView.isPrimitive = function (aDescriptor) {
|
||||
// For accessor property descriptors, the getter and setter need to be
|
||||
// contained in 'get' and 'set' properties.
|
||||
let getter = aDescriptor.get;
|
||||
let setter = aDescriptor.set;
|
||||
if (getter || setter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// As described in the remote debugger protocol, the value grip
|
||||
// must be contained in a 'value' property.
|
||||
let grip = aDescriptor.value;
|
||||
|
|
@ -3261,7 +3253,8 @@ VariablesView.isPrimitive = function (aDescriptor) {
|
|||
type == "NaN" ||
|
||||
type == "-0" ||
|
||||
type == "symbol" ||
|
||||
type == "longString") {
|
||||
type == "longString" ||
|
||||
type == "BigInt") {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3354,6 +3347,10 @@ VariablesView.getGrip = function (aValue) {
|
|||
return { type: "-0" };
|
||||
}
|
||||
return aValue;
|
||||
case "bigint":
|
||||
return { type: "BigInt",
|
||||
text: aValue.toString(),
|
||||
};
|
||||
case "undefined":
|
||||
// document.all is also "undefined"
|
||||
if (aValue === undefined) {
|
||||
|
|
@ -3496,6 +3493,10 @@ VariablesView.stringifiers.byType = {
|
|||
return keyString + " \u2192 " + valueString;
|
||||
},
|
||||
|
||||
BigInt: function (aGrip, aOptions) {
|
||||
return aGrip.text + "n";
|
||||
},
|
||||
|
||||
}; // VariablesView.stringifiers.byType
|
||||
|
||||
VariablesView.stringifiers.byObjectClass = {
|
||||
|
|
|
|||
|
|
@ -1293,6 +1293,7 @@ Messages.Extended.prototype = extend(Messages.Simple.prototype, {
|
|||
{
|
||||
let map = {
|
||||
"number": "cm-number",
|
||||
"bigint": "cm-number",
|
||||
"longstring": "console-string",
|
||||
"string": "console-string",
|
||||
"regexp": "cm-string-2",
|
||||
|
|
@ -3364,6 +3365,15 @@ Widgets.ObjectRenderers.add({
|
|||
render: WrappedPrimitiveRenderer,
|
||||
});
|
||||
|
||||
/**
|
||||
* The widget used for displaying BigInt previews.
|
||||
*/
|
||||
Widgets.ObjectRenderers.add({
|
||||
byClass: "BigInt",
|
||||
|
||||
render: WrappedPrimitiveRenderer,
|
||||
});
|
||||
|
||||
/**
|
||||
* The widget used for displaying String previews.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2159,6 +2159,12 @@ function createValueGrip(value, pool, makeObjectGrip) {
|
|||
}
|
||||
return value;
|
||||
|
||||
case "bigint":
|
||||
return {
|
||||
type: "BigInt",
|
||||
text: value.toString(),
|
||||
};
|
||||
|
||||
case "undefined":
|
||||
return { type: "undefined" };
|
||||
|
||||
|
|
|
|||
|
|
@ -41,25 +41,15 @@ function test_object_grip()
|
|||
|
||||
let objClient = gThreadClient.pauseGrip(args[0]);
|
||||
objClient.getPrototypeAndProperties(function (aResponse) {
|
||||
do_check_eq(aResponse.ownProperties.a.configurable, true);
|
||||
do_check_eq(aResponse.ownProperties.a.enumerable, true);
|
||||
do_check_eq(aResponse.ownProperties.a.writable, true);
|
||||
do_check_eq(aResponse.ownProperties.a.value.type, "Infinity");
|
||||
const {a, b, c, d, e, f, g} = aResponse.ownProperties;
|
||||
|
||||
do_check_eq(aResponse.ownProperties.b.configurable, true);
|
||||
do_check_eq(aResponse.ownProperties.b.enumerable, true);
|
||||
do_check_eq(aResponse.ownProperties.b.writable, true);
|
||||
do_check_eq(aResponse.ownProperties.b.value.type, "-Infinity");
|
||||
|
||||
do_check_eq(aResponse.ownProperties.c.configurable, true);
|
||||
do_check_eq(aResponse.ownProperties.c.enumerable, true);
|
||||
do_check_eq(aResponse.ownProperties.c.writable, true);
|
||||
do_check_eq(aResponse.ownProperties.c.value.type, "NaN");
|
||||
|
||||
do_check_eq(aResponse.ownProperties.d.configurable, true);
|
||||
do_check_eq(aResponse.ownProperties.d.enumerable, true);
|
||||
do_check_eq(aResponse.ownProperties.d.writable, true);
|
||||
do_check_eq(aResponse.ownProperties.d.value.type, "-0");
|
||||
testPropertyType(a, "Infinity");
|
||||
testPropertyType(b, "-Infinity");
|
||||
testPropertyType(c, "NaN");
|
||||
testPropertyType(d, "-0");
|
||||
testPropertyType(e, "BigInt");
|
||||
testPropertyType(f, "BigInt");
|
||||
testPropertyType(g, "BigInt");
|
||||
|
||||
gThreadClient.resume(function () {
|
||||
gClient.close().then(gCallback);
|
||||
|
|
@ -67,6 +57,20 @@ function test_object_grip()
|
|||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("stopMe({ a: Infinity, b: -Infinity, c: NaN, d: -0 })");
|
||||
gDebuggee.eval(`stopMe({
|
||||
a: Infinity,
|
||||
b: -Infinity,
|
||||
c: NaN,
|
||||
d: -0,
|
||||
e: 1n,
|
||||
f: -2n,
|
||||
g: 0n,
|
||||
})`);
|
||||
}
|
||||
|
||||
function testPropertyType(prop, expectedType) {
|
||||
do_check_eq(prop.configurable, true);
|
||||
do_check_eq(prop.enumerable, true);
|
||||
do_check_eq(prop.writable, true);
|
||||
do_check_eq(prop.value.type, expectedType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -553,6 +553,10 @@ class MOZ_NON_PARAM alignas(8) Value
|
|||
return isObject() || isNull();
|
||||
}
|
||||
|
||||
bool isNumeric() const {
|
||||
return isNumber() || isBigInt();
|
||||
}
|
||||
|
||||
bool isGCThing() const {
|
||||
#if defined(JS_NUNBOX32)
|
||||
/* gcc sometimes generates signed < without explicit casts. */
|
||||
|
|
@ -1410,6 +1414,7 @@ class WrappedPtrOperations<JS::Value, Wrapper>
|
|||
|
||||
bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
|
||||
bool isObjectOrNull() const { return value().isObjectOrNull(); }
|
||||
bool isNumeric() const { return value().isNumeric(); }
|
||||
|
||||
bool toBoolean() const { return value().toBoolean(); }
|
||||
double toNumber() const { return value().toNumber(); }
|
||||
|
|
|
|||
|
|
@ -139,32 +139,6 @@ BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp)
|
|||
return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.3.2. "This function is
|
||||
// implementation-dependent, and it is permissible, but not encouraged,
|
||||
// for it to return the same thing as toString."
|
||||
bool
|
||||
BigIntObject::toLocaleString_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
HandleValue thisv = args.thisv();
|
||||
MOZ_ASSERT(IsBigInt(thisv));
|
||||
RootedBigInt bi(cx, thisv.isBigInt()
|
||||
? thisv.toBigInt()
|
||||
: thisv.toObject().as<BigIntObject>().unbox());
|
||||
|
||||
RootedString str(cx, BigInt::toString(cx, bi, 10));
|
||||
if (!str)
|
||||
return false;
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BigIntObject::toLocaleString(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsBigInt, toLocaleString_impl>(cx, args);
|
||||
}
|
||||
|
||||
// BigInt proposal section 5.2.1. BigInt.asUintN ( bits, bigint )
|
||||
bool
|
||||
BigIntObject::asUintN(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
|
@ -247,7 +221,7 @@ const JSPropertySpec BigIntObject::properties[] = {
|
|||
const JSFunctionSpec BigIntObject::methods[] = {
|
||||
JS_FN("valueOf", valueOf, 0, 0),
|
||||
JS_FN("toString", toString, 0, 0),
|
||||
JS_FN("toLocaleString", toLocaleString, 0, 0),
|
||||
JS_SELF_HOSTED_FN("toLocaleString", "BigInt_toLocaleString", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ class BigIntObject : public NativeObject
|
|||
static bool valueOf(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
static bool toString_impl(JSContext* cx, const CallArgs& args);
|
||||
static bool toString(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
static bool toLocaleString_impl(JSContext* cx, const CallArgs& args);
|
||||
static bool toLocaleString(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
static bool asUintN(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
static bool asIntN(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
|
|
|
|||
34
js/src/builtin/BigInt.js
Normal file
34
js/src/builtin/BigInt.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Format this BigInt object into a string, using the locale and formatting
|
||||
* options provided.
|
||||
*
|
||||
* Spec PR: https://github.com/tc39/ecma402/pull/236
|
||||
*/
|
||||
function BigInt_toLocaleString() {
|
||||
// Step 1. Note that valueOf enforces "thisBigIntValue" restrictions.
|
||||
var x = callFunction(std_BigInt_valueOf, this);
|
||||
|
||||
var locales = arguments.length > 0 ? arguments[0] : undefined;
|
||||
var options = arguments.length > 1 ? arguments[1] : undefined;
|
||||
|
||||
// Step 2.
|
||||
var numberFormat;
|
||||
if (locales === undefined && options === undefined) {
|
||||
// This cache only optimizes when no explicit locales and options
|
||||
// arguments were supplied.
|
||||
if (!IsRuntimeDefaultLocale(numberFormatCache.runtimeDefaultLocale)) {
|
||||
numberFormatCache.numberFormat = intl_NumberFormat(locales, options);
|
||||
numberFormatCache.runtimeDefaultLocale = RuntimeDefaultLocale();
|
||||
}
|
||||
numberFormat = numberFormatCache.numberFormat;
|
||||
} else {
|
||||
numberFormat = intl_NumberFormat(locales, options);
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
return intl_FormatNumber(numberFormat, x, /* formatToParts = */ false);
|
||||
}
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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_) \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ using namespace js;
|
|||
|
||||
using mozilla::AssertedCast;
|
||||
using mozilla::IsFinite;
|
||||
using mozilla::IsNegative;
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::IsNegativeZero;
|
||||
using js::intl::CallICU;
|
||||
|
|
@ -401,24 +402,51 @@ NewUNumberFormat(JSContext* cx, Handle<NumberFormatObject*> numberFormat)
|
|||
}
|
||||
|
||||
static JSString*
|
||||
PartitionNumberPattern(JSContext* cx, UNumberFormat* nf, double* x,
|
||||
PartitionNumberPattern(JSContext* cx, UNumberFormat* nf, HandleValue x,
|
||||
UFieldPositionIterator* fpositer)
|
||||
{
|
||||
// PartitionNumberPattern doesn't consider -0.0 to be negative.
|
||||
if (IsNegativeZero(*x))
|
||||
*x = 0.0;
|
||||
if (x.isNumber()) {
|
||||
double num = x.toNumber();
|
||||
|
||||
return CallICU(cx, [nf, x, fpositer](UChar* chars, int32_t size, UErrorCode* status) {
|
||||
return unum_formatDoubleForFields(nf, *x, chars, size, fpositer, status);
|
||||
});
|
||||
// PartitionNumberPattern doesn't consider -0.0 to be negative.
|
||||
if (IsNegativeZero(num))
|
||||
num = 0.0;
|
||||
|
||||
return CallICU(cx, [nf, num, fpositer](UChar* chars, int32_t size, UErrorCode* status) {
|
||||
return unum_formatDoubleForFields(nf, num, chars, size, fpositer, status);
|
||||
});
|
||||
} else if(x.isBigInt()) {
|
||||
RootedBigInt bi(cx, x.toBigInt());
|
||||
int64_t num;
|
||||
|
||||
if (BigInt::isInt64(bi, &num)) {
|
||||
return CallICU(cx, [nf, num](UChar* chars, int32_t size, UErrorCode* status) {
|
||||
return unum_formatInt64(nf, num, chars, size, nullptr, status);
|
||||
});
|
||||
} else {
|
||||
JSLinearString* str = BigInt::toString(cx, bi, 10);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(str->hasLatin1Chars());
|
||||
|
||||
JS::AutoCheckCannotGC noGC(cx);
|
||||
const char* latinchars = reinterpret_cast<const char*>(str->latin1Chars(noGC));
|
||||
size_t length = str->length();
|
||||
return CallICU(cx, [nf, latinchars, length](UChar* chars, int32_t size, UErrorCode* status) {
|
||||
return unum_formatDecimal(nf, latinchars, length, chars, size, nullptr, status);
|
||||
});
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_FormatNumber(JSContext* cx, UNumberFormat* nf, double x, MutableHandleValue result)
|
||||
js::FormatNumeric(JSContext* cx, UNumberFormat* nf, HandleValue x, MutableHandleValue result)
|
||||
{
|
||||
// Passing null for |fpositer| will just not compute partition information,
|
||||
// letting us common up all ICU number-formatting code.
|
||||
JSString* str = PartitionNumberPattern(cx, nf, &x, nullptr);
|
||||
JSString* str = PartitionNumberPattern(cx, nf, x, nullptr);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
|
|
@ -429,7 +457,7 @@ js::intl_FormatNumber(JSContext* cx, UNumberFormat* nf, double x, MutableHandleV
|
|||
using FieldType = ImmutablePropertyNamePtr JSAtomState::*;
|
||||
|
||||
static FieldType
|
||||
GetFieldTypeForNumberField(UNumberFormatFields fieldName, double d)
|
||||
GetFieldTypeForNumberField(UNumberFormatFields fieldName, HandleValue x)
|
||||
{
|
||||
// See intl/icu/source/i18n/unicode/unum.h for a detailed field list. This
|
||||
// list is deliberately exhaustive: cases might have to be added/removed if
|
||||
|
|
@ -438,10 +466,15 @@ GetFieldTypeForNumberField(UNumberFormatFields fieldName, double d)
|
|||
// version-testing #ifdefs, should cross-version divergence occur.
|
||||
switch (fieldName) {
|
||||
case UNUM_INTEGER_FIELD:
|
||||
if (IsNaN(d))
|
||||
return &JSAtomState::nan;
|
||||
if (!IsFinite(d))
|
||||
return &JSAtomState::infinity;
|
||||
if (x.isNumber()) {
|
||||
double d = x.toNumber();
|
||||
if (IsNaN(d)) {
|
||||
return &JSAtomState::nan;
|
||||
}
|
||||
if (!IsFinite(d)) {
|
||||
return &JSAtomState::infinity;
|
||||
}
|
||||
}
|
||||
return &JSAtomState::integer;
|
||||
|
||||
case UNUM_GROUPING_SEPARATOR_FIELD:
|
||||
|
|
@ -454,13 +487,17 @@ GetFieldTypeForNumberField(UNumberFormatFields fieldName, double d)
|
|||
return &JSAtomState::fraction;
|
||||
|
||||
case UNUM_SIGN_FIELD: {
|
||||
MOZ_ASSERT(!IsNegativeZero(d),
|
||||
"-0 should have been excluded by PartitionNumberPattern");
|
||||
|
||||
// Manual trawling through the ICU call graph appears to indicate that
|
||||
// the basic formatting we request will never include a positive sign.
|
||||
// But this analysis may be mistaken, so don't absolutely trust it.
|
||||
return d < 0 ? &JSAtomState::minusSign : &JSAtomState::plusSign;
|
||||
// Manual trawling through the ICU call graph appears to indicate that
|
||||
// the basic formatting we request will never include a positive sign.
|
||||
// But this analysis may be mistaken, so don't absolutely trust it.
|
||||
MOZ_ASSERT(!x.isNumber() || !IsNaN(x.toNumber()),
|
||||
"ICU appearing not to produce positive-sign among fields, "
|
||||
"plus our coercing all NaNs to one with sign bit unset "
|
||||
"(i.e. \"positive\"), means we shouldn't reach here with a "
|
||||
"NaN value");
|
||||
bool isNegative =
|
||||
x.isNumber() ? IsNegative(x.toNumber()) : x.toBigInt()->isNegative();
|
||||
return isNegative ? &JSAtomState::minusSign : &JSAtomState::plusSign;
|
||||
}
|
||||
|
||||
case UNUM_PERCENT_FIELD:
|
||||
|
|
@ -495,7 +532,7 @@ GetFieldTypeForNumberField(UNumberFormatFields fieldName, double d)
|
|||
}
|
||||
|
||||
static bool
|
||||
intl_FormatNumberToParts(JSContext* cx, UNumberFormat* nf, double x, MutableHandleValue result)
|
||||
FormatNumericToParts(JSContext* cx, UNumberFormat* nf, HandleValue x, MutableHandleValue result)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
|
|
@ -508,7 +545,7 @@ intl_FormatNumberToParts(JSContext* cx, UNumberFormat* nf, double x, MutableHand
|
|||
MOZ_ASSERT(fpositer);
|
||||
ScopedICUObject<UFieldPositionIterator, ufieldpositer_close> toClose(fpositer);
|
||||
|
||||
RootedString overallResult(cx, PartitionNumberPattern(cx, nf, &x, fpositer));
|
||||
RootedString overallResult(cx, PartitionNumberPattern(cx, nf, x, fpositer));
|
||||
if (!overallResult)
|
||||
return false;
|
||||
|
||||
|
|
@ -824,7 +861,7 @@ js::intl_FormatNumber(JSContext* cx, unsigned argc, Value* vp)
|
|||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 3);
|
||||
MOZ_ASSERT(args[0].isObject());
|
||||
MOZ_ASSERT(args[1].isNumber());
|
||||
MOZ_ASSERT(args[1].isNumeric());
|
||||
MOZ_ASSERT(args[2].isBoolean());
|
||||
|
||||
Rooted<NumberFormatObject*> numberFormat(cx, &args[0].toObject().as<NumberFormatObject>());
|
||||
|
|
@ -842,8 +879,7 @@ js::intl_FormatNumber(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
// Use the UNumberFormat to actually format the number.
|
||||
if (args[2].toBoolean()) {
|
||||
return intl_FormatNumberToParts(cx, nf, args[1].toNumber(), args.rval());
|
||||
return FormatNumericToParts(cx, nf, args.get(1), args.rval());
|
||||
}
|
||||
return intl_FormatNumber(cx, nf, args[1].toNumber(), args.rval());
|
||||
return FormatNumeric(cx, nf, args.get(1), args.rval());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ intl_numberingSystem(JSContext* cx, unsigned argc, Value* vp);
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_FormatNumber(JSContext* cx, unsigned argc, Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_FormatNumber(JSContext* cx, UNumberFormat* nf, double x, MutableHandleValue result);
|
||||
FormatNumeric(JSContext* cx, UNumberFormat* nf, HandleValue x, MutableHandleValue result);
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
|
|
|||
|
|
@ -454,14 +454,14 @@ function numberFormatFormatToBind(value) {
|
|||
// ES5.1 10.5, step 4.d.ii.
|
||||
|
||||
// Step 1.a.ii-iii.
|
||||
var x = ToNumber(value);
|
||||
var x = ToNumeric(value);
|
||||
return intl_FormatNumber(this, x, /* formatToParts = */ false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a function bound to this NumberFormat that returns a String value
|
||||
* representing the result of calling ToNumber(value) according to the
|
||||
* representing the result of calling ToNumeric(value) according to the
|
||||
* effective locale and the formatting options of this NumberFormat.
|
||||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, 11.4.3.
|
||||
|
|
@ -497,7 +497,7 @@ function Intl_NumberFormat_formatToParts(value) {
|
|||
getNumberFormatInternals(nf);
|
||||
|
||||
// Step 4.
|
||||
var x = ToNumber(value);
|
||||
var x = ToNumeric(value);
|
||||
|
||||
// Step 5.
|
||||
return intl_FormatNumber(nf, x, /* formatToParts = */ true);
|
||||
|
|
|
|||
|
|
@ -292,8 +292,6 @@ js::intl_SelectPluralRule(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!type)
|
||||
return false;
|
||||
|
||||
double x = args[1].toNumber();
|
||||
|
||||
// We need a NumberFormat in order to format the number
|
||||
// using the number formatting options (minimum/maximum*Digits)
|
||||
// before we push the result to PluralRules
|
||||
|
|
@ -302,7 +300,7 @@ js::intl_SelectPluralRule(JSContext* cx, unsigned argc, Value* vp)
|
|||
// API: http://bugs.icu-project.org/trac/ticket/12763
|
||||
//
|
||||
RootedValue fmtNumValue(cx);
|
||||
if (!intl_FormatNumber(cx, nf, x, &fmtNumValue))
|
||||
if (!FormatNumeric(cx, nf, args[1], &fmtNumValue))
|
||||
return false;
|
||||
RootedString fmtNumValueString(cx, fmtNumValue.toString());
|
||||
AutoStableStringChars stableChars(cx);
|
||||
|
|
|
|||
|
|
@ -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, ¬Int32);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1895,6 +1895,8 @@ SnapshotIterator::allocationValue(const RValueAllocation& alloc, ReadMethod rm)
|
|||
return FromStringPayload(fromStack(alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_SYMBOL:
|
||||
return FromSymbolPayload(fromStack(alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_BIGINT:
|
||||
return FromBigIntPayload(fromStack(alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return FromObjectPayload(fromStack(alloc.stackOffset2()));
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -725,7 +725,6 @@ class MemoryAccessDesc
|
|||
trapOffset_(trapOffset)
|
||||
{
|
||||
MOZ_ASSERT(Scalar::isSimdType(type) == (numSimdElems > 0));
|
||||
MOZ_ASSERT(numSimdElems <= jit::ScalarTypeToLength(type));
|
||||
MOZ_ASSERT(mozilla::IsPowerOfTwo(align));
|
||||
MOZ_ASSERT_IF(isSimd(), hasTrap());
|
||||
MOZ_ASSERT_IF(isAtomic(), hasTrap());
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -545,7 +545,9 @@ Number(JSContext* cx, unsigned argc, Value* vp)
|
|||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||
return false;
|
||||
JSObject* obj = NumberObject::create(cx, args.rval().toNumber(), proto);
|
||||
|
||||
double d = args.length() > 0 ? args[0].toNumber() : 0;
|
||||
JSObject* obj = NumberObject::create(cx, d, proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
args.rval().setObject(*obj);
|
||||
|
|
@ -1503,8 +1505,7 @@ js::ToInt8Slow(JSContext *cx, const HandleValue v, int8_t *out)
|
|||
bool
|
||||
js::ToNumericSlow(ExclusiveContext* cx, MutableHandleValue vp)
|
||||
{
|
||||
MOZ_ASSERT(!vp.isNumber());
|
||||
MOZ_ASSERT(!vp.isBigInt());
|
||||
MOZ_ASSERT(!vp.isNumeric());
|
||||
|
||||
// Step 1.
|
||||
if (!vp.isPrimitive()) {
|
||||
|
|
|
|||
|
|
@ -378,10 +378,9 @@ ToNumericSlow(ExclusiveContext* cx, JS::MutableHandleValue vp);
|
|||
MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
|
||||
ToNumeric(ExclusiveContext* cx, JS::MutableHandleValue vp)
|
||||
{
|
||||
if (vp.isNumber())
|
||||
return true;
|
||||
if (vp.isBigInt())
|
||||
if (vp.isNumeric()) {
|
||||
return true;
|
||||
}
|
||||
return ToNumericSlow(cx, vp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)) \
|
||||
|
|
|
|||
|
|
@ -705,6 +705,7 @@ selfhosted.inputs = [
|
|||
'builtin/Utilities.js',
|
||||
'builtin/Array.js',
|
||||
'builtin/AsyncIteration.js',
|
||||
'builtin/BigInt.js',
|
||||
'builtin/Classes.js',
|
||||
'builtin/Date.js',
|
||||
'builtin/Error.js',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@
|
|||
#include "mozilla/WrappingOperations.h"
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -2211,6 +2212,43 @@ uint64_t BigInt::toUint64(BigInt* x) {
|
|||
return digit;
|
||||
}
|
||||
|
||||
bool BigInt::isInt64(BigInt* x, int64_t* result) {
|
||||
MOZ_MAKE_MEM_UNDEFINED(result, sizeof(*result));
|
||||
|
||||
size_t length = x->digitLength();
|
||||
if (length > (DigitBits == 32 ? 2 : 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
*result = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t magnitude = x->digit(0);
|
||||
if (DigitBits == 32 && length > 1) {
|
||||
magnitude |= static_cast<uint64_t>(x->digit(1)) << 32;
|
||||
}
|
||||
|
||||
if (x->isNegative()) {
|
||||
constexpr uint64_t Int64MinMagnitude = uint64_t(1) << 63;
|
||||
if (magnitude <= Int64MinMagnitude) {
|
||||
*result = magnitude == Int64MinMagnitude
|
||||
? std::numeric_limits<int64_t>::min()
|
||||
: -AssertedCast<int64_t>(magnitude);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (magnitude <=
|
||||
static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
|
||||
*result = AssertedCast<int64_t>(magnitude);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute `2**bits - (x & (2**bits - 1))`. Used when treating BigInt values as
|
||||
// arbitrary-precision two's complement signed integers.
|
||||
BigInt* BigInt::truncateAndSubFromPowerOfTwo(ExclusiveContext* cx, HandleBigInt x,
|
||||
|
|
@ -2626,6 +2664,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;
|
||||
|
|
@ -2645,7 +2699,7 @@ double BigInt::numberValue(BigInt* x) {
|
|||
if (length <= 64 / DigitBits) {
|
||||
uint64_t magnitude = x->digit(0);
|
||||
if (DigitBits == 32 && length > 1) {
|
||||
magnitude |= uint64_t(x->digit(1)) << 32;
|
||||
magnitude |= static_cast<uint64_t>(x->digit(1)) << 32;
|
||||
}
|
||||
const uint64_t MaxIntegralPrecisionDouble = uint64_t(1)
|
||||
<< (SignificandWidth + 1);
|
||||
|
|
|
|||
|
|
@ -119,6 +119,11 @@ class BigInt final : public js::gc::TenuredCell {
|
|||
static int64_t toInt64(BigInt* x);
|
||||
static uint64_t toUint64(BigInt* x);
|
||||
|
||||
// Return true if the BigInt is without loss of precision representable as an
|
||||
// int64 and store the int64 value in the output. Otherwise return false and
|
||||
// leave the value of the output parameter unspecified.
|
||||
static bool isInt64(BigInt* x, int64_t* result);
|
||||
|
||||
static BigInt* asIntN(js::ExclusiveContext* cx, Handle<BigInt*> x, uint64_t bits);
|
||||
static BigInt* asUintN(js::ExclusiveContext* cx, Handle<BigInt*> x, uint64_t bits);
|
||||
|
||||
|
|
@ -358,6 +363,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.
|
||||
|
|
|
|||
|
|
@ -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") \
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -957,6 +959,20 @@ GlobalObject::setCreateArrayFromBuffer<int32_t>(Handle<JSFunction*> fun)
|
|||
setCreateArrayFromBufferHelper(FROM_BUFFER_INT32, 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)
|
||||
|
|
@ -1020,6 +1036,20 @@ GlobalObject::createArrayFromBuffer<int32_t>() const
|
|||
return createArrayFromBufferHelper(FROM_BUFFER_INT32);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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*
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
@ -2364,38 +2365,6 @@ SetNonexistentProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue re
|
|||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
|
@ -2416,8 +2385,23 @@ 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);
|
||||
}
|
||||
|
||||
if (WouldDefinePastNonwritableLength(pobj, index))
|
||||
return result.fail(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
|
||||
|
||||
if (!pobj->maybeCopyElementsForWrite(cx))
|
||||
return false;
|
||||
|
||||
pobj->setDenseElementWithType(cx, index, v);
|
||||
return result.succeed();
|
||||
}
|
||||
|
||||
// Steps 5.b-f.
|
||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "jswrapper.h"
|
||||
#include "selfhosted.out.h"
|
||||
|
||||
#include "builtin/BigInt.h"
|
||||
#include "builtin/intl/Collator.h"
|
||||
#include "builtin/intl/DateTimeFormat.h"
|
||||
#include "builtin/intl/IntlObject.h"
|
||||
|
|
@ -44,6 +45,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"
|
||||
|
|
@ -1181,6 +1183,18 @@ intrinsic_IsFloat32TypedArray(JSContext* cx, unsigned argc, Value* vp)
|
|||
return intrinsic_IsSpecificTypedArray(cx, argc, vp, Scalar::Float32);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -1521,6 +1535,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 +1601,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 +2196,29 @@ 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;
|
||||
}
|
||||
|
||||
static bool intrinsic_ToNumeric(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
if (!ToNumeric(cx, args[0])) {
|
||||
return false;
|
||||
}
|
||||
args.rval().set(args[0]);
|
||||
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
|
||||
|
|
@ -2187,6 +2242,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("std_Array_reverse", array_reverse, 0,0),
|
||||
JS_FNINFO("std_Array_splice", array_splice, &array_splice_info, 2,0),
|
||||
|
||||
JS_FN("std_BigInt_valueOf", BigIntObject::valueOf, 0,0),
|
||||
|
||||
JS_FN("std_Date_now", date_now, 0,0),
|
||||
JS_FN("std_Date_valueOf", date_valueOf, 0,0),
|
||||
|
||||
|
|
@ -2399,6 +2456,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 +2650,9 @@ 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_FN("ToNumeric", intrinsic_ToNumeric, 1, 0),
|
||||
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
template <>
|
||||
bool TypedArrayObject::getElement<NoGC>(
|
||||
ExclusiveContext* cx, uint32_t index,
|
||||
typename MaybeRooted<Value, NoGC>::MutableHandleType vp) {
|
||||
return getElementPure(index, vp.address());
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
bool TypedArrayObject::getElementPure(uint32_t index, Value* vp)
|
||||
{
|
||||
MOZ_ASSERT(index < obj.length());
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// See the comment in ElementSpecific::doubleToNative.
|
||||
d = JS::CanonicalizeNaN(d);
|
||||
#endif
|
||||
|
||||
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;
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue