Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: src/x64/codegen-x64.cc

Issue 1148007: Merge bleeding_edge from version 2.1.3 up to revision 4205... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 2406 matching lines...) Expand 10 before | Expand all | Expand 10 after
2417 2417
2418 // Load the literals array of the function. 2418 // Load the literals array of the function.
2419 __ movq(literals.reg(), 2419 __ movq(literals.reg(),
2420 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); 2420 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset));
2421 // Literal array. 2421 // Literal array.
2422 frame_->Push(&literals); 2422 frame_->Push(&literals);
2423 // Literal index. 2423 // Literal index.
2424 frame_->Push(Smi::FromInt(node->literal_index())); 2424 frame_->Push(Smi::FromInt(node->literal_index()));
2425 // Constant properties. 2425 // Constant properties.
2426 frame_->Push(node->constant_properties()); 2426 frame_->Push(node->constant_properties());
2427 // Should the object literal have fast elements?
2428 frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0));
2427 Result clone; 2429 Result clone;
2428 if (node->depth() > 1) { 2430 if (node->depth() > 1) {
2429 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); 2431 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4);
2430 } else { 2432 } else {
2431 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); 2433 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
2432 } 2434 }
2433 frame_->Push(&clone); 2435 frame_->Push(&clone);
2434 2436
2435 for (int i = 0; i < node->properties()->length(); i++) { 2437 for (int i = 0; i < node->properties()->length(); i++) {
2436 ObjectLiteral::Property* property = node->properties()->at(i); 2438 ObjectLiteral::Property* property = node->properties()->at(i);
2437 switch (property->kind()) { 2439 switch (property->kind()) {
2438 case ObjectLiteral::Property::CONSTANT: 2440 case ObjectLiteral::Property::CONSTANT:
2439 break; 2441 break;
2440 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 2442 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2441 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; 2443 if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
(...skipping 1151 matching lines...) Expand 10 before | Expand all | Expand 10 after
3593 Load(right); 3595 Load(right);
3594 Comparison(node, cc, strict, destination()); 3596 Comparison(node, cc, strict, destination());
3595 } 3597 }
3596 3598
3597 3599
3598 void CodeGenerator::VisitThisFunction(ThisFunction* node) { 3600 void CodeGenerator::VisitThisFunction(ThisFunction* node) {
3599 frame_->PushFunction(); 3601 frame_->PushFunction();
3600 } 3602 }
3601 3603
3602 3604
3603 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { 3605 void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
3604 ASSERT(args->length() == 1); 3606 ASSERT(args->length() == 1);
3605 3607
3606 // ArgumentsAccessStub expects the key in rdx and the formal 3608 // ArgumentsAccessStub expects the key in rdx and the formal
3607 // parameter count in rax. 3609 // parameter count in rax.
3608 Load(args->at(0)); 3610 Load(args->at(0));
3609 Result key = frame_->Pop(); 3611 Result key = frame_->Pop();
3610 // Explicitly create a constant result. 3612 // Explicitly create a constant result.
3611 Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); 3613 Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters())));
3612 // Call the shared stub to get to arguments[key]. 3614 // Call the shared stub to get to arguments[key].
3613 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); 3615 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after
4044 frame_->Push(&result); 4046 frame_->Push(&result);
4045 } 4047 }
4046 4048
4047 4049
4048 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { 4050 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
4049 ASSERT_EQ(args->length(), 1); 4051 ASSERT_EQ(args->length(), 1);
4050 4052
4051 // Load the argument on the stack and jump to the runtime. 4053 // Load the argument on the stack and jump to the runtime.
4052 Load(args->at(0)); 4054 Load(args->at(0));
4053 4055
4054 Result answer = frame_->CallRuntime(Runtime::kNumberToString, 1); 4056 NumberToStringStub stub;
4055 frame_->Push(&answer); 4057 Result result = frame_->CallStub(&stub, 1);
4058 frame_->Push(&result);
4056 } 4059 }
4057 4060
4058 4061
4059 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { 4062 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
4060 ASSERT_EQ(args->length(), 1); 4063 ASSERT_EQ(args->length(), 1);
4061 // Load the argument on the stack and jump to the runtime. 4064 // Load the argument on the stack and jump to the runtime.
4062 Load(args->at(0)); 4065 Load(args->at(0));
4063 Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1); 4066 Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1);
4064 frame_->Push(&answer); 4067 frame_->Push(&answer);
4065 } 4068 }
(...skipping 3106 matching lines...) Expand 10 before | Expand all | Expand 10 after
7172 Label next_capture, done; 7175 Label next_capture, done;
7173 __ movq(rax, Operand(rsp, kPreviousIndexOffset)); 7176 __ movq(rax, Operand(rsp, kPreviousIndexOffset));
7174 // Capture register counter starts from number of capture registers and 7177 // Capture register counter starts from number of capture registers and
7175 // counts down until wraping after zero. 7178 // counts down until wraping after zero.
7176 __ bind(&next_capture); 7179 __ bind(&next_capture);
7177 __ subq(rdx, Immediate(1)); 7180 __ subq(rdx, Immediate(1));
7178 __ j(negative, &done); 7181 __ j(negative, &done);
7179 // Read the value from the static offsets vector buffer and make it a smi. 7182 // Read the value from the static offsets vector buffer and make it a smi.
7180 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0)); 7183 __ movl(rdi, Operand(rcx, rdx, times_int_size, 0));
7181 __ Integer32ToSmi(rdi, rdi, &runtime); 7184 __ Integer32ToSmi(rdi, rdi, &runtime);
7182 // Add previous index (from its stack slot) if value is not negative.
7183 Label capture_negative;
7184 // Negative flag set by smi convertion above.
7185 __ j(negative, &capture_negative);
7186 __ SmiAdd(rdi, rdi, rax, &runtime); // Add previous index.
7187 __ bind(&capture_negative);
7188 // Store the smi value in the last match info. 7185 // Store the smi value in the last match info.
7189 __ movq(FieldOperand(rbx, 7186 __ movq(FieldOperand(rbx,
7190 rdx, 7187 rdx,
7191 times_pointer_size, 7188 times_pointer_size,
7192 RegExpImpl::kFirstCaptureOffset), 7189 RegExpImpl::kFirstCaptureOffset),
7193 rdi); 7190 rdi);
7194 __ jmp(&next_capture); 7191 __ jmp(&next_capture);
7195 __ bind(&done); 7192 __ bind(&done);
7196 7193
7197 // Return last match info. 7194 // Return last match info.
7198 __ movq(rax, Operand(rsp, kLastMatchInfoOffset)); 7195 __ movq(rax, Operand(rsp, kLastMatchInfoOffset));
7199 __ ret(4 * kPointerSize); 7196 __ ret(4 * kPointerSize);
7200 7197
7201 // Do the runtime call to execute the regexp. 7198 // Do the runtime call to execute the regexp.
7202 __ bind(&runtime); 7199 __ bind(&runtime);
7203 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 7200 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
7204 #endif // V8_NATIVE_REGEXP 7201 #endif // V8_NATIVE_REGEXP
7205 } 7202 }
7206 7203
7207 7204
7205 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm,
7206 Register object,
7207 Register result,
7208 Register scratch1,
7209 Register scratch2,
7210 bool object_is_smi,
7211 Label* not_found) {
7212 // Currently only lookup for smis. Check for smi if object is not known to be
7213 // a smi.
7214 if (!object_is_smi) {
7215 __ JumpIfNotSmi(object, not_found);
7216 }
7217
7218 // Use of registers. Register result is used as a temporary.
7219 Register number_string_cache = result;
7220 Register mask = scratch1;
7221 Register scratch = scratch2;
7222
7223 // Load the number string cache.
7224 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
7225
7226 // Make the hash mask from the length of the number string cache. It
7227 // contains two elements (number and string) for each cache entry.
7228 __ movl(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
7229 __ shrl(mask, Immediate(1)); // Divide length by two (length is not a smi).
7230 __ subl(mask, Immediate(1)); // Make mask.
7231
7232 // Calculate the entry in the number string cache. The hash value in the
7233 // number string cache for smis is just the smi value.
7234 __ movq(scratch, object);
7235 __ SmiToInteger32(scratch, scratch);
7236 __ andl(scratch, mask);
7237
7238 // Each entry in string cache consists of two pointer sized fields,
7239 // but times_twice_pointer_size (multiplication by 16) scale factor
7240 // is not supported by addrmode on x64 platform.
7241 // So we have to premultiply entry index before lookup
7242 __ shl(scratch, Immediate(kPointerSizeLog2 + 1));
7243 // Check if the entry is the smi we are looking for.
7244 __ cmpq(object,
7245 FieldOperand(number_string_cache,
7246 scratch,
7247 times_1,
7248 FixedArray::kHeaderSize));
7249 __ j(not_equal, not_found);
7250
7251 // Get the result from the cache.
7252 __ movq(result,
7253 FieldOperand(number_string_cache,
7254 scratch,
7255 times_1,
7256 FixedArray::kHeaderSize + kPointerSize));
7257 __ IncrementCounter(&Counters::number_to_string_native, 1);
7258 }
7259
7260
7261 void NumberToStringStub::Generate(MacroAssembler* masm) {
7262 Label runtime;
7263
7264 __ movq(rbx, Operand(rsp, kPointerSize));
7265
7266 // Generate code to lookup number in the number string cache.
7267 GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime);
7268 __ ret(1 * kPointerSize);
7269
7270 __ bind(&runtime);
7271 // Handle number to string in the runtime system if not found in the cache.
7272 __ TailCallRuntime(Runtime::kNumberToString, 1, 1);
7273 }
7274
7275
7208 void CompareStub::Generate(MacroAssembler* masm) { 7276 void CompareStub::Generate(MacroAssembler* masm) {
7209 Label call_builtin, done; 7277 Label call_builtin, done;
7210 7278
7211 // NOTICE! This code is only reached after a smi-fast-case check, so 7279 // NOTICE! This code is only reached after a smi-fast-case check, so
7212 // it is certain that at least one operand isn't a smi. 7280 // it is certain that at least one operand isn't a smi.
7213 7281
7214 if (cc_ == equal) { // Both strict and non-strict. 7282 if (cc_ == equal) { // Both strict and non-strict.
7215 Label slow; // Fallthrough label. 7283 Label slow; // Fallthrough label.
7216 // Equality is almost reflexive (everything but NaN), so start by testing 7284 // Equality is almost reflexive (everything but NaN), so start by testing
7217 // for "identity and not NaN". 7285 // for "identity and not NaN".
(...skipping 1109 matching lines...) Expand 10 before | Expand all | Expand 10 after
8327 const char* op_name = Token::Name(op_); 8395 const char* op_name = Token::Name(op_);
8328 const char* overwrite_name; 8396 const char* overwrite_name;
8329 switch (mode_) { 8397 switch (mode_) {
8330 case NO_OVERWRITE: overwrite_name = "Alloc"; break; 8398 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
8331 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 8399 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
8332 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 8400 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
8333 default: overwrite_name = "UnknownOverwrite"; break; 8401 default: overwrite_name = "UnknownOverwrite"; break;
8334 } 8402 }
8335 8403
8336 OS::SNPrintF(Vector<char>(name_, len), 8404 OS::SNPrintF(Vector<char>(name_, len),
8337 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", 8405 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s_%s",
8338 op_name, 8406 op_name,
8339 overwrite_name, 8407 overwrite_name,
8340 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", 8408 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
8341 args_in_registers_ ? "RegArgs" : "StackArgs", 8409 args_in_registers_ ? "RegArgs" : "StackArgs",
8342 args_reversed_ ? "_R" : "", 8410 args_reversed_ ? "_R" : "",
8343 use_sse3_ ? "SSE3" : "SSE2", 8411 use_sse3_ ? "SSE3" : "SSE2",
8344 operands_type_.ToString()); 8412 static_operands_type_.ToString(),
8413 BinaryOpIC::GetName(runtime_operands_type_));
8345 return name_; 8414 return name_;
8346 } 8415 }
8347 8416
8348 8417
8349 void GenericBinaryOpStub::GenerateCall( 8418 void GenericBinaryOpStub::GenerateCall(
8350 MacroAssembler* masm, 8419 MacroAssembler* masm,
8351 Register left, 8420 Register left,
8352 Register right) { 8421 Register right) {
8353 if (!ArgsInRegistersSupported()) { 8422 if (!ArgsInRegistersSupported()) {
8354 // Pass arguments on the stack. 8423 // Pass arguments on the stack.
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
8484 return frame->CallStub(this, left, right); 8553 return frame->CallStub(this, left, right);
8485 } else { 8554 } else {
8486 frame->Push(left); 8555 frame->Push(left);
8487 frame->Push(right); 8556 frame->Push(right);
8488 return frame->CallStub(this, 2); 8557 return frame->CallStub(this, 2);
8489 } 8558 }
8490 } 8559 }
8491 8560
8492 8561
8493 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { 8562 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
8494 // 1. Move arguments into edx, eax except for DIV and MOD, which need the 8563 // 1. Move arguments into rdx, rax except for DIV and MOD, which need the
8495 // dividend in eax and edx free for the division. Use eax, ebx for those. 8564 // dividend in rax and rdx free for the division. Use rax, rbx for those.
8496 Comment load_comment(masm, "-- Load arguments"); 8565 Comment load_comment(masm, "-- Load arguments");
8497 Register left = rdx; 8566 Register left = rdx;
8498 Register right = rax; 8567 Register right = rax;
8499 if (op_ == Token::DIV || op_ == Token::MOD) { 8568 if (op_ == Token::DIV || op_ == Token::MOD) {
8500 left = rax; 8569 left = rax;
8501 right = rbx; 8570 right = rbx;
8502 if (HasArgsInRegisters()) { 8571 if (HasArgsInRegisters()) {
8503 __ movq(rbx, rax); 8572 __ movq(rbx, rax);
8504 __ movq(rax, rdx); 8573 __ movq(rax, rdx);
8505 } 8574 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
8584 UNREACHABLE(); 8653 UNREACHABLE();
8585 } 8654 }
8586 __ movq(rax, left); 8655 __ movq(rax, left);
8587 break; 8656 break;
8588 8657
8589 default: 8658 default:
8590 UNREACHABLE(); 8659 UNREACHABLE();
8591 break; 8660 break;
8592 } 8661 }
8593 8662
8594 // 4. Emit return of result in eax. 8663 // 4. Emit return of result in rax.
8595 GenerateReturn(masm); 8664 GenerateReturn(masm);
8596 8665
8597 // 5. For some operations emit inline code to perform floating point 8666 // 5. For some operations emit inline code to perform floating point
8598 // operations on known smis (e.g., if the result of the operation 8667 // operations on known smis (e.g., if the result of the operation
8599 // overflowed the smi range). 8668 // overflowed the smi range).
8600 switch (op_) { 8669 switch (op_) {
8601 case Token::ADD: 8670 case Token::ADD:
8602 case Token::SUB: 8671 case Token::SUB:
8603 case Token::MUL: 8672 case Token::MUL:
8604 case Token::DIV: { 8673 case Token::DIV: {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
8645 break; 8714 break;
8646 8715
8647 default: 8716 default:
8648 break; 8717 break;
8649 } 8718 }
8650 } 8719 }
8651 8720
8652 8721
8653 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { 8722 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
8654 Label call_runtime; 8723 Label call_runtime;
8655 if (HasSmiCodeInStub()) { 8724
8725 if (ShouldGenerateSmiCode()) {
8656 GenerateSmiCode(masm, &call_runtime); 8726 GenerateSmiCode(masm, &call_runtime);
8657 } else if (op_ != Token::MOD) { 8727 } else if (op_ != Token::MOD) {
8658 GenerateLoadArguments(masm); 8728 if (!HasArgsInRegisters()) {
8729 GenerateLoadArguments(masm);
8730 }
8659 } 8731 }
8660 // Floating point case. 8732 // Floating point case.
8661 switch (op_) { 8733 if (ShouldGenerateFPCode()) {
8662 case Token::ADD: 8734 switch (op_) {
8663 case Token::SUB: 8735 case Token::ADD:
8664 case Token::MUL: 8736 case Token::SUB:
8665 case Token::DIV: { 8737 case Token::MUL:
8666 // rax: y 8738 case Token::DIV: {
8667 // rdx: x 8739 if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
8668 if (operands_type_.IsNumber()) { 8740 HasSmiCodeInStub()) {
8741 // Execution reaches this point when the first non-smi argument occurs
8742 // (and only if smi code is generated). This is the right moment to
8743 // patch to HEAP_NUMBERS state. The transition is attempted only for
8744 // the four basic operations. The stub stays in the DEFAULT state
8745 // forever for all other operations (also if smi code is skipped).
8746 GenerateTypeTransition(masm);
8747 }
8748
8749 Label not_floats;
8750 // rax: y
8751 // rdx: x
8752 if (static_operands_type_.IsNumber()) {
8669 if (FLAG_debug_code) { 8753 if (FLAG_debug_code) {
8670 // Assert at runtime that inputs are only numbers. 8754 // Assert at runtime that inputs are only numbers.
8671 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); 8755 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number.");
8672 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); 8756 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number.");
8673 } 8757 }
8674 } else { 8758 } else {
8675 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); 8759 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime);
8676 } 8760 }
8677 // Fast-case: Both operands are numbers. 8761 // Fast-case: Both operands are numbers.
8678 // xmm4 and xmm5 are volatile XMM registers. 8762 // xmm4 and xmm5 are volatile XMM registers.
8679 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); 8763 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5);
8680 8764
8681 switch (op_) { 8765 switch (op_) {
8682 case Token::ADD: __ addsd(xmm4, xmm5); break; 8766 case Token::ADD: __ addsd(xmm4, xmm5); break;
8683 case Token::SUB: __ subsd(xmm4, xmm5); break; 8767 case Token::SUB: __ subsd(xmm4, xmm5); break;
8684 case Token::MUL: __ mulsd(xmm4, xmm5); break; 8768 case Token::MUL: __ mulsd(xmm4, xmm5); break;
8685 case Token::DIV: __ divsd(xmm4, xmm5); break; 8769 case Token::DIV: __ divsd(xmm4, xmm5); break;
8686 default: UNREACHABLE(); 8770 default: UNREACHABLE();
8687 } 8771 }
8688 // Allocate a heap number, if needed. 8772 // Allocate a heap number, if needed.
8689 Label skip_allocation; 8773 Label skip_allocation;
8690 OverwriteMode mode = mode_; 8774 OverwriteMode mode = mode_;
8691 if (HasArgsReversed()) { 8775 if (HasArgsReversed()) {
8692 if (mode == OVERWRITE_RIGHT) { 8776 if (mode == OVERWRITE_RIGHT) {
8693 mode = OVERWRITE_LEFT; 8777 mode = OVERWRITE_LEFT;
8694 } else if (mode == OVERWRITE_LEFT) { 8778 } else if (mode == OVERWRITE_LEFT) {
8695 mode = OVERWRITE_RIGHT; 8779 mode = OVERWRITE_RIGHT;
8696 } 8780 }
8697 } 8781 }
8698 switch (mode) { 8782 switch (mode) {
8699 case OVERWRITE_LEFT:
8700 __ JumpIfNotSmi(rdx, &skip_allocation);
8701 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
8702 __ movq(rdx, rbx);
8703 __ bind(&skip_allocation);
8704 __ movq(rax, rdx);
8705 break;
8706 case OVERWRITE_RIGHT:
8707 // If the argument in rax is already an object, we skip the
8708 // allocation of a heap number.
8709 __ JumpIfNotSmi(rax, &skip_allocation);
8710 // Fall through!
8711 case NO_OVERWRITE:
8712 // Allocate a heap number for the result. Keep rax and rdx intact
8713 // for the possible runtime call.
8714 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
8715 __ movq(rax, rbx);
8716 __ bind(&skip_allocation);
8717 break;
8718 default: UNREACHABLE();
8719 }
8720 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4);
8721 GenerateReturn(masm);
8722 }
8723 case Token::MOD: {
8724 // For MOD we go directly to runtime in the non-smi case.
8725 break;
8726 }
8727 case Token::BIT_OR:
8728 case Token::BIT_AND:
8729 case Token::BIT_XOR:
8730 case Token::SAR:
8731 case Token::SHL:
8732 case Token::SHR: {
8733 Label skip_allocation, non_smi_result;
8734 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime);
8735 switch (op_) {
8736 case Token::BIT_OR: __ orl(rax, rcx); break;
8737 case Token::BIT_AND: __ andl(rax, rcx); break;
8738 case Token::BIT_XOR: __ xorl(rax, rcx); break;
8739 case Token::SAR: __ sarl_cl(rax); break;
8740 case Token::SHL: __ shll_cl(rax); break;
8741 case Token::SHR: __ shrl_cl(rax); break;
8742 default: UNREACHABLE();
8743 }
8744 if (op_ == Token::SHR) {
8745 // Check if result is non-negative. This can only happen for a shift
8746 // by zero, which also doesn't update the sign flag.
8747 __ testl(rax, rax);
8748 __ j(negative, &non_smi_result);
8749 }
8750 __ JumpIfNotValidSmiValue(rax, &non_smi_result);
8751 // Tag smi result, if possible, and return.
8752 __ Integer32ToSmi(rax, rax);
8753 GenerateReturn(masm);
8754
8755 // All ops except SHR return a signed int32 that we load in a HeapNumber.
8756 if (op_ != Token::SHR && non_smi_result.is_linked()) {
8757 __ bind(&non_smi_result);
8758 // Allocate a heap number if needed.
8759 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result
8760 switch (mode_) {
8761 case OVERWRITE_LEFT: 8783 case OVERWRITE_LEFT:
8784 __ JumpIfNotSmi(rdx, &skip_allocation);
8785 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
8786 __ movq(rdx, rbx);
8787 __ bind(&skip_allocation);
8788 __ movq(rax, rdx);
8789 break;
8762 case OVERWRITE_RIGHT: 8790 case OVERWRITE_RIGHT:
8763 // If the operand was an object, we skip the 8791 // If the argument in rax is already an object, we skip the
8764 // allocation of a heap number. 8792 // allocation of a heap number.
8765 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
8766 1 * kPointerSize : 2 * kPointerSize));
8767 __ JumpIfNotSmi(rax, &skip_allocation); 8793 __ JumpIfNotSmi(rax, &skip_allocation);
8768 // Fall through! 8794 // Fall through!
8769 case NO_OVERWRITE: 8795 case NO_OVERWRITE:
8770 __ AllocateHeapNumber(rax, rcx, &call_runtime); 8796 // Allocate a heap number for the result. Keep rax and rdx intact
8797 // for the possible runtime call.
8798 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
8799 __ movq(rax, rbx);
8771 __ bind(&skip_allocation); 8800 __ bind(&skip_allocation);
8772 break; 8801 break;
8773 default: UNREACHABLE(); 8802 default: UNREACHABLE();
8774 } 8803 }
8775 // Store the result in the HeapNumber and return. 8804 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4);
8776 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
8777 __ fild_s(Operand(rsp, 1 * kPointerSize));
8778 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
8779 GenerateReturn(masm); 8805 GenerateReturn(masm);
8780 } 8806 __ bind(&not_floats);
8781 8807 if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
8782 // SHR should return uint32 - go to runtime for non-smi/negative result. 8808 !HasSmiCodeInStub()) {
8783 if (op_ == Token::SHR) { 8809 // Execution reaches this point when the first non-number argument
8784 __ bind(&non_smi_result); 8810 // occurs (and only if smi code is skipped from the stub, otherwise
8785 } 8811 // the patching has already been done earlier in this case branch).
8786 break; 8812 // A perfect moment to try patching to STRINGS for ADD operation.
8813 if (op_ == Token::ADD) {
8814 GenerateTypeTransition(masm);
8815 }
8816 }
8817 break;
8818 }
8819 case Token::MOD: {
8820 // For MOD we go directly to runtime in the non-smi case.
8821 break;
8822 }
8823 case Token::BIT_OR:
8824 case Token::BIT_AND:
8825 case Token::BIT_XOR:
8826 case Token::SAR:
8827 case Token::SHL:
8828 case Token::SHR: {
8829 Label skip_allocation, non_smi_result;
8830 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime);
8831 switch (op_) {
8832 case Token::BIT_OR: __ orl(rax, rcx); break;
8833 case Token::BIT_AND: __ andl(rax, rcx); break;
8834 case Token::BIT_XOR: __ xorl(rax, rcx); break;
8835 case Token::SAR: __ sarl_cl(rax); break;
8836 case Token::SHL: __ shll_cl(rax); break;
8837 case Token::SHR: __ shrl_cl(rax); break;
8838 default: UNREACHABLE();
8839 }
8840 if (op_ == Token::SHR) {
8841 // Check if result is non-negative. This can only happen for a shift
8842 // by zero, which also doesn't update the sign flag.
8843 __ testl(rax, rax);
8844 __ j(negative, &non_smi_result);
8845 }
8846 __ JumpIfNotValidSmiValue(rax, &non_smi_result);
8847 // Tag smi result, if possible, and return.
8848 __ Integer32ToSmi(rax, rax);
8849 GenerateReturn(masm);
8850
8851 // All ops except SHR return a signed int32 that we load in
8852 // a HeapNumber.
8853 if (op_ != Token::SHR && non_smi_result.is_linked()) {
8854 __ bind(&non_smi_result);
8855 // Allocate a heap number if needed.
8856 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result
8857 switch (mode_) {
8858 case OVERWRITE_LEFT:
8859 case OVERWRITE_RIGHT:
8860 // If the operand was an object, we skip the
8861 // allocation of a heap number.
8862 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
8863 1 * kPointerSize : 2 * kPointerSize));
8864 __ JumpIfNotSmi(rax, &skip_allocation);
8865 // Fall through!
8866 case NO_OVERWRITE:
8867 __ AllocateHeapNumber(rax, rcx, &call_runtime);
8868 __ bind(&skip_allocation);
8869 break;
8870 default: UNREACHABLE();
8871 }
8872 // Store the result in the HeapNumber and return.
8873 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
8874 __ fild_s(Operand(rsp, 1 * kPointerSize));
8875 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
8876 GenerateReturn(masm);
8877 }
8878
8879 // SHR should return uint32 - go to runtime for non-smi/negative result.
8880 if (op_ == Token::SHR) {
8881 __ bind(&non_smi_result);
8882 }
8883 break;
8884 }
8885 default: UNREACHABLE(); break;
8787 } 8886 }
8788 default: UNREACHABLE(); break;
8789 } 8887 }
8790 8888
8791 // If all else fails, use the runtime system to get the correct 8889 // If all else fails, use the runtime system to get the correct
8792 // result. If arguments was passed in registers now place them on the 8890 // result. If arguments was passed in registers now place them on the
8793 // stack in the correct order below the return address. 8891 // stack in the correct order below the return address.
8794 __ bind(&call_runtime); 8892 __ bind(&call_runtime);
8893
8795 if (HasArgsInRegisters()) { 8894 if (HasArgsInRegisters()) {
8796 __ pop(rcx); 8895 GenerateRegisterArgsPush(masm);
8797 if (HasArgsReversed()) {
8798 __ push(rax);
8799 __ push(rdx);
8800 } else {
8801 __ push(rdx);
8802 __ push(rax);
8803 }
8804 __ push(rcx);
8805 } 8896 }
8897
8806 switch (op_) { 8898 switch (op_) {
8807 case Token::ADD: { 8899 case Token::ADD: {
8900 // Registers containing left and right operands respectively.
8901 Register lhs, rhs;
8902
8903 if (HasArgsReversed()) {
8904 lhs = rax;
8905 rhs = rdx;
8906 } else {
8907 lhs = rdx;
8908 rhs = rax;
8909 }
8910
8808 // Test for string arguments before calling runtime. 8911 // Test for string arguments before calling runtime.
8809 Label not_strings, both_strings, not_string1, string1; 8912 Label not_strings, both_strings, not_string1, string1, string1_smi2;
8913
8914 // If this stub has already generated FP-specific code then the arguments
8915 // are already in rdx, rax
8916 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
8917 GenerateLoadArguments(masm);
8918 }
8919
8810 Condition is_smi; 8920 Condition is_smi;
8811 Result answer; 8921 is_smi = masm->CheckSmi(lhs);
8812 is_smi = masm->CheckSmi(rdx);
8813 __ j(is_smi, &not_string1); 8922 __ j(is_smi, &not_string1);
8814 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); 8923 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8);
8815 __ j(above_equal, &not_string1); 8924 __ j(above_equal, &not_string1);
8816 8925
8817 // First argument is a a string, test second. 8926 // First argument is a a string, test second.
8818 is_smi = masm->CheckSmi(rax); 8927 is_smi = masm->CheckSmi(rhs);
8819 __ j(is_smi, &string1); 8928 __ j(is_smi, &string1_smi2);
8820 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); 8929 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9);
8821 __ j(above_equal, &string1); 8930 __ j(above_equal, &string1);
8822 8931
8823 // First and second argument are strings. 8932 // First and second argument are strings.
8824 StringAddStub stub(NO_STRING_CHECK_IN_STUB); 8933 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
8825 __ TailCallStub(&stub); 8934 __ TailCallStub(&string_add_stub);
8935
8936 __ bind(&string1_smi2);
8937 // First argument is a string, second is a smi. Try to lookup the number
8938 // string for the smi in the number string cache.
8939 NumberToStringStub::GenerateLookupNumberStringCache(
8940 masm, rhs, rbx, rcx, r8, true, &string1);
8941
8942 // Replace second argument on stack and tailcall string add stub to make
8943 // the result.
8944 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
8945 __ TailCallStub(&string_add_stub);
8826 8946
8827 // Only first argument is a string. 8947 // Only first argument is a string.
8828 __ bind(&string1); 8948 __ bind(&string1);
8829 __ InvokeBuiltin( 8949 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
8830 HasArgsReversed() ?
8831 Builtins::STRING_ADD_RIGHT :
8832 Builtins::STRING_ADD_LEFT,
8833 JUMP_FUNCTION);
8834 8950
8835 // First argument was not a string, test second. 8951 // First argument was not a string, test second.
8836 __ bind(&not_string1); 8952 __ bind(&not_string1);
8837 is_smi = masm->CheckSmi(rax); 8953 is_smi = masm->CheckSmi(rhs);
8838 __ j(is_smi, &not_strings); 8954 __ j(is_smi, &not_strings);
8839 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); 8955 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, rhs);
8840 __ j(above_equal, &not_strings); 8956 __ j(above_equal, &not_strings);
8841 8957
8842 // Only second argument is a string. 8958 // Only second argument is a string.
8843 __ InvokeBuiltin( 8959 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
8844 HasArgsReversed() ?
8845 Builtins::STRING_ADD_LEFT :
8846 Builtins::STRING_ADD_RIGHT,
8847 JUMP_FUNCTION);
8848 8960
8849 __ bind(&not_strings); 8961 __ bind(&not_strings);
8850 // Neither argument is a string. 8962 // Neither argument is a string.
8851 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 8963 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
8852 break; 8964 break;
8853 } 8965 }
8854 case Token::SUB: 8966 case Token::SUB:
8855 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 8967 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
8856 break; 8968 break;
8857 case Token::MUL: 8969 case Token::MUL:
(...skipping 19 matching lines...) Expand all
8877 break; 8989 break;
8878 case Token::SHL: 8990 case Token::SHL:
8879 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 8991 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
8880 break; 8992 break;
8881 case Token::SHR: 8993 case Token::SHR:
8882 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 8994 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
8883 break; 8995 break;
8884 default: 8996 default:
8885 UNREACHABLE(); 8997 UNREACHABLE();
8886 } 8998 }
8999
9000 // TODO(kaznacheev) Remove this (along with clearing) if it does not harm
9001 // performance.
9002 // Generate an unreachable reference to the DEFAULT stub so that it can be
9003 // found at the end of this stub when clearing ICs at GC.
9004 if (runtime_operands_type_ != BinaryOpIC::DEFAULT) {
9005 GenericBinaryOpStub uninit(MinorKey(), BinaryOpIC::DEFAULT);
9006 __ TailCallStub(&uninit);
9007 }
8887 } 9008 }
8888 9009
8889 9010
8890 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { 9011 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) {
8891 // If arguments are not passed in registers read them from the stack. 9012 ASSERT(!HasArgsInRegisters());
8892 if (!HasArgsInRegisters()) { 9013 __ movq(rax, Operand(rsp, 1 * kPointerSize));
8893 __ movq(rax, Operand(rsp, 1 * kPointerSize)); 9014 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
8894 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
8895 }
8896 } 9015 }
8897 9016
8898 9017
8899 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { 9018 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
8900 // If arguments are not passed in registers remove them from the stack before 9019 // If arguments are not passed in registers remove them from the stack before
8901 // returning. 9020 // returning.
8902 if (!HasArgsInRegisters()) { 9021 if (!HasArgsInRegisters()) {
8903 __ ret(2 * kPointerSize); // Remove both operands 9022 __ ret(2 * kPointerSize); // Remove both operands
8904 } else { 9023 } else {
8905 __ ret(0); 9024 __ ret(0);
8906 } 9025 }
8907 } 9026 }
8908 9027
8909 9028
9029 void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
9030 ASSERT(HasArgsInRegisters());
9031 __ pop(rcx);
9032 if (HasArgsReversed()) {
9033 __ push(rax);
9034 __ push(rdx);
9035 } else {
9036 __ push(rdx);
9037 __ push(rax);
9038 }
9039 __ push(rcx);
9040 }
9041
9042
9043 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
9044 Label get_result;
9045
9046 // Keep a copy of operands on the stack and make sure they are also in
9047 // rdx, rax.
9048 if (HasArgsInRegisters()) {
9049 GenerateRegisterArgsPush(masm);
9050 } else {
9051 GenerateLoadArguments(masm);
9052 }
9053
9054 // Internal frame is necessary to handle exceptions properly.
9055 __ EnterInternalFrame();
9056
9057 // Push arguments on stack if the stub expects them there.
9058 if (!HasArgsInRegisters()) {
9059 __ push(rdx);
9060 __ push(rax);
9061 }
9062 // Call the stub proper to get the result in rax.
9063 __ call(&get_result);
9064 __ LeaveInternalFrame();
9065
9066 // Left and right arguments are already on stack.
9067 __ pop(rcx);
9068 // Push the operation result. The tail call to BinaryOp_Patch will
9069 // return it to the original caller..
9070 __ push(rax);
9071
9072 // Push this stub's key.
9073 __ movq(rax, Immediate(MinorKey()));
9074 __ Integer32ToSmi(rax, rax);
9075 __ push(rax);
9076
9077 // Although the operation and the type info are encoded into the key,
9078 // the encoding is opaque, so push them too.
9079 __ movq(rax, Immediate(op_));
9080 __ Integer32ToSmi(rax, rax);
9081 __ push(rax);
9082
9083 __ movq(rax, Immediate(runtime_operands_type_));
9084 __ Integer32ToSmi(rax, rax);
9085 __ push(rax);
9086
9087 __ push(rcx);
9088
9089 // Perform patching to an appropriate fast case and return the result.
9090 __ TailCallExternalReference(
9091 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
9092 6,
9093 1);
9094
9095 // The entry point for the result calculation is assumed to be immediately
9096 // after this sequence.
9097 __ bind(&get_result);
9098 }
9099
9100
8910 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { 9101 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
8911 return Handle<Code>::null(); 9102 GenericBinaryOpStub stub(key, type_info);
9103 return stub.GetCode();
8912 } 9104 }
8913 9105
8914 9106
8915 int CompareStub::MinorKey() { 9107 int CompareStub::MinorKey() {
8916 // Encode the three parameters in a unique 16 bit value. 9108 // Encode the three parameters in a unique 16 bit value.
8917 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); 9109 ASSERT(static_cast<unsigned>(cc_) < (1 << 14));
8918 int nnn_value = (never_nan_nan_ ? 2 : 0); 9110 int nnn_value = (never_nan_nan_ ? 2 : 0);
8919 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. 9111 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs.
8920 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); 9112 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0);
8921 } 9113 }
(...skipping 874 matching lines...) Expand 10 before | Expand all | Expand 10 after
9796 // Call the function from C++. 9988 // Call the function from C++.
9797 return FUNCTION_CAST<ModuloFunction>(buffer); 9989 return FUNCTION_CAST<ModuloFunction>(buffer);
9798 } 9990 }
9799 9991
9800 #endif 9992 #endif
9801 9993
9802 9994
9803 #undef __ 9995 #undef __
9804 9996
9805 } } // namespace v8::internal 9997 } } // namespace v8::internal
OLDNEW
« src/runtime.cc ('K') | « src/x64/codegen-x64.h ('k') | src/x64/disasm-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698