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; |