Chromium Code Reviews| Index: src/builtins/x64/builtins-x64.cc | 
| diff --git a/src/builtins/x64/builtins-x64.cc b/src/builtins/x64/builtins-x64.cc | 
| index 87dfc7d3a6b6305a4d7ec63c05c36e47b5418a7c..16e9d00cf56e96ca24953e9f5558c5f67f5844a8 100644 | 
| --- a/src/builtins/x64/builtins-x64.cc | 
| +++ b/src/builtins/x64/builtins-x64.cc | 
| @@ -559,6 +559,132 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { | 
| __ jmp(&stepping_prepared); | 
| } | 
| +// static | 
| +void Builtins::Generate_ResumeAwaitedGeneratorTrampoline(MacroAssembler* masm) { | 
| + // ----------- S t a t e ------------- | 
| + // -- rax : the value to pass to the generator | 
| + // -- rbx : the JSGeneratorObject to resume | 
| 
 
Dan Ehrenberg
2017/01/13 19:41:09
Presumably this would only be called on JSAsyncGen
 
caitp
2017/01/13 20:11:52
Yes, will update the comment. I don't think it's w
 
 | 
| + // -- rdx : the resume mode (tagged) | 
| + // -- rsp[0] : return address | 
| + // ----------------------------------- | 
| + __ AssertGeneratorObject(rbx); | 
| + | 
| + // Restore saved input | 
| + __ movp(rcx, FieldOperand(rbx, JSGeneratorObject::kAwaitInputOffset)); | 
| + __ movp(FieldOperand(rbx, JSGeneratorObject::kInputOrDebugPosOffset), rcx); | 
| + __ RecordWriteField(rbx, JSGeneratorObject::kInputOrDebugPosOffset, rcx, rsi, | 
| + kDontSaveFPRegs); | 
| + | 
| + // Store input value into generator object. | 
| + __ movp(FieldOperand(rbx, JSGeneratorObject::kAwaitInputOffset), rax); | 
| + __ RecordWriteField(rbx, JSGeneratorObject::kAwaitInputOffset, rax, rcx, | 
| + kDontSaveFPRegs); | 
| 
 
Dan Ehrenberg
2017/01/13 19:41:09
Is the only difference here vs Generate_ResumeGene
 
caitp
2017/01/13 20:11:52
I agree :D but... I kind of want to avoid adding a
 
 | 
| + | 
| + // Store resume mode into generator object. | 
| + __ movp(FieldOperand(rbx, JSGeneratorObject::kResumeModeOffset), rdx); | 
| + | 
| + // Load suspended function and context. | 
| + __ movp(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset)); | 
| + __ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset)); | 
| + | 
| + // Flood function if we are stepping. | 
| + Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator; | 
| + Label stepping_prepared; | 
| + ExternalReference last_step_action = | 
| + ExternalReference::debug_last_step_action_address(masm->isolate()); | 
| + Operand last_step_action_operand = masm->ExternalOperand(last_step_action); | 
| + STATIC_ASSERT(StepFrame > StepIn); | 
| + __ cmpb(last_step_action_operand, Immediate(StepIn)); | 
| + __ j(greater_equal, &prepare_step_in_if_stepping); | 
| + | 
| + // Flood function if we need to continue stepping in the suspended generator. | 
| + ExternalReference debug_suspended_generator = | 
| + ExternalReference::debug_suspended_generator_address(masm->isolate()); | 
| + Operand debug_suspended_generator_operand = | 
| + masm->ExternalOperand(debug_suspended_generator); | 
| + __ cmpp(rbx, debug_suspended_generator_operand); | 
| + __ j(equal, &prepare_step_in_suspended_generator); | 
| + __ bind(&stepping_prepared); | 
| + | 
| + // Pop return address. | 
| + __ PopReturnAddressTo(rax); | 
| + | 
| + // Push receiver. | 
| + __ Push(FieldOperand(rbx, JSGeneratorObject::kReceiverOffset)); | 
| + | 
| + // ----------- S t a t e ------------- | 
| + // -- rax : return address | 
| + // -- rbx : the JSGeneratorObject to resume | 
| + // -- rdx : the resume mode (tagged) | 
| + // -- rdi : generator function | 
| + // -- rsi : generator context | 
| + // -- rsp[0] : generator receiver | 
| + // ----------------------------------- | 
| + | 
| + // Push holes for arguments to generator function. Since the parser forced | 
| + // context allocation for any variables in generators, the actual argument | 
| + // values have already been copied into the context and these dummy values | 
| + // will never be used. | 
| + __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 
| + __ LoadSharedFunctionInfoSpecialField( | 
| + rcx, rcx, SharedFunctionInfo::kFormalParameterCountOffset); | 
| + { | 
| + Label done_loop, loop; | 
| + __ bind(&loop); | 
| + __ subl(rcx, Immediate(1)); | 
| + __ j(carry, &done_loop, Label::kNear); | 
| + __ PushRoot(Heap::kTheHoleValueRootIndex); | 
| + __ jmp(&loop); | 
| + __ bind(&done_loop); | 
| + } | 
| + | 
| + // Underlying function needs to have bytecode available. | 
| + if (FLAG_debug_code) { | 
| + __ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 
| + __ movp(rcx, FieldOperand(rcx, SharedFunctionInfo::kFunctionDataOffset)); | 
| + __ CmpObjectType(rcx, BYTECODE_ARRAY_TYPE, rcx); | 
| + __ Assert(equal, kMissingBytecodeArray); | 
| + } | 
| + | 
| + // Resume (Ignition/TurboFan) generator object. | 
| + { | 
| + __ PushReturnAddressFrom(rax); | 
| + __ movp(rax, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 
| + __ LoadSharedFunctionInfoSpecialField( | 
| + rax, rax, SharedFunctionInfo::kFormalParameterCountOffset); | 
| + // We abuse new.target both to indicate that this is a resume call and to | 
| + // pass in the generator object. In ordinary calls, new.target is always | 
| + // undefined because generator functions are non-constructable. | 
| + __ movp(rdx, rbx); | 
| + __ jmp(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); | 
| + } | 
| + | 
| + __ bind(&prepare_step_in_if_stepping); | 
| + { | 
| + FrameScope scope(masm, StackFrame::INTERNAL); | 
| + __ Push(rbx); | 
| + __ Push(rdx); | 
| + __ Push(rdi); | 
| + __ CallRuntime(Runtime::kDebugPrepareStepInIfStepping); | 
| + __ Pop(rdx); | 
| + __ Pop(rbx); | 
| + __ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset)); | 
| + } | 
| + __ jmp(&stepping_prepared); | 
| + | 
| + __ bind(&prepare_step_in_suspended_generator); | 
| + { | 
| + FrameScope scope(masm, StackFrame::INTERNAL); | 
| + __ Push(rbx); | 
| + __ Push(rdx); | 
| + __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator); | 
| + __ Pop(rdx); | 
| + __ Pop(rbx); | 
| + __ movp(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset)); | 
| + } | 
| + __ jmp(&stepping_prepared); | 
| +} | 
| + | 
| static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1, | 
| Register scratch2) { | 
| Register args_count = scratch1; |