Bug 1684316 - Implement highWaterMark as required by WebIDL. r=arai

Differential Revision: https://phabricator.services.mozilla.com/D109239
This commit is contained in:
Tom Schuster 2021-03-22 16:38:19 +00:00
Родитель 2fe6127401
Коммит 610b70603a
5 изменённых файлов: 111 добавлений и 153 удалений

Просмотреть файл

@ -749,6 +749,7 @@ MSG_DEF(JSMSG_WRITABLESTREAM_ALREADY_LOCKED, 0, JSEXN_TYPEERR, "writ
MSG_DEF(JSMSG_READABLESTREAM_NYI, 0, JSEXN_ERR, "full WritableStream support is not yet implemented")
// Other Stream-related
MSG_DEF(JSMSG_STREAM_MISSING_HIGHWATERMARK, 0, JSEXN_TYPEERR, "'highWaterMark' must not be undefined.")
MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.")
MSG_DEF(JSMSG_STREAM_CONSUME_ERROR, 0, JSEXN_TYPEERR, "error consuming stream body")

Просмотреть файл

@ -10,7 +10,8 @@
#include "builtin/streams/ClassSpecMacro.h" // JS_STREAMS_CLASS_SPEC
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
#include "js/Class.h" // JS::ObjectOpResult, JS_NULL_CLASS_OPS
#include "js/Class.h" // JS::ObjectOpResult, JS_NULL_CLASS_OPS
#include "js/Conversions.h" // JS::ToNumber
#include "js/PropertySpec.h" // JS{Property,Function}Spec, JS_FN, JS_FS_END, JS_PS_END
#include "js/ProtoKey.h" // JSProto_{ByteLength,Count}QueuingStrategy
#include "js/RootingAPI.h" // JS::{Handle,Rooted}
@ -19,37 +20,26 @@
#include "vm/Runtime.h" // JSAtomState
#include "vm/StringType.h" // js::NameToId, PropertyName
#include "vm/Compartment-inl.h" // js::UnwrapAndTypeCheckThis
#include "vm/JSObject-inl.h" // js::NewObjectWithClassProto
#include "vm/NativeObject-inl.h" // js::ThrowIfNotConstructing
using js::ByteLengthQueuingStrategy;
using js::CountQueuingStrategy;
using js::PropertyName;
using js::UnwrapAndTypeCheckThis;
using JS::CallArgs;
using JS::CallArgsFromVp;
using JS::Handle;
using JS::ObjectOpResult;
using JS::Rooted;
using JS::ToNumber;
using JS::ToObject;
using JS::Value;
/*** 6.1. Queuing strategies ************************************************/
/**
* ECMA-262 7.3.4 CreateDataProperty(O, P, V)
*/
[[nodiscard]] static bool CreateDataProperty(JSContext* cx,
Handle<JSObject*> obj,
Handle<PropertyName*> key,
Handle<Value> value,
ObjectOpResult& result) {
Rooted<jsid> id(cx, js::NameToId(key));
Rooted<JS::PropertyDescriptor> desc(cx);
desc.setDataDescriptor(value, JSPROP_ENUMERATE);
return js::DefineProperty(cx, obj, id, desc, result);
}
// Streams spec, 6.1.2.2. new ByteLengthQueuingStrategy({ highWaterMark })
bool js::ByteLengthQueuingStrategy::constructor(JSContext* cx, unsigned argc,
Value* vp) {
@ -65,35 +55,65 @@ bool js::ByteLengthQueuingStrategy::constructor(JSContext* cx, unsigned argc,
cx, args, JSProto_ByteLengthQueuingStrategy, &proto)) {
return false;
}
Rooted<JSObject*> strategy(
Rooted<ByteLengthQueuingStrategy*> strategy(
cx, NewObjectWithClassProto<ByteLengthQueuingStrategy>(cx, proto));
if (!strategy) {
return false;
}
// Implicit in the spec: Argument destructuring.
Rooted<JSObject*> argObj(cx, ToObject(cx, args.get(0)));
RootedObject argObj(cx, ToObject(cx, args.get(0)));
if (!argObj) {
return false;
}
Rooted<Value> highWaterMark(cx);
// https://heycam.github.io/webidl/#es-dictionary
// 3.2.17. Dictionary types
// Step 4.1.2: Let esMemberValue be an ECMAScript value,
// depending on Type(esDict): ? Get(esDict, key)
RootedValue highWaterMarkV(cx);
if (!GetProperty(cx, argObj, argObj, cx->names().highWaterMark,
&highWaterMark)) {
&highWaterMarkV)) {
return false;
}
// Step 4.1.5: Otherwise, if esMemberValue is undefined and
// member is required, then throw a TypeError.
if (highWaterMarkV.isUndefined()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_STREAM_MISSING_HIGHWATERMARK);
return false;
}
// Step 4.1.3: If esMemberValue is not undefined, then:
// Let idlMemberValue be the result of converting esMemberValue to
// an IDL value whose type is the type member is declared to be of.
double highWaterMark;
if (!ToNumber(cx, highWaterMarkV, &highWaterMark)) {
return false;
}
// Step 1: Perform ! CreateDataProperty(this, "highWaterMark",
// highWaterMark).
ObjectOpResult ignored;
if (!CreateDataProperty(cx, strategy, cx->names().highWaterMark,
highWaterMark, ignored)) {
return false;
}
// Step 1: Set this.[[highWaterMark]] to init["highWaterMark"].
strategy->setHighWaterMark(highWaterMark);
args.rval().setObject(*strategy);
return true;
}
static bool ByteLengthQueuingStrategy_highWaterMark(JSContext* cx,
unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<ByteLengthQueuingStrategy*> unwrappedStrategy(
cx, UnwrapAndTypeCheckThis<ByteLengthQueuingStrategy>(
cx, args, "get highWaterMark"));
if (!unwrappedStrategy) {
return false;
}
// Step 1: Return this.[[highWaterMark]].
args.rval().setDouble(unwrappedStrategy->highWaterMark());
return true;
}
// Streams spec 6.1.2.3.1. size ( chunk )
static bool ByteLengthQueuingStrategy_size(JSContext* cx, unsigned argc,
Value* vp) {
@ -104,13 +124,16 @@ static bool ByteLengthQueuingStrategy_size(JSContext* cx, unsigned argc,
}
static const JSPropertySpec ByteLengthQueuingStrategy_properties[] = {
JS_PSG("highWaterMark", ByteLengthQueuingStrategy_highWaterMark,
JSPROP_ENUMERATE),
JS_STRING_SYM_PS(toStringTag, "ByteLengthQueuingStrategy", JSPROP_READONLY),
JS_PS_END};
static const JSFunctionSpec ByteLengthQueuingStrategy_methods[] = {
JS_FN("size", ByteLengthQueuingStrategy_size, 1, 0), JS_FS_END};
JS_STREAMS_CLASS_SPEC(ByteLengthQueuingStrategy, 1, 0, 0, 0, JS_NULL_CLASS_OPS);
JS_STREAMS_CLASS_SPEC(ByteLengthQueuingStrategy, 1, SlotCount, 0, 0,
JS_NULL_CLASS_OPS);
// Streams spec, 6.1.3.2. new CountQueuingStrategy({ highWaterMark })
bool js::CountQueuingStrategy::constructor(JSContext* cx, unsigned argc,
@ -138,23 +161,53 @@ bool js::CountQueuingStrategy::constructor(JSContext* cx, unsigned argc,
if (!argObj) {
return false;
}
RootedValue highWaterMark(cx);
// https://heycam.github.io/webidl/#es-dictionary
// 3.2.17. Dictionary types
// Step 4.1.2: Let esMemberValue be an ECMAScript value,
// depending on Type(esDict): ? Get(esDict, key)
RootedValue highWaterMarkV(cx);
if (!GetProperty(cx, argObj, argObj, cx->names().highWaterMark,
&highWaterMark)) {
&highWaterMarkV)) {
return false;
}
// Step 4.1.5: Otherwise, if esMemberValue is undefined and
// member is required, then throw a TypeError.
if (highWaterMarkV.isUndefined()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_STREAM_MISSING_HIGHWATERMARK);
return false;
}
// Step 4.1.3: If esMemberValue is not undefined, then:
// Let idlMemberValue be the result of converting esMemberValue to
// an IDL value whose type is the type member is declared to be of.
double highWaterMark;
if (!ToNumber(cx, highWaterMarkV, &highWaterMark)) {
return false;
}
// Step 1: Perform ! CreateDataProperty(this, "highWaterMark", highWaterMark).
ObjectOpResult ignored;
if (!CreateDataProperty(cx, strategy, cx->names().highWaterMark,
highWaterMark, ignored)) {
return false;
}
// Step 1: Set this.[[highWaterMark]] to init["highWaterMark"].
strategy->setHighWaterMark(highWaterMark);
args.rval().setObject(*strategy);
return true;
}
static bool CountQueuingStrategy_highWaterMark(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<CountQueuingStrategy*> unwrappedStrategy(
cx, UnwrapAndTypeCheckThis<CountQueuingStrategy>(cx, args,
"get highWaterMark"));
if (!unwrappedStrategy) {
return false;
}
// Step 1: Return this.[[highWaterMark]].
args.rval().setDouble(unwrappedStrategy->highWaterMark());
return true;
}
// Streams spec 6.1.3.3.1. size ( chunk )
static bool CountQueuingStrategy_size(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
@ -165,10 +218,13 @@ static bool CountQueuingStrategy_size(JSContext* cx, unsigned argc, Value* vp) {
}
static const JSPropertySpec CountQueuingStrategy_properties[] = {
JS_PSG("highWaterMark", CountQueuingStrategy_highWaterMark,
JSPROP_ENUMERATE),
JS_STRING_SYM_PS(toStringTag, "CountQueuingStrategy", JSPROP_READONLY),
JS_PS_END};
static const JSFunctionSpec CountQueuingStrategy_methods[] = {
JS_FN("size", CountQueuingStrategy_size, 0, 0), JS_FS_END};
JS_STREAMS_CLASS_SPEC(CountQueuingStrategy, 1, 0, 0, 0, JS_NULL_CLASS_OPS);
JS_STREAMS_CLASS_SPEC(CountQueuingStrategy, 1, SlotCount, 0, 0,
JS_NULL_CLASS_OPS);

Просмотреть файл

@ -18,6 +18,15 @@ namespace js {
class ByteLengthQueuingStrategy : public NativeObject {
public:
enum Slots { Slot_HighWaterMark, SlotCount };
double highWaterMark() const {
return getFixedSlot(Slot_HighWaterMark).toDouble();
}
void setHighWaterMark(double value) {
setFixedSlot(Slot_HighWaterMark, JS::DoubleValue(value));
}
static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
static const ClassSpec classSpec_;
static const JSClass class_;
@ -27,6 +36,15 @@ class ByteLengthQueuingStrategy : public NativeObject {
class CountQueuingStrategy : public NativeObject {
public:
enum Slots { Slot_HighWaterMark, SlotCount };
double highWaterMark() const {
return getFixedSlot(Slot_HighWaterMark).toDouble();
}
void setHighWaterMark(double value) {
setFixedSlot(Slot_HighWaterMark, JS::DoubleValue(value));
}
static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
static const ClassSpec classSpec_;
static const JSClass class_;

Просмотреть файл

@ -212,9 +212,6 @@
[TransformStreamDefaultController interface: existence and properties of interface prototype object]
expected: FAIL
[ByteLengthQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[WritableStreamDefaultWriter interface: attribute ready]
expected: FAIL
@ -245,9 +242,6 @@
[Stringification of (new WritableStream()).getWriter()]
expected: FAIL
[CountQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[TransformStream interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
@ -335,9 +329,6 @@
[ReadableStreamBYOBReader interface: operation cancel(optional any)]
expected: FAIL
[ByteLengthQueuingStrategy interface: new ByteLengthQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[ReadableStream interface: calling pipeTo(WritableStream, optional StreamPipeOptions) on new ReadableStream() with too few arguments must throw TypeError]
expected: FAIL
@ -386,9 +377,6 @@
[TransformStreamDefaultController interface object length]
expected: FAIL
[CountQueuingStrategy interface: new CountQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()]
expected: FAIL
@ -751,9 +739,6 @@
[TransformStreamDefaultController interface: existence and properties of interface prototype object]
expected: FAIL
[ByteLengthQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[WritableStreamDefaultWriter interface: attribute ready]
expected: FAIL
@ -784,9 +769,6 @@
[Stringification of (new WritableStream()).getWriter()]
expected: FAIL
[CountQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[TransformStream interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
@ -874,9 +856,6 @@
[ReadableStreamBYOBReader interface: operation cancel(optional any)]
expected: FAIL
[ByteLengthQueuingStrategy interface: new ByteLengthQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[ReadableStream interface: calling pipeTo(WritableStream, optional StreamPipeOptions) on new ReadableStream() with too few arguments must throw TypeError]
expected: FAIL
@ -925,9 +904,6 @@
[TransformStreamDefaultController interface object length]
expected: FAIL
[CountQueuingStrategy interface: new CountQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()]
expected: FAIL
@ -1290,9 +1266,6 @@
[TransformStreamDefaultController interface: existence and properties of interface prototype object]
expected: FAIL
[ByteLengthQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[WritableStreamDefaultWriter interface: attribute ready]
expected: FAIL
@ -1323,9 +1296,6 @@
[Stringification of (new WritableStream()).getWriter()]
expected: FAIL
[CountQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[TransformStream interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
@ -1413,9 +1383,6 @@
[ReadableStreamBYOBReader interface: operation cancel(optional any)]
expected: FAIL
[ByteLengthQueuingStrategy interface: new ByteLengthQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[ReadableStream interface: calling pipeTo(WritableStream, optional StreamPipeOptions) on new ReadableStream() with too few arguments must throw TypeError]
expected: FAIL
@ -1464,9 +1431,6 @@
[TransformStreamDefaultController interface object length]
expected: FAIL
[CountQueuingStrategy interface: new CountQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()]
expected: FAIL
@ -1829,9 +1793,6 @@
[TransformStreamDefaultController interface: existence and properties of interface prototype object]
expected: FAIL
[ByteLengthQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[WritableStreamDefaultWriter interface: attribute ready]
expected: FAIL
@ -1862,9 +1823,6 @@
[Stringification of (new WritableStream()).getWriter()]
expected: FAIL
[CountQueuingStrategy interface: attribute highWaterMark]
expected: FAIL
[TransformStream interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
@ -1952,9 +1910,6 @@
[ReadableStreamBYOBReader interface: operation cancel(optional any)]
expected: FAIL
[ByteLengthQueuingStrategy interface: new ByteLengthQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[ReadableStream interface: calling pipeTo(WritableStream, optional StreamPipeOptions) on new ReadableStream() with too few arguments must throw TypeError]
expected: FAIL
@ -2003,9 +1958,6 @@
[TransformStreamDefaultController interface object length]
expected: FAIL
[CountQueuingStrategy interface: new CountQueuingStrategy({ highWaterMark: 5 }) must inherit property "highWaterMark" with the proper type]
expected: FAIL
[WritableStreamDefaultWriter must be primary interface of (new WritableStream()).getWriter()]
expected: FAIL

Просмотреть файл

@ -1,69 +0,0 @@
[queuing-strategies.any.serviceworker.html]
[ByteLengthQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[CountQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[ByteLengthQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[CountQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[queuing-strategies.any.sharedworker.html]
[ByteLengthQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[CountQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[ByteLengthQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[CountQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[queuing-strategies.any.html]
[ByteLengthQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[CountQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[ByteLengthQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[CountQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[queuing-strategies.any.worker.html]
[ByteLengthQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[CountQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[ByteLengthQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[CountQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[queuing-strategies.any.js]
[ByteLengthQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL
[CountQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[ByteLengthQueuingStrategy: Constructor behaves as expected with strange arguments]
expected: FAIL
[CountQueuingStrategy: highWaterMark constructor values are converted per the unrestricted double rules]
expected: FAIL