| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 #ifdef _MSC_VER | 104 #ifdef _MSC_VER |
| 105 void LCodeGen::MakeSureStackPagesMapped(int offset) { | 105 void LCodeGen::MakeSureStackPagesMapped(int offset) { |
| 106 const int kPageSize = 4 * KB; | 106 const int kPageSize = 4 * KB; |
| 107 for (offset -= kPageSize; offset > 0; offset -= kPageSize) { | 107 for (offset -= kPageSize; offset > 0; offset -= kPageSize) { |
| 108 __ movq(Operand(rsp, offset), rax); | 108 __ movq(Operand(rsp, offset), rax); |
| 109 } | 109 } |
| 110 } | 110 } |
| 111 #endif | 111 #endif |
| 112 | 112 |
| 113 | 113 |
| 114 void LCodeGen::SaveCallerDoubles() { |
| 115 ASSERT(info()->saves_caller_doubles()); |
| 116 ASSERT(NeedsEagerFrame()); |
| 117 Comment(";;; Save clobbered callee double registers"); |
| 118 int count = 0; |
| 119 BitVector* doubles = chunk()->allocated_double_registers(); |
| 120 BitVector::Iterator save_iterator(doubles); |
| 121 while (!save_iterator.Done()) { |
| 122 __ movsd(MemOperand(rsp, count * kDoubleSize), |
| 123 XMMRegister::FromAllocationIndex(save_iterator.Current())); |
| 124 save_iterator.Advance(); |
| 125 count++; |
| 126 } |
| 127 } |
| 128 |
| 129 |
| 130 void LCodeGen::RestoreCallerDoubles() { |
| 131 ASSERT(info()->saves_caller_doubles()); |
| 132 ASSERT(NeedsEagerFrame()); |
| 133 Comment(";;; Restore clobbered callee double registers"); |
| 134 BitVector* doubles = chunk()->allocated_double_registers(); |
| 135 BitVector::Iterator save_iterator(doubles); |
| 136 int count = 0; |
| 137 while (!save_iterator.Done()) { |
| 138 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()), |
| 139 MemOperand(rsp, count * kDoubleSize)); |
| 140 save_iterator.Advance(); |
| 141 count++; |
| 142 } |
| 143 } |
| 144 |
| 145 |
| 114 bool LCodeGen::GeneratePrologue() { | 146 bool LCodeGen::GeneratePrologue() { |
| 115 ASSERT(is_generating()); | 147 ASSERT(is_generating()); |
| 116 | 148 |
| 117 if (info()->IsOptimizing()) { | 149 if (info()->IsOptimizing()) { |
| 118 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 150 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 119 | 151 |
| 120 #ifdef DEBUG | 152 #ifdef DEBUG |
| 121 if (strlen(FLAG_stop_at) > 0 && | 153 if (strlen(FLAG_stop_at) > 0 && |
| 122 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 154 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 123 __ int3(); | 155 __ int3(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 __ j(not_zero, &loop); | 198 __ j(not_zero, &loop); |
| 167 __ pop(rax); | 199 __ pop(rax); |
| 168 } else { | 200 } else { |
| 169 __ subq(rsp, Immediate(slots * kPointerSize)); | 201 __ subq(rsp, Immediate(slots * kPointerSize)); |
| 170 #ifdef _MSC_VER | 202 #ifdef _MSC_VER |
| 171 MakeSureStackPagesMapped(slots * kPointerSize); | 203 MakeSureStackPagesMapped(slots * kPointerSize); |
| 172 #endif | 204 #endif |
| 173 } | 205 } |
| 174 | 206 |
| 175 if (info()->saves_caller_doubles()) { | 207 if (info()->saves_caller_doubles()) { |
| 176 Comment(";;; Save clobbered callee double registers"); | 208 SaveCallerDoubles(); |
| 177 int count = 0; | |
| 178 BitVector* doubles = chunk()->allocated_double_registers(); | |
| 179 BitVector::Iterator save_iterator(doubles); | |
| 180 while (!save_iterator.Done()) { | |
| 181 __ movsd(MemOperand(rsp, count * kDoubleSize), | |
| 182 XMMRegister::FromAllocationIndex(save_iterator.Current())); | |
| 183 save_iterator.Advance(); | |
| 184 count++; | |
| 185 } | |
| 186 } | 209 } |
| 187 } | 210 } |
| 188 | 211 |
| 189 // Possibly allocate a local context. | 212 // Possibly allocate a local context. |
| 190 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 213 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 191 if (heap_slots > 0) { | 214 if (heap_slots > 0) { |
| 192 Comment(";;; Allocate local context"); | 215 Comment(";;; Allocate local context"); |
| 193 // Argument to NewContext is the function, which is still in rdi. | 216 // Argument to NewContext is the function, which is still in rdi. |
| 194 __ push(rdi); | 217 __ push(rdi); |
| 195 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 218 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 __ bind(&jump_table_[i].label); | 277 __ bind(&jump_table_[i].label); |
| 255 Address entry = jump_table_[i].address; | 278 Address entry = jump_table_[i].address; |
| 256 Deoptimizer::BailoutType type = jump_table_[i].bailout_type; | 279 Deoptimizer::BailoutType type = jump_table_[i].bailout_type; |
| 257 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); | 280 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); |
| 258 if (id == Deoptimizer::kNotDeoptimizationEntry) { | 281 if (id == Deoptimizer::kNotDeoptimizationEntry) { |
| 259 Comment(";;; jump table entry %d.", i); | 282 Comment(";;; jump table entry %d.", i); |
| 260 } else { | 283 } else { |
| 261 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); | 284 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); |
| 262 } | 285 } |
| 263 if (jump_table_[i].needs_frame) { | 286 if (jump_table_[i].needs_frame) { |
| 287 ASSERT(!info()->saves_caller_doubles()); |
| 264 __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); | 288 __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); |
| 265 if (needs_frame.is_bound()) { | 289 if (needs_frame.is_bound()) { |
| 266 __ jmp(&needs_frame); | 290 __ jmp(&needs_frame); |
| 267 } else { | 291 } else { |
| 268 __ bind(&needs_frame); | 292 __ bind(&needs_frame); |
| 269 __ movq(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset)); | 293 __ movq(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset)); |
| 270 __ push(rbp); | 294 __ push(rbp); |
| 271 __ movq(rbp, rsp); | 295 __ movq(rbp, rsp); |
| 272 __ push(rsi); | 296 __ push(rsi); |
| 273 // This variant of deopt can only be used with stubs. Since we don't | 297 // This variant of deopt can only be used with stubs. Since we don't |
| 274 // have a function pointer to install in the stack frame that we're | 298 // have a function pointer to install in the stack frame that we're |
| 275 // building, install a special marker there instead. | 299 // building, install a special marker there instead. |
| 276 ASSERT(info()->IsStub()); | 300 ASSERT(info()->IsStub()); |
| 277 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); | 301 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); |
| 278 __ push(rsi); | 302 __ push(rsi); |
| 279 __ movq(rsi, MemOperand(rsp, kPointerSize)); | 303 __ movq(rsi, MemOperand(rsp, kPointerSize)); |
| 280 __ call(kScratchRegister); | 304 __ call(kScratchRegister); |
| 281 } | 305 } |
| 282 } else { | 306 } else { |
| 307 if (info()->saves_caller_doubles()) { |
| 308 ASSERT(info()->IsStub()); |
| 309 RestoreCallerDoubles(); |
| 310 } |
| 283 __ call(entry, RelocInfo::RUNTIME_ENTRY); | 311 __ call(entry, RelocInfo::RUNTIME_ENTRY); |
| 284 } | 312 } |
| 285 } | 313 } |
| 286 return !is_aborted(); | 314 return !is_aborted(); |
| 287 } | 315 } |
| 288 | 316 |
| 289 | 317 |
| 290 bool LCodeGen::GenerateDeferredCode() { | 318 bool LCodeGen::GenerateDeferredCode() { |
| 291 ASSERT(is_generating()); | 319 ASSERT(is_generating()); |
| 292 if (deferred_.length() > 0) { | 320 if (deferred_.length() > 0) { |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 } | 436 } |
| 409 | 437 |
| 410 | 438 |
| 411 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { | 439 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { |
| 412 HConstant* constant = chunk_->LookupConstant(op); | 440 HConstant* constant = chunk_->LookupConstant(op); |
| 413 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged()); | 441 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged()); |
| 414 return constant->handle(isolate()); | 442 return constant->handle(isolate()); |
| 415 } | 443 } |
| 416 | 444 |
| 417 | 445 |
| 446 static int ArgumentsOffsetWithoutFrame(int index) { |
| 447 ASSERT(index < 0); |
| 448 return -(index + 1) * kPointerSize + kPCOnStackSize; |
| 449 } |
| 450 |
| 451 |
| 418 Operand LCodeGen::ToOperand(LOperand* op) const { | 452 Operand LCodeGen::ToOperand(LOperand* op) const { |
| 419 // Does not handle registers. In X64 assembler, plain registers are not | 453 // Does not handle registers. In X64 assembler, plain registers are not |
| 420 // representable as an Operand. | 454 // representable as an Operand. |
| 421 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); | 455 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); |
| 422 return Operand(rbp, StackSlotOffset(op->index())); | 456 if (NeedsEagerFrame()) { |
| 457 return Operand(rbp, StackSlotOffset(op->index())); |
| 458 } else { |
| 459 // Retrieve parameter without eager stack-frame relative to the |
| 460 // stack-pointer. |
| 461 return Operand(rsp, ArgumentsOffsetWithoutFrame(op->index())); |
| 462 } |
| 423 } | 463 } |
| 424 | 464 |
| 425 | 465 |
| 426 void LCodeGen::WriteTranslation(LEnvironment* environment, | 466 void LCodeGen::WriteTranslation(LEnvironment* environment, |
| 427 Translation* translation) { | 467 Translation* translation) { |
| 428 if (environment == NULL) return; | 468 if (environment == NULL) return; |
| 429 | 469 |
| 430 // The translation includes one command per value in the environment. | 470 // The translation includes one command per value in the environment. |
| 431 int translation_size = environment->translation_size(); | 471 int translation_size = environment->translation_size(); |
| 432 // The output frame height does not include the parameters. | 472 // The output frame height does not include the parameters. |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 if (info()->ShouldTrapOnDeopt()) { | 735 if (info()->ShouldTrapOnDeopt()) { |
| 696 Label done; | 736 Label done; |
| 697 if (cc != no_condition) { | 737 if (cc != no_condition) { |
| 698 __ j(NegateCondition(cc), &done, Label::kNear); | 738 __ j(NegateCondition(cc), &done, Label::kNear); |
| 699 } | 739 } |
| 700 __ int3(); | 740 __ int3(); |
| 701 __ bind(&done); | 741 __ bind(&done); |
| 702 } | 742 } |
| 703 | 743 |
| 704 ASSERT(info()->IsStub() || frame_is_built_); | 744 ASSERT(info()->IsStub() || frame_is_built_); |
| 705 if (cc == no_condition && frame_is_built_) { | 745 // Go through jump table if we need to handle condition, build frame, or |
| 746 // restore caller doubles. |
| 747 if (cc == no_condition && frame_is_built_ && |
| 748 !info()->saves_caller_doubles()) { |
| 706 __ call(entry, RelocInfo::RUNTIME_ENTRY); | 749 __ call(entry, RelocInfo::RUNTIME_ENTRY); |
| 707 } else { | 750 } else { |
| 708 // We often have several deopts to the same entry, reuse the last | 751 // We often have several deopts to the same entry, reuse the last |
| 709 // jump entry if this is the case. | 752 // jump entry if this is the case. |
| 710 if (jump_table_.is_empty() || | 753 if (jump_table_.is_empty() || |
| 711 jump_table_.last().address != entry || | 754 jump_table_.last().address != entry || |
| 712 jump_table_.last().needs_frame != !frame_is_built_ || | 755 jump_table_.last().needs_frame != !frame_is_built_ || |
| 713 jump_table_.last().bailout_type != bailout_type) { | 756 jump_table_.last().bailout_type != bailout_type) { |
| 714 Deoptimizer::JumpTableEntry table_entry(entry, | 757 Deoptimizer::JumpTableEntry table_entry(entry, |
| 715 bailout_type, | 758 bailout_type, |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 __ negl(left_reg); | 1037 __ negl(left_reg); |
| 995 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1038 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 996 DeoptimizeIf(zero, instr->environment()); | 1039 DeoptimizeIf(zero, instr->environment()); |
| 997 } | 1040 } |
| 998 __ jmp(&done, Label::kNear); | 1041 __ jmp(&done, Label::kNear); |
| 999 } | 1042 } |
| 1000 | 1043 |
| 1001 __ bind(&left_is_not_negative); | 1044 __ bind(&left_is_not_negative); |
| 1002 __ andl(left_reg, Immediate(divisor - 1)); | 1045 __ andl(left_reg, Immediate(divisor - 1)); |
| 1003 __ bind(&done); | 1046 __ bind(&done); |
| 1004 | |
| 1005 } else if (hmod->fixed_right_arg().has_value) { | |
| 1006 Register left_reg = ToRegister(instr->left()); | |
| 1007 ASSERT(left_reg.is(ToRegister(instr->result()))); | |
| 1008 Register right_reg = ToRegister(instr->right()); | |
| 1009 | |
| 1010 int32_t divisor = hmod->fixed_right_arg().value; | |
| 1011 ASSERT(IsPowerOf2(divisor)); | |
| 1012 | |
| 1013 // Check if our assumption of a fixed right operand still holds. | |
| 1014 __ cmpl(right_reg, Immediate(divisor)); | |
| 1015 DeoptimizeIf(not_equal, instr->environment()); | |
| 1016 | |
| 1017 Label left_is_not_negative, done; | |
| 1018 if (left->CanBeNegative()) { | |
| 1019 __ testl(left_reg, left_reg); | |
| 1020 __ j(not_sign, &left_is_not_negative, Label::kNear); | |
| 1021 __ negl(left_reg); | |
| 1022 __ andl(left_reg, Immediate(divisor - 1)); | |
| 1023 __ negl(left_reg); | |
| 1024 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 1025 DeoptimizeIf(zero, instr->environment()); | |
| 1026 } | |
| 1027 __ jmp(&done, Label::kNear); | |
| 1028 } | |
| 1029 | |
| 1030 __ bind(&left_is_not_negative); | |
| 1031 __ andl(left_reg, Immediate(divisor - 1)); | |
| 1032 __ bind(&done); | |
| 1033 | |
| 1034 } else { | 1047 } else { |
| 1035 Register left_reg = ToRegister(instr->left()); | 1048 Register left_reg = ToRegister(instr->left()); |
| 1036 ASSERT(left_reg.is(rax)); | 1049 ASSERT(left_reg.is(rax)); |
| 1037 Register right_reg = ToRegister(instr->right()); | 1050 Register right_reg = ToRegister(instr->right()); |
| 1038 ASSERT(!right_reg.is(rax)); | 1051 ASSERT(!right_reg.is(rax)); |
| 1039 ASSERT(!right_reg.is(rdx)); | 1052 ASSERT(!right_reg.is(rdx)); |
| 1040 Register result_reg = ToRegister(instr->result()); | 1053 Register result_reg = ToRegister(instr->result()); |
| 1041 ASSERT(result_reg.is(rdx)); | 1054 ASSERT(result_reg.is(rdx)); |
| 1042 | 1055 |
| 1043 Label done; | 1056 Label done; |
| (...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1713 __ movzxwl(result, operand); | 1726 __ movzxwl(result, operand); |
| 1714 } | 1727 } |
| 1715 } | 1728 } |
| 1716 | 1729 |
| 1717 | 1730 |
| 1718 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { | 1731 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { |
| 1719 String::Encoding encoding = instr->hydrogen()->encoding(); | 1732 String::Encoding encoding = instr->hydrogen()->encoding(); |
| 1720 Register string = ToRegister(instr->string()); | 1733 Register string = ToRegister(instr->string()); |
| 1721 | 1734 |
| 1722 if (FLAG_debug_code) { | 1735 if (FLAG_debug_code) { |
| 1723 __ push(string); | 1736 Register value = ToRegister(instr->value()); |
| 1724 __ movq(string, FieldOperand(string, HeapObject::kMapOffset)); | 1737 Register index = ToRegister(instr->index()); |
| 1725 __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset)); | |
| 1726 | |
| 1727 __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask)); | |
| 1728 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 1738 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 1729 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 1739 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 1730 __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING | 1740 int encoding_mask = |
| 1731 ? one_byte_seq_type : two_byte_seq_type)); | 1741 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING |
| 1732 __ Check(equal, kUnexpectedStringType); | 1742 ? one_byte_seq_type : two_byte_seq_type; |
| 1733 __ pop(string); | 1743 __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask); |
| 1734 } | 1744 } |
| 1735 | 1745 |
| 1736 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding); | 1746 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding); |
| 1737 if (instr->value()->IsConstantOperand()) { | 1747 if (instr->value()->IsConstantOperand()) { |
| 1738 int value = ToInteger32(LConstantOperand::cast(instr->value())); | 1748 int value = ToInteger32(LConstantOperand::cast(instr->value())); |
| 1739 ASSERT_LE(0, value); | 1749 ASSERT_LE(0, value); |
| 1740 if (encoding == String::ONE_BYTE_ENCODING) { | 1750 if (encoding == String::ONE_BYTE_ENCODING) { |
| 1741 ASSERT_LE(value, String::kMaxOneByteCharCode); | 1751 ASSERT_LE(value, String::kMaxOneByteCharCode); |
| 1742 __ movb(operand, Immediate(value)); | 1752 __ movb(operand, Immediate(value)); |
| 1743 } else { | 1753 } else { |
| (...skipping 927 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2671 if (FLAG_trace && info()->IsOptimizing()) { | 2681 if (FLAG_trace && info()->IsOptimizing()) { |
| 2672 // Preserve the return value on the stack and rely on the runtime call | 2682 // Preserve the return value on the stack and rely on the runtime call |
| 2673 // to return the value in the same register. We're leaving the code | 2683 // to return the value in the same register. We're leaving the code |
| 2674 // managed by the register allocator and tearing down the frame, it's | 2684 // managed by the register allocator and tearing down the frame, it's |
| 2675 // safe to write to the context register. | 2685 // safe to write to the context register. |
| 2676 __ push(rax); | 2686 __ push(rax); |
| 2677 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2687 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2678 __ CallRuntime(Runtime::kTraceExit, 1); | 2688 __ CallRuntime(Runtime::kTraceExit, 1); |
| 2679 } | 2689 } |
| 2680 if (info()->saves_caller_doubles()) { | 2690 if (info()->saves_caller_doubles()) { |
| 2681 ASSERT(NeedsEagerFrame()); | 2691 RestoreCallerDoubles(); |
| 2682 BitVector* doubles = chunk()->allocated_double_registers(); | |
| 2683 BitVector::Iterator save_iterator(doubles); | |
| 2684 int count = 0; | |
| 2685 while (!save_iterator.Done()) { | |
| 2686 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()), | |
| 2687 MemOperand(rsp, count * kDoubleSize)); | |
| 2688 save_iterator.Advance(); | |
| 2689 count++; | |
| 2690 } | |
| 2691 } | 2692 } |
| 2692 int no_frame_start = -1; | 2693 int no_frame_start = -1; |
| 2693 if (NeedsEagerFrame()) { | 2694 if (NeedsEagerFrame()) { |
| 2694 __ movq(rsp, rbp); | 2695 __ movq(rsp, rbp); |
| 2695 __ pop(rbp); | 2696 __ pop(rbp); |
| 2696 no_frame_start = masm_->pc_offset(); | 2697 no_frame_start = masm_->pc_offset(); |
| 2697 } | 2698 } |
| 2698 if (instr->has_constant_parameter_count()) { | 2699 if (instr->has_constant_parameter_count()) { |
| 2699 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize, | 2700 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize, |
| 2700 rcx); | 2701 rcx); |
| (...skipping 1011 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3712 MathPowStub stub(MathPowStub::INTEGER); | 3713 MathPowStub stub(MathPowStub::INTEGER); |
| 3713 __ CallStub(&stub); | 3714 __ CallStub(&stub); |
| 3714 } else { | 3715 } else { |
| 3715 ASSERT(exponent_type.IsDouble()); | 3716 ASSERT(exponent_type.IsDouble()); |
| 3716 MathPowStub stub(MathPowStub::DOUBLE); | 3717 MathPowStub stub(MathPowStub::DOUBLE); |
| 3717 __ CallStub(&stub); | 3718 __ CallStub(&stub); |
| 3718 } | 3719 } |
| 3719 } | 3720 } |
| 3720 | 3721 |
| 3721 | 3722 |
| 3722 void LCodeGen::DoRandom(LRandom* instr) { | |
| 3723 // Assert that register size is twice the size of each seed. | |
| 3724 static const int kSeedSize = sizeof(uint32_t); | |
| 3725 STATIC_ASSERT(kPointerSize == 2 * kSeedSize); | |
| 3726 | |
| 3727 // Load native context | |
| 3728 Register global_object = ToRegister(instr->global_object()); | |
| 3729 Register native_context = global_object; | |
| 3730 __ movq(native_context, FieldOperand( | |
| 3731 global_object, GlobalObject::kNativeContextOffset)); | |
| 3732 | |
| 3733 // Load state (FixedArray of the native context's random seeds) | |
| 3734 static const int kRandomSeedOffset = | |
| 3735 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize; | |
| 3736 Register state = native_context; | |
| 3737 __ movq(state, FieldOperand(native_context, kRandomSeedOffset)); | |
| 3738 | |
| 3739 // Load state[0]. | |
| 3740 Register state0 = ToRegister(instr->scratch()); | |
| 3741 __ movl(state0, FieldOperand(state, ByteArray::kHeaderSize)); | |
| 3742 // Load state[1]. | |
| 3743 Register state1 = ToRegister(instr->scratch2()); | |
| 3744 __ movl(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize)); | |
| 3745 | |
| 3746 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16) | |
| 3747 Register scratch3 = ToRegister(instr->scratch3()); | |
| 3748 __ movzxwl(scratch3, state0); | |
| 3749 __ imull(scratch3, scratch3, Immediate(18273)); | |
| 3750 __ shrl(state0, Immediate(16)); | |
| 3751 __ addl(state0, scratch3); | |
| 3752 // Save state[0]. | |
| 3753 __ movl(FieldOperand(state, ByteArray::kHeaderSize), state0); | |
| 3754 | |
| 3755 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16) | |
| 3756 __ movzxwl(scratch3, state1); | |
| 3757 __ imull(scratch3, scratch3, Immediate(36969)); | |
| 3758 __ shrl(state1, Immediate(16)); | |
| 3759 __ addl(state1, scratch3); | |
| 3760 // Save state[1]. | |
| 3761 __ movl(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1); | |
| 3762 | |
| 3763 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF) | |
| 3764 Register random = state0; | |
| 3765 __ shll(random, Immediate(14)); | |
| 3766 __ andl(state1, Immediate(0x3FFFF)); | |
| 3767 __ addl(random, state1); | |
| 3768 | |
| 3769 // Convert 32 random bits in rax to 0.(32 random bits) in a double | |
| 3770 // by computing: | |
| 3771 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | |
| 3772 XMMRegister result = ToDoubleRegister(instr->result()); | |
| 3773 XMMRegister scratch4 = double_scratch0(); | |
| 3774 __ movq(scratch3, V8_INT64_C(0x4130000000000000)); // 1.0 x 2^20 as double | |
| 3775 __ movq(scratch4, scratch3); | |
| 3776 __ movd(result, random); | |
| 3777 __ xorps(result, scratch4); | |
| 3778 __ subsd(result, scratch4); | |
| 3779 } | |
| 3780 | |
| 3781 | |
| 3782 void LCodeGen::DoMathExp(LMathExp* instr) { | 3723 void LCodeGen::DoMathExp(LMathExp* instr) { |
| 3783 XMMRegister input = ToDoubleRegister(instr->value()); | 3724 XMMRegister input = ToDoubleRegister(instr->value()); |
| 3784 XMMRegister result = ToDoubleRegister(instr->result()); | 3725 XMMRegister result = ToDoubleRegister(instr->result()); |
| 3785 XMMRegister temp0 = double_scratch0(); | 3726 XMMRegister temp0 = double_scratch0(); |
| 3786 Register temp1 = ToRegister(instr->temp1()); | 3727 Register temp1 = ToRegister(instr->temp1()); |
| 3787 Register temp2 = ToRegister(instr->temp2()); | 3728 Register temp2 = ToRegister(instr->temp2()); |
| 3788 | 3729 |
| 3789 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2); | 3730 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2); |
| 3790 } | 3731 } |
| 3791 | 3732 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3903 } | 3844 } |
| 3904 | 3845 |
| 3905 | 3846 |
| 3906 void LCodeGen::DoCallFunction(LCallFunction* instr) { | 3847 void LCodeGen::DoCallFunction(LCallFunction* instr) { |
| 3907 ASSERT(ToRegister(instr->context()).is(rsi)); | 3848 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 3908 ASSERT(ToRegister(instr->function()).is(rdi)); | 3849 ASSERT(ToRegister(instr->function()).is(rdi)); |
| 3909 ASSERT(ToRegister(instr->result()).is(rax)); | 3850 ASSERT(ToRegister(instr->result()).is(rax)); |
| 3910 | 3851 |
| 3911 int arity = instr->arity(); | 3852 int arity = instr->arity(); |
| 3912 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); | 3853 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); |
| 3913 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 3854 if (instr->hydrogen()->IsTailCall()) { |
| 3855 if (NeedsEagerFrame()) __ leave(); |
| 3856 __ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET); |
| 3857 } else { |
| 3858 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 3859 } |
| 3914 } | 3860 } |
| 3915 | 3861 |
| 3916 | 3862 |
| 3917 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 3863 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
| 3918 ASSERT(ToRegister(instr->context()).is(rsi)); | 3864 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 3919 ASSERT(ToRegister(instr->result()).is(rax)); | 3865 ASSERT(ToRegister(instr->result()).is(rax)); |
| 3920 int arity = instr->arity(); | 3866 int arity = instr->arity(); |
| 3921 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; | 3867 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; |
| 3922 Handle<Code> ic = | 3868 Handle<Code> ic = |
| 3923 isolate()->stub_cache()->ComputeCallInitialize(arity, mode); | 3869 isolate()->stub_cache()->ComputeCallInitialize(arity, mode); |
| (...skipping 1300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5224 if (instr->size()->IsRegister()) { | 5170 if (instr->size()->IsRegister()) { |
| 5225 Register size = ToRegister(instr->size()); | 5171 Register size = ToRegister(instr->size()); |
| 5226 ASSERT(!size.is(result)); | 5172 ASSERT(!size.is(result)); |
| 5227 __ Integer32ToSmi(size, size); | 5173 __ Integer32ToSmi(size, size); |
| 5228 __ push(size); | 5174 __ push(size); |
| 5229 } else { | 5175 } else { |
| 5230 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); | 5176 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); |
| 5231 __ Push(Smi::FromInt(size)); | 5177 __ Push(Smi::FromInt(size)); |
| 5232 } | 5178 } |
| 5233 | 5179 |
| 5180 int flags = 0; |
| 5234 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) { | 5181 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) { |
| 5235 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation()); | 5182 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation()); |
| 5236 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); | 5183 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); |
| 5237 CallRuntimeFromDeferred( | 5184 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE); |
| 5238 Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context()); | |
| 5239 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) { | 5185 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) { |
| 5240 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); | 5186 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); |
| 5241 CallRuntimeFromDeferred( | 5187 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE); |
| 5242 Runtime::kAllocateInOldDataSpace, 1, instr, instr->context()); | |
| 5243 } else { | 5188 } else { |
| 5244 CallRuntimeFromDeferred( | 5189 flags = AllocateTargetSpace::update(flags, NEW_SPACE); |
| 5245 Runtime::kAllocateInNewSpace, 1, instr, instr->context()); | |
| 5246 } | 5190 } |
| 5191 __ Push(Smi::FromInt(flags)); |
| 5192 |
| 5193 CallRuntimeFromDeferred( |
| 5194 Runtime::kAllocateInTargetSpace, 2, instr, instr->context()); |
| 5247 __ StoreToSafepointRegisterSlot(result, rax); | 5195 __ StoreToSafepointRegisterSlot(result, rax); |
| 5248 } | 5196 } |
| 5249 | 5197 |
| 5250 | 5198 |
| 5251 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { | 5199 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { |
| 5252 ASSERT(ToRegister(instr->value()).is(rax)); | 5200 ASSERT(ToRegister(instr->value()).is(rax)); |
| 5253 __ push(rax); | 5201 __ push(rax); |
| 5254 CallRuntime(Runtime::kToFastProperties, 1, instr); | 5202 CallRuntime(Runtime::kToFastProperties, 1, instr); |
| 5255 } | 5203 } |
| 5256 | 5204 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5341 } else if (operand->IsRegister()) { | 5289 } else if (operand->IsRegister()) { |
| 5342 __ push(ToRegister(operand)); | 5290 __ push(ToRegister(operand)); |
| 5343 } else { | 5291 } else { |
| 5344 __ push(ToOperand(operand)); | 5292 __ push(ToOperand(operand)); |
| 5345 } | 5293 } |
| 5346 } | 5294 } |
| 5347 | 5295 |
| 5348 | 5296 |
| 5349 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 5297 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 5350 Register input = ToRegister(instr->value()); | 5298 Register input = ToRegister(instr->value()); |
| 5351 | 5299 Condition final_branch_condition = EmitTypeofIs(instr, input); |
| 5352 Condition final_branch_condition = | |
| 5353 EmitTypeofIs(instr->TrueLabel(chunk_), | |
| 5354 instr->FalseLabel(chunk_), input, instr->type_literal()); | |
| 5355 if (final_branch_condition != no_condition) { | 5300 if (final_branch_condition != no_condition) { |
| 5356 EmitBranch(instr, final_branch_condition); | 5301 EmitBranch(instr, final_branch_condition); |
| 5357 } | 5302 } |
| 5358 } | 5303 } |
| 5359 | 5304 |
| 5360 | 5305 |
| 5361 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 5306 Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { |
| 5362 Label* false_label, | 5307 Label* true_label = instr->TrueLabel(chunk_); |
| 5363 Register input, | 5308 Label* false_label = instr->FalseLabel(chunk_); |
| 5364 Handle<String> type_name) { | 5309 Handle<String> type_name = instr->type_literal(); |
| 5310 int left_block = instr->TrueDestination(chunk_); |
| 5311 int right_block = instr->FalseDestination(chunk_); |
| 5312 int next_block = GetNextEmittedBlock(); |
| 5313 |
| 5314 Label::Distance true_distance = left_block == next_block ? Label::kNear |
| 5315 : Label::kFar; |
| 5316 Label::Distance false_distance = right_block == next_block ? Label::kNear |
| 5317 : Label::kFar; |
| 5365 Condition final_branch_condition = no_condition; | 5318 Condition final_branch_condition = no_condition; |
| 5366 if (type_name->Equals(heap()->number_string())) { | 5319 if (type_name->Equals(heap()->number_string())) { |
| 5367 __ JumpIfSmi(input, true_label); | 5320 __ JumpIfSmi(input, true_label, true_distance); |
| 5368 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset), | 5321 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset), |
| 5369 Heap::kHeapNumberMapRootIndex); | 5322 Heap::kHeapNumberMapRootIndex); |
| 5370 | 5323 |
| 5371 final_branch_condition = equal; | 5324 final_branch_condition = equal; |
| 5372 | 5325 |
| 5373 } else if (type_name->Equals(heap()->string_string())) { | 5326 } else if (type_name->Equals(heap()->string_string())) { |
| 5374 __ JumpIfSmi(input, false_label); | 5327 __ JumpIfSmi(input, false_label, false_distance); |
| 5375 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); | 5328 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); |
| 5376 __ j(above_equal, false_label); | 5329 __ j(above_equal, false_label, false_distance); |
| 5377 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 5330 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 5378 Immediate(1 << Map::kIsUndetectable)); | 5331 Immediate(1 << Map::kIsUndetectable)); |
| 5379 final_branch_condition = zero; | 5332 final_branch_condition = zero; |
| 5380 | 5333 |
| 5381 } else if (type_name->Equals(heap()->symbol_string())) { | 5334 } else if (type_name->Equals(heap()->symbol_string())) { |
| 5382 __ JumpIfSmi(input, false_label); | 5335 __ JumpIfSmi(input, false_label, false_distance); |
| 5383 __ CmpObjectType(input, SYMBOL_TYPE, input); | 5336 __ CmpObjectType(input, SYMBOL_TYPE, input); |
| 5384 final_branch_condition = equal; | 5337 final_branch_condition = equal; |
| 5385 | 5338 |
| 5386 } else if (type_name->Equals(heap()->boolean_string())) { | 5339 } else if (type_name->Equals(heap()->boolean_string())) { |
| 5387 __ CompareRoot(input, Heap::kTrueValueRootIndex); | 5340 __ CompareRoot(input, Heap::kTrueValueRootIndex); |
| 5388 __ j(equal, true_label); | 5341 __ j(equal, true_label, true_distance); |
| 5389 __ CompareRoot(input, Heap::kFalseValueRootIndex); | 5342 __ CompareRoot(input, Heap::kFalseValueRootIndex); |
| 5390 final_branch_condition = equal; | 5343 final_branch_condition = equal; |
| 5391 | 5344 |
| 5392 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { | 5345 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { |
| 5393 __ CompareRoot(input, Heap::kNullValueRootIndex); | 5346 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 5394 final_branch_condition = equal; | 5347 final_branch_condition = equal; |
| 5395 | 5348 |
| 5396 } else if (type_name->Equals(heap()->undefined_string())) { | 5349 } else if (type_name->Equals(heap()->undefined_string())) { |
| 5397 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); | 5350 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); |
| 5398 __ j(equal, true_label); | 5351 __ j(equal, true_label, true_distance); |
| 5399 __ JumpIfSmi(input, false_label); | 5352 __ JumpIfSmi(input, false_label, false_distance); |
| 5400 // Check for undetectable objects => true. | 5353 // Check for undetectable objects => true. |
| 5401 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | 5354 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 5402 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 5355 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 5403 Immediate(1 << Map::kIsUndetectable)); | 5356 Immediate(1 << Map::kIsUndetectable)); |
| 5404 final_branch_condition = not_zero; | 5357 final_branch_condition = not_zero; |
| 5405 | 5358 |
| 5406 } else if (type_name->Equals(heap()->function_string())) { | 5359 } else if (type_name->Equals(heap()->function_string())) { |
| 5407 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); | 5360 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
| 5408 __ JumpIfSmi(input, false_label); | 5361 __ JumpIfSmi(input, false_label, false_distance); |
| 5409 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); | 5362 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); |
| 5410 __ j(equal, true_label); | 5363 __ j(equal, true_label, true_distance); |
| 5411 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); | 5364 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); |
| 5412 final_branch_condition = equal; | 5365 final_branch_condition = equal; |
| 5413 | 5366 |
| 5414 } else if (type_name->Equals(heap()->object_string())) { | 5367 } else if (type_name->Equals(heap()->object_string())) { |
| 5415 __ JumpIfSmi(input, false_label); | 5368 __ JumpIfSmi(input, false_label, false_distance); |
| 5416 if (!FLAG_harmony_typeof) { | 5369 if (!FLAG_harmony_typeof) { |
| 5417 __ CompareRoot(input, Heap::kNullValueRootIndex); | 5370 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 5418 __ j(equal, true_label); | 5371 __ j(equal, true_label, true_distance); |
| 5419 } | 5372 } |
| 5420 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); | 5373 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); |
| 5421 __ j(below, false_label); | 5374 __ j(below, false_label, false_distance); |
| 5422 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 5375 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 5423 __ j(above, false_label); | 5376 __ j(above, false_label, false_distance); |
| 5424 // Check for undetectable objects => false. | 5377 // Check for undetectable objects => false. |
| 5425 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 5378 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 5426 Immediate(1 << Map::kIsUndetectable)); | 5379 Immediate(1 << Map::kIsUndetectable)); |
| 5427 final_branch_condition = zero; | 5380 final_branch_condition = zero; |
| 5428 | 5381 |
| 5429 } else { | 5382 } else { |
| 5430 __ jmp(false_label); | 5383 __ jmp(false_label, false_distance); |
| 5431 } | 5384 } |
| 5432 | 5385 |
| 5433 return final_branch_condition; | 5386 return final_branch_condition; |
| 5434 } | 5387 } |
| 5435 | 5388 |
| 5436 | 5389 |
| 5437 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 5390 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 5438 Register temp = ToRegister(instr->temp()); | 5391 Register temp = ToRegister(instr->temp()); |
| 5439 | 5392 |
| 5440 EmitIsConstructCall(temp); | 5393 EmitIsConstructCall(temp); |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5673 FixedArray::kHeaderSize - kPointerSize)); | 5626 FixedArray::kHeaderSize - kPointerSize)); |
| 5674 __ bind(&done); | 5627 __ bind(&done); |
| 5675 } | 5628 } |
| 5676 | 5629 |
| 5677 | 5630 |
| 5678 #undef __ | 5631 #undef __ |
| 5679 | 5632 |
| 5680 } } // namespace v8::internal | 5633 } } // namespace v8::internal |
| 5681 | 5634 |
| 5682 #endif // V8_TARGET_ARCH_X64 | 5635 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |