Index: src/x64/full-codegen-x64.cc |
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc |
index f9651f01efad26a02bbdf1e86df2745c1b943258..86dd4e10a4f3d32d1b487a5121500537cc1bb871 100644 |
--- a/src/x64/full-codegen-x64.cc |
+++ b/src/x64/full-codegen-x64.cc |
@@ -1961,6 +1961,99 @@ void FullCodeGenerator::VisitYield(Yield* expr) { |
} |
+void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
+ Expression *value, |
+ JSGeneratorObject::ResumeMode resume_mode) { |
+ // The value stays in rax, and is ultimately read by the resumed generator, as |
+ // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. rbx |
+ // will hold the generator object until the activation has been resumed. |
+ VisitForStackValue(generator); |
+ VisitForAccumulatorValue(value); |
+ __ pop(rbx); |
+ |
+ // Check generator state. |
+ Label wrong_state, done; |
+ STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); |
+ STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); |
+ __ SmiCompare(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset), |
+ Smi::FromInt(0)); |
+ __ j(less_equal, &wrong_state); |
+ |
+ // Load suspended function and context. |
+ __ movq(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset)); |
+ __ movq(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset)); |
+ |
+ // Push holes for arguments to generator function. |
+ __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ movsxlq(rdx, |
+ FieldOperand(rdx, |
+ SharedFunctionInfo::kFormalParameterCountOffset)); |
+ __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex); |
+ Label push_argument_holes; |
+ __ bind(&push_argument_holes); |
+ __ push(rcx); |
+ __ subq(rdx, Immediate(1)); |
+ __ j(not_carry, &push_argument_holes); |
+ |
+ // Enter a new JavaScript frame, and initialize its slots as they were when |
+ // the generator was suspended. |
+ Label push_frame, resume_frame; |
+ __ bind(&push_frame); |
+ __ call(&resume_frame); |
+ __ jmp(&done); |
+ __ bind(&resume_frame); |
+ __ push(rbp); // Caller's frame pointer. |
+ __ movq(rbp, rsp); |
+ __ push(rsi); // Callee's context. |
+ __ push(rdi); // Callee's JS Function. |
+ |
+ // Load the operand stack size. |
+ __ movq(rdx, FieldOperand(rbx, JSGeneratorObject::kOperandStackOffset)); |
+ __ movq(rdx, FieldOperand(rdx, FixedArray::kLengthOffset)); |
+ __ SmiToInteger32(rdx, rdx); |
+ |
+ // If we are sending a value and there is no operand stack, we can jump back |
+ // in directly. |
+ if (resume_mode == JSGeneratorObject::SEND) { |
+ Label slow_resume; |
+ __ cmpq(rdx, Immediate(0)); |
+ __ j(not_zero, &slow_resume); |
+ __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
+ __ SmiToInteger64(rcx, |
+ FieldOperand(rbx, JSGeneratorObject::kContinuationOffset)); |
+ __ addq(rdx, rcx); |
+ __ Move(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset), |
+ Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)); |
+ __ jmp(rdx); |
+ __ bind(&slow_resume); |
+ } |
+ |
+ // Otherwise, we push holes for the operand stack and call the runtime to fix |
+ // up the stack and the handlers. |
+ Label push_operand_holes, call_resume; |
+ __ bind(&push_operand_holes); |
+ __ subq(rdx, Immediate(1)); |
+ __ j(carry, &call_resume); |
+ __ push(rcx); |
+ __ jmp(&push_operand_holes); |
+ __ bind(&call_resume); |
+ __ push(rbx); |
+ __ push(result_register()); |
+ __ Push(Smi::FromInt(resume_mode)); |
+ __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); |
+ // Not reached: the runtime call returns elsewhere. |
+ __ Abort("Generator failed to resume."); |
+ |
+ // Throw error if we attempt to operate on a running generator. |
+ __ bind(&wrong_state); |
+ __ push(rbx); |
+ __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); |
+ |
+ __ bind(&done); |
+ context()->Plug(result_register()); |
+} |
+ |
+ |
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
SetSourcePosition(prop->position()); |
Literal* key = prop->key()->AsLiteral(); |