Home | History | Annotate | Download | only in runtime
      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/runtime/runtime-utils.h"
      6 
      7 #include "src/arguments.h"
      8 #include "src/factory.h"
      9 #include "src/frames-inl.h"
     10 #include "src/objects-inl.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 
     36   return *generator;
     37 }
     38 
     39 
     40 RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
     41   HandleScope handle_scope(isolate);
     42   DCHECK(args.length() == 1 || args.length() == 2);
     43   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
     44 
     45   JavaScriptFrameIterator stack_iterator(isolate);
     46   JavaScriptFrame* frame = stack_iterator.frame();
     47   RUNTIME_ASSERT(frame->function()->shared()->is_generator());
     48   DCHECK_EQ(frame->function(), generator_object->function());
     49 
     50   // The caller should have saved the context and continuation already.
     51   DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
     52   DCHECK_LT(0, generator_object->continuation());
     53 
     54   // We expect there to be at least two values on the operand stack: the return
     55   // value of the yield expression, and the arguments to this runtime call.
     56   // Neither of those should be saved.
     57   int operands_count = frame->ComputeOperandsCount();
     58   DCHECK_GE(operands_count, 1 + args.length());
     59   operands_count -= 1 + args.length();
     60 
     61   // Second argument indicates that we need to patch the handler table because
     62   // a delegating yield introduced a try-catch statement at expression level,
     63   // hence the operand count was off when we statically computed it.
     64   // TODO(mstarzinger): This special case disappears with do-expressions.
     65   if (args.length() == 2) {
     66     CONVERT_SMI_ARG_CHECKED(handler_index, 1);
     67     Handle<Code> code(frame->unchecked_code());
     68     Handle<HandlerTable> table(HandlerTable::cast(code->handler_table()));
     69     int handler_depth = operands_count - TryBlockConstant::kElementCount;
     70     table->SetRangeDepth(handler_index, handler_depth);
     71   }
     72 
     73   if (operands_count == 0) {
     74     // Although it's semantically harmless to call this function with an
     75     // operands_count of zero, it is also unnecessary.
     76     DCHECK_EQ(generator_object->operand_stack(),
     77               isolate->heap()->empty_fixed_array());
     78   } else {
     79     Handle<FixedArray> operand_stack =
     80         isolate->factory()->NewFixedArray(operands_count);
     81     frame->SaveOperandStack(*operand_stack);
     82     generator_object->set_operand_stack(*operand_stack);
     83   }
     84 
     85   return isolate->heap()->undefined_value();
     86 }
     87 
     88 
     89 // Note that this function is the slow path for resuming generators.  It is only
     90 // called if the suspended activation had operands on the stack, stack handlers
     91 // needing rewinding, or if the resume should throw an exception.  The fast path
     92 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
     93 // inlined into GeneratorNext and GeneratorThrow.  EmitGeneratorResumeResume is
     94 // called in any case, as it needs to reconstruct the stack frame and make space
     95 // for arguments and operands.
     96 RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
     97   SealHandleScope shs(isolate);
     98   DCHECK(args.length() == 3);
     99   CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
    100   CONVERT_ARG_CHECKED(Object, value, 1);
    101   CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
    102   JavaScriptFrameIterator stack_iterator(isolate);
    103   JavaScriptFrame* frame = stack_iterator.frame();
    104 
    105   DCHECK_EQ(frame->function(), generator_object->function());
    106   DCHECK(frame->function()->is_compiled());
    107 
    108   STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
    109   STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
    110 
    111   Address pc = generator_object->function()->code()->instruction_start();
    112   int offset = generator_object->continuation();
    113   DCHECK(offset > 0);
    114   frame->set_pc(pc + offset);
    115   if (FLAG_enable_embedded_constant_pool) {
    116     frame->set_constant_pool(
    117         generator_object->function()->code()->constant_pool());
    118   }
    119   generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
    120 
    121   FixedArray* operand_stack = generator_object->operand_stack();
    122   int operands_count = operand_stack->length();
    123   if (operands_count != 0) {
    124     frame->RestoreOperandStack(operand_stack);
    125     generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
    126   }
    127 
    128   JSGeneratorObject::ResumeMode resume_mode =
    129       static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
    130   switch (resume_mode) {
    131     case JSGeneratorObject::NEXT:
    132       return value;
    133     case JSGeneratorObject::THROW:
    134       return isolate->Throw(value);
    135   }
    136 
    137   UNREACHABLE();
    138   return isolate->ThrowIllegalOperation();
    139 }
    140 
    141 
    142 RUNTIME_FUNCTION(Runtime_GeneratorClose) {
    143   HandleScope scope(isolate);
    144   DCHECK(args.length() == 1);
    145   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
    146 
    147   generator->set_continuation(JSGeneratorObject::kGeneratorClosed);
    148 
    149   return isolate->heap()->undefined_value();
    150 }
    151 
    152 
    153 // Returns function of generator activation.
    154 RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
    155   HandleScope scope(isolate);
    156   DCHECK(args.length() == 1);
    157   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
    158 
    159   return generator->function();
    160 }
    161 
    162 
    163 // Returns context of generator activation.
    164 RUNTIME_FUNCTION(Runtime_GeneratorGetContext) {
    165   HandleScope scope(isolate);
    166   DCHECK(args.length() == 1);
    167   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
    168 
    169   return generator->context();
    170 }
    171 
    172 
    173 // Returns receiver of generator activation.
    174 RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
    175   HandleScope scope(isolate);
    176   DCHECK(args.length() == 1);
    177   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
    178 
    179   return generator->receiver();
    180 }
    181 
    182 
    183 // Returns generator continuation as a PC offset, or the magic -1 or 0 values.
    184 RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
    185   HandleScope scope(isolate);
    186   DCHECK(args.length() == 1);
    187   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
    188 
    189   return Smi::FromInt(generator->continuation());
    190 }
    191 
    192 
    193 RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
    194   HandleScope scope(isolate);
    195   DCHECK(args.length() == 1);
    196   CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
    197 
    198   if (generator->is_suspended()) {
    199     Handle<Code> code(generator->function()->code(), isolate);
    200     int offset = generator->continuation();
    201 
    202     RUNTIME_ASSERT(0 <= offset && offset < code->Size());
    203     Address pc = code->address() + offset;
    204 
    205     return Smi::FromInt(code->SourcePosition(pc));
    206   }
    207 
    208   return isolate->heap()->undefined_value();
    209 }
    210 
    211 
    212 RUNTIME_FUNCTION(Runtime_GeneratorNext) {
    213   UNREACHABLE();  // Optimization disabled in SetUpGenerators().
    214   return NULL;
    215 }
    216 
    217 
    218 RUNTIME_FUNCTION(Runtime_GeneratorThrow) {
    219   UNREACHABLE();  // Optimization disabled in SetUpGenerators().
    220   return NULL;
    221 }
    222 }  // namespace internal
    223 }  // namespace v8
    224