| 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "arm/lithium-codegen-arm.h" | 28 #include "arm/lithium-codegen-arm.h" |
| 29 #include "arm/lithium-gap-resolver-arm.h" |
| 29 #include "code-stubs.h" | 30 #include "code-stubs.h" |
| 30 #include "stub-cache.h" | 31 #include "stub-cache.h" |
| 31 | 32 |
| 32 namespace v8 { | 33 namespace v8 { |
| 33 namespace internal { | 34 namespace internal { |
| 34 | 35 |
| 35 | 36 |
| 36 class SafepointGenerator : public PostCallGenerator { | 37 class SafepointGenerator : public CallWrapper { |
| 37 public: | 38 public: |
| 38 SafepointGenerator(LCodeGen* codegen, | 39 SafepointGenerator(LCodeGen* codegen, |
| 39 LPointerMap* pointers, | 40 LPointerMap* pointers, |
| 40 int deoptimization_index) | 41 int deoptimization_index) |
| 41 : codegen_(codegen), | 42 : codegen_(codegen), |
| 42 pointers_(pointers), | 43 pointers_(pointers), |
| 43 deoptimization_index_(deoptimization_index) { } | 44 deoptimization_index_(deoptimization_index) { } |
| 44 virtual ~SafepointGenerator() { } | 45 virtual ~SafepointGenerator() { } |
| 45 | 46 |
| 46 virtual void Generate() { | 47 virtual void BeforeCall(int call_size) { |
| 48 ASSERT(call_size >= 0); |
| 49 // Ensure that we have enough space after the previous safepoint position |
| 50 // for the generated code there. |
| 51 int call_end = codegen_->masm()->pc_offset() + call_size; |
| 52 int prev_jump_end = |
| 53 codegen_->LastSafepointEnd() + Deoptimizer::patch_size(); |
| 54 if (call_end < prev_jump_end) { |
| 55 int padding_size = prev_jump_end - call_end; |
| 56 ASSERT_EQ(0, padding_size % Assembler::kInstrSize); |
| 57 while (padding_size > 0) { |
| 58 codegen_->masm()->nop(); |
| 59 padding_size -= Assembler::kInstrSize; |
| 60 } |
| 61 } |
| 62 } |
| 63 |
| 64 virtual void AfterCall() { |
| 47 codegen_->RecordSafepoint(pointers_, deoptimization_index_); | 65 codegen_->RecordSafepoint(pointers_, deoptimization_index_); |
| 48 } | 66 } |
| 49 | 67 |
| 50 private: | 68 private: |
| 51 LCodeGen* codegen_; | 69 LCodeGen* codegen_; |
| 52 LPointerMap* pointers_; | 70 LPointerMap* pointers_; |
| 53 int deoptimization_index_; | 71 int deoptimization_index_; |
| 54 }; | 72 }; |
| 55 | 73 |
| 56 | 74 |
| 57 class LGapNode: public ZoneObject { | |
| 58 public: | |
| 59 explicit LGapNode(LOperand* operand) | |
| 60 : operand_(operand), resolved_(false), visited_id_(-1) { } | |
| 61 | |
| 62 LOperand* operand() const { return operand_; } | |
| 63 bool IsResolved() const { return !IsAssigned() || resolved_; } | |
| 64 void MarkResolved() { | |
| 65 ASSERT(!IsResolved()); | |
| 66 resolved_ = true; | |
| 67 } | |
| 68 int visited_id() const { return visited_id_; } | |
| 69 void set_visited_id(int id) { | |
| 70 ASSERT(id > visited_id_); | |
| 71 visited_id_ = id; | |
| 72 } | |
| 73 | |
| 74 bool IsAssigned() const { return assigned_from_.is_set(); } | |
| 75 LGapNode* assigned_from() const { return assigned_from_.get(); } | |
| 76 void set_assigned_from(LGapNode* n) { assigned_from_.set(n); } | |
| 77 | |
| 78 private: | |
| 79 LOperand* operand_; | |
| 80 SetOncePointer<LGapNode> assigned_from_; | |
| 81 bool resolved_; | |
| 82 int visited_id_; | |
| 83 }; | |
| 84 | |
| 85 | |
| 86 LGapResolver::LGapResolver() | |
| 87 : nodes_(32), | |
| 88 identified_cycles_(4), | |
| 89 result_(16), | |
| 90 next_visited_id_(0) { | |
| 91 } | |
| 92 | |
| 93 | |
| 94 const ZoneList<LMoveOperands>* LGapResolver::Resolve( | |
| 95 const ZoneList<LMoveOperands>* moves, | |
| 96 LOperand* marker_operand) { | |
| 97 nodes_.Rewind(0); | |
| 98 identified_cycles_.Rewind(0); | |
| 99 result_.Rewind(0); | |
| 100 next_visited_id_ = 0; | |
| 101 | |
| 102 for (int i = 0; i < moves->length(); ++i) { | |
| 103 LMoveOperands move = moves->at(i); | |
| 104 if (!move.IsRedundant()) RegisterMove(move); | |
| 105 } | |
| 106 | |
| 107 for (int i = 0; i < identified_cycles_.length(); ++i) { | |
| 108 ResolveCycle(identified_cycles_[i], marker_operand); | |
| 109 } | |
| 110 | |
| 111 int unresolved_nodes; | |
| 112 do { | |
| 113 unresolved_nodes = 0; | |
| 114 for (int j = 0; j < nodes_.length(); j++) { | |
| 115 LGapNode* node = nodes_[j]; | |
| 116 if (!node->IsResolved() && node->assigned_from()->IsResolved()) { | |
| 117 AddResultMove(node->assigned_from(), node); | |
| 118 node->MarkResolved(); | |
| 119 } | |
| 120 if (!node->IsResolved()) ++unresolved_nodes; | |
| 121 } | |
| 122 } while (unresolved_nodes > 0); | |
| 123 return &result_; | |
| 124 } | |
| 125 | |
| 126 | |
| 127 void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) { | |
| 128 AddResultMove(from->operand(), to->operand()); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 void LGapResolver::AddResultMove(LOperand* from, LOperand* to) { | |
| 133 result_.Add(LMoveOperands(from, to)); | |
| 134 } | |
| 135 | |
| 136 | |
| 137 void LGapResolver::ResolveCycle(LGapNode* start, LOperand* marker_operand) { | |
| 138 ZoneList<LOperand*> cycle_operands(8); | |
| 139 cycle_operands.Add(marker_operand); | |
| 140 LGapNode* cur = start; | |
| 141 do { | |
| 142 cur->MarkResolved(); | |
| 143 cycle_operands.Add(cur->operand()); | |
| 144 cur = cur->assigned_from(); | |
| 145 } while (cur != start); | |
| 146 cycle_operands.Add(marker_operand); | |
| 147 | |
| 148 for (int i = cycle_operands.length() - 1; i > 0; --i) { | |
| 149 LOperand* from = cycle_operands[i]; | |
| 150 LOperand* to = cycle_operands[i - 1]; | |
| 151 AddResultMove(from, to); | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 | |
| 156 bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) { | |
| 157 ASSERT(a != b); | |
| 158 LGapNode* cur = a; | |
| 159 while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) { | |
| 160 cur->set_visited_id(visited_id); | |
| 161 cur = cur->assigned_from(); | |
| 162 } | |
| 163 | |
| 164 return cur == b; | |
| 165 } | |
| 166 | |
| 167 | |
| 168 bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) { | |
| 169 ASSERT(a != b); | |
| 170 return CanReach(a, b, next_visited_id_++); | |
| 171 } | |
| 172 | |
| 173 | |
| 174 void LGapResolver::RegisterMove(LMoveOperands move) { | |
| 175 if (move.source()->IsConstantOperand()) { | |
| 176 // Constant moves should be last in the machine code. Therefore add them | |
| 177 // first to the result set. | |
| 178 AddResultMove(move.source(), move.destination()); | |
| 179 } else { | |
| 180 LGapNode* from = LookupNode(move.source()); | |
| 181 LGapNode* to = LookupNode(move.destination()); | |
| 182 if (to->IsAssigned() && to->assigned_from() == from) { | |
| 183 move.Eliminate(); | |
| 184 return; | |
| 185 } | |
| 186 ASSERT(!to->IsAssigned()); | |
| 187 if (CanReach(from, to)) { | |
| 188 // This introduces a cycle. Save. | |
| 189 identified_cycles_.Add(from); | |
| 190 } | |
| 191 to->set_assigned_from(from); | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 | |
| 196 LGapNode* LGapResolver::LookupNode(LOperand* operand) { | |
| 197 for (int i = 0; i < nodes_.length(); ++i) { | |
| 198 if (nodes_[i]->operand()->Equals(operand)) return nodes_[i]; | |
| 199 } | |
| 200 | |
| 201 // No node found => create a new one. | |
| 202 LGapNode* result = new LGapNode(operand); | |
| 203 nodes_.Add(result); | |
| 204 return result; | |
| 205 } | |
| 206 | |
| 207 | |
| 208 #define __ masm()-> | 75 #define __ masm()-> |
| 209 | 76 |
| 210 bool LCodeGen::GenerateCode() { | 77 bool LCodeGen::GenerateCode() { |
| 211 HPhase phase("Code generation", chunk()); | 78 HPhase phase("Code generation", chunk()); |
| 212 ASSERT(is_unused()); | 79 ASSERT(is_unused()); |
| 213 status_ = GENERATING; | 80 status_ = GENERATING; |
| 214 CpuFeatures::Scope scope1(VFP3); | 81 CpuFeatures::Scope scope1(VFP3); |
| 215 CpuFeatures::Scope scope2(ARMv7); | 82 CpuFeatures::Scope scope2(ARMv7); |
| 216 return GeneratePrologue() && | 83 return GeneratePrologue() && |
| 217 GenerateBody() && | 84 GenerateBody() && |
| 218 GenerateDeferredCode() && | 85 GenerateDeferredCode() && |
| 219 GenerateSafepointTable(); | 86 GenerateSafepointTable(); |
| 220 } | 87 } |
| 221 | 88 |
| 222 | 89 |
| 223 void LCodeGen::FinishCode(Handle<Code> code) { | 90 void LCodeGen::FinishCode(Handle<Code> code) { |
| 224 ASSERT(is_done()); | 91 ASSERT(is_done()); |
| 225 code->set_stack_slots(StackSlotCount()); | 92 code->set_stack_slots(StackSlotCount()); |
| 226 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); | 93 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); |
| 227 PopulateDeoptimizationData(code); | 94 PopulateDeoptimizationData(code); |
| 228 } | 95 } |
| 229 | 96 |
| 230 | 97 |
| 231 void LCodeGen::Abort(const char* format, ...) { | 98 void LCodeGen::Abort(const char* format, ...) { |
| 232 if (FLAG_trace_bailout) { | 99 if (FLAG_trace_bailout) { |
| 233 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 100 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 234 PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name); | 101 PrintF("Aborting LCodeGen in @\"%s\": ", *name); |
| 235 va_list arguments; | 102 va_list arguments; |
| 236 va_start(arguments, format); | 103 va_start(arguments, format); |
| 237 OS::VPrint(format, arguments); | 104 OS::VPrint(format, arguments); |
| 238 va_end(arguments); | 105 va_end(arguments); |
| 239 PrintF("\n"); | 106 PrintF("\n"); |
| 240 } | 107 } |
| 241 status_ = ABORTED; | 108 status_ = ABORTED; |
| 242 } | 109 } |
| 243 | 110 |
| 244 | 111 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 287 Label loop; | 154 Label loop; |
| 288 __ bind(&loop); | 155 __ bind(&loop); |
| 289 __ push(r2); | 156 __ push(r2); |
| 290 __ sub(r0, r0, Operand(1), SetCC); | 157 __ sub(r0, r0, Operand(1), SetCC); |
| 291 __ b(ne, &loop); | 158 __ b(ne, &loop); |
| 292 } else { | 159 } else { |
| 293 __ sub(sp, sp, Operand(slots * kPointerSize)); | 160 __ sub(sp, sp, Operand(slots * kPointerSize)); |
| 294 } | 161 } |
| 295 } | 162 } |
| 296 | 163 |
| 164 // Possibly allocate a local context. |
| 165 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 166 if (heap_slots > 0) { |
| 167 Comment(";;; Allocate local context"); |
| 168 // Argument to NewContext is the function, which is in r1. |
| 169 __ push(r1); |
| 170 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 171 FastNewContextStub stub(heap_slots); |
| 172 __ CallStub(&stub); |
| 173 } else { |
| 174 __ CallRuntime(Runtime::kNewContext, 1); |
| 175 } |
| 176 RecordSafepoint(Safepoint::kNoDeoptimizationIndex); |
| 177 // Context is returned in both r0 and cp. It replaces the context |
| 178 // passed to us. It's saved in the stack and kept live in cp. |
| 179 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 180 // Copy any necessary parameters into the context. |
| 181 int num_parameters = scope()->num_parameters(); |
| 182 for (int i = 0; i < num_parameters; i++) { |
| 183 Slot* slot = scope()->parameter(i)->AsSlot(); |
| 184 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 185 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 186 (num_parameters - 1 - i) * kPointerSize; |
| 187 // Load parameter from stack. |
| 188 __ ldr(r0, MemOperand(fp, parameter_offset)); |
| 189 // Store it in the context. |
| 190 __ mov(r1, Operand(Context::SlotOffset(slot->index()))); |
| 191 __ str(r0, MemOperand(cp, r1)); |
| 192 // Update the write barrier. This clobbers all involved |
| 193 // registers, so we have to use two more registers to avoid |
| 194 // clobbering cp. |
| 195 __ mov(r2, Operand(cp)); |
| 196 __ RecordWrite(r2, Operand(r1), r3, r0); |
| 197 } |
| 198 } |
| 199 Comment(";;; End allocate local context"); |
| 200 } |
| 201 |
| 297 // Trace the call. | 202 // Trace the call. |
| 298 if (FLAG_trace) { | 203 if (FLAG_trace) { |
| 299 __ CallRuntime(Runtime::kTraceEnter, 0); | 204 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 300 } | 205 } |
| 301 return !is_aborted(); | 206 return !is_aborted(); |
| 302 } | 207 } |
| 303 | 208 |
| 304 | 209 |
| 305 bool LCodeGen::GenerateBody() { | 210 bool LCodeGen::GenerateBody() { |
| 306 ASSERT(is_generating()); | 211 ASSERT(is_generating()); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 Abort("ToOperand IsDoubleRegister unimplemented"); | 362 Abort("ToOperand IsDoubleRegister unimplemented"); |
| 458 return Operand(0); | 363 return Operand(0); |
| 459 } | 364 } |
| 460 // Stack slots not implemented, use ToMemOperand instead. | 365 // Stack slots not implemented, use ToMemOperand instead. |
| 461 UNREACHABLE(); | 366 UNREACHABLE(); |
| 462 return Operand(0); | 367 return Operand(0); |
| 463 } | 368 } |
| 464 | 369 |
| 465 | 370 |
| 466 MemOperand LCodeGen::ToMemOperand(LOperand* op) const { | 371 MemOperand LCodeGen::ToMemOperand(LOperand* op) const { |
| 467 // TODO(regis): Revisit. | |
| 468 ASSERT(!op->IsRegister()); | 372 ASSERT(!op->IsRegister()); |
| 469 ASSERT(!op->IsDoubleRegister()); | 373 ASSERT(!op->IsDoubleRegister()); |
| 470 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); | 374 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); |
| 471 int index = op->index(); | 375 int index = op->index(); |
| 472 if (index >= 0) { | 376 if (index >= 0) { |
| 473 // Local or spill slot. Skip the frame pointer, function, and | 377 // Local or spill slot. Skip the frame pointer, function, and |
| 474 // context in the fixed part of the frame. | 378 // context in the fixed part of the frame. |
| 475 return MemOperand(fp, -(index + 3) * kPointerSize); | 379 return MemOperand(fp, -(index + 3) * kPointerSize); |
| 476 } else { | 380 } else { |
| 477 // Incoming parameter. Skip the return address. | 381 // Incoming parameter. Skip the return address. |
| 478 return MemOperand(fp, -(index - 1) * kPointerSize); | 382 return MemOperand(fp, -(index - 1) * kPointerSize); |
| 479 } | 383 } |
| 480 } | 384 } |
| 481 | 385 |
| 482 | 386 |
| 387 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { |
| 388 ASSERT(op->IsDoubleStackSlot()); |
| 389 int index = op->index(); |
| 390 if (index >= 0) { |
| 391 // Local or spill slot. Skip the frame pointer, function, context, |
| 392 // and the first word of the double in the fixed part of the frame. |
| 393 return MemOperand(fp, -(index + 3) * kPointerSize + kPointerSize); |
| 394 } else { |
| 395 // Incoming parameter. Skip the return address and the first word of |
| 396 // the double. |
| 397 return MemOperand(fp, -(index - 1) * kPointerSize + kPointerSize); |
| 398 } |
| 399 } |
| 400 |
| 401 |
| 483 void LCodeGen::WriteTranslation(LEnvironment* environment, | 402 void LCodeGen::WriteTranslation(LEnvironment* environment, |
| 484 Translation* translation) { | 403 Translation* translation) { |
| 485 if (environment == NULL) return; | 404 if (environment == NULL) return; |
| 486 | 405 |
| 487 // The translation includes one command per value in the environment. | 406 // The translation includes one command per value in the environment. |
| 488 int translation_size = environment->values()->length(); | 407 int translation_size = environment->values()->length(); |
| 489 // The output frame height does not include the parameters. | 408 // The output frame height does not include the parameters. |
| 490 int height = translation_size - environment->parameter_count(); | 409 int height = translation_size - environment->parameter_count(); |
| 491 | 410 |
| 492 WriteTranslation(environment->outer(), translation); | 411 WriteTranslation(environment->outer(), translation); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 664 } | 583 } |
| 665 | 584 |
| 666 | 585 |
| 667 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { | 586 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { |
| 668 int length = deoptimizations_.length(); | 587 int length = deoptimizations_.length(); |
| 669 if (length == 0) return; | 588 if (length == 0) return; |
| 670 ASSERT(FLAG_deopt); | 589 ASSERT(FLAG_deopt); |
| 671 Handle<DeoptimizationInputData> data = | 590 Handle<DeoptimizationInputData> data = |
| 672 Factory::NewDeoptimizationInputData(length, TENURED); | 591 Factory::NewDeoptimizationInputData(length, TENURED); |
| 673 | 592 |
| 674 data->SetTranslationByteArray(*translations_.CreateByteArray()); | 593 Handle<ByteArray> translations = translations_.CreateByteArray(); |
| 594 data->SetTranslationByteArray(*translations); |
| 675 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); | 595 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); |
| 676 | 596 |
| 677 Handle<FixedArray> literals = | 597 Handle<FixedArray> literals = |
| 678 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED); | 598 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED); |
| 679 for (int i = 0; i < deoptimization_literals_.length(); i++) { | 599 for (int i = 0; i < deoptimization_literals_.length(); i++) { |
| 680 literals->set(i, *deoptimization_literals_[i]); | 600 literals->set(i, *deoptimization_literals_[i]); |
| 681 } | 601 } |
| 682 data->SetLiteralArray(*literals); | 602 data->SetLiteralArray(*literals); |
| 683 | 603 |
| 684 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); | 604 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 744 } | 664 } |
| 745 } | 665 } |
| 746 | 666 |
| 747 | 667 |
| 748 void LCodeGen::RecordSafepoint(LPointerMap* pointers, | 668 void LCodeGen::RecordSafepoint(LPointerMap* pointers, |
| 749 int deoptimization_index) { | 669 int deoptimization_index) { |
| 750 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); | 670 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index); |
| 751 } | 671 } |
| 752 | 672 |
| 753 | 673 |
| 674 void LCodeGen::RecordSafepoint(int deoptimization_index) { |
| 675 LPointerMap empty_pointers(RelocInfo::kNoPosition); |
| 676 RecordSafepoint(&empty_pointers, deoptimization_index); |
| 677 } |
| 678 |
| 679 |
| 754 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, | 680 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, |
| 755 int arguments, | 681 int arguments, |
| 756 int deoptimization_index) { | 682 int deoptimization_index) { |
| 757 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, | 683 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, |
| 758 deoptimization_index); | 684 deoptimization_index); |
| 759 } | 685 } |
| 760 | 686 |
| 761 | 687 |
| 762 void LCodeGen::RecordSafepointWithRegistersAndDoubles( | 688 void LCodeGen::RecordSafepointWithRegistersAndDoubles( |
| 763 LPointerMap* pointers, | 689 LPointerMap* pointers, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 780 } else { | 706 } else { |
| 781 Comment(";;; B%d", label->block_id()); | 707 Comment(";;; B%d", label->block_id()); |
| 782 } | 708 } |
| 783 __ bind(label->label()); | 709 __ bind(label->label()); |
| 784 current_block_ = label->block_id(); | 710 current_block_ = label->block_id(); |
| 785 LCodeGen::DoGap(label); | 711 LCodeGen::DoGap(label); |
| 786 } | 712 } |
| 787 | 713 |
| 788 | 714 |
| 789 void LCodeGen::DoParallelMove(LParallelMove* move) { | 715 void LCodeGen::DoParallelMove(LParallelMove* move) { |
| 790 // d0 must always be a scratch register. | 716 resolver_.Resolve(move); |
| 791 DoubleRegister dbl_scratch = d0; | |
| 792 LUnallocated marker_operand(LUnallocated::NONE); | |
| 793 | |
| 794 Register core_scratch = scratch0(); | |
| 795 bool destroys_core_scratch = false; | |
| 796 | |
| 797 const ZoneList<LMoveOperands>* moves = | |
| 798 resolver_.Resolve(move->move_operands(), &marker_operand); | |
| 799 for (int i = moves->length() - 1; i >= 0; --i) { | |
| 800 LMoveOperands move = moves->at(i); | |
| 801 LOperand* from = move.source(); | |
| 802 LOperand* to = move.destination(); | |
| 803 ASSERT(!from->IsDoubleRegister() || | |
| 804 !ToDoubleRegister(from).is(dbl_scratch)); | |
| 805 ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(dbl_scratch)); | |
| 806 ASSERT(!from->IsRegister() || !ToRegister(from).is(core_scratch)); | |
| 807 ASSERT(!to->IsRegister() || !ToRegister(to).is(core_scratch)); | |
| 808 if (from == &marker_operand) { | |
| 809 if (to->IsRegister()) { | |
| 810 __ mov(ToRegister(to), core_scratch); | |
| 811 ASSERT(destroys_core_scratch); | |
| 812 } else if (to->IsStackSlot()) { | |
| 813 __ str(core_scratch, ToMemOperand(to)); | |
| 814 ASSERT(destroys_core_scratch); | |
| 815 } else if (to->IsDoubleRegister()) { | |
| 816 __ vmov(ToDoubleRegister(to), dbl_scratch); | |
| 817 } else { | |
| 818 ASSERT(to->IsDoubleStackSlot()); | |
| 819 // TODO(regis): Why is vstr not taking a MemOperand? | |
| 820 // __ vstr(dbl_scratch, ToMemOperand(to)); | |
| 821 MemOperand to_operand = ToMemOperand(to); | |
| 822 __ vstr(dbl_scratch, to_operand.rn(), to_operand.offset()); | |
| 823 } | |
| 824 } else if (to == &marker_operand) { | |
| 825 if (from->IsRegister() || from->IsConstantOperand()) { | |
| 826 __ mov(core_scratch, ToOperand(from)); | |
| 827 destroys_core_scratch = true; | |
| 828 } else if (from->IsStackSlot()) { | |
| 829 __ ldr(core_scratch, ToMemOperand(from)); | |
| 830 destroys_core_scratch = true; | |
| 831 } else if (from->IsDoubleRegister()) { | |
| 832 __ vmov(dbl_scratch, ToDoubleRegister(from)); | |
| 833 } else { | |
| 834 ASSERT(from->IsDoubleStackSlot()); | |
| 835 // TODO(regis): Why is vldr not taking a MemOperand? | |
| 836 // __ vldr(dbl_scratch, ToMemOperand(from)); | |
| 837 MemOperand from_operand = ToMemOperand(from); | |
| 838 __ vldr(dbl_scratch, from_operand.rn(), from_operand.offset()); | |
| 839 } | |
| 840 } else if (from->IsConstantOperand()) { | |
| 841 if (to->IsRegister()) { | |
| 842 __ mov(ToRegister(to), ToOperand(from)); | |
| 843 } else { | |
| 844 ASSERT(to->IsStackSlot()); | |
| 845 __ mov(ip, ToOperand(from)); | |
| 846 __ str(ip, ToMemOperand(to)); | |
| 847 } | |
| 848 } else if (from->IsRegister()) { | |
| 849 if (to->IsRegister()) { | |
| 850 __ mov(ToRegister(to), ToOperand(from)); | |
| 851 } else { | |
| 852 ASSERT(to->IsStackSlot()); | |
| 853 __ str(ToRegister(from), ToMemOperand(to)); | |
| 854 } | |
| 855 } else if (to->IsRegister()) { | |
| 856 ASSERT(from->IsStackSlot()); | |
| 857 __ ldr(ToRegister(to), ToMemOperand(from)); | |
| 858 } else if (from->IsStackSlot()) { | |
| 859 ASSERT(to->IsStackSlot()); | |
| 860 __ ldr(ip, ToMemOperand(from)); | |
| 861 __ str(ip, ToMemOperand(to)); | |
| 862 } else if (from->IsDoubleRegister()) { | |
| 863 if (to->IsDoubleRegister()) { | |
| 864 __ vmov(ToDoubleRegister(to), ToDoubleRegister(from)); | |
| 865 } else { | |
| 866 ASSERT(to->IsDoubleStackSlot()); | |
| 867 // TODO(regis): Why is vstr not taking a MemOperand? | |
| 868 // __ vstr(dbl_scratch, ToMemOperand(to)); | |
| 869 MemOperand to_operand = ToMemOperand(to); | |
| 870 __ vstr(ToDoubleRegister(from), to_operand.rn(), to_operand.offset()); | |
| 871 } | |
| 872 } else if (to->IsDoubleRegister()) { | |
| 873 ASSERT(from->IsDoubleStackSlot()); | |
| 874 // TODO(regis): Why is vldr not taking a MemOperand? | |
| 875 // __ vldr(ToDoubleRegister(to), ToMemOperand(from)); | |
| 876 MemOperand from_operand = ToMemOperand(from); | |
| 877 __ vldr(ToDoubleRegister(to), from_operand.rn(), from_operand.offset()); | |
| 878 } else { | |
| 879 ASSERT(to->IsDoubleStackSlot() && from->IsDoubleStackSlot()); | |
| 880 // TODO(regis): Why is vldr not taking a MemOperand? | |
| 881 // __ vldr(dbl_scratch, ToMemOperand(from)); | |
| 882 MemOperand from_operand = ToMemOperand(from); | |
| 883 __ vldr(dbl_scratch, from_operand.rn(), from_operand.offset()); | |
| 884 // TODO(regis): Why is vstr not taking a MemOperand? | |
| 885 // __ vstr(dbl_scratch, ToMemOperand(to)); | |
| 886 MemOperand to_operand = ToMemOperand(to); | |
| 887 __ vstr(dbl_scratch, to_operand.rn(), to_operand.offset()); | |
| 888 } | |
| 889 } | |
| 890 | |
| 891 if (destroys_core_scratch) { | |
| 892 __ ldr(core_scratch, MemOperand(fp, -kPointerSize)); | |
| 893 } | |
| 894 | |
| 895 LInstruction* next = GetNextInstruction(); | |
| 896 if (next != NULL && next->IsLazyBailout()) { | |
| 897 int pc = masm()->pc_offset(); | |
| 898 safepoints_.SetPcAfterGap(pc); | |
| 899 } | |
| 900 } | 717 } |
| 901 | 718 |
| 902 | 719 |
| 903 void LCodeGen::DoGap(LGap* gap) { | 720 void LCodeGen::DoGap(LGap* gap) { |
| 904 for (int i = LGap::FIRST_INNER_POSITION; | 721 for (int i = LGap::FIRST_INNER_POSITION; |
| 905 i <= LGap::LAST_INNER_POSITION; | 722 i <= LGap::LAST_INNER_POSITION; |
| 906 i++) { | 723 i++) { |
| 907 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); | 724 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); |
| 908 LParallelMove* move = gap->GetParallelMove(inner_pos); | 725 LParallelMove* move = gap->GetParallelMove(inner_pos); |
| 909 if (move != NULL) DoParallelMove(move); | 726 if (move != NULL) DoParallelMove(move); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 933 case CodeStub::RegExpExec: { | 750 case CodeStub::RegExpExec: { |
| 934 RegExpExecStub stub; | 751 RegExpExecStub stub; |
| 935 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 752 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 936 break; | 753 break; |
| 937 } | 754 } |
| 938 case CodeStub::SubString: { | 755 case CodeStub::SubString: { |
| 939 SubStringStub stub; | 756 SubStringStub stub; |
| 940 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 757 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 941 break; | 758 break; |
| 942 } | 759 } |
| 943 case CodeStub::StringCharAt: { | |
| 944 StringCharAtStub stub; | |
| 945 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | |
| 946 break; | |
| 947 } | |
| 948 case CodeStub::MathPow: { | |
| 949 Abort("MathPowStub unimplemented."); | |
| 950 break; | |
| 951 } | |
| 952 case CodeStub::NumberToString: { | 760 case CodeStub::NumberToString: { |
| 953 NumberToStringStub stub; | 761 NumberToStringStub stub; |
| 954 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 762 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 955 break; | 763 break; |
| 956 } | 764 } |
| 957 case CodeStub::StringAdd: { | 765 case CodeStub::StringAdd: { |
| 958 StringAddStub stub(NO_STRING_ADD_FLAGS); | 766 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 959 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 767 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 960 break; | 768 break; |
| 961 } | 769 } |
| 962 case CodeStub::StringCompare: { | 770 case CodeStub::StringCompare: { |
| 963 StringCompareStub stub; | 771 StringCompareStub stub; |
| 964 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 772 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 965 break; | 773 break; |
| 966 } | 774 } |
| 967 case CodeStub::TranscendentalCache: { | 775 case CodeStub::TranscendentalCache: { |
| 968 __ ldr(r0, MemOperand(sp, 0)); | 776 __ ldr(r0, MemOperand(sp, 0)); |
| 969 TranscendentalCacheStub stub(instr->transcendental_type()); | 777 TranscendentalCacheStub stub(instr->transcendental_type(), |
| 778 TranscendentalCacheStub::TAGGED); |
| 970 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 779 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 971 break; | 780 break; |
| 972 } | 781 } |
| 973 default: | 782 default: |
| 974 UNREACHABLE(); | 783 UNREACHABLE(); |
| 975 } | 784 } |
| 976 } | 785 } |
| 977 | 786 |
| 978 | 787 |
| 979 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 788 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 980 // Nothing to do. | 789 // Nothing to do. |
| 981 } | 790 } |
| 982 | 791 |
| 983 | 792 |
| 984 void LCodeGen::DoModI(LModI* instr) { | 793 void LCodeGen::DoModI(LModI* instr) { |
| 794 if (instr->hydrogen()->HasPowerOf2Divisor()) { |
| 795 Register dividend = ToRegister(instr->InputAt(0)); |
| 796 |
| 797 int32_t divisor = |
| 798 HConstant::cast(instr->hydrogen()->right())->Integer32Value(); |
| 799 |
| 800 if (divisor < 0) divisor = -divisor; |
| 801 |
| 802 Label positive_dividend, done; |
| 803 __ tst(dividend, Operand(dividend)); |
| 804 __ b(pl, &positive_dividend); |
| 805 __ rsb(dividend, dividend, Operand(0)); |
| 806 __ and_(dividend, dividend, Operand(divisor - 1)); |
| 807 __ rsb(dividend, dividend, Operand(0), SetCC); |
| 808 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 809 __ b(ne, &done); |
| 810 DeoptimizeIf(al, instr->environment()); |
| 811 } |
| 812 __ bind(&positive_dividend); |
| 813 __ and_(dividend, dividend, Operand(divisor - 1)); |
| 814 __ bind(&done); |
| 815 return; |
| 816 } |
| 817 |
| 985 class DeferredModI: public LDeferredCode { | 818 class DeferredModI: public LDeferredCode { |
| 986 public: | 819 public: |
| 987 DeferredModI(LCodeGen* codegen, LModI* instr) | 820 DeferredModI(LCodeGen* codegen, LModI* instr) |
| 988 : LDeferredCode(codegen), instr_(instr) { } | 821 : LDeferredCode(codegen), instr_(instr) { } |
| 989 virtual void Generate() { | 822 virtual void Generate() { |
| 990 codegen()->DoDeferredGenericBinaryStub(instr_, Token::MOD); | 823 codegen()->DoDeferredBinaryOpStub(instr_, Token::MOD); |
| 991 } | 824 } |
| 992 private: | 825 private: |
| 993 LModI* instr_; | 826 LModI* instr_; |
| 994 }; | 827 }; |
| 995 // These registers hold untagged 32 bit values. | 828 // These registers hold untagged 32 bit values. |
| 996 Register left = ToRegister(instr->InputAt(0)); | 829 Register left = ToRegister(instr->InputAt(0)); |
| 997 Register right = ToRegister(instr->InputAt(1)); | 830 Register right = ToRegister(instr->InputAt(1)); |
| 998 Register result = ToRegister(instr->result()); | 831 Register result = ToRegister(instr->result()); |
| 999 Register scratch = scratch0(); | 832 Register scratch = scratch0(); |
| 1000 | 833 |
| 1001 Label deoptimize, done; | 834 Label deoptimize, done; |
| 1002 // Check for x % 0. | 835 // Check for x % 0. |
| 1003 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { | 836 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1004 __ tst(right, Operand(right)); | 837 __ tst(right, Operand(right)); |
| 1005 __ b(eq, &deoptimize); | 838 __ b(eq, &deoptimize); |
| 1006 } | 839 } |
| 1007 | 840 |
| 1008 // Check for (0 % -x) that will produce negative zero. | 841 // Check for (0 % -x) that will produce negative zero. |
| 1009 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 842 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1010 Label ok; | 843 Label ok; |
| 1011 __ tst(left, Operand(left)); | 844 __ tst(left, Operand(left)); |
| 1012 __ b(ne, &ok); | 845 __ b(ne, &ok); |
| 1013 __ tst(right, Operand(right)); | 846 __ tst(right, Operand(right)); |
| 1014 __ b(pl, &ok); | 847 __ b(pl, &ok); |
| 1015 __ b(al, &deoptimize); | 848 __ b(al, &deoptimize); |
| 1016 __ bind(&ok); | 849 __ bind(&ok); |
| 1017 } | 850 } |
| 1018 | 851 |
| 1019 // Try a few common cases before using the generic stub. | 852 // Try a few common cases before using the stub. |
| 1020 Label call_stub; | 853 Label call_stub; |
| 1021 const int kUnfolds = 3; | 854 const int kUnfolds = 3; |
| 1022 // Skip if either side is negative. | 855 // Skip if either side is negative. |
| 1023 __ cmp(left, Operand(0)); | 856 __ cmp(left, Operand(0)); |
| 1024 __ cmp(right, Operand(0), NegateCondition(mi)); | 857 __ cmp(right, Operand(0), NegateCondition(mi)); |
| 1025 __ b(mi, &call_stub); | 858 __ b(mi, &call_stub); |
| 1026 // If the right hand side is smaller than the (nonnegative) | 859 // If the right hand side is smaller than the (nonnegative) |
| 1027 // left hand side, it is the result. Else try a few subtractions | 860 // left hand side, it is the result. Else try a few subtractions |
| 1028 // of the left hand side. | 861 // of the left hand side. |
| 1029 __ mov(scratch, left); | 862 __ mov(scratch, left); |
| 1030 for (int i = 0; i < kUnfolds; i++) { | 863 for (int i = 0; i < kUnfolds; i++) { |
| 1031 // Check if the left hand side is less or equal than the | 864 // Check if the left hand side is less or equal than the |
| 1032 // the right hand side. | 865 // the right hand side. |
| 1033 __ cmp(scratch, right); | 866 __ cmp(scratch, right); |
| 1034 __ mov(result, scratch, LeaveCC, lt); | 867 __ mov(result, scratch, LeaveCC, lt); |
| 1035 __ b(lt, &done); | 868 __ b(lt, &done); |
| 1036 // If not, reduce the left hand side by the right hand | 869 // If not, reduce the left hand side by the right hand |
| 1037 // side and check again. | 870 // side and check again. |
| 1038 if (i < kUnfolds - 1) __ sub(scratch, scratch, right); | 871 if (i < kUnfolds - 1) __ sub(scratch, scratch, right); |
| 1039 } | 872 } |
| 1040 | 873 |
| 1041 // Check for power of two on the right hand side. | 874 // Check for power of two on the right hand side. |
| 1042 __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub); | 875 __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub); |
| 1043 // Perform modulo operation (scratch contains right - 1). | 876 // Perform modulo operation (scratch contains right - 1). |
| 1044 __ and_(result, scratch, Operand(left)); | 877 __ and_(result, scratch, Operand(left)); |
| 878 __ b(&done); |
| 1045 | 879 |
| 1046 __ bind(&call_stub); | 880 __ bind(&call_stub); |
| 1047 // Call the generic stub. The numbers in r0 and r1 have | 881 // Call the stub. The numbers in r0 and r1 have |
| 1048 // to be tagged to Smis. If that is not possible, deoptimize. | 882 // to be tagged to Smis. If that is not possible, deoptimize. |
| 1049 DeferredModI* deferred = new DeferredModI(this, instr); | 883 DeferredModI* deferred = new DeferredModI(this, instr); |
| 1050 __ TrySmiTag(left, &deoptimize, scratch); | 884 __ TrySmiTag(left, &deoptimize, scratch); |
| 1051 __ TrySmiTag(right, &deoptimize, scratch); | 885 __ TrySmiTag(right, &deoptimize, scratch); |
| 1052 | 886 |
| 1053 __ b(al, deferred->entry()); | 887 __ b(al, deferred->entry()); |
| 1054 __ bind(deferred->exit()); | 888 __ bind(deferred->exit()); |
| 1055 | 889 |
| 1056 // If the result in r0 is a Smi, untag it, else deoptimize. | 890 // If the result in r0 is a Smi, untag it, else deoptimize. |
| 1057 __ JumpIfNotSmi(result, &deoptimize); | 891 __ JumpIfNotSmi(result, &deoptimize); |
| 1058 __ SmiUntag(result); | 892 __ SmiUntag(result); |
| 1059 | 893 |
| 1060 __ b(al, &done); | 894 __ b(al, &done); |
| 1061 __ bind(&deoptimize); | 895 __ bind(&deoptimize); |
| 1062 DeoptimizeIf(al, instr->environment()); | 896 DeoptimizeIf(al, instr->environment()); |
| 1063 __ bind(&done); | 897 __ bind(&done); |
| 1064 } | 898 } |
| 1065 | 899 |
| 1066 | 900 |
| 1067 void LCodeGen::DoDivI(LDivI* instr) { | 901 void LCodeGen::DoDivI(LDivI* instr) { |
| 1068 class DeferredDivI: public LDeferredCode { | 902 class DeferredDivI: public LDeferredCode { |
| 1069 public: | 903 public: |
| 1070 DeferredDivI(LCodeGen* codegen, LDivI* instr) | 904 DeferredDivI(LCodeGen* codegen, LDivI* instr) |
| 1071 : LDeferredCode(codegen), instr_(instr) { } | 905 : LDeferredCode(codegen), instr_(instr) { } |
| 1072 virtual void Generate() { | 906 virtual void Generate() { |
| 1073 codegen()->DoDeferredGenericBinaryStub(instr_, Token::DIV); | 907 codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV); |
| 1074 } | 908 } |
| 1075 private: | 909 private: |
| 1076 LDivI* instr_; | 910 LDivI* instr_; |
| 1077 }; | 911 }; |
| 1078 | 912 |
| 1079 const Register left = ToRegister(instr->InputAt(0)); | 913 const Register left = ToRegister(instr->InputAt(0)); |
| 1080 const Register right = ToRegister(instr->InputAt(1)); | 914 const Register right = ToRegister(instr->InputAt(1)); |
| 1081 const Register scratch = scratch0(); | 915 const Register scratch = scratch0(); |
| 1082 const Register result = ToRegister(instr->result()); | 916 const Register result = ToRegister(instr->result()); |
| 1083 | 917 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 __ cmp(right, Operand(2)); | 950 __ cmp(right, Operand(2)); |
| 1117 __ tst(left, Operand(1), eq); | 951 __ tst(left, Operand(1), eq); |
| 1118 __ mov(result, Operand(left, ASR, 1), LeaveCC, eq); | 952 __ mov(result, Operand(left, ASR, 1), LeaveCC, eq); |
| 1119 __ b(eq, &done); | 953 __ b(eq, &done); |
| 1120 | 954 |
| 1121 __ cmp(right, Operand(4)); | 955 __ cmp(right, Operand(4)); |
| 1122 __ tst(left, Operand(3), eq); | 956 __ tst(left, Operand(3), eq); |
| 1123 __ mov(result, Operand(left, ASR, 2), LeaveCC, eq); | 957 __ mov(result, Operand(left, ASR, 2), LeaveCC, eq); |
| 1124 __ b(eq, &done); | 958 __ b(eq, &done); |
| 1125 | 959 |
| 1126 // Call the generic stub. The numbers in r0 and r1 have | 960 // Call the stub. The numbers in r0 and r1 have |
| 1127 // to be tagged to Smis. If that is not possible, deoptimize. | 961 // to be tagged to Smis. If that is not possible, deoptimize. |
| 1128 DeferredDivI* deferred = new DeferredDivI(this, instr); | 962 DeferredDivI* deferred = new DeferredDivI(this, instr); |
| 1129 | 963 |
| 1130 __ TrySmiTag(left, &deoptimize, scratch); | 964 __ TrySmiTag(left, &deoptimize, scratch); |
| 1131 __ TrySmiTag(right, &deoptimize, scratch); | 965 __ TrySmiTag(right, &deoptimize, scratch); |
| 1132 | 966 |
| 1133 __ b(al, deferred->entry()); | 967 __ b(al, deferred->entry()); |
| 1134 __ bind(deferred->exit()); | 968 __ bind(deferred->exit()); |
| 1135 | 969 |
| 1136 // If the result in r0 is a Smi, untag it, else deoptimize. | 970 // If the result in r0 is a Smi, untag it, else deoptimize. |
| 1137 __ JumpIfNotSmi(result, &deoptimize); | 971 __ JumpIfNotSmi(result, &deoptimize); |
| 1138 __ SmiUntag(result); | 972 __ SmiUntag(result); |
| 1139 __ b(&done); | 973 __ b(&done); |
| 1140 | 974 |
| 1141 __ bind(&deoptimize); | 975 __ bind(&deoptimize); |
| 1142 DeoptimizeIf(al, instr->environment()); | 976 DeoptimizeIf(al, instr->environment()); |
| 1143 __ bind(&done); | 977 __ bind(&done); |
| 1144 } | 978 } |
| 1145 | 979 |
| 1146 | 980 |
| 1147 template<int T> | 981 template<int T> |
| 1148 void LCodeGen::DoDeferredGenericBinaryStub(LTemplateInstruction<1, 2, T>* instr, | 982 void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr, |
| 1149 Token::Value op) { | 983 Token::Value op) { |
| 1150 Register left = ToRegister(instr->InputAt(0)); | 984 Register left = ToRegister(instr->InputAt(0)); |
| 1151 Register right = ToRegister(instr->InputAt(1)); | 985 Register right = ToRegister(instr->InputAt(1)); |
| 1152 | 986 |
| 1153 __ PushSafepointRegistersAndDoubles(); | 987 __ PushSafepointRegistersAndDoubles(); |
| 1154 GenericBinaryOpStub stub(op, OVERWRITE_LEFT, left, right); | 988 // Move left to r1 and right to r0 for the stub call. |
| 989 if (left.is(r1)) { |
| 990 __ Move(r0, right); |
| 991 } else if (left.is(r0) && right.is(r1)) { |
| 992 __ Swap(r0, r1, r2); |
| 993 } else if (left.is(r0)) { |
| 994 ASSERT(!right.is(r1)); |
| 995 __ mov(r1, r0); |
| 996 __ mov(r0, right); |
| 997 } else { |
| 998 ASSERT(!left.is(r0) && !right.is(r0)); |
| 999 __ mov(r0, right); |
| 1000 __ mov(r1, left); |
| 1001 } |
| 1002 TypeRecordingBinaryOpStub stub(op, OVERWRITE_LEFT); |
| 1155 __ CallStub(&stub); | 1003 __ CallStub(&stub); |
| 1156 RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), | 1004 RecordSafepointWithRegistersAndDoubles(instr->pointer_map(), |
| 1157 0, | 1005 0, |
| 1158 Safepoint::kNoDeoptimizationIndex); | 1006 Safepoint::kNoDeoptimizationIndex); |
| 1159 // Overwrite the stored value of r0 with the result of the stub. | 1007 // Overwrite the stored value of r0 with the result of the stub. |
| 1160 __ StoreToSafepointRegistersAndDoublesSlot(r0); | 1008 __ StoreToSafepointRegistersAndDoublesSlot(r0, r0); |
| 1161 __ PopSafepointRegistersAndDoubles(); | 1009 __ PopSafepointRegistersAndDoubles(); |
| 1162 } | 1010 } |
| 1163 | 1011 |
| 1164 | 1012 |
| 1165 void LCodeGen::DoMulI(LMulI* instr) { | 1013 void LCodeGen::DoMulI(LMulI* instr) { |
| 1166 Register scratch = scratch0(); | 1014 Register scratch = scratch0(); |
| 1167 Register left = ToRegister(instr->InputAt(0)); | 1015 Register left = ToRegister(instr->InputAt(0)); |
| 1168 Register right = EmitLoadRegister(instr->InputAt(1), scratch); | 1016 Register right = EmitLoadRegister(instr->InputAt(1), scratch); |
| 1169 | 1017 |
| 1170 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) && | 1018 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) && |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1315 } | 1163 } |
| 1316 | 1164 |
| 1317 | 1165 |
| 1318 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { | 1166 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { |
| 1319 Register result = ToRegister(instr->result()); | 1167 Register result = ToRegister(instr->result()); |
| 1320 Register array = ToRegister(instr->InputAt(0)); | 1168 Register array = ToRegister(instr->InputAt(0)); |
| 1321 __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); | 1169 __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset)); |
| 1322 } | 1170 } |
| 1323 | 1171 |
| 1324 | 1172 |
| 1325 void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) { | 1173 void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) { |
| 1326 Register result = ToRegister(instr->result()); | 1174 Register result = ToRegister(instr->result()); |
| 1327 Register array = ToRegister(instr->InputAt(0)); | 1175 Register array = ToRegister(instr->InputAt(0)); |
| 1328 __ ldr(result, FieldMemOperand(array, PixelArray::kLengthOffset)); | 1176 __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset)); |
| 1329 } | 1177 } |
| 1330 | 1178 |
| 1331 | 1179 |
| 1332 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { | 1180 void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { |
| 1333 Register result = ToRegister(instr->result()); | 1181 Register result = ToRegister(instr->result()); |
| 1334 Register array = ToRegister(instr->InputAt(0)); | 1182 Register array = ToRegister(instr->InputAt(0)); |
| 1335 __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); | 1183 __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); |
| 1336 } | 1184 } |
| 1337 | 1185 |
| 1338 | 1186 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1406 break; | 1254 break; |
| 1407 case Token::MOD: { | 1255 case Token::MOD: { |
| 1408 // Save r0-r3 on the stack. | 1256 // Save r0-r3 on the stack. |
| 1409 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit()); | 1257 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit()); |
| 1410 | 1258 |
| 1411 __ PrepareCallCFunction(4, scratch0()); | 1259 __ PrepareCallCFunction(4, scratch0()); |
| 1412 __ vmov(r0, r1, left); | 1260 __ vmov(r0, r1, left); |
| 1413 __ vmov(r2, r3, right); | 1261 __ vmov(r2, r3, right); |
| 1414 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4); | 1262 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4); |
| 1415 // Move the result in the double result register. | 1263 // Move the result in the double result register. |
| 1416 __ vmov(ToDoubleRegister(instr->result()), r0, r1); | 1264 __ GetCFunctionDoubleResult(ToDoubleRegister(instr->result())); |
| 1417 | 1265 |
| 1418 // Restore r0-r3. | 1266 // Restore r0-r3. |
| 1419 __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit()); | 1267 __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit()); |
| 1420 break; | 1268 break; |
| 1421 } | 1269 } |
| 1422 default: | 1270 default: |
| 1423 UNREACHABLE(); | 1271 UNREACHABLE(); |
| 1424 break; | 1272 break; |
| 1425 } | 1273 } |
| 1426 } | 1274 } |
| 1427 | 1275 |
| 1428 | 1276 |
| 1429 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { | 1277 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { |
| 1430 ASSERT(ToRegister(instr->InputAt(0)).is(r1)); | 1278 ASSERT(ToRegister(instr->InputAt(0)).is(r1)); |
| 1431 ASSERT(ToRegister(instr->InputAt(1)).is(r0)); | 1279 ASSERT(ToRegister(instr->InputAt(1)).is(r0)); |
| 1432 ASSERT(ToRegister(instr->result()).is(r0)); | 1280 ASSERT(ToRegister(instr->result()).is(r0)); |
| 1433 | 1281 |
| 1434 // TODO(regis): Implement TypeRecordingBinaryOpStub and replace current | 1282 TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE); |
| 1435 // GenericBinaryOpStub: | |
| 1436 // TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE); | |
| 1437 GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, r1, r0); | |
| 1438 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 1283 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 1439 } | 1284 } |
| 1440 | 1285 |
| 1441 | 1286 |
| 1442 int LCodeGen::GetNextEmittedBlock(int block) { | 1287 int LCodeGen::GetNextEmittedBlock(int block) { |
| 1443 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { | 1288 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { |
| 1444 LLabel* label = chunk_->GetLabel(i); | 1289 LLabel* label = chunk_->GetLabel(i); |
| 1445 if (!label->HasReplacement()) return i; | 1290 if (!label->HasReplacement()) return i; |
| 1446 } | 1291 } |
| 1447 return -1; | 1292 return -1; |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1889 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1734 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1890 | 1735 |
| 1891 __ tst(input, Operand(kSmiTagMask)); | 1736 __ tst(input, Operand(kSmiTagMask)); |
| 1892 __ b(eq, false_label); | 1737 __ b(eq, false_label); |
| 1893 | 1738 |
| 1894 __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen())); | 1739 __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen())); |
| 1895 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); | 1740 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); |
| 1896 } | 1741 } |
| 1897 | 1742 |
| 1898 | 1743 |
| 1744 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { |
| 1745 Register input = ToRegister(instr->InputAt(0)); |
| 1746 Register result = ToRegister(instr->result()); |
| 1747 |
| 1748 if (FLAG_debug_code) { |
| 1749 __ AbortIfNotString(input); |
| 1750 } |
| 1751 |
| 1752 __ ldr(result, FieldMemOperand(input, String::kHashFieldOffset)); |
| 1753 __ IndexFromHash(result, result); |
| 1754 } |
| 1755 |
| 1756 |
| 1899 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { | 1757 void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) { |
| 1900 Register input = ToRegister(instr->InputAt(0)); | 1758 Register input = ToRegister(instr->InputAt(0)); |
| 1901 Register result = ToRegister(instr->result()); | 1759 Register result = ToRegister(instr->result()); |
| 1902 Register scratch = scratch0(); | 1760 Register scratch = scratch0(); |
| 1903 | 1761 |
| 1904 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); | 1762 ASSERT(instr->hydrogen()->value()->representation().IsTagged()); |
| 1905 __ ldr(scratch, | 1763 __ ldr(scratch, |
| 1906 FieldMemOperand(input, String::kContainsCachedArrayIndexMask)); | 1764 FieldMemOperand(input, String::kHashFieldOffset)); |
| 1907 __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask)); | 1765 __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask)); |
| 1908 __ LoadRoot(result, Heap::kTrueValueRootIndex, ne); | 1766 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq); |
| 1909 __ LoadRoot(result, Heap::kFalseValueRootIndex, eq); | 1767 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne); |
| 1910 } | 1768 } |
| 1911 | 1769 |
| 1912 | 1770 |
| 1913 void LCodeGen::DoHasCachedArrayIndexAndBranch( | 1771 void LCodeGen::DoHasCachedArrayIndexAndBranch( |
| 1914 LHasCachedArrayIndexAndBranch* instr) { | 1772 LHasCachedArrayIndexAndBranch* instr) { |
| 1915 Register input = ToRegister(instr->InputAt(0)); | 1773 Register input = ToRegister(instr->InputAt(0)); |
| 1916 Register scratch = scratch0(); | 1774 Register scratch = scratch0(); |
| 1917 | 1775 |
| 1918 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1776 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1919 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1777 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1920 | 1778 |
| 1921 __ ldr(scratch, | 1779 __ ldr(scratch, |
| 1922 FieldMemOperand(input, String::kContainsCachedArrayIndexMask)); | 1780 FieldMemOperand(input, String::kHashFieldOffset)); |
| 1923 __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask)); | 1781 __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask)); |
| 1924 EmitBranch(true_block, false_block, ne); | 1782 EmitBranch(true_block, false_block, eq); |
| 1925 } | 1783 } |
| 1926 | 1784 |
| 1927 | 1785 |
| 1928 // Branches to a label or falls through with the answer in flags. Trashes | 1786 // Branches to a label or falls through with the answer in flags. Trashes |
| 1929 // the temp registers, but not the input. Only input and temp2 may alias. | 1787 // the temp registers, but not the input. Only input and temp2 may alias. |
| 1930 void LCodeGen::EmitClassOfTest(Label* is_true, | 1788 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1931 Label* is_false, | 1789 Label* is_false, |
| 1932 Handle<String>class_name, | 1790 Handle<String>class_name, |
| 1933 Register input, | 1791 Register input, |
| 1934 Register temp, | 1792 Register temp, |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2157 // offset to the location of the map check. | 2015 // offset to the location of the map check. |
| 2158 Register temp = ToRegister(instr->TempAt(0)); | 2016 Register temp = ToRegister(instr->TempAt(0)); |
| 2159 ASSERT(temp.is(r4)); | 2017 ASSERT(temp.is(r4)); |
| 2160 __ mov(InstanceofStub::right(), Operand(instr->function())); | 2018 __ mov(InstanceofStub::right(), Operand(instr->function())); |
| 2161 static const int kAdditionalDelta = 4; | 2019 static const int kAdditionalDelta = 4; |
| 2162 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; | 2020 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; |
| 2163 Label before_push_delta; | 2021 Label before_push_delta; |
| 2164 __ bind(&before_push_delta); | 2022 __ bind(&before_push_delta); |
| 2165 __ BlockConstPoolFor(kAdditionalDelta); | 2023 __ BlockConstPoolFor(kAdditionalDelta); |
| 2166 __ mov(temp, Operand(delta * kPointerSize)); | 2024 __ mov(temp, Operand(delta * kPointerSize)); |
| 2167 __ StoreToSafepointRegisterSlot(temp); | 2025 __ StoreToSafepointRegisterSlot(temp, temp); |
| 2168 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); | 2026 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2169 ASSERT_EQ(kAdditionalDelta, | |
| 2170 masm_->InstructionsGeneratedSince(&before_push_delta)); | |
| 2171 RecordSafepointWithRegisters( | |
| 2172 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | |
| 2173 // Put the result value into the result register slot and | 2027 // Put the result value into the result register slot and |
| 2174 // restore all registers. | 2028 // restore all registers. |
| 2175 __ StoreToSafepointRegisterSlot(result); | 2029 __ StoreToSafepointRegisterSlot(result, result); |
| 2176 | 2030 |
| 2177 __ PopSafepointRegisters(); | 2031 __ PopSafepointRegisters(); |
| 2178 } | 2032 } |
| 2179 | 2033 |
| 2180 | 2034 |
| 2181 static Condition ComputeCompareCondition(Token::Value op) { | 2035 static Condition ComputeCompareCondition(Token::Value op) { |
| 2182 switch (op) { | 2036 switch (op) { |
| 2183 case Token::EQ_STRICT: | 2037 case Token::EQ_STRICT: |
| 2184 case Token::EQ: | 2038 case Token::EQ: |
| 2185 return eq; | 2039 return eq; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2285 } | 2139 } |
| 2286 | 2140 |
| 2287 // Store the value. | 2141 // Store the value. |
| 2288 __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 2142 __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
| 2289 } | 2143 } |
| 2290 | 2144 |
| 2291 | 2145 |
| 2292 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2146 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2293 Register context = ToRegister(instr->context()); | 2147 Register context = ToRegister(instr->context()); |
| 2294 Register result = ToRegister(instr->result()); | 2148 Register result = ToRegister(instr->result()); |
| 2295 __ ldr(result, | 2149 __ ldr(result, ContextOperand(context, instr->slot_index())); |
| 2296 MemOperand(context, Context::SlotOffset(Context::FCONTEXT_INDEX))); | |
| 2297 __ ldr(result, ContextOperand(result, instr->slot_index())); | |
| 2298 } | 2150 } |
| 2299 | 2151 |
| 2300 | 2152 |
| 2301 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2153 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2302 Register context = ToRegister(instr->context()); | 2154 Register context = ToRegister(instr->context()); |
| 2303 Register value = ToRegister(instr->value()); | 2155 Register value = ToRegister(instr->value()); |
| 2304 __ ldr(context, | |
| 2305 MemOperand(context, Context::SlotOffset(Context::FCONTEXT_INDEX))); | |
| 2306 __ str(value, ContextOperand(context, instr->slot_index())); | 2156 __ str(value, ContextOperand(context, instr->slot_index())); |
| 2307 if (instr->needs_write_barrier()) { | 2157 if (instr->needs_write_barrier()) { |
| 2308 int offset = Context::SlotOffset(instr->slot_index()); | 2158 int offset = Context::SlotOffset(instr->slot_index()); |
| 2309 __ RecordWrite(context, Operand(offset), value, scratch0()); | 2159 __ RecordWrite(context, Operand(offset), value, scratch0()); |
| 2310 } | 2160 } |
| 2311 } | 2161 } |
| 2312 | 2162 |
| 2313 | 2163 |
| 2314 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2164 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 2315 Register object = ToRegister(instr->InputAt(0)); | 2165 Register object = ToRegister(instr->InputAt(0)); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2383 Register input = ToRegister(instr->InputAt(0)); | 2233 Register input = ToRegister(instr->InputAt(0)); |
| 2384 Register scratch = scratch0(); | 2234 Register scratch = scratch0(); |
| 2385 | 2235 |
| 2386 __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset)); | 2236 __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset)); |
| 2387 if (FLAG_debug_code) { | 2237 if (FLAG_debug_code) { |
| 2388 Label done; | 2238 Label done; |
| 2389 __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset)); | 2239 __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset)); |
| 2390 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 2240 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 2391 __ cmp(scratch, ip); | 2241 __ cmp(scratch, ip); |
| 2392 __ b(eq, &done); | 2242 __ b(eq, &done); |
| 2393 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); | 2243 __ LoadRoot(ip, Heap::kExternalPixelArrayMapRootIndex); |
| 2394 __ cmp(scratch, ip); | 2244 __ cmp(scratch, ip); |
| 2395 __ b(eq, &done); | 2245 __ b(eq, &done); |
| 2396 __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); | 2246 __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); |
| 2397 __ cmp(scratch, ip); | 2247 __ cmp(scratch, ip); |
| 2398 __ Check(eq, "Check for fast elements failed."); | 2248 __ Check(eq, "Check for fast elements failed."); |
| 2399 __ bind(&done); | 2249 __ bind(&done); |
| 2400 } | 2250 } |
| 2401 } | 2251 } |
| 2402 | 2252 |
| 2403 | 2253 |
| 2404 void LCodeGen::DoLoadPixelArrayExternalPointer( | 2254 void LCodeGen::DoLoadExternalArrayPointer( |
| 2405 LLoadPixelArrayExternalPointer* instr) { | 2255 LLoadExternalArrayPointer* instr) { |
| 2406 Register to_reg = ToRegister(instr->result()); | 2256 Register to_reg = ToRegister(instr->result()); |
| 2407 Register from_reg = ToRegister(instr->InputAt(0)); | 2257 Register from_reg = ToRegister(instr->InputAt(0)); |
| 2408 __ ldr(to_reg, FieldMemOperand(from_reg, PixelArray::kExternalPointerOffset)); | 2258 __ ldr(to_reg, FieldMemOperand(from_reg, |
| 2259 ExternalArray::kExternalPointerOffset)); |
| 2409 } | 2260 } |
| 2410 | 2261 |
| 2411 | 2262 |
| 2412 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { | 2263 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
| 2413 Register arguments = ToRegister(instr->arguments()); | 2264 Register arguments = ToRegister(instr->arguments()); |
| 2414 Register length = ToRegister(instr->length()); | 2265 Register length = ToRegister(instr->length()); |
| 2415 Register index = ToRegister(instr->index()); | 2266 Register index = ToRegister(instr->index()); |
| 2416 Register result = ToRegister(instr->result()); | 2267 Register result = ToRegister(instr->result()); |
| 2417 | 2268 |
| 2418 // Bailout index is not a valid argument index. Use unsigned check to get | 2269 // Bailout index is not a valid argument index. Use unsigned check to get |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2439 __ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize)); | 2290 __ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize)); |
| 2440 | 2291 |
| 2441 // Check for the hole value. | 2292 // Check for the hole value. |
| 2442 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | 2293 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); |
| 2443 __ cmp(result, scratch); | 2294 __ cmp(result, scratch); |
| 2444 DeoptimizeIf(eq, instr->environment()); | 2295 DeoptimizeIf(eq, instr->environment()); |
| 2445 } | 2296 } |
| 2446 | 2297 |
| 2447 | 2298 |
| 2448 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { | 2299 void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) { |
| 2449 Register external_elements = ToRegister(instr->external_pointer()); | 2300 Register external_pointer = ToRegister(instr->external_pointer()); |
| 2450 Register key = ToRegister(instr->key()); | 2301 Register key = ToRegister(instr->key()); |
| 2451 Register result = ToRegister(instr->result()); | 2302 Register result = ToRegister(instr->result()); |
| 2452 | 2303 |
| 2453 // Load the result. | 2304 // Load the result. |
| 2454 __ ldrb(result, MemOperand(external_elements, key)); | 2305 __ ldrb(result, MemOperand(external_pointer, key)); |
| 2455 } | 2306 } |
| 2456 | 2307 |
| 2457 | 2308 |
| 2458 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { | 2309 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { |
| 2459 ASSERT(ToRegister(instr->object()).is(r1)); | 2310 ASSERT(ToRegister(instr->object()).is(r1)); |
| 2460 ASSERT(ToRegister(instr->key()).is(r0)); | 2311 ASSERT(ToRegister(instr->key()).is(r0)); |
| 2461 | 2312 |
| 2462 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 2313 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 2463 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2314 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2464 } | 2315 } |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2614 Register result = ToRegister(instr->result()); | 2465 Register result = ToRegister(instr->result()); |
| 2615 __ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset)); | 2466 __ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset)); |
| 2616 } | 2467 } |
| 2617 | 2468 |
| 2618 | 2469 |
| 2619 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 2470 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
| 2620 int arity, | 2471 int arity, |
| 2621 LInstruction* instr) { | 2472 LInstruction* instr) { |
| 2622 // Change context if needed. | 2473 // Change context if needed. |
| 2623 bool change_context = | 2474 bool change_context = |
| 2624 (graph()->info()->closure()->context() != function->context()) || | 2475 (info()->closure()->context() != function->context()) || |
| 2625 scope()->contains_with() || | 2476 scope()->contains_with() || |
| 2626 (scope()->num_heap_slots() > 0); | 2477 (scope()->num_heap_slots() > 0); |
| 2627 if (change_context) { | 2478 if (change_context) { |
| 2628 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 2479 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
| 2629 } | 2480 } |
| 2630 | 2481 |
| 2631 // Set r0 to arguments count if adaption is not needed. Assumes that r0 | 2482 // Set r0 to arguments count if adaption is not needed. Assumes that r0 |
| 2632 // is available to write to at this point. | 2483 // is available to write to at this point. |
| 2633 if (!function->NeedsArgumentsAdaption()) { | 2484 if (!function->NeedsArgumentsAdaption()) { |
| 2634 __ mov(r0, Operand(arity)); | 2485 __ mov(r0, Operand(arity)); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2698 | 2549 |
| 2699 // Slow case: Call the runtime system to do the number allocation. | 2550 // Slow case: Call the runtime system to do the number allocation. |
| 2700 __ bind(&slow); | 2551 __ bind(&slow); |
| 2701 | 2552 |
| 2702 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 2553 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 2703 RecordSafepointWithRegisters( | 2554 RecordSafepointWithRegisters( |
| 2704 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 2555 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 2705 // Set the pointer to the new heap number in tmp. | 2556 // Set the pointer to the new heap number in tmp. |
| 2706 if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0)); | 2557 if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0)); |
| 2707 // Restore input_reg after call to runtime. | 2558 // Restore input_reg after call to runtime. |
| 2708 __ LoadFromSafepointRegisterSlot(input); | 2559 __ LoadFromSafepointRegisterSlot(input, input); |
| 2709 __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); | 2560 __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); |
| 2710 | 2561 |
| 2711 __ bind(&allocated); | 2562 __ bind(&allocated); |
| 2712 // exponent: floating point exponent value. | 2563 // exponent: floating point exponent value. |
| 2713 // tmp1: allocated heap number. | 2564 // tmp1: allocated heap number. |
| 2714 __ bic(exponent, exponent, Operand(HeapNumber::kSignMask)); | 2565 __ bic(exponent, exponent, Operand(HeapNumber::kSignMask)); |
| 2715 __ str(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset)); | 2566 __ str(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset)); |
| 2716 __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset)); | 2567 __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset)); |
| 2717 __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset)); | 2568 __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset)); |
| 2718 | 2569 |
| 2719 __ str(tmp1, masm()->SafepointRegisterSlot(input)); | 2570 __ StoreToSafepointRegisterSlot(tmp1, input); |
| 2720 __ PopSafepointRegisters(); | 2571 __ PopSafepointRegisters(); |
| 2721 | 2572 |
| 2722 __ bind(&done); | 2573 __ bind(&done); |
| 2723 } | 2574 } |
| 2724 | 2575 |
| 2725 | 2576 |
| 2726 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { | 2577 void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { |
| 2727 Register input = ToRegister(instr->InputAt(0)); | 2578 Register input = ToRegister(instr->InputAt(0)); |
| 2728 __ cmp(input, Operand(0)); | 2579 __ cmp(input, Operand(0)); |
| 2729 // We can make rsb conditional because the previous cmp instruction | 2580 // We can make rsb conditional because the previous cmp instruction |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2763 Register input = ToRegister(instr->InputAt(0)); | 2614 Register input = ToRegister(instr->InputAt(0)); |
| 2764 // Smi check. | 2615 // Smi check. |
| 2765 __ JumpIfNotSmi(input, deferred->entry()); | 2616 __ JumpIfNotSmi(input, deferred->entry()); |
| 2766 // If smi, handle it directly. | 2617 // If smi, handle it directly. |
| 2767 EmitIntegerMathAbs(instr); | 2618 EmitIntegerMathAbs(instr); |
| 2768 __ bind(deferred->exit()); | 2619 __ bind(deferred->exit()); |
| 2769 } | 2620 } |
| 2770 } | 2621 } |
| 2771 | 2622 |
| 2772 | 2623 |
| 2773 // Truncates a double using a specific rounding mode. | |
| 2774 // Clears the z flag (ne condition) if an overflow occurs. | |
| 2775 void LCodeGen::EmitVFPTruncate(VFPRoundingMode rounding_mode, | |
| 2776 SwVfpRegister result, | |
| 2777 DwVfpRegister double_input, | |
| 2778 Register scratch1, | |
| 2779 Register scratch2) { | |
| 2780 Register prev_fpscr = scratch1; | |
| 2781 Register scratch = scratch2; | |
| 2782 | |
| 2783 // Set custom FPCSR: | |
| 2784 // - Set rounding mode. | |
| 2785 // - Clear vfp cumulative exception flags. | |
| 2786 // - Make sure Flush-to-zero mode control bit is unset. | |
| 2787 __ vmrs(prev_fpscr); | |
| 2788 __ bic(scratch, prev_fpscr, Operand(kVFPExceptionMask | | |
| 2789 kVFPRoundingModeMask | | |
| 2790 kVFPFlushToZeroMask)); | |
| 2791 __ orr(scratch, scratch, Operand(rounding_mode)); | |
| 2792 __ vmsr(scratch); | |
| 2793 | |
| 2794 // Convert the argument to an integer. | |
| 2795 __ vcvt_s32_f64(result, | |
| 2796 double_input, | |
| 2797 kFPSCRRounding); | |
| 2798 | |
| 2799 // Retrieve FPSCR. | |
| 2800 __ vmrs(scratch); | |
| 2801 // Restore FPSCR. | |
| 2802 __ vmsr(prev_fpscr); | |
| 2803 // Check for vfp exceptions. | |
| 2804 __ tst(scratch, Operand(kVFPExceptionMask)); | |
| 2805 } | |
| 2806 | |
| 2807 | |
| 2808 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { | 2624 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
| 2809 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); | 2625 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2810 Register result = ToRegister(instr->result()); | 2626 Register result = ToRegister(instr->result()); |
| 2811 SwVfpRegister single_scratch = double_scratch0().low(); | 2627 SwVfpRegister single_scratch = double_scratch0().low(); |
| 2812 Register scratch1 = scratch0(); | 2628 Register scratch1 = scratch0(); |
| 2813 Register scratch2 = ToRegister(instr->TempAt(0)); | 2629 Register scratch2 = ToRegister(instr->TempAt(0)); |
| 2814 | 2630 |
| 2815 EmitVFPTruncate(kRoundToMinusInf, | 2631 __ EmitVFPTruncate(kRoundToMinusInf, |
| 2816 single_scratch, | 2632 single_scratch, |
| 2817 input, | 2633 input, |
| 2818 scratch1, | 2634 scratch1, |
| 2819 scratch2); | 2635 scratch2); |
| 2820 DeoptimizeIf(ne, instr->environment()); | 2636 DeoptimizeIf(ne, instr->environment()); |
| 2821 | 2637 |
| 2822 // Move the result back to general purpose register r0. | 2638 // Move the result back to general purpose register r0. |
| 2823 __ vmov(result, single_scratch); | 2639 __ vmov(result, single_scratch); |
| 2824 | 2640 |
| 2825 // Test for -0. | 2641 // Test for -0. |
| 2826 Label done; | 2642 Label done; |
| 2827 __ cmp(result, Operand(0)); | 2643 __ cmp(result, Operand(0)); |
| 2828 __ b(ne, &done); | 2644 __ b(ne, &done); |
| 2829 __ vmov(scratch1, input.high()); | 2645 __ vmov(scratch1, input.high()); |
| 2830 __ tst(scratch1, Operand(HeapNumber::kSignMask)); | 2646 __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
| 2831 DeoptimizeIf(ne, instr->environment()); | 2647 DeoptimizeIf(ne, instr->environment()); |
| 2832 __ bind(&done); | 2648 __ bind(&done); |
| 2833 } | 2649 } |
| 2834 | 2650 |
| 2835 | 2651 |
| 2652 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { |
| 2653 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2654 Register result = ToRegister(instr->result()); |
| 2655 Register scratch1 = scratch0(); |
| 2656 Register scratch2 = result; |
| 2657 __ EmitVFPTruncate(kRoundToNearest, |
| 2658 double_scratch0().low(), |
| 2659 input, |
| 2660 scratch1, |
| 2661 scratch2); |
| 2662 DeoptimizeIf(ne, instr->environment()); |
| 2663 __ vmov(result, double_scratch0().low()); |
| 2664 |
| 2665 // Test for -0. |
| 2666 Label done; |
| 2667 __ cmp(result, Operand(0)); |
| 2668 __ b(ne, &done); |
| 2669 __ vmov(scratch1, input.high()); |
| 2670 __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
| 2671 DeoptimizeIf(ne, instr->environment()); |
| 2672 __ bind(&done); |
| 2673 } |
| 2674 |
| 2675 |
| 2836 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { | 2676 void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
| 2837 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); | 2677 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2838 ASSERT(ToDoubleRegister(instr->result()).is(input)); | 2678 ASSERT(ToDoubleRegister(instr->result()).is(input)); |
| 2839 __ vsqrt(input, input); | 2679 __ vsqrt(input, input); |
| 2840 } | 2680 } |
| 2841 | 2681 |
| 2842 | 2682 |
| 2683 void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { |
| 2684 DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2685 Register scratch = scratch0(); |
| 2686 SwVfpRegister single_scratch = double_scratch0().low(); |
| 2687 DoubleRegister double_scratch = double_scratch0(); |
| 2688 ASSERT(ToDoubleRegister(instr->result()).is(input)); |
| 2689 |
| 2690 // Add +0 to convert -0 to +0. |
| 2691 __ mov(scratch, Operand(0)); |
| 2692 __ vmov(single_scratch, scratch); |
| 2693 __ vcvt_f64_s32(double_scratch, single_scratch); |
| 2694 __ vadd(input, input, double_scratch); |
| 2695 __ vsqrt(input, input); |
| 2696 } |
| 2697 |
| 2698 |
| 2699 void LCodeGen::DoPower(LPower* instr) { |
| 2700 LOperand* left = instr->InputAt(0); |
| 2701 LOperand* right = instr->InputAt(1); |
| 2702 Register scratch = scratch0(); |
| 2703 DoubleRegister result_reg = ToDoubleRegister(instr->result()); |
| 2704 Representation exponent_type = instr->hydrogen()->right()->representation(); |
| 2705 if (exponent_type.IsDouble()) { |
| 2706 // Prepare arguments and call C function. |
| 2707 __ PrepareCallCFunction(4, scratch); |
| 2708 __ vmov(r0, r1, ToDoubleRegister(left)); |
| 2709 __ vmov(r2, r3, ToDoubleRegister(right)); |
| 2710 __ CallCFunction(ExternalReference::power_double_double_function(), 4); |
| 2711 } else if (exponent_type.IsInteger32()) { |
| 2712 ASSERT(ToRegister(right).is(r0)); |
| 2713 // Prepare arguments and call C function. |
| 2714 __ PrepareCallCFunction(4, scratch); |
| 2715 __ mov(r2, ToRegister(right)); |
| 2716 __ vmov(r0, r1, ToDoubleRegister(left)); |
| 2717 __ CallCFunction(ExternalReference::power_double_int_function(), 4); |
| 2718 } else { |
| 2719 ASSERT(exponent_type.IsTagged()); |
| 2720 ASSERT(instr->hydrogen()->left()->representation().IsDouble()); |
| 2721 |
| 2722 Register right_reg = ToRegister(right); |
| 2723 |
| 2724 // Check for smi on the right hand side. |
| 2725 Label non_smi, call; |
| 2726 __ JumpIfNotSmi(right_reg, &non_smi); |
| 2727 |
| 2728 // Untag smi and convert it to a double. |
| 2729 __ SmiUntag(right_reg); |
| 2730 SwVfpRegister single_scratch = double_scratch0().low(); |
| 2731 __ vmov(single_scratch, right_reg); |
| 2732 __ vcvt_f64_s32(result_reg, single_scratch); |
| 2733 __ jmp(&call); |
| 2734 |
| 2735 // Heap number map check. |
| 2736 __ bind(&non_smi); |
| 2737 __ ldr(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset)); |
| 2738 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 2739 __ cmp(scratch, Operand(ip)); |
| 2740 DeoptimizeIf(ne, instr->environment()); |
| 2741 int32_t value_offset = HeapNumber::kValueOffset - kHeapObjectTag; |
| 2742 __ add(scratch, right_reg, Operand(value_offset)); |
| 2743 __ vldr(result_reg, scratch, 0); |
| 2744 |
| 2745 // Prepare arguments and call C function. |
| 2746 __ bind(&call); |
| 2747 __ PrepareCallCFunction(4, scratch); |
| 2748 __ vmov(r0, r1, ToDoubleRegister(left)); |
| 2749 __ vmov(r2, r3, result_reg); |
| 2750 __ CallCFunction(ExternalReference::power_double_double_function(), 4); |
| 2751 } |
| 2752 // Store the result in the result register. |
| 2753 __ GetCFunctionDoubleResult(result_reg); |
| 2754 } |
| 2755 |
| 2756 |
| 2757 void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { |
| 2758 ASSERT(ToDoubleRegister(instr->result()).is(d2)); |
| 2759 TranscendentalCacheStub stub(TranscendentalCache::LOG, |
| 2760 TranscendentalCacheStub::UNTAGGED); |
| 2761 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2762 } |
| 2763 |
| 2764 |
| 2765 void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { |
| 2766 ASSERT(ToDoubleRegister(instr->result()).is(d2)); |
| 2767 TranscendentalCacheStub stub(TranscendentalCache::COS, |
| 2768 TranscendentalCacheStub::UNTAGGED); |
| 2769 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2770 } |
| 2771 |
| 2772 |
| 2773 void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { |
| 2774 ASSERT(ToDoubleRegister(instr->result()).is(d2)); |
| 2775 TranscendentalCacheStub stub(TranscendentalCache::SIN, |
| 2776 TranscendentalCacheStub::UNTAGGED); |
| 2777 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 2778 } |
| 2779 |
| 2780 |
| 2843 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { | 2781 void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { |
| 2844 switch (instr->op()) { | 2782 switch (instr->op()) { |
| 2845 case kMathAbs: | 2783 case kMathAbs: |
| 2846 DoMathAbs(instr); | 2784 DoMathAbs(instr); |
| 2847 break; | 2785 break; |
| 2848 case kMathFloor: | 2786 case kMathFloor: |
| 2849 DoMathFloor(instr); | 2787 DoMathFloor(instr); |
| 2850 break; | 2788 break; |
| 2789 case kMathRound: |
| 2790 DoMathRound(instr); |
| 2791 break; |
| 2851 case kMathSqrt: | 2792 case kMathSqrt: |
| 2852 DoMathSqrt(instr); | 2793 DoMathSqrt(instr); |
| 2853 break; | 2794 break; |
| 2795 case kMathPowHalf: |
| 2796 DoMathPowHalf(instr); |
| 2797 break; |
| 2798 case kMathCos: |
| 2799 DoMathCos(instr); |
| 2800 break; |
| 2801 case kMathSin: |
| 2802 DoMathSin(instr); |
| 2803 break; |
| 2804 case kMathLog: |
| 2805 DoMathLog(instr); |
| 2806 break; |
| 2854 default: | 2807 default: |
| 2855 Abort("Unimplemented type of LUnaryMathOperation."); | 2808 Abort("Unimplemented type of LUnaryMathOperation."); |
| 2856 UNREACHABLE(); | 2809 UNREACHABLE(); |
| 2857 } | 2810 } |
| 2858 } | 2811 } |
| 2859 | 2812 |
| 2860 | 2813 |
| 2861 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { | 2814 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { |
| 2862 ASSERT(ToRegister(instr->result()).is(r0)); | 2815 ASSERT(ToRegister(instr->result()).is(r0)); |
| 2863 | 2816 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2955 } | 2908 } |
| 2956 } | 2909 } |
| 2957 | 2910 |
| 2958 | 2911 |
| 2959 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 2912 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 2960 ASSERT(ToRegister(instr->object()).is(r1)); | 2913 ASSERT(ToRegister(instr->object()).is(r1)); |
| 2961 ASSERT(ToRegister(instr->value()).is(r0)); | 2914 ASSERT(ToRegister(instr->value()).is(r0)); |
| 2962 | 2915 |
| 2963 // Name is always in r2. | 2916 // Name is always in r2. |
| 2964 __ mov(r2, Operand(instr->name())); | 2917 __ mov(r2, Operand(instr->name())); |
| 2965 Handle<Code> ic(Builtins::builtin(info_->is_strict() | 2918 Handle<Code> ic(Builtins::builtin( |
| 2966 ? Builtins::StoreIC_Initialize_Strict | 2919 info_->is_strict() ? Builtins::StoreIC_Initialize_Strict |
| 2967 : Builtins::StoreIC_Initialize)); | 2920 : Builtins::StoreIC_Initialize)); |
| 2968 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2921 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 2969 } | 2922 } |
| 2970 | 2923 |
| 2971 | 2924 |
| 2972 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { | 2925 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { |
| 2973 __ cmp(ToRegister(instr->index()), ToRegister(instr->length())); | 2926 __ cmp(ToRegister(instr->index()), ToRegister(instr->length())); |
| 2974 DeoptimizeIf(hs, instr->environment()); | 2927 DeoptimizeIf(hs, instr->environment()); |
| 2975 } | 2928 } |
| 2976 | 2929 |
| 2977 | 2930 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2994 } | 2947 } |
| 2995 | 2948 |
| 2996 if (instr->hydrogen()->NeedsWriteBarrier()) { | 2949 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2997 // Compute address of modified element and store it into key register. | 2950 // Compute address of modified element and store it into key register. |
| 2998 __ add(key, scratch, Operand(FixedArray::kHeaderSize)); | 2951 __ add(key, scratch, Operand(FixedArray::kHeaderSize)); |
| 2999 __ RecordWrite(elements, key, value); | 2952 __ RecordWrite(elements, key, value); |
| 3000 } | 2953 } |
| 3001 } | 2954 } |
| 3002 | 2955 |
| 3003 | 2956 |
| 2957 void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) { |
| 2958 Register external_pointer = ToRegister(instr->external_pointer()); |
| 2959 Register key = ToRegister(instr->key()); |
| 2960 Register value = ToRegister(instr->value()); |
| 2961 |
| 2962 // Clamp the value to [0..255]. |
| 2963 __ Usat(value, 8, Operand(value)); |
| 2964 __ strb(value, MemOperand(external_pointer, key, LSL, 0)); |
| 2965 } |
| 2966 |
| 2967 |
| 3004 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 2968 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 3005 ASSERT(ToRegister(instr->object()).is(r2)); | 2969 ASSERT(ToRegister(instr->object()).is(r2)); |
| 3006 ASSERT(ToRegister(instr->key()).is(r1)); | 2970 ASSERT(ToRegister(instr->key()).is(r1)); |
| 3007 ASSERT(ToRegister(instr->value()).is(r0)); | 2971 ASSERT(ToRegister(instr->value()).is(r0)); |
| 3008 | 2972 |
| 3009 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 2973 Handle<Code> ic(Builtins::builtin( |
| 2974 info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 2975 : Builtins::KeyedStoreIC_Initialize)); |
| 3010 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2976 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 3011 } | 2977 } |
| 3012 | 2978 |
| 3013 | 2979 |
| 3014 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 2980 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 3015 class DeferredStringCharCodeAt: public LDeferredCode { | 2981 class DeferredStringCharCodeAt: public LDeferredCode { |
| 3016 public: | 2982 public: |
| 3017 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 2983 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 3018 : LDeferredCode(codegen), instr_(instr) { } | 2984 : LDeferredCode(codegen), instr_(instr) { } |
| 3019 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | 2985 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3140 __ SmiTag(index); | 3106 __ SmiTag(index); |
| 3141 __ push(index); | 3107 __ push(index); |
| 3142 } | 3108 } |
| 3143 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); | 3109 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt); |
| 3144 RecordSafepointWithRegisters( | 3110 RecordSafepointWithRegisters( |
| 3145 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); | 3111 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex); |
| 3146 if (FLAG_debug_code) { | 3112 if (FLAG_debug_code) { |
| 3147 __ AbortIfNotSmi(r0); | 3113 __ AbortIfNotSmi(r0); |
| 3148 } | 3114 } |
| 3149 __ SmiUntag(r0); | 3115 __ SmiUntag(r0); |
| 3150 MemOperand result_stack_slot = masm()->SafepointRegisterSlot(result); | 3116 __ StoreToSafepointRegisterSlot(r0, result); |
| 3151 __ str(r0, result_stack_slot); | 3117 __ PopSafepointRegisters(); |
| 3118 } |
| 3119 |
| 3120 |
| 3121 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { |
| 3122 class DeferredStringCharFromCode: public LDeferredCode { |
| 3123 public: |
| 3124 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) |
| 3125 : LDeferredCode(codegen), instr_(instr) { } |
| 3126 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } |
| 3127 private: |
| 3128 LStringCharFromCode* instr_; |
| 3129 }; |
| 3130 |
| 3131 DeferredStringCharFromCode* deferred = |
| 3132 new DeferredStringCharFromCode(this, instr); |
| 3133 |
| 3134 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
| 3135 Register char_code = ToRegister(instr->char_code()); |
| 3136 Register result = ToRegister(instr->result()); |
| 3137 ASSERT(!char_code.is(result)); |
| 3138 |
| 3139 __ cmp(char_code, Operand(String::kMaxAsciiCharCode)); |
| 3140 __ b(hi, deferred->entry()); |
| 3141 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex); |
| 3142 __ add(result, result, Operand(char_code, LSL, kPointerSizeLog2)); |
| 3143 __ ldr(result, FieldMemOperand(result, FixedArray::kHeaderSize)); |
| 3144 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 3145 __ cmp(result, ip); |
| 3146 __ b(eq, deferred->entry()); |
| 3147 __ bind(deferred->exit()); |
| 3148 } |
| 3149 |
| 3150 |
| 3151 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { |
| 3152 Register char_code = ToRegister(instr->char_code()); |
| 3153 Register result = ToRegister(instr->result()); |
| 3154 |
| 3155 // TODO(3095996): Get rid of this. For now, we need to make the |
| 3156 // result register contain a valid pointer because it is already |
| 3157 // contained in the register pointer map. |
| 3158 __ mov(result, Operand(0)); |
| 3159 |
| 3160 __ PushSafepointRegisters(); |
| 3161 __ SmiTag(char_code); |
| 3162 __ push(char_code); |
| 3163 __ CallRuntimeSaveDoubles(Runtime::kCharFromCode); |
| 3164 RecordSafepointWithRegisters( |
| 3165 instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex); |
| 3166 __ StoreToSafepointRegisterSlot(r0, result); |
| 3152 __ PopSafepointRegisters(); | 3167 __ PopSafepointRegisters(); |
| 3153 } | 3168 } |
| 3154 | 3169 |
| 3155 | 3170 |
| 3156 void LCodeGen::DoStringLength(LStringLength* instr) { | 3171 void LCodeGen::DoStringLength(LStringLength* instr) { |
| 3157 Register string = ToRegister(instr->InputAt(0)); | 3172 Register string = ToRegister(instr->InputAt(0)); |
| 3158 Register result = ToRegister(instr->result()); | 3173 Register result = ToRegister(instr->result()); |
| 3159 __ ldr(result, FieldMemOperand(string, String::kLengthOffset)); | 3174 __ ldr(result, FieldMemOperand(string, String::kLengthOffset)); |
| 3160 } | 3175 } |
| 3161 | 3176 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3222 __ b(&done); | 3237 __ b(&done); |
| 3223 } | 3238 } |
| 3224 | 3239 |
| 3225 // Slow case: Call the runtime system to do the number allocation. | 3240 // Slow case: Call the runtime system to do the number allocation. |
| 3226 __ bind(&slow); | 3241 __ bind(&slow); |
| 3227 | 3242 |
| 3228 // TODO(3095996): Put a valid pointer value in the stack slot where the result | 3243 // TODO(3095996): Put a valid pointer value in the stack slot where the result |
| 3229 // register is stored, as this register is in the pointer map, but contains an | 3244 // register is stored, as this register is in the pointer map, but contains an |
| 3230 // integer value. | 3245 // integer value. |
| 3231 __ mov(ip, Operand(0)); | 3246 __ mov(ip, Operand(0)); |
| 3232 int reg_stack_index = __ SafepointRegisterStackIndex(reg.code()); | 3247 __ StoreToSafepointRegisterSlot(ip, reg); |
| 3233 __ str(ip, MemOperand(sp, reg_stack_index * kPointerSize)); | |
| 3234 | |
| 3235 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 3248 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 3236 RecordSafepointWithRegisters( | 3249 RecordSafepointWithRegisters( |
| 3237 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 3250 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 3238 if (!reg.is(r0)) __ mov(reg, r0); | 3251 if (!reg.is(r0)) __ mov(reg, r0); |
| 3239 | 3252 |
| 3240 // Done. Put the value in dbl_scratch into the value of the allocated heap | 3253 // Done. Put the value in dbl_scratch into the value of the allocated heap |
| 3241 // number. | 3254 // number. |
| 3242 __ bind(&done); | 3255 __ bind(&done); |
| 3243 __ sub(ip, reg, Operand(kHeapObjectTag)); | 3256 __ sub(ip, reg, Operand(kHeapObjectTag)); |
| 3244 __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset); | 3257 __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset); |
| 3245 __ str(reg, MemOperand(sp, reg_stack_index * kPointerSize)); | 3258 __ StoreToSafepointRegisterSlot(reg, reg); |
| 3246 __ PopSafepointRegisters(); | 3259 __ PopSafepointRegisters(); |
| 3247 } | 3260 } |
| 3248 | 3261 |
| 3249 | 3262 |
| 3250 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 3263 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| 3251 class DeferredNumberTagD: public LDeferredCode { | 3264 class DeferredNumberTagD: public LDeferredCode { |
| 3252 public: | 3265 public: |
| 3253 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 3266 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 3254 : LDeferredCode(codegen), instr_(instr) { } | 3267 : LDeferredCode(codegen), instr_(instr) { } |
| 3255 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 3268 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3280 // TODO(3095996): Get rid of this. For now, we need to make the | 3293 // TODO(3095996): Get rid of this. For now, we need to make the |
| 3281 // result register contain a valid pointer because it is already | 3294 // result register contain a valid pointer because it is already |
| 3282 // contained in the register pointer map. | 3295 // contained in the register pointer map. |
| 3283 Register reg = ToRegister(instr->result()); | 3296 Register reg = ToRegister(instr->result()); |
| 3284 __ mov(reg, Operand(0)); | 3297 __ mov(reg, Operand(0)); |
| 3285 | 3298 |
| 3286 __ PushSafepointRegisters(); | 3299 __ PushSafepointRegisters(); |
| 3287 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 3300 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 3288 RecordSafepointWithRegisters( | 3301 RecordSafepointWithRegisters( |
| 3289 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); | 3302 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
| 3290 int reg_stack_index = __ SafepointRegisterStackIndex(reg.code()); | 3303 __ StoreToSafepointRegisterSlot(r0, reg); |
| 3291 __ str(r0, MemOperand(sp, reg_stack_index * kPointerSize)); | |
| 3292 __ PopSafepointRegisters(); | 3304 __ PopSafepointRegisters(); |
| 3293 } | 3305 } |
| 3294 | 3306 |
| 3295 | 3307 |
| 3296 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 3308 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 3297 LOperand* input = instr->InputAt(0); | 3309 LOperand* input = instr->InputAt(0); |
| 3298 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3310 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 3299 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); | 3311 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); |
| 3300 __ SmiTag(ToRegister(input)); | 3312 __ SmiTag(ToRegister(input)); |
| 3301 } | 3313 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3361 public: | 3373 public: |
| 3362 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) | 3374 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
| 3363 : LDeferredCode(codegen), instr_(instr) { } | 3375 : LDeferredCode(codegen), instr_(instr) { } |
| 3364 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } | 3376 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } |
| 3365 private: | 3377 private: |
| 3366 LTaggedToI* instr_; | 3378 LTaggedToI* instr_; |
| 3367 }; | 3379 }; |
| 3368 | 3380 |
| 3369 | 3381 |
| 3370 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { | 3382 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
| 3383 Register input_reg = ToRegister(instr->InputAt(0)); |
| 3384 Register scratch1 = scratch0(); |
| 3385 Register scratch2 = ToRegister(instr->TempAt(0)); |
| 3386 DwVfpRegister double_scratch = double_scratch0(); |
| 3387 SwVfpRegister single_scratch = double_scratch.low(); |
| 3388 |
| 3389 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); |
| 3390 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); |
| 3391 |
| 3371 Label done; | 3392 Label done; |
| 3372 Register input_reg = ToRegister(instr->InputAt(0)); | |
| 3373 Register scratch = scratch0(); | |
| 3374 DoubleRegister dbl_scratch = d0; | |
| 3375 SwVfpRegister flt_scratch = s0; | |
| 3376 DoubleRegister dbl_tmp = ToDoubleRegister(instr->TempAt(0)); | |
| 3377 | 3393 |
| 3378 // Heap number map check. | 3394 // Heap number map check. |
| 3379 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); | 3395 __ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset)); |
| 3380 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3396 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 3381 __ cmp(scratch, Operand(ip)); | 3397 __ cmp(scratch1, Operand(ip)); |
| 3382 | 3398 |
| 3383 if (instr->truncating()) { | 3399 if (instr->truncating()) { |
| 3400 Register scratch3 = ToRegister(instr->TempAt(1)); |
| 3401 DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2)); |
| 3402 ASSERT(!scratch3.is(input_reg) && |
| 3403 !scratch3.is(scratch1) && |
| 3404 !scratch3.is(scratch2)); |
| 3405 // Performs a truncating conversion of a floating point number as used by |
| 3406 // the JS bitwise operations. |
| 3384 Label heap_number; | 3407 Label heap_number; |
| 3385 __ b(eq, &heap_number); | 3408 __ b(eq, &heap_number); |
| 3386 // Check for undefined. Undefined is converted to zero for truncating | 3409 // Check for undefined. Undefined is converted to zero for truncating |
| 3387 // conversions. | 3410 // conversions. |
| 3388 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 3411 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 3389 __ cmp(input_reg, Operand(ip)); | 3412 __ cmp(input_reg, Operand(ip)); |
| 3390 DeoptimizeIf(ne, instr->environment()); | 3413 DeoptimizeIf(ne, instr->environment()); |
| 3391 __ mov(input_reg, Operand(0)); | 3414 __ mov(input_reg, Operand(0)); |
| 3392 __ b(&done); | 3415 __ b(&done); |
| 3393 | 3416 |
| 3394 __ bind(&heap_number); | 3417 __ bind(&heap_number); |
| 3395 __ sub(ip, input_reg, Operand(kHeapObjectTag)); | 3418 __ sub(scratch1, input_reg, Operand(kHeapObjectTag)); |
| 3396 __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset); | 3419 __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset); |
| 3397 __ vcmp(dbl_tmp, 0.0); // Sets overflow bit in FPSCR flags if NaN. | 3420 |
| 3398 __ vcvt_s32_f64(flt_scratch, dbl_tmp); | 3421 __ EmitECMATruncate(input_reg, |
| 3399 __ vmov(input_reg, flt_scratch); // 32-bit result of conversion. | 3422 double_scratch2, |
| 3400 __ vmrs(pc); // Move vector status bits to normal status bits. | 3423 single_scratch, |
| 3401 // Overflow bit is set if dbl_tmp is Nan. | 3424 scratch1, |
| 3402 __ cmn(input_reg, Operand(1), vc); // 0x7fffffff + 1 -> overflow. | 3425 scratch2, |
| 3403 __ cmp(input_reg, Operand(1), vc); // 0x80000000 - 1 -> overflow. | 3426 scratch3); |
| 3404 DeoptimizeIf(vs, instr->environment()); // Saturation may have occured. | |
| 3405 | 3427 |
| 3406 } else { | 3428 } else { |
| 3429 CpuFeatures::Scope scope(VFP3); |
| 3407 // Deoptimize if we don't have a heap number. | 3430 // Deoptimize if we don't have a heap number. |
| 3408 DeoptimizeIf(ne, instr->environment()); | 3431 DeoptimizeIf(ne, instr->environment()); |
| 3409 | 3432 |
| 3410 __ sub(ip, input_reg, Operand(kHeapObjectTag)); | 3433 __ sub(ip, input_reg, Operand(kHeapObjectTag)); |
| 3411 __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset); | 3434 __ vldr(double_scratch, ip, HeapNumber::kValueOffset); |
| 3412 __ vcvt_s32_f64(flt_scratch, dbl_tmp); | 3435 __ EmitVFPTruncate(kRoundToZero, |
| 3413 __ vmov(input_reg, flt_scratch); // 32-bit result of conversion. | 3436 single_scratch, |
| 3414 // Non-truncating conversion means that we cannot lose bits, so we convert | 3437 double_scratch, |
| 3415 // back to check; note that using non-overlapping s and d regs would be | 3438 scratch1, |
| 3416 // slightly faster. | 3439 scratch2, |
| 3417 __ vcvt_f64_s32(dbl_scratch, flt_scratch); | 3440 kCheckForInexactConversion); |
| 3418 __ VFPCompareAndSetFlags(dbl_scratch, dbl_tmp); | 3441 DeoptimizeIf(ne, instr->environment()); |
| 3419 DeoptimizeIf(ne, instr->environment()); // Not equal or unordered. | 3442 // Load the result. |
| 3443 __ vmov(input_reg, single_scratch); |
| 3444 |
| 3420 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3445 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3421 __ tst(input_reg, Operand(input_reg)); | 3446 __ cmp(input_reg, Operand(0)); |
| 3422 __ b(ne, &done); | 3447 __ b(ne, &done); |
| 3423 __ vmov(lr, ip, dbl_tmp); | 3448 __ vmov(scratch1, double_scratch.high()); |
| 3424 __ tst(ip, Operand(1 << 31)); // Test sign bit. | 3449 __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
| 3425 DeoptimizeIf(ne, instr->environment()); | 3450 DeoptimizeIf(ne, instr->environment()); |
| 3426 } | 3451 } |
| 3427 } | 3452 } |
| 3428 __ bind(&done); | 3453 __ bind(&done); |
| 3429 } | 3454 } |
| 3430 | 3455 |
| 3431 | 3456 |
| 3432 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { | 3457 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
| 3433 LOperand* input = instr->InputAt(0); | 3458 LOperand* input = instr->InputAt(0); |
| 3434 ASSERT(input->IsRegister()); | 3459 ASSERT(input->IsRegister()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3456 ASSERT(result->IsDoubleRegister()); | 3481 ASSERT(result->IsDoubleRegister()); |
| 3457 | 3482 |
| 3458 Register input_reg = ToRegister(input); | 3483 Register input_reg = ToRegister(input); |
| 3459 DoubleRegister result_reg = ToDoubleRegister(result); | 3484 DoubleRegister result_reg = ToDoubleRegister(result); |
| 3460 | 3485 |
| 3461 EmitNumberUntagD(input_reg, result_reg, instr->environment()); | 3486 EmitNumberUntagD(input_reg, result_reg, instr->environment()); |
| 3462 } | 3487 } |
| 3463 | 3488 |
| 3464 | 3489 |
| 3465 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { | 3490 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
| 3466 LOperand* input = instr->InputAt(0); | 3491 Register result_reg = ToRegister(instr->result()); |
| 3467 ASSERT(input->IsDoubleRegister()); | |
| 3468 LOperand* result = instr->result(); | |
| 3469 ASSERT(result->IsRegister()); | |
| 3470 | |
| 3471 DoubleRegister double_input = ToDoubleRegister(input); | |
| 3472 Register result_reg = ToRegister(result); | |
| 3473 SwVfpRegister single_scratch = double_scratch0().low(); | |
| 3474 Register scratch1 = scratch0(); | 3492 Register scratch1 = scratch0(); |
| 3475 Register scratch2 = ToRegister(instr->TempAt(0)); | 3493 Register scratch2 = ToRegister(instr->TempAt(0)); |
| 3494 DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0)); |
| 3495 DwVfpRegister double_scratch = double_scratch0(); |
| 3496 SwVfpRegister single_scratch = double_scratch0().low(); |
| 3476 | 3497 |
| 3477 VFPRoundingMode rounding_mode = instr->truncating() ? kRoundToMinusInf | 3498 Label done; |
| 3478 : kRoundToNearest; | |
| 3479 | 3499 |
| 3480 EmitVFPTruncate(rounding_mode, | 3500 if (instr->truncating()) { |
| 3481 single_scratch, | 3501 Register scratch3 = ToRegister(instr->TempAt(1)); |
| 3482 double_input, | 3502 __ EmitECMATruncate(result_reg, |
| 3483 scratch1, | 3503 double_input, |
| 3484 scratch2); | 3504 single_scratch, |
| 3485 // Deoptimize if we had a vfp invalid exception. | 3505 scratch1, |
| 3486 DeoptimizeIf(ne, instr->environment()); | 3506 scratch2, |
| 3487 // Retrieve the result. | 3507 scratch3); |
| 3488 __ vmov(result_reg, single_scratch); | 3508 } else { |
| 3489 | 3509 VFPRoundingMode rounding_mode = kRoundToMinusInf; |
| 3490 if (instr->truncating() && | 3510 __ EmitVFPTruncate(rounding_mode, |
| 3491 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3511 single_scratch, |
| 3492 Label done; | 3512 double_input, |
| 3493 __ cmp(result_reg, Operand(0)); | 3513 scratch1, |
| 3494 __ b(ne, &done); | 3514 scratch2, |
| 3495 // Check for -0. | 3515 kCheckForInexactConversion); |
| 3496 __ vmov(scratch1, double_input.high()); | 3516 // Deoptimize if we had a vfp invalid exception, |
| 3497 __ tst(scratch1, Operand(HeapNumber::kSignMask)); | 3517 // including inexact operation. |
| 3498 DeoptimizeIf(ne, instr->environment()); | 3518 DeoptimizeIf(ne, instr->environment()); |
| 3499 | 3519 // Retrieve the result. |
| 3520 __ vmov(result_reg, single_scratch); |
| 3521 } |
| 3500 __ bind(&done); | 3522 __ bind(&done); |
| 3501 } | |
| 3502 } | 3523 } |
| 3503 | 3524 |
| 3504 | 3525 |
| 3505 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 3526 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 3506 LOperand* input = instr->InputAt(0); | 3527 LOperand* input = instr->InputAt(0); |
| 3507 ASSERT(input->IsRegister()); | 3528 ASSERT(input->IsRegister()); |
| 3508 __ tst(ToRegister(input), Operand(kSmiTagMask)); | 3529 __ tst(ToRegister(input), Operand(kSmiTagMask)); |
| 3509 DeoptimizeIf(instr->condition(), instr->environment()); | 3530 DeoptimizeIf(instr->condition(), instr->environment()); |
| 3510 } | 3531 } |
| 3511 | 3532 |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3761 } | 3782 } |
| 3762 | 3783 |
| 3763 | 3784 |
| 3764 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 3785 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
| 3765 Label* false_label, | 3786 Label* false_label, |
| 3766 Register input, | 3787 Register input, |
| 3767 Handle<String> type_name) { | 3788 Handle<String> type_name) { |
| 3768 Condition final_branch_condition = kNoCondition; | 3789 Condition final_branch_condition = kNoCondition; |
| 3769 Register scratch = scratch0(); | 3790 Register scratch = scratch0(); |
| 3770 if (type_name->Equals(Heap::number_symbol())) { | 3791 if (type_name->Equals(Heap::number_symbol())) { |
| 3771 __ tst(input, Operand(kSmiTagMask)); | 3792 __ JumpIfSmi(input, true_label); |
| 3772 __ b(eq, true_label); | |
| 3773 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); | 3793 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 3774 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3794 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 3775 __ cmp(input, Operand(ip)); | 3795 __ cmp(input, Operand(ip)); |
| 3776 final_branch_condition = eq; | 3796 final_branch_condition = eq; |
| 3777 | 3797 |
| 3778 } else if (type_name->Equals(Heap::string_symbol())) { | 3798 } else if (type_name->Equals(Heap::string_symbol())) { |
| 3779 __ tst(input, Operand(kSmiTagMask)); | 3799 __ JumpIfSmi(input, false_label); |
| 3780 __ b(eq, false_label); | 3800 __ CompareObjectType(input, input, scratch, FIRST_NONSTRING_TYPE); |
| 3781 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); | 3801 __ b(ge, false_label); |
| 3782 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); | 3802 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); |
| 3783 __ tst(ip, Operand(1 << Map::kIsUndetectable)); | 3803 __ tst(ip, Operand(1 << Map::kIsUndetectable)); |
| 3784 __ b(ne, false_label); | 3804 final_branch_condition = eq; |
| 3785 __ CompareInstanceType(input, scratch, FIRST_NONSTRING_TYPE); | |
| 3786 final_branch_condition = lo; | |
| 3787 | 3805 |
| 3788 } else if (type_name->Equals(Heap::boolean_symbol())) { | 3806 } else if (type_name->Equals(Heap::boolean_symbol())) { |
| 3789 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 3807 __ CompareRoot(input, Heap::kTrueValueRootIndex); |
| 3790 __ cmp(input, ip); | |
| 3791 __ b(eq, true_label); | 3808 __ b(eq, true_label); |
| 3792 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 3809 __ CompareRoot(input, Heap::kFalseValueRootIndex); |
| 3793 __ cmp(input, ip); | |
| 3794 final_branch_condition = eq; | 3810 final_branch_condition = eq; |
| 3795 | 3811 |
| 3796 } else if (type_name->Equals(Heap::undefined_symbol())) { | 3812 } else if (type_name->Equals(Heap::undefined_symbol())) { |
| 3797 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 3813 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); |
| 3798 __ cmp(input, ip); | |
| 3799 __ b(eq, true_label); | 3814 __ b(eq, true_label); |
| 3800 __ tst(input, Operand(kSmiTagMask)); | 3815 __ JumpIfSmi(input, false_label); |
| 3801 __ b(eq, false_label); | |
| 3802 // Check for undetectable objects => true. | 3816 // Check for undetectable objects => true. |
| 3803 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); | 3817 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 3804 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); | 3818 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); |
| 3805 __ tst(ip, Operand(1 << Map::kIsUndetectable)); | 3819 __ tst(ip, Operand(1 << Map::kIsUndetectable)); |
| 3806 final_branch_condition = ne; | 3820 final_branch_condition = ne; |
| 3807 | 3821 |
| 3808 } else if (type_name->Equals(Heap::function_symbol())) { | 3822 } else if (type_name->Equals(Heap::function_symbol())) { |
| 3809 __ tst(input, Operand(kSmiTagMask)); | 3823 __ JumpIfSmi(input, false_label); |
| 3810 __ b(eq, false_label); | 3824 __ CompareObjectType(input, input, scratch, FIRST_FUNCTION_CLASS_TYPE); |
| 3811 __ CompareObjectType(input, input, scratch, JS_FUNCTION_TYPE); | 3825 final_branch_condition = ge; |
| 3812 __ b(eq, true_label); | |
| 3813 // Regular expressions => 'function' (they are callable). | |
| 3814 __ CompareInstanceType(input, scratch, JS_REGEXP_TYPE); | |
| 3815 final_branch_condition = eq; | |
| 3816 | 3826 |
| 3817 } else if (type_name->Equals(Heap::object_symbol())) { | 3827 } else if (type_name->Equals(Heap::object_symbol())) { |
| 3818 __ tst(input, Operand(kSmiTagMask)); | 3828 __ JumpIfSmi(input, false_label); |
| 3819 __ b(eq, false_label); | 3829 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 3820 __ LoadRoot(ip, Heap::kNullValueRootIndex); | |
| 3821 __ cmp(input, ip); | |
| 3822 __ b(eq, true_label); | 3830 __ b(eq, true_label); |
| 3823 // Regular expressions => 'function', not 'object'. | 3831 __ CompareObjectType(input, input, scratch, FIRST_JS_OBJECT_TYPE); |
| 3824 __ CompareObjectType(input, input, scratch, JS_REGEXP_TYPE); | 3832 __ b(lo, false_label); |
| 3825 __ b(eq, false_label); | 3833 __ CompareInstanceType(input, scratch, FIRST_FUNCTION_CLASS_TYPE); |
| 3834 __ b(hs, false_label); |
| 3826 // Check for undetectable objects => false. | 3835 // Check for undetectable objects => false. |
| 3827 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); | 3836 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); |
| 3828 __ tst(ip, Operand(1 << Map::kIsUndetectable)); | 3837 __ tst(ip, Operand(1 << Map::kIsUndetectable)); |
| 3829 __ b(ne, false_label); | 3838 final_branch_condition = eq; |
| 3830 // Check for JS objects => true. | |
| 3831 __ CompareInstanceType(input, scratch, FIRST_JS_OBJECT_TYPE); | |
| 3832 __ b(lo, false_label); | |
| 3833 __ CompareInstanceType(input, scratch, LAST_JS_OBJECT_TYPE); | |
| 3834 final_branch_condition = ls; | |
| 3835 | 3839 |
| 3836 } else { | 3840 } else { |
| 3837 final_branch_condition = ne; | 3841 final_branch_condition = ne; |
| 3838 __ b(false_label); | 3842 __ b(false_label); |
| 3839 // A dead branch instruction will be generated after this point. | 3843 // A dead branch instruction will be generated after this point. |
| 3840 } | 3844 } |
| 3841 | 3845 |
| 3842 return final_branch_condition; | 3846 return final_branch_condition; |
| 3843 } | 3847 } |
| 3844 | 3848 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3946 ASSERT(!environment->HasBeenRegistered()); | 3950 ASSERT(!environment->HasBeenRegistered()); |
| 3947 RegisterEnvironmentForDeoptimization(environment); | 3951 RegisterEnvironmentForDeoptimization(environment); |
| 3948 ASSERT(osr_pc_offset_ == -1); | 3952 ASSERT(osr_pc_offset_ == -1); |
| 3949 osr_pc_offset_ = masm()->pc_offset(); | 3953 osr_pc_offset_ = masm()->pc_offset(); |
| 3950 } | 3954 } |
| 3951 | 3955 |
| 3952 | 3956 |
| 3953 #undef __ | 3957 #undef __ |
| 3954 | 3958 |
| 3955 } } // namespace v8::internal | 3959 } } // namespace v8::internal |
| OLD | NEW |