summaryrefslogtreecommitdiffstats
path: root/js/src/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin')
-rw-r--r--js/src/builtin/Intl.cpp102
-rw-r--r--js/src/builtin/TypedArray.js75
2 files changed, 101 insertions, 76 deletions
diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp
index 990a4acdb..3a20c487b 100644
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -765,42 +765,53 @@ static const JSFunctionSpec collator_methods[] = {
};
/**
- * Collator constructor.
- * Spec: ECMAScript Internationalization API Specification, 10.1
+ * 10.1.2 Intl.Collator([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
Collator(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when Collator is called because of
+ // backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 10.1.2.1 step 3
+ // ES Intl 1st ed., 10.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 10.1.2.1 step 4
+ // ES Intl 1st ed., 10.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 10.1.2.1 step 5
+ // ES Intl 1st ed., 10.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 10.1.2.1 step 3.a
+ // ES Intl 1st ed., 10.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 10.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateCollatorPrototype(cx));
- if (!proto)
+ // Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateCollatorPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &CollatorClass, proto);
if (!obj)
return false;
@@ -808,15 +819,13 @@ Collator(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
}
- // 10.1.2.1 steps 1 and 2; 10.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 10.1.2.1 step 6; 10.1.3.1 step 3
+ // Step 6.
if (!IntlInitialize(cx, obj, cx->names().InitializeCollator, locales, options))
return false;
- // 10.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -833,6 +842,7 @@ js::intl_Collator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
// be used with "new", but it still has to be treated as a constructor.
return Collator(cx, args, true);
@@ -1257,42 +1267,53 @@ static const JSFunctionSpec numberFormat_methods[] = {
};
/**
- * NumberFormat constructor.
- * Spec: ECMAScript Internationalization API Specification, 11.1
+ * 11.2.1 Intl.NumberFormat([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when NumberFormat is called
+ // because of backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 11.1.2.1 step 3
+ // ES Intl 1st ed., 11.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 11.1.2.1 step 4
+ // ES Intl 1st ed., 11.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 11.1.2.1 step 5
+ // ES Intl 1st ed., 11.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 11.1.2.1 step 3.a
+ // ES Intl 1st ed., 11.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 11.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
- if (!proto)
+ // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateNumberFormatPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto);
if (!obj)
return false;
@@ -1300,15 +1321,13 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
}
- // 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 11.1.2.1 step 6; 11.1.3.1 step 3
+ // Step 3.
if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
return false;
- // 11.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -1325,6 +1344,7 @@ js::intl_NumberFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_NumberFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
// constructor.
@@ -1725,42 +1745,53 @@ static const JSFunctionSpec dateTimeFormat_methods[] = {
};
/**
- * DateTimeFormat constructor.
- * Spec: ECMAScript Internationalization API Specification, 12.1
+ * 12.2.1 Intl.DateTimeFormat([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when DateTimeFormat is called
+ // because of backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 12.1.2.1 step 3
+ // ES Intl 1st ed., 12.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 12.1.2.1 step 4
+ // ES Intl 1st ed., 12.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 12.1.2.1 step 5
+ // ES Intl 1st ed., 12.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 12.1.2.1 step 3.a
+ // ES Intl 1st ed., 12.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 12.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateDateTimeFormatPrototype(cx));
- if (!proto)
+ // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &DateTimeFormatClass, proto);
if (!obj)
return false;
@@ -1768,15 +1799,13 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
}
- // 12.1.2.1 steps 1 and 2; 12.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 12.1.2.1 step 6; 12.1.3.1 step 3
+ // Step 3.
if (!IntlInitialize(cx, obj, cx->names().InitializeDateTimeFormat, locales, options))
return false;
- // 12.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -1793,6 +1822,7 @@ js::intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_DateTimeFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
// constructor.
diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js
index 4d2d6488f..4a3f38365 100644
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -35,6 +35,10 @@ function IsDetachedBuffer(buffer) {
return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
}
+function TypedArrayLengthMethod() {
+ return TypedArrayLength(this);
+}
+
function GetAttachedArrayBuffer(tarray) {
var buffer = ViewedArrayBufferIfReified(tarray);
if (IsDetachedBuffer(buffer))
@@ -42,6 +46,10 @@ function GetAttachedArrayBuffer(tarray) {
return buffer;
}
+function GetAttachedArrayBufferMethod() {
+ return GetAttachedArrayBuffer(this);
+}
+
// A function which ensures that the argument is either a typed array or a
// cross-compartment wrapper for a typed array and that the typed array involved
// has an attached array buffer. If one of those conditions doesn't hold (wrong
@@ -54,10 +62,7 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
return true;
}
- // This is a bit hacky but gets the job done: the first `arg` is used to
- // test for a wrapped typed array, the second as an argument to
- // GetAttachedArrayBuffer.
- callFunction(CallTypedArrayMethodIfWrapped, arg, arg, "GetAttachedArrayBuffer");
+ callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
return false;
}
@@ -98,8 +103,8 @@ function TypedArrayCreateWithLength(constructor, length) {
if (isTypedArray) {
len = TypedArrayLength(newTypedArray);
} else {
- len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray, newTypedArray,
- "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray,
+ "TypedArrayLengthMethod");
}
if (len < length)
@@ -259,15 +264,14 @@ function TypedArrayEvery(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -348,15 +352,14 @@ function TypedArrayFilter(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
if (arguments.length === 0)
@@ -410,15 +413,14 @@ function TypedArrayFind(predicate/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -452,15 +454,14 @@ function TypedArrayFindIndex(predicate/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -492,15 +493,14 @@ function TypedArrayForEach(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3-4.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 5.
if (arguments.length === 0)
@@ -686,15 +686,14 @@ function TypedArrayMap(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
if (arguments.length === 0)
@@ -730,15 +729,14 @@ function TypedArrayReduce(callbackfn/*, initialValue*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -776,15 +774,14 @@ function TypedArrayReduceRight(callbackfn/*, initialValue*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -1034,15 +1031,14 @@ function TypedArraySome(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -1137,7 +1133,7 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
- buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "GetAttachedArrayBuffer");
+ buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, "GetAttachedArrayBufferMethod");
}
// Step 3.
@@ -1145,7 +1141,7 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
len = TypedArrayLength(obj);
} else {
- len = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, obj, "TypedArrayLengthMethod");
}
if (comparefn === undefined) {
@@ -1181,8 +1177,8 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
- buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj,
- "GetAttachedArrayBuffer");
+ buffer = callFunction(CallTypedArrayMethodIfWrapped, obj,
+ "GetAttachedArrayBufferMethod");
}
}
var bufferDetached;
@@ -1217,15 +1213,14 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(array);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 2.
var len;
if (isTypedArray)
len = TypedArrayLength(array);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, array, array, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, array, "TypedArrayLengthMethod");
// Step 4.
if (len === 0)