diff options
Diffstat (limited to 'deps/v8/src/mips/full-codegen-mips.cc')
-rw-r--r-- | deps/v8/src/mips/full-codegen-mips.cc | 179 |
1 files changed, 162 insertions, 17 deletions
diff --git a/deps/v8/src/mips/full-codegen-mips.cc b/deps/v8/src/mips/full-codegen-mips.cc index bc0d85543..a6fd39aa1 100644 --- a/deps/v8/src/mips/full-codegen-mips.cc +++ b/deps/v8/src/mips/full-codegen-mips.cc @@ -1926,6 +1926,156 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { } +void FullCodeGenerator::VisitYield(Yield* expr) { + Comment cmnt(masm_, "[ Yield"); + // Evaluate yielded value first; the initial iterator definition depends on + // this. It stays on the stack while we update the iterator. + VisitForStackValue(expr->expression()); + + switch (expr->yield_kind()) { + case Yield::INITIAL: + case Yield::SUSPEND: { + VisitForStackValue(expr->generator_object()); + __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); + __ lw(context_register(), + MemOperand(fp, StandardFrameConstants::kContextOffset)); + + Label resume; + __ LoadRoot(at, Heap::kTheHoleValueRootIndex); + __ Branch(&resume, ne, result_register(), Operand(at)); + __ pop(result_register()); + if (expr->yield_kind() == Yield::SUSPEND) { + // TODO(wingo): Box into { value: VALUE, done: false }. + } + EmitReturnSequence(); + + __ bind(&resume); + context()->Plug(result_register()); + break; + } + + case Yield::FINAL: { + VisitForAccumulatorValue(expr->generator_object()); + __ li(a1, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorClosed))); + __ sw(a1, FieldMemOperand(result_register(), + JSGeneratorObject::kContinuationOffset)); + __ pop(result_register()); + // TODO(wingo): Box into { value: VALUE, done: true }. + + // Exit all nested statements. + NestedStatement* current = nesting_stack_; + int stack_depth = 0; + int context_length = 0; + while (current != NULL) { + current = current->Exit(&stack_depth, &context_length); + } + __ Drop(stack_depth); + EmitReturnSequence(); + break; + } + + case Yield::DELEGATING: + UNIMPLEMENTED(); + } +} + + +void FullCodeGenerator::EmitGeneratorResume(Expression *generator, + Expression *value, + JSGeneratorObject::ResumeMode resume_mode) { + // The value stays in a0, and is ultimately read by the resumed generator, as + // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. a1 + // will hold the generator object until the activation has been resumed. + VisitForStackValue(generator); + VisitForAccumulatorValue(value); + __ pop(a1); + + // Check generator state. + Label wrong_state, done; + __ lw(a3, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset)); + STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); + STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); + __ Branch(&wrong_state, le, a3, Operand(zero_reg)); + + // Load suspended function and context. + __ lw(cp, FieldMemOperand(a1, JSGeneratorObject::kContextOffset)); + __ lw(t0, FieldMemOperand(a1, JSGeneratorObject::kFunctionOffset)); + + // Load receiver and store as the first argument. + __ lw(a2, FieldMemOperand(a1, JSGeneratorObject::kReceiverOffset)); + __ push(a2); + + // Push holes for the rest of the arguments to the generator function. + __ lw(a3, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset)); + __ lw(a3, + FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset)); + __ LoadRoot(a2, Heap::kTheHoleValueRootIndex); + Label push_argument_holes, push_frame; + __ bind(&push_argument_holes); + __ Subu(a3, a3, Operand(1)); + __ Branch(&push_frame, lt, a3, Operand(zero_reg)); + __ push(a2); + __ jmp(&push_argument_holes); + + // Enter a new JavaScript frame, and initialize its slots as they were when + // the generator was suspended. + Label resume_frame; + __ bind(&push_frame); + __ Call(&resume_frame); + __ jmp(&done); + __ bind(&resume_frame); + __ push(ra); // Return address. + __ push(fp); // Caller's frame pointer. + __ mov(fp, sp); + __ push(cp); // Callee's context. + __ push(t0); // Callee's JS Function. + + // Load the operand stack size. + __ lw(a3, FieldMemOperand(a1, JSGeneratorObject::kOperandStackOffset)); + __ lw(a3, FieldMemOperand(a3, FixedArray::kLengthOffset)); + __ SmiUntag(a3); + + // If we are sending a value and there is no operand stack, we can jump back + // in directly. + if (resume_mode == JSGeneratorObject::SEND) { + Label slow_resume; + __ Branch(&slow_resume, ne, a3, Operand(zero_reg)); + __ lw(a3, FieldMemOperand(t0, JSFunction::kCodeEntryOffset)); + __ lw(a2, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset)); + __ SmiUntag(a2); + __ Addu(a3, a3, Operand(a2)); + __ li(a2, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))); + __ sw(a2, FieldMemOperand(a1, JSGeneratorObject::kContinuationOffset)); + __ Jump(a3); + __ bind(&slow_resume); + } + + // Otherwise, we push holes for the operand stack and call the runtime to fix + // up the stack and the handlers. + Label push_operand_holes, call_resume; + __ bind(&push_operand_holes); + __ Subu(a3, a3, Operand(1)); + __ Branch(&call_resume, lt, a3, Operand(zero_reg)); + __ push(a2); + __ b(&push_operand_holes); + __ bind(&call_resume); + __ push(a1); + __ push(result_register()); + __ Push(Smi::FromInt(resume_mode)); + __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); + // Not reached: the runtime call returns elsewhere. + __ stop("not-reached"); + + // Throw error if we attempt to operate on a running generator. + __ bind(&wrong_state); + __ push(a1); + __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); + + __ bind(&done); + context()->Plug(result_register()); +} + + void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); @@ -4398,26 +4548,21 @@ void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, VisitForAccumulatorValue(sub_expr); PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); - Heap::RootListIndex nil_value = nil == kNullValue ? - Heap::kNullValueRootIndex : - Heap::kUndefinedValueRootIndex; + EqualityKind kind = expr->op() == Token::EQ_STRICT + ? kStrictEquality : kNonStrictEquality; __ mov(a0, result_register()); - __ LoadRoot(a1, nil_value); - if (expr->op() == Token::EQ_STRICT) { + if (kind == kStrictEquality) { + Heap::RootListIndex nil_value = nil == kNullValue ? + Heap::kNullValueRootIndex : + Heap::kUndefinedValueRootIndex; + __ LoadRoot(a1, nil_value); Split(eq, a0, Operand(a1), if_true, if_false, fall_through); } else { - Heap::RootListIndex other_nil_value = nil == kNullValue ? - Heap::kUndefinedValueRootIndex : - Heap::kNullValueRootIndex; - __ Branch(if_true, eq, a0, Operand(a1)); - __ LoadRoot(a1, other_nil_value); - __ Branch(if_true, eq, a0, Operand(a1)); - __ JumpIfSmi(a0, if_false); - // It can be an undetectable object. - __ lw(a1, FieldMemOperand(a0, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset)); - __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); - Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); + Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), + kNonStrictEquality, + nil); + CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); + Split(ne, v0, Operand(zero_reg), if_true, if_false, fall_through); } context()->Plug(if_true, if_false); } |