Bug 1582348 - Add the most skeleton WritableStream class imaginable. r=arai

Differential Revision: https://phabricator.services.mozilla.com/D46397

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jeff Walden 2019-09-23 23:57:58 +00:00
Родитель d05c6fe9fd
Коммит ef9d1b4371
10 изменённых файлов: 343 добавлений и 1 удалений

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

@ -117,7 +117,7 @@
&js::ReadableStreamDefaultController::class_) \
REAL(ReadableByteStreamController, InitViaClassSpec, \
&js::ReadableByteStreamController::class_) \
IMAGINARY(WritableStream, dummy, dummy) \
REAL(WritableStream, InitViaClassSpec, &js::WritableStream::class_) \
IMAGINARY(WritableStreamDefaultWriter, dummy, dummy) \
IMAGINARY(WritableStreamDefaultController, dummy, dummy) \
REAL(ByteLengthQueuingStrategy, InitViaClassSpec, \

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

@ -0,0 +1,153 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=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/. */
/* Class WritableStream. */
#include "builtin/streams/WritableStream.h"
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jsapi.h" // JS_ReportErrorNumberASCII
#include "jspubtd.h" // JSProto_WritableStream
#include "builtin/streams/ClassSpecMacro.h" // JS_STREAMS_CLASS_SPEC
#include "builtin/streams/MiscellaneousOperations.h" // js::MakeSizeAlgorithmFromSizeFunction, js::ValidateAndNormalizeHighWaterMark
#include "builtin/streams/WritableStreamDefaultControllerOperations.h" // js::SetUpWritableStreamDefaultControllerFromUnderlyingSink
#include "js/CallArgs.h" // JS::CallArgs{,FromVp}
#include "js/Class.h" // JS{Function,Property}Spec, JS_{FS,PS}_END, JSCLASS_PRIVATE_IS_NSISUPPORTS, JSCLASS_HAS_PRIVATE, JS_NULL_CLASS_OPS
#include "js/RealmOptions.h" // JS::RealmCreationOptions
#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
#include "js/Value.h" // JS::{,Object}Value
#include "vm/JSContext.h" // JSContext
#include "vm/JSObject.h" // js::GetPrototypeFromBuiltinConstructor
#include "vm/NativeObject.h" // js::PlainObject
#include "vm/ObjectOperations.h" // js::GetProperty
#include "vm/Realm.h" // JS::Realm
#include "vm/JSObject-inl.h" // js::NewBuiltinClassInstance
#include "vm/NativeObject-inl.h" // js::ThrowIfNotConstructing
using js::WritableStream;
using JS::CallArgs;
using JS::CallArgsFromVp;
using JS::Handle;
using JS::ObjectValue;
using JS::Rooted;
using JS::Value;
/*** 4.2. Class WritableStream **********************************************/
/**
* Streams spec, 4.2.3. new WritableStream(underlyingSink = {}, strategy = {})
*/
bool WritableStream::constructor(JSContext* cx, unsigned argc, Value* vp) {
MOZ_ASSERT(cx->realm()->creationOptions().getWritableStreamsEnabled(),
"WritableStream should be enabled in this realm if we reach here");
CallArgs args = CallArgsFromVp(argc, vp);
if (!ThrowIfNotConstructing(cx, args, "WritableStream")) {
return false;
}
// Implicit in the spec: argument default values.
Rooted<Value> underlyingSink(cx, args.get(0));
if (underlyingSink.isUndefined()) {
JSObject* emptyObj = NewBuiltinClassInstance<PlainObject>(cx);
if (!emptyObj) {
return false;
}
underlyingSink = ObjectValue(*emptyObj);
}
Rooted<Value> strategy(cx, args.get(1));
if (strategy.isUndefined()) {
JSObject* emptyObj = NewBuiltinClassInstance<PlainObject>(cx);
if (!emptyObj) {
return false;
}
strategy = ObjectValue(*emptyObj);
}
// Implicit in the spec: Set this to
// OrdinaryCreateFromConstructor(NewTarget, ...).
// Step 1: Perform ! InitializeWritableStream(this).
Rooted<JSObject*> proto(cx);
if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_WritableStream,
&proto)) {
return false;
}
Rooted<WritableStream*> stream(cx,
WritableStream::create(cx, nullptr, proto));
if (!stream) {
return false;
}
// Step 2: Let size be ? GetV(strategy, "size").
Rooted<Value> size(cx);
if (!GetProperty(cx, strategy, cx->names().size, &size)) {
return false;
}
// Step 3: Let highWaterMark be ? GetV(strategy, "highWaterMark").
Rooted<Value> highWaterMarkVal(cx);
if (!GetProperty(cx, strategy, cx->names().highWaterMark,
&highWaterMarkVal)) {
return false;
}
// Step 4: Let type be ? GetV(underlyingSink, "type").
Rooted<Value> type(cx);
if (!GetProperty(cx, underlyingSink, cx->names().type, &type)) {
return false;
}
// Step 5: If type is not undefined, throw a RangeError exception.
if (!type.isUndefined()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_READABLESTREAM_UNDERLYINGSINK_TYPE_WRONG);
return false;
}
// Step 6: Let sizeAlgorithm be ? MakeSizeAlgorithmFromSizeFunction(size).
if (!MakeSizeAlgorithmFromSizeFunction(cx, size)) {
return false;
}
// Step 7: If highWaterMark is undefined, let highWaterMark be 1.
double highWaterMark;
if (highWaterMarkVal.isUndefined()) {
highWaterMark = 1;
} else {
// Step 8: Set highWaterMark to ?
// ValidateAndNormalizeHighWaterMark(highWaterMark).
if (!ValidateAndNormalizeHighWaterMark(cx, highWaterMarkVal,
&highWaterMark)) {
return false;
}
}
// Step 9: Perform
// ? SetUpWritableStreamDefaultControllerFromUnderlyingSink(
// this, underlyingSink, highWaterMark, sizeAlgorithm).
if (!SetUpWritableStreamDefaultControllerFromUnderlyingSink(
cx, stream, underlyingSink, highWaterMark, size)) {
return false;
}
args.rval().setObject(*stream);
return true;
}
static const JSFunctionSpec WritableStream_methods[] = {JS_FS_END};
static const JSPropertySpec WritableStream_properties[] = {JS_PS_END};
JS_STREAMS_CLASS_SPEC(WritableStream, 0, SlotCount, 0,
JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_HAS_PRIVATE,
JS_NULL_CLASS_OPS);

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

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=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/. */
/* Class WritableStream. */
#ifndef builtin_streams_WritableStream_h
#define builtin_streams_WritableStream_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "js/Class.h" // JSClass, js::ClassSpec
#include "js/RootingAPI.h" // JS::Handle
#include "js/Value.h" // JS::Value
#include "vm/NativeObject.h" // js::NativeObject
struct JSContext;
namespace js {
class WritableStream : public NativeObject {
public:
/**
* Memory layout of WritableStream instances.
*
* See https://streams.spec.whatwg.org/#ws-internal-slots for details on
* the stored state.
*
* XXX jwalden needs fleshin' out
*/
enum Slots { SlotCount };
public:
static MOZ_MUST_USE WritableStream* create(
JSContext* cx, void* nsISupportsObject_alreadyAddreffed = nullptr,
JS::Handle<JSObject*> proto = nullptr);
static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
static const ClassSpec classSpec_;
static const JSClass class_;
static const ClassSpec protoClassSpec_;
static const JSClass protoClass_;
};
} // namespace js
#endif // builtin_streams_WritableStream_h

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

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=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/. */
/* Writable stream default controller abstract operations. */
#include "builtin/streams/WritableStreamDefaultControllerOperations.h"
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jsapi.h" // JS_ReportErrorASCII
#include "builtin/streams/WritableStream.h" // js::WritableStream
#include "vm/JSObject-inl.h" // js::NewObjectWithClassProto
using JS::Handle;
using JS::Value;
/*** 4.8. Writable stream default controller abstract operations ************/
/**
* Streams spec, 4.8.3.
* SetUpWritableStreamDefaultControllerFromUnderlyingSink( stream,
* underlyingSink, highWaterMark, sizeAlgorithm )
*/
MOZ_MUST_USE bool js::SetUpWritableStreamDefaultControllerFromUnderlyingSink(
JSContext* cx, Handle<WritableStream*> stream, Handle<Value> underlyingSink,
double highWaterMark, Handle<Value> sizeAlgorithm) {
// XXX jwalden flesh me out
JS_ReportErrorASCII(cx, "epic fail");
return false;
}

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

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=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/. */
/* Writable stream default controller abstract operations. */
#ifndef builtin_streams_WritableStreamDefaultControllerOperations_h
#define builtin_streams_WritableStreamDefaultControllerOperations_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "js/RootingAPI.h" // JS::Handle
#include "js/Value.h" // JS::Value
struct JSContext;
namespace js {
class WritableStream;
extern MOZ_MUST_USE bool SetUpWritableStreamDefaultControllerFromUnderlyingSink(
JSContext* cx, JS::Handle<WritableStream*> stream,
JS::Handle<JS::Value> underlyingSink, double highWaterMark,
JS::Handle<JS::Value> sizeAlgorithm);
} // namespace js
#endif // builtin_streams_WritableStreamDefaultControllerOperations_h

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

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=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/. */
/* Writable stream abstract operations. */
#include "builtin/streams/WritableStreamOperations.h"
#include "mozilla/Attributes.h" // MOZ_MUST_USE
#include "jsapi.h" // JS_SetPrivate
#include "builtin/streams/WritableStream.h" // js::WritableStream
#include "vm/JSObject-inl.h" // js::NewObjectWithClassProto
using js::WritableStream;
using JS::Handle;
using JS::ObjectValue;
using JS::Rooted;
using JS::Value;
/*** 4.3. General writable stream abstract operations. **********************/
/**
* Streams spec, 4.3.4. InitializeWritableStream ( stream )
*/
MOZ_MUST_USE /* static */
WritableStream*
WritableStream::create(
JSContext* cx, void* nsISupportsObject_alreadyAddreffed /* = nullptr */,
Handle<JSObject*> proto /* = nullptr */) {
// In the spec, InitializeWritableStream is always passed a newly created
// WritableStream object. We instead create it here and return it below.
Rooted<WritableStream*> stream(
cx, NewObjectWithClassProto<WritableStream>(cx, proto));
if (!stream) {
return nullptr;
}
JS_SetPrivate(stream, nsISupportsObject_alreadyAddreffed);
// XXX jwalden need to keep fleshin' out here
return stream;
}

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

@ -0,0 +1,14 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=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/. */
/* Writable stream abstract operations. */
#ifndef builtin_streams_WritableStreamOperations_h
#define builtin_streams_WritableStreamOperations_h
namespace js {} // namespace js
#endif // builtin_streams_WritableStreamOperations_h

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

@ -682,6 +682,10 @@ MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_NO_CONTROLLER, 1, JSEXN_TYPEERR, "Read
MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_RESPOND_CLOSED, 0, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method 'respond' called with non-zero number of bytes with a closed controller.")
MSG_DEF(JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, 1, JSEXN_TYPEERR, "ReadableStream method {0} not yet implemented")
// WritableStream
MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSINK_TYPE_WRONG, 0, JSEXN_RANGEERR,"'underlyingSink.type' must be undefined.")
MSG_DEF(JSMSG_READABLESTREAM_NYI, 0, JSEXN_ERR, "full WritableStream support is not yet implemented")
// Other Stream-related
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")

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

@ -237,6 +237,9 @@ UNIFIED_SOURCES += [
'builtin/streams/ReadableStreamReader.cpp',
'builtin/streams/StreamAPI.cpp',
'builtin/streams/TeeState.cpp',
'builtin/streams/WritableStream.cpp',
'builtin/streams/WritableStreamDefaultControllerOperations.cpp',
'builtin/streams/WritableStreamOperations.cpp',
'builtin/String.cpp',
'builtin/Symbol.cpp',
'builtin/TestingFunctions.cpp',

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

@ -25,6 +25,7 @@
#include "builtin/streams/ReadableStream.h" // js::ReadableStream
#include "builtin/streams/ReadableStreamController.h" // js::Readable{StreamDefault,ByteStream}Controller
#include "builtin/streams/ReadableStreamReader.h" // js::ReadableStreamDefaultReader
#include "builtin/streams/WritableStream.h" // js::WritableStream
#include "builtin/Symbol.h"
#include "builtin/TypedObject.h"
#include "builtin/WeakMapObject.h"
@ -108,6 +109,12 @@ bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
case JSProto_CountQueuingStrategy:
return !cx->realm()->creationOptions().getStreamsEnabled();
case JSProto_WritableStream: {
const auto& realmOptions = cx->realm()->creationOptions();
return !realmOptions.getStreamsEnabled() ||
!realmOptions.getWritableStreamsEnabled();
}
// Return true if the given constructor has been disabled at run-time.
case JSProto_Atomics:
case JSProto_SharedArrayBuffer: