diff options
Diffstat (limited to 'deps/v8/src/x64/full-codegen-x64.cc')
-rw-r--r-- | deps/v8/src/x64/full-codegen-x64.cc | 200 |
1 files changed, 168 insertions, 32 deletions
diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 8ca173b30f..a20d468bae 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -1907,6 +1907,157 @@ 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); + __ movq(context_register(), + Operand(rbp, StandardFrameConstants::kContextOffset)); + + Label resume; + __ CompareRoot(result_register(), Heap::kTheHoleValueRootIndex); + __ j(not_equal, &resume); + __ 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()); + __ Move(FieldOperand(result_register(), + JSGeneratorObject::kContinuationOffset), + Smi::FromInt(JSGeneratorObject::kGeneratorClosed)); + __ 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 rax, and is ultimately read by the resumed generator, as + // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. rbx + // will hold the generator object until the activation has been resumed. + VisitForStackValue(generator); + VisitForAccumulatorValue(value); + __ pop(rbx); + + // Check generator state. + Label wrong_state, done; + STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); + STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); + __ SmiCompare(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset), + Smi::FromInt(0)); + __ j(less_equal, &wrong_state); + + // Load suspended function and context. + __ movq(rsi, FieldOperand(rbx, JSGeneratorObject::kContextOffset)); + __ movq(rdi, FieldOperand(rbx, JSGeneratorObject::kFunctionOffset)); + + // Push receiver. + __ push(FieldOperand(rbx, JSGeneratorObject::kReceiverOffset)); + + // Push holes for arguments to generator function. + __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); + __ movsxlq(rdx, + FieldOperand(rdx, + SharedFunctionInfo::kFormalParameterCountOffset)); + __ LoadRoot(rcx, Heap::kTheHoleValueRootIndex); + Label push_argument_holes, push_frame; + __ bind(&push_argument_holes); + __ subq(rdx, Immediate(1)); + __ j(carry, &push_frame); + __ push(rcx); + __ 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(rbp); // Caller's frame pointer. + __ movq(rbp, rsp); + __ push(rsi); // Callee's context. + __ push(rdi); // Callee's JS Function. + + // Load the operand stack size. + __ movq(rdx, FieldOperand(rbx, JSGeneratorObject::kOperandStackOffset)); + __ movq(rdx, FieldOperand(rdx, FixedArray::kLengthOffset)); + __ SmiToInteger32(rdx, rdx); + + // 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; + __ cmpq(rdx, Immediate(0)); + __ j(not_zero, &slow_resume); + __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); + __ SmiToInteger64(rcx, + FieldOperand(rbx, JSGeneratorObject::kContinuationOffset)); + __ addq(rdx, rcx); + __ Move(FieldOperand(rbx, JSGeneratorObject::kContinuationOffset), + Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)); + __ jmp(rdx); + __ 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); + __ subq(rdx, Immediate(1)); + __ j(carry, &call_resume); + __ push(rcx); + __ jmp(&push_operand_holes); + __ bind(&call_resume); + __ push(rbx); + __ push(result_register()); + __ Push(Smi::FromInt(resume_mode)); + __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3); + // Not reached: the runtime call returns elsewhere. + __ Abort("Generator failed to resume."); + + // Throw error if we attempt to operate on a running generator. + __ bind(&wrong_state); + __ push(rbx); + __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); + + __ bind(&done); + context()->Plug(result_register()); +} + + void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); @@ -2947,16 +3098,10 @@ void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) { // Return a random uint32 number in rax. // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs. __ PrepareCallCFunction(1); -#ifdef _WIN64 - __ movq(rcx, - ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX)); - __ movq(rcx, FieldOperand(rcx, GlobalObject::kNativeContextOffset)); - -#else - __ movq(rdi, + __ movq(arg_reg_1, ContextOperand(context_register(), Context::GLOBAL_OBJECT_INDEX)); - __ movq(rdi, FieldOperand(rdi, GlobalObject::kNativeContextOffset)); -#endif + __ movq(arg_reg_1, + FieldOperand(arg_reg_1, GlobalObject::kNativeContextOffset)); __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); // Convert 32 random bits in rax to 0.(32 random bits) in a double @@ -3054,13 +3199,8 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) { } __ bind(&runtime); __ PrepareCallCFunction(2); -#ifdef _WIN64 - __ movq(rcx, object); - __ movq(rdx, index, RelocInfo::NONE64); -#else - __ movq(rdi, object); - __ movq(rsi, index, RelocInfo::NONE64); -#endif + __ movq(arg_reg_1, object); + __ movq(arg_reg_2, index, RelocInfo::NONE64); __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ jmp(&done); @@ -4381,24 +4521,20 @@ 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; - __ CompareRoot(rax, nil_value); - if (expr->op() == Token::EQ_STRICT) { + EqualityKind kind = expr->op() == Token::EQ_STRICT + ? kStrictEquality : kNonStrictEquality; + if (kind == kStrictEquality) { + Heap::RootListIndex nil_value = nil == kNullValue ? + Heap::kNullValueRootIndex : + Heap::kUndefinedValueRootIndex; + __ CompareRoot(rax, nil_value); Split(equal, if_true, if_false, fall_through); } else { - Heap::RootListIndex other_nil_value = nil == kNullValue ? - Heap::kUndefinedValueRootIndex : - Heap::kNullValueRootIndex; - __ j(equal, if_true); - __ CompareRoot(rax, other_nil_value); - __ j(equal, if_true); - __ JumpIfSmi(rax, if_false); - // It can be an undetectable object. - __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); - __ testb(FieldOperand(rdx, Map::kBitFieldOffset), - Immediate(1 << Map::kIsUndetectable)); + Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), + kNonStrictEquality, + nil); + CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId()); + __ testq(rax, rax); Split(not_zero, if_true, if_false, fall_through); } context()->Plug(if_true, if_false); |