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.
7 #include "src/arguments.h"
8 #include "src/frames-inl.h"
9 #include "src/runtime/runtime-utils.h"
14 RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
15 HandleScope scope(isolate);
16 DCHECK(args.length() == 0);
18 JavaScriptFrameIterator it(isolate);
19 JavaScriptFrame* frame = it.frame();
20 Handle<JSFunction> function(frame->function());
21 RUNTIME_ASSERT(function->shared()->is_generator());
23 Handle<JSGeneratorObject> generator;
24 if (frame->IsConstructor()) {
25 generator = handle(JSGeneratorObject::cast(frame->receiver()));
27 generator = isolate->factory()->NewJSGeneratorObject(function);
29 generator->set_function(*function);
30 generator->set_context(Context::cast(frame->context()));
31 generator->set_receiver(frame->receiver());
32 generator->set_continuation(0);
33 generator->set_operand_stack(isolate->heap()->empty_fixed_array());
39 RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
40 HandleScope handle_scope(isolate);
41 DCHECK(args.length() == 1 || args.length() == 2);
42 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
44 JavaScriptFrameIterator stack_iterator(isolate);
45 JavaScriptFrame* frame = stack_iterator.frame();
46 RUNTIME_ASSERT(frame->function()->shared()->is_generator());
47 DCHECK_EQ(frame->function(), generator_object->function());
49 // The caller should have saved the context and continuation already.
50 DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
51 DCHECK_LT(0, generator_object->continuation());
53 // We expect there to be at least two values on the operand stack: the return
54 // value of the yield expression, and the arguments to this runtime call.
55 // Neither of those should be saved.
56 int operands_count = frame->ComputeOperandsCount();
57 DCHECK_GE(operands_count, 1 + args.length());
58 operands_count -= 1 + args.length();
60 // Second argument indicates that we need to patch the handler table because
61 // a delegating yield introduced a try-catch statement at expression level,
62 // hence the operand count was off when we statically computed it.
63 // TODO(mstarzinger): This special case disappears with do-expressions.
64 if (args.length() == 2) {
65 CONVERT_SMI_ARG_CHECKED(handler_index, 1);
66 Handle<Code> code(frame->unchecked_code());
67 Handle<HandlerTable> table(HandlerTable::cast(code->handler_table()));
68 int handler_depth = operands_count - TryBlockConstant::kElementCount;
69 table->SetRangeDepth(handler_index, handler_depth);
72 if (operands_count == 0) {
73 // Although it's semantically harmless to call this function with an
74 // operands_count of zero, it is also unnecessary.
75 DCHECK_EQ(generator_object->operand_stack(),
76 isolate->heap()->empty_fixed_array());
78 Handle<FixedArray> operand_stack =
79 isolate->factory()->NewFixedArray(operands_count);
80 frame->SaveOperandStack(*operand_stack);
81 generator_object->set_operand_stack(*operand_stack);
84 return isolate->heap()->undefined_value();
88 // Note that this function is the slow path for resuming generators. It is only
89 // called if the suspended activation had operands on the stack, stack handlers
90 // needing rewinding, or if the resume should throw an exception. The fast path
91 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
92 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
93 // called in any case, as it needs to reconstruct the stack frame and make space
94 // for arguments and operands.
95 RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
96 SealHandleScope shs(isolate);
97 DCHECK(args.length() == 3);
98 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
99 CONVERT_ARG_CHECKED(Object, value, 1);
100 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
101 JavaScriptFrameIterator stack_iterator(isolate);
102 JavaScriptFrame* frame = stack_iterator.frame();
104 DCHECK_EQ(frame->function(), generator_object->function());
105 DCHECK(frame->function()->is_compiled());
107 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
108 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
110 Address pc = generator_object->function()->code()->instruction_start();
111 int offset = generator_object->continuation();
113 frame->set_pc(pc + offset);
114 if (FLAG_enable_ool_constant_pool) {
115 frame->set_constant_pool(
116 generator_object->function()->code()->constant_pool());
118 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
120 FixedArray* operand_stack = generator_object->operand_stack();
121 int operands_count = operand_stack->length();
122 if (operands_count != 0) {
123 frame->RestoreOperandStack(operand_stack);
124 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
127 JSGeneratorObject::ResumeMode resume_mode =
128 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
129 switch (resume_mode) {
130 case JSGeneratorObject::NEXT:
132 case JSGeneratorObject::THROW:
133 return isolate->Throw(value);
137 return isolate->ThrowIllegalOperation();
141 RUNTIME_FUNCTION(Runtime_GeneratorClose) {
142 HandleScope scope(isolate);
143 DCHECK(args.length() == 1);
144 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
146 generator->set_continuation(JSGeneratorObject::kGeneratorClosed);
148 return isolate->heap()->undefined_value();
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);
158 return generator->function();
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);
168 return generator->context();
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);
178 return generator->receiver();
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);
188 return Smi::FromInt(generator->continuation());
192 RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
193 HandleScope scope(isolate);
194 DCHECK(args.length() == 1);
195 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
197 if (generator->is_suspended()) {
198 Handle<Code> code(generator->function()->code(), isolate);
199 int offset = generator->continuation();
201 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
202 Address pc = code->address() + offset;
204 return Smi::FromInt(code->SourcePosition(pc));
207 return isolate->heap()->undefined_value();
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());
219 RUNTIME_FUNCTION(Runtime_GeneratorNext) {
220 UNREACHABLE(); // Optimization disabled in SetUpGenerators().
225 RUNTIME_FUNCTION(Runtime_GeneratorThrow) {
226 UNREACHABLE(); // Optimization disabled in SetUpGenerators().
230 } // namespace v8::internal