Skip to content

Commit

Permalink
Forward the absence of the argument on AsyncFromSyncIterator prototyp…
Browse files Browse the repository at this point in the history
…e methods

tc39/ecma262#1776 is a normative change that
reached consensus in the November 2019 TC39. It changes
%AsyncFromSyncIteratorPrototype% methods to forward the absence of
arguments to the underlying sync iterator. This is observable via
`arguments.length` inside the underlying sync iterator.

For example, .next is changed to, roughly:

```
%AsyncFromSyncIteratorPrototype%.next = function(value) {
  let res;
  if (arguments.length < 1) {
     res = [[SyncIteratorRecord]].[[Iterator]].next();
  } else {
     res = [[SyncIteratorRecord]].[[Iterator]].next(value);
  }
  // ...
};
```

Bug: v8:10395
Change-Id: Ib8127d08cd78b8d502e6510241f3f13fbbaba5c7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2247041
Reviewed-by: Marja Hölttä <marja@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68398}
  • Loading branch information
syg authored and Commit Bot committed Jun 17, 2020
1 parent 4015132 commit 44a655c
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 37 deletions.
92 changes: 63 additions & 29 deletions src/builtins/builtins-async-iterator-gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ namespace internal {
namespace {
class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
public:
// The 'next' and 'return' take an optional value parameter, and the 'throw'
// method take an optional reason parameter.
static const int kValueOrReasonArg = 0;

explicit AsyncFromSyncBuiltinsAssembler(compiler::CodeAssemblerState* state)
: AsyncBuiltinsAssembler(state) {}

Expand All @@ -31,26 +35,26 @@ class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
using SyncIteratorNodeGenerator =
std::function<TNode<Object>(TNode<JSReceiver>)>;
void Generate_AsyncFromSyncIteratorMethod(
const TNode<Context> context, const TNode<Object> iterator,
const TNode<Object> sent_value,
CodeStubArguments* args, const TNode<Context> context,
const TNode<Object> iterator, const TNode<Object> sent_value,
const SyncIteratorNodeGenerator& get_method,
const UndefinedMethodHandler& if_method_undefined,
const char* operation_name,
Label::Type reject_label_type = Label::kDeferred,
base::Optional<TNode<Object>> initial_exception_value = base::nullopt);

void Generate_AsyncFromSyncIteratorMethod(
const TNode<Context> context, const TNode<Object> iterator,
const TNode<Object> sent_value, Handle<String> name,
const UndefinedMethodHandler& if_method_undefined,
CodeStubArguments* args, const TNode<Context> context,
const TNode<Object> iterator, const TNode<Object> sent_value,
Handle<String> name, const UndefinedMethodHandler& if_method_undefined,
const char* operation_name,
Label::Type reject_label_type = Label::kDeferred,
base::Optional<TNode<Object>> initial_exception_value = base::nullopt) {
auto get_method = [=](const TNode<JSReceiver> sync_iterator) {
return GetProperty(context, sync_iterator, name);
};
return Generate_AsyncFromSyncIteratorMethod(
context, iterator, sent_value, get_method, if_method_undefined,
args, context, iterator, sent_value, get_method, if_method_undefined,
operation_name, reject_label_type, initial_exception_value);
}

Expand Down Expand Up @@ -97,8 +101,9 @@ void AsyncFromSyncBuiltinsAssembler::ThrowIfNotAsyncFromSyncIterator(
}

void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
const TNode<Context> context, const TNode<Object> iterator,
const TNode<Object> sent_value, const SyncIteratorNodeGenerator& get_method,
CodeStubArguments* args, const TNode<Context> context,
const TNode<Object> iterator, const TNode<Object> sent_value,
const SyncIteratorNodeGenerator& get_method,
const UndefinedMethodHandler& if_method_undefined,
const char* operation_name, Label::Type reject_label_type,
base::Optional<TNode<Object>> initial_exception_value) {
Expand Down Expand Up @@ -128,16 +133,31 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
BIND(&if_isnotundefined);
}

TNode<Object> iter_result;
TVARIABLE(Object, iter_result);
{
Label has_sent_value(this), no_sent_value(this), merge(this);
ScopedExceptionHandler handler(this, &reject_promise, &var_exception);
iter_result = Call(context, method, sync_iterator, sent_value);
Branch(
IntPtrGreaterThan(args->GetLength(), IntPtrConstant(kValueOrReasonArg)),
&has_sent_value, &no_sent_value);
BIND(&has_sent_value);
{
iter_result = Call(context, method, sync_iterator, sent_value);
Goto(&merge);
}
BIND(&no_sent_value);
{
iter_result = Call(context, method, sync_iterator);
Goto(&merge);
}
BIND(&merge);
}

TNode<Object> value;
TNode<Oddball> done;
std::tie(value, done) = LoadIteratorResult(
context, native_context, iter_result, &reject_promise, &var_exception);
std::tie(value, done) =
LoadIteratorResult(context, native_context, iter_result.value(),
&reject_promise, &var_exception);

const TNode<JSFunction> promise_fun =
CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
Expand All @@ -160,15 +180,16 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(

// Perform ! PerformPromiseThen(valueWrapper,
// onFulfilled, undefined, promiseCapability).
Return(CallBuiltin(Builtins::kPerformPromiseThen, context, value_wrapper,
on_fulfilled, UndefinedConstant(), promise));
args->PopAndReturn(CallBuiltin(Builtins::kPerformPromiseThen, context,
value_wrapper, on_fulfilled,
UndefinedConstant(), promise));

BIND(&reject_promise);
{
const TNode<Object> exception = var_exception.value();
CallBuiltin(Builtins::kRejectPromise, context, promise, exception,
TrueConstant());
Return(promise);
args->PopAndReturn(promise);
}
}

Expand Down Expand Up @@ -252,28 +273,37 @@ AsyncFromSyncBuiltinsAssembler::LoadIteratorResult(
// https://tc39.github.io/proposal-async-iteration/
// Section #sec-%asyncfromsynciteratorprototype%.next
TF_BUILTIN(AsyncFromSyncIteratorPrototypeNext, AsyncFromSyncBuiltinsAssembler) {
const TNode<Object> iterator = CAST(Parameter(Descriptor::kReceiver));
const TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<IntPtrT> argc = ChangeInt32ToIntPtr(
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
CodeStubArguments args(this, argc);

const TNode<Object> iterator = args.GetReceiver();
const TNode<Object> value = args.GetOptionalArgumentValue(kValueOrReasonArg);
const TNode<Context> context = CAST(Parameter(Descriptor::kContext));

auto get_method = [=](const TNode<JSReceiver> unused) {
return LoadObjectField(CAST(iterator),
JSAsyncFromSyncIterator::kNextOffset);
};
Generate_AsyncFromSyncIteratorMethod(
context, iterator, value, get_method, UndefinedMethodHandler(),
&args, context, iterator, value, get_method, UndefinedMethodHandler(),
"[Async-from-Sync Iterator].prototype.next");
}

// https://tc39.github.io/proposal-async-iteration/
// Section #sec-%asyncfromsynciteratorprototype%.return
TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn,
AsyncFromSyncBuiltinsAssembler) {
const TNode<Object> iterator = CAST(Parameter(Descriptor::kReceiver));
const TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<IntPtrT> argc = ChangeInt32ToIntPtr(
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
CodeStubArguments args(this, argc);

const TNode<Object> iterator = args.GetReceiver();
const TNode<Object> value = args.GetOptionalArgumentValue(kValueOrReasonArg);
const TNode<Context> context = CAST(Parameter(Descriptor::kContext));

auto if_return_undefined = [=](const TNode<NativeContext> native_context,
auto if_return_undefined = [=, &args](
const TNode<NativeContext> native_context,
const TNode<JSPromise> promise,
Label* if_exception) {
// If return is undefined, then
Expand All @@ -285,30 +315,34 @@ TF_BUILTIN(AsyncFromSyncIteratorPrototypeReturn,
// IfAbruptRejectPromise(nextDone, promiseCapability).
// Return promiseCapability.[[Promise]].
CallBuiltin(Builtins::kResolvePromise, context, promise, iter_result);
Return(promise);
args.PopAndReturn(promise);
};

Generate_AsyncFromSyncIteratorMethod(
context, iterator, value, factory()->return_string(), if_return_undefined,
"[Async-from-Sync Iterator].prototype.return");
&args, context, iterator, value, factory()->return_string(),
if_return_undefined, "[Async-from-Sync Iterator].prototype.return");
}

// https://tc39.github.io/proposal-async-iteration/
// Section #sec-%asyncfromsynciteratorprototype%.throw
TF_BUILTIN(AsyncFromSyncIteratorPrototypeThrow,
AsyncFromSyncBuiltinsAssembler) {
const TNode<Object> iterator = CAST(Parameter(Descriptor::kReceiver));
const TNode<Object> reason = CAST(Parameter(Descriptor::kReason));
TNode<IntPtrT> argc = ChangeInt32ToIntPtr(
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount)));
CodeStubArguments args(this, argc);

const TNode<Object> iterator = args.GetReceiver();
const TNode<Object> reason = args.GetOptionalArgumentValue(kValueOrReasonArg);
const TNode<Context> context = CAST(Parameter(Descriptor::kContext));

auto if_throw_undefined = [=](const TNode<NativeContext> native_context,
const TNode<JSPromise> promise,
Label* if_exception) { Goto(if_exception); };

Generate_AsyncFromSyncIteratorMethod(
context, iterator, reason, factory()->throw_string(), if_throw_undefined,
"[Async-from-Sync Iterator].prototype.throw", Label::kNonDeferred,
reason);
&args, context, iterator, reason, factory()->throw_string(),
if_throw_undefined, "[Async-from-Sync Iterator].prototype.throw",
Label::kNonDeferred, reason);
}

} // namespace internal
Expand Down
6 changes: 3 additions & 3 deletions src/builtins/builtins-definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -877,11 +877,11 @@ namespace internal {
/* %AsyncFromSyncIteratorPrototype% */ \
/* See tc39.github.io/proposal-async-iteration/ */ \
/* #sec-%asyncfromsynciteratorprototype%-object) */ \
TFJ(AsyncFromSyncIteratorPrototypeNext, 1, kReceiver, kValue) \
TFJ(AsyncFromSyncIteratorPrototypeNext, kDontAdaptArgumentsSentinel) \
/* #sec-%asyncfromsynciteratorprototype%.throw */ \
TFJ(AsyncFromSyncIteratorPrototypeThrow, 1, kReceiver, kReason) \
TFJ(AsyncFromSyncIteratorPrototypeThrow, kDontAdaptArgumentsSentinel) \
/* #sec-%asyncfromsynciteratorprototype%.return */ \
TFJ(AsyncFromSyncIteratorPrototypeReturn, 1, kReceiver, kValue) \
TFJ(AsyncFromSyncIteratorPrototypeReturn, kDontAdaptArgumentsSentinel) \
/* #sec-async-iterator-value-unwrap-functions */ \
TFJ(AsyncIteratorValueUnwrap, 1, kReceiver, kValue) \
\
Expand Down
7 changes: 4 additions & 3 deletions src/init/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -918,13 +918,14 @@ void Genesis::CreateAsyncIteratorMaps(Handle<JSFunction> empty) {
Handle<JSObject> async_from_sync_iterator_prototype = factory()->NewJSObject(
isolate()->object_function(), AllocationType::kOld);
SimpleInstallFunction(isolate(), async_from_sync_iterator_prototype, "next",
Builtins::kAsyncFromSyncIteratorPrototypeNext, 1, true);
Builtins::kAsyncFromSyncIteratorPrototypeNext, 1,
false);
SimpleInstallFunction(isolate(), async_from_sync_iterator_prototype, "return",
Builtins::kAsyncFromSyncIteratorPrototypeReturn, 1,
true);
false);
SimpleInstallFunction(isolate(), async_from_sync_iterator_prototype, "throw",
Builtins::kAsyncFromSyncIteratorPrototypeThrow, 1,
true);
false);

InstallToStringTag(isolate(), async_from_sync_iterator_prototype,
"Async-from-Sync Iterator");
Expand Down
2 changes: 0 additions & 2 deletions test/test262/test262.status
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,6 @@
'built-ins/RegExp/prototype/Symbol.replace/fn-invoke-args-empty-result': [FAIL],

# https://bugs.chromium.org/p/v8/issues/detail?id=10395
'built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed': [FAIL],
'built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed': [FAIL],
'built-ins/AsyncFromSyncIteratorPrototype/return/return-null': [FAIL],
'built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null': [FAIL],

Expand Down

0 comments on commit 44a655c

Please sign in to comment.