OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/v8.h" |
| 6 |
| 7 #include "src/arguments.h" |
| 8 #include "src/frames-inl.h" |
| 9 #include "src/runtime/runtime.h" |
| 10 #include "src/runtime/runtime-utils.h" |
| 11 |
| 12 namespace v8 { |
| 13 namespace internal { |
| 14 |
| 15 RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) { |
| 16 HandleScope scope(isolate); |
| 17 DCHECK(args.length() == 0); |
| 18 |
| 19 JavaScriptFrameIterator it(isolate); |
| 20 JavaScriptFrame* frame = it.frame(); |
| 21 Handle<JSFunction> function(frame->function()); |
| 22 RUNTIME_ASSERT(function->shared()->is_generator()); |
| 23 |
| 24 Handle<JSGeneratorObject> generator; |
| 25 if (frame->IsConstructor()) { |
| 26 generator = handle(JSGeneratorObject::cast(frame->receiver())); |
| 27 } else { |
| 28 generator = isolate->factory()->NewJSGeneratorObject(function); |
| 29 } |
| 30 generator->set_function(*function); |
| 31 generator->set_context(Context::cast(frame->context())); |
| 32 generator->set_receiver(frame->receiver()); |
| 33 generator->set_continuation(0); |
| 34 generator->set_operand_stack(isolate->heap()->empty_fixed_array()); |
| 35 generator->set_stack_handler_index(-1); |
| 36 |
| 37 return *generator; |
| 38 } |
| 39 |
| 40 |
| 41 RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) { |
| 42 HandleScope handle_scope(isolate); |
| 43 DCHECK(args.length() == 1); |
| 44 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); |
| 45 |
| 46 JavaScriptFrameIterator stack_iterator(isolate); |
| 47 JavaScriptFrame* frame = stack_iterator.frame(); |
| 48 RUNTIME_ASSERT(frame->function()->shared()->is_generator()); |
| 49 DCHECK_EQ(frame->function(), generator_object->function()); |
| 50 |
| 51 // The caller should have saved the context and continuation already. |
| 52 DCHECK_EQ(generator_object->context(), Context::cast(frame->context())); |
| 53 DCHECK_LT(0, generator_object->continuation()); |
| 54 |
| 55 // We expect there to be at least two values on the operand stack: the return |
| 56 // value of the yield expression, and the argument to this runtime call. |
| 57 // Neither of those should be saved. |
| 58 int operands_count = frame->ComputeOperandsCount(); |
| 59 DCHECK_GE(operands_count, 2); |
| 60 operands_count -= 2; |
| 61 |
| 62 if (operands_count == 0) { |
| 63 // Although it's semantically harmless to call this function with an |
| 64 // operands_count of zero, it is also unnecessary. |
| 65 DCHECK_EQ(generator_object->operand_stack(), |
| 66 isolate->heap()->empty_fixed_array()); |
| 67 DCHECK_EQ(generator_object->stack_handler_index(), -1); |
| 68 // If there are no operands on the stack, there shouldn't be a handler |
| 69 // active either. |
| 70 DCHECK(!frame->HasHandler()); |
| 71 } else { |
| 72 int stack_handler_index = -1; |
| 73 Handle<FixedArray> operand_stack = |
| 74 isolate->factory()->NewFixedArray(operands_count); |
| 75 frame->SaveOperandStack(*operand_stack, &stack_handler_index); |
| 76 generator_object->set_operand_stack(*operand_stack); |
| 77 generator_object->set_stack_handler_index(stack_handler_index); |
| 78 } |
| 79 |
| 80 return isolate->heap()->undefined_value(); |
| 81 } |
| 82 |
| 83 |
| 84 // Note that this function is the slow path for resuming generators. It is only |
| 85 // called if the suspended activation had operands on the stack, stack handlers |
| 86 // needing rewinding, or if the resume should throw an exception. The fast path |
| 87 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is |
| 88 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is |
| 89 // called in any case, as it needs to reconstruct the stack frame and make space |
| 90 // for arguments and operands. |
| 91 RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) { |
| 92 SealHandleScope shs(isolate); |
| 93 DCHECK(args.length() == 3); |
| 94 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); |
| 95 CONVERT_ARG_CHECKED(Object, value, 1); |
| 96 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); |
| 97 JavaScriptFrameIterator stack_iterator(isolate); |
| 98 JavaScriptFrame* frame = stack_iterator.frame(); |
| 99 |
| 100 DCHECK_EQ(frame->function(), generator_object->function()); |
| 101 DCHECK(frame->function()->is_compiled()); |
| 102 |
| 103 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); |
| 104 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); |
| 105 |
| 106 Address pc = generator_object->function()->code()->instruction_start(); |
| 107 int offset = generator_object->continuation(); |
| 108 DCHECK(offset > 0); |
| 109 frame->set_pc(pc + offset); |
| 110 if (FLAG_enable_ool_constant_pool) { |
| 111 frame->set_constant_pool( |
| 112 generator_object->function()->code()->constant_pool()); |
| 113 } |
| 114 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); |
| 115 |
| 116 FixedArray* operand_stack = generator_object->operand_stack(); |
| 117 int operands_count = operand_stack->length(); |
| 118 if (operands_count != 0) { |
| 119 frame->RestoreOperandStack(operand_stack, |
| 120 generator_object->stack_handler_index()); |
| 121 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); |
| 122 generator_object->set_stack_handler_index(-1); |
| 123 } |
| 124 |
| 125 JSGeneratorObject::ResumeMode resume_mode = |
| 126 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); |
| 127 switch (resume_mode) { |
| 128 case JSGeneratorObject::NEXT: |
| 129 return value; |
| 130 case JSGeneratorObject::THROW: |
| 131 return isolate->Throw(value); |
| 132 } |
| 133 |
| 134 UNREACHABLE(); |
| 135 return isolate->ThrowIllegalOperation(); |
| 136 } |
| 137 |
| 138 |
| 139 RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) { |
| 140 HandleScope scope(isolate); |
| 141 DCHECK(args.length() == 1); |
| 142 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
| 143 int continuation = generator->continuation(); |
| 144 const char* message = continuation == JSGeneratorObject::kGeneratorClosed |
| 145 ? "generator_finished" |
| 146 : "generator_running"; |
| 147 Vector<Handle<Object> > argv = HandleVector<Object>(NULL, 0); |
| 148 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv)); |
| 149 } |
| 150 |
| 151 |
| 152 // Returns function of generator activation. |
| 153 RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) { |
| 154 HandleScope scope(isolate); |
| 155 DCHECK(args.length() == 1); |
| 156 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
| 157 |
| 158 return generator->function(); |
| 159 } |
| 160 |
| 161 |
| 162 // Returns context of generator activation. |
| 163 RUNTIME_FUNCTION(Runtime_GeneratorGetContext) { |
| 164 HandleScope scope(isolate); |
| 165 DCHECK(args.length() == 1); |
| 166 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
| 167 |
| 168 return generator->context(); |
| 169 } |
| 170 |
| 171 |
| 172 // Returns receiver of generator activation. |
| 173 RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) { |
| 174 HandleScope scope(isolate); |
| 175 DCHECK(args.length() == 1); |
| 176 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
| 177 |
| 178 return generator->receiver(); |
| 179 } |
| 180 |
| 181 |
| 182 // Returns generator continuation as a PC offset, or the magic -1 or 0 values. |
| 183 RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) { |
| 184 HandleScope scope(isolate); |
| 185 DCHECK(args.length() == 1); |
| 186 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
| 187 |
| 188 return Smi::FromInt(generator->continuation()); |
| 189 } |
| 190 |
| 191 |
| 192 RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) { |
| 193 HandleScope scope(isolate); |
| 194 DCHECK(args.length() == 1); |
| 195 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); |
| 196 |
| 197 if (generator->is_suspended()) { |
| 198 Handle<Code> code(generator->function()->code(), isolate); |
| 199 int offset = generator->continuation(); |
| 200 |
| 201 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); |
| 202 Address pc = code->address() + offset; |
| 203 |
| 204 return Smi::FromInt(code->SourcePosition(pc)); |
| 205 } |
| 206 |
| 207 return isolate->heap()->undefined_value(); |
| 208 } |
| 209 |
| 210 |
| 211 RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) { |
| 212 SealHandleScope shs(isolate); |
| 213 DCHECK(args.length() == 1); |
| 214 CONVERT_ARG_CHECKED(JSFunction, f, 0); |
| 215 return isolate->heap()->ToBoolean(f->shared()->is_generator()); |
| 216 } |
| 217 |
| 218 |
| 219 RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) { |
| 220 UNREACHABLE(); // Optimization disabled in SetUpGenerators(). |
| 221 return NULL; |
| 222 } |
| 223 |
| 224 |
| 225 RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) { |
| 226 UNREACHABLE(); // Optimization disabled in SetUpGenerators(). |
| 227 return NULL; |
| 228 } |
| 229 } |
| 230 } // namespace v8::internal |
OLD | NEW |