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