Index: src/arm/full-codegen-arm.cc |
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc |
index 7ecc2b3df9493f5549608eb7060e7c5957c0a576..6b9c28bee900b89b6fe884f9984efb8a2ed7ebea 100644 |
--- a/src/arm/full-codegen-arm.cc |
+++ b/src/arm/full-codegen-arm.cc |
@@ -1976,6 +1976,98 @@ void FullCodeGenerator::VisitYield(Yield* expr) { |
} |
+void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
+ Expression *value, |
+ JSGeneratorObject::ResumeMode resume_mode) { |
+ // The value stays in r0, and is ultimately read by the resumed generator, as |
+ // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. r1 |
+ // will hold the generator object until the activation has been resumed. |
+ VisitForStackValue(generator); |
+ VisitForAccumulatorValue(value); |
+ __ pop(r1); |
+ |
+ // Check generator state. |
+ Label wrong_state, done; |
+ __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset)); |
+ STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); |
+ STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); |
+ __ cmp(r3, Immediate(Smi::FromInt(0))); |
+ __ b(le, &wrong_state); |
+ |
+ // Load suspended function and context. |
+ __ ldr(cp, FieldMemOperand(r1, JSGeneratorObject::kContextOffset)); |
+ __ ldr(r4, FieldMemOperand(r1, JSGeneratorObject::kFunctionOffset)); |
+ |
+ // Push holes for arguments to generator function. |
+ __ ldr(r3, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset)); |
+ __ ldr(r3, |
+ FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); |
+ __ Move(r2, isolate()->factory()->the_hole_value()); |
+ Label push_argument_holes; |
+ __ bind(&push_argument_holes); |
+ __ push(r2); |
+ __ sub(r3, r3, Immediate(1)); |
+ __ b(vc, &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); |
+ __ bl(&resume_frame); |
+ __ jmp(&done); |
+ __ bind(&resume_frame); |
+ __ push(fp); // Caller's frame pointer. |
+ __ mov(fp, sp); |
+ __ push(cp); // Callee's context. |
+ __ push(r4); // Callee's JS Function. |
+ |
+ // Load the operand stack size. |
+ __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kOperandStackOffset)); |
+ __ ldr(r3, FieldMemOperand(r3, FixedArray::kLengthOffset)); |
+ __ SmiUntag(r3); |
+ |
+ // 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(r3, Immediate(0)); |
+ __ b(ne, &slow_resume); |
+ __ ldr(r3, FieldMemOperand(r4, JSFunction::kCodeEntryOffset)); |
+ __ ldr(r2, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset)); |
+ __ SmiUntag(r2); |
+ __ add(r3, r3, r2); |
+ __ mov(r2, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))); |
+ __ str(r2, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset)); |
+ __ Jump(r3); |
+ __ 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(r3, r3, Immediate(1)); |
+ __ b(vs, &call_resume); |
+ __ push(r2); |
+ __ b(&push_operand_holes); |
+ __ bind(&call_resume); |
+ __ push(r1); |
+ __ push(result_register()); |
+ __ Push(Smi::FromInt(resume_mode)); |
+ __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); |
+ // Not reached: the runtime call returns elsewhere. |
+ __ stop("not-reached"); |
+ |
+ // Throw error if we attempt to operate on a running generator. |
+ __ bind(&wrong_state); |
+ __ push(r1); |
+ __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); |
+ |
+ __ bind(&done); |
+ context()->Plug(result_register()); |
+} |
+ |
+ |
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
SetSourcePosition(prop->position()); |
Literal* key = prop->key()->AsLiteral(); |