@@ -70,65 +70,93 @@ MaybeHandle<Object> JSDisposableStackBase::DisposeResources(
7070 DisposeCallTypeBit::decode (stack_type_case);
7171 DisposeMethodHint hint = DisposeHintBit::decode (stack_type_case);
7272
73- // (TODO:rezvan):
74- // https://github.com/tc39/proposal-explicit-resource-management/pull/219
7573 // d. If hint is sync-dispose and needsAwait is true and hasAwaited is
7674 // false, then
7775 // i. Perform ! Await(undefined).
7876 // ii. Set needsAwait to false.
7977
80- // e. If method is not undefined, then
81- // i. Let result be Completion(Call(method, value)).
82- // ii. If result is a normal completion and hint is async-dispose, then
83- // 1. Set result to Completion(Await(result.[[Value]])).
84- // 2. Set hasAwaited to true.
85- // iii. If result is a throw completion, then
86- // Else,
87- // i. Assert: hint is async-dispose.
88- // ii. Set needsAwait to true.
89- // iii. NOTE: This can only indicate a case where either null or
90- // undefined was the initialized value of an await using declaration.
91- // 4. If needsAwait is true and hasAwaited is false, then
92- // a. Perform ! Await(undefined).
93- v8::TryCatch try_catch (reinterpret_cast <v8::Isolate*>(isolate));
94- try_catch.SetVerbose (false );
95- try_catch.SetCaptureMessage (false );
96-
97- if (call_type == DisposeMethodCallType::kValueIsReceiver ) {
98- result = Execution::Call (isolate, method, value, 0 , nullptr );
99- } else if (call_type == DisposeMethodCallType::kValueIsArgument ) {
100- result = Execution::Call (isolate, method,
101- ReadOnlyRoots (isolate).undefined_value_handle (),
102- 1 , argv);
103- }
78+ if (hint == DisposeMethodHint::kSyncDispose &&
79+ disposable_stack->needsAwait () == true &&
80+ disposable_stack->hasAwaited () == false ) {
81+ // i. Perform ! Await(undefined).
82+ // ii. Set needsAwait to false.
83+ disposable_stack->set_needsAwait (false );
10484
105- Handle<Object> result_handle;
85+ return ResolveAPromiseWithValueAndReturnIt (
86+ isolate, ReadOnlyRoots (isolate).undefined_value_handle ());
87+ }
10688
107- if (result.ToHandle (&result_handle)) {
108- if (hint == DisposeMethodHint::kAsyncDispose ) {
109- DCHECK_NE (resources_type, DisposableStackResourcesType::kAllSync );
110- disposable_stack->set_length (length);
89+ // e. If method is not undefined, then
90+ if (!IsUndefined (*method)) {
91+ // i. Let result be Completion(Call(method, value)).
92+ v8::TryCatch try_catch (reinterpret_cast <v8::Isolate*>(isolate));
93+ try_catch.SetVerbose (false );
94+ try_catch.SetCaptureMessage (false );
95+
96+ if (call_type == DisposeMethodCallType::kValueIsReceiver ) {
97+ result = Execution::Call (isolate, method, value, 0 , nullptr );
98+ } else if (call_type == DisposeMethodCallType::kValueIsArgument ) {
99+ result = Execution::Call (
100+ isolate, method, ReadOnlyRoots (isolate).undefined_value_handle (), 1 ,
101+ argv);
102+ }
111103
112- Handle<JSFunction> promise_function = isolate->promise_function ();
113- Handle<Object> argv[] = {result_handle};
114- Handle<Object> resolve_result =
115- Execution::CallBuiltin (isolate, isolate->promise_resolve (),
116- promise_function, arraysize (argv), argv)
117- .ToHandleChecked ();
118- return Cast<JSReceiver>(resolve_result);
104+ Handle<Object> result_handle;
105+ // ii. If result is a normal completion and hint is async-dispose, then
106+ // 1. Set result to Completion(Await(result.[[Value]])).
107+ // 2. Set hasAwaited to true.
108+ if (result.ToHandle (&result_handle)) {
109+ if (hint == DisposeMethodHint::kAsyncDispose ) {
110+ DCHECK_NE (resources_type, DisposableStackResourcesType::kAllSync );
111+ disposable_stack->set_length (length);
112+
113+ disposable_stack->set_hasAwaited (true );
114+
115+ return ResolveAPromiseWithValueAndReturnIt (isolate, result_handle);
116+ }
117+ } else {
118+ // iii. If result is a throw completion, then
119+ // 1. If completion is a throw completion, then
120+ // a. Set result to result.[[Value]].
121+ // b. Let suppressed be completion.[[Value]].
122+ // c. Let error be a newly created SuppressedError object.
123+ // d. Perform CreateNonEnumerableDataPropertyOrThrow(error,
124+ // "error", result). e. Perform
125+ // CreateNonEnumerableDataPropertyOrThrow(error, "suppressed",
126+ // suppressed). f. Set completion to ThrowCompletion(error).
127+ // 2. Else,
128+ // a. Set completion to result.
129+ DCHECK (isolate->has_exception ());
130+ DCHECK (try_catch.HasCaught ());
131+ Handle<Object> current_error (isolate->exception (), isolate);
132+ if (!isolate->is_catchable_by_javascript (*current_error)) {
133+ return {};
134+ }
135+ HandleErrorInDisposal (isolate, disposable_stack, current_error);
119136 }
120137 } else {
121- // b. If result is a throw completion, then
122- DCHECK (isolate-> has_exception ());
123- DCHECK (try_catch. HasCaught () );
124- Handle<Object> current_error (isolate-> exception (), isolate);
125- if (!isolate-> is_catchable_by_javascript (*current_error)) {
126- return {};
127- }
128- HandleErrorInDisposal (isolate, disposable_stack, current_error );
138+ // Else,
139+ // i. Assert: hint is async-dispose.
140+ DCHECK_EQ (hint, DisposeMethodHint:: kAsyncDispose );
141+ // ii. Set needsAwait to true.
142+ // iii. NOTE: This can only indicate a case where either null or
143+ // undefined was the initialized value of an await using declaration.
144+ disposable_stack-> set_length (length);
145+ disposable_stack-> set_needsAwait ( true );
129146 }
130147 }
131148
149+ // 4. If needsAwait is true and hasAwaited is false, then
150+ // a. Perform ! Await(undefined).
151+ if (disposable_stack->needsAwait () == true &&
152+ disposable_stack->hasAwaited () == false ) {
153+ disposable_stack->set_length (length);
154+ disposable_stack->set_hasAwaited (true );
155+
156+ return ResolveAPromiseWithValueAndReturnIt (
157+ isolate, ReadOnlyRoots (isolate).undefined_value_handle ());
158+ }
159+
132160 // 5. NOTE: After disposeCapability has been disposed, it will never be used
133161 // again. The contents of disposeCapability.[[DisposableResourceStack]] can be
134162 // discarded in implementations, such as by garbage collection, at this point.
@@ -146,7 +174,18 @@ MaybeHandle<Object> JSDisposableStackBase::DisposeResources(
146174 isolate->Throw (*existing_error_handle);
147175 return MaybeHandle<Object>();
148176 }
149- return isolate->factory ()->undefined_value ();
177+ return isolate->factory ()->true_value ();
178+ }
179+
180+ Handle<JSReceiver> JSDisposableStackBase::ResolveAPromiseWithValueAndReturnIt (
181+ Isolate* isolate, Handle<Object> value) {
182+ Handle<JSFunction> promise_function = isolate->promise_function ();
183+ Handle<Object> argv[] = {value};
184+ Handle<Object> resolve_result =
185+ Execution::CallBuiltin (isolate, isolate->promise_resolve (),
186+ promise_function, arraysize (argv), argv)
187+ .ToHandleChecked ();
188+ return Cast<JSReceiver>(resolve_result);
150189}
151190
152191Maybe<bool > JSAsyncDisposableStack::NextDisposeAsyncIteration (
@@ -169,7 +208,7 @@ Maybe<bool> JSAsyncDisposableStack::NextDisposeAsyncIteration(
169208 Handle<Object> result_handle;
170209
171210 if (result.ToHandle (&result_handle)) {
172- if (!IsUndefined (*result_handle)) {
211+ if (!IsTrue (*result_handle)) {
173212 Handle<Context> async_disposable_stack_context =
174213 isolate->factory ()->NewBuiltinContext (
175214 isolate->native_context (),
@@ -201,8 +240,8 @@ Maybe<bool> JSAsyncDisposableStack::NextDisposeAsyncIteration(
201240 .Build ();
202241
203242 Handle<Object> argv[] = {on_fulfilled, on_rejected};
204- // (TODO:rezvan): Add a wrapper function for PerformPromiseThen.
205- Execution::CallBuiltin (isolate, isolate->promise_then (),
243+
244+ Execution::CallBuiltin (isolate, isolate->perform_promise_then (),
206245 Cast<JSPromise>(result_handle), arraysize (argv),
207246 argv)
208247 .ToHandleChecked ();
0 commit comments