diff --git a/js/src/builtin/Stream.cpp b/js/src/builtin/Stream.cpp index bbfbc7cc11..daa3558b56 100644 --- a/js/src/builtin/Stream.cpp +++ b/js/src/builtin/Stream.cpp @@ -932,6 +932,13 @@ CallStreamExtra(JSContext* cx, const char* name, HandleValue streamVal, if (!JS_GetProperty(cx, global, name, &fun)) return false; + if (!fun.isObject() || !IsCallable(fun)) { + if (!InitStreamExtras(cx, global)) + return false; + if (!JS_GetProperty(cx, global, name, &fun)) + return false; + } + if (!fun.isObject() || !IsCallable(fun)) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, name); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index f1627e481e..3ea147eaff 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -951,6 +951,20 @@ LookupStdName(const JSAtomState& names, JSAtom* name, const JSStdName* table) return nullptr; } +static bool +IsStreamExtraName(JSFlatString* name) +{ + return JS_FlatStringEqualsAscii(name, "WritableStream") || + JS_FlatStringEqualsAscii(name, "WritableStreamDefaultWriter") || + JS_FlatStringEqualsAscii(name, "WritableStreamDefaultController") || + JS_FlatStringEqualsAscii(name, "TransformStream") || + JS_FlatStringEqualsAscii(name, "TransformStreamDefaultController") || + JS_FlatStringEqualsAscii(name, "TextEncoderStream") || + JS_FlatStringEqualsAscii(name, "TextDecoderStream") || + JS_FlatStringEqualsAscii(name, "CompressionStream") || + JS_FlatStringEqualsAscii(name, "DecompressionStream"); +} + /* * Table of standard classes, indexed by JSProtoKey. For entries where the * JSProtoKey does not correspond to a class with a meaningful constructor, we @@ -1041,11 +1055,27 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso if (!GlobalObject::ensureConstructor(cx, global, key)) return false; + if (key == JSProto_ReadableStream) { + RootedObject globalObj(cx, global); + if (!InitStreamExtras(cx, globalObj)) + return false; + } + *resolved = true; return true; } } + if (cx->options().streams() && IsStreamExtraName(idAtom)) { + RootedObject globalObj(cx, global); + if (!InitStreamExtras(cx, globalObj)) + return false; + + if (!HasOwnProperty(cx, globalObj, id, resolved)) + return false; + return true; + } + // There is no such property to resolve. An ordinary resolve hook would // just return true at this point. But the global object is special in one // more way: its prototype chain is lazily initialized. That is, @@ -1075,6 +1105,7 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj return atom == names.undefined || atom == names.globalThis || + IsStreamExtraName(atom) || LookupStdName(names, atom, standard_class_names) || LookupStdName(names, atom, builtin_property_names); } diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index fa9d27ba68..be82c18f11 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -465,9 +465,6 @@ GlobalObject::initStandardClasses(JSContext* cx, Handle global) return false; } - if (cx->options().streams() && !InitStreamExtras(cx, global)) - return false; - return true; }