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