diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/builtin/streams/MiscellaneousOperations.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/builtin/streams/MiscellaneousOperations.cpp')
-rw-r--r-- | js/src/builtin/streams/MiscellaneousOperations.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/js/src/builtin/streams/MiscellaneousOperations.cpp b/js/src/builtin/streams/MiscellaneousOperations.cpp new file mode 100644 index 0000000000..3d08886dcb --- /dev/null +++ b/js/src/builtin/streams/MiscellaneousOperations.cpp @@ -0,0 +1,194 @@ +/* -*- 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/. */ + +/* Miscellaneous operations. */ + +#include "builtin/streams/MiscellaneousOperations.h" + +#include "mozilla/Assertions.h" // MOZ_ASSERT +#include "mozilla/Attributes.h" // MOZ_MUST_USE +#include "mozilla/FloatingPoint.h" // mozilla::IsNaN + +#include "jsapi.h" // JS_ReportErrorNumberASCII + +#include "js/Conversions.h" // JS::ToNumber +#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* +#include "js/RootingAPI.h" // JS::{,Mutable}Handle, JS::Rooted +#include "vm/Interpreter.h" // js::{Call,GetAndClearException} +#include "vm/JSContext.h" // JSContext +#include "vm/ObjectOperations.h" // js::GetProperty +#include "vm/PromiseObject.h" // js::PromiseObject +#include "vm/StringType.h" // js::PropertyName + +#include "vm/JSContext-inl.h" // JSContext::check +#include "vm/JSObject-inl.h" // js::IsCallable + +using JS::Handle; +using JS::MutableHandle; +using JS::ToNumber; +using JS::Value; + +MOZ_MUST_USE js::PromiseObject* js::PromiseRejectedWithPendingError( + JSContext* cx) { + Rooted<Value> exn(cx); + if (!cx->isExceptionPending() || !GetAndClearException(cx, &exn)) { + // Uncatchable error. This happens when a slow script is killed or a + // worker is terminated. Propagate the uncatchable error. This will + // typically kill off the calling asynchronous process: the caller + // can't hook its continuation to the new rejected promise. + return nullptr; + } + return PromiseObject::unforgeableReject(cx, exn); +} + +/*** 6.3. Miscellaneous operations ******************************************/ + +/** + * Streams spec, 6.3.1. + * CreateAlgorithmFromUnderlyingMethod ( underlyingObject, methodName, + * algoArgCount, extraArgs ) + * + * This function only partly implements the standard algorithm. We do not + * actually create a new JSFunction completely encapsulating the new algorithm. + * Instead, this just gets the specified method and checks for errors. It's the + * caller's responsibility to make sure that later, when the algorithm is + * "performed", the appropriate steps are carried out. + */ +MOZ_MUST_USE bool js::CreateAlgorithmFromUnderlyingMethod( + JSContext* cx, Handle<Value> underlyingObject, + const char* methodNameForErrorMessage, Handle<PropertyName*> methodName, + MutableHandle<Value> method) { + cx->check(underlyingObject); + cx->check(methodName); + cx->check(method); + + // Step 1: Assert: underlyingObject is not undefined. + MOZ_ASSERT(!underlyingObject.isUndefined()); + + // Step 2: Assert: ! IsPropertyKey(methodName) is true (implicit). + // Step 3: Assert: algoArgCount is 0 or 1 (omitted). + // Step 4: Assert: extraArgs is a List (omitted). + + // Step 5: Let method be ? GetV(underlyingObject, methodName). + if (!GetProperty(cx, underlyingObject, methodName, method)) { + return false; + } + + // Step 6: If method is not undefined, + if (!method.isUndefined()) { + // Step a: If ! IsCallable(method) is false, throw a TypeError + // exception. + if (!IsCallable(method)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_NOT_FUNCTION, methodNameForErrorMessage); + return false; + } + + // Step b: If algoArgCount is 0, return an algorithm that performs the + // following steps: + // Step i: Return ! PromiseCall(method, underlyingObject, + // extraArgs). + // Step c: Otherwise, return an algorithm that performs the following + // steps, taking an arg argument: + // Step i: Let fullArgs be a List consisting of arg followed by the + // elements of extraArgs in order. + // Step ii: Return ! PromiseCall(method, underlyingObject, + // fullArgs). + // (These steps are deferred to the code that performs the algorithm. + // See Perform{Write,Close}Algorithm, ReadableStreamControllerCancelSteps, + // and ReadableStreamControllerCallPullIfNeeded.) + return true; + } + + // Step 7: Return an algorithm which returns a promise resolved with + // undefined (implicit). + return true; +} + +/** + * Streams spec, 6.3.2. InvokeOrNoop ( O, P, args ) + * As it happens, all callers pass exactly one argument. + */ +MOZ_MUST_USE bool js::InvokeOrNoop(JSContext* cx, Handle<Value> O, + Handle<PropertyName*> P, Handle<Value> arg, + MutableHandle<Value> rval) { + cx->check(O, P, arg); + + // Step 1: Assert: O is not undefined. + MOZ_ASSERT(!O.isUndefined()); + + // Step 2: Assert: ! IsPropertyKey(P) is true (implicit). + // Step 3: Assert: args is a List (implicit). + // Step 4: Let method be ? GetV(O, P). + Rooted<Value> method(cx); + if (!GetProperty(cx, O, P, &method)) { + return false; + } + + // Step 5: If method is undefined, return. + if (method.isUndefined()) { + return true; + } + + // Step 6: Return ? Call(method, O, args). + return Call(cx, method, O, arg, rval); +} + +/** + * Streams spec, 6.3.7. ValidateAndNormalizeHighWaterMark ( highWaterMark ) + */ +MOZ_MUST_USE bool js::ValidateAndNormalizeHighWaterMark( + JSContext* cx, Handle<Value> highWaterMarkVal, double* highWaterMark) { + // Step 1: Set highWaterMark to ? ToNumber(highWaterMark). + if (!ToNumber(cx, highWaterMarkVal, highWaterMark)) { + return false; + } + + // Step 2: If highWaterMark is NaN or highWaterMark < 0, throw a RangeError + // exception. + if (mozilla::IsNaN(*highWaterMark) || *highWaterMark < 0) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_STREAM_INVALID_HIGHWATERMARK); + return false; + } + + // Step 3: Return highWaterMark. + return true; +} + +/** + * Streams spec, 6.3.8. MakeSizeAlgorithmFromSizeFunction ( size ) + * + * The standard makes a big deal of turning JavaScript functions (grubby, + * touched by users, covered with germs) into algorithms (pristine, + * respectable, purposeful). We don't bother. Here we only check for errors and + * leave `size` unchanged. Then, in ReadableStreamDefaultControllerEnqueue and + * WritableStreamDefaultControllerGetChunkSize where this value is used, we + * check for undefined and behave as if we had "made" an "algorithm" for it. + */ +MOZ_MUST_USE bool js::MakeSizeAlgorithmFromSizeFunction(JSContext* cx, + Handle<Value> size) { + cx->check(size); + + // Step 1: If size is undefined, return an algorithm that returns 1. + if (size.isUndefined()) { + // Deferred. Size algorithm users must check for undefined. + return true; + } + + // Step 2: If ! IsCallable(size) is false, throw a TypeError exception. + if (!IsCallable(size)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION, + "ReadableStream argument options.size"); + return false; + } + + // Step 3: Return an algorithm that performs the following steps, taking a + // chunk argument: + // a. Return ? Call(size, undefined, « chunk »). + // Deferred. Size algorithm users must know how to call the size function. + return true; +} |