| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 19 matching lines...) Expand all Loading... |
| 30 #if defined(V8_TARGET_ARCH_X64) | 30 #if defined(V8_TARGET_ARCH_X64) |
| 31 | 31 |
| 32 #include "x64/lithium-codegen-x64.h" | 32 #include "x64/lithium-codegen-x64.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "stub-cache.h" | 34 #include "stub-cache.h" |
| 35 | 35 |
| 36 namespace v8 { | 36 namespace v8 { |
| 37 namespace internal { | 37 namespace internal { |
| 38 | 38 |
| 39 | 39 |
| 40 // When invoking builtins, we need to record the safepoint in the middle of |
| 41 // the invoke instruction sequence generated by the macro assembler. |
| 42 class SafepointGenerator : public CallWrapper { |
| 43 public: |
| 44 SafepointGenerator(LCodeGen* codegen, |
| 45 LPointerMap* pointers, |
| 46 int deoptimization_index, |
| 47 bool ensure_reloc_space = false) |
| 48 : codegen_(codegen), |
| 49 pointers_(pointers), |
| 50 deoptimization_index_(deoptimization_index), |
| 51 ensure_reloc_space_(ensure_reloc_space) { } |
| 52 virtual ~SafepointGenerator() { } |
| 53 |
| 54 virtual void BeforeCall(int call_size) { |
| 55 ASSERT(call_size >= 0); |
| 56 // Ensure that we have enough space after the previous safepoint position |
| 57 // for the jump generated there. |
| 58 int call_end = codegen_->masm()->pc_offset() + call_size; |
| 59 int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize; |
| 60 if (call_end < prev_jump_end) { |
| 61 int padding_size = prev_jump_end - call_end; |
| 62 STATIC_ASSERT(kMinSafepointSize <= 9); // One multibyte nop is enough. |
| 63 codegen_->masm()->nop(padding_size); |
| 64 } |
| 65 } |
| 66 |
| 67 virtual void AfterCall() { |
| 68 // Ensure that we have enough space in the reloc info to patch |
| 69 // this with calls when doing deoptimization. |
| 70 if (ensure_reloc_space_) { |
| 71 codegen_->masm()->RecordComment(RelocInfo::kFillerCommentString, true); |
| 72 } |
| 73 codegen_->RecordSafepoint(pointers_, deoptimization_index_); |
| 74 } |
| 75 |
| 76 private: |
| 77 static const int kMinSafepointSize = |
| 78 MacroAssembler::kShortCallInstructionLength; |
| 79 LCodeGen* codegen_; |
| 80 LPointerMap* pointers_; |
| 81 int deoptimization_index_; |
| 82 bool ensure_reloc_space_; |
| 83 }; |
| 84 |
| 85 |
| 40 #define __ masm()-> | 86 #define __ masm()-> |
| 41 | 87 |
| 42 bool LCodeGen::GenerateCode() { | 88 bool LCodeGen::GenerateCode() { |
| 43 HPhase phase("Code generation", chunk()); | 89 HPhase phase("Code generation", chunk()); |
| 44 ASSERT(is_unused()); | 90 ASSERT(is_unused()); |
| 45 status_ = GENERATING; | 91 status_ = GENERATING; |
| 46 return GeneratePrologue() && | 92 return GeneratePrologue() && |
| 47 GenerateBody() && | 93 GenerateBody() && |
| 48 GenerateDeferredCode() && | 94 GenerateDeferredCode() && |
| 95 GenerateJumpTable() && |
| 49 GenerateSafepointTable(); | 96 GenerateSafepointTable(); |
| 50 } | 97 } |
| 51 | 98 |
| 52 | 99 |
| 53 void LCodeGen::FinishCode(Handle<Code> code) { | 100 void LCodeGen::FinishCode(Handle<Code> code) { |
| 54 ASSERT(is_done()); | 101 ASSERT(is_done()); |
| 55 code->set_stack_slots(StackSlotCount()); | 102 code->set_stack_slots(StackSlotCount()); |
| 56 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 103 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 57 PopulateDeoptimizationData(code); | 104 PopulateDeoptimizationData(code); |
| 58 } | 105 } |
| 59 | 106 |
| 60 | 107 |
| 61 void LCodeGen::Abort(const char* format, ...) { | 108 void LCodeGen::Abort(const char* format, ...) { |
| 62 if (FLAG_trace_bailout) { | 109 if (FLAG_trace_bailout) { |
| 63 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 110 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 64 PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name); | 111 PrintF("Aborting LCodeGen in @\"%s\": ", *name); |
| 65 va_list arguments; | 112 va_list arguments; |
| 66 va_start(arguments, format); | 113 va_start(arguments, format); |
| 67 OS::VPrint(format, arguments); | 114 OS::VPrint(format, arguments); |
| 68 va_end(arguments); | 115 va_end(arguments); |
| 69 PrintF("\n"); | 116 PrintF("\n"); |
| 70 } | 117 } |
| 71 status_ = ABORTED; | 118 status_ = ABORTED; |
| 72 } | 119 } |
| 73 | 120 |
| 74 | 121 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 const int kPageSize = 4 * KB; | 172 const int kPageSize = 4 * KB; |
| 126 for (int offset = slots * kPointerSize - kPageSize; | 173 for (int offset = slots * kPointerSize - kPageSize; |
| 127 offset > 0; | 174 offset > 0; |
| 128 offset -= kPageSize) { | 175 offset -= kPageSize) { |
| 129 __ movq(Operand(rsp, offset), rax); | 176 __ movq(Operand(rsp, offset), rax); |
| 130 } | 177 } |
| 131 #endif | 178 #endif |
| 132 } | 179 } |
| 133 } | 180 } |
| 134 | 181 |
| 182 // Possibly allocate a local context. |
| 183 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 184 if (heap_slots > 0) { |
| 185 Comment(";;; Allocate local context"); |
| 186 // Argument to NewContext is the function, which is still in rdi. |
| 187 __ push(rdi); |
| 188 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 189 FastNewContextStub stub(heap_slots); |
| 190 __ CallStub(&stub); |
| 191 } else { |
| 192 __ CallRuntime(Runtime::kNewContext, 1); |
| 193 } |
| 194 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); |
| 195 // Context is returned in both rax and rsi. It replaces the context |
| 196 // passed to us. It's saved in the stack and kept live in rsi. |
| 197 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
| 198 |
| 199 // Copy any necessary parameters into the context. |
| 200 int num_parameters = scope()->num_parameters(); |
| 201 for (int i = 0; i < num_parameters; i++) { |
| 202 Slot* slot = scope()->parameter(i)->AsSlot(); |
| 203 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 204 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 205 (num_parameters - 1 - i) * kPointerSize; |
| 206 // Load parameter from stack. |
| 207 __ movq(rax, Operand(rbp, parameter_offset)); |
| 208 // Store it in the context. |
| 209 int context_offset = Context::SlotOffset(slot->index()); |
| 210 __ movq(Operand(rsi, context_offset), rax); |
| 211 // Update the write barrier. This clobbers all involved |
| 212 // registers, so we have use a third register to avoid |
| 213 // clobbering rsi. |
| 214 __ movq(rcx, rsi); |
| 215 __ RecordWrite(rcx, context_offset, rax, rbx); |
| 216 } |
| 217 } |
| 218 Comment(";;; End allocate local context"); |
| 219 } |
| 220 |
| 135 // Trace the call. | 221 // Trace the call. |
| 136 if (FLAG_trace) { | 222 if (FLAG_trace) { |
| 137 __ CallRuntime(Runtime::kTraceEnter, 0); | 223 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 138 } | 224 } |
| 139 return !is_aborted(); | 225 return !is_aborted(); |
| 140 } | 226 } |
| 141 | 227 |
| 142 | 228 |
| 143 bool LCodeGen::GenerateBody() { | 229 bool LCodeGen::GenerateBody() { |
| 144 ASSERT(is_generating()); | 230 ASSERT(is_generating()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 163 | 249 |
| 164 LInstruction* LCodeGen::GetNextInstruction() { | 250 LInstruction* LCodeGen::GetNextInstruction() { |
| 165 if (current_instruction_ < instructions_->length() - 1) { | 251 if (current_instruction_ < instructions_->length() - 1) { |
| 166 return instructions_->at(current_instruction_ + 1); | 252 return instructions_->at(current_instruction_ + 1); |
| 167 } else { | 253 } else { |
| 168 return NULL; | 254 return NULL; |
| 169 } | 255 } |
| 170 } | 256 } |
| 171 | 257 |
| 172 | 258 |
| 259 bool LCodeGen::GenerateJumpTable() { |
| 260 for (int i = 0; i < jump_table_.length(); i++) { |
| 261 __ bind(&jump_table_[i].label); |
| 262 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); |
| 263 } |
| 264 return !is_aborted(); |
| 265 } |
| 266 |
| 267 |
| 173 bool LCodeGen::GenerateDeferredCode() { | 268 bool LCodeGen::GenerateDeferredCode() { |
| 174 ASSERT(is_generating()); | 269 ASSERT(is_generating()); |
| 175 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 270 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 176 LDeferredCode* code = deferred_[i]; | 271 LDeferredCode* code = deferred_[i]; |
| 177 __ bind(code->entry()); | 272 __ bind(code->entry()); |
| 178 code->Generate(); | 273 code->Generate(); |
| 179 __ jmp(code->exit()); | 274 __ jmp(code->exit()); |
| 180 } | 275 } |
| 181 | 276 |
| 182 // Deferred code is the last part of the instruction sequence. Mark | 277 // Deferred code is the last part of the instruction sequence. Mark |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 Handle<Object> value = chunk_->LookupLiteral(op); | 340 Handle<Object> value = chunk_->LookupLiteral(op); |
| 246 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); | 341 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); |
| 247 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == | 342 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == |
| 248 value->Number()); | 343 value->Number()); |
| 249 return static_cast<int32_t>(value->Number()); | 344 return static_cast<int32_t>(value->Number()); |
| 250 } | 345 } |
| 251 | 346 |
| 252 | 347 |
| 253 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { | 348 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { |
| 254 Handle<Object> literal = chunk_->LookupLiteral(op); | 349 Handle<Object> literal = chunk_->LookupLiteral(op); |
| 255 Representation r = chunk_->LookupLiteralRepresentation(op); | 350 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); |
| 256 ASSERT(r.IsTagged()); | |
| 257 return literal; | 351 return literal; |
| 258 } | 352 } |
| 259 | 353 |
| 260 | 354 |
| 261 Operand LCodeGen::ToOperand(LOperand* op) const { | 355 Operand LCodeGen::ToOperand(LOperand* op) const { |
| 262 // Does not handle registers. In X64 assembler, plain registers are not | 356 // Does not handle registers. In X64 assembler, plain registers are not |
| 263 // representable as an Operand. | 357 // representable as an Operand. |
| 264 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); | 358 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); |
| 265 int index = op->index(); | 359 int index = op->index(); |
| 266 if (index >= 0) { | 360 if (index >= 0) { |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); | 530 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); |
| 437 ASSERT(entry != NULL); | 531 ASSERT(entry != NULL); |
| 438 if (entry == NULL) { | 532 if (entry == NULL) { |
| 439 Abort("bailout was not prepared"); | 533 Abort("bailout was not prepared"); |
| 440 return; | 534 return; |
| 441 } | 535 } |
| 442 | 536 |
| 443 if (cc == no_condition) { | 537 if (cc == no_condition) { |
| 444 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 538 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); |
| 445 } else { | 539 } else { |
| 446 NearLabel done; | 540 // We often have several deopts to the same entry, reuse the last |
| 447 __ j(NegateCondition(cc), &done); | 541 // jump entry if this is the case. |
| 448 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); | 542 if (jump_table_.is_empty() || |
| 449 __ bind(&done); | 543 jump_table_.last().address != entry) { |
| 544 jump_table_.Add(entry); |
| 545 } |
| 546 __ j(cc, &jump_table_.last().label); |
| 450 } | 547 } |
| 451 } | 548 } |
| 452 | 549 |
| 453 | 550 |
| 454 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { | 551 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { |
| 455 int length = deoptimizations_.length(); | 552 int length = deoptimizations_.length(); |
| 456 if (length == 0) return; | 553 if (length == 0) return; |
| 457 ASSERT(FLAG_deopt); | 554 ASSERT(FLAG_deopt); |
| 458 Handle<DeoptimizationInputData> data = | 555 Handle<DeoptimizationInputData> data = |
| 459 Factory::NewDeoptimizationInputData(length, TENURED); | 556 Factory::NewDeoptimizationInputData(length, TENURED); |
| 460 | 557 |
| 461 data->SetTranslationByteArray(*translations_.CreateByteArray()); | 558 Handle<ByteArray> translations = translations_.CreateByteArray(); |
| 559 data->SetTranslationByteArray(*translations); |
| 462 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); | 560 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); |
| 463 | 561 |
| 464 Handle<FixedArray> literals = | 562 Handle<FixedArray> literals = |
| 465 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED); | 563 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED); |
| 466 for (int i = 0; i < deoptimization_literals_.length(); i++) { | 564 for (int i = 0; i < deoptimization_literals_.length(); i++) { |
| 467 literals->set(i, *deoptimization_literals_[i]); | 565 literals->set(i, *deoptimization_literals_[i]); |
| 468 } | 566 } |
| 469 data->SetLiteralArray(*literals); | 567 data->SetLiteralArray(*literals); |
| 470 | 568 |
| 471 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); | 569 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 } | 630 } |
| 533 } | 631 } |
| 534 | 632 |
| 535 | 633 |
| 536 void LCodeGen::RecordSafepoint(LPointerMap* pointers, | 634 void LCodeGen::RecordSafepoint(LPointerMap* pointers, |
| 537 int deoptimization_index) { | 635 int deoptimization_index) { |
| 538 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); | 636 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); |
| 539 } | 637 } |
| 540 | 638 |
| 541 | 639 |
| 640 void LCodeGen::RecordSafepoint(int deoptimization_index) { |
| 641 LPointerMap empty_pointers(RelocInfo::kNoPosition); |
| 642 RecordSafepoint(&empty_pointers, deoptimization_index); |
| 643 } |
| 644 |
| 645 |
| 542 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 646 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 543 int arguments, | 647 int arguments, |
| 544 int deoptimization_index) { | 648 int deoptimization_index) { |
| 545 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, | 649 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, |
| 546 deoptimization_index); | 650 deoptimization_index); |
| 547 } | 651 } |
| 548 | 652 |
| 549 | 653 |
| 550 void LCodeGen::RecordPosition(int position) { | 654 void LCodeGen::RecordPosition(int position) { |
| 551 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; | 655 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 case CodeStub::RegExpExec: { | 707 case CodeStub::RegExpExec: { |
| 604 RegExpExecStub stub; | 708 RegExpExecStub stub; |
| 605 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 709 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 606 break; | 710 break; |
| 607 } | 711 } |
| 608 case CodeStub::SubString: { | 712 case CodeStub::SubString: { |
| 609 SubStringStub stub; | 713 SubStringStub stub; |
| 610 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 714 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 611 break; | 715 break; |
| 612 } | 716 } |
| 613 case CodeStub::StringCharAt: { | |
| 614 // TODO(1116): Add StringCharAt stub to x64. | |
| 615 Abort("Unimplemented: %s", "StringCharAt Stub"); | |
| 616 break; | |
| 617 } | |
| 618 case CodeStub::MathPow: { | |
| 619 // TODO(1115): Add MathPow stub to x64. | |
| 620 Abort("Unimplemented: %s", "MathPow Stub"); | |
| 621 break; | |
| 622 } | |
| 623 case CodeStub::NumberToString: { | 717 case CodeStub::NumberToString: { |
| 624 NumberToStringStub stub; | 718 NumberToStringStub stub; |
| 625 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 719 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 626 break; | 720 break; |
| 627 } | 721 } |
| 628 case CodeStub::StringAdd: { | 722 case CodeStub::StringAdd: { |
| 629 StringAddStub stub(NO_STRING_ADD_FLAGS); | 723 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 630 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 724 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 631 break; | 725 break; |
| 632 } | 726 } |
| 633 case CodeStub::StringCompare: { | 727 case CodeStub::StringCompare: { |
| 634 StringCompareStub stub; | 728 StringCompareStub stub; |
| 635 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 729 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 636 break; | 730 break; |
| 637 } | 731 } |
| 638 case CodeStub::TranscendentalCache: { | 732 case CodeStub::TranscendentalCache: { |
| 639 TranscendentalCacheStub stub(instr->transcendental_type()); | 733 TranscendentalCacheStub stub(instr->transcendental_type(), |
| 734 TranscendentalCacheStub::TAGGED); |
| 640 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 735 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 641 break; | 736 break; |
| 642 } | 737 } |
| 643 default: | 738 default: |
| 644 UNREACHABLE(); | 739 UNREACHABLE(); |
| 645 } | 740 } |
| 646 } | 741 } |
| 647 | 742 |
| 648 | 743 |
| 649 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 744 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 650 // Nothing to do. | 745 // Nothing to do. |
| 651 } | 746 } |
| 652 | 747 |
| 653 | 748 |
| 654 void LCodeGen::DoModI(LModI* instr) { | 749 void LCodeGen::DoModI(LModI* instr) { |
| 655 Abort("Unimplemented: %s", "DoModI"); | 750 if (instr->hydrogen()->HasPowerOf2Divisor()) { |
| 751 Register dividend = ToRegister(instr->InputAt(0)); |
| 752 |
| 753 int32_t divisor = |
| 754 HConstant::cast(instr->hydrogen()->right())->Integer32Value(); |
| 755 |
| 756 if (divisor < 0) divisor = -divisor; |
| 757 |
| 758 NearLabel positive_dividend, done; |
| 759 __ testl(dividend, dividend); |
| 760 __ j(not_sign, &positive_dividend); |
| 761 __ negl(dividend); |
| 762 __ andl(dividend, Immediate(divisor - 1)); |
| 763 __ negl(dividend); |
| 764 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 765 __ j(not_zero, &done); |
| 766 DeoptimizeIf(no_condition, instr->environment()); |
| 767 } |
| 768 __ bind(&positive_dividend); |
| 769 __ andl(dividend, Immediate(divisor - 1)); |
| 770 __ bind(&done); |
| 771 } else { |
| 772 LOperand* right = instr->InputAt(1); |
| 773 Register right_reg = ToRegister(right); |
| 774 |
| 775 ASSERT(ToRegister(instr->result()).is(rdx)); |
| 776 ASSERT(ToRegister(instr->InputAt(0)).is(rax)); |
| 777 ASSERT(!right_reg.is(rax)); |
| 778 ASSERT(!right_reg.is(rdx)); |
| 779 |
| 780 // Check for x % 0. |
| 781 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 782 __ testl(right_reg, right_reg); |
| 783 DeoptimizeIf(zero, instr->environment()); |
| 784 } |
| 785 |
| 786 // Sign extend eax to edx. |
| 787 // (We are using only the low 32 bits of the values.) |
| 788 __ cdq(); |
| 789 |
| 790 // Check for (0 % -x) that will produce negative zero. |
| 791 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 792 NearLabel positive_left; |
| 793 NearLabel done; |
| 794 __ testl(rax, rax); |
| 795 __ j(not_sign, &positive_left); |
| 796 __ idivl(right_reg); |
| 797 |
| 798 // Test the remainder for 0, because then the result would be -0. |
| 799 __ testl(rdx, rdx); |
| 800 __ j(not_zero, &done); |
| 801 |
| 802 DeoptimizeIf(no_condition, instr->environment()); |
| 803 __ bind(&positive_left); |
| 804 __ idivl(right_reg); |
| 805 __ bind(&done); |
| 806 } else { |
| 807 __ idivl(right_reg); |
| 808 } |
| 809 } |
| 656 } | 810 } |
| 657 | 811 |
| 658 | 812 |
| 659 void LCodeGen::DoDivI(LDivI* instr) { | 813 void LCodeGen::DoDivI(LDivI* instr) { |
| 660 LOperand* right = instr->InputAt(1); | 814 LOperand* right = instr->InputAt(1); |
| 661 ASSERT(ToRegister(instr->result()).is(rax)); | 815 ASSERT(ToRegister(instr->result()).is(rax)); |
| 662 ASSERT(ToRegister(instr->InputAt(0)).is(rax)); | 816 ASSERT(ToRegister(instr->InputAt(0)).is(rax)); |
| 663 ASSERT(!ToRegister(instr->InputAt(1)).is(rax)); | 817 ASSERT(!ToRegister(instr->InputAt(1)).is(rax)); |
| 664 ASSERT(!ToRegister(instr->InputAt(1)).is(rdx)); | 818 ASSERT(!ToRegister(instr->InputAt(1)).is(rdx)); |
| 665 | 819 |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 914 } | 1068 } |
| 915 | 1069 |
| 916 | 1070 |
| 917 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { | 1071 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { |
| 918 Register result = ToRegister(instr->result()); | 1072 Register result = ToRegister(instr->result()); |
| 919 Register array = ToRegister(instr->InputAt(0)); | 1073 Register array = ToRegister(instr->InputAt(0)); |
| 920 __ movq(result, FieldOperand(array, FixedArray::kLengthOffset)); | 1074 __ movq(result, FieldOperand(array, FixedArray::kLengthOffset)); |
| 921 } | 1075 } |
| 922 | 1076 |
| 923 | 1077 |
| 924 void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) { | 1078 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { |
| 925 Register result = ToRegister(instr->result()); | 1079 Register result = ToRegister(instr->result()); |
| 926 Register array = ToRegister(instr->InputAt(0)); | 1080 Register array = ToRegister(instr->InputAt(0)); |
| 927 __ movq(result, FieldOperand(array, PixelArray::kLengthOffset)); | 1081 __ movl(result, FieldOperand(array, ExternalPixelArray::kLengthOffset)); |
| 928 } | 1082 } |
| 929 | 1083 |
| 930 | 1084 |
| 931 void LCodeGen::DoValueOf(LValueOf* instr) { | 1085 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 932 Abort("Unimplemented: %s", "DoValueOf"); | 1086 Register input = ToRegister(instr->InputAt(0)); |
| 1087 Register result = ToRegister(instr->result()); |
| 1088 ASSERT(input.is(result)); |
| 1089 NearLabel done; |
| 1090 // If the object is a smi return the object. |
| 1091 __ JumpIfSmi(input, &done); |
| 1092 |
| 1093 // If the object is not a value type, return the object. |
| 1094 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); |
| 1095 __ j(not_equal, &done); |
| 1096 __ movq(result, FieldOperand(input, JSValue::kValueOffset)); |
| 1097 |
| 1098 __ bind(&done); |
| 933 } | 1099 } |
| 934 | 1100 |
| 935 | 1101 |
| 936 void LCodeGen::DoBitNotI(LBitNotI* instr) { | 1102 void LCodeGen::DoBitNotI(LBitNotI* instr) { |
| 937 LOperand* input = instr->InputAt(0); | 1103 LOperand* input = instr->InputAt(0); |
| 938 ASSERT(input->Equals(instr->result())); | 1104 ASSERT(input->Equals(instr->result())); |
| 939 __ not_(ToRegister(input)); | 1105 __ not_(ToRegister(input)); |
| 940 } | 1106 } |
| 941 | 1107 |
| 942 | 1108 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 965 __ addl(ToRegister(left), ToOperand(right)); | 1131 __ addl(ToRegister(left), ToOperand(right)); |
| 966 } | 1132 } |
| 967 | 1133 |
| 968 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1134 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 969 DeoptimizeIf(overflow, instr->environment()); | 1135 DeoptimizeIf(overflow, instr->environment()); |
| 970 } | 1136 } |
| 971 } | 1137 } |
| 972 | 1138 |
| 973 | 1139 |
| 974 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { | 1140 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
| 975 LOperand* left = instr->InputAt(0); | 1141 XMMRegister left = ToDoubleRegister(instr->InputAt(0)); |
| 976 LOperand* right = instr->InputAt(1); | 1142 XMMRegister right = ToDoubleRegister(instr->InputAt(1)); |
| 1143 XMMRegister result = ToDoubleRegister(instr->result()); |
| 977 // All operations except MOD are computed in-place. | 1144 // All operations except MOD are computed in-place. |
| 978 ASSERT(instr->op() == Token::MOD || left->Equals(instr->result())); | 1145 ASSERT(instr->op() == Token::MOD || left.is(result)); |
| 979 switch (instr->op()) { | 1146 switch (instr->op()) { |
| 980 case Token::ADD: | 1147 case Token::ADD: |
| 981 __ addsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1148 __ addsd(left, right); |
| 982 break; | 1149 break; |
| 983 case Token::SUB: | 1150 case Token::SUB: |
| 984 __ subsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1151 __ subsd(left, right); |
| 985 break; | 1152 break; |
| 986 case Token::MUL: | 1153 case Token::MUL: |
| 987 __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1154 __ mulsd(left, right); |
| 988 break; | 1155 break; |
| 989 case Token::DIV: | 1156 case Token::DIV: |
| 990 __ divsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1157 __ divsd(left, right); |
| 991 break; | 1158 break; |
| 992 case Token::MOD: | 1159 case Token::MOD: |
| 993 Abort("Unimplemented: %s", "DoArithmeticD MOD"); | 1160 __ PrepareCallCFunction(2); |
| 1161 __ movsd(xmm0, left); |
| 1162 ASSERT(right.is(xmm1)); |
| 1163 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 2); |
| 1164 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1165 __ movsd(result, xmm0); |
| 994 break; | 1166 break; |
| 995 default: | 1167 default: |
| 996 UNREACHABLE(); | 1168 UNREACHABLE(); |
| 997 break; | 1169 break; |
| 998 } | 1170 } |
| 999 } | 1171 } |
| 1000 | 1172 |
| 1001 | 1173 |
| 1002 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { | 1174 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { |
| 1003 ASSERT(ToRegister(instr->InputAt(0)).is(rdx)); | 1175 ASSERT(ToRegister(instr->InputAt(0)).is(rdx)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 } else if (r.IsDouble()) { | 1222 } else if (r.IsDouble()) { |
| 1051 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); | 1223 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); |
| 1052 __ xorpd(xmm0, xmm0); | 1224 __ xorpd(xmm0, xmm0); |
| 1053 __ ucomisd(reg, xmm0); | 1225 __ ucomisd(reg, xmm0); |
| 1054 EmitBranch(true_block, false_block, not_equal); | 1226 EmitBranch(true_block, false_block, not_equal); |
| 1055 } else { | 1227 } else { |
| 1056 ASSERT(r.IsTagged()); | 1228 ASSERT(r.IsTagged()); |
| 1057 Register reg = ToRegister(instr->InputAt(0)); | 1229 Register reg = ToRegister(instr->InputAt(0)); |
| 1058 HType type = instr->hydrogen()->type(); | 1230 HType type = instr->hydrogen()->type(); |
| 1059 if (type.IsBoolean()) { | 1231 if (type.IsBoolean()) { |
| 1060 __ Cmp(reg, Factory::true_value()); | 1232 __ CompareRoot(reg, Heap::kTrueValueRootIndex); |
| 1061 EmitBranch(true_block, false_block, equal); | 1233 EmitBranch(true_block, false_block, equal); |
| 1062 } else if (type.IsSmi()) { | 1234 } else if (type.IsSmi()) { |
| 1063 __ SmiCompare(reg, Smi::FromInt(0)); | 1235 __ SmiCompare(reg, Smi::FromInt(0)); |
| 1064 EmitBranch(true_block, false_block, not_equal); | 1236 EmitBranch(true_block, false_block, not_equal); |
| 1065 } else { | 1237 } else { |
| 1066 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1238 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1067 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1239 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1068 | 1240 |
| 1069 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); | 1241 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); |
| 1070 __ j(equal, false_label); | 1242 __ j(equal, false_label); |
| 1071 __ CompareRoot(reg, Heap::kTrueValueRootIndex); | 1243 __ CompareRoot(reg, Heap::kTrueValueRootIndex); |
| 1072 __ j(equal, true_label); | 1244 __ j(equal, true_label); |
| 1073 __ CompareRoot(reg, Heap::kFalseValueRootIndex); | 1245 __ CompareRoot(reg, Heap::kFalseValueRootIndex); |
| 1074 __ j(equal, false_label); | 1246 __ j(equal, false_label); |
| 1075 __ SmiCompare(reg, Smi::FromInt(0)); | 1247 __ Cmp(reg, Smi::FromInt(0)); |
| 1076 __ j(equal, false_label); | 1248 __ j(equal, false_label); |
| 1077 __ JumpIfSmi(reg, true_label); | 1249 __ JumpIfSmi(reg, true_label); |
| 1078 | 1250 |
| 1079 // Test for double values. Plus/minus zero and NaN are false. | 1251 // Test for double values. Plus/minus zero and NaN are false. |
| 1080 NearLabel call_stub; | 1252 NearLabel call_stub; |
| 1081 __ CompareRoot(FieldOperand(reg, HeapObject::kMapOffset), | 1253 __ CompareRoot(FieldOperand(reg, HeapObject::kMapOffset), |
| 1082 Heap::kHeapNumberMapRootIndex); | 1254 Heap::kHeapNumberMapRootIndex); |
| 1083 __ j(not_equal, &call_stub); | 1255 __ j(not_equal, &call_stub); |
| 1084 | 1256 |
| 1085 // HeapNumber => false iff +0, -0, or NaN. These three cases set the | 1257 // HeapNumber => false iff +0, -0, or NaN. These three cases set the |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1277 return; | 1449 return; |
| 1278 } | 1450 } |
| 1279 | 1451 |
| 1280 __ CompareRoot(reg, Heap::kNullValueRootIndex); | 1452 __ CompareRoot(reg, Heap::kNullValueRootIndex); |
| 1281 if (instr->is_strict()) { | 1453 if (instr->is_strict()) { |
| 1282 __ movl(result, Immediate(Heap::kTrueValueRootIndex)); | 1454 __ movl(result, Immediate(Heap::kTrueValueRootIndex)); |
| 1283 NearLabel load; | 1455 NearLabel load; |
| 1284 __ j(equal, &load); | 1456 __ j(equal, &load); |
| 1285 __ movl(result, Immediate(Heap::kFalseValueRootIndex)); | 1457 __ movl(result, Immediate(Heap::kFalseValueRootIndex)); |
| 1286 __ bind(&load); | 1458 __ bind(&load); |
| 1287 __ movq(result, Operand(kRootRegister, result, times_pointer_size, 0)); | 1459 __ LoadRootIndexed(result, result, 0); |
| 1288 } else { | 1460 } else { |
| 1289 NearLabel true_value, false_value, done; | 1461 NearLabel true_value, false_value, done; |
| 1290 __ j(equal, &true_value); | 1462 __ j(equal, &true_value); |
| 1291 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); | 1463 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); |
| 1292 __ j(equal, &true_value); | 1464 __ j(equal, &true_value); |
| 1293 __ JumpIfSmi(reg, &false_value); | 1465 __ JumpIfSmi(reg, &false_value); |
| 1294 // Check for undetectable objects by looking in the bit field in | 1466 // Check for undetectable objects by looking in the bit field in |
| 1295 // the map. The object has already been smi checked. | 1467 // the map. The object has already been smi checked. |
| 1296 Register scratch = result; | 1468 Register scratch = result; |
| 1297 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 1469 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1317 instr->hydrogen()->type().IsSmi()) { | 1489 instr->hydrogen()->type().IsSmi()) { |
| 1318 // If the expression is known to untagged or smi, then it's definitely | 1490 // If the expression is known to untagged or smi, then it's definitely |
| 1319 // not null, and it can't be a an undetectable object. | 1491 // not null, and it can't be a an undetectable object. |
| 1320 // Jump directly to the false block. | 1492 // Jump directly to the false block. |
| 1321 EmitGoto(false_block); | 1493 EmitGoto(false_block); |
| 1322 return; | 1494 return; |
| 1323 } | 1495 } |
| 1324 | 1496 |
| 1325 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1497 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1326 | 1498 |
| 1327 __ Cmp(reg, Factory::null_value()); | 1499 __ CompareRoot(reg, Heap::kNullValueRootIndex); |
| 1328 if (instr->is_strict()) { | 1500 if (instr->is_strict()) { |
| 1329 EmitBranch(true_block, false_block, equal); | 1501 EmitBranch(true_block, false_block, equal); |
| 1330 } else { | 1502 } else { |
| 1331 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1503 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1332 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1504 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1333 __ j(equal, true_label); | 1505 __ j(equal, true_label); |
| 1334 __ Cmp(reg, Factory::undefined_value()); | 1506 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); |
| 1335 __ j(equal, true_label); | 1507 __ j(equal, true_label); |
| 1336 __ JumpIfSmi(reg, false_label); | 1508 __ JumpIfSmi(reg, false_label); |
| 1337 // Check for undetectable objects by looking in the bit field in | 1509 // Check for undetectable objects by looking in the bit field in |
| 1338 // the map. The object has already been smi checked. | 1510 // the map. The object has already been smi checked. |
| 1339 Register scratch = ToRegister(instr->TempAt(0)); | 1511 Register scratch = ToRegister(instr->TempAt(0)); |
| 1340 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 1512 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
| 1341 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), | 1513 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), |
| 1342 Immediate(1 << Map::kIsUndetectable)); | 1514 Immediate(1 << Map::kIsUndetectable)); |
| 1343 EmitBranch(true_block, false_block, not_zero); | 1515 EmitBranch(true_block, false_block, not_zero); |
| 1344 } | 1516 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 Register result = ToRegister(instr->result()); | 1580 Register result = ToRegister(instr->result()); |
| 1409 if (input_operand->IsRegister()) { | 1581 if (input_operand->IsRegister()) { |
| 1410 Register input = ToRegister(input_operand); | 1582 Register input = ToRegister(input_operand); |
| 1411 __ CheckSmiToIndicator(result, input); | 1583 __ CheckSmiToIndicator(result, input); |
| 1412 } else { | 1584 } else { |
| 1413 Operand input = ToOperand(instr->InputAt(0)); | 1585 Operand input = ToOperand(instr->InputAt(0)); |
| 1414 __ CheckSmiToIndicator(result, input); | 1586 __ CheckSmiToIndicator(result, input); |
| 1415 } | 1587 } |
| 1416 // result is zero if input is a smi, and one otherwise. | 1588 // result is zero if input is a smi, and one otherwise. |
| 1417 ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1); | 1589 ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1); |
| 1418 __ movq(result, Operand(kRootRegister, result, times_pointer_size, | 1590 __ LoadRootIndexed(result, result, Heap::kTrueValueRootIndex); |
| 1419 Heap::kTrueValueRootIndex * kPointerSize)); | |
| 1420 } | 1591 } |
| 1421 | 1592 |
| 1422 | 1593 |
| 1423 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { | 1594 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { |
| 1424 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1595 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1425 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1596 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1426 | 1597 |
| 1427 Condition is_smi; | 1598 Condition is_smi; |
| 1428 if (instr->InputAt(0)->IsRegister()) { | 1599 if (instr->InputAt(0)->IsRegister()) { |
| 1429 Register input = ToRegister(instr->InputAt(0)); | 1600 Register input = ToRegister(instr->InputAt(0)); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1450 InstanceType to = instr->to(); | 1621 InstanceType to = instr->to(); |
| 1451 if (from == to) return equal; | 1622 if (from == to) return equal; |
| 1452 if (to == LAST_TYPE) return above_equal; | 1623 if (to == LAST_TYPE) return above_equal; |
| 1453 if (from == FIRST_TYPE) return below_equal; | 1624 if (from == FIRST_TYPE) return below_equal; |
| 1454 UNREACHABLE(); | 1625 UNREACHABLE(); |
| 1455 return equal; | 1626 return equal; |
| 1456 } | 1627 } |
| 1457 | 1628 |
| 1458 | 1629 |
| 1459 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { | 1630 void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) { |
| 1460 Abort("Unimplemented: %s", "DoHasInstanceType"); | 1631 Register input = ToRegister(instr->InputAt(0)); |
| 1632 Register result = ToRegister(instr->result()); |
| 1633 |
| 1634 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1635 __ testl(input, Immediate(kSmiTagMask)); |
| 1636 NearLabel done, is_false; |
| 1637 __ j(zero, &is_false); |
| 1638 __ CmpObjectType(input, TestType(instr->hydrogen()), result); |
| 1639 __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false); |
| 1640 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 1641 __ jmp(&done); |
| 1642 __ bind(&is_false); |
| 1643 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 1644 __ bind(&done); |
| 1461 } | 1645 } |
| 1462 | 1646 |
| 1463 | 1647 |
| 1464 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { | 1648 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { |
| 1465 Register input = ToRegister(instr->InputAt(0)); | 1649 Register input = ToRegister(instr->InputAt(0)); |
| 1466 | 1650 |
| 1467 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1651 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1468 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1652 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1469 | 1653 |
| 1470 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1654 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1471 | 1655 |
| 1472 __ JumpIfSmi(input, false_label); | 1656 __ JumpIfSmi(input, false_label); |
| 1473 | 1657 |
| 1474 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister); | 1658 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister); |
| 1475 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | 1659 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1476 } | 1660 } |
| 1477 | 1661 |
| 1478 | 1662 |
| 1663 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 1664 Register input = ToRegister(instr->InputAt(0)); |
| 1665 Register result = ToRegister(instr->result()); |
| 1666 |
| 1667 if (FLAG_debug_code) { |
| 1668 __ AbortIfNotString(input); |
| 1669 } |
| 1670 |
| 1671 __ movl(result, FieldOperand(input, String::kHashFieldOffset)); |
| 1672 ASSERT(String::kHashShift >= kSmiTagSize); |
| 1673 __ IndexFromHash(result, result); |
| 1674 } |
| 1675 |
| 1676 |
| 1479 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | 1677 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
| 1480 Abort("Unimplemented: %s", "DoHasCachedArrayIndex"); | 1678 Register input = ToRegister(instr->InputAt(0)); |
| 1679 Register result = ToRegister(instr->result()); |
| 1680 |
| 1681 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1682 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 1683 __ testl(FieldOperand(input, String::kHashFieldOffset), |
| 1684 Immediate(String::kContainsCachedArrayIndexMask)); |
| 1685 NearLabel done; |
| 1686 __ j(zero, &done); |
| 1687 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 1688 __ bind(&done); |
| 1481 } | 1689 } |
| 1482 | 1690 |
| 1483 | 1691 |
| 1484 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1692 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 1485 LHasCachedArrayIndexAndBranch* instr) { | 1693 LHasCachedArrayIndexAndBranch* instr) { |
| 1486 Register input = ToRegister(instr->InputAt(0)); | 1694 Register input = ToRegister(instr->InputAt(0)); |
| 1487 | 1695 |
| 1488 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1696 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1489 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1697 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1490 | 1698 |
| 1491 __ testl(FieldOperand(input, String::kHashFieldOffset), | 1699 __ testl(FieldOperand(input, String::kHashFieldOffset), |
| 1492 Immediate(String::kContainsCachedArrayIndexMask)); | 1700 Immediate(String::kContainsCachedArrayIndexMask)); |
| 1493 EmitBranch(true_block, false_block, not_equal); | 1701 EmitBranch(true_block, false_block, equal); |
| 1494 } | 1702 } |
| 1495 | 1703 |
| 1496 | 1704 |
| 1497 // Branches to a label or falls through with the answer in the z flag. | 1705 // Branches to a label or falls through with the answer in the z flag. |
| 1498 // Trashes the temp register and possibly input (if it and temp are aliased). | 1706 // Trashes the temp register and possibly input (if it and temp are aliased). |
| 1499 void LCodeGen::EmitClassOfTest(Label* is_true, | 1707 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1500 Label* is_false, | 1708 Label* is_false, |
| 1501 Handle<String> class_name, | 1709 Handle<String> class_name, |
| 1502 Register input, | 1710 Register input, |
| 1503 Register temp) { | 1711 Register temp) { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1592 Register reg = ToRegister(instr->InputAt(0)); | 1800 Register reg = ToRegister(instr->InputAt(0)); |
| 1593 int true_block = instr->true_block_id(); | 1801 int true_block = instr->true_block_id(); |
| 1594 int false_block = instr->false_block_id(); | 1802 int false_block = instr->false_block_id(); |
| 1595 | 1803 |
| 1596 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); | 1804 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); |
| 1597 EmitBranch(true_block, false_block, equal); | 1805 EmitBranch(true_block, false_block, equal); |
| 1598 } | 1806 } |
| 1599 | 1807 |
| 1600 | 1808 |
| 1601 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { | 1809 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { |
| 1602 Abort("Unimplemented: %s", "DoInstanceOf"); | 1810 InstanceofStub stub(InstanceofStub::kNoFlags); |
| 1811 __ push(ToRegister(instr->InputAt(0))); |
| 1812 __ push(ToRegister(instr->InputAt(1))); |
| 1813 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1814 NearLabel true_value, done; |
| 1815 __ testq(rax, rax); |
| 1816 __ j(zero, &true_value); |
| 1817 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| 1818 __ jmp(&done); |
| 1819 __ bind(&true_value); |
| 1820 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); |
| 1821 __ bind(&done); |
| 1603 } | 1822 } |
| 1604 | 1823 |
| 1605 | 1824 |
| 1606 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { | 1825 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) { |
| 1607 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1826 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1608 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1827 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1609 | 1828 |
| 1610 InstanceofStub stub(InstanceofStub::kArgsInRegisters); | 1829 InstanceofStub stub(InstanceofStub::kNoFlags); |
| 1830 __ push(ToRegister(instr->InputAt(0))); |
| 1831 __ push(ToRegister(instr->InputAt(1))); |
| 1611 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 1832 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1612 __ testq(rax, rax); | 1833 __ testq(rax, rax); |
| 1613 EmitBranch(true_block, false_block, zero); | 1834 EmitBranch(true_block, false_block, zero); |
| 1614 } | 1835 } |
| 1615 | 1836 |
| 1616 | 1837 |
| 1617 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 1838 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 1618 Abort("Unimplemented: %s", "DoInstanceOfKnowGLobal"); | 1839 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 1840 public: |
| 1841 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 1842 LInstanceOfKnownGlobal* instr) |
| 1843 : LDeferredCode(codegen), instr_(instr) { } |
| 1844 virtual void Generate() { |
| 1845 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
| 1846 } |
| 1847 |
| 1848 Label* map_check() { return &map_check_; } |
| 1849 |
| 1850 private: |
| 1851 LInstanceOfKnownGlobal* instr_; |
| 1852 Label map_check_; |
| 1853 }; |
| 1854 |
| 1855 |
| 1856 DeferredInstanceOfKnownGlobal* deferred; |
| 1857 deferred = new DeferredInstanceOfKnownGlobal(this, instr); |
| 1858 |
| 1859 Label done, false_result; |
| 1860 Register object = ToRegister(instr->InputAt(0)); |
| 1861 |
| 1862 // A Smi is not an instance of anything. |
| 1863 __ JumpIfSmi(object, &false_result); |
| 1864 |
| 1865 // This is the inlined call site instanceof cache. The two occurences of the |
| 1866 // hole value will be patched to the last map/result pair generated by the |
| 1867 // instanceof stub. |
| 1868 NearLabel cache_miss; |
| 1869 // Use a temp register to avoid memory operands with variable lengths. |
| 1870 Register map = ToRegister(instr->TempAt(0)); |
| 1871 __ movq(map, FieldOperand(object, HeapObject::kMapOffset)); |
| 1872 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 1873 __ Move(kScratchRegister, Factory::the_hole_value()); |
| 1874 __ cmpq(map, kScratchRegister); // Patched to cached map. |
| 1875 __ j(not_equal, &cache_miss); |
| 1876 // Patched to load either true or false. |
| 1877 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); |
| 1878 #ifdef DEBUG |
| 1879 // Check that the code size between patch label and patch sites is invariant. |
| 1880 Label end_of_patched_code; |
| 1881 __ bind(&end_of_patched_code); |
| 1882 ASSERT(true); |
| 1883 #endif |
| 1884 __ jmp(&done); |
| 1885 |
| 1886 // The inlined call site cache did not match. Check for null and string |
| 1887 // before calling the deferred code. |
| 1888 __ bind(&cache_miss); // Null is not an instance of anything. |
| 1889 __ CompareRoot(object, Heap::kNullValueRootIndex); |
| 1890 __ j(equal, &false_result); |
| 1891 |
| 1892 // String values are not instances of anything. |
| 1893 __ JumpIfNotString(object, kScratchRegister, deferred->entry()); |
| 1894 |
| 1895 __ bind(&false_result); |
| 1896 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); |
| 1897 |
| 1898 __ bind(deferred->exit()); |
| 1899 __ bind(&done); |
| 1619 } | 1900 } |
| 1620 | 1901 |
| 1621 | 1902 |
| 1622 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, | 1903 void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, |
| 1623 Label* map_check) { | 1904 Label* map_check) { |
| 1624 Abort("Unimplemented: %s", "DoDeferredLInstanceOfKnownGlobakl"); | 1905 __ PushSafepointRegisters(); |
| 1906 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>( |
| 1907 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck); |
| 1908 InstanceofStub stub(flags); |
| 1909 |
| 1910 __ push(ToRegister(instr->InputAt(0))); |
| 1911 __ Push(instr->function()); |
| 1912 Register temp = ToRegister(instr->TempAt(0)); |
| 1913 ASSERT(temp.is(rdi)); |
| 1914 static const int kAdditionalDelta = 16; |
| 1915 int delta = |
| 1916 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; |
| 1917 __ movq(temp, Immediate(delta)); |
| 1918 __ push(temp); |
| 1919 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1920 __ movq(kScratchRegister, rax); |
| 1921 __ PopSafepointRegisters(); |
| 1922 __ testq(kScratchRegister, kScratchRegister); |
| 1923 Label load_false; |
| 1924 Label done; |
| 1925 __ j(not_zero, &load_false); |
| 1926 __ LoadRoot(rax, Heap::kTrueValueRootIndex); |
| 1927 __ jmp(&done); |
| 1928 __ bind(&load_false); |
| 1929 __ LoadRoot(rax, Heap::kFalseValueRootIndex); |
| 1930 __ bind(&done); |
| 1625 } | 1931 } |
| 1626 | 1932 |
| 1627 | 1933 |
| 1628 void LCodeGen::DoCmpT(LCmpT* instr) { | 1934 void LCodeGen::DoCmpT(LCmpT* instr) { |
| 1629 Token::Value op = instr->op(); | 1935 Token::Value op = instr->op(); |
| 1630 | 1936 |
| 1631 Handle<Code> ic = CompareIC::GetUninitialized(op); | 1937 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 1632 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 1938 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 1633 | 1939 |
| 1634 Condition condition = TokenToCondition(op, false); | 1940 Condition condition = TokenToCondition(op, false); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1711 __ movq(temp, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); | 2017 __ movq(temp, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); |
| 1712 if (check_hole) { | 2018 if (check_hole) { |
| 1713 __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex); | 2019 __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex); |
| 1714 DeoptimizeIf(equal, instr->environment()); | 2020 DeoptimizeIf(equal, instr->environment()); |
| 1715 } | 2021 } |
| 1716 __ movq(Operand(temp, 0), value); | 2022 __ movq(Operand(temp, 0), value); |
| 1717 } | 2023 } |
| 1718 | 2024 |
| 1719 | 2025 |
| 1720 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2026 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 1721 Abort("Unimplemented: %s", "DoLoadContextSlot"); | 2027 Register context = ToRegister(instr->context()); |
| 2028 Register result = ToRegister(instr->result()); |
| 2029 __ movq(result, ContextOperand(context, instr->slot_index())); |
| 2030 } |
| 2031 |
| 2032 |
| 2033 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2034 Register context = ToRegister(instr->context()); |
| 2035 Register value = ToRegister(instr->value()); |
| 2036 __ movq(ContextOperand(context, instr->slot_index()), value); |
| 2037 if (instr->needs_write_barrier()) { |
| 2038 int offset = Context::SlotOffset(instr->slot_index()); |
| 2039 Register scratch = ToRegister(instr->TempAt(0)); |
| 2040 __ RecordWrite(context, offset, value, scratch); |
| 2041 } |
| 1722 } | 2042 } |
| 1723 | 2043 |
| 1724 | 2044 |
| 1725 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2045 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 1726 Register object = ToRegister(instr->InputAt(0)); | 2046 Register object = ToRegister(instr->InputAt(0)); |
| 1727 Register result = ToRegister(instr->result()); | 2047 Register result = ToRegister(instr->result()); |
| 1728 if (instr->hydrogen()->is_in_object()) { | 2048 if (instr->hydrogen()->is_in_object()) { |
| 1729 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); | 2049 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); |
| 1730 } else { | 2050 } else { |
| 1731 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); | 2051 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1784 __ bind(&done); | 2104 __ bind(&done); |
| 1785 } | 2105 } |
| 1786 | 2106 |
| 1787 | 2107 |
| 1788 void LCodeGen::DoLoadElements(LLoadElements* instr) { | 2108 void LCodeGen::DoLoadElements(LLoadElements* instr) { |
| 1789 Register result = ToRegister(instr->result()); | 2109 Register result = ToRegister(instr->result()); |
| 1790 Register input = ToRegister(instr->InputAt(0)); | 2110 Register input = ToRegister(instr->InputAt(0)); |
| 1791 __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); | 2111 __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); |
| 1792 if (FLAG_debug_code) { | 2112 if (FLAG_debug_code) { |
| 1793 NearLabel done; | 2113 NearLabel done; |
| 1794 __ Cmp(FieldOperand(result, HeapObject::kMapOffset), | 2114 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), |
| 1795 Factory::fixed_array_map()); | 2115 Heap::kFixedArrayMapRootIndex); |
| 1796 __ j(equal, &done); | 2116 __ j(equal, &done); |
| 1797 __ Cmp(FieldOperand(result, HeapObject::kMapOffset), | 2117 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), |
| 1798 Factory::pixel_array_map()); | 2118 Heap::kExternalPixelArrayMapRootIndex); |
| 1799 __ j(equal, &done); | 2119 __ j(equal, &done); |
| 1800 __ Cmp(FieldOperand(result, HeapObject::kMapOffset), | 2120 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), |
| 1801 Factory::fixed_cow_array_map()); | 2121 Heap::kFixedCOWArrayMapRootIndex); |
| 1802 __ Check(equal, "Check for fast elements failed."); | 2122 __ Check(equal, "Check for fast elements failed."); |
| 1803 __ bind(&done); | 2123 __ bind(&done); |
| 1804 } | 2124 } |
| 1805 } | 2125 } |
| 1806 | 2126 |
| 1807 | 2127 |
| 1808 void LCodeGen::DoLoadPixelArrayExternalPointer( | 2128 void LCodeGen::DoLoadExternalArrayPointer( |
| 1809 LLoadPixelArrayExternalPointer* instr) { | 2129 LLoadExternalArrayPointer* instr) { |
| 1810 Register result = ToRegister(instr->result()); | 2130 Register result = ToRegister(instr->result()); |
| 1811 Register input = ToRegister(instr->InputAt(0)); | 2131 Register input = ToRegister(instr->InputAt(0)); |
| 1812 __ movq(result, FieldOperand(input, PixelArray::kExternalPointerOffset)); | 2132 __ movq(result, FieldOperand(input, |
| 2133 ExternalPixelArray::kExternalPointerOffset)); |
| 1813 } | 2134 } |
| 1814 | 2135 |
| 1815 | 2136 |
| 1816 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { | 2137 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
| 1817 Register arguments = ToRegister(instr->arguments()); | 2138 Register arguments = ToRegister(instr->arguments()); |
| 1818 Register length = ToRegister(instr->length()); | 2139 Register length = ToRegister(instr->length()); |
| 1819 Register result = ToRegister(instr->result()); | 2140 Register result = ToRegister(instr->result()); |
| 1820 | 2141 |
| 1821 if (instr->index()->IsRegister()) { | 2142 if (instr->index()->IsRegister()) { |
| 1822 __ subl(length, ToRegister(instr->index())); | 2143 __ subl(length, ToRegister(instr->index())); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1837 Register result = ToRegister(instr->result()); | 2158 Register result = ToRegister(instr->result()); |
| 1838 ASSERT(result.is(elements)); | 2159 ASSERT(result.is(elements)); |
| 1839 | 2160 |
| 1840 // Load the result. | 2161 // Load the result. |
| 1841 __ movq(result, FieldOperand(elements, | 2162 __ movq(result, FieldOperand(elements, |
| 1842 key, | 2163 key, |
| 1843 times_pointer_size, | 2164 times_pointer_size, |
| 1844 FixedArray::kHeaderSize)); | 2165 FixedArray::kHeaderSize)); |
| 1845 | 2166 |
| 1846 // Check for the hole value. | 2167 // Check for the hole value. |
| 1847 __ Cmp(result, Factory::the_hole_value()); | 2168 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 1848 DeoptimizeIf(equal, instr->environment()); | 2169 DeoptimizeIf(equal, instr->environment()); |
| 1849 } | 2170 } |
| 1850 | 2171 |
| 1851 | 2172 |
| 1852 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { | 2173 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { |
| 1853 Register external_elements = ToRegister(instr->external_pointer()); | 2174 Register external_elements = ToRegister(instr->external_pointer()); |
| 1854 Register key = ToRegister(instr->key()); | 2175 Register key = ToRegister(instr->key()); |
| 1855 Register result = ToRegister(instr->result()); | 2176 Register result = ToRegister(instr->result()); |
| 1856 ASSERT(result.is(external_elements)); | 2177 ASSERT(result.is(external_elements)); |
| 1857 | 2178 |
| 1858 // Load the result. | 2179 // Load the result. |
| 1859 __ movzxbq(result, Operand(external_elements, key, times_1, 0)); | 2180 __ movzxbq(result, Operand(external_elements, key, times_1, 0)); |
| 1860 } | 2181 } |
| 1861 | 2182 |
| 1862 | 2183 |
| 1863 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { | 2184 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { |
| 1864 Abort("Unimplemented: %s", "DoLoadKeyedGeneric"); | 2185 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 2186 ASSERT(ToRegister(instr->key()).is(rax)); |
| 2187 |
| 2188 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 2189 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 1865 } | 2190 } |
| 1866 | 2191 |
| 1867 | 2192 |
| 1868 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { | 2193 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { |
| 1869 Register result = ToRegister(instr->result()); | 2194 Register result = ToRegister(instr->result()); |
| 1870 | 2195 |
| 1871 // Check for arguments adapter frame. | 2196 // Check for arguments adapter frame. |
| 1872 NearLabel done, adapted; | 2197 NearLabel done, adapted; |
| 1873 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2198 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1874 __ SmiCompare(Operand(result, StandardFrameConstants::kContextOffset), | 2199 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset), |
| 1875 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2200 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1876 __ j(equal, &adapted); | 2201 __ j(equal, &adapted); |
| 1877 | 2202 |
| 1878 // No arguments adaptor frame. | 2203 // No arguments adaptor frame. |
| 1879 __ movq(result, rbp); | 2204 __ movq(result, rbp); |
| 1880 __ jmp(&done); | 2205 __ jmp(&done); |
| 1881 | 2206 |
| 1882 // Arguments adaptor frame present. | 2207 // Arguments adaptor frame present. |
| 1883 __ bind(&adapted); | 2208 __ bind(&adapted); |
| 1884 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2209 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1885 | 2210 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1908 __ movq(result, Operand(result, | 2233 __ movq(result, Operand(result, |
| 1909 ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2234 ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 1910 __ SmiToInteger32(result, result); | 2235 __ SmiToInteger32(result, result); |
| 1911 | 2236 |
| 1912 // Argument length is in result register. | 2237 // Argument length is in result register. |
| 1913 __ bind(&done); | 2238 __ bind(&done); |
| 1914 } | 2239 } |
| 1915 | 2240 |
| 1916 | 2241 |
| 1917 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 2242 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
| 1918 Abort("Unimplemented: %s", "DoApplyArguments"); | 2243 Register receiver = ToRegister(instr->receiver()); |
| 2244 Register function = ToRegister(instr->function()); |
| 2245 Register length = ToRegister(instr->length()); |
| 2246 Register elements = ToRegister(instr->elements()); |
| 2247 ASSERT(receiver.is(rax)); // Used for parameter count. |
| 2248 ASSERT(function.is(rdi)); // Required by InvokeFunction. |
| 2249 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2250 |
| 2251 // If the receiver is null or undefined, we have to pass the global object |
| 2252 // as a receiver. |
| 2253 NearLabel global_object, receiver_ok; |
| 2254 __ CompareRoot(receiver, Heap::kNullValueRootIndex); |
| 2255 __ j(equal, &global_object); |
| 2256 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); |
| 2257 __ j(equal, &global_object); |
| 2258 |
| 2259 // The receiver should be a JS object. |
| 2260 Condition is_smi = __ CheckSmi(receiver); |
| 2261 DeoptimizeIf(is_smi, instr->environment()); |
| 2262 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, kScratchRegister); |
| 2263 DeoptimizeIf(below, instr->environment()); |
| 2264 __ jmp(&receiver_ok); |
| 2265 |
| 2266 __ bind(&global_object); |
| 2267 // TODO(kmillikin): We have a hydrogen value for the global object. See |
| 2268 // if it's better to use it than to explicitly fetch it from the context |
| 2269 // here. |
| 2270 __ movq(receiver, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2271 __ movq(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX)); |
| 2272 __ bind(&receiver_ok); |
| 2273 |
| 2274 // Copy the arguments to this function possibly from the |
| 2275 // adaptor frame below it. |
| 2276 const uint32_t kArgumentsLimit = 1 * KB; |
| 2277 __ cmpq(length, Immediate(kArgumentsLimit)); |
| 2278 DeoptimizeIf(above, instr->environment()); |
| 2279 |
| 2280 __ push(receiver); |
| 2281 __ movq(receiver, length); |
| 2282 |
| 2283 // Loop through the arguments pushing them onto the execution |
| 2284 // stack. |
| 2285 NearLabel invoke, loop; |
| 2286 // length is a small non-negative integer, due to the test above. |
| 2287 __ testl(length, length); |
| 2288 __ j(zero, &invoke); |
| 2289 __ bind(&loop); |
| 2290 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); |
| 2291 __ decl(length); |
| 2292 __ j(not_zero, &loop); |
| 2293 |
| 2294 // Invoke the function. |
| 2295 __ bind(&invoke); |
| 2296 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 2297 LPointerMap* pointers = instr->pointer_map(); |
| 2298 LEnvironment* env = instr->deoptimization_environment(); |
| 2299 RecordPosition(pointers->position()); |
| 2300 RegisterEnvironmentForDeoptimization(env); |
| 2301 SafepointGenerator safepoint_generator(this, |
| 2302 pointers, |
| 2303 env->deoptimization_index(), |
| 2304 true); |
| 2305 v8::internal::ParameterCount actual(rax); |
| 2306 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator); |
| 1919 } | 2307 } |
| 1920 | 2308 |
| 1921 | 2309 |
| 1922 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 2310 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
| 1923 LOperand* argument = instr->InputAt(0); | 2311 LOperand* argument = instr->InputAt(0); |
| 1924 if (argument->IsConstantOperand()) { | 2312 if (argument->IsConstantOperand()) { |
| 1925 LConstantOperand* const_op = LConstantOperand::cast(argument); | 2313 EmitPushConstantOperand(argument); |
| 1926 Handle<Object> literal = chunk_->LookupLiteral(const_op); | |
| 1927 Representation r = chunk_->LookupLiteralRepresentation(const_op); | |
| 1928 if (r.IsInteger32()) { | |
| 1929 ASSERT(literal->IsNumber()); | |
| 1930 __ push(Immediate(static_cast<int32_t>(literal->Number()))); | |
| 1931 } else if (r.IsDouble()) { | |
| 1932 Abort("unsupported double immediate"); | |
| 1933 } else { | |
| 1934 ASSERT(r.IsTagged()); | |
| 1935 __ Push(literal); | |
| 1936 } | |
| 1937 } else if (argument->IsRegister()) { | 2314 } else if (argument->IsRegister()) { |
| 1938 __ push(ToRegister(argument)); | 2315 __ push(ToRegister(argument)); |
| 1939 } else { | 2316 } else { |
| 1940 ASSERT(!argument->IsDoubleRegister()); | 2317 ASSERT(!argument->IsDoubleRegister()); |
| 1941 __ push(ToOperand(argument)); | 2318 __ push(ToOperand(argument)); |
| 1942 } | 2319 } |
| 1943 } | 2320 } |
| 1944 | 2321 |
| 1945 | 2322 |
| 1946 void LCodeGen::DoContext(LContext* instr) { | 2323 void LCodeGen::DoContext(LContext* instr) { |
| 1947 Register result = ToRegister(instr->result()); | 2324 Register result = ToRegister(instr->result()); |
| 1948 __ movq(result, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2325 __ movq(result, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1949 } | 2326 } |
| 1950 | 2327 |
| 1951 | 2328 |
| 2329 void LCodeGen::DoOuterContext(LOuterContext* instr) { |
| 2330 Register context = ToRegister(instr->context()); |
| 2331 Register result = ToRegister(instr->result()); |
| 2332 __ movq(result, |
| 2333 Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 2334 __ movq(result, FieldOperand(result, JSFunction::kContextOffset)); |
| 2335 } |
| 2336 |
| 2337 |
| 1952 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { | 2338 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { |
| 1953 Register result = ToRegister(instr->result()); | 2339 Register result = ToRegister(instr->result()); |
| 1954 __ movq(result, GlobalObjectOperand()); | 2340 __ movq(result, GlobalObjectOperand()); |
| 1955 } | 2341 } |
| 1956 | 2342 |
| 1957 | 2343 |
| 1958 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { | 2344 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { |
| 1959 Register result = ToRegister(instr->result()); | 2345 Register result = ToRegister(instr->result()); |
| 1960 __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 2346 __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 1961 __ movq(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset)); | 2347 __ movq(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset)); |
| 1962 } | 2348 } |
| 1963 | 2349 |
| 1964 | 2350 |
| 1965 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 2351 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
| 1966 int arity, | 2352 int arity, |
| 1967 LInstruction* instr) { | 2353 LInstruction* instr) { |
| 1968 // Change context if needed. | 2354 // Change context if needed. |
| 1969 bool change_context = | 2355 bool change_context = |
| 1970 (graph()->info()->closure()->context() != function->context()) || | 2356 (info()->closure()->context() != function->context()) || |
| 1971 scope()->contains_with() || | 2357 scope()->contains_with() || |
| 1972 (scope()->num_heap_slots() > 0); | 2358 (scope()->num_heap_slots() > 0); |
| 1973 if (change_context) { | 2359 if (change_context) { |
| 1974 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 2360 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 1975 } | 2361 } |
| 1976 | 2362 |
| 1977 // Set rax to arguments count if adaption is not needed. Assumes that rax | 2363 // Set rax to arguments count if adaption is not needed. Assumes that rax |
| 1978 // is available to write to at this point. | 2364 // is available to write to at this point. |
| 1979 if (!function->NeedsArgumentsAdaption()) { | 2365 if (!function->NeedsArgumentsAdaption()) { |
| 1980 __ Set(rax, arity); | 2366 __ Set(rax, arity); |
| 1981 } | 2367 } |
| 1982 | 2368 |
| 1983 LPointerMap* pointers = instr->pointer_map(); | 2369 LPointerMap* pointers = instr->pointer_map(); |
| 1984 RecordPosition(pointers->position()); | 2370 RecordPosition(pointers->position()); |
| 1985 | 2371 |
| 1986 // Invoke function. | 2372 // Invoke function. |
| 1987 if (*function == *graph()->info()->closure()) { | 2373 if (*function == *info()->closure()) { |
| 1988 __ CallSelf(); | 2374 __ CallSelf(); |
| 1989 } else { | 2375 } else { |
| 1990 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); | 2376 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 1991 } | 2377 } |
| 1992 | 2378 |
| 1993 // Setup deoptimization. | 2379 // Setup deoptimization. |
| 1994 RegisterLazyDeoptimization(instr); | 2380 RegisterLazyDeoptimization(instr); |
| 1995 | 2381 |
| 1996 // Restore context. | 2382 // Restore context. |
| 1997 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2383 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1998 } | 2384 } |
| 1999 | 2385 |
| 2000 | 2386 |
| 2001 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { | 2387 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { |
| 2002 ASSERT(ToRegister(instr->result()).is(rax)); | 2388 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2003 __ Move(rdi, instr->function()); | 2389 __ Move(rdi, instr->function()); |
| 2004 CallKnownFunction(instr->function(), instr->arity(), instr); | 2390 CallKnownFunction(instr->function(), instr->arity(), instr); |
| 2005 } | 2391 } |
| 2006 | 2392 |
| 2007 | 2393 |
| 2008 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { | 2394 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { |
| 2009 Abort("Unimplemented: %s", "DoDeferredMathAbsTaggedHeapNumber"); | 2395 Register input_reg = ToRegister(instr->InputAt(0)); |
| 2396 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 2397 Heap::kHeapNumberMapRootIndex); |
| 2398 DeoptimizeIf(not_equal, instr->environment()); |
| 2399 |
| 2400 Label done; |
| 2401 Register tmp = input_reg.is(rax) ? rcx : rax; |
| 2402 Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx; |
| 2403 |
| 2404 // Preserve the value of all registers. |
| 2405 __ PushSafepointRegisters(); |
| 2406 |
| 2407 Label negative; |
| 2408 __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |
| 2409 // Check the sign of the argument. If the argument is positive, just |
| 2410 // return it. We do not need to patch the stack since |input| and |
| 2411 // |result| are the same register and |input| will be restored |
| 2412 // unchanged by popping safepoint registers. |
| 2413 __ testl(tmp, Immediate(HeapNumber::kSignMask)); |
| 2414 __ j(not_zero, &negative); |
| 2415 __ jmp(&done); |
| 2416 |
| 2417 __ bind(&negative); |
| 2418 |
| 2419 Label allocated, slow; |
| 2420 __ AllocateHeapNumber(tmp, tmp2, &slow); |
| 2421 __ jmp(&allocated); |
| 2422 |
| 2423 // Slow case: Call the runtime system to do the number allocation. |
| 2424 __ bind(&slow); |
| 2425 |
| 2426 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 2427 RecordSafepointWithRegisters( |
| 2428 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2429 // Set the pointer to the new heap number in tmp. |
| 2430 if (!tmp.is(rax)) { |
| 2431 __ movq(tmp, rax); |
| 2432 } |
| 2433 |
| 2434 // Restore input_reg after call to runtime. |
| 2435 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); |
| 2436 |
| 2437 __ bind(&allocated); |
| 2438 __ movq(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 2439 __ shl(tmp2, Immediate(1)); |
| 2440 __ shr(tmp2, Immediate(1)); |
| 2441 __ movq(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2); |
| 2442 __ StoreToSafepointRegisterSlot(input_reg, tmp); |
| 2443 |
| 2444 __ bind(&done); |
| 2445 __ PopSafepointRegisters(); |
| 2446 } |
| 2447 |
| 2448 |
| 2449 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { |
| 2450 Register input_reg = ToRegister(instr->InputAt(0)); |
| 2451 __ testl(input_reg, input_reg); |
| 2452 Label is_positive; |
| 2453 __ j(not_sign, &is_positive); |
| 2454 __ negl(input_reg); // Sets flags. |
| 2455 DeoptimizeIf(negative, instr->environment()); |
| 2456 __ bind(&is_positive); |
| 2010 } | 2457 } |
| 2011 | 2458 |
| 2012 | 2459 |
| 2013 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { | 2460 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| 2014 Abort("Unimplemented: %s", "DoMathAbs"); | 2461 // Class for deferred case. |
| 2462 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| 2463 public: |
| 2464 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, |
| 2465 LUnaryMathOperation* instr) |
| 2466 : LDeferredCode(codegen), instr_(instr) { } |
| 2467 virtual void Generate() { |
| 2468 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); |
| 2469 } |
| 2470 private: |
| 2471 LUnaryMathOperation* instr_; |
| 2472 }; |
| 2473 |
| 2474 ASSERT(instr->InputAt(0)->Equals(instr->result())); |
| 2475 Representation r = instr->hydrogen()->value()->representation(); |
| 2476 |
| 2477 if (r.IsDouble()) { |
| 2478 XMMRegister scratch = xmm0; |
| 2479 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2480 __ xorpd(scratch, scratch); |
| 2481 __ subsd(scratch, input_reg); |
| 2482 __ andpd(input_reg, scratch); |
| 2483 } else if (r.IsInteger32()) { |
| 2484 EmitIntegerMathAbs(instr); |
| 2485 } else { // Tagged case. |
| 2486 DeferredMathAbsTaggedHeapNumber* deferred = |
| 2487 new DeferredMathAbsTaggedHeapNumber(this, instr); |
| 2488 Register input_reg = ToRegister(instr->InputAt(0)); |
| 2489 // Smi check. |
| 2490 __ JumpIfNotSmi(input_reg, deferred->entry()); |
| 2491 EmitIntegerMathAbs(instr); |
| 2492 __ bind(deferred->exit()); |
| 2493 } |
| 2015 } | 2494 } |
| 2016 | 2495 |
| 2017 | 2496 |
| 2018 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { | 2497 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
| 2019 Abort("Unimplemented: %s", "DoMathFloor"); | 2498 XMMRegister xmm_scratch = xmm0; |
| 2499 Register output_reg = ToRegister(instr->result()); |
| 2500 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2501 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register. |
| 2502 __ ucomisd(input_reg, xmm_scratch); |
| 2503 |
| 2504 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 2505 DeoptimizeIf(below_equal, instr->environment()); |
| 2506 } else { |
| 2507 DeoptimizeIf(below, instr->environment()); |
| 2508 } |
| 2509 |
| 2510 // Use truncating instruction (OK because input is positive). |
| 2511 __ cvttsd2si(output_reg, input_reg); |
| 2512 |
| 2513 // Overflow is signalled with minint. |
| 2514 __ cmpl(output_reg, Immediate(0x80000000)); |
| 2515 DeoptimizeIf(equal, instr->environment()); |
| 2020 } | 2516 } |
| 2021 | 2517 |
| 2022 | 2518 |
| 2023 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { | 2519 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
| 2024 Abort("Unimplemented: %s", "DoMathRound"); | 2520 const XMMRegister xmm_scratch = xmm0; |
| 2521 Register output_reg = ToRegister(instr->result()); |
| 2522 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2523 |
| 2524 // xmm_scratch = 0.5 |
| 2525 __ movq(kScratchRegister, V8_INT64_C(0x3FE0000000000000), RelocInfo::NONE); |
| 2526 __ movq(xmm_scratch, kScratchRegister); |
| 2527 |
| 2528 // input = input + 0.5 |
| 2529 __ addsd(input_reg, xmm_scratch); |
| 2530 |
| 2531 // We need to return -0 for the input range [-0.5, 0[, otherwise |
| 2532 // compute Math.floor(value + 0.5). |
| 2533 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 2534 __ ucomisd(input_reg, xmm_scratch); |
| 2535 DeoptimizeIf(below_equal, instr->environment()); |
| 2536 } else { |
| 2537 // If we don't need to bailout on -0, we check only bailout |
| 2538 // on negative inputs. |
| 2539 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register. |
| 2540 __ ucomisd(input_reg, xmm_scratch); |
| 2541 DeoptimizeIf(below, instr->environment()); |
| 2542 } |
| 2543 |
| 2544 // Compute Math.floor(value + 0.5). |
| 2545 // Use truncating instruction (OK because input is positive). |
| 2546 __ cvttsd2si(output_reg, input_reg); |
| 2547 |
| 2548 // Overflow is signalled with minint. |
| 2549 __ cmpl(output_reg, Immediate(0x80000000)); |
| 2550 DeoptimizeIf(equal, instr->environment()); |
| 2025 } | 2551 } |
| 2026 | 2552 |
| 2027 | 2553 |
| 2028 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { | 2554 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
| 2029 Abort("Unimplemented: %s", "DoMathSqrt"); | 2555 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2556 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
| 2557 __ sqrtsd(input_reg, input_reg); |
| 2030 } | 2558 } |
| 2031 | 2559 |
| 2032 | 2560 |
| 2033 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { | 2561 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { |
| 2034 Abort("Unimplemented: %s", "DoMathPowHalf"); | 2562 XMMRegister xmm_scratch = xmm0; |
| 2563 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2564 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
| 2565 __ xorpd(xmm_scratch, xmm_scratch); |
| 2566 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. |
| 2567 __ sqrtsd(input_reg, input_reg); |
| 2035 } | 2568 } |
| 2036 | 2569 |
| 2037 | 2570 |
| 2038 void LCodeGen::DoPower(LPower* instr) { | 2571 void LCodeGen::DoPower(LPower* instr) { |
| 2039 Abort("Unimplemented: %s", "DoPower"); | 2572 LOperand* left = instr->InputAt(0); |
| 2573 XMMRegister left_reg = ToDoubleRegister(left); |
| 2574 ASSERT(!left_reg.is(xmm1)); |
| 2575 LOperand* right = instr->InputAt(1); |
| 2576 XMMRegister result_reg = ToDoubleRegister(instr->result()); |
| 2577 Representation exponent_type = instr->hydrogen()->right()->representation(); |
| 2578 if (exponent_type.IsDouble()) { |
| 2579 __ PrepareCallCFunction(2); |
| 2580 // Move arguments to correct registers |
| 2581 __ movsd(xmm0, left_reg); |
| 2582 ASSERT(ToDoubleRegister(right).is(xmm1)); |
| 2583 __ CallCFunction(ExternalReference::power_double_double_function(), 2); |
| 2584 } else if (exponent_type.IsInteger32()) { |
| 2585 __ PrepareCallCFunction(2); |
| 2586 // Move arguments to correct registers: xmm0 and edi (not rdi). |
| 2587 // On Windows, the registers are xmm0 and edx. |
| 2588 __ movsd(xmm0, left_reg); |
| 2589 #ifdef _WIN64 |
| 2590 ASSERT(ToRegister(right).is(rdx)); |
| 2591 #else |
| 2592 ASSERT(ToRegister(right).is(rdi)); |
| 2593 #endif |
| 2594 __ CallCFunction(ExternalReference::power_double_int_function(), 2); |
| 2595 } else { |
| 2596 ASSERT(exponent_type.IsTagged()); |
| 2597 CpuFeatures::Scope scope(SSE2); |
| 2598 Register right_reg = ToRegister(right); |
| 2599 |
| 2600 Label non_smi, call; |
| 2601 __ JumpIfNotSmi(right_reg, &non_smi); |
| 2602 __ SmiToInteger32(right_reg, right_reg); |
| 2603 __ cvtlsi2sd(xmm1, right_reg); |
| 2604 __ jmp(&call); |
| 2605 |
| 2606 __ bind(&non_smi); |
| 2607 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , kScratchRegister); |
| 2608 DeoptimizeIf(not_equal, instr->environment()); |
| 2609 __ movsd(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset)); |
| 2610 |
| 2611 __ bind(&call); |
| 2612 __ PrepareCallCFunction(2); |
| 2613 // Move arguments to correct registers xmm0 and xmm1. |
| 2614 __ movsd(xmm0, left_reg); |
| 2615 // Right argument is already in xmm1. |
| 2616 __ CallCFunction(ExternalReference::power_double_double_function(), 2); |
| 2617 } |
| 2618 // Return value is in xmm0. |
| 2619 __ movsd(result_reg, xmm0); |
| 2620 // Restore context register. |
| 2621 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2040 } | 2622 } |
| 2041 | 2623 |
| 2042 | 2624 |
| 2043 void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { | 2625 void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { |
| 2044 Abort("Unimplemented: %s", "DoMathLog"); | 2626 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
| 2627 TranscendentalCacheStub stub(TranscendentalCache::LOG, |
| 2628 TranscendentalCacheStub::UNTAGGED); |
| 2629 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2045 } | 2630 } |
| 2046 | 2631 |
| 2047 | 2632 |
| 2048 void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { | 2633 void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { |
| 2049 Abort("Unimplemented: %s", "DoMathCos"); | 2634 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
| 2635 TranscendentalCacheStub stub(TranscendentalCache::COS, |
| 2636 TranscendentalCacheStub::UNTAGGED); |
| 2637 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2050 } | 2638 } |
| 2051 | 2639 |
| 2052 | 2640 |
| 2053 void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { | 2641 void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { |
| 2054 Abort("Unimplemented: %s", "DoMathSin"); | 2642 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); |
| 2643 TranscendentalCacheStub stub(TranscendentalCache::SIN, |
| 2644 TranscendentalCacheStub::UNTAGGED); |
| 2645 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2055 } | 2646 } |
| 2056 | 2647 |
| 2057 | 2648 |
| 2058 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { | 2649 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { |
| 2059 Abort("Unimplemented: %s", "DoUnaryMathOperation"); | 2650 switch (instr->op()) { |
| 2651 case kMathAbs: |
| 2652 DoMathAbs(instr); |
| 2653 break; |
| 2654 case kMathFloor: |
| 2655 DoMathFloor(instr); |
| 2656 break; |
| 2657 case kMathRound: |
| 2658 DoMathRound(instr); |
| 2659 break; |
| 2660 case kMathSqrt: |
| 2661 DoMathSqrt(instr); |
| 2662 break; |
| 2663 case kMathPowHalf: |
| 2664 DoMathPowHalf(instr); |
| 2665 break; |
| 2666 case kMathCos: |
| 2667 DoMathCos(instr); |
| 2668 break; |
| 2669 case kMathSin: |
| 2670 DoMathSin(instr); |
| 2671 break; |
| 2672 case kMathLog: |
| 2673 DoMathLog(instr); |
| 2674 break; |
| 2675 |
| 2676 default: |
| 2677 UNREACHABLE(); |
| 2678 } |
| 2060 } | 2679 } |
| 2061 | 2680 |
| 2062 | 2681 |
| 2063 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { | 2682 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { |
| 2064 Abort("Unimplemented: %s", "DoCallKeyed"); | 2683 ASSERT(ToRegister(instr->key()).is(rcx)); |
| 2065 } | 2684 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2066 | 2685 |
| 2067 | 2686 int arity = instr->arity(); |
| 2687 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP); |
| 2688 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2689 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2690 } |
| 2691 |
| 2692 |
| 2068 void LCodeGen::DoCallNamed(LCallNamed* instr) { | 2693 void LCodeGen::DoCallNamed(LCallNamed* instr) { |
| 2069 ASSERT(ToRegister(instr->result()).is(rax)); | 2694 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2070 | 2695 |
| 2071 int arity = instr->arity(); | 2696 int arity = instr->arity(); |
| 2072 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP); | 2697 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP); |
| 2073 __ Move(rcx, instr->name()); | 2698 __ Move(rcx, instr->name()); |
| 2074 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2699 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2075 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2700 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2076 } | 2701 } |
| 2077 | 2702 |
| 2078 | 2703 |
| 2079 void LCodeGen::DoCallFunction(LCallFunction* instr) { | 2704 void LCodeGen::DoCallFunction(LCallFunction* instr) { |
| 2080 Abort("Unimplemented: %s", "DoCallFunction"); | 2705 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2706 |
| 2707 int arity = instr->arity(); |
| 2708 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); |
| 2709 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2710 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2711 __ Drop(1); |
| 2081 } | 2712 } |
| 2082 | 2713 |
| 2083 | 2714 |
| 2084 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 2715 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
| 2085 ASSERT(ToRegister(instr->result()).is(rax)); | 2716 ASSERT(ToRegister(instr->result()).is(rax)); |
| 2086 int arity = instr->arity(); | 2717 int arity = instr->arity(); |
| 2087 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP); | 2718 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP); |
| 2088 __ Move(rcx, instr->name()); | 2719 __ Move(rcx, instr->name()); |
| 2089 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); | 2720 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); |
| 2090 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2721 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2137 if (instr->needs_write_barrier()) { | 2768 if (instr->needs_write_barrier()) { |
| 2138 // Update the write barrier for the properties array. | 2769 // Update the write barrier for the properties array. |
| 2139 // object is used as a scratch register. | 2770 // object is used as a scratch register. |
| 2140 __ RecordWrite(temp, offset, value, object); | 2771 __ RecordWrite(temp, offset, value, object); |
| 2141 } | 2772 } |
| 2142 } | 2773 } |
| 2143 } | 2774 } |
| 2144 | 2775 |
| 2145 | 2776 |
| 2146 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 2777 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 2147 Abort("Unimplemented: %s", "DoStoreNamedGeneric"); | 2778 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 2779 ASSERT(ToRegister(instr->value()).is(rax)); |
| 2780 |
| 2781 __ Move(rcx, instr->hydrogen()->name()); |
| 2782 Handle<Code> ic(Builtins::builtin( |
| 2783 info_->is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 2784 : Builtins::StoreIC_Initialize)); |
| 2785 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2786 } |
| 2787 |
| 2788 |
| 2789 void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) { |
| 2790 Register external_pointer = ToRegister(instr->external_pointer()); |
| 2791 Register key = ToRegister(instr->key()); |
| 2792 Register value = ToRegister(instr->value()); |
| 2793 |
| 2794 { // Clamp the value to [0..255]. |
| 2795 NearLabel done; |
| 2796 __ testl(value, Immediate(0xFFFFFF00)); |
| 2797 __ j(zero, &done); |
| 2798 __ setcc(negative, value); // 1 if negative, 0 if positive. |
| 2799 __ decb(value); // 0 if negative, 255 if positive. |
| 2800 __ bind(&done); |
| 2801 } |
| 2802 |
| 2803 __ movb(Operand(external_pointer, key, times_1, 0), value); |
| 2148 } | 2804 } |
| 2149 | 2805 |
| 2150 | 2806 |
| 2151 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { | 2807 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
| 2152 if (instr->length()->IsRegister()) { | 2808 if (instr->length()->IsRegister()) { |
| 2153 __ cmpq(ToRegister(instr->index()), ToRegister(instr->length())); | 2809 __ cmpq(ToRegister(instr->index()), ToRegister(instr->length())); |
| 2154 } else { | 2810 } else { |
| 2155 __ cmpq(ToRegister(instr->index()), ToOperand(instr->length())); | 2811 __ cmpq(ToRegister(instr->index()), ToOperand(instr->length())); |
| 2156 } | 2812 } |
| 2157 DeoptimizeIf(above_equal, instr->environment()); | 2813 DeoptimizeIf(above_equal, instr->environment()); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2183 __ lea(key, FieldOperand(elements, | 2839 __ lea(key, FieldOperand(elements, |
| 2184 key, | 2840 key, |
| 2185 times_pointer_size, | 2841 times_pointer_size, |
| 2186 FixedArray::kHeaderSize)); | 2842 FixedArray::kHeaderSize)); |
| 2187 __ RecordWrite(elements, key, value); | 2843 __ RecordWrite(elements, key, value); |
| 2188 } | 2844 } |
| 2189 } | 2845 } |
| 2190 | 2846 |
| 2191 | 2847 |
| 2192 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 2848 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 2193 Abort("Unimplemented: %s", "DoStoreKeyedGeneric"); | 2849 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 2850 ASSERT(ToRegister(instr->key()).is(rcx)); |
| 2851 ASSERT(ToRegister(instr->value()).is(rax)); |
| 2852 |
| 2853 Handle<Code> ic(Builtins::builtin( |
| 2854 info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 2855 : Builtins::KeyedStoreIC_Initialize)); |
| 2856 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2857 } |
| 2858 |
| 2859 |
| 2860 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 2861 class DeferredStringCharCodeAt: public LDeferredCode { |
| 2862 public: |
| 2863 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 2864 : LDeferredCode(codegen), instr_(instr) { } |
| 2865 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| 2866 private: |
| 2867 LStringCharCodeAt* instr_; |
| 2868 }; |
| 2869 |
| 2870 Register string = ToRegister(instr->string()); |
| 2871 Register index = no_reg; |
| 2872 int const_index = -1; |
| 2873 if (instr->index()->IsConstantOperand()) { |
| 2874 const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 2875 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 2876 if (!Smi::IsValid(const_index)) { |
| 2877 // Guaranteed to be out of bounds because of the assert above. |
| 2878 // So the bounds check that must dominate this instruction must |
| 2879 // have deoptimized already. |
| 2880 if (FLAG_debug_code) { |
| 2881 __ Abort("StringCharCodeAt: out of bounds index."); |
| 2882 } |
| 2883 // No code needs to be generated. |
| 2884 return; |
| 2885 } |
| 2886 } else { |
| 2887 index = ToRegister(instr->index()); |
| 2888 } |
| 2889 Register result = ToRegister(instr->result()); |
| 2890 |
| 2891 DeferredStringCharCodeAt* deferred = |
| 2892 new DeferredStringCharCodeAt(this, instr); |
| 2893 |
| 2894 NearLabel flat_string, ascii_string, done; |
| 2895 |
| 2896 // Fetch the instance type of the receiver into result register. |
| 2897 __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); |
| 2898 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
| 2899 |
| 2900 // We need special handling for non-sequential strings. |
| 2901 STATIC_ASSERT(kSeqStringTag == 0); |
| 2902 __ testb(result, Immediate(kStringRepresentationMask)); |
| 2903 __ j(zero, &flat_string); |
| 2904 |
| 2905 // Handle cons strings and go to deferred code for the rest. |
| 2906 __ testb(result, Immediate(kIsConsStringMask)); |
| 2907 __ j(zero, deferred->entry()); |
| 2908 |
| 2909 // ConsString. |
| 2910 // Check whether the right hand side is the empty string (i.e. if |
| 2911 // this is really a flat string in a cons string). If that is not |
| 2912 // the case we would rather go to the runtime system now to flatten |
| 2913 // the string. |
| 2914 __ CompareRoot(FieldOperand(string, ConsString::kSecondOffset), |
| 2915 Heap::kEmptyStringRootIndex); |
| 2916 __ j(not_equal, deferred->entry()); |
| 2917 // Get the first of the two strings and load its instance type. |
| 2918 __ movq(string, FieldOperand(string, ConsString::kFirstOffset)); |
| 2919 __ movq(result, FieldOperand(string, HeapObject::kMapOffset)); |
| 2920 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
| 2921 // If the first cons component is also non-flat, then go to runtime. |
| 2922 STATIC_ASSERT(kSeqStringTag == 0); |
| 2923 __ testb(result, Immediate(kStringRepresentationMask)); |
| 2924 __ j(not_zero, deferred->entry()); |
| 2925 |
| 2926 // Check for ASCII or two-byte string. |
| 2927 __ bind(&flat_string); |
| 2928 STATIC_ASSERT(kAsciiStringTag != 0); |
| 2929 __ testb(result, Immediate(kStringEncodingMask)); |
| 2930 __ j(not_zero, &ascii_string); |
| 2931 |
| 2932 // Two-byte string. |
| 2933 // Load the two-byte character code into the result register. |
| 2934 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 2935 if (instr->index()->IsConstantOperand()) { |
| 2936 __ movzxwl(result, |
| 2937 FieldOperand(string, |
| 2938 SeqTwoByteString::kHeaderSize + |
| 2939 (kUC16Size * const_index))); |
| 2940 } else { |
| 2941 __ movzxwl(result, FieldOperand(string, |
| 2942 index, |
| 2943 times_2, |
| 2944 SeqTwoByteString::kHeaderSize)); |
| 2945 } |
| 2946 __ jmp(&done); |
| 2947 |
| 2948 // ASCII string. |
| 2949 // Load the byte into the result register. |
| 2950 __ bind(&ascii_string); |
| 2951 if (instr->index()->IsConstantOperand()) { |
| 2952 __ movzxbl(result, FieldOperand(string, |
| 2953 SeqAsciiString::kHeaderSize + const_index)); |
| 2954 } else { |
| 2955 __ movzxbl(result, FieldOperand(string, |
| 2956 index, |
| 2957 times_1, |
| 2958 SeqAsciiString::kHeaderSize)); |
| 2959 } |
| 2960 __ bind(&done); |
| 2961 __ bind(deferred->exit()); |
| 2962 } |
| 2963 |
| 2964 |
| 2965 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { |
| 2966 Register string = ToRegister(instr->string()); |
| 2967 Register result = ToRegister(instr->result()); |
| 2968 |
| 2969 // TODO(3095996): Get rid of this. For now, we need to make the |
| 2970 // result register contain a valid pointer because it is already |
| 2971 // contained in the register pointer map. |
| 2972 __ Set(result, 0); |
| 2973 |
| 2974 __ PushSafepointRegisters(); |
| 2975 __ push(string); |
| 2976 // Push the index as a smi. This is safe because of the checks in |
| 2977 // DoStringCharCodeAt above. |
| 2978 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 2979 if (instr->index()->IsConstantOperand()) { |
| 2980 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 2981 __ Push(Smi::FromInt(const_index)); |
| 2982 } else { |
| 2983 Register index = ToRegister(instr->index()); |
| 2984 __ Integer32ToSmi(index, index); |
| 2985 __ push(index); |
| 2986 } |
| 2987 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2988 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); |
| 2989 RecordSafepointWithRegisters( |
| 2990 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); |
| 2991 if (FLAG_debug_code) { |
| 2992 __ AbortIfNotSmi(rax); |
| 2993 } |
| 2994 __ SmiToInteger32(rax, rax); |
| 2995 __ StoreToSafepointRegisterSlot(result, rax); |
| 2996 __ PopSafepointRegisters(); |
| 2997 } |
| 2998 |
| 2999 |
| 3000 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { |
| 3001 class DeferredStringCharFromCode: public LDeferredCode { |
| 3002 public: |
| 3003 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) |
| 3004 : LDeferredCode(codegen), instr_(instr) { } |
| 3005 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } |
| 3006 private: |
| 3007 LStringCharFromCode* instr_; |
| 3008 }; |
| 3009 |
| 3010 DeferredStringCharFromCode* deferred = |
| 3011 new DeferredStringCharFromCode(this, instr); |
| 3012 |
| 3013 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
| 3014 Register char_code = ToRegister(instr->char_code()); |
| 3015 Register result = ToRegister(instr->result()); |
| 3016 ASSERT(!char_code.is(result)); |
| 3017 |
| 3018 __ cmpl(char_code, Immediate(String::kMaxAsciiCharCode)); |
| 3019 __ j(above, deferred->entry()); |
| 3020 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex); |
| 3021 __ movq(result, FieldOperand(result, |
| 3022 char_code, times_pointer_size, |
| 3023 FixedArray::kHeaderSize)); |
| 3024 __ CompareRoot(result, Heap::kUndefinedValueRootIndex); |
| 3025 __ j(equal, deferred->entry()); |
| 3026 __ bind(deferred->exit()); |
| 3027 } |
| 3028 |
| 3029 |
| 3030 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { |
| 3031 Register char_code = ToRegister(instr->char_code()); |
| 3032 Register result = ToRegister(instr->result()); |
| 3033 |
| 3034 // TODO(3095996): Get rid of this. For now, we need to make the |
| 3035 // result register contain a valid pointer because it is already |
| 3036 // contained in the register pointer map. |
| 3037 __ Set(result, 0); |
| 3038 |
| 3039 __ PushSafepointRegisters(); |
| 3040 __ Integer32ToSmi(char_code, char_code); |
| 3041 __ push(char_code); |
| 3042 __ CallRuntimeSaveDoubles(Runtime::kCharFromCode); |
| 3043 RecordSafepointWithRegisters( |
| 3044 instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex); |
| 3045 __ StoreToSafepointRegisterSlot(result, rax); |
| 3046 __ PopSafepointRegisters(); |
| 2194 } | 3047 } |
| 2195 | 3048 |
| 2196 | 3049 |
| 2197 void LCodeGen::DoStringLength(LStringLength* instr) { | 3050 void LCodeGen::DoStringLength(LStringLength* instr) { |
| 2198 Register string = ToRegister(instr->string()); | 3051 Register string = ToRegister(instr->string()); |
| 2199 Register result = ToRegister(instr->result()); | 3052 Register result = ToRegister(instr->result()); |
| 2200 __ movq(result, FieldOperand(string, String::kLengthOffset)); | 3053 __ movq(result, FieldOperand(string, String::kLengthOffset)); |
| 2201 } | 3054 } |
| 2202 | 3055 |
| 2203 | 3056 |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2396 ASSERT(result->IsDoubleRegister()); | 3249 ASSERT(result->IsDoubleRegister()); |
| 2397 | 3250 |
| 2398 Register input_reg = ToRegister(input); | 3251 Register input_reg = ToRegister(input); |
| 2399 XMMRegister result_reg = ToDoubleRegister(result); | 3252 XMMRegister result_reg = ToDoubleRegister(result); |
| 2400 | 3253 |
| 2401 EmitNumberUntagD(input_reg, result_reg, instr->environment()); | 3254 EmitNumberUntagD(input_reg, result_reg, instr->environment()); |
| 2402 } | 3255 } |
| 2403 | 3256 |
| 2404 | 3257 |
| 2405 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 3258 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 2406 Abort("Unimplemented: %s", "DoDoubleToI"); | 3259 LOperand* input = instr->InputAt(0); |
| 3260 ASSERT(input->IsDoubleRegister()); |
| 3261 LOperand* result = instr->result(); |
| 3262 ASSERT(result->IsRegister()); |
| 3263 |
| 3264 XMMRegister input_reg = ToDoubleRegister(input); |
| 3265 Register result_reg = ToRegister(result); |
| 3266 |
| 3267 if (instr->truncating()) { |
| 3268 // Performs a truncating conversion of a floating point number as used by |
| 3269 // the JS bitwise operations. |
| 3270 __ cvttsd2siq(result_reg, input_reg); |
| 3271 __ movq(kScratchRegister, V8_INT64_C(0x8000000000000000), RelocInfo::NONE); |
| 3272 __ cmpl(result_reg, kScratchRegister); |
| 3273 DeoptimizeIf(equal, instr->environment()); |
| 3274 } else { |
| 3275 __ cvttsd2si(result_reg, input_reg); |
| 3276 __ cvtlsi2sd(xmm0, result_reg); |
| 3277 __ ucomisd(xmm0, input_reg); |
| 3278 DeoptimizeIf(not_equal, instr->environment()); |
| 3279 DeoptimizeIf(parity_even, instr->environment()); // NaN. |
| 3280 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3281 NearLabel done; |
| 3282 // The integer converted back is equal to the original. We |
| 3283 // only have to test if we got -0 as an input. |
| 3284 __ testl(result_reg, result_reg); |
| 3285 __ j(not_zero, &done); |
| 3286 __ movmskpd(result_reg, input_reg); |
| 3287 // Bit 0 contains the sign of the double in input_reg. |
| 3288 // If input was positive, we are ok and return 0, otherwise |
| 3289 // deoptimize. |
| 3290 __ andl(result_reg, Immediate(1)); |
| 3291 DeoptimizeIf(not_zero, instr->environment()); |
| 3292 __ bind(&done); |
| 3293 } |
| 3294 } |
| 2407 } | 3295 } |
| 2408 | 3296 |
| 2409 | 3297 |
| 2410 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 3298 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 2411 LOperand* input = instr->InputAt(0); | 3299 LOperand* input = instr->InputAt(0); |
| 2412 ASSERT(input->IsRegister()); | 3300 ASSERT(input->IsRegister()); |
| 2413 Condition cc = masm()->CheckSmi(ToRegister(input)); | 3301 Condition cc = masm()->CheckSmi(ToRegister(input)); |
| 2414 if (instr->condition() != equal) { | 3302 if (instr->condition() != equal) { |
| 2415 cc = NegateCondition(cc); | 3303 cc = NegateCondition(cc); |
| 2416 } | 3304 } |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2545 // Pick the right runtime function to call. | 3433 // Pick the right runtime function to call. |
| 2546 if (instr->hydrogen()->depth() > 1) { | 3434 if (instr->hydrogen()->depth() > 1) { |
| 2547 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); | 3435 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); |
| 2548 } else { | 3436 } else { |
| 2549 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); | 3437 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); |
| 2550 } | 3438 } |
| 2551 } | 3439 } |
| 2552 | 3440 |
| 2553 | 3441 |
| 2554 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { | 3442 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { |
| 2555 Abort("Unimplemented: %s", "DoRegExpLiteral"); | 3443 NearLabel materialized; |
| 3444 // Registers will be used as follows: |
| 3445 // rdi = JS function. |
| 3446 // rcx = literals array. |
| 3447 // rbx = regexp literal. |
| 3448 // rax = regexp literal clone. |
| 3449 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3450 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 3451 int literal_offset = FixedArray::kHeaderSize + |
| 3452 instr->hydrogen()->literal_index() * kPointerSize; |
| 3453 __ movq(rbx, FieldOperand(rcx, literal_offset)); |
| 3454 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); |
| 3455 __ j(not_equal, &materialized); |
| 3456 |
| 3457 // Create regexp literal using runtime function |
| 3458 // Result will be in rax. |
| 3459 __ push(rcx); |
| 3460 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); |
| 3461 __ Push(instr->hydrogen()->pattern()); |
| 3462 __ Push(instr->hydrogen()->flags()); |
| 3463 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); |
| 3464 __ movq(rbx, rax); |
| 3465 |
| 3466 __ bind(&materialized); |
| 3467 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
| 3468 Label allocated, runtime_allocate; |
| 3469 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); |
| 3470 __ jmp(&allocated); |
| 3471 |
| 3472 __ bind(&runtime_allocate); |
| 3473 __ push(rbx); |
| 3474 __ Push(Smi::FromInt(size)); |
| 3475 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); |
| 3476 __ pop(rbx); |
| 3477 |
| 3478 __ bind(&allocated); |
| 3479 // Copy the content into the newly allocated memory. |
| 3480 // (Unroll copy loop once for better throughput). |
| 3481 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { |
| 3482 __ movq(rdx, FieldOperand(rbx, i)); |
| 3483 __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); |
| 3484 __ movq(FieldOperand(rax, i), rdx); |
| 3485 __ movq(FieldOperand(rax, i + kPointerSize), rcx); |
| 3486 } |
| 3487 if ((size % (2 * kPointerSize)) != 0) { |
| 3488 __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); |
| 3489 __ movq(FieldOperand(rax, size - kPointerSize), rdx); |
| 3490 } |
| 2556 } | 3491 } |
| 2557 | 3492 |
| 2558 | 3493 |
| 2559 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 3494 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
| 2560 // Use the fast case closure allocation code that allocates in new | 3495 // Use the fast case closure allocation code that allocates in new |
| 2561 // space for nested functions that don't need literals cloning. | 3496 // space for nested functions that don't need literals cloning. |
| 2562 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); | 3497 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); |
| 2563 bool pretenure = instr->hydrogen()->pretenure(); | 3498 bool pretenure = instr->hydrogen()->pretenure(); |
| 2564 if (shared_info->num_literals() == 0 && !pretenure) { | 3499 if (shared_info->num_literals() == 0 && !pretenure) { |
| 2565 FastNewClosureStub stub; | 3500 FastNewClosureStub stub; |
| 2566 __ Push(shared_info); | 3501 __ Push(shared_info); |
| 2567 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3502 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2568 } else { | 3503 } else { |
| 2569 __ push(rsi); | 3504 __ push(rsi); |
| 2570 __ Push(shared_info); | 3505 __ Push(shared_info); |
| 2571 __ Push(pretenure ? Factory::true_value() : Factory::false_value()); | 3506 __ PushRoot(pretenure ? |
| 3507 Heap::kTrueValueRootIndex : |
| 3508 Heap::kFalseValueRootIndex); |
| 2572 CallRuntime(Runtime::kNewClosure, 3, instr); | 3509 CallRuntime(Runtime::kNewClosure, 3, instr); |
| 2573 } | 3510 } |
| 2574 } | 3511 } |
| 2575 | 3512 |
| 2576 | 3513 |
| 2577 void LCodeGen::DoTypeof(LTypeof* instr) { | 3514 void LCodeGen::DoTypeof(LTypeof* instr) { |
| 2578 Abort("Unimplemented: %s", "DoTypeof"); | 3515 LOperand* input = instr->InputAt(0); |
| 3516 if (input->IsConstantOperand()) { |
| 3517 __ Push(ToHandle(LConstantOperand::cast(input))); |
| 3518 } else if (input->IsRegister()) { |
| 3519 __ push(ToRegister(input)); |
| 3520 } else { |
| 3521 ASSERT(input->IsStackSlot()); |
| 3522 __ push(ToOperand(input)); |
| 3523 } |
| 3524 CallRuntime(Runtime::kTypeof, 1, instr); |
| 2579 } | 3525 } |
| 2580 | 3526 |
| 2581 | 3527 |
| 2582 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { | 3528 void LCodeGen::DoTypeofIs(LTypeofIs* instr) { |
| 2583 Abort("Unimplemented: %s", "DoTypeofIs"); | 3529 Register input = ToRegister(instr->InputAt(0)); |
| 2584 } | |
| 2585 | |
| 2586 | |
| 2587 void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) { | |
| 2588 Register result = ToRegister(instr->result()); | 3530 Register result = ToRegister(instr->result()); |
| 2589 NearLabel true_label; | 3531 Label true_label; |
| 2590 NearLabel false_label; | 3532 Label false_label; |
| 2591 NearLabel done; | 3533 NearLabel done; |
| 2592 | 3534 |
| 2593 EmitIsConstructCall(result); | 3535 Condition final_branch_condition = EmitTypeofIs(&true_label, |
| 2594 __ j(equal, &true_label); | 3536 &false_label, |
| 2595 | 3537 input, |
| 3538 instr->type_literal()); |
| 3539 __ j(final_branch_condition, &true_label); |
| 3540 __ bind(&false_label); |
| 2596 __ LoadRoot(result, Heap::kFalseValueRootIndex); | 3541 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 2597 __ jmp(&done); | 3542 __ jmp(&done); |
| 2598 | 3543 |
| 2599 __ bind(&true_label); | 3544 __ bind(&true_label); |
| 2600 __ LoadRoot(result, Heap::kTrueValueRootIndex); | 3545 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 2601 | 3546 |
| 2602 | |
| 2603 __ bind(&done); | 3547 __ bind(&done); |
| 2604 } | 3548 } |
| 2605 | 3549 |
| 2606 | 3550 |
| 2607 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 3551 void LCodeGen::EmitPushConstantOperand(LOperand* operand) { |
| 2608 Register temp = ToRegister(instr->TempAt(0)); | 3552 ASSERT(operand->IsConstantOperand()); |
| 2609 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 3553 LConstantOperand* const_op = LConstantOperand::cast(operand); |
| 2610 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 3554 Handle<Object> literal = chunk_->LookupLiteral(const_op); |
| 2611 | 3555 Representation r = chunk_->LookupLiteralRepresentation(const_op); |
| 2612 EmitIsConstructCall(temp); | 3556 if (r.IsInteger32()) { |
| 2613 EmitBranch(true_block, false_block, equal); | 3557 ASSERT(literal->IsNumber()); |
| 2614 } | 3558 __ push(Immediate(static_cast<int32_t>(literal->Number()))); |
| 2615 | 3559 } else if (r.IsDouble()) { |
| 2616 | 3560 Abort("unsupported double immediate"); |
| 2617 void LCodeGen::EmitIsConstructCall(Register temp) { | 3561 } else { |
| 2618 // Get the frame pointer for the calling frame. | 3562 ASSERT(r.IsTagged()); |
| 2619 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 3563 __ Push(literal); |
| 2620 | 3564 } |
| 2621 // Skip the arguments adaptor frame if it exists. | |
| 2622 NearLabel check_frame_marker; | |
| 2623 __ SmiCompare(Operand(temp, StandardFrameConstants::kContextOffset), | |
| 2624 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | |
| 2625 __ j(not_equal, &check_frame_marker); | |
| 2626 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | |
| 2627 | |
| 2628 // Check the marker in the calling frame. | |
| 2629 __ bind(&check_frame_marker); | |
| 2630 __ SmiCompare(Operand(temp, StandardFrameConstants::kMarkerOffset), | |
| 2631 Smi::FromInt(StackFrame::CONSTRUCT)); | |
| 2632 } | 3565 } |
| 2633 | 3566 |
| 2634 | 3567 |
| 2635 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 3568 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
| 2636 Register input = ToRegister(instr->InputAt(0)); | 3569 Register input = ToRegister(instr->InputAt(0)); |
| 2637 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 3570 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 2638 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 3571 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 2639 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 3572 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 2640 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 3573 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 2641 | 3574 |
| 2642 Condition final_branch_condition = EmitTypeofIs(true_label, | 3575 Condition final_branch_condition = EmitTypeofIs(true_label, |
| 2643 false_label, | 3576 false_label, |
| 2644 input, | 3577 input, |
| 2645 instr->type_literal()); | 3578 instr->type_literal()); |
| 2646 | 3579 |
| 2647 EmitBranch(true_block, false_block, final_branch_condition); | 3580 EmitBranch(true_block, false_block, final_branch_condition); |
| 2648 } | 3581 } |
| 2649 | 3582 |
| 2650 | 3583 |
| 2651 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 3584 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 2652 Label* false_label, | 3585 Label* false_label, |
| 2653 Register input, | 3586 Register input, |
| 2654 Handle<String> type_name) { | 3587 Handle<String> type_name) { |
| 2655 Condition final_branch_condition = no_condition; | 3588 Condition final_branch_condition = no_condition; |
| 2656 if (type_name->Equals(Heap::number_symbol())) { | 3589 if (type_name->Equals(Heap::number_symbol())) { |
| 2657 __ JumpIfSmi(input, true_label); | 3590 __ JumpIfSmi(input, true_label); |
| 2658 __ Cmp(FieldOperand(input, HeapObject::kMapOffset), | 3591 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset), |
| 2659 Factory::heap_number_map()); | 3592 Heap::kHeapNumberMapRootIndex); |
| 3593 |
| 2660 final_branch_condition = equal; | 3594 final_branch_condition = equal; |
| 2661 | 3595 |
| 2662 } else if (type_name->Equals(Heap::string_symbol())) { | 3596 } else if (type_name->Equals(Heap::string_symbol())) { |
| 2663 __ JumpIfSmi(input, false_label); | 3597 __ JumpIfSmi(input, false_label); |
| 2664 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | 3598 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); |
| 3599 __ j(above_equal, false_label); |
| 2665 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 3600 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 2666 Immediate(1 << Map::kIsUndetectable)); | 3601 Immediate(1 << Map::kIsUndetectable)); |
| 2667 __ j(not_zero, false_label); | 3602 final_branch_condition = zero; |
| 2668 __ CmpInstanceType(input, FIRST_NONSTRING_TYPE); | |
| 2669 final_branch_condition = below; | |
| 2670 | 3603 |
| 2671 } else if (type_name->Equals(Heap::boolean_symbol())) { | 3604 } else if (type_name->Equals(Heap::boolean_symbol())) { |
| 2672 __ CompareRoot(input, Heap::kTrueValueRootIndex); | 3605 __ CompareRoot(input, Heap::kTrueValueRootIndex); |
| 2673 __ j(equal, true_label); | 3606 __ j(equal, true_label); |
| 2674 __ CompareRoot(input, Heap::kFalseValueRootIndex); | 3607 __ CompareRoot(input, Heap::kFalseValueRootIndex); |
| 2675 final_branch_condition = equal; | 3608 final_branch_condition = equal; |
| 2676 | 3609 |
| 2677 } else if (type_name->Equals(Heap::undefined_symbol())) { | 3610 } else if (type_name->Equals(Heap::undefined_symbol())) { |
| 2678 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); | 3611 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); |
| 2679 __ j(equal, true_label); | 3612 __ j(equal, true_label); |
| 2680 __ JumpIfSmi(input, false_label); | 3613 __ JumpIfSmi(input, false_label); |
| 2681 // Check for undetectable objects => true. | 3614 // Check for undetectable objects => true. |
| 2682 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | 3615 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 2683 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 3616 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 2684 Immediate(1 << Map::kIsUndetectable)); | 3617 Immediate(1 << Map::kIsUndetectable)); |
| 2685 final_branch_condition = not_zero; | 3618 final_branch_condition = not_zero; |
| 2686 | 3619 |
| 2687 } else if (type_name->Equals(Heap::function_symbol())) { | 3620 } else if (type_name->Equals(Heap::function_symbol())) { |
| 2688 __ JumpIfSmi(input, false_label); | 3621 __ JumpIfSmi(input, false_label); |
| 2689 __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input); | 3622 __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input); |
| 2690 final_branch_condition = above_equal; | 3623 final_branch_condition = above_equal; |
| 2691 | 3624 |
| 2692 } else if (type_name->Equals(Heap::object_symbol())) { | 3625 } else if (type_name->Equals(Heap::object_symbol())) { |
| 2693 __ JumpIfSmi(input, false_label); | 3626 __ JumpIfSmi(input, false_label); |
| 2694 __ Cmp(input, Factory::null_value()); | 3627 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 2695 __ j(equal, true_label); | 3628 __ j(equal, true_label); |
| 3629 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input); |
| 3630 __ j(below, false_label); |
| 3631 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); |
| 3632 __ j(above_equal, false_label); |
| 2696 // Check for undetectable objects => false. | 3633 // Check for undetectable objects => false. |
| 2697 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 3634 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 2698 Immediate(1 << Map::kIsUndetectable)); | 3635 Immediate(1 << Map::kIsUndetectable)); |
| 2699 __ j(not_zero, false_label); | 3636 final_branch_condition = zero; |
| 2700 // Check for JS objects that are not RegExp or Function => true. | |
| 2701 __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE); | |
| 2702 __ j(below, false_label); | |
| 2703 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); | |
| 2704 final_branch_condition = below_equal; | |
| 2705 | 3637 |
| 2706 } else { | 3638 } else { |
| 2707 final_branch_condition = never; | 3639 final_branch_condition = never; |
| 2708 __ jmp(false_label); | 3640 __ jmp(false_label); |
| 2709 } | 3641 } |
| 2710 | 3642 |
| 2711 return final_branch_condition; | 3643 return final_branch_condition; |
| 2712 } | 3644 } |
| 2713 | 3645 |
| 2714 | 3646 |
| 3647 void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) { |
| 3648 Register result = ToRegister(instr->result()); |
| 3649 NearLabel true_label; |
| 3650 NearLabel false_label; |
| 3651 NearLabel done; |
| 3652 |
| 3653 EmitIsConstructCall(result); |
| 3654 __ j(equal, &true_label); |
| 3655 |
| 3656 __ LoadRoot(result, Heap::kFalseValueRootIndex); |
| 3657 __ jmp(&done); |
| 3658 |
| 3659 __ bind(&true_label); |
| 3660 __ LoadRoot(result, Heap::kTrueValueRootIndex); |
| 3661 |
| 3662 |
| 3663 __ bind(&done); |
| 3664 } |
| 3665 |
| 3666 |
| 3667 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 3668 Register temp = ToRegister(instr->TempAt(0)); |
| 3669 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 3670 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 3671 |
| 3672 EmitIsConstructCall(temp); |
| 3673 EmitBranch(true_block, false_block, equal); |
| 3674 } |
| 3675 |
| 3676 |
| 3677 void LCodeGen::EmitIsConstructCall(Register temp) { |
| 3678 // Get the frame pointer for the calling frame. |
| 3679 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 3680 |
| 3681 // Skip the arguments adaptor frame if it exists. |
| 3682 NearLabel check_frame_marker; |
| 3683 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset), |
| 3684 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 3685 __ j(not_equal, &check_frame_marker); |
| 3686 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
| 3687 |
| 3688 // Check the marker in the calling frame. |
| 3689 __ bind(&check_frame_marker); |
| 3690 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), |
| 3691 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 3692 } |
| 3693 |
| 3694 |
| 2715 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { | 3695 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { |
| 2716 // No code for lazy bailout instruction. Used to capture environment after a | 3696 // No code for lazy bailout instruction. Used to capture environment after a |
| 2717 // call for populating the safepoint data with deoptimization data. | 3697 // call for populating the safepoint data with deoptimization data. |
| 2718 } | 3698 } |
| 2719 | 3699 |
| 2720 | 3700 |
| 2721 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { | 3701 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { |
| 2722 DeoptimizeIf(no_condition, instr->environment()); | 3702 DeoptimizeIf(no_condition, instr->environment()); |
| 2723 } | 3703 } |
| 2724 | 3704 |
| 2725 | 3705 |
| 2726 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { | 3706 void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { |
| 2727 Abort("Unimplemented: %s", "DoDeleteProperty"); | 3707 LOperand* obj = instr->object(); |
| 3708 LOperand* key = instr->key(); |
| 3709 // Push object. |
| 3710 if (obj->IsRegister()) { |
| 3711 __ push(ToRegister(obj)); |
| 3712 } else { |
| 3713 __ push(ToOperand(obj)); |
| 3714 } |
| 3715 // Push key. |
| 3716 if (key->IsConstantOperand()) { |
| 3717 EmitPushConstantOperand(key); |
| 3718 } else if (key->IsRegister()) { |
| 3719 __ push(ToRegister(key)); |
| 3720 } else { |
| 3721 __ push(ToOperand(key)); |
| 3722 } |
| 3723 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); |
| 3724 LPointerMap* pointers = instr->pointer_map(); |
| 3725 LEnvironment* env = instr->deoptimization_environment(); |
| 3726 RecordPosition(pointers->position()); |
| 3727 RegisterEnvironmentForDeoptimization(env); |
| 3728 // Create safepoint generator that will also ensure enough space in the |
| 3729 // reloc info for patching in deoptimization (since this is invoking a |
| 3730 // builtin) |
| 3731 SafepointGenerator safepoint_generator(this, |
| 3732 pointers, |
| 3733 env->deoptimization_index(), |
| 3734 true); |
| 3735 __ Push(Smi::FromInt(strict_mode_flag())); |
| 3736 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator); |
| 2728 } | 3737 } |
| 2729 | 3738 |
| 2730 | 3739 |
| 2731 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 3740 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 2732 // Perform stack overflow check. | 3741 // Perform stack overflow check. |
| 2733 NearLabel done; | 3742 NearLabel done; |
| 2734 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 3743 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 2735 __ j(above_equal, &done); | 3744 __ j(above_equal, &done); |
| 2736 | 3745 |
| 2737 StackCheckStub stub; | 3746 StackCheckStub stub; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2754 RegisterEnvironmentForDeoptimization(environment); | 3763 RegisterEnvironmentForDeoptimization(environment); |
| 2755 ASSERT(osr_pc_offset_ == -1); | 3764 ASSERT(osr_pc_offset_ == -1); |
| 2756 osr_pc_offset_ = masm()->pc_offset(); | 3765 osr_pc_offset_ = masm()->pc_offset(); |
| 2757 } | 3766 } |
| 2758 | 3767 |
| 2759 #undef __ | 3768 #undef __ |
| 2760 | 3769 |
| 2761 } } // namespace v8::internal | 3770 } } // namespace v8::internal |
| 2762 | 3771 |
| 2763 #endif // V8_TARGET_ARCH_X64 | 3772 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |