#include "src/api/api.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/handles/maybe-handles.h"
#include "src/objects/heap-object.h"
#include "src/objects/js-disposable-stack-inl.h"
#include "src/objects/js-disposable-stack.h"
#include "src/objects/js-objects.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/js-promise.h"
#include "src/objects/objects.h"
#include "src/roots/roots.h"
namespace v8 {
namespace internal {
BUILTIN(AsyncDisposableStackOnFulfilled) {
HandleScope scope(isolate);
DirectHandle<JSDisposableStackBase> stack(
Cast<
JSDisposableStackBase>(isolate->context()->GetNoCell(static_cast<int>(
JSDisposableStackBase::AsyncDisposableStackContextSlots::kStack))),
isolate);
DirectHandle<JSPromise> promise(
Cast<JSPromise>(isolate->context()->GetNoCell(static_cast<int>(
JSDisposableStackBase::AsyncDisposableStackContextSlots::
kOuterPromise))),
isolate);
MAYBE_RETURN(JSAsyncDisposableStack::NextDisposeAsyncIteration(isolate, stack,
promise),
ReadOnlyRoots(isolate).exception());
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(AsyncDisposableStackOnRejected) {
HandleScope scope(isolate);
DirectHandle<JSDisposableStackBase> stack(
Cast<
JSDisposableStackBase>(isolate->context()->GetNoCell(static_cast<int>(
JSDisposableStackBase::AsyncDisposableStackContextSlots::kStack))),
isolate);
DirectHandle<JSPromise> promise(
Cast<JSPromise>(isolate->context()->GetNoCell(static_cast<int>(
JSDisposableStackBase::AsyncDisposableStackContextSlots::
kOuterPromise))),
isolate);
DirectHandle<Object> rejection_error = args.at(1);
DirectHandle<Object> message(isolate->pending_message(), isolate);
DCHECK(isolate->is_catchable_by_javascript(*rejection_error));
JSDisposableStackBase::HandleErrorInDisposal(isolate, stack, rejection_error,
message);
MAYBE_RETURN(JSAsyncDisposableStack::NextDisposeAsyncIteration(isolate, stack,
promise),
ReadOnlyRoots(isolate).exception());
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(AsyncDisposeFromSyncDispose) {
HandleScope scope(isolate);
DirectHandle<Object> receiver = args.receiver();
DirectHandle<JSPromise> promise = isolate->factory()->NewJSPromise();
DirectHandle<JSCallable> sync_method(
Cast<JSCallable>(isolate->context()->GetNoCell(static_cast<int>(
JSDisposableStackBase::AsyncDisposeFromSyncDisposeContextSlots::
kMethod))),
isolate);
MaybeDirectHandle<Object> result =
Execution::Call(isolate, sync_method, receiver, {});
if (!result.is_null()) {
JSPromise::Resolve(promise, isolate->factory()->undefined_value())
.ToHandleChecked();
} else {
Tagged<Object> exception = isolate->exception();
if (!isolate->is_catchable_by_javascript(exception)) {
return ReadOnlyRoots(isolate).exception();
}
isolate->clear_internal_exception();
isolate->clear_pending_message();
JSPromise::Reject(promise, direct_handle(exception, isolate));
}
return *promise;
}
BUILTIN(AsyncDisposableStackConstructor) {
const char kMethodName[] = "AsyncDisposableStack";
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::kExplicitResourceManagement);
if (!IsJSReceiver(*args.new_target(), isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
isolate->factory()->NewStringFromAsciiChecked(
kMethodName)));
}
DirectHandle<Map> map;
DirectHandle<JSFunction> target = args.target();
DirectHandle<JSReceiver> new_target = Cast<JSReceiver>(args.new_target());
DCHECK_EQ(*target,
target->native_context()->js_async_disposable_stack_function());
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
DirectHandle<JSAsyncDisposableStack> async_disposable_stack =
isolate->factory()->NewJSAsyncDisposableStack(map);
JSDisposableStackBase::InitializeJSDisposableStackBase(
isolate, async_disposable_stack);
return *async_disposable_stack;
}
BUILTIN(AsyncDisposableStackPrototypeUse) {
const char kMethodName[] = "AsyncDisposableStack.prototype.use";
HandleScope scope(isolate);
CHECK_RECEIVER(JSAsyncDisposableStack, async_disposable_stack, kMethodName);
DirectHandle<JSAny> value = args.at<JSAny>(1);
if (async_disposable_stack->state() == DisposableStackState::kDisposed) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewReferenceError(
MessageTemplate::kDisposableStackIsDisposed,
isolate->factory()->NewStringFromAsciiChecked(kMethodName)));
}
DirectHandle<Object> method;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, method,
JSDisposableStackBase::CheckValueAndGetDisposeMethod(
isolate, value, DisposeMethodHint::kAsyncDispose));
JSDisposableStackBase::Add(
isolate, async_disposable_stack,
(IsNullOrUndefined(*value) ? isolate->factory()->undefined_value()
: value),
method, DisposeMethodCallType::kValueIsReceiver,
DisposeMethodHint::kAsyncDispose);
return *value;
}
BUILTIN(AsyncDisposableStackPrototypeDisposeAsync) {
HandleScope scope(isolate);
DirectHandle<Object> receiver = args.receiver();
DirectHandle<JSPromise> promise = isolate->factory()->NewJSPromise();
if (!IsJSAsyncDisposableStack(*receiver)) {
JSPromise::Reject(promise,
isolate->factory()->NewTypeError(
MessageTemplate::kNotAnAsyncDisposableStack));
return *promise;
}
DirectHandle<JSAsyncDisposableStack> async_disposable_stack =
Cast<JSAsyncDisposableStack>(receiver);
if (async_disposable_stack->state() == DisposableStackState::kDisposed) {
JSPromise::Resolve(
promise,
direct_handle(ReadOnlyRoots(isolate).undefined_value(), isolate))
.ToHandleChecked();
return *promise;
}
async_disposable_stack->set_state(DisposableStackState::kDisposed);
MAYBE_RETURN(JSAsyncDisposableStack::NextDisposeAsyncIteration(
isolate, async_disposable_stack, promise),
ReadOnlyRoots(isolate).exception());
return *promise;
}
BUILTIN(AsyncDisposableStackPrototypeGetDisposed) {
const char kMethodName[] = "get AsyncDisposableStack.prototype.disposed";
HandleScope scope(isolate);
CHECK_RECEIVER(JSAsyncDisposableStack, async_disposable_stack, kMethodName);
return *(isolate->factory()->ToBoolean(async_disposable_stack->state() ==
DisposableStackState::kDisposed));
}
BUILTIN(AsyncDisposableStackPrototypeAdopt) {
const char kMethodName[] = "AsyncDisposableStack.prototype.adopt";
HandleScope scope(isolate);
DirectHandle<Object> value = args.at(1);
DirectHandle<Object> on_dispose_async = args.at(2);
CHECK_RECEIVER(JSAsyncDisposableStack, async_disposable_stack, kMethodName);
if (async_disposable_stack->state() == DisposableStackState::kDisposed) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewReferenceError(
MessageTemplate::kDisposableStackIsDisposed,
isolate->factory()->NewStringFromAsciiChecked(kMethodName)));
}
if (!IsCallable(*on_dispose_async)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotCallable, on_dispose_async));
}
JSDisposableStackBase::Add(isolate, async_disposable_stack, value,
on_dispose_async,
DisposeMethodCallType::kValueIsArgument,
DisposeMethodHint::kAsyncDispose);
return *value;
}
BUILTIN(AsyncDisposableStackPrototypeDefer) {
const char kMethodName[] = "AsyncDisposableStack.prototype.defer";
HandleScope scope(isolate);
DirectHandle<Object> on_dispose_async = args.at(1);
CHECK_RECEIVER(JSAsyncDisposableStack, async_disposable_stack, kMethodName);
if (async_disposable_stack->state() == DisposableStackState::kDisposed) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewReferenceError(
MessageTemplate::kDisposableStackIsDisposed,
isolate->factory()->NewStringFromAsciiChecked(kMethodName)));
}
if (!IsCallable(*on_dispose_async)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kNotCallable, on_dispose_async));
}
JSDisposableStackBase::Add(
isolate, async_disposable_stack, isolate->factory()->undefined_value(),
on_dispose_async, DisposeMethodCallType::kValueIsReceiver,
DisposeMethodHint::kAsyncDispose);
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(AsyncDisposableStackPrototypeMove) {
const char kMethodName[] = "AsyncDisposableStack.prototype.move";
HandleScope scope(isolate);
CHECK_RECEIVER(JSAsyncDisposableStack, async_disposable_stack, kMethodName);
if (async_disposable_stack->state() == DisposableStackState::kDisposed) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewReferenceError(
MessageTemplate::kDisposableStackIsDisposed,
isolate->factory()->NewStringFromAsciiChecked(kMethodName)));
}
Tagged<JSFunction> constructor_function =
Cast<JSFunction>(isolate->native_context()->GetNoCell(
Context::JS_ASYNC_DISPOSABLE_STACK_FUNCTION_INDEX));
DirectHandle<Map> map(constructor_function->initial_map(), isolate);
DirectHandle<JSAsyncDisposableStack> new_async_disposable_stack =
isolate->factory()->NewJSAsyncDisposableStack(map);
new_async_disposable_stack->set_stack(async_disposable_stack->stack());
new_async_disposable_stack->set_length(async_disposable_stack->length());
new_async_disposable_stack->set_state(DisposableStackState::kPending);
new_async_disposable_stack->set_error(
*(isolate->factory()->uninitialized_value()));
async_disposable_stack->set_stack(ReadOnlyRoots(isolate).empty_fixed_array());
async_disposable_stack->set_length(0);
async_disposable_stack->set_error(
*(isolate->factory()->uninitialized_value()));
async_disposable_stack->set_state(DisposableStackState::kDisposed);
return *new_async_disposable_stack;
}
}
}