Index: src/ia32/full-codegen-ia32.cc |
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc |
index 113ca4b480a9827d30d47cd927168f2dfd6f2284..d3ca3d6359d9fa07ff07c1d11f85792582735507 100644 |
--- a/src/ia32/full-codegen-ia32.cc |
+++ b/src/ia32/full-codegen-ia32.cc |
@@ -1937,6 +1937,98 @@ void FullCodeGenerator::VisitYield(Yield* expr) { |
} |
+void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
+ Expression *value, |
+ JSGeneratorObject::ResumeMode resume_mode) { |
+ // The value stays in eax, and is ultimately read by the resumed generator, as |
+ // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. ebx |
+ // will hold the generator object until the activation has been resumed. |
+ VisitForStackValue(generator); |
+ VisitForAccumulatorValue(value); |
+ __ pop(ebx); |
+ |
+ // Check generator state. |
+ Label wrong_state, done; |
+ STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); |
+ STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); |
+ __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset), |
+ Immediate(Smi::FromInt(0))); |
+ __ j(less_equal, &wrong_state); |
+ |
+ // Load suspended function and context. |
+ __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset)); |
+ __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset)); |
+ |
+ // Push holes for arguments to generator function. |
+ __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ mov(edx, |
+ FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
+ __ mov(ecx, isolate()->factory()->the_hole_value()); |
+ Label push_argument_holes; |
+ __ bind(&push_argument_holes); |
+ __ push(ecx); |
+ __ sub(edx, 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(ebp); // Caller's frame pointer. |
+ __ mov(ebp, esp); |
+ __ push(esi); // Callee's context. |
+ __ push(edi); // Callee's JS Function. |
+ |
+ // Load the operand stack size. |
+ __ mov(edx, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset)); |
+ __ mov(edx, FieldOperand(edx, FixedArray::kLengthOffset)); |
+ __ SmiUntag(edx); |
+ |
+ // 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; |
+ __ cmp(edx, Immediate(0)); |
+ __ j(not_zero, &slow_resume); |
+ __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); |
+ __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset)); |
+ __ SmiUntag(ecx); |
+ __ add(edx, ecx); |
+ __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset), |
+ Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))); |
+ __ jmp(edx); |
+ __ 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); |
+ __ sub(edx, Immediate(1)); |
+ __ j(carry, &call_resume); |
+ __ push(ecx); |
+ __ jmp(&push_operand_holes); |
+ __ bind(&call_resume); |
+ __ push(ebx); |
+ __ 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(ebx); |
+ __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); |
+ |
+ __ bind(&done); |
+ context()->Plug(result_register()); |
+} |
+ |
+ |
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
SetSourcePosition(prop->position()); |
Literal* key = prop->key()->AsLiteral(); |