Commit 04233410 authored by caitp's avatar caitp Committed by Commit bot

[async-iteration] implement Async-from-Sync Iterator

Introduce a new Object to allow GetIterator("async") to function when the
iterable does not have a Symbol.asyncIterator method.

This patch has been split out from https://codereview.chromium.org/2622833002/
and incorporates test cases.

BUG=v8:5855, v8:4483
R=jgruber@chromium.org, rmcilroy@chromium.org, neis@chromium.org
TBR=hpayer@chromium.org, bmeurer@chromium.org

Review-Url: https://codereview.chromium.org/2645313003
Cr-Commit-Position: refs/heads/master@{#43419}
parent 8cfe45b6
......@@ -930,6 +930,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-array.cc",
"src/builtins/builtins-arraybuffer.cc",
"src/builtins/builtins-async-function.cc",
"src/builtins/builtins-async-iterator.cc",
"src/builtins/builtins-async.cc",
"src/builtins/builtins-async.h",
"src/builtins/builtins-boolean.cc",
......
......@@ -220,6 +220,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) {
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
......
......@@ -172,6 +172,7 @@ class Genesis BASE_EMBEDDED {
void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
void CreateIteratorMaps(Handle<JSFunction> empty);
void CreateAsyncIteratorMaps();
void CreateAsyncFunctionMaps(Handle<JSFunction> empty);
void CreateJSProxyMaps();
......@@ -785,6 +786,50 @@ void Genesis::CreateIteratorMaps(Handle<JSFunction> empty) {
*generator_object_prototype_map);
}
void Genesis::CreateAsyncIteratorMaps() {
// %AsyncIteratorPrototype%
// proposal-async-iteration/#sec-asynciteratorprototype
Handle<JSObject> async_iterator_prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
Handle<JSFunction> async_iterator_prototype_iterator = SimpleCreateFunction(
isolate(), factory()->NewStringFromAsciiChecked("[Symbol.asyncIterator]"),
Builtins::kReturnReceiver, 0, true);
JSObject::AddProperty(async_iterator_prototype,
factory()->async_iterator_symbol(),
async_iterator_prototype_iterator, DONT_ENUM);
// %AsyncFromSyncIteratorPrototype%
// proposal-async-iteration/#sec-%asyncfromsynciteratorprototype%-object
Handle<JSObject> async_from_sync_iterator_prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
SimpleInstallFunction(async_from_sync_iterator_prototype,
factory()->next_string(),
Builtins::kAsyncFromSyncIteratorPrototypeNext, 1, true);
SimpleInstallFunction(
async_from_sync_iterator_prototype, factory()->return_string(),
Builtins::kAsyncFromSyncIteratorPrototypeReturn, 1, true);
SimpleInstallFunction(
async_from_sync_iterator_prototype, factory()->throw_string(),
Builtins::kAsyncFromSyncIteratorPrototypeThrow, 1, true);
JSObject::AddProperty(
async_from_sync_iterator_prototype, factory()->to_string_tag_symbol(),
factory()->NewStringFromAsciiChecked("Async-from-Sync Iterator"),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
JSObject::ForceSetPrototype(async_from_sync_iterator_prototype,
async_iterator_prototype);
Handle<Map> async_from_sync_iterator_map = factory()->NewMap(
JS_ASYNC_FROM_SYNC_ITERATOR_TYPE, JSAsyncFromSyncIterator::kSize);
Map::SetPrototype(async_from_sync_iterator_map,
async_from_sync_iterator_prototype);
native_context()->set_async_from_sync_iterator_map(
*async_from_sync_iterator_map);
}
void Genesis::CreateAsyncFunctionMaps(Handle<JSFunction> empty) {
// %AsyncFunctionPrototype% intrinsic
Handle<JSObject> async_function_prototype =
......@@ -1295,6 +1340,16 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
class_function_map_->SetConstructor(*function_fun);
}
{
// --- A s y n c F r o m S y n c I t e r a t o r
Handle<Code> code = isolate->builtins()->AsyncIteratorValueUnwrap();
Handle<SharedFunctionInfo> info =
factory->NewSharedFunctionInfo(factory->empty_string(), code, false);
info->set_internal_formal_parameter_count(1);
info->set_length(1);
native_context()->set_async_iterator_value_unwrap_shared_fun(*info);
}
{ // --- A r r a y ---
Handle<JSFunction> array_function =
InstallFunction(global, "Array", JS_ARRAY_TYPE, JSArray::kSize,
......@@ -4761,6 +4816,7 @@ Genesis::Genesis(
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
CreateStrictModeFunctionMaps(empty_function);
CreateIteratorMaps(empty_function);
CreateAsyncIteratorMaps();
CreateAsyncFunctionMaps(empty_function);
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
......
This diff is collapsed.
......@@ -846,7 +846,18 @@ class Isolate;
WasmRuntimeCall, 1) \
TFS(ThrowWasmTrapFuncInvalid, BUILTIN, kNoExtraICState, WasmRuntimeCall, 1) \
TFS(ThrowWasmTrapFuncSigMismatch, BUILTIN, kNoExtraICState, WasmRuntimeCall, \
1)
1) \
\
/* Async-from-Sync Iterator */ \
\
/* %AsyncFromSyncIteratorPrototype% */ \
/* (proposal-async-iteration/#sec-%asyncfromsynciteratorprototype%-object)*/ \
TFJ(AsyncFromSyncIteratorPrototypeNext, 1) \
TFJ(AsyncFromSyncIteratorPrototypeThrow, 1) \
TFJ(AsyncFromSyncIteratorPrototypeReturn, 1) \
\
/* proposal-async-iteration/#sec-async-iterator-value-unwrap-functions */ \
TFJ(AsyncIteratorValueUnwrap, 1)
#define IGNORE_BUILTIN(...)
......
......@@ -2890,6 +2890,11 @@ Node* CodeStubAssembler::IsJSReceiver(Node* object) {
return IsJSReceiverInstanceType(LoadInstanceType(object));
}
Node* CodeStubAssembler::IsJSReceiverMap(Node* map) {
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
return IsJSReceiverInstanceType(LoadMapInstanceType(map));
}
Node* CodeStubAssembler::IsJSObject(Node* object) {
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
return Int32GreaterThanOrEqual(LoadInstanceType(object),
......
......@@ -692,6 +692,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsJSGlobalProxy(Node* object);
Node* IsJSReceiverInstanceType(Node* instance_type);
Node* IsJSReceiver(Node* object);
Node* IsJSReceiverMap(Node* map);
Node* IsMap(Node* object);
Node* IsCallableMap(Node* map);
Node* IsCallable(Node* object);
......@@ -1003,6 +1004,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Label* if_found, Variable* var_value,
Label* if_not_found, Label* if_bailout);
Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
return CallStub(CodeFactory::GetProperty(isolate()), context, receiver,
HeapConstant(name));
}
void LoadPropertyFromFastObject(Node* object, Node* map, Node* descriptors,
Node* name_index, Variable* var_details,
Variable* var_value);
......@@ -1258,6 +1264,16 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void Print(const char* prefix, Node* tagged_value);
inline void Print(Node* tagged_value) { return Print(nullptr, tagged_value); }
template <class... TArgs>
Node* MakeTypeError(MessageTemplate::Template message, Node* context,
TArgs... args) {
STATIC_ASSERT(sizeof...(TArgs) <= 3);
Node* const make_type_error = LoadContextElement(
LoadNativeContext(context), Context::MAKE_TYPE_ERROR_INDEX);
return CallJS(CodeFactory::Call(isolate()), context, make_type_error,
UndefinedConstant(), SmiConstant(message), args...);
}
protected:
void DescriptorLookup(Node* unique_name, Node* descriptors, Node* bitfield3,
Label* if_found, Variable* var_name_index,
......
......@@ -188,6 +188,10 @@ Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) {
return raw_assembler()->HeapConstant(object);
}
Node* CodeAssembler::CStringConstant(const char* str) {
return HeapConstant(factory()->NewStringFromAsciiChecked(str, TENURED));
}
Node* CodeAssembler::BooleanConstant(bool value) {
return raw_assembler()->BooleanConstant(value);
}
......
......@@ -216,6 +216,7 @@ class V8_EXPORT_PRIVATE CodeAssembler {
Node* SmiConstant(Smi* value);
Node* SmiConstant(int value);
Node* HeapConstant(Handle<HeapObject> object);
Node* CStringConstant(const char* str);
Node* BooleanConstant(bool value);
Node* ExternalConstant(ExternalReference address);
Node* Float64Constant(double value);
......
......@@ -225,6 +225,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
......
......@@ -197,11 +197,14 @@ enum ContextLookupFlags {
V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(ARRAY_BUFFER_MAP_INDEX, Map, array_buffer_map) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
V(ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX, Map, async_from_sync_iterator_map) \
V(ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, SharedFunctionInfo, \
async_function_await_reject_shared_fun) \
V(ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN, SharedFunctionInfo, \
async_function_await_resolve_shared_fun) \
V(ASYNC_FUNCTION_FUNCTION_INDEX, JSFunction, async_function_constructor) \
V(ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN, SharedFunctionInfo, \
async_iterator_value_unwrap_shared_fun) \
V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \
V(BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX, Map, \
bound_function_with_constructor_map) \
......
......@@ -3794,6 +3794,19 @@ Handle<Object> TranslatedState::MaterializeCapturedObjectAt(
object->set_index(Smi::cast(*next_index)->value());
return object;
}
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: {
Handle<JSAsyncFromSyncIterator> object =
Handle<JSAsyncFromSyncIterator>::cast(
isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED));
slot->value_ = object;
Handle<Object> properties = materializer.FieldAt(value_index);
Handle<Object> elements = materializer.FieldAt(value_index);
Handle<Object> sync_iterator = materializer.FieldAt(value_index);
object->set_properties(FixedArray::cast(*properties));
object->set_elements(FixedArrayBase::cast(*elements));
object->set_sync_iterator(JSReceiver::cast(*sync_iterator));
return object;
}
case JS_ARRAY_TYPE: {
Handle<JSArray> object = Handle<JSArray>::cast(
isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED));
......
......@@ -1975,6 +1975,16 @@ Handle<JSIteratorResult> Factory::NewJSIteratorResult(Handle<Object> value,
return js_iter_result;
}
Handle<JSAsyncFromSyncIterator> Factory::NewJSAsyncFromSyncIterator(
Handle<JSReceiver> sync_iterator) {
Handle<Map> map(isolate()->native_context()->async_from_sync_iterator_map());
Handle<JSAsyncFromSyncIterator> iterator =
Handle<JSAsyncFromSyncIterator>::cast(NewJSObjectFromMap(map));
iterator->set_sync_iterator(*sync_iterator);
return iterator;
}
Handle<JSMap> Factory::NewJSMap() {
Handle<Map> map(isolate()->native_context()->js_map_map());
Handle<JSMap> js_map = Handle<JSMap>::cast(NewJSObjectFromMap(map));
......
......@@ -558,6 +558,8 @@ class V8_EXPORT_PRIVATE Factory final {
size_t byte_offset, size_t byte_length);
Handle<JSIteratorResult> NewJSIteratorResult(Handle<Object> value, bool done);
Handle<JSAsyncFromSyncIterator> NewJSAsyncFromSyncIterator(
Handle<JSReceiver> sync_iterator);
Handle<JSMap> NewJSMap();
Handle<JSSet> NewJSSet();
......
......@@ -109,6 +109,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_OBJECT_TYPE:
case JS_ERROR_TYPE:
case JS_ARGUMENTS_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
case JS_MODULE_NAMESPACE_TYPE:
......
......@@ -299,6 +299,44 @@ Node* IntrinsicsHelper::ClassOf(Node* args_reg, Node* arg_count,
return __ ClassOf(value);
}
Node* IntrinsicsHelper::CreateAsyncFromSyncIterator(Node* args_reg,
Node* arg_count,
Node* context) {
InterpreterAssembler::Label not_receiver(
assembler_, InterpreterAssembler::Label::kDeferred);
InterpreterAssembler::Label done(assembler_);
InterpreterAssembler::Variable return_value(assembler_,
MachineRepresentation::kTagged);
Node* sync_iterator = __ LoadRegister(args_reg);
__ GotoIf(__ TaggedIsSmi(sync_iterator), &not_receiver);
__ GotoIfNot(__ IsJSReceiver(sync_iterator), &not_receiver);
Node* const native_context = __ LoadNativeContext(context);
Node* const map = __ LoadContextElement(
native_context, Context::ASYNC_FROM_SYNC_ITERATOR_MAP_INDEX);
Node* const iterator = __ AllocateJSObjectFromMap(map);
__ StoreObjectFieldNoWriteBarrier(
iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset, sync_iterator);
return_value.Bind(iterator);
__ Goto(&done);
__ Bind(&not_receiver);
{
return_value.Bind(
__ CallRuntime(Runtime::kThrowSymbolIteratorInvalid, context));
// Unreachable due to the Throw in runtime call.
__ Goto(&done);
}
__ Bind(&done);
return return_value.value();
}
void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) {
InterpreterAssembler::Label match(assembler_);
Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected));
......
......@@ -23,21 +23,22 @@ namespace interpreter {
// List of supported intrisics, with upper case name, lower case name and
// expected number of arguments (-1 denoting argument count is variable).
#define INTRINSICS_LIST(V) \
V(Call, call, -1) \
V(ClassOf, class_of, 1) \
V(CreateIterResultObject, create_iter_result_object, 2) \
V(HasProperty, has_property, 2) \
V(IsArray, is_array, 1) \
V(IsJSProxy, is_js_proxy, 1) \
V(IsJSReceiver, is_js_receiver, 1) \
V(IsSmi, is_smi, 1) \
V(IsTypedArray, is_typed_array, 1) \
V(SubString, sub_string, 3) \
V(ToString, to_string, 1) \
V(ToLength, to_length, 1) \
V(ToInteger, to_integer, 1) \
V(ToNumber, to_number, 1) \
#define INTRINSICS_LIST(V) \
V(Call, call, -1) \
V(ClassOf, class_of, 1) \
V(CreateIterResultObject, create_iter_result_object, 2) \
V(CreateAsyncFromSyncIterator, create_async_from_sync_iterator, 1) \
V(HasProperty, has_property, 2) \
V(IsArray, is_array, 1) \
V(IsJSProxy, is_js_proxy, 1) \
V(IsJSReceiver, is_js_receiver, 1) \
V(IsSmi, is_smi, 1) \
V(IsTypedArray, is_typed_array, 1) \
V(SubString, sub_string, 3) \
V(ToString, to_string, 1) \
V(ToLength, to_length, 1) \
V(ToInteger, to_integer, 1) \
V(ToNumber, to_number, 1) \
V(ToObject, to_object, 1)
class IntrinsicsHelper {
......
......@@ -467,6 +467,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
case JS_OBJECT_TYPE:
case JS_ERROR_TYPE:
case JS_ARGUMENTS_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_PROMISE_CAPABILITY_TYPE:
case JS_PROMISE_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
......
......@@ -200,6 +200,9 @@ void HeapObject::HeapObjectVerify() {
case JS_STRING_ITERATOR_TYPE:
JSStringIterator::cast(this)->JSStringIteratorVerify();
break;
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
JSAsyncFromSyncIterator::cast(this)->JSAsyncFromSyncIteratorVerify();
break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapVerify();
break;
......@@ -890,6 +893,12 @@ void JSStringIterator::JSStringIteratorVerify() {
CHECK_LE(index(), String::kMaxLength);
}
void JSAsyncFromSyncIterator::JSAsyncFromSyncIteratorVerify() {
CHECK(IsJSAsyncFromSyncIterator());
JSObjectVerify();
VerifyHeapPointer(sync_iterator());
}
void JSWeakSet::JSWeakSetVerify() {
CHECK(IsJSWeakSet());
JSObjectVerify();
......
......@@ -164,6 +164,7 @@ TYPE_CHECKER(JSPromise, JS_PROMISE_TYPE)
TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
TYPE_CHECKER(JSSet, JS_SET_TYPE)
TYPE_CHECKER(JSSetIterator, JS_SET_ITERATOR_TYPE)
TYPE_CHECKER(JSAsyncFromSyncIterator, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE)
TYPE_CHECKER(JSStringIterator, JS_STRING_ITERATOR_TYPE)
TYPE_CHECKER(JSTypedArray, JS_TYPED_ARRAY_TYPE)
TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
......@@ -656,6 +657,7 @@ CAST_ACCESSOR(JSPromiseCapability)
CAST_ACCESSOR(JSPromise)
CAST_ACCESSOR(JSSet)
CAST_ACCESSOR(JSSetIterator)
CAST_ACCESSOR(JSAsyncFromSyncIterator)
CAST_ACCESSOR(JSStringIterator)
CAST_ACCESSOR(JSArrayIterator)
CAST_ACCESSOR(JSTypedArray)
......@@ -8214,6 +8216,9 @@ ACCESSORS(JSArrayIterator, object, Object, kIteratedObjectOffset)
ACCESSORS(JSArrayIterator, index, Object, kNextIndexOffset)
ACCESSORS(JSArrayIterator, object_map, Object, kIteratedObjectMapOffset)
ACCESSORS(JSAsyncFromSyncIterator, sync_iterator, JSReceiver,
kSyncIteratorOffset)
ACCESSORS(JSStringIterator, string, String, kStringOffset)
SMI_ACCESSORS(JSStringIterator, index, kNextIndexOffset)
......
......@@ -12555,6 +12555,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_API_OBJECT_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_ARRAY_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_DATA_VIEW_TYPE:
case JS_DATE_TYPE:
......
......@@ -398,6 +398,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(JS_PROMISE_TYPE) \
V(JS_REGEXP_TYPE) \
V(JS_ERROR_TYPE) \
V(JS_ASYNC_FROM_SYNC_ITERATOR_TYPE) \
V(JS_STRING_ITERATOR_TYPE) \
\
V(JS_TYPED_ARRAY_KEY_ITERATOR_TYPE) \
......@@ -743,6 +744,7 @@ enum InstanceType {
JS_PROMISE_TYPE,
JS_REGEXP_TYPE,
JS_ERROR_TYPE,
JS_ASYNC_FROM_SYNC_ITERATOR_TYPE,
JS_STRING_ITERATOR_TYPE,
JS_TYPED_ARRAY_KEY_ITERATOR_TYPE,
......@@ -1039,6 +1041,7 @@ template <class C> inline bool Is(Object* obj);
V(JSArray) \
V(JSArrayBuffer) \
V(JSArrayBufferView) \
V(JSAsyncFromSyncIterator) \
V(JSCollection) \
V(JSTypedArray) \
V(JSArrayIterator) \
......@@ -10437,6 +10440,32 @@ class JSArrayIterator : public JSObject {
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayIterator);
};
// The [Async-from-Sync Iterator] object
// (proposal-async-iteration/#sec-async-from-sync-iterator-objects)
// An object which wraps an ordinary Iterator and converts it to behave
// according to the Async Iterator protocol.
// (See https://tc39.github.io/proposal-async-iteration/#sec-iteration)
class JSAsyncFromSyncIterator : public JSObject {
public:
DECLARE_CAST(JSAsyncFromSyncIterator)
DECLARE_PRINTER(JSAsyncFromSyncIterator)
DECLARE_VERIFIER(JSAsyncFromSyncIterator)
// Async-from-Sync Iterator instances are ordinary objects that inherit
// properties from the %AsyncFromSyncIteratorPrototype% intrinsic object.
// Async-from-Sync Iterator instances are initially created with the internal
// slots listed in Table 4.
// (proposal-async-iteration/#table-async-from-sync-iterator-internal-slots)
DECL_ACCESSORS(sync_iterator, JSReceiver)
// Offsets of object fields.
static const int kSyncIteratorOffset = JSObject::kHeaderSize;
static const int kSize = kSyncIteratorOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSAsyncFromSyncIterator);
};
class JSStringIterator : public JSObject {
public:
// Dispatched behavior.
......
......@@ -511,10 +511,18 @@ RUNTIME_FUNCTION(Runtime_AllowDynamicFunction) {
}
RUNTIME_FUNCTION(Runtime_CreateAsyncFromSyncIterator) {
// TODO(caitp): split AsyncFromSyncIterator functionality out of
// https://codereview.chromium.org/2622833002
UNREACHABLE();
return isolate->heap()->undefined_value();
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, sync_iterator, 0);
if (!sync_iterator->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kSymbolIteratorInvalid));
}
return *isolate->factory()->NewJSAsyncFromSyncIterator(
Handle<JSReceiver>::cast(sync_iterator));
}
} // namespace internal
......
......@@ -477,6 +477,7 @@
'builtins/builtins-arguments.h',
'builtins/builtins-arraybuffer.cc',
'builtins/builtins-array.cc',
'builtins/builtins-async-iterator.cc',
'builtins/builtins-async-function.cc',
'builtins/builtins-async.cc',
'builtins/builtins-async.h',
......
......@@ -43,6 +43,7 @@ class ProgramOptions final {
module_(false),
top_level_(false),
do_expressions_(false),
async_iteration_(false),
verbose_(false) {}
bool Validate() const;
......@@ -61,6 +62,7 @@ class ProgramOptions final {
bool module() const { return module_; }
bool top_level() const { return top_level_; }
bool do_expressions() const { return do_expressions_; }
bool async_iteration() const { return async_iteration_; }
bool verbose() const { return verbose_; }
bool suppress_runtime_errors() const { return rebaseline_ && !verbose_; }
std::vector<std::string> input_filenames() const { return input_filenames_; }
......@@ -77,6 +79,7 @@ class ProgramOptions final {
bool module_;
bool top_level_;
bool do_expressions_;
bool async_iteration_;
bool verbose_;
std::vector<std::string> input_filenames_;
std::string output_filename_;
......@@ -165,6 +168,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) {
options.top_level_ = true;
} else if (strcmp(argv[i], "--do-expressions") == 0) {
options.do_expressions_ = true;
} else if (strcmp(argv[i], "--async-iteration") == 0) {
options.async_iteration_ = true;
} else if (strcmp(argv[i], "--verbose") == 0) {
options.verbose_ = true;
} else if (strncmp(argv[i], "--output=", 9) == 0) {
......@@ -267,6 +272,8 @@ void ProgramOptions::UpdateFromHeader(std::istream& stream) {
top_level_ = ParseBoolean(line.c_str() + 11);
} else if (line.compare(0, 16, "do expressions: ") == 0) {
do_expressions_ = ParseBoolean(line.c_str() + 16);
} else if (line.compare(0, 17, "async iteration: ") == 0) {
async_iteration_ = ParseBoolean(line.c_str() + 17);
} else if (line == "---") {
break;
} else if (line.empty()) {
......@@ -289,6 +296,7 @@ void ProgramOptions::PrintHeader(std::ostream& stream) const { // NOLINT
if (module_) stream << "\nmodule: yes";
if (top_level_) stream << "\ntop level: yes";
if (do_expressions_) stream << "\ndo expressions: yes";
if (async_iteration_) stream << "\nasync iteration: yes";
stream << "\n\n";
}
......@@ -393,6 +401,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT
}
if (options.do_expressions()) i::FLAG_harmony_do_expressions = true;
if (options.async_iteration()) i::FLAG_harmony_async_iteration = true;
stream << "#\n# Autogenerated by generate-bytecode-expectations.\n#\n\n";
options.PrintHeader(stream);
......@@ -401,6 +410,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT
}
i::FLAG_harmony_do_expressions = false;
i::FLAG_harmony_async_iteration = false;
}
bool WriteExpectationsFile(const std::vector<std::string>& snippet_list,
......@@ -445,6 +455,7 @@ void PrintUsage(const char* exec_path) {
"Specify the name of the test function.\n"
" --top-level Process top level code, not the top-level function.\n"
" --do-expressions Enable harmony_do_expressions flag.\n"
" --async-iteration Enable harmony_async_iteration flag.\n"
" --output=file.name\n"
" Specify the output file. If not specified, output goes to "
"stdout.\n"
......
......@@ -2371,6 +2371,45 @@ TEST(NewAndSpread) {
LoadGolden("NewAndSpread.golden")));
}
TEST(ForAwaitOf) {
bool old_flag = i::FLAG_harmony_async_iteration;
i::FLAG_harmony_async_iteration = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
printer.set_wrap(false);
printer.set_test_function_name("f");
const char* snippets[] = {
"async function f() {\n"
" for await (let x of [1, 2, 3]) {}\n"
"}\n"
"f();\n",
"async function f() {\n"
" for await (let x of [1, 2, 3]) { return x; }\n"
"}\n"
"f();\n",
"async function f() {\n"
" for await (let x of [10, 20, 30]) {\n"
" if (x == 10) continue;\n"
" if (x == 20) break;\n"
" }\n"
"}\n"
"f();\n",
"async function f() {\n"
" var x = { 'a': 1, 'b': 2 };\n"
" for (x['a'] of [1,2,3]) { return x['a']; }\n"
"}\n"
"f();\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("ForAwaitOf.golden")));
i::FLAG_harmony_async_iteration = old_flag;
}
} // namespace interpreter
} // namespace internal
} // namespace v8
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment