summaryrefslogtreecommitdiff
path: root/deps/v8/src/x64/full-codegen-x64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/x64/full-codegen-x64.cc')
-rw-r--r--deps/v8/src/x64/full-codegen-x64.cc200
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);