Completion.cpp 4.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /*
  2. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/TypeCasts.h>
  7. #include <LibJS/Runtime/Completion.h>
  8. #include <LibJS/Runtime/GlobalObject.h>
  9. #include <LibJS/Runtime/NativeFunction.h>
  10. #include <LibJS/Runtime/PromiseConstructor.h>
  11. #include <LibJS/Runtime/PromiseReaction.h>
  12. #include <LibJS/Runtime/VM.h>
  13. #include <LibJS/Runtime/Value.h>
  14. namespace JS {
  15. // 6.2.3.1 Await, https://tc39.es/ecma262/#await
  16. ThrowCompletionOr<Value> await(GlobalObject& global_object, Value value)
  17. {
  18. auto& vm = global_object.vm();
  19. // 1. Let asyncContext be the running execution context.
  20. auto& async_context = vm.running_execution_context();
  21. // 2. Let promise be ? PromiseResolve(%Promise%, value).
  22. auto* promise = TRY(promise_resolve(global_object, *global_object.promise_constructor(), value));
  23. bool success = false;
  24. Value result;
  25. // 3. Let fulfilledClosure be a new Abstract Closure with parameters (value) that captures asyncContext and performs the following steps when called:
  26. auto fulfilled_closure = [&async_context, &success, &result](VM& vm, GlobalObject& global_object) -> ThrowCompletionOr<Value> {
  27. // a. Let prevContext be the running execution context.
  28. // b. Suspend prevContext.
  29. // FIXME: We don't have this concept yet.
  30. // NOTE: Since we don't support context suspension, we exfiltrate the result to await()'s scope instead
  31. success = true;
  32. result = vm.argument(0);
  33. // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
  34. vm.push_execution_context(async_context, global_object);
  35. // d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it.
  36. // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
  37. // FIXME: We don't have this concept yet.
  38. // f. Return undefined.
  39. return js_undefined();
  40. };
  41. // 4. Let onFulfilled be ! CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
  42. auto on_fulfilled = NativeFunction::create(global_object, "", move(fulfilled_closure));
  43. // 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the following steps when called:
  44. auto rejected_closure = [&async_context, &success, &result](VM& vm, GlobalObject& global_object) -> ThrowCompletionOr<Value> {
  45. // a. Let prevContext be the running execution context.
  46. // b. Suspend prevContext.
  47. // FIXME: We don't have this concept yet.
  48. // NOTE: Since we don't support context suspension, we exfiltrate the result to await()'s scope instead
  49. success = false;
  50. result = vm.argument(0);
  51. // c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
  52. vm.push_execution_context(async_context, global_object);
  53. // d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it.
  54. // e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
  55. // FIXME: We don't have this concept yet.
  56. // f. Return undefined.
  57. return js_undefined();
  58. };
  59. // 6. Let onRejected be ! CreateBuiltinFunction(rejectedClosure, 1, "", « »).
  60. auto on_rejected = NativeFunction::create(global_object, "", move(rejected_closure));
  61. // 7. Perform ! PerformPromiseThen(promise, onFulfilled, onRejected).
  62. verify_cast<Promise>(promise)->perform_then(on_fulfilled, on_rejected, {});
  63. // 8. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
  64. vm.pop_execution_context();
  65. // 9. Set the code evaluation state of asyncContext such that when evaluation is resumed with a Completion completion, the following steps of the algorithm that invoked Await will be performed, with completion available.
  66. // 10. Return.
  67. // 11. NOTE: This returns to the evaluation of the operation that had most previously resumed evaluation of asyncContext.
  68. // FIXME: Since we don't support context suspension, we synchronously execute the promise
  69. vm.run_queued_promise_jobs();
  70. if (success)
  71. return result;
  72. else
  73. return throw_completion(result);
  74. }
  75. }