Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index c942d029d45e0614ee8e5cd6cf84ebf84fc962b2..ee717c7cee6d627b1c32c3c6b3fea37dc50d7a05 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -2421,51 +2421,51 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) { |
RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { |
- HandleScope scope(isolate); |
+ NoHandleAllocation ha(isolate); |
ASSERT(args.length() == 1); |
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); |
+ CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); |
JavaScriptFrameIterator stack_iterator(isolate); |
- JavaScriptFrame *frame = stack_iterator.frame(); |
- Handle<JSFunction> function(JSFunction::cast(frame->function())); |
+ JavaScriptFrame* frame = stack_iterator.frame(); |
+ JSFunction* function = JSFunction::cast(frame->function()); |
RUNTIME_ASSERT(function->shared()->is_generator()); |
+ ASSERT_EQ(function, generator_object->function()); |
- intptr_t offset = frame->pc() - function->code()->instruction_start(); |
- ASSERT(*function == generator_object->function()); |
- ASSERT(offset > 0 && Smi::IsValid(offset)); |
- generator_object->set_continuation(static_cast<int>(offset)); |
+ // We expect there to be at least two values on the operand stack: the return |
+ // value of the yield expression, and the argument to this runtime call. |
+ // Neither of those should be saved. |
+ int operands_count = frame->ComputeOperandsCount(); |
+ ASSERT(operands_count >= 2); |
+ operands_count -= 2; |
- // Generator functions force context allocation for locals, so Local0 points |
- // to the bottom of the operand stack. Assume the stack grows down. |
- // |
- // TODO(wingo): Move these magical calculations to frames.h when the |
- // generators implementation has stabilized. |
- intptr_t stack_size_in_bytes = |
- (frame->fp() + JavaScriptFrameConstants::kLocal0Offset) - |
- (frame->sp() - kPointerSize); |
- ASSERT(IsAddressAligned(frame->fp(), kPointerSize)); |
- ASSERT(IsAligned(stack_size_in_bytes, kPointerSize)); |
- ASSERT(stack_size_in_bytes >= 0); |
- ASSERT(Smi::IsValid(stack_size_in_bytes)); |
- intptr_t stack_size = stack_size_in_bytes >> kPointerSizeLog2; |
- |
- // We expect there to be at least two values on the stack: the return value of |
- // the yield expression, and the argument to this runtime call. Neither of |
- // those should be saved. |
- ASSERT(stack_size >= 2); |
- stack_size -= 2; |
- |
- if (stack_size == 0) { |
+ if (operands_count == 0) { |
ASSERT_EQ(generator_object->operand_stack(), |
isolate->heap()->empty_fixed_array()); |
// If there are no operands on the stack, there shouldn't be a handler |
// active either. |
ASSERT(!frame->HasHandler()); |
} else { |
- // TODO(wingo): Save the operand stack and/or the stack handlers. |
- UNIMPLEMENTED(); |
+ if (frame->HasHandler()) { |
+ // TODO(wingo): Unwind the stack handlers. |
+ UNIMPLEMENTED(); |
+ } |
+ |
+ FixedArray* operand_stack; |
+ MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count); |
+ if (!alloc->To(&operand_stack)) return alloc; |
+ |
+ for (int i = 0; i < operands_count; i++) { |
+ operand_stack->set(i, frame->GetOperand(i)); |
+ } |
+ generator_object->set_operand_stack(operand_stack); |
} |
+ // Set continuation down here to avoid side effects if the operand stack |
+ // allocation fails. |
+ intptr_t offset = frame->pc() - function->code()->instruction_start(); |
+ ASSERT(offset > 0 && Smi::IsValid(offset)); |
+ generator_object->set_continuation(offset); |
+ |
// It's possible for the context to be other than the initial context even if |
// there is no stack handler active. For example, this is the case in the |
// body of a "with" statement. Therefore we always save the context. |
@@ -2485,13 +2485,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { |
// EmitGeneratorResumeResume is called in any case, as it needs to reconstruct |
// the stack frame and make space for arguments and operands. |
RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { |
- HandleScope scope(isolate); |
+ NoHandleAllocation ha(isolate); |
ASSERT(args.length() == 3); |
- CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); |
- CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); |
+ CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); |
+ CONVERT_ARG_CHECKED(Object, value, 1); |
CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); |
JavaScriptFrameIterator stack_iterator(isolate); |
- JavaScriptFrame *frame = stack_iterator.frame(); |
+ JavaScriptFrame* frame = stack_iterator.frame(); |
ASSERT_EQ(frame->function(), generator_object->function()); |
@@ -2504,18 +2504,26 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { |
frame->set_pc(pc + offset); |
generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); |
- if (generator_object->operand_stack()->length() != 0) { |
- // TODO(wingo): Copy operand stack. Rewind handlers. |
- UNIMPLEMENTED(); |
+ FixedArray* operand_stack = generator_object->operand_stack(); |
+ int operands_count = operand_stack->length(); |
+ if (operands_count != 0) { |
+ // TODO(wingo): Rewind stack handlers. However until |
+ // SuspendJSGeneratorObject unwinds them, we won't see frames with stack |
+ // handlers here. |
+ for (int i = 0; i < operands_count; i++) { |
+ ASSERT_EQ(frame->GetOperand(i), isolate->heap()->the_hole_value()); |
+ Memory::Object_at(frame->GetOperandSlot(i)) = operand_stack->get(i); |
+ } |
+ generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); |
} |
JSGeneratorObject::ResumeMode resume_mode = |
static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); |
switch (resume_mode) { |
case JSGeneratorObject::SEND: |
- return *value; |
+ return value; |
case JSGeneratorObject::THROW: |
- return isolate->Throw(*value); |
+ return isolate->Throw(value); |
} |
UNREACHABLE(); |
@@ -2528,7 +2536,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) { |
ASSERT(args.length() == 1); |
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
int continuation = generator->continuation(); |
- const char *message = continuation == JSGeneratorObject::kGeneratorClosed ? |
+ const char* message = continuation == JSGeneratorObject::kGeneratorClosed ? |
"generator_finished" : "generator_running"; |
Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0); |
Handle<Object> error = isolate->factory()->NewError(message, argv); |