| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 info()->CommitDependencies(code); | 91 info()->CommitDependencies(code); |
| 92 } | 92 } |
| 93 | 93 |
| 94 | 94 |
| 95 void LChunkBuilder::Abort(BailoutReason reason) { | 95 void LChunkBuilder::Abort(BailoutReason reason) { |
| 96 info()->set_bailout_reason(reason); | 96 info()->set_bailout_reason(reason); |
| 97 status_ = ABORTED; | 97 status_ = ABORTED; |
| 98 } | 98 } |
| 99 | 99 |
| 100 | 100 |
| 101 void LCodeGen::SaveCallerDoubles() { |
| 102 ASSERT(info()->saves_caller_doubles()); |
| 103 ASSERT(NeedsEagerFrame()); |
| 104 Comment(";;; Save clobbered callee double registers"); |
| 105 int count = 0; |
| 106 BitVector* doubles = chunk()->allocated_double_registers(); |
| 107 BitVector::Iterator save_iterator(doubles); |
| 108 while (!save_iterator.Done()) { |
| 109 __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), |
| 110 MemOperand(sp, count * kDoubleSize)); |
| 111 save_iterator.Advance(); |
| 112 count++; |
| 113 } |
| 114 } |
| 115 |
| 116 |
| 117 void LCodeGen::RestoreCallerDoubles() { |
| 118 ASSERT(info()->saves_caller_doubles()); |
| 119 ASSERT(NeedsEagerFrame()); |
| 120 Comment(";;; Restore clobbered callee double registers"); |
| 121 BitVector* doubles = chunk()->allocated_double_registers(); |
| 122 BitVector::Iterator save_iterator(doubles); |
| 123 int count = 0; |
| 124 while (!save_iterator.Done()) { |
| 125 __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), |
| 126 MemOperand(sp, count * kDoubleSize)); |
| 127 save_iterator.Advance(); |
| 128 count++; |
| 129 } |
| 130 } |
| 131 |
| 132 |
| 101 bool LCodeGen::GeneratePrologue() { | 133 bool LCodeGen::GeneratePrologue() { |
| 102 ASSERT(is_generating()); | 134 ASSERT(is_generating()); |
| 103 | 135 |
| 104 if (info()->IsOptimizing()) { | 136 if (info()->IsOptimizing()) { |
| 105 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 137 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 106 | 138 |
| 107 #ifdef DEBUG | 139 #ifdef DEBUG |
| 108 if (strlen(FLAG_stop_at) > 0 && | 140 if (strlen(FLAG_stop_at) > 0 && |
| 109 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 141 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 110 __ stop("stop_at"); | 142 __ stop("stop_at"); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 __ sw(a1, MemOperand(a0, 2 * kPointerSize)); | 185 __ sw(a1, MemOperand(a0, 2 * kPointerSize)); |
| 154 __ Branch(&loop, ne, a0, Operand(sp)); | 186 __ Branch(&loop, ne, a0, Operand(sp)); |
| 155 __ pop(a1); | 187 __ pop(a1); |
| 156 __ pop(a0); | 188 __ pop(a0); |
| 157 } else { | 189 } else { |
| 158 __ Subu(sp, sp, Operand(slots * kPointerSize)); | 190 __ Subu(sp, sp, Operand(slots * kPointerSize)); |
| 159 } | 191 } |
| 160 } | 192 } |
| 161 | 193 |
| 162 if (info()->saves_caller_doubles()) { | 194 if (info()->saves_caller_doubles()) { |
| 163 Comment(";;; Save clobbered callee double registers"); | 195 SaveCallerDoubles(); |
| 164 int count = 0; | |
| 165 BitVector* doubles = chunk()->allocated_double_registers(); | |
| 166 BitVector::Iterator save_iterator(doubles); | |
| 167 while (!save_iterator.Done()) { | |
| 168 __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), | |
| 169 MemOperand(sp, count * kDoubleSize)); | |
| 170 save_iterator.Advance(); | |
| 171 count++; | |
| 172 } | |
| 173 } | 196 } |
| 174 | 197 |
| 175 // Possibly allocate a local context. | 198 // Possibly allocate a local context. |
| 176 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 199 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 177 if (heap_slots > 0) { | 200 if (heap_slots > 0) { |
| 178 Comment(";;; Allocate local context"); | 201 Comment(";;; Allocate local context"); |
| 179 // Argument to NewContext is the function, which is in a1. | 202 // Argument to NewContext is the function, which is in a1. |
| 180 __ push(a1); | 203 __ push(a1); |
| 181 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 204 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 182 FastNewContextStub stub(heap_slots); | 205 FastNewContextStub stub(heap_slots); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 code->instr()->Mnemonic()); | 273 code->instr()->Mnemonic()); |
| 251 __ bind(code->entry()); | 274 __ bind(code->entry()); |
| 252 if (NeedsDeferredFrame()) { | 275 if (NeedsDeferredFrame()) { |
| 253 Comment(";;; Build frame"); | 276 Comment(";;; Build frame"); |
| 254 ASSERT(!frame_is_built_); | 277 ASSERT(!frame_is_built_); |
| 255 ASSERT(info()->IsStub()); | 278 ASSERT(info()->IsStub()); |
| 256 frame_is_built_ = true; | 279 frame_is_built_ = true; |
| 257 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); | 280 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); |
| 258 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); | 281 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| 259 __ push(scratch0()); | 282 __ push(scratch0()); |
| 260 __ Addu(fp, sp, Operand(2 * kPointerSize)); | 283 __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); |
| 261 Comment(";;; Deferred code"); | 284 Comment(";;; Deferred code"); |
| 262 } | 285 } |
| 263 code->Generate(); | 286 code->Generate(); |
| 264 if (NeedsDeferredFrame()) { | 287 if (NeedsDeferredFrame()) { |
| 265 Comment(";;; Destroy frame"); | 288 Comment(";;; Destroy frame"); |
| 266 ASSERT(frame_is_built_); | 289 ASSERT(frame_is_built_); |
| 267 __ pop(at); | 290 __ pop(at); |
| 268 __ MultiPop(cp.bit() | fp.bit() | ra.bit()); | 291 __ MultiPop(cp.bit() | fp.bit() | ra.bit()); |
| 269 frame_is_built_ = false; | 292 frame_is_built_ = false; |
| 270 } | 293 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 291 Address entry = deopt_jump_table_[i].address; | 314 Address entry = deopt_jump_table_[i].address; |
| 292 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; | 315 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; |
| 293 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); | 316 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); |
| 294 if (id == Deoptimizer::kNotDeoptimizationEntry) { | 317 if (id == Deoptimizer::kNotDeoptimizationEntry) { |
| 295 Comment(";;; jump table entry %d.", i); | 318 Comment(";;; jump table entry %d.", i); |
| 296 } else { | 319 } else { |
| 297 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); | 320 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); |
| 298 } | 321 } |
| 299 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry))); | 322 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry))); |
| 300 if (deopt_jump_table_[i].needs_frame) { | 323 if (deopt_jump_table_[i].needs_frame) { |
| 324 ASSERT(!info()->saves_caller_doubles()); |
| 301 if (needs_frame.is_bound()) { | 325 if (needs_frame.is_bound()) { |
| 302 __ Branch(&needs_frame); | 326 __ Branch(&needs_frame); |
| 303 } else { | 327 } else { |
| 304 __ bind(&needs_frame); | 328 __ bind(&needs_frame); |
| 305 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); | 329 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); |
| 306 // This variant of deopt can only be used with stubs. Since we don't | 330 // This variant of deopt can only be used with stubs. Since we don't |
| 307 // have a function pointer to install in the stack frame that we're | 331 // have a function pointer to install in the stack frame that we're |
| 308 // building, install a special marker there instead. | 332 // building, install a special marker there instead. |
| 309 ASSERT(info()->IsStub()); | 333 ASSERT(info()->IsStub()); |
| 310 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); | 334 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); |
| 311 __ push(scratch0()); | 335 __ push(scratch0()); |
| 312 __ Addu(fp, sp, Operand(2 * kPointerSize)); | 336 __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); |
| 313 __ Call(t9); | 337 __ Call(t9); |
| 314 } | 338 } |
| 315 } else { | 339 } else { |
| 340 if (info()->saves_caller_doubles()) { |
| 341 ASSERT(info()->IsStub()); |
| 342 RestoreCallerDoubles(); |
| 343 } |
| 316 __ Call(t9); | 344 __ Call(t9); |
| 317 } | 345 } |
| 318 } | 346 } |
| 319 __ RecordComment("]"); | 347 __ RecordComment("]"); |
| 320 | 348 |
| 321 // The deoptimization jump table is the last part of the instruction | 349 // The deoptimization jump table is the last part of the instruction |
| 322 // sequence. Mark the generated code as done unless we bailed out. | 350 // sequence. Mark the generated code as done unless we bailed out. |
| 323 if (!is_aborted()) status_ = DONE; | 351 if (!is_aborted()) status_ = DONE; |
| 324 return !is_aborted(); | 352 return !is_aborted(); |
| 325 } | 353 } |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 } else if (op->IsDoubleRegister()) { | 509 } else if (op->IsDoubleRegister()) { |
| 482 Abort(kToOperandIsDoubleRegisterUnimplemented); | 510 Abort(kToOperandIsDoubleRegisterUnimplemented); |
| 483 return Operand(0); | 511 return Operand(0); |
| 484 } | 512 } |
| 485 // Stack slots not implemented, use ToMemOperand instead. | 513 // Stack slots not implemented, use ToMemOperand instead. |
| 486 UNREACHABLE(); | 514 UNREACHABLE(); |
| 487 return Operand(0); | 515 return Operand(0); |
| 488 } | 516 } |
| 489 | 517 |
| 490 | 518 |
| 519 static int ArgumentsOffsetWithoutFrame(int index) { |
| 520 ASSERT(index < 0); |
| 521 return -(index + 1) * kPointerSize; |
| 522 } |
| 523 |
| 524 |
| 491 MemOperand LCodeGen::ToMemOperand(LOperand* op) const { | 525 MemOperand LCodeGen::ToMemOperand(LOperand* op) const { |
| 492 ASSERT(!op->IsRegister()); | 526 ASSERT(!op->IsRegister()); |
| 493 ASSERT(!op->IsDoubleRegister()); | 527 ASSERT(!op->IsDoubleRegister()); |
| 494 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); | 528 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); |
| 495 return MemOperand(fp, StackSlotOffset(op->index())); | 529 if (NeedsEagerFrame()) { |
| 530 return MemOperand(fp, StackSlotOffset(op->index())); |
| 531 } else { |
| 532 // Retrieve parameter without eager stack-frame relative to the |
| 533 // stack-pointer. |
| 534 return MemOperand(sp, ArgumentsOffsetWithoutFrame(op->index())); |
| 535 } |
| 496 } | 536 } |
| 497 | 537 |
| 498 | 538 |
| 499 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { | 539 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { |
| 500 ASSERT(op->IsDoubleStackSlot()); | 540 ASSERT(op->IsDoubleStackSlot()); |
| 501 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize); | 541 if (NeedsEagerFrame()) { |
| 542 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize); |
| 543 } else { |
| 544 // Retrieve parameter without eager stack-frame relative to the |
| 545 // stack-pointer. |
| 546 return MemOperand( |
| 547 sp, ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize); |
| 548 } |
| 502 } | 549 } |
| 503 | 550 |
| 504 | 551 |
| 505 void LCodeGen::WriteTranslation(LEnvironment* environment, | 552 void LCodeGen::WriteTranslation(LEnvironment* environment, |
| 506 Translation* translation) { | 553 Translation* translation) { |
| 507 if (environment == NULL) return; | 554 if (environment == NULL) return; |
| 508 | 555 |
| 509 // The translation includes one command per value in the environment. | 556 // The translation includes one command per value in the environment. |
| 510 int translation_size = environment->translation_size(); | 557 int translation_size = environment->translation_size(); |
| 511 // The output frame height does not include the parameters. | 558 // The output frame height does not include the parameters. |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 if (info()->ShouldTrapOnDeopt()) { | 807 if (info()->ShouldTrapOnDeopt()) { |
| 761 Label skip; | 808 Label skip; |
| 762 if (condition != al) { | 809 if (condition != al) { |
| 763 __ Branch(&skip, NegateCondition(condition), src1, src2); | 810 __ Branch(&skip, NegateCondition(condition), src1, src2); |
| 764 } | 811 } |
| 765 __ stop("trap_on_deopt"); | 812 __ stop("trap_on_deopt"); |
| 766 __ bind(&skip); | 813 __ bind(&skip); |
| 767 } | 814 } |
| 768 | 815 |
| 769 ASSERT(info()->IsStub() || frame_is_built_); | 816 ASSERT(info()->IsStub() || frame_is_built_); |
| 770 if (condition == al && frame_is_built_) { | 817 // Go through jump table if we need to handle condition, build frame, or |
| 818 // restore caller doubles. |
| 819 if (condition == al && frame_is_built_ && |
| 820 !info()->saves_caller_doubles()) { |
| 771 __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2); | 821 __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2); |
| 772 } else { | 822 } else { |
| 773 // We often have several deopts to the same entry, reuse the last | 823 // We often have several deopts to the same entry, reuse the last |
| 774 // jump entry if this is the case. | 824 // jump entry if this is the case. |
| 775 if (deopt_jump_table_.is_empty() || | 825 if (deopt_jump_table_.is_empty() || |
| 776 (deopt_jump_table_.last().address != entry) || | 826 (deopt_jump_table_.last().address != entry) || |
| 777 (deopt_jump_table_.last().bailout_type != bailout_type) || | 827 (deopt_jump_table_.last().bailout_type != bailout_type) || |
| 778 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { | 828 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { |
| 779 Deoptimizer::JumpTableEntry table_entry(entry, | 829 Deoptimizer::JumpTableEntry table_entry(entry, |
| 780 bailout_type, | 830 bailout_type, |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1115 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1066 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); | 1116 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
| 1067 } | 1117 } |
| 1068 __ Branch(USE_DELAY_SLOT, &done); | 1118 __ Branch(USE_DELAY_SLOT, &done); |
| 1069 __ subu(result_reg, zero_reg, result_reg); | 1119 __ subu(result_reg, zero_reg, result_reg); |
| 1070 } | 1120 } |
| 1071 | 1121 |
| 1072 __ bind(&left_is_not_negative); | 1122 __ bind(&left_is_not_negative); |
| 1073 __ And(result_reg, left_reg, divisor - 1); | 1123 __ And(result_reg, left_reg, divisor - 1); |
| 1074 __ bind(&done); | 1124 __ bind(&done); |
| 1075 | |
| 1076 } else if (hmod->fixed_right_arg().has_value) { | |
| 1077 const Register left_reg = ToRegister(instr->left()); | |
| 1078 const Register result_reg = ToRegister(instr->result()); | |
| 1079 const Register right_reg = ToRegister(instr->right()); | |
| 1080 | |
| 1081 int32_t divisor = hmod->fixed_right_arg().value; | |
| 1082 ASSERT(IsPowerOf2(divisor)); | |
| 1083 | |
| 1084 // Check if our assumption of a fixed right operand still holds. | |
| 1085 DeoptimizeIf(ne, instr->environment(), right_reg, Operand(divisor)); | |
| 1086 | |
| 1087 Label left_is_not_negative, done; | |
| 1088 if (left->CanBeNegative()) { | |
| 1089 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT, | |
| 1090 &left_is_not_negative, ge, left_reg, Operand(zero_reg)); | |
| 1091 __ subu(result_reg, zero_reg, left_reg); | |
| 1092 __ And(result_reg, result_reg, divisor - 1); | |
| 1093 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 1094 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); | |
| 1095 } | |
| 1096 __ Branch(USE_DELAY_SLOT, &done); | |
| 1097 __ subu(result_reg, zero_reg, result_reg); | |
| 1098 } | |
| 1099 | |
| 1100 __ bind(&left_is_not_negative); | |
| 1101 __ And(result_reg, left_reg, divisor - 1); | |
| 1102 __ bind(&done); | |
| 1103 | |
| 1104 } else { | 1125 } else { |
| 1105 const Register scratch = scratch0(); | 1126 const Register scratch = scratch0(); |
| 1106 const Register left_reg = ToRegister(instr->left()); | 1127 const Register left_reg = ToRegister(instr->left()); |
| 1107 const Register result_reg = ToRegister(instr->result()); | 1128 const Register result_reg = ToRegister(instr->result()); |
| 1108 | 1129 |
| 1109 // div runs in the background while we check for special cases. | 1130 // div runs in the background while we check for special cases. |
| 1110 Register right_reg = EmitLoadRegister(instr->right(), scratch); | 1131 Register right_reg = EmitLoadRegister(instr->right(), scratch); |
| 1111 __ div(left_reg, right_reg); | 1132 __ div(left_reg, right_reg); |
| 1112 | 1133 |
| 1113 Label done; | 1134 Label done; |
| (...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1707 Register object = ToRegister(instr->date()); | 1728 Register object = ToRegister(instr->date()); |
| 1708 Register result = ToRegister(instr->result()); | 1729 Register result = ToRegister(instr->result()); |
| 1709 Register scratch = ToRegister(instr->temp()); | 1730 Register scratch = ToRegister(instr->temp()); |
| 1710 Smi* index = instr->index(); | 1731 Smi* index = instr->index(); |
| 1711 Label runtime, done; | 1732 Label runtime, done; |
| 1712 ASSERT(object.is(a0)); | 1733 ASSERT(object.is(a0)); |
| 1713 ASSERT(result.is(v0)); | 1734 ASSERT(result.is(v0)); |
| 1714 ASSERT(!scratch.is(scratch0())); | 1735 ASSERT(!scratch.is(scratch0())); |
| 1715 ASSERT(!scratch.is(object)); | 1736 ASSERT(!scratch.is(object)); |
| 1716 | 1737 |
| 1717 __ And(at, object, Operand(kSmiTagMask)); | 1738 __ SmiTst(object, at); |
| 1718 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); | 1739 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); |
| 1719 __ GetObjectType(object, scratch, scratch); | 1740 __ GetObjectType(object, scratch, scratch); |
| 1720 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE)); | 1741 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE)); |
| 1721 | 1742 |
| 1722 if (index->value() == 0) { | 1743 if (index->value() == 0) { |
| 1723 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset)); | 1744 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset)); |
| 1724 } else { | 1745 } else { |
| 1725 if (index->value() < JSDate::kFirstUncachedField) { | 1746 if (index->value() < JSDate::kFirstUncachedField) { |
| 1726 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); | 1747 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); |
| 1727 __ li(scratch, Operand(stamp)); | 1748 __ li(scratch, Operand(stamp)); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1794 } | 1815 } |
| 1795 | 1816 |
| 1796 | 1817 |
| 1797 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { | 1818 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { |
| 1798 String::Encoding encoding = instr->hydrogen()->encoding(); | 1819 String::Encoding encoding = instr->hydrogen()->encoding(); |
| 1799 Register string = ToRegister(instr->string()); | 1820 Register string = ToRegister(instr->string()); |
| 1800 Register value = ToRegister(instr->value()); | 1821 Register value = ToRegister(instr->value()); |
| 1801 | 1822 |
| 1802 if (FLAG_debug_code) { | 1823 if (FLAG_debug_code) { |
| 1803 Register scratch = scratch0(); | 1824 Register scratch = scratch0(); |
| 1804 __ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); | 1825 Register index = ToRegister(instr->index()); |
| 1805 __ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | |
| 1806 | |
| 1807 __ And(scratch, scratch, | |
| 1808 Operand(kStringRepresentationMask | kStringEncodingMask)); | |
| 1809 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 1826 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 1810 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 1827 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 1811 __ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING | 1828 int encoding_mask = |
| 1812 ? one_byte_seq_type : two_byte_seq_type)); | 1829 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING |
| 1813 __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg)); | 1830 ? one_byte_seq_type : two_byte_seq_type; |
| 1831 __ EmitSeqStringSetCharCheck(string, index, value, scratch, encoding_mask); |
| 1814 } | 1832 } |
| 1815 | 1833 |
| 1816 MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding); | 1834 MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding); |
| 1817 if (encoding == String::ONE_BYTE_ENCODING) { | 1835 if (encoding == String::ONE_BYTE_ENCODING) { |
| 1818 __ sb(value, operand); | 1836 __ sb(value, operand); |
| 1819 } else { | 1837 } else { |
| 1820 __ sh(value, operand); | 1838 __ sh(value, operand); |
| 1821 } | 1839 } |
| 1822 } | 1840 } |
| 1823 | 1841 |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2121 __ LoadRoot(at, Heap::kNullValueRootIndex); | 2139 __ LoadRoot(at, Heap::kNullValueRootIndex); |
| 2122 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); | 2140 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); |
| 2123 } | 2141 } |
| 2124 | 2142 |
| 2125 if (expected.Contains(ToBooleanStub::SMI)) { | 2143 if (expected.Contains(ToBooleanStub::SMI)) { |
| 2126 // Smis: 0 -> false, all other -> true. | 2144 // Smis: 0 -> false, all other -> true. |
| 2127 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg)); | 2145 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg)); |
| 2128 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); | 2146 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); |
| 2129 } else if (expected.NeedsMap()) { | 2147 } else if (expected.NeedsMap()) { |
| 2130 // If we need a map later and have a Smi -> deopt. | 2148 // If we need a map later and have a Smi -> deopt. |
| 2131 __ And(at, reg, Operand(kSmiTagMask)); | 2149 __ SmiTst(reg, at); |
| 2132 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); | 2150 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); |
| 2133 } | 2151 } |
| 2134 | 2152 |
| 2135 const Register map = scratch0(); | 2153 const Register map = scratch0(); |
| 2136 if (expected.NeedsMap()) { | 2154 if (expected.NeedsMap()) { |
| 2137 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset)); | 2155 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 2138 if (expected.CanBeUndetectable()) { | 2156 if (expected.CanBeUndetectable()) { |
| 2139 // Undetectable -> false. | 2157 // Undetectable -> false. |
| 2140 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); | 2158 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 2141 __ And(at, at, Operand(1 << Map::kIsUndetectable)); | 2159 __ And(at, at, Operand(1 << Map::kIsUndetectable)); |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2783 if (FLAG_trace && info()->IsOptimizing()) { | 2801 if (FLAG_trace && info()->IsOptimizing()) { |
| 2784 // Push the return value on the stack as the parameter. | 2802 // Push the return value on the stack as the parameter. |
| 2785 // Runtime::TraceExit returns its parameter in v0. We're leaving the code | 2803 // Runtime::TraceExit returns its parameter in v0. We're leaving the code |
| 2786 // managed by the register allocator and tearing down the frame, it's | 2804 // managed by the register allocator and tearing down the frame, it's |
| 2787 // safe to write to the context register. | 2805 // safe to write to the context register. |
| 2788 __ push(v0); | 2806 __ push(v0); |
| 2789 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2807 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2790 __ CallRuntime(Runtime::kTraceExit, 1); | 2808 __ CallRuntime(Runtime::kTraceExit, 1); |
| 2791 } | 2809 } |
| 2792 if (info()->saves_caller_doubles()) { | 2810 if (info()->saves_caller_doubles()) { |
| 2793 ASSERT(NeedsEagerFrame()); | 2811 RestoreCallerDoubles(); |
| 2794 BitVector* doubles = chunk()->allocated_double_registers(); | |
| 2795 BitVector::Iterator save_iterator(doubles); | |
| 2796 int count = 0; | |
| 2797 while (!save_iterator.Done()) { | |
| 2798 __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), | |
| 2799 MemOperand(sp, count * kDoubleSize)); | |
| 2800 save_iterator.Advance(); | |
| 2801 count++; | |
| 2802 } | |
| 2803 } | 2812 } |
| 2804 int no_frame_start = -1; | 2813 int no_frame_start = -1; |
| 2805 if (NeedsEagerFrame()) { | 2814 if (NeedsEagerFrame()) { |
| 2806 __ mov(sp, fp); | 2815 __ mov(sp, fp); |
| 2807 no_frame_start = masm_->pc_offset(); | 2816 no_frame_start = masm_->pc_offset(); |
| 2808 __ Pop(ra, fp); | 2817 __ Pop(ra, fp); |
| 2809 } | 2818 } |
| 2810 if (instr->has_constant_parameter_count()) { | 2819 if (instr->has_constant_parameter_count()) { |
| 2811 int parameter_count = ToInteger32(instr->constant_parameter_count()); | 2820 int parameter_count = ToInteger32(instr->constant_parameter_count()); |
| 2812 int32_t sp_delta = (parameter_count + 1) * kPointerSize; | 2821 int32_t sp_delta = (parameter_count + 1) * kPointerSize; |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3043 Register to_reg = ToRegister(instr->result()); | 3052 Register to_reg = ToRegister(instr->result()); |
| 3044 Register from_reg = ToRegister(instr->object()); | 3053 Register from_reg = ToRegister(instr->object()); |
| 3045 __ lw(to_reg, FieldMemOperand(from_reg, | 3054 __ lw(to_reg, FieldMemOperand(from_reg, |
| 3046 ExternalArray::kExternalPointerOffset)); | 3055 ExternalArray::kExternalPointerOffset)); |
| 3047 } | 3056 } |
| 3048 | 3057 |
| 3049 | 3058 |
| 3050 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { | 3059 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
| 3051 Register arguments = ToRegister(instr->arguments()); | 3060 Register arguments = ToRegister(instr->arguments()); |
| 3052 Register result = ToRegister(instr->result()); | 3061 Register result = ToRegister(instr->result()); |
| 3053 if (instr->length()->IsConstantOperand() && | 3062 // There are two words between the frame pointer and the last argument. |
| 3054 instr->index()->IsConstantOperand()) { | 3063 // Subtracting from length accounts for one of them add one more. |
| 3064 if (instr->length()->IsConstantOperand()) { |
| 3065 int const_length = ToInteger32(LConstantOperand::cast(instr->length())); |
| 3066 if (instr->index()->IsConstantOperand()) { |
| 3067 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 3068 int index = (const_length - const_index) + 1; |
| 3069 __ lw(result, MemOperand(arguments, index * kPointerSize)); |
| 3070 } else { |
| 3071 Register index = ToRegister(instr->index()); |
| 3072 __ li(at, Operand(const_length + 1)); |
| 3073 __ Subu(result, at, index); |
| 3074 __ sll(at, result, kPointerSizeLog2); |
| 3075 __ Addu(at, arguments, at); |
| 3076 __ lw(result, MemOperand(at)); |
| 3077 } |
| 3078 } else if (instr->index()->IsConstantOperand()) { |
| 3079 Register length = ToRegister(instr->length()); |
| 3055 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); | 3080 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 3056 int const_length = ToInteger32(LConstantOperand::cast(instr->length())); | 3081 int loc = const_index - 1; |
| 3057 int index = (const_length - const_index) + 1; | 3082 if (loc != 0) { |
| 3058 __ lw(result, MemOperand(arguments, index * kPointerSize)); | 3083 __ Subu(result, length, Operand(loc)); |
| 3084 __ sll(at, result, kPointerSizeLog2); |
| 3085 __ Addu(at, arguments, at); |
| 3086 __ lw(result, MemOperand(at)); |
| 3087 } else { |
| 3088 __ sll(at, length, kPointerSizeLog2); |
| 3089 __ Addu(at, arguments, at); |
| 3090 __ lw(result, MemOperand(at)); |
| 3091 } |
| 3059 } else { | 3092 } else { |
| 3060 Register length = ToRegister(instr->length()); | 3093 Register length = ToRegister(instr->length()); |
| 3061 Register index = ToRegister(instr->index()); | 3094 Register index = ToRegister(instr->index()); |
| 3062 // There are two words between the frame pointer and the last argument. | 3095 __ Subu(result, length, index); |
| 3063 // Subtracting from length accounts for one of them, add one more. | 3096 __ Addu(result, result, 1); |
| 3064 __ subu(length, length, index); | 3097 __ sll(at, result, kPointerSizeLog2); |
| 3065 __ Addu(length, length, Operand(1)); | 3098 __ Addu(at, arguments, at); |
| 3066 __ sll(length, length, kPointerSizeLog2); | 3099 __ lw(result, MemOperand(at)); |
| 3067 __ Addu(at, arguments, Operand(length)); | |
| 3068 __ lw(result, MemOperand(at, 0)); | |
| 3069 } | 3100 } |
| 3070 } | 3101 } |
| 3071 | 3102 |
| 3072 | 3103 |
| 3073 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { | 3104 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
| 3074 Register external_pointer = ToRegister(instr->elements()); | 3105 Register external_pointer = ToRegister(instr->elements()); |
| 3075 Register key = no_reg; | 3106 Register key = no_reg; |
| 3076 ElementsKind elements_kind = instr->elements_kind(); | 3107 ElementsKind elements_kind = instr->elements_kind(); |
| 3077 bool key_is_constant = instr->key()->IsConstantOperand(); | 3108 bool key_is_constant = instr->key()->IsConstantOperand(); |
| 3078 int constant_key = 0; | 3109 int constant_key = 0; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3214 __ sll(scratch, key, kPointerSizeLog2); | 3245 __ sll(scratch, key, kPointerSizeLog2); |
| 3215 __ addu(scratch, elements, scratch); | 3246 __ addu(scratch, elements, scratch); |
| 3216 } | 3247 } |
| 3217 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); | 3248 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); |
| 3218 } | 3249 } |
| 3219 __ lw(result, FieldMemOperand(store_base, offset)); | 3250 __ lw(result, FieldMemOperand(store_base, offset)); |
| 3220 | 3251 |
| 3221 // Check for the hole value. | 3252 // Check for the hole value. |
| 3222 if (instr->hydrogen()->RequiresHoleCheck()) { | 3253 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3223 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { | 3254 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { |
| 3224 __ And(scratch, result, Operand(kSmiTagMask)); | 3255 __ SmiTst(result, scratch); |
| 3225 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); | 3256 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); |
| 3226 } else { | 3257 } else { |
| 3227 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | 3258 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); |
| 3228 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch)); | 3259 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch)); |
| 3229 } | 3260 } |
| 3230 } | 3261 } |
| 3231 } | 3262 } |
| 3232 | 3263 |
| 3233 | 3264 |
| 3234 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { | 3265 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3363 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask)); | 3394 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask)); |
| 3364 __ Branch(&receiver_ok, ne, scratch, Operand(zero_reg)); | 3395 __ Branch(&receiver_ok, ne, scratch, Operand(zero_reg)); |
| 3365 | 3396 |
| 3366 // Normal function. Replace undefined or null with global receiver. | 3397 // Normal function. Replace undefined or null with global receiver. |
| 3367 __ LoadRoot(scratch, Heap::kNullValueRootIndex); | 3398 __ LoadRoot(scratch, Heap::kNullValueRootIndex); |
| 3368 __ Branch(&global_object, eq, receiver, Operand(scratch)); | 3399 __ Branch(&global_object, eq, receiver, Operand(scratch)); |
| 3369 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | 3400 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); |
| 3370 __ Branch(&global_object, eq, receiver, Operand(scratch)); | 3401 __ Branch(&global_object, eq, receiver, Operand(scratch)); |
| 3371 | 3402 |
| 3372 // Deoptimize if the receiver is not a JS object. | 3403 // Deoptimize if the receiver is not a JS object. |
| 3373 __ And(scratch, receiver, Operand(kSmiTagMask)); | 3404 __ SmiTst(receiver, scratch); |
| 3374 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); | 3405 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); |
| 3375 | 3406 |
| 3376 __ GetObjectType(receiver, scratch, scratch); | 3407 __ GetObjectType(receiver, scratch, scratch); |
| 3377 DeoptimizeIf(lt, instr->environment(), | 3408 DeoptimizeIf(lt, instr->environment(), |
| 3378 scratch, Operand(FIRST_SPEC_OBJECT_TYPE)); | 3409 scratch, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 3379 __ Branch(&receiver_ok); | 3410 __ Branch(&receiver_ok); |
| 3380 | 3411 |
| 3381 __ bind(&global_object); | 3412 __ bind(&global_object); |
| 3382 __ lw(receiver, GlobalObjectOperand()); | 3413 __ lw(receiver, GlobalObjectOperand()); |
| 3383 __ lw(receiver, | 3414 __ lw(receiver, |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3835 MathPowStub stub(MathPowStub::INTEGER); | 3866 MathPowStub stub(MathPowStub::INTEGER); |
| 3836 __ CallStub(&stub); | 3867 __ CallStub(&stub); |
| 3837 } else { | 3868 } else { |
| 3838 ASSERT(exponent_type.IsDouble()); | 3869 ASSERT(exponent_type.IsDouble()); |
| 3839 MathPowStub stub(MathPowStub::DOUBLE); | 3870 MathPowStub stub(MathPowStub::DOUBLE); |
| 3840 __ CallStub(&stub); | 3871 __ CallStub(&stub); |
| 3841 } | 3872 } |
| 3842 } | 3873 } |
| 3843 | 3874 |
| 3844 | 3875 |
| 3845 void LCodeGen::DoRandom(LRandom* instr) { | |
| 3846 // Assert that the register size is indeed the size of each seed. | |
| 3847 static const int kSeedSize = sizeof(uint32_t); | |
| 3848 STATIC_ASSERT(kPointerSize == kSeedSize); | |
| 3849 | |
| 3850 // Load native context. | |
| 3851 Register global_object = ToRegister(instr->global_object()); | |
| 3852 Register native_context = global_object; | |
| 3853 __ lw(native_context, FieldMemOperand( | |
| 3854 global_object, GlobalObject::kNativeContextOffset)); | |
| 3855 | |
| 3856 // Load state (FixedArray of the native context's random seeds). | |
| 3857 static const int kRandomSeedOffset = | |
| 3858 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize; | |
| 3859 Register state = native_context; | |
| 3860 __ lw(state, FieldMemOperand(native_context, kRandomSeedOffset)); | |
| 3861 | |
| 3862 // Load state[0]. | |
| 3863 Register state0 = ToRegister(instr->scratch()); | |
| 3864 __ lw(state0, FieldMemOperand(state, ByteArray::kHeaderSize)); | |
| 3865 // Load state[1]. | |
| 3866 Register state1 = ToRegister(instr->scratch2()); | |
| 3867 __ lw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize)); | |
| 3868 | |
| 3869 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16) | |
| 3870 Register scratch3 = ToRegister(instr->scratch3()); | |
| 3871 Register scratch4 = scratch0(); | |
| 3872 __ And(scratch3, state0, Operand(0xFFFF)); | |
| 3873 __ li(scratch4, Operand(18273)); | |
| 3874 __ Mul(scratch3, scratch3, scratch4); | |
| 3875 __ srl(state0, state0, 16); | |
| 3876 __ Addu(state0, scratch3, state0); | |
| 3877 // Save state[0]. | |
| 3878 __ sw(state0, FieldMemOperand(state, ByteArray::kHeaderSize)); | |
| 3879 | |
| 3880 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16) | |
| 3881 __ And(scratch3, state1, Operand(0xFFFF)); | |
| 3882 __ li(scratch4, Operand(36969)); | |
| 3883 __ Mul(scratch3, scratch3, scratch4); | |
| 3884 __ srl(state1, state1, 16), | |
| 3885 __ Addu(state1, scratch3, state1); | |
| 3886 // Save state[1]. | |
| 3887 __ sw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize)); | |
| 3888 | |
| 3889 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF) | |
| 3890 Register random = scratch4; | |
| 3891 __ And(random, state1, Operand(0x3FFFF)); | |
| 3892 __ sll(state0, state0, 14); | |
| 3893 __ Addu(random, random, state0); | |
| 3894 | |
| 3895 // 0x41300000 is the top half of 1.0 x 2^20 as a double. | |
| 3896 __ li(scratch3, Operand(0x41300000)); | |
| 3897 // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU. | |
| 3898 DoubleRegister result = ToDoubleRegister(instr->result()); | |
| 3899 __ Move(result, random, scratch3); | |
| 3900 // Move 0x4130000000000000 to FPU. | |
| 3901 DoubleRegister scratch5 = double_scratch0(); | |
| 3902 __ Move(scratch5, zero_reg, scratch3); | |
| 3903 __ sub_d(result, result, scratch5); | |
| 3904 } | |
| 3905 | |
| 3906 | |
| 3907 void LCodeGen::DoMathExp(LMathExp* instr) { | 3876 void LCodeGen::DoMathExp(LMathExp* instr) { |
| 3908 DoubleRegister input = ToDoubleRegister(instr->value()); | 3877 DoubleRegister input = ToDoubleRegister(instr->value()); |
| 3909 DoubleRegister result = ToDoubleRegister(instr->result()); | 3878 DoubleRegister result = ToDoubleRegister(instr->result()); |
| 3910 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); | 3879 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); |
| 3911 DoubleRegister double_scratch2 = double_scratch0(); | 3880 DoubleRegister double_scratch2 = double_scratch0(); |
| 3912 Register temp1 = ToRegister(instr->temp1()); | 3881 Register temp1 = ToRegister(instr->temp1()); |
| 3913 Register temp2 = ToRegister(instr->temp2()); | 3882 Register temp2 = ToRegister(instr->temp2()); |
| 3914 | 3883 |
| 3915 MathExpGenerator::EmitMathExp( | 3884 MathExpGenerator::EmitMathExp( |
| 3916 masm(), input, result, double_scratch1, double_scratch2, | 3885 masm(), input, result, double_scratch1, double_scratch2, |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4008 } | 3977 } |
| 4009 | 3978 |
| 4010 | 3979 |
| 4011 void LCodeGen::DoCallFunction(LCallFunction* instr) { | 3980 void LCodeGen::DoCallFunction(LCallFunction* instr) { |
| 4012 ASSERT(ToRegister(instr->context()).is(cp)); | 3981 ASSERT(ToRegister(instr->context()).is(cp)); |
| 4013 ASSERT(ToRegister(instr->function()).is(a1)); | 3982 ASSERT(ToRegister(instr->function()).is(a1)); |
| 4014 ASSERT(ToRegister(instr->result()).is(v0)); | 3983 ASSERT(ToRegister(instr->result()).is(v0)); |
| 4015 | 3984 |
| 4016 int arity = instr->arity(); | 3985 int arity = instr->arity(); |
| 4017 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); | 3986 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); |
| 4018 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 3987 if (instr->hydrogen()->IsTailCall()) { |
| 3988 if (NeedsEagerFrame()) __ mov(sp, fp); |
| 3989 __ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET); |
| 3990 } else { |
| 3991 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 3992 } |
| 4019 } | 3993 } |
| 4020 | 3994 |
| 4021 | 3995 |
| 4022 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 3996 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
| 4023 ASSERT(ToRegister(instr->context()).is(cp)); | 3997 ASSERT(ToRegister(instr->context()).is(cp)); |
| 4024 ASSERT(ToRegister(instr->result()).is(v0)); | 3998 ASSERT(ToRegister(instr->result()).is(v0)); |
| 4025 | 3999 |
| 4026 int arity = instr->arity(); | 4000 int arity = instr->arity(); |
| 4027 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; | 4001 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; |
| 4028 Handle<Code> ic = | 4002 Handle<Code> ic = |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4136 MemOperand operand = MemOperand(object, offset); | 4110 MemOperand operand = MemOperand(object, offset); |
| 4137 __ Store(value, operand, representation); | 4111 __ Store(value, operand, representation); |
| 4138 return; | 4112 return; |
| 4139 } | 4113 } |
| 4140 | 4114 |
| 4141 Handle<Map> transition = instr->transition(); | 4115 Handle<Map> transition = instr->transition(); |
| 4142 | 4116 |
| 4143 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { | 4117 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { |
| 4144 Register value = ToRegister(instr->value()); | 4118 Register value = ToRegister(instr->value()); |
| 4145 if (!instr->hydrogen()->value()->type().IsHeapObject()) { | 4119 if (!instr->hydrogen()->value()->type().IsHeapObject()) { |
| 4146 __ And(scratch, value, Operand(kSmiTagMask)); | 4120 __ SmiTst(value, scratch); |
| 4147 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); | 4121 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); |
| 4148 } | 4122 } |
| 4149 } else if (FLAG_track_double_fields && representation.IsDouble()) { | 4123 } else if (FLAG_track_double_fields && representation.IsDouble()) { |
| 4150 ASSERT(transition.is_null()); | 4124 ASSERT(transition.is_null()); |
| 4151 ASSERT(access.IsInobject()); | 4125 ASSERT(access.IsInobject()); |
| 4152 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); | 4126 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 4153 DoubleRegister value = ToDoubleRegister(instr->value()); | 4127 DoubleRegister value = ToDoubleRegister(instr->value()); |
| 4154 __ sdc1(value, FieldMemOperand(object, offset)); | 4128 __ sdc1(value, FieldMemOperand(object, offset)); |
| 4155 return; | 4129 return; |
| 4156 } | 4130 } |
| (...skipping 974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5131 __ bind(&done); | 5105 __ bind(&done); |
| 5132 } | 5106 } |
| 5133 } | 5107 } |
| 5134 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1); | 5108 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1); |
| 5135 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg)); | 5109 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg)); |
| 5136 } | 5110 } |
| 5137 | 5111 |
| 5138 | 5112 |
| 5139 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 5113 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 5140 LOperand* input = instr->value(); | 5114 LOperand* input = instr->value(); |
| 5141 __ And(at, ToRegister(input), Operand(kSmiTagMask)); | 5115 __ SmiTst(ToRegister(input), at); |
| 5142 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); | 5116 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); |
| 5143 } | 5117 } |
| 5144 | 5118 |
| 5145 | 5119 |
| 5146 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 5120 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 5147 if (!instr->hydrogen()->value()->IsHeapObject()) { | 5121 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 5148 LOperand* input = instr->value(); | 5122 LOperand* input = instr->value(); |
| 5149 __ And(at, ToRegister(input), Operand(kSmiTagMask)); | 5123 __ SmiTst(ToRegister(input), at); |
| 5150 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); | 5124 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); |
| 5151 } | 5125 } |
| 5152 } | 5126 } |
| 5153 | 5127 |
| 5154 | 5128 |
| 5155 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 5129 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 5156 Register input = ToRegister(instr->value()); | 5130 Register input = ToRegister(instr->value()); |
| 5157 Register scratch = scratch0(); | 5131 Register scratch = scratch0(); |
| 5158 | 5132 |
| 5159 __ GetObjectType(input, scratch, scratch); | 5133 __ GetObjectType(input, scratch, scratch); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5212 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { | 5186 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { |
| 5213 { | 5187 { |
| 5214 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); | 5188 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
| 5215 __ push(object); | 5189 __ push(object); |
| 5216 __ mov(cp, zero_reg); | 5190 __ mov(cp, zero_reg); |
| 5217 __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance); | 5191 __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance); |
| 5218 RecordSafepointWithRegisters( | 5192 RecordSafepointWithRegisters( |
| 5219 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); | 5193 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); |
| 5220 __ StoreToSafepointRegisterSlot(v0, scratch0()); | 5194 __ StoreToSafepointRegisterSlot(v0, scratch0()); |
| 5221 } | 5195 } |
| 5222 __ And(at, scratch0(), Operand(kSmiTagMask)); | 5196 __ SmiTst(scratch0(), at); |
| 5223 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); | 5197 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); |
| 5224 } | 5198 } |
| 5225 | 5199 |
| 5226 | 5200 |
| 5227 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { | 5201 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { |
| 5228 class DeferredCheckMaps V8_FINAL : public LDeferredCode { | 5202 class DeferredCheckMaps V8_FINAL : public LDeferredCode { |
| 5229 public: | 5203 public: |
| 5230 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) | 5204 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) |
| 5231 : LDeferredCode(codegen), instr_(instr), object_(object) { | 5205 : LDeferredCode(codegen), instr_(instr), object_(object) { |
| 5232 SetExit(check_maps()); | 5206 SetExit(check_maps()); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5404 if (instr->size()->IsRegister()) { | 5378 if (instr->size()->IsRegister()) { |
| 5405 Register size = ToRegister(instr->size()); | 5379 Register size = ToRegister(instr->size()); |
| 5406 ASSERT(!size.is(result)); | 5380 ASSERT(!size.is(result)); |
| 5407 __ SmiTag(size); | 5381 __ SmiTag(size); |
| 5408 __ push(size); | 5382 __ push(size); |
| 5409 } else { | 5383 } else { |
| 5410 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); | 5384 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); |
| 5411 __ Push(Smi::FromInt(size)); | 5385 __ Push(Smi::FromInt(size)); |
| 5412 } | 5386 } |
| 5413 | 5387 |
| 5388 int flags = AllocateDoubleAlignFlag::encode( |
| 5389 instr->hydrogen()->MustAllocateDoubleAligned()); |
| 5414 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) { | 5390 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) { |
| 5415 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation()); | 5391 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation()); |
| 5416 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); | 5392 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); |
| 5417 CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr, | 5393 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE); |
| 5418 instr->context()); | |
| 5419 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) { | 5394 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) { |
| 5420 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); | 5395 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); |
| 5421 CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr, | 5396 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE); |
| 5422 instr->context()); | |
| 5423 } else { | 5397 } else { |
| 5424 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr, | 5398 flags = AllocateTargetSpace::update(flags, NEW_SPACE); |
| 5425 instr->context()); | |
| 5426 } | 5399 } |
| 5400 __ Push(Smi::FromInt(flags)); |
| 5401 |
| 5402 CallRuntimeFromDeferred( |
| 5403 Runtime::kAllocateInTargetSpace, 2, instr, instr->context()); |
| 5427 __ StoreToSafepointRegisterSlot(v0, result); | 5404 __ StoreToSafepointRegisterSlot(v0, result); |
| 5428 } | 5405 } |
| 5429 | 5406 |
| 5430 | 5407 |
| 5431 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { | 5408 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { |
| 5432 ASSERT(ToRegister(instr->value()).is(a0)); | 5409 ASSERT(ToRegister(instr->value()).is(a0)); |
| 5433 ASSERT(ToRegister(instr->result()).is(v0)); | 5410 ASSERT(ToRegister(instr->result()).is(v0)); |
| 5434 __ push(a0); | 5411 __ push(a0); |
| 5435 CallRuntime(Runtime::kToFastProperties, 1, instr); | 5412 CallRuntime(Runtime::kToFastProperties, 1, instr); |
| 5436 } | 5413 } |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5890 __ Subu(scratch, result, scratch); | 5867 __ Subu(scratch, result, scratch); |
| 5891 __ lw(result, FieldMemOperand(scratch, | 5868 __ lw(result, FieldMemOperand(scratch, |
| 5892 FixedArray::kHeaderSize - kPointerSize)); | 5869 FixedArray::kHeaderSize - kPointerSize)); |
| 5893 __ bind(&done); | 5870 __ bind(&done); |
| 5894 } | 5871 } |
| 5895 | 5872 |
| 5896 | 5873 |
| 5897 #undef __ | 5874 #undef __ |
| 5898 | 5875 |
| 5899 } } // namespace v8::internal | 5876 } } // namespace v8::internal |
| OLD | NEW |