deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / runtime / runtime-generator.cc
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-utils.h"
10
11 namespace v8 {
12 namespace internal {
13
14 RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
15   HandleScope scope(isolate);
16   DCHECK(args.length() == 0);
17
18   JavaScriptFrameIterator it(isolate);
19   JavaScriptFrame* frame = it.frame();
20   Handle<JSFunction> function(frame->function());
21   RUNTIME_ASSERT(function->shared()->is_generator());
22
23   Handle<JSGeneratorObject> generator;
24   if (frame->IsConstructor()) {
25     generator = handle(JSGeneratorObject::cast(frame->receiver()));
26   } else {
27     generator = isolate->factory()->NewJSGeneratorObject(function);
28   }
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());
34
35   return *generator;
36 }
37
38
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);
43
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());
48
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());
52
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();
59
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);
70   }
71
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());
77   } else {
78     Handle<FixedArray> operand_stack =
79         isolate->factory()->NewFixedArray(operands_count);
80     frame->SaveOperandStack(*operand_stack);
81     generator_object->set_operand_stack(*operand_stack);
82   }
83
84   return isolate->heap()->undefined_value();
85 }
86
87
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();
103
104   DCHECK_EQ(frame->function(), generator_object->function());
105   DCHECK(frame->function()->is_compiled());
106
107   STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
108   STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
109
110   Address pc = generator_object->function()->code()->instruction_start();
111   int offset = generator_object->continuation();
112   DCHECK(offset > 0);
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());
117   }
118   generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
119
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());
125   }
126
127   JSGeneratorObject::ResumeMode resume_mode =
128       static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
129   switch (resume_mode) {
130     case JSGeneratorObject::NEXT:
131       return value;
132     case JSGeneratorObject::THROW:
133       return isolate->Throw(value);
134   }
135
136   UNREACHABLE();
137   return isolate->ThrowIllegalOperation();
138 }
139
140
141 RUNTIME_FUNCTION(Runtime_GeneratorClose) {
142   HandleScope scope(isolate);
143   DCHECK(args.length() == 1);
144   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
145
146   generator->set_continuation(JSGeneratorObject::kGeneratorClosed);
147
148   return isolate->heap()->undefined_value();
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(Runtime_GeneratorNext) {
220   UNREACHABLE();  // Optimization disabled in SetUpGenerators().
221   return NULL;
222 }
223
224
225 RUNTIME_FUNCTION(Runtime_GeneratorThrow) {
226   UNREACHABLE();  // Optimization disabled in SetUpGenerators().
227   return NULL;
228 }
229 }
230 }  // namespace v8::internal