| 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 : codegen_(codegen), | 48 : codegen_(codegen), |
| 49 pointers_(pointers), | 49 pointers_(pointers), |
| 50 deoptimization_index_(deoptimization_index), | 50 deoptimization_index_(deoptimization_index), |
| 51 ensure_reloc_space_(ensure_reloc_space) { } | 51 ensure_reloc_space_(ensure_reloc_space) { } |
| 52 virtual ~SafepointGenerator() { } | 52 virtual ~SafepointGenerator() { } |
| 53 | 53 |
| 54 virtual void Generate() { | 54 virtual void Generate() { |
| 55 // Ensure that we have enough space in the reloc info to patch | 55 // Ensure that we have enough space in the reloc info to patch |
| 56 // this with calls when doing deoptimization. | 56 // this with calls when doing deoptimization. |
| 57 if (ensure_reloc_space_) { | 57 if (ensure_reloc_space_) { |
| 58 codegen_->masm()->RecordComment(RelocInfo::kFillerCommentString, true); | 58 codegen_->EnsureRelocSpaceForDeoptimization(); |
| 59 } | 59 } |
| 60 codegen_->RecordSafepoint(pointers_, deoptimization_index_); | 60 codegen_->RecordSafepoint(pointers_, deoptimization_index_); |
| 61 } | 61 } |
| 62 | 62 |
| 63 private: | 63 private: |
| 64 LCodeGen* codegen_; | 64 LCodeGen* codegen_; |
| 65 LPointerMap* pointers_; | 65 LPointerMap* pointers_; |
| 66 int deoptimization_index_; | 66 int deoptimization_index_; |
| 67 bool ensure_reloc_space_; | 67 bool ensure_reloc_space_; |
| 68 }; | 68 }; |
| 69 | 69 |
| 70 | 70 |
| 71 #define __ masm()-> | 71 #define __ masm()-> |
| 72 | 72 |
| 73 bool LCodeGen::GenerateCode() { | 73 bool LCodeGen::GenerateCode() { |
| 74 HPhase phase("Code generation", chunk()); | 74 HPhase phase("Code generation", chunk()); |
| 75 ASSERT(is_unused()); | 75 ASSERT(is_unused()); |
| 76 status_ = GENERATING; | 76 status_ = GENERATING; |
| 77 CpuFeatures::Scope scope(SSE2); | 77 CpuFeatures::Scope scope(SSE2); |
| 78 return GeneratePrologue() && | 78 return GeneratePrologue() && |
| 79 GenerateBody() && | 79 GenerateBody() && |
| 80 GenerateDeferredCode() && | 80 GenerateDeferredCode() && |
| 81 GenerateRelocPadding() && |
| 81 GenerateSafepointTable(); | 82 GenerateSafepointTable(); |
| 82 } | 83 } |
| 83 | 84 |
| 84 | 85 |
| 85 void LCodeGen::FinishCode(Handle<Code> code) { | 86 void LCodeGen::FinishCode(Handle<Code> code) { |
| 86 ASSERT(is_done()); | 87 ASSERT(is_done()); |
| 87 code->set_stack_slots(StackSlotCount()); | 88 code->set_stack_slots(StackSlotCount()); |
| 88 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 89 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 89 PopulateDeoptimizationData(code); | 90 PopulateDeoptimizationData(code); |
| 90 } | 91 } |
| 91 | 92 |
| 92 | 93 |
| 93 void LCodeGen::Abort(const char* format, ...) { | 94 void LCodeGen::Abort(const char* format, ...) { |
| 94 if (FLAG_trace_bailout) { | 95 if (FLAG_trace_bailout) { |
| 95 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 96 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 96 PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name); | 97 PrintF("Aborting LCodeGen in @\"%s\": ", *name); |
| 97 va_list arguments; | 98 va_list arguments; |
| 98 va_start(arguments, format); | 99 va_start(arguments, format); |
| 99 OS::VPrint(format, arguments); | 100 OS::VPrint(format, arguments); |
| 100 va_end(arguments); | 101 va_end(arguments); |
| 101 PrintF("\n"); | 102 PrintF("\n"); |
| 102 } | 103 } |
| 103 status_ = ABORTED; | 104 status_ = ABORTED; |
| 104 } | 105 } |
| 105 | 106 |
| 106 | 107 |
| 107 void LCodeGen::Comment(const char* format, ...) { | 108 void LCodeGen::Comment(const char* format, ...) { |
| 108 if (!FLAG_code_comments) return; | 109 if (!FLAG_code_comments) return; |
| 109 char buffer[4 * KB]; | 110 char buffer[4 * KB]; |
| 110 StringBuilder builder(buffer, ARRAY_SIZE(buffer)); | 111 StringBuilder builder(buffer, ARRAY_SIZE(buffer)); |
| 111 va_list arguments; | 112 va_list arguments; |
| 112 va_start(arguments, format); | 113 va_start(arguments, format); |
| 113 builder.AddFormattedList(format, arguments); | 114 builder.AddFormattedList(format, arguments); |
| 114 va_end(arguments); | 115 va_end(arguments); |
| 115 | 116 |
| 116 // Copy the string before recording it in the assembler to avoid | 117 // Copy the string before recording it in the assembler to avoid |
| 117 // issues when the stack allocated buffer goes out of scope. | 118 // issues when the stack allocated buffer goes out of scope. |
| 118 size_t length = builder.position(); | 119 size_t length = builder.position(); |
| 119 Vector<char> copy = Vector<char>::New(length + 1); | 120 Vector<char> copy = Vector<char>::New(length + 1); |
| 120 memcpy(copy.start(), builder.Finalize(), copy.length()); | 121 memcpy(copy.start(), builder.Finalize(), copy.length()); |
| 121 masm()->RecordComment(copy.start()); | 122 masm()->RecordComment(copy.start()); |
| 122 } | 123 } |
| 123 | 124 |
| 124 | 125 |
| 126 bool LCodeGen::GenerateRelocPadding() { |
| 127 int reloc_size = masm()->relocation_writer_size(); |
| 128 while (reloc_size < deoptimization_reloc_size.min_size) { |
| 129 __ RecordComment(RelocInfo::kFillerCommentString, true); |
| 130 reloc_size += RelocInfo::kMinRelocCommentSize; |
| 131 } |
| 132 return !is_aborted(); |
| 133 } |
| 134 |
| 135 |
| 125 bool LCodeGen::GeneratePrologue() { | 136 bool LCodeGen::GeneratePrologue() { |
| 126 ASSERT(is_generating()); | 137 ASSERT(is_generating()); |
| 127 | 138 |
| 128 #ifdef DEBUG | 139 #ifdef DEBUG |
| 129 if (strlen(FLAG_stop_at) > 0 && | 140 if (strlen(FLAG_stop_at) > 0 && |
| 130 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 141 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 131 __ int3(); | 142 __ int3(); |
| 132 } | 143 } |
| 133 #endif | 144 #endif |
| 134 | 145 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 156 const int kPageSize = 4 * KB; | 167 const int kPageSize = 4 * KB; |
| 157 for (int offset = slots * kPointerSize - kPageSize; | 168 for (int offset = slots * kPointerSize - kPageSize; |
| 158 offset > 0; | 169 offset > 0; |
| 159 offset -= kPageSize) { | 170 offset -= kPageSize) { |
| 160 __ mov(Operand(esp, offset), eax); | 171 __ mov(Operand(esp, offset), eax); |
| 161 } | 172 } |
| 162 #endif | 173 #endif |
| 163 } | 174 } |
| 164 } | 175 } |
| 165 | 176 |
| 177 // Possibly allocate a local context. |
| 178 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 179 if (heap_slots > 0) { |
| 180 Comment(";;; Allocate local context"); |
| 181 // Argument to NewContext is the function, which is still in edi. |
| 182 __ push(edi); |
| 183 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 184 FastNewContextStub stub(heap_slots); |
| 185 __ CallStub(&stub); |
| 186 } else { |
| 187 __ CallRuntime(Runtime::kNewContext, 1); |
| 188 } |
| 189 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); |
| 190 // Context is returned in both eax and esi. It replaces the context |
| 191 // passed to us. It's saved in the stack and kept live in esi. |
| 192 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
| 193 |
| 194 // Copy parameters into context if necessary. |
| 195 int num_parameters = scope()->num_parameters(); |
| 196 for (int i = 0; i < num_parameters; i++) { |
| 197 Slot* slot = scope()->parameter(i)->AsSlot(); |
| 198 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 199 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 200 (num_parameters - 1 - i) * kPointerSize; |
| 201 // Load parameter from stack. |
| 202 __ mov(eax, Operand(ebp, parameter_offset)); |
| 203 // Store it in the context. |
| 204 int context_offset = Context::SlotOffset(slot->index()); |
| 205 __ mov(Operand(esi, context_offset), eax); |
| 206 // Update the write barrier. This clobbers all involved |
| 207 // registers, so we have to use a third register to avoid |
| 208 // clobbering esi. |
| 209 __ mov(ecx, esi); |
| 210 __ RecordWrite(ecx, context_offset, eax, ebx); |
| 211 } |
| 212 } |
| 213 Comment(";;; End allocate local context"); |
| 214 } |
| 215 |
| 166 // Trace the call. | 216 // Trace the call. |
| 167 if (FLAG_trace) { | 217 if (FLAG_trace) { |
| 168 // We have not executed any compiled code yet, so esi still holds the | 218 // We have not executed any compiled code yet, so esi still holds the |
| 169 // incoming context. | 219 // incoming context. |
| 170 __ CallRuntime(Runtime::kTraceEnter, 0); | 220 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 171 } | 221 } |
| 172 return !is_aborted(); | 222 return !is_aborted(); |
| 173 } | 223 } |
| 174 | 224 |
| 175 | 225 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 environment->spilled_double_registers()[value->index()], | 378 environment->spilled_double_registers()[value->index()], |
| 329 false); | 379 false); |
| 330 } | 380 } |
| 331 } | 381 } |
| 332 | 382 |
| 333 AddToTranslation(translation, value, environment->HasTaggedValueAt(i)); | 383 AddToTranslation(translation, value, environment->HasTaggedValueAt(i)); |
| 334 } | 384 } |
| 335 } | 385 } |
| 336 | 386 |
| 337 | 387 |
| 388 void LCodeGen::EnsureRelocSpaceForDeoptimization() { |
| 389 // Since we patch the reloc info with RUNTIME_ENTRY calls every patch |
| 390 // site will take up 2 bytes + any pc-jumps. |
| 391 // We are conservative and always reserver 6 bytes in case where a |
| 392 // simple pc-jump is not enough. |
| 393 uint32_t pc_delta = |
| 394 masm()->pc_offset() - deoptimization_reloc_size.last_pc_offset; |
| 395 if (is_uintn(pc_delta, 6)) { |
| 396 deoptimization_reloc_size.min_size += 2; |
| 397 } else { |
| 398 deoptimization_reloc_size.min_size += 6; |
| 399 } |
| 400 deoptimization_reloc_size.last_pc_offset = masm()->pc_offset(); |
| 401 } |
| 402 |
| 403 |
| 338 void LCodeGen::AddToTranslation(Translation* translation, | 404 void LCodeGen::AddToTranslation(Translation* translation, |
| 339 LOperand* op, | 405 LOperand* op, |
| 340 bool is_tagged) { | 406 bool is_tagged) { |
| 341 if (op == NULL) { | 407 if (op == NULL) { |
| 342 // TODO(twuerthinger): Introduce marker operands to indicate that this value | 408 // TODO(twuerthinger): Introduce marker operands to indicate that this value |
| 343 // is not present and must be reconstructed from the deoptimizer. Currently | 409 // is not present and must be reconstructed from the deoptimizer. Currently |
| 344 // this is only used for the arguments object. | 410 // this is only used for the arguments object. |
| 345 translation->StoreArgumentsObject(); | 411 translation->StoreArgumentsObject(); |
| 346 } else if (op->IsStackSlot()) { | 412 } else if (op->IsStackSlot()) { |
| 347 if (is_tagged) { | 413 if (is_tagged) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 375 } | 441 } |
| 376 | 442 |
| 377 | 443 |
| 378 void LCodeGen::CallCode(Handle<Code> code, | 444 void LCodeGen::CallCode(Handle<Code> code, |
| 379 RelocInfo::Mode mode, | 445 RelocInfo::Mode mode, |
| 380 LInstruction* instr, | 446 LInstruction* instr, |
| 381 bool adjusted) { | 447 bool adjusted) { |
| 382 ASSERT(instr != NULL); | 448 ASSERT(instr != NULL); |
| 383 LPointerMap* pointers = instr->pointer_map(); | 449 LPointerMap* pointers = instr->pointer_map(); |
| 384 RecordPosition(pointers->position()); | 450 RecordPosition(pointers->position()); |
| 451 |
| 385 if (!adjusted) { | 452 if (!adjusted) { |
| 386 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 453 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 387 } | 454 } |
| 388 __ call(code, mode); | 455 __ call(code, mode); |
| 456 |
| 457 EnsureRelocSpaceForDeoptimization(); |
| 389 RegisterLazyDeoptimization(instr); | 458 RegisterLazyDeoptimization(instr); |
| 390 | 459 |
| 391 // Signal that we don't inline smi code before these stubs in the | 460 // Signal that we don't inline smi code before these stubs in the |
| 392 // optimizing code generator. | 461 // optimizing code generator. |
| 393 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC || | 462 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC || |
| 394 code->kind() == Code::COMPARE_IC) { | 463 code->kind() == Code::COMPARE_IC) { |
| 395 __ nop(); | 464 __ nop(); |
| 396 } | 465 } |
| 397 } | 466 } |
| 398 | 467 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 } | 581 } |
| 513 | 582 |
| 514 | 583 |
| 515 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { | 584 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { |
| 516 int length = deoptimizations_.length(); | 585 int length = deoptimizations_.length(); |
| 517 if (length == 0) return; | 586 if (length == 0) return; |
| 518 ASSERT(FLAG_deopt); | 587 ASSERT(FLAG_deopt); |
| 519 Handle<DeoptimizationInputData> data = | 588 Handle<DeoptimizationInputData> data = |
| 520 Factory::NewDeoptimizationInputData(length, TENURED); | 589 Factory::NewDeoptimizationInputData(length, TENURED); |
| 521 | 590 |
| 522 data->SetTranslationByteArray(*translations_.CreateByteArray()); | 591 Handle<ByteArray> translations = translations_.CreateByteArray(); |
| 592 data->SetTranslationByteArray(*translations); |
| 523 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); | 593 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); |
| 524 | 594 |
| 525 Handle<FixedArray> literals = | 595 Handle<FixedArray> literals = |
| 526 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED); | 596 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED); |
| 527 for (int i = 0; i < deoptimization_literals_.length(); i++) { | 597 for (int i = 0; i < deoptimization_literals_.length(); i++) { |
| 528 literals->set(i, *deoptimization_literals_[i]); | 598 literals->set(i, *deoptimization_literals_[i]); |
| 529 } | 599 } |
| 530 data->SetLiteralArray(*literals); | 600 data->SetLiteralArray(*literals); |
| 531 | 601 |
| 532 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); | 602 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 } | 658 } |
| 589 } | 659 } |
| 590 | 660 |
| 591 | 661 |
| 592 void LCodeGen::RecordSafepoint(LPointerMap* pointers, | 662 void LCodeGen::RecordSafepoint(LPointerMap* pointers, |
| 593 int deoptimization_index) { | 663 int deoptimization_index) { |
| 594 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); | 664 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); |
| 595 } | 665 } |
| 596 | 666 |
| 597 | 667 |
| 668 void LCodeGen::RecordSafepoint(int deoptimization_index) { |
| 669 LPointerMap empty_pointers(RelocInfo::kNoPosition); |
| 670 RecordSafepoint(&empty_pointers, deoptimization_index); |
| 671 } |
| 672 |
| 673 |
| 598 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 674 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 599 int arguments, | 675 int arguments, |
| 600 int deoptimization_index) { | 676 int deoptimization_index) { |
| 601 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, | 677 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, |
| 602 deoptimization_index); | 678 deoptimization_index); |
| 603 } | 679 } |
| 604 | 680 |
| 605 | 681 |
| 606 void LCodeGen::RecordPosition(int position) { | 682 void LCodeGen::RecordPosition(int position) { |
| 607 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; | 683 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 case CodeStub::RegExpExec: { | 736 case CodeStub::RegExpExec: { |
| 661 RegExpExecStub stub; | 737 RegExpExecStub stub; |
| 662 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 738 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 663 break; | 739 break; |
| 664 } | 740 } |
| 665 case CodeStub::SubString: { | 741 case CodeStub::SubString: { |
| 666 SubStringStub stub; | 742 SubStringStub stub; |
| 667 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 743 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 668 break; | 744 break; |
| 669 } | 745 } |
| 670 case CodeStub::StringCharAt: { | |
| 671 StringCharAtStub stub; | |
| 672 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
| 673 break; | |
| 674 } | |
| 675 case CodeStub::MathPow: { | |
| 676 MathPowStub stub; | |
| 677 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
| 678 break; | |
| 679 } | |
| 680 case CodeStub::NumberToString: { | 746 case CodeStub::NumberToString: { |
| 681 NumberToStringStub stub; | 747 NumberToStringStub stub; |
| 682 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 748 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 683 break; | 749 break; |
| 684 } | 750 } |
| 685 case CodeStub::StringAdd: { | 751 case CodeStub::StringAdd: { |
| 686 StringAddStub stub(NO_STRING_ADD_FLAGS); | 752 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 687 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 753 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 688 break; | 754 break; |
| 689 } | 755 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 703 } | 769 } |
| 704 } | 770 } |
| 705 | 771 |
| 706 | 772 |
| 707 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 773 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 708 // Nothing to do. | 774 // Nothing to do. |
| 709 } | 775 } |
| 710 | 776 |
| 711 | 777 |
| 712 void LCodeGen::DoModI(LModI* instr) { | 778 void LCodeGen::DoModI(LModI* instr) { |
| 713 LOperand* right = instr->InputAt(1); | 779 if (instr->hydrogen()->HasPowerOf2Divisor()) { |
| 714 ASSERT(ToRegister(instr->result()).is(edx)); | 780 Register dividend = ToRegister(instr->InputAt(0)); |
| 715 ASSERT(ToRegister(instr->InputAt(0)).is(eax)); | |
| 716 ASSERT(!ToRegister(instr->InputAt(1)).is(eax)); | |
| 717 ASSERT(!ToRegister(instr->InputAt(1)).is(edx)); | |
| 718 | 781 |
| 719 Register right_reg = ToRegister(right); | 782 int32_t divisor = |
| 783 HConstant::cast(instr->hydrogen()->right())->Integer32Value(); |
| 720 | 784 |
| 721 // Check for x % 0. | 785 if (divisor < 0) divisor = -divisor; |
| 722 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { | |
| 723 __ test(right_reg, ToOperand(right)); | |
| 724 DeoptimizeIf(zero, instr->environment()); | |
| 725 } | |
| 726 | 786 |
| 727 // Sign extend to edx. | 787 NearLabel positive_dividend, done; |
| 728 __ cdq(); | 788 __ test(dividend, Operand(dividend)); |
| 729 | 789 __ j(not_sign, &positive_dividend); |
| 730 // Check for (0 % -x) that will produce negative zero. | 790 __ neg(dividend); |
| 731 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 791 __ and_(dividend, divisor - 1); |
| 732 NearLabel positive_left; | 792 __ neg(dividend); |
| 733 NearLabel done; | 793 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 734 __ test(eax, Operand(eax)); | 794 __ j(not_zero, &done); |
| 735 __ j(not_sign, &positive_left); | 795 DeoptimizeIf(no_condition, instr->environment()); |
| 736 __ idiv(right_reg); | 796 } |
| 737 | 797 __ bind(&positive_dividend); |
| 738 // Test the remainder for 0, because then the result would be -0. | 798 __ and_(dividend, divisor - 1); |
| 739 __ test(edx, Operand(edx)); | |
| 740 __ j(not_zero, &done); | |
| 741 | |
| 742 DeoptimizeIf(no_condition, instr->environment()); | |
| 743 __ bind(&positive_left); | |
| 744 __ idiv(right_reg); | |
| 745 __ bind(&done); | 799 __ bind(&done); |
| 746 } else { | 800 } else { |
| 747 __ idiv(right_reg); | 801 LOperand* right = instr->InputAt(1); |
| 802 ASSERT(ToRegister(instr->InputAt(0)).is(eax)); |
| 803 ASSERT(ToRegister(instr->result()).is(edx)); |
| 804 |
| 805 Register right_reg = ToRegister(right); |
| 806 ASSERT(!right_reg.is(eax)); |
| 807 ASSERT(!right_reg.is(edx)); |
| 808 |
| 809 // Check for x % 0. |
| 810 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 811 __ test(right_reg, ToOperand(right)); |
| 812 DeoptimizeIf(zero, instr->environment()); |
| 813 } |
| 814 |
| 815 // Sign extend to edx. |
| 816 __ cdq(); |
| 817 |
| 818 // Check for (0 % -x) that will produce negative zero. |
| 819 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 820 NearLabel positive_left; |
| 821 NearLabel done; |
| 822 __ test(eax, Operand(eax)); |
| 823 __ j(not_sign, &positive_left); |
| 824 __ idiv(right_reg); |
| 825 |
| 826 // Test the remainder for 0, because then the result would be -0. |
| 827 __ test(edx, Operand(edx)); |
| 828 __ j(not_zero, &done); |
| 829 |
| 830 DeoptimizeIf(no_condition, instr->environment()); |
| 831 __ bind(&positive_left); |
| 832 __ idiv(right_reg); |
| 833 __ bind(&done); |
| 834 } else { |
| 835 __ idiv(right_reg); |
| 836 } |
| 748 } | 837 } |
| 749 } | 838 } |
| 750 | 839 |
| 751 | 840 |
| 752 void LCodeGen::DoDivI(LDivI* instr) { | 841 void LCodeGen::DoDivI(LDivI* instr) { |
| 753 LOperand* right = instr->InputAt(1); | 842 LOperand* right = instr->InputAt(1); |
| 754 ASSERT(ToRegister(instr->result()).is(eax)); | 843 ASSERT(ToRegister(instr->result()).is(eax)); |
| 755 ASSERT(ToRegister(instr->InputAt(0)).is(eax)); | 844 ASSERT(ToRegister(instr->InputAt(0)).is(eax)); |
| 756 ASSERT(!ToRegister(instr->InputAt(1)).is(eax)); | 845 ASSERT(!ToRegister(instr->InputAt(1)).is(eax)); |
| 757 ASSERT(!ToRegister(instr->InputAt(1)).is(edx)); | 846 ASSERT(!ToRegister(instr->InputAt(1)).is(edx)); |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1003 } | 1092 } |
| 1004 | 1093 |
| 1005 | 1094 |
| 1006 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { | 1095 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { |
| 1007 Register result = ToRegister(instr->result()); | 1096 Register result = ToRegister(instr->result()); |
| 1008 Register array = ToRegister(instr->InputAt(0)); | 1097 Register array = ToRegister(instr->InputAt(0)); |
| 1009 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); | 1098 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset)); |
| 1010 } | 1099 } |
| 1011 | 1100 |
| 1012 | 1101 |
| 1013 void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) { | 1102 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { |
| 1014 Register result = ToRegister(instr->result()); | 1103 Register result = ToRegister(instr->result()); |
| 1015 Register array = ToRegister(instr->InputAt(0)); | 1104 Register array = ToRegister(instr->InputAt(0)); |
| 1016 __ mov(result, FieldOperand(array, PixelArray::kLengthOffset)); | 1105 __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset)); |
| 1017 } | 1106 } |
| 1018 | 1107 |
| 1019 | 1108 |
| 1020 void LCodeGen::DoValueOf(LValueOf* instr) { | 1109 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1021 Register input = ToRegister(instr->InputAt(0)); | 1110 Register input = ToRegister(instr->InputAt(0)); |
| 1022 Register result = ToRegister(instr->result()); | 1111 Register result = ToRegister(instr->result()); |
| 1023 Register map = ToRegister(instr->TempAt(0)); | 1112 Register map = ToRegister(instr->TempAt(0)); |
| 1024 ASSERT(input.is(result)); | 1113 ASSERT(input.is(result)); |
| 1025 NearLabel done; | 1114 NearLabel done; |
| 1026 // If the object is a smi return the object. | 1115 // If the object is a smi return the object. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 __ add(ToRegister(left), ToOperand(right)); | 1154 __ add(ToRegister(left), ToOperand(right)); |
| 1066 } | 1155 } |
| 1067 | 1156 |
| 1068 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1157 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { |
| 1069 DeoptimizeIf(overflow, instr->environment()); | 1158 DeoptimizeIf(overflow, instr->environment()); |
| 1070 } | 1159 } |
| 1071 } | 1160 } |
| 1072 | 1161 |
| 1073 | 1162 |
| 1074 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { | 1163 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { |
| 1075 LOperand* left = instr->InputAt(0); | 1164 XMMRegister left = ToDoubleRegister(instr->InputAt(0)); |
| 1076 LOperand* right = instr->InputAt(1); | 1165 XMMRegister right = ToDoubleRegister(instr->InputAt(1)); |
| 1166 XMMRegister result = ToDoubleRegister(instr->result()); |
| 1077 // Modulo uses a fixed result register. | 1167 // Modulo uses a fixed result register. |
| 1078 ASSERT(instr->op() == Token::MOD || left->Equals(instr->result())); | 1168 ASSERT(instr->op() == Token::MOD || left.is(result)); |
| 1079 switch (instr->op()) { | 1169 switch (instr->op()) { |
| 1080 case Token::ADD: | 1170 case Token::ADD: |
| 1081 __ addsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1171 __ addsd(left, right); |
| 1082 break; | 1172 break; |
| 1083 case Token::SUB: | 1173 case Token::SUB: |
| 1084 __ subsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1174 __ subsd(left, right); |
| 1085 break; | 1175 break; |
| 1086 case Token::MUL: | 1176 case Token::MUL: |
| 1087 __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1177 __ mulsd(left, right); |
| 1088 break; | 1178 break; |
| 1089 case Token::DIV: | 1179 case Token::DIV: |
| 1090 __ divsd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1180 __ divsd(left, right); |
| 1091 break; | 1181 break; |
| 1092 case Token::MOD: { | 1182 case Token::MOD: { |
| 1093 // Pass two doubles as arguments on the stack. | 1183 // Pass two doubles as arguments on the stack. |
| 1094 __ PrepareCallCFunction(4, eax); | 1184 __ PrepareCallCFunction(4, eax); |
| 1095 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left)); | 1185 __ movdbl(Operand(esp, 0 * kDoubleSize), left); |
| 1096 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right)); | 1186 __ movdbl(Operand(esp, 1 * kDoubleSize), right); |
| 1097 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4); | 1187 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4); |
| 1098 | 1188 |
| 1099 // Return value is in st(0) on ia32. | 1189 // Return value is in st(0) on ia32. |
| 1100 // Store it into the (fixed) result register. | 1190 // Store it into the (fixed) result register. |
| 1101 __ sub(Operand(esp), Immediate(kDoubleSize)); | 1191 __ sub(Operand(esp), Immediate(kDoubleSize)); |
| 1102 __ fstp_d(Operand(esp, 0)); | 1192 __ fstp_d(Operand(esp, 0)); |
| 1103 __ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0)); | 1193 __ movdbl(result, Operand(esp, 0)); |
| 1104 __ add(Operand(esp), Immediate(kDoubleSize)); | 1194 __ add(Operand(esp), Immediate(kDoubleSize)); |
| 1105 break; | 1195 break; |
| 1106 } | 1196 } |
| 1107 default: | 1197 default: |
| 1108 UNREACHABLE(); | 1198 UNREACHABLE(); |
| 1109 break; | 1199 break; |
| 1110 } | 1200 } |
| 1111 } | 1201 } |
| 1112 | 1202 |
| 1113 | 1203 |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1570 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1660 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1571 | 1661 |
| 1572 __ test(input, Immediate(kSmiTagMask)); | 1662 __ test(input, Immediate(kSmiTagMask)); |
| 1573 __ j(zero, false_label); | 1663 __ j(zero, false_label); |
| 1574 | 1664 |
| 1575 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); | 1665 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); |
| 1576 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | 1666 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1577 } | 1667 } |
| 1578 | 1668 |
| 1579 | 1669 |
| 1670 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 1671 Register input = ToRegister(instr->InputAt(0)); |
| 1672 Register result = ToRegister(instr->result()); |
| 1673 |
| 1674 if (FLAG_debug_code) { |
| 1675 __ AbortIfNotString(input); |
| 1676 } |
| 1677 |
| 1678 __ mov(result, FieldOperand(input, String::kHashFieldOffset)); |
| 1679 __ IndexFromHash(result, result); |
| 1680 } |
| 1681 |
| 1682 |
| 1580 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | 1683 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
| 1581 Register input = ToRegister(instr->InputAt(0)); | 1684 Register input = ToRegister(instr->InputAt(0)); |
| 1582 Register result = ToRegister(instr->result()); | 1685 Register result = ToRegister(instr->result()); |
| 1583 | 1686 |
| 1584 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | 1687 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1585 __ mov(result, Factory::true_value()); | 1688 __ mov(result, Factory::true_value()); |
| 1586 __ test(FieldOperand(input, String::kHashFieldOffset), | 1689 __ test(FieldOperand(input, String::kHashFieldOffset), |
| 1587 Immediate(String::kContainsCachedArrayIndexMask)); | 1690 Immediate(String::kContainsCachedArrayIndexMask)); |
| 1588 NearLabel done; | 1691 NearLabel done; |
| 1589 __ j(not_zero, &done); | 1692 __ j(zero, &done); |
| 1590 __ mov(result, Factory::false_value()); | 1693 __ mov(result, Factory::false_value()); |
| 1591 __ bind(&done); | 1694 __ bind(&done); |
| 1592 } | 1695 } |
| 1593 | 1696 |
| 1594 | 1697 |
| 1595 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1698 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 1596 LHasCachedArrayIndexAndBranch* instr) { | 1699 LHasCachedArrayIndexAndBranch* instr) { |
| 1597 Register input = ToRegister(instr->InputAt(0)); | 1700 Register input = ToRegister(instr->InputAt(0)); |
| 1598 | 1701 |
| 1599 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1702 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1600 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1703 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1601 | 1704 |
| 1602 __ test(FieldOperand(input, String::kHashFieldOffset), | 1705 __ test(FieldOperand(input, String::kHashFieldOffset), |
| 1603 Immediate(String::kContainsCachedArrayIndexMask)); | 1706 Immediate(String::kContainsCachedArrayIndexMask)); |
| 1604 EmitBranch(true_block, false_block, not_equal); | 1707 EmitBranch(true_block, false_block, equal); |
| 1605 } | 1708 } |
| 1606 | 1709 |
| 1607 | 1710 |
| 1608 // Branches to a label or falls through with the answer in the z flag. Trashes | 1711 // Branches to a label or falls through with the answer in the z flag. Trashes |
| 1609 // the temp registers, but not the input. Only input and temp2 may alias. | 1712 // the temp registers, but not the input. Only input and temp2 may alias. |
| 1610 void LCodeGen::EmitClassOfTest(Label* is_true, | 1713 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1611 Label* is_false, | 1714 Label* is_false, |
| 1612 Handle<String>class_name, | 1715 Handle<String>class_name, |
| 1613 Register input, | 1716 Register input, |
| 1614 Register temp, | 1717 Register temp, |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1826 InstanceofStub stub(flags); | 1929 InstanceofStub stub(flags); |
| 1827 | 1930 |
| 1828 // Get the temp register reserved by the instruction. This needs to be edi as | 1931 // Get the temp register reserved by the instruction. This needs to be edi as |
| 1829 // its slot of the pushing of safepoint registers is used to communicate the | 1932 // its slot of the pushing of safepoint registers is used to communicate the |
| 1830 // offset to the location of the map check. | 1933 // offset to the location of the map check. |
| 1831 Register temp = ToRegister(instr->TempAt(0)); | 1934 Register temp = ToRegister(instr->TempAt(0)); |
| 1832 ASSERT(temp.is(edi)); | 1935 ASSERT(temp.is(edi)); |
| 1833 __ mov(InstanceofStub::right(), Immediate(instr->function())); | 1936 __ mov(InstanceofStub::right(), Immediate(instr->function())); |
| 1834 static const int kAdditionalDelta = 16; | 1937 static const int kAdditionalDelta = 16; |
| 1835 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; | 1938 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; |
| 1836 Label before_push_delta; | |
| 1837 __ bind(&before_push_delta); | |
| 1838 __ mov(temp, Immediate(delta)); | 1939 __ mov(temp, Immediate(delta)); |
| 1839 __ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp); | 1940 __ StoreToSafepointRegisterSlot(temp, temp); |
| 1840 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1941 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false); |
| 1841 __ call(stub.GetCode(), RelocInfo::CODE_TARGET); | |
| 1842 ASSERT_EQ(kAdditionalDelta, | |
| 1843 masm_->SizeOfCodeGeneratedSince(&before_push_delta)); | |
| 1844 RecordSafepointWithRegisters( | |
| 1845 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | |
| 1846 // Put the result value into the eax slot and restore all registers. | 1942 // Put the result value into the eax slot and restore all registers. |
| 1847 __ mov(Operand(esp, EspIndexForPushAll(eax) * kPointerSize), eax); | 1943 __ StoreToSafepointRegisterSlot(eax, eax); |
| 1848 | |
| 1849 __ PopSafepointRegisters(); | 1944 __ PopSafepointRegisters(); |
| 1850 } | 1945 } |
| 1851 | 1946 |
| 1852 | 1947 |
| 1853 static Condition ComputeCompareCondition(Token::Value op) { | 1948 static Condition ComputeCompareCondition(Token::Value op) { |
| 1854 switch (op) { | 1949 switch (op) { |
| 1855 case Token::EQ_STRICT: | 1950 case Token::EQ_STRICT: |
| 1856 case Token::EQ: | 1951 case Token::EQ: |
| 1857 return equal; | 1952 return equal; |
| 1858 case Token::LT: | 1953 case Token::LT: |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 void LCodeGen::DoLoadElements(LLoadElements* instr) { | 2147 void LCodeGen::DoLoadElements(LLoadElements* instr) { |
| 2053 Register result = ToRegister(instr->result()); | 2148 Register result = ToRegister(instr->result()); |
| 2054 Register input = ToRegister(instr->InputAt(0)); | 2149 Register input = ToRegister(instr->InputAt(0)); |
| 2055 __ mov(result, FieldOperand(input, JSObject::kElementsOffset)); | 2150 __ mov(result, FieldOperand(input, JSObject::kElementsOffset)); |
| 2056 if (FLAG_debug_code) { | 2151 if (FLAG_debug_code) { |
| 2057 NearLabel done; | 2152 NearLabel done; |
| 2058 __ cmp(FieldOperand(result, HeapObject::kMapOffset), | 2153 __ cmp(FieldOperand(result, HeapObject::kMapOffset), |
| 2059 Immediate(Factory::fixed_array_map())); | 2154 Immediate(Factory::fixed_array_map())); |
| 2060 __ j(equal, &done); | 2155 __ j(equal, &done); |
| 2061 __ cmp(FieldOperand(result, HeapObject::kMapOffset), | 2156 __ cmp(FieldOperand(result, HeapObject::kMapOffset), |
| 2062 Immediate(Factory::pixel_array_map())); | 2157 Immediate(Factory::external_pixel_array_map())); |
| 2063 __ j(equal, &done); | 2158 __ j(equal, &done); |
| 2064 __ cmp(FieldOperand(result, HeapObject::kMapOffset), | 2159 __ cmp(FieldOperand(result, HeapObject::kMapOffset), |
| 2065 Immediate(Factory::fixed_cow_array_map())); | 2160 Immediate(Factory::fixed_cow_array_map())); |
| 2066 __ Check(equal, "Check for fast elements or pixel array failed."); | 2161 __ Check(equal, "Check for fast elements or pixel array failed."); |
| 2067 __ bind(&done); | 2162 __ bind(&done); |
| 2068 } | 2163 } |
| 2069 } | 2164 } |
| 2070 | 2165 |
| 2071 | 2166 |
| 2072 void LCodeGen::DoLoadPixelArrayExternalPointer( | 2167 void LCodeGen::DoLoadExternalArrayPointer( |
| 2073 LLoadPixelArrayExternalPointer* instr) { | 2168 LLoadExternalArrayPointer* instr) { |
| 2074 Register result = ToRegister(instr->result()); | 2169 Register result = ToRegister(instr->result()); |
| 2075 Register input = ToRegister(instr->InputAt(0)); | 2170 Register input = ToRegister(instr->InputAt(0)); |
| 2076 __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset)); | 2171 __ mov(result, FieldOperand(input, |
| 2172 ExternalArray::kExternalPointerOffset)); |
| 2077 } | 2173 } |
| 2078 | 2174 |
| 2079 | 2175 |
| 2080 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { | 2176 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
| 2081 Register arguments = ToRegister(instr->arguments()); | 2177 Register arguments = ToRegister(instr->arguments()); |
| 2082 Register length = ToRegister(instr->length()); | 2178 Register length = ToRegister(instr->length()); |
| 2083 Operand index = ToOperand(instr->index()); | 2179 Operand index = ToOperand(instr->index()); |
| 2084 Register result = ToRegister(instr->result()); | 2180 Register result = ToRegister(instr->result()); |
| 2085 | 2181 |
| 2086 __ sub(length, index); | 2182 __ sub(length, index); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2104 times_pointer_size, | 2200 times_pointer_size, |
| 2105 FixedArray::kHeaderSize)); | 2201 FixedArray::kHeaderSize)); |
| 2106 | 2202 |
| 2107 // Check for the hole value. | 2203 // Check for the hole value. |
| 2108 __ cmp(result, Factory::the_hole_value()); | 2204 __ cmp(result, Factory::the_hole_value()); |
| 2109 DeoptimizeIf(equal, instr->environment()); | 2205 DeoptimizeIf(equal, instr->environment()); |
| 2110 } | 2206 } |
| 2111 | 2207 |
| 2112 | 2208 |
| 2113 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { | 2209 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { |
| 2114 Register external_elements = ToRegister(instr->external_pointer()); | 2210 Register external_pointer = ToRegister(instr->external_pointer()); |
| 2115 Register key = ToRegister(instr->key()); | 2211 Register key = ToRegister(instr->key()); |
| 2116 Register result = ToRegister(instr->result()); | 2212 Register result = ToRegister(instr->result()); |
| 2117 ASSERT(result.is(external_elements)); | 2213 ASSERT(result.is(external_pointer)); |
| 2118 | 2214 |
| 2119 // Load the result. | 2215 // Load the result. |
| 2120 __ movzx_b(result, Operand(external_elements, key, times_1, 0)); | 2216 __ movzx_b(result, Operand(external_pointer, key, times_1, 0)); |
| 2121 } | 2217 } |
| 2122 | 2218 |
| 2123 | 2219 |
| 2124 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { | 2220 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { |
| 2125 ASSERT(ToRegister(instr->context()).is(esi)); | 2221 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2126 ASSERT(ToRegister(instr->object()).is(edx)); | 2222 ASSERT(ToRegister(instr->object()).is(edx)); |
| 2127 ASSERT(ToRegister(instr->key()).is(eax)); | 2223 ASSERT(ToRegister(instr->key()).is(eax)); |
| 2128 | 2224 |
| 2129 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 2225 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 2130 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2226 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2283 Register result = ToRegister(instr->result()); | 2379 Register result = ToRegister(instr->result()); |
| 2284 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset)); | 2380 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset)); |
| 2285 } | 2381 } |
| 2286 | 2382 |
| 2287 | 2383 |
| 2288 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 2384 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
| 2289 int arity, | 2385 int arity, |
| 2290 LInstruction* instr) { | 2386 LInstruction* instr) { |
| 2291 // Change context if needed. | 2387 // Change context if needed. |
| 2292 bool change_context = | 2388 bool change_context = |
| 2293 (graph()->info()->closure()->context() != function->context()) || | 2389 (info()->closure()->context() != function->context()) || |
| 2294 scope()->contains_with() || | 2390 scope()->contains_with() || |
| 2295 (scope()->num_heap_slots() > 0); | 2391 (scope()->num_heap_slots() > 0); |
| 2296 if (change_context) { | 2392 if (change_context) { |
| 2297 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 2393 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 2298 } else { | 2394 } else { |
| 2299 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2395 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2300 } | 2396 } |
| 2301 | 2397 |
| 2302 // Set eax to arguments count if adaption is not needed. Assumes that eax | 2398 // Set eax to arguments count if adaption is not needed. Assumes that eax |
| 2303 // is available to write to at this point. | 2399 // is available to write to at this point. |
| 2304 if (!function->NeedsArgumentsAdaption()) { | 2400 if (!function->NeedsArgumentsAdaption()) { |
| 2305 __ mov(eax, arity); | 2401 __ mov(eax, arity); |
| 2306 } | 2402 } |
| 2307 | 2403 |
| 2308 LPointerMap* pointers = instr->pointer_map(); | 2404 LPointerMap* pointers = instr->pointer_map(); |
| 2309 RecordPosition(pointers->position()); | 2405 RecordPosition(pointers->position()); |
| 2310 | 2406 |
| 2311 // Invoke function. | 2407 // Invoke function. |
| 2312 if (*function == *graph()->info()->closure()) { | 2408 if (*function == *info()->closure()) { |
| 2313 __ CallSelf(); | 2409 __ CallSelf(); |
| 2314 } else { | 2410 } else { |
| 2315 // This is an indirect call and will not be recorded in the reloc info. | |
| 2316 // Add a comment to the reloc info in case we need to patch this during | |
| 2317 // deoptimization. | |
| 2318 __ RecordComment(RelocInfo::kFillerCommentString, true); | |
| 2319 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); | 2411 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); |
| 2412 EnsureRelocSpaceForDeoptimization(); |
| 2320 } | 2413 } |
| 2321 | 2414 |
| 2322 // Setup deoptimization. | 2415 // Setup deoptimization. |
| 2323 RegisterLazyDeoptimization(instr); | 2416 RegisterLazyDeoptimization(instr); |
| 2324 } | 2417 } |
| 2325 | 2418 |
| 2326 | 2419 |
| 2327 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { | 2420 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { |
| 2328 ASSERT(ToRegister(instr->result()).is(eax)); | 2421 ASSERT(ToRegister(instr->result()).is(eax)); |
| 2329 __ mov(edi, instr->function()); | 2422 __ mov(edi, instr->function()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2364 __ bind(&slow); | 2457 __ bind(&slow); |
| 2365 | 2458 |
| 2366 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2459 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2367 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 2460 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 2368 RecordSafepointWithRegisters( | 2461 RecordSafepointWithRegisters( |
| 2369 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 2462 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2370 // Set the pointer to the new heap number in tmp. | 2463 // Set the pointer to the new heap number in tmp. |
| 2371 if (!tmp.is(eax)) __ mov(tmp, eax); | 2464 if (!tmp.is(eax)) __ mov(tmp, eax); |
| 2372 | 2465 |
| 2373 // Restore input_reg after call to runtime. | 2466 // Restore input_reg after call to runtime. |
| 2374 __ mov(input_reg, Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize)); | 2467 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); |
| 2375 | 2468 |
| 2376 __ bind(&allocated); | 2469 __ bind(&allocated); |
| 2377 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset)); | 2470 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset)); |
| 2378 __ and_(tmp2, ~HeapNumber::kSignMask); | 2471 __ and_(tmp2, ~HeapNumber::kSignMask); |
| 2379 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2); | 2472 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2); |
| 2380 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); | 2473 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); |
| 2381 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2); | 2474 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2); |
| 2382 __ mov(Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize), tmp); | 2475 __ StoreToSafepointRegisterSlot(input_reg, tmp); |
| 2383 | 2476 |
| 2384 __ bind(&done); | 2477 __ bind(&done); |
| 2385 __ PopSafepointRegisters(); | 2478 __ PopSafepointRegisters(); |
| 2386 } | 2479 } |
| 2387 | 2480 |
| 2388 | 2481 |
| 2389 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { | 2482 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { |
| 2390 Register input_reg = ToRegister(instr->InputAt(0)); | 2483 Register input_reg = ToRegister(instr->InputAt(0)); |
| 2391 __ test(input_reg, Operand(input_reg)); | 2484 __ test(input_reg, Operand(input_reg)); |
| 2392 Label is_positive; | 2485 Label is_positive; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2497 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2590 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2498 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); | 2591 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
| 2499 __ sqrtsd(input_reg, input_reg); | 2592 __ sqrtsd(input_reg, input_reg); |
| 2500 } | 2593 } |
| 2501 | 2594 |
| 2502 | 2595 |
| 2503 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { | 2596 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { |
| 2504 XMMRegister xmm_scratch = xmm0; | 2597 XMMRegister xmm_scratch = xmm0; |
| 2505 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 2598 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 2506 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); | 2599 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
| 2507 ExternalReference negative_infinity = | |
| 2508 ExternalReference::address_of_negative_infinity(); | |
| 2509 __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity)); | |
| 2510 __ ucomisd(xmm_scratch, input_reg); | |
| 2511 DeoptimizeIf(equal, instr->environment()); | |
| 2512 __ xorpd(xmm_scratch, xmm_scratch); | 2600 __ xorpd(xmm_scratch, xmm_scratch); |
| 2513 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. | 2601 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. |
| 2514 __ sqrtsd(input_reg, input_reg); | 2602 __ sqrtsd(input_reg, input_reg); |
| 2515 } | 2603 } |
| 2516 | 2604 |
| 2517 | 2605 |
| 2518 void LCodeGen::DoPower(LPower* instr) { | 2606 void LCodeGen::DoPower(LPower* instr) { |
| 2519 LOperand* left = instr->InputAt(0); | 2607 LOperand* left = instr->InputAt(0); |
| 2520 LOperand* right = instr->InputAt(1); | 2608 LOperand* right = instr->InputAt(1); |
| 2521 DoubleRegister result_reg = ToDoubleRegister(instr->result()); | 2609 DoubleRegister result_reg = ToDoubleRegister(instr->result()); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2724 } | 2812 } |
| 2725 } | 2813 } |
| 2726 | 2814 |
| 2727 | 2815 |
| 2728 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 2816 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 2729 ASSERT(ToRegister(instr->context()).is(esi)); | 2817 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2730 ASSERT(ToRegister(instr->object()).is(edx)); | 2818 ASSERT(ToRegister(instr->object()).is(edx)); |
| 2731 ASSERT(ToRegister(instr->value()).is(eax)); | 2819 ASSERT(ToRegister(instr->value()).is(eax)); |
| 2732 | 2820 |
| 2733 __ mov(ecx, instr->name()); | 2821 __ mov(ecx, instr->name()); |
| 2734 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2822 Handle<Code> ic(Builtins::builtin( |
| 2823 info_->is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 2824 : Builtins::StoreIC_Initialize)); |
| 2735 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2825 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2736 } | 2826 } |
| 2737 | 2827 |
| 2738 | 2828 |
| 2739 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { | 2829 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
| 2740 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); | 2830 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); |
| 2741 DeoptimizeIf(above_equal, instr->environment()); | 2831 DeoptimizeIf(above_equal, instr->environment()); |
| 2742 } | 2832 } |
| 2743 | 2833 |
| 2744 | 2834 |
| 2835 void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) { |
| 2836 Register external_pointer = ToRegister(instr->external_pointer()); |
| 2837 Register key = ToRegister(instr->key()); |
| 2838 Register value = ToRegister(instr->value()); |
| 2839 ASSERT(ToRegister(instr->TempAt(0)).is(eax)); |
| 2840 |
| 2841 __ mov(eax, value); |
| 2842 { // Clamp the value to [0..255]. |
| 2843 NearLabel done; |
| 2844 __ test(eax, Immediate(0xFFFFFF00)); |
| 2845 __ j(zero, &done); |
| 2846 __ setcc(negative, eax); // 1 if negative, 0 if positive. |
| 2847 __ dec_b(eax); // 0 if negative, 255 if positive. |
| 2848 __ bind(&done); |
| 2849 } |
| 2850 __ mov_b(Operand(external_pointer, key, times_1, 0), eax); |
| 2851 } |
| 2852 |
| 2853 |
| 2745 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { | 2854 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { |
| 2746 Register value = ToRegister(instr->value()); | 2855 Register value = ToRegister(instr->value()); |
| 2747 Register elements = ToRegister(instr->object()); | 2856 Register elements = ToRegister(instr->object()); |
| 2748 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; | 2857 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; |
| 2749 | 2858 |
| 2750 // Do the store. | 2859 // Do the store. |
| 2751 if (instr->key()->IsConstantOperand()) { | 2860 if (instr->key()->IsConstantOperand()) { |
| 2752 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); | 2861 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 2753 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); | 2862 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); |
| 2754 int offset = | 2863 int offset = |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2773 } | 2882 } |
| 2774 } | 2883 } |
| 2775 | 2884 |
| 2776 | 2885 |
| 2777 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 2886 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 2778 ASSERT(ToRegister(instr->context()).is(esi)); | 2887 ASSERT(ToRegister(instr->context()).is(esi)); |
| 2779 ASSERT(ToRegister(instr->object()).is(edx)); | 2888 ASSERT(ToRegister(instr->object()).is(edx)); |
| 2780 ASSERT(ToRegister(instr->key()).is(ecx)); | 2889 ASSERT(ToRegister(instr->key()).is(ecx)); |
| 2781 ASSERT(ToRegister(instr->value()).is(eax)); | 2890 ASSERT(ToRegister(instr->value()).is(eax)); |
| 2782 | 2891 |
| 2783 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 2892 Handle<Code> ic(Builtins::builtin( |
| 2893 info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 2894 : Builtins::KeyedStoreIC_Initialize)); |
| 2784 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2895 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2785 } | 2896 } |
| 2786 | 2897 |
| 2787 | 2898 |
| 2788 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 2899 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 2789 class DeferredStringCharCodeAt: public LDeferredCode { | 2900 class DeferredStringCharCodeAt: public LDeferredCode { |
| 2790 public: | 2901 public: |
| 2791 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 2902 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 2792 : LDeferredCode(codegen), instr_(instr) { } | 2903 : LDeferredCode(codegen), instr_(instr) { } |
| 2793 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | 2904 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2844 __ j(not_equal, deferred->entry()); | 2955 __ j(not_equal, deferred->entry()); |
| 2845 // Get the first of the two strings and load its instance type. | 2956 // Get the first of the two strings and load its instance type. |
| 2846 __ mov(string, FieldOperand(string, ConsString::kFirstOffset)); | 2957 __ mov(string, FieldOperand(string, ConsString::kFirstOffset)); |
| 2847 __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); | 2958 __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); |
| 2848 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | 2959 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); |
| 2849 // If the first cons component is also non-flat, then go to runtime. | 2960 // If the first cons component is also non-flat, then go to runtime. |
| 2850 STATIC_ASSERT(kSeqStringTag == 0); | 2961 STATIC_ASSERT(kSeqStringTag == 0); |
| 2851 __ test(result, Immediate(kStringRepresentationMask)); | 2962 __ test(result, Immediate(kStringRepresentationMask)); |
| 2852 __ j(not_zero, deferred->entry()); | 2963 __ j(not_zero, deferred->entry()); |
| 2853 | 2964 |
| 2854 // Check for 1-byte or 2-byte string. | 2965 // Check for ASCII or two-byte string. |
| 2855 __ bind(&flat_string); | 2966 __ bind(&flat_string); |
| 2856 STATIC_ASSERT(kAsciiStringTag != 0); | 2967 STATIC_ASSERT(kAsciiStringTag != 0); |
| 2857 __ test(result, Immediate(kStringEncodingMask)); | 2968 __ test(result, Immediate(kStringEncodingMask)); |
| 2858 __ j(not_zero, &ascii_string); | 2969 __ j(not_zero, &ascii_string); |
| 2859 | 2970 |
| 2860 // 2-byte string. | 2971 // Two-byte string. |
| 2861 // Load the 2-byte character code into the result register. | 2972 // Load the two-byte character code into the result register. |
| 2862 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 2973 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 2863 if (instr->index()->IsConstantOperand()) { | 2974 if (instr->index()->IsConstantOperand()) { |
| 2864 __ movzx_w(result, | 2975 __ movzx_w(result, |
| 2865 FieldOperand(string, | 2976 FieldOperand(string, |
| 2866 SeqTwoByteString::kHeaderSize + 2 * const_index)); | 2977 SeqTwoByteString::kHeaderSize + |
| 2978 (kUC16Size * const_index))); |
| 2867 } else { | 2979 } else { |
| 2868 __ movzx_w(result, FieldOperand(string, | 2980 __ movzx_w(result, FieldOperand(string, |
| 2869 index, | 2981 index, |
| 2870 times_2, | 2982 times_2, |
| 2871 SeqTwoByteString::kHeaderSize)); | 2983 SeqTwoByteString::kHeaderSize)); |
| 2872 } | 2984 } |
| 2873 __ jmp(&done); | 2985 __ jmp(&done); |
| 2874 | 2986 |
| 2875 // ASCII string. | 2987 // ASCII string. |
| 2876 // Load the byte into the result register. | 2988 // Load the byte into the result register. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2912 __ push(index); | 3024 __ push(index); |
| 2913 } | 3025 } |
| 2914 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3026 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2915 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); | 3027 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); |
| 2916 RecordSafepointWithRegisters( | 3028 RecordSafepointWithRegisters( |
| 2917 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); | 3029 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); |
| 2918 if (FLAG_debug_code) { | 3030 if (FLAG_debug_code) { |
| 2919 __ AbortIfNotSmi(eax); | 3031 __ AbortIfNotSmi(eax); |
| 2920 } | 3032 } |
| 2921 __ SmiUntag(eax); | 3033 __ SmiUntag(eax); |
| 2922 __ mov(Operand(esp, EspIndexForPushAll(result) * kPointerSize), eax); | 3034 __ StoreToSafepointRegisterSlot(result, eax); |
| 3035 __ PopSafepointRegisters(); |
| 3036 } |
| 3037 |
| 3038 |
| 3039 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { |
| 3040 class DeferredStringCharFromCode: public LDeferredCode { |
| 3041 public: |
| 3042 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) |
| 3043 : LDeferredCode(codegen), instr_(instr) { } |
| 3044 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } |
| 3045 private: |
| 3046 LStringCharFromCode* instr_; |
| 3047 }; |
| 3048 |
| 3049 DeferredStringCharFromCode* deferred = |
| 3050 new DeferredStringCharFromCode(this, instr); |
| 3051 |
| 3052 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
| 3053 Register char_code = ToRegister(instr->char_code()); |
| 3054 Register result = ToRegister(instr->result()); |
| 3055 ASSERT(!char_code.is(result)); |
| 3056 |
| 3057 __ cmp(char_code, String::kMaxAsciiCharCode); |
| 3058 __ j(above, deferred->entry()); |
| 3059 __ Set(result, Immediate(Factory::single_character_string_cache())); |
| 3060 __ mov(result, FieldOperand(result, |
| 3061 char_code, times_pointer_size, |
| 3062 FixedArray::kHeaderSize)); |
| 3063 __ cmp(result, Factory::undefined_value()); |
| 3064 __ j(equal, deferred->entry()); |
| 3065 __ bind(deferred->exit()); |
| 3066 } |
| 3067 |
| 3068 |
| 3069 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { |
| 3070 Register char_code = ToRegister(instr->char_code()); |
| 3071 Register result = ToRegister(instr->result()); |
| 3072 |
| 3073 // TODO(3095996): Get rid of this. For now, we need to make the |
| 3074 // result register contain a valid pointer because it is already |
| 3075 // contained in the register pointer map. |
| 3076 __ Set(result, Immediate(0)); |
| 3077 |
| 3078 __ PushSafepointRegisters(); |
| 3079 __ SmiTag(char_code); |
| 3080 __ push(char_code); |
| 3081 __ CallRuntimeSaveDoubles(Runtime::kCharFromCode); |
| 3082 RecordSafepointWithRegisters( |
| 3083 instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex); |
| 3084 __ StoreToSafepointRegisterSlot(result, eax); |
| 2923 __ PopSafepointRegisters(); | 3085 __ PopSafepointRegisters(); |
| 2924 } | 3086 } |
| 2925 | 3087 |
| 2926 | 3088 |
| 2927 void LCodeGen::DoStringLength(LStringLength* instr) { | 3089 void LCodeGen::DoStringLength(LStringLength* instr) { |
| 2928 Register string = ToRegister(instr->string()); | 3090 Register string = ToRegister(instr->string()); |
| 2929 Register result = ToRegister(instr->result()); | 3091 Register result = ToRegister(instr->result()); |
| 2930 __ mov(result, FieldOperand(string, String::kLengthOffset)); | 3092 __ mov(result, FieldOperand(string, String::kLengthOffset)); |
| 2931 } | 3093 } |
| 2932 | 3094 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2980 __ AllocateHeapNumber(reg, tmp, no_reg, &slow); | 3142 __ AllocateHeapNumber(reg, tmp, no_reg, &slow); |
| 2981 __ jmp(&done); | 3143 __ jmp(&done); |
| 2982 } | 3144 } |
| 2983 | 3145 |
| 2984 // Slow case: Call the runtime system to do the number allocation. | 3146 // Slow case: Call the runtime system to do the number allocation. |
| 2985 __ bind(&slow); | 3147 __ bind(&slow); |
| 2986 | 3148 |
| 2987 // TODO(3095996): Put a valid pointer value in the stack slot where the result | 3149 // TODO(3095996): Put a valid pointer value in the stack slot where the result |
| 2988 // register is stored, as this register is in the pointer map, but contains an | 3150 // register is stored, as this register is in the pointer map, but contains an |
| 2989 // integer value. | 3151 // integer value. |
| 2990 __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), Immediate(0)); | 3152 __ StoreToSafepointRegisterSlot(reg, Immediate(0)); |
| 2991 | 3153 |
| 2992 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3154 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2993 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 3155 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 2994 RecordSafepointWithRegisters( | 3156 RecordSafepointWithRegisters( |
| 2995 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 3157 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2996 if (!reg.is(eax)) __ mov(reg, eax); | 3158 if (!reg.is(eax)) __ mov(reg, eax); |
| 2997 | 3159 |
| 2998 // Done. Put the value in xmm0 into the value of the allocated heap | 3160 // Done. Put the value in xmm0 into the value of the allocated heap |
| 2999 // number. | 3161 // number. |
| 3000 __ bind(&done); | 3162 __ bind(&done); |
| 3001 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); | 3163 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0); |
| 3002 __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), reg); | 3164 __ StoreToSafepointRegisterSlot(reg, reg); |
| 3003 __ PopSafepointRegisters(); | 3165 __ PopSafepointRegisters(); |
| 3004 } | 3166 } |
| 3005 | 3167 |
| 3006 | 3168 |
| 3007 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 3169 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| 3008 class DeferredNumberTagD: public LDeferredCode { | 3170 class DeferredNumberTagD: public LDeferredCode { |
| 3009 public: | 3171 public: |
| 3010 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 3172 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 3011 : LDeferredCode(codegen), instr_(instr) { } | 3173 : LDeferredCode(codegen), instr_(instr) { } |
| 3012 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 3174 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3034 // result register contain a valid pointer because it is already | 3196 // result register contain a valid pointer because it is already |
| 3035 // contained in the register pointer map. | 3197 // contained in the register pointer map. |
| 3036 Register reg = ToRegister(instr->result()); | 3198 Register reg = ToRegister(instr->result()); |
| 3037 __ Set(reg, Immediate(0)); | 3199 __ Set(reg, Immediate(0)); |
| 3038 | 3200 |
| 3039 __ PushSafepointRegisters(); | 3201 __ PushSafepointRegisters(); |
| 3040 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3202 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3041 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 3203 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 3042 RecordSafepointWithRegisters( | 3204 RecordSafepointWithRegisters( |
| 3043 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 3205 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 3044 __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), eax); | 3206 __ StoreToSafepointRegisterSlot(reg, eax); |
| 3045 __ PopSafepointRegisters(); | 3207 __ PopSafepointRegisters(); |
| 3046 } | 3208 } |
| 3047 | 3209 |
| 3048 | 3210 |
| 3049 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 3211 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 3050 LOperand* input = instr->InputAt(0); | 3212 LOperand* input = instr->InputAt(0); |
| 3051 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3213 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 3052 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); | 3214 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); |
| 3053 __ SmiTag(ToRegister(input)); | 3215 __ SmiTag(ToRegister(input)); |
| 3054 } | 3216 } |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3606 EmitBranch(true_block, false_block, final_branch_condition); | 3768 EmitBranch(true_block, false_block, final_branch_condition); |
| 3607 } | 3769 } |
| 3608 | 3770 |
| 3609 | 3771 |
| 3610 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 3772 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 3611 Label* false_label, | 3773 Label* false_label, |
| 3612 Register input, | 3774 Register input, |
| 3613 Handle<String> type_name) { | 3775 Handle<String> type_name) { |
| 3614 Condition final_branch_condition = no_condition; | 3776 Condition final_branch_condition = no_condition; |
| 3615 if (type_name->Equals(Heap::number_symbol())) { | 3777 if (type_name->Equals(Heap::number_symbol())) { |
| 3616 __ test(input, Immediate(kSmiTagMask)); | 3778 __ JumpIfSmi(input, true_label); |
| 3617 __ j(zero, true_label); | |
| 3618 __ cmp(FieldOperand(input, HeapObject::kMapOffset), | 3779 __ cmp(FieldOperand(input, HeapObject::kMapOffset), |
| 3619 Factory::heap_number_map()); | 3780 Factory::heap_number_map()); |
| 3620 final_branch_condition = equal; | 3781 final_branch_condition = equal; |
| 3621 | 3782 |
| 3622 } else if (type_name->Equals(Heap::string_symbol())) { | 3783 } else if (type_name->Equals(Heap::string_symbol())) { |
| 3623 __ test(input, Immediate(kSmiTagMask)); | 3784 __ JumpIfSmi(input, false_label); |
| 3624 __ j(zero, false_label); | 3785 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); |
| 3625 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); | 3786 __ j(above_equal, false_label); |
| 3626 __ test_b(FieldOperand(input, Map::kBitFieldOffset), | 3787 __ test_b(FieldOperand(input, Map::kBitFieldOffset), |
| 3627 1 << Map::kIsUndetectable); | 3788 1 << Map::kIsUndetectable); |
| 3628 __ j(not_zero, false_label); | 3789 final_branch_condition = zero; |
| 3629 __ CmpInstanceType(input, FIRST_NONSTRING_TYPE); | |
| 3630 final_branch_condition = below; | |
| 3631 | 3790 |
| 3632 } else if (type_name->Equals(Heap::boolean_symbol())) { | 3791 } else if (type_name->Equals(Heap::boolean_symbol())) { |
| 3633 __ cmp(input, Factory::true_value()); | 3792 __ cmp(input, Factory::true_value()); |
| 3634 __ j(equal, true_label); | 3793 __ j(equal, true_label); |
| 3635 __ cmp(input, Factory::false_value()); | 3794 __ cmp(input, Factory::false_value()); |
| 3636 final_branch_condition = equal; | 3795 final_branch_condition = equal; |
| 3637 | 3796 |
| 3638 } else if (type_name->Equals(Heap::undefined_symbol())) { | 3797 } else if (type_name->Equals(Heap::undefined_symbol())) { |
| 3639 __ cmp(input, Factory::undefined_value()); | 3798 __ cmp(input, Factory::undefined_value()); |
| 3640 __ j(equal, true_label); | 3799 __ j(equal, true_label); |
| 3641 __ test(input, Immediate(kSmiTagMask)); | 3800 __ JumpIfSmi(input, false_label); |
| 3642 __ j(zero, false_label); | |
| 3643 // Check for undetectable objects => true. | 3801 // Check for undetectable objects => true. |
| 3644 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); | 3802 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 3645 __ test_b(FieldOperand(input, Map::kBitFieldOffset), | 3803 __ test_b(FieldOperand(input, Map::kBitFieldOffset), |
| 3646 1 << Map::kIsUndetectable); | 3804 1 << Map::kIsUndetectable); |
| 3647 final_branch_condition = not_zero; | 3805 final_branch_condition = not_zero; |
| 3648 | 3806 |
| 3649 } else if (type_name->Equals(Heap::function_symbol())) { | 3807 } else if (type_name->Equals(Heap::function_symbol())) { |
| 3650 __ test(input, Immediate(kSmiTagMask)); | 3808 __ JumpIfSmi(input, false_label); |
| 3651 __ j(zero, false_label); | |
| 3652 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); | 3809 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); |
| 3653 __ j(equal, true_label); | 3810 __ j(equal, true_label); |
| 3654 // Regular expressions => 'function' (they are callable). | 3811 // Regular expressions => 'function' (they are callable). |
| 3655 __ CmpInstanceType(input, JS_REGEXP_TYPE); | 3812 __ CmpInstanceType(input, JS_REGEXP_TYPE); |
| 3656 final_branch_condition = equal; | 3813 final_branch_condition = equal; |
| 3657 | 3814 |
| 3658 } else if (type_name->Equals(Heap::object_symbol())) { | 3815 } else if (type_name->Equals(Heap::object_symbol())) { |
| 3659 __ test(input, Immediate(kSmiTagMask)); | 3816 __ JumpIfSmi(input, false_label); |
| 3660 __ j(zero, false_label); | |
| 3661 __ cmp(input, Factory::null_value()); | 3817 __ cmp(input, Factory::null_value()); |
| 3662 __ j(equal, true_label); | 3818 __ j(equal, true_label); |
| 3663 // Regular expressions => 'function', not 'object'. | 3819 // Regular expressions => 'function', not 'object'. |
| 3664 __ CmpObjectType(input, JS_REGEXP_TYPE, input); | 3820 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input); |
| 3665 __ j(equal, false_label); | 3821 __ j(below, false_label); |
| 3822 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE); |
| 3823 __ j(above_equal, false_label); |
| 3666 // Check for undetectable objects => false. | 3824 // Check for undetectable objects => false. |
| 3667 __ test_b(FieldOperand(input, Map::kBitFieldOffset), | 3825 __ test_b(FieldOperand(input, Map::kBitFieldOffset), |
| 3668 1 << Map::kIsUndetectable); | 3826 1 << Map::kIsUndetectable); |
| 3669 __ j(not_zero, false_label); | 3827 final_branch_condition = zero; |
| 3670 // Check for JS objects => true. | |
| 3671 __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE); | |
| 3672 __ j(below, false_label); | |
| 3673 __ CmpInstanceType(input, LAST_JS_OBJECT_TYPE); | |
| 3674 final_branch_condition = below_equal; | |
| 3675 | 3828 |
| 3676 } else { | 3829 } else { |
| 3677 final_branch_condition = not_equal; | 3830 final_branch_condition = not_equal; |
| 3678 __ jmp(false_label); | 3831 __ jmp(false_label); |
| 3679 // A dead branch instruction will be generated after this point. | 3832 // A dead branch instruction will be generated after this point. |
| 3680 } | 3833 } |
| 3681 | 3834 |
| 3682 return final_branch_condition; | 3835 return final_branch_condition; |
| 3683 } | 3836 } |
| 3684 | 3837 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3796 ASSERT(osr_pc_offset_ == -1); | 3949 ASSERT(osr_pc_offset_ == -1); |
| 3797 osr_pc_offset_ = masm()->pc_offset(); | 3950 osr_pc_offset_ = masm()->pc_offset(); |
| 3798 } | 3951 } |
| 3799 | 3952 |
| 3800 | 3953 |
| 3801 #undef __ | 3954 #undef __ |
| 3802 | 3955 |
| 3803 } } // namespace v8::internal | 3956 } } // namespace v8::internal |
| 3804 | 3957 |
| 3805 #endif // V8_TARGET_ARCH_IA32 | 3958 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |