Chromium Code Reviews| Index: src/interpreter/bytecode-generator.cc | 
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc | 
| index 7279f69d8a01c554e1b0b627f423c994331568f8..82cc63decaa62be170a2c9e06d6a6977bd1f459f 100644 | 
| --- a/src/interpreter/bytecode-generator.cc | 
| +++ b/src/interpreter/bytecode-generator.cc | 
| @@ -585,6 +585,8 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) | 
| loop_depth_(0), | 
| home_object_symbol_(info->isolate()->factory()->home_object_symbol()), | 
| iterator_symbol_(info->isolate()->factory()->iterator_symbol()), | 
| + async_iterator_symbol_( | 
| + info->isolate()->factory()->async_iterator_symbol()), | 
| empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()) { | 
| AstValueFactory* ast_value_factory = info->parse_info()->ast_value_factory(); | 
| const AstRawString* prototype_string = ast_value_factory->prototype_string(); | 
| @@ -2244,12 +2246,44 @@ void BytecodeGenerator::VisitYield(Yield* expr) { | 
| Register generator = VisitForRegisterValue(expr->generator_object()); | 
| - // Save context, registers, and state. Then return. | 
| - builder() | 
| - ->LoadLiteral(Smi::FromInt(expr->yield_id())) | 
| - .SuspendGenerator(generator) | 
| - .LoadAccumulatorWithRegister(value) | 
| - .Return(); // Hard return (ignore any finally blocks). | 
| + const bool kIsAsyncGenerator = | 
| + IsAsyncGeneratorFunction(scope()->function_kind()); | 
| + | 
| + if (kIsAsyncGenerator && expr->yield_id() > 0 && | 
| + expr->yield_type() != Yield::kAwait) { | 
| + RegisterList args = register_allocator()->NewRegisterList(2); | 
| + | 
| + int context_index = Context::ASYNC_GENERATOR_YIELD; | 
| + if (expr->yield_type() == Yield::kDelegate) { | 
| + // Avoid wrapping in iterator result for yield* yields | 
| + context_index = Context::ASYNC_GENERATOR_RAW_YIELD; | 
| + } | 
| + | 
| + builder() | 
| + ->LoadLiteral(Smi::FromInt(expr->yield_id())) | 
| + .SuspendGenerator(generator) | 
| + .MoveRegister(generator, args[0]) | 
| + .MoveRegister(value, args[1]) | 
| + .CallJSRuntime(context_index, args) | 
| + .Return(); // Hard return (ignore any finally blocks). | 
| + } else { | 
| + // Save context, registers, and state. Then return. | 
| + if (IsAsyncGeneratorFunction(scope()->function_kind()) && | 
| + expr->yield_type() == Yield::kAwait) { | 
| + // For Await expressions in async generators, store the original | 
| + // generator input in the await input position, so it can be restored | 
| + // later. The first Yield can never be an Await. | 
| + DCHECK_GE(expr->yield_id(), 1); | 
| + builder()->CallRuntime(Runtime::kInlineGeneratorSaveInputForAwait, | 
| + generator); | 
| + } | 
| + | 
| + builder() | 
| + ->LoadLiteral(Smi::FromInt(expr->yield_id())) | 
| + .SuspendGenerator(generator) | 
| + .LoadAccumulatorWithRegister(value) | 
| + .Return(); // Hard return (ignore any finally blocks). | 
| + } | 
| builder()->Bind(&(generator_resume_points_[expr->yield_id()])); | 
| // Upon resume, we continue here. | 
| @@ -2264,9 +2298,17 @@ void BytecodeGenerator::VisitYield(Yield* expr) { | 
| .StoreAccumulatorInRegister(generator_state_); | 
| Register input = register_allocator()->NewRegister(); | 
| - builder() | 
| - ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) | 
| - .StoreAccumulatorInRegister(input); | 
| + if (!kIsAsyncGenerator || expr->yield_type() != Yield::kAwait) { | 
| + builder() | 
| + ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) | 
| + .StoreAccumulatorInRegister(input); | 
| + } else { | 
| + // When resuming from an Await expression, the sent value is in the | 
| + // await input slot. | 
| + builder() | 
| + ->CallRuntime(Runtime::kInlineGeneratorGetAwaitInput, generator) | 
| 
 
Dan Ehrenberg
2017/01/14 00:48:38
Nit: 'GeneratorGetAwaitInput' is a sort of funny n
 
 | 
| + .StoreAccumulatorInRegister(input); | 
| + } | 
| Register resume_mode = register_allocator()->NewRegister(); | 
| builder() | 
| @@ -2888,21 +2930,61 @@ void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { | 
| VisitForAccumulatorValue(expr->iterable()); | 
| - // Let method be GetMethod(obj, @@iterator). | 
| - builder() | 
| - ->StoreAccumulatorInRegister(obj) | 
| - .LoadNamedProperty(obj, iterator_symbol(), feedback_index(load_slot)) | 
| - .StoreAccumulatorInRegister(method); | 
| - | 
| - // Let iterator be Call(method, obj). | 
| - builder()->Call(method, args, feedback_index(call_slot), | 
| - Call::NAMED_PROPERTY_CALL); | 
| - | 
| - // If Type(iterator) is not Object, throw a TypeError exception. | 
| - BytecodeLabel no_type_error; | 
| - builder()->JumpIfJSReceiver(&no_type_error); | 
| - builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); | 
| - builder()->Bind(&no_type_error); | 
| + if (expr->hint() == GetIterator::kAsync) { | 
| + FeedbackVectorSlot load_slot2 = expr->AsyncIteratorPropertyFeedbackSlot(); | 
| + FeedbackVectorSlot call_slot2 = expr->AsyncIteratorCallFeedbackSlot(); | 
| + | 
| + // Set method to GetMethod(obj, @@asyncIterator) | 
| + builder()->StoreAccumulatorInRegister(obj).LoadNamedProperty( | 
| + obj, async_iterator_symbol(), feedback_index(load_slot2)); | 
| + | 
| + BytecodeLabel create_async_from_sync, done; | 
| + builder()->JumpIfUndefined(&create_async_from_sync); | 
| + | 
| + // Let iterator be Call(method, obj) | 
| + builder()->StoreAccumulatorInRegister(method).Call( | 
| + method, args, feedback_index(call_slot), Call::NAMED_PROPERTY_CALL); | 
| + | 
| + // If Type(iterator) is not Object, throw a TypeError exception. | 
| + builder()->JumpIfJSReceiver(&done); | 
| + builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid); | 
| + | 
| + builder()->Bind(&create_async_from_sync); | 
| + // If method is undefined, | 
| + // Let syncMethod be GetMethod(obj, @@iterator) | 
| + builder() | 
| + ->LoadNamedProperty(obj, iterator_symbol(), feedback_index(load_slot)) | 
| + .StoreAccumulatorInRegister(method); | 
| + | 
| + // Let syncIterator be Call(syncMethod, obj) | 
| + builder()->Call(method, args, feedback_index(call_slot2), | 
| + Call::NAMED_PROPERTY_CALL); | 
| + | 
| + // Return CreateAsyncFromSyncIterator(syncIterator) | 
| + RegisterList args = register_allocator()->NewRegisterList(1); | 
| + Register sync_iterator = args[0]; | 
| + builder() | 
| + ->StoreAccumulatorInRegister(sync_iterator) | 
| + .CallRuntime(Runtime::kInlineCreateAsyncFromSyncIterator, args); | 
| + | 
| + builder()->Bind(&done); | 
| + } else { | 
| + // Let method be GetMethod(obj, @@iterator). | 
| + builder() | 
| + ->StoreAccumulatorInRegister(obj) | 
| + .LoadNamedProperty(obj, iterator_symbol(), feedback_index(load_slot)) | 
| + .StoreAccumulatorInRegister(method); | 
| + | 
| + // Let iterator be Call(method, obj). | 
| + builder()->Call(method, args, feedback_index(call_slot), | 
| + Call::NAMED_PROPERTY_CALL); | 
| + | 
| + // If Type(iterator) is not Object, throw a TypeError exception. | 
| + BytecodeLabel no_type_error; | 
| + builder()->JumpIfJSReceiver(&no_type_error); | 
| + builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); | 
| + builder()->Bind(&no_type_error); | 
| + } | 
| } | 
| void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { |