1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins-utils.h" 7 8 #include "src/code-factory.h" 9 10 namespace v8 { 11 namespace internal { 12 13 namespace { 14 15 void Generate_GeneratorPrototypeResume( 16 CodeStubAssembler* assembler, JSGeneratorObject::ResumeMode resume_mode, 17 char const* const method_name) { 18 typedef CodeStubAssembler::Label Label; 19 typedef compiler::Node Node; 20 21 Node* receiver = assembler->Parameter(0); 22 Node* value = assembler->Parameter(1); 23 Node* context = assembler->Parameter(4); 24 Node* closed = 25 assembler->SmiConstant(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)); 26 27 // Check if the {receiver} is actually a JSGeneratorObject. 28 Label if_receiverisincompatible(assembler, Label::kDeferred); 29 assembler->GotoIf(assembler->TaggedIsSmi(receiver), 30 &if_receiverisincompatible); 31 Node* receiver_instance_type = assembler->LoadInstanceType(receiver); 32 assembler->GotoUnless(assembler->Word32Equal( 33 receiver_instance_type, 34 assembler->Int32Constant(JS_GENERATOR_OBJECT_TYPE)), 35 &if_receiverisincompatible); 36 37 // Check if the {receiver} is running or already closed. 38 Node* receiver_continuation = assembler->LoadObjectField( 39 receiver, JSGeneratorObject::kContinuationOffset); 40 Label if_receiverisclosed(assembler, Label::kDeferred), 41 if_receiverisrunning(assembler, Label::kDeferred); 42 assembler->GotoIf(assembler->SmiEqual(receiver_continuation, closed), 43 &if_receiverisclosed); 44 DCHECK_LT(JSGeneratorObject::kGeneratorExecuting, 45 JSGeneratorObject::kGeneratorClosed); 46 assembler->GotoIf(assembler->SmiLessThan(receiver_continuation, closed), 47 &if_receiverisrunning); 48 49 // Resume the {receiver} using our trampoline. 50 Node* result = assembler->CallStub( 51 CodeFactory::ResumeGenerator(assembler->isolate()), context, value, 52 receiver, assembler->SmiConstant(Smi::FromInt(resume_mode))); 53 assembler->Return(result); 54 55 assembler->Bind(&if_receiverisincompatible); 56 { 57 // The {receiver} is not a valid JSGeneratorObject. 58 Node* result = assembler->CallRuntime( 59 Runtime::kThrowIncompatibleMethodReceiver, context, 60 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( 61 method_name, TENURED)), 62 receiver); 63 assembler->Return(result); // Never reached. 64 } 65 66 assembler->Bind(&if_receiverisclosed); 67 { 68 // The {receiver} is closed already. 69 Node* result = nullptr; 70 switch (resume_mode) { 71 case JSGeneratorObject::kNext: 72 result = assembler->CallRuntime(Runtime::kCreateIterResultObject, 73 context, assembler->UndefinedConstant(), 74 assembler->BooleanConstant(true)); 75 break; 76 case JSGeneratorObject::kReturn: 77 result = 78 assembler->CallRuntime(Runtime::kCreateIterResultObject, context, 79 value, assembler->BooleanConstant(true)); 80 break; 81 case JSGeneratorObject::kThrow: 82 result = assembler->CallRuntime(Runtime::kThrow, context, value); 83 break; 84 } 85 assembler->Return(result); 86 } 87 88 assembler->Bind(&if_receiverisrunning); 89 { 90 Node* result = 91 assembler->CallRuntime(Runtime::kThrowGeneratorRunning, context); 92 assembler->Return(result); // Never reached. 93 } 94 } 95 96 } // anonymous namespace 97 98 // ES6 section 25.3.1.2 Generator.prototype.next ( value ) 99 void Builtins::Generate_GeneratorPrototypeNext(CodeStubAssembler* assembler) { 100 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kNext, 101 "[Generator].prototype.next"); 102 } 103 104 // ES6 section 25.3.1.3 Generator.prototype.return ( value ) 105 void Builtins::Generate_GeneratorPrototypeReturn(CodeStubAssembler* assembler) { 106 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kReturn, 107 "[Generator].prototype.return"); 108 } 109 110 // ES6 section 25.3.1.4 Generator.prototype.throw ( exception ) 111 void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) { 112 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kThrow, 113 "[Generator].prototype.throw"); 114 } 115 116 } // namespace internal 117 } // namespace v8 118