| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 | 96 |
| 97 | 97 |
| 98 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, | 98 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode, |
| 99 Condition cond) { | 99 Condition cond) { |
| 100 ASSERT(RelocInfo::IsCodeTarget(rmode)); | 100 ASSERT(RelocInfo::IsCodeTarget(rmode)); |
| 101 // 'code' is always generated ARM code, never THUMB code | 101 // 'code' is always generated ARM code, never THUMB code |
| 102 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond); | 102 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond); |
| 103 } | 103 } |
| 104 | 104 |
| 105 | 105 |
| 106 int MacroAssembler::CallSize(Register target, Condition cond) { |
| 107 #if USE_BLX |
| 108 return kInstrSize; |
| 109 #else |
| 110 return 2 * kInstrSize; |
| 111 #endif |
| 112 } |
| 113 |
| 114 |
| 106 void MacroAssembler::Call(Register target, Condition cond) { | 115 void MacroAssembler::Call(Register target, Condition cond) { |
| 116 // Block constant pool for the call instruction sequence. |
| 117 BlockConstPoolScope block_const_pool(this); |
| 118 #ifdef DEBUG |
| 119 int pre_position = pc_offset(); |
| 120 #endif |
| 121 |
| 107 #if USE_BLX | 122 #if USE_BLX |
| 108 blx(target, cond); | 123 blx(target, cond); |
| 109 #else | 124 #else |
| 110 // set lr for return at current pc + 8 | 125 // set lr for return at current pc + 8 |
| 111 mov(lr, Operand(pc), LeaveCC, cond); | 126 mov(lr, Operand(pc), LeaveCC, cond); |
| 112 mov(pc, Operand(target), LeaveCC, cond); | 127 mov(pc, Operand(target), LeaveCC, cond); |
| 113 #endif | 128 #endif |
| 129 |
| 130 #ifdef DEBUG |
| 131 int post_position = pc_offset(); |
| 132 CHECK_EQ(pre_position + CallSize(target, cond), post_position); |
| 133 #endif |
| 114 } | 134 } |
| 115 | 135 |
| 116 | 136 |
| 117 void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode, | 137 int MacroAssembler::CallSize( |
| 118 Condition cond) { | 138 intptr_t target, RelocInfo::Mode rmode, Condition cond) { |
| 139 int size = 2 * kInstrSize; |
| 140 Instr mov_instr = cond | MOV | LeaveCC; |
| 141 if (!Operand(target, rmode).is_single_instruction(mov_instr)) { |
| 142 size += kInstrSize; |
| 143 } |
| 144 return size; |
| 145 } |
| 146 |
| 147 |
| 148 void MacroAssembler::Call( |
| 149 intptr_t target, RelocInfo::Mode rmode, Condition cond) { |
| 150 // Block constant pool for the call instruction sequence. |
| 151 BlockConstPoolScope block_const_pool(this); |
| 152 #ifdef DEBUG |
| 153 int pre_position = pc_offset(); |
| 154 #endif |
| 155 |
| 119 #if USE_BLX | 156 #if USE_BLX |
| 120 // On ARMv5 and after the recommended call sequence is: | 157 // On ARMv5 and after the recommended call sequence is: |
| 121 // ldr ip, [pc, #...] | 158 // ldr ip, [pc, #...] |
| 122 // blx ip | 159 // blx ip |
| 123 | 160 |
| 124 // The two instructions (ldr and blx) could be separated by a constant | 161 // Statement positions are expected to be recorded when the target |
| 125 // pool and the code would still work. The issue comes from the | 162 // address is loaded. The mov method will automatically record |
| 126 // patching code which expect the ldr to be just above the blx. | 163 // positions when pc is the target, since this is not the case here |
| 127 { BlockConstPoolScope block_const_pool(this); | 164 // we have to do it explicitly. |
| 128 // Statement positions are expected to be recorded when the target | 165 positions_recorder()->WriteRecordedPositions(); |
| 129 // address is loaded. The mov method will automatically record | |
| 130 // positions when pc is the target, since this is not the case here | |
| 131 // we have to do it explicitly. | |
| 132 positions_recorder()->WriteRecordedPositions(); | |
| 133 | 166 |
| 134 mov(ip, Operand(target, rmode), LeaveCC, cond); | 167 mov(ip, Operand(target, rmode), LeaveCC, cond); |
| 135 blx(ip, cond); | 168 blx(ip, cond); |
| 136 } | |
| 137 | 169 |
| 138 ASSERT(kCallTargetAddressOffset == 2 * kInstrSize); | 170 ASSERT(kCallTargetAddressOffset == 2 * kInstrSize); |
| 139 #else | 171 #else |
| 140 // Set lr for return at current pc + 8. | 172 // Set lr for return at current pc + 8. |
| 141 mov(lr, Operand(pc), LeaveCC, cond); | 173 mov(lr, Operand(pc), LeaveCC, cond); |
| 142 // Emit a ldr<cond> pc, [pc + offset of target in constant pool]. | 174 // Emit a ldr<cond> pc, [pc + offset of target in constant pool]. |
| 143 mov(pc, Operand(target, rmode), LeaveCC, cond); | 175 mov(pc, Operand(target, rmode), LeaveCC, cond); |
| 176 ASSERT(kCallTargetAddressOffset == kInstrSize); |
| 177 #endif |
| 144 | 178 |
| 145 ASSERT(kCallTargetAddressOffset == kInstrSize); | 179 #ifdef DEBUG |
| 180 int post_position = pc_offset(); |
| 181 CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position); |
| 146 #endif | 182 #endif |
| 147 } | 183 } |
| 148 | 184 |
| 149 | 185 |
| 150 void MacroAssembler::Call(byte* target, RelocInfo::Mode rmode, | 186 int MacroAssembler::CallSize( |
| 151 Condition cond) { | 187 byte* target, RelocInfo::Mode rmode, Condition cond) { |
| 152 ASSERT(!RelocInfo::IsCodeTarget(rmode)); | 188 return CallSize(reinterpret_cast<intptr_t>(target), rmode); |
| 153 Call(reinterpret_cast<intptr_t>(target), rmode, cond); | |
| 154 } | 189 } |
| 155 | 190 |
| 156 | 191 |
| 157 void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode, | 192 void MacroAssembler::Call( |
| 158 Condition cond) { | 193 byte* target, RelocInfo::Mode rmode, Condition cond) { |
| 194 #ifdef DEBUG |
| 195 int pre_position = pc_offset(); |
| 196 #endif |
| 197 |
| 198 ASSERT(!RelocInfo::IsCodeTarget(rmode)); |
| 199 Call(reinterpret_cast<intptr_t>(target), rmode, cond); |
| 200 |
| 201 #ifdef DEBUG |
| 202 int post_position = pc_offset(); |
| 203 CHECK_EQ(pre_position + CallSize(target, rmode, cond), post_position); |
| 204 #endif |
| 205 } |
| 206 |
| 207 |
| 208 int MacroAssembler::CallSize( |
| 209 Handle<Code> code, RelocInfo::Mode rmode, Condition cond) { |
| 210 return CallSize(reinterpret_cast<intptr_t>(code.location()), rmode, cond); |
| 211 } |
| 212 |
| 213 |
| 214 void MacroAssembler::Call( |
| 215 Handle<Code> code, RelocInfo::Mode rmode, Condition cond) { |
| 216 #ifdef DEBUG |
| 217 int pre_position = pc_offset(); |
| 218 #endif |
| 219 |
| 159 ASSERT(RelocInfo::IsCodeTarget(rmode)); | 220 ASSERT(RelocInfo::IsCodeTarget(rmode)); |
| 160 // 'code' is always generated ARM code, never THUMB code | 221 // 'code' is always generated ARM code, never THUMB code |
| 161 Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond); | 222 Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond); |
| 223 |
| 224 #ifdef DEBUG |
| 225 int post_position = pc_offset(); |
| 226 CHECK_EQ(pre_position + CallSize(code, rmode, cond), post_position); |
| 227 #endif |
| 162 } | 228 } |
| 163 | 229 |
| 164 | 230 |
| 165 void MacroAssembler::Ret(Condition cond) { | 231 void MacroAssembler::Ret(Condition cond) { |
| 166 #if USE_BX | 232 #if USE_BX |
| 167 bx(lr, cond); | 233 bx(lr, cond); |
| 168 #else | 234 #else |
| 169 mov(pc, Operand(lr), LeaveCC, cond); | 235 mov(pc, Operand(lr), LeaveCC, cond); |
| 170 #endif | 236 #endif |
| 171 } | 237 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 } | 330 } |
| 265 if (shift_down != 0) { | 331 if (shift_down != 0) { |
| 266 mov(dst, Operand(dst, ASR, shift_down), LeaveCC, cond); | 332 mov(dst, Operand(dst, ASR, shift_down), LeaveCC, cond); |
| 267 } | 333 } |
| 268 } else { | 334 } else { |
| 269 sbfx(dst, src1, lsb, width, cond); | 335 sbfx(dst, src1, lsb, width, cond); |
| 270 } | 336 } |
| 271 } | 337 } |
| 272 | 338 |
| 273 | 339 |
| 340 void MacroAssembler::Bfi(Register dst, |
| 341 Register src, |
| 342 Register scratch, |
| 343 int lsb, |
| 344 int width, |
| 345 Condition cond) { |
| 346 ASSERT(0 <= lsb && lsb < 32); |
| 347 ASSERT(0 <= width && width < 32); |
| 348 ASSERT(lsb + width < 32); |
| 349 ASSERT(!scratch.is(dst)); |
| 350 if (width == 0) return; |
| 351 if (!CpuFeatures::IsSupported(ARMv7)) { |
| 352 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); |
| 353 bic(dst, dst, Operand(mask)); |
| 354 and_(scratch, src, Operand((1 << width) - 1)); |
| 355 mov(scratch, Operand(scratch, LSL, lsb)); |
| 356 orr(dst, dst, scratch); |
| 357 } else { |
| 358 bfi(dst, src, lsb, width, cond); |
| 359 } |
| 360 } |
| 361 |
| 362 |
| 274 void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) { | 363 void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) { |
| 275 ASSERT(lsb < 32); | 364 ASSERT(lsb < 32); |
| 276 if (!CpuFeatures::IsSupported(ARMv7)) { | 365 if (!CpuFeatures::IsSupported(ARMv7)) { |
| 277 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); | 366 int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1); |
| 278 bic(dst, dst, Operand(mask)); | 367 bic(dst, dst, Operand(mask)); |
| 279 } else { | 368 } else { |
| 280 bfc(dst, lsb, width, cond); | 369 bfc(dst, lsb, width, cond); |
| 281 } | 370 } |
| 282 } | 371 } |
| 283 | 372 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 Heap::RootListIndex index, | 427 Heap::RootListIndex index, |
| 339 Condition cond) { | 428 Condition cond) { |
| 340 str(source, MemOperand(roots, index << kPointerSizeLog2), cond); | 429 str(source, MemOperand(roots, index << kPointerSizeLog2), cond); |
| 341 } | 430 } |
| 342 | 431 |
| 343 | 432 |
| 344 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER | 433 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER |
| 345 void MacroAssembler::RecordWriteHelper(Register object, | 434 void MacroAssembler::RecordWriteHelper(Register object, |
| 346 Register address, | 435 Register address, |
| 347 Register scratch) { | 436 Register scratch) { |
| 348 if (FLAG_debug_code) { | 437 if (emit_debug_code()) { |
| 349 // Check that the object is not in new space. | 438 // Check that the object is not in new space. |
| 350 Label not_in_new_space; | 439 Label not_in_new_space; |
| 351 InNewSpace(object, scratch, ne, ¬_in_new_space); | 440 InNewSpace(object, scratch, ne, ¬_in_new_space); |
| 352 Abort("new-space object passed to RecordWriteHelper"); | 441 Abort("new-space object passed to RecordWriteHelper"); |
| 353 bind(¬_in_new_space); | 442 bind(¬_in_new_space); |
| 354 } | 443 } |
| 355 | 444 |
| 356 // Calculate page address. | 445 // Calculate page address. |
| 357 Bfc(object, 0, kPageSizeBits); | 446 Bfc(object, 0, kPageSizeBits); |
| 358 | 447 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 // Add offset into the object. | 489 // Add offset into the object. |
| 401 add(scratch0, object, offset); | 490 add(scratch0, object, offset); |
| 402 | 491 |
| 403 // Record the actual write. | 492 // Record the actual write. |
| 404 RecordWriteHelper(object, scratch0, scratch1); | 493 RecordWriteHelper(object, scratch0, scratch1); |
| 405 | 494 |
| 406 bind(&done); | 495 bind(&done); |
| 407 | 496 |
| 408 // Clobber all input registers when running with the debug-code flag | 497 // Clobber all input registers when running with the debug-code flag |
| 409 // turned on to provoke errors. | 498 // turned on to provoke errors. |
| 410 if (FLAG_debug_code) { | 499 if (emit_debug_code()) { |
| 411 mov(object, Operand(BitCast<int32_t>(kZapValue))); | 500 mov(object, Operand(BitCast<int32_t>(kZapValue))); |
| 412 mov(scratch0, Operand(BitCast<int32_t>(kZapValue))); | 501 mov(scratch0, Operand(BitCast<int32_t>(kZapValue))); |
| 413 mov(scratch1, Operand(BitCast<int32_t>(kZapValue))); | 502 mov(scratch1, Operand(BitCast<int32_t>(kZapValue))); |
| 414 } | 503 } |
| 415 } | 504 } |
| 416 | 505 |
| 417 | 506 |
| 418 // Will clobber 4 registers: object, address, scratch, ip. The | 507 // Will clobber 4 registers: object, address, scratch, ip. The |
| 419 // register 'object' contains a heap object pointer. The heap object | 508 // register 'object' contains a heap object pointer. The heap object |
| 420 // tag is shifted away. | 509 // tag is shifted away. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 432 // region marks for new space pages. | 521 // region marks for new space pages. |
| 433 InNewSpace(object, scratch, eq, &done); | 522 InNewSpace(object, scratch, eq, &done); |
| 434 | 523 |
| 435 // Record the actual write. | 524 // Record the actual write. |
| 436 RecordWriteHelper(object, address, scratch); | 525 RecordWriteHelper(object, address, scratch); |
| 437 | 526 |
| 438 bind(&done); | 527 bind(&done); |
| 439 | 528 |
| 440 // Clobber all input registers when running with the debug-code flag | 529 // Clobber all input registers when running with the debug-code flag |
| 441 // turned on to provoke errors. | 530 // turned on to provoke errors. |
| 442 if (FLAG_debug_code) { | 531 if (emit_debug_code()) { |
| 443 mov(object, Operand(BitCast<int32_t>(kZapValue))); | 532 mov(object, Operand(BitCast<int32_t>(kZapValue))); |
| 444 mov(address, Operand(BitCast<int32_t>(kZapValue))); | 533 mov(address, Operand(BitCast<int32_t>(kZapValue))); |
| 445 mov(scratch, Operand(BitCast<int32_t>(kZapValue))); | 534 mov(scratch, Operand(BitCast<int32_t>(kZapValue))); |
| 446 } | 535 } |
| 447 } | 536 } |
| 448 #endif | 537 #endif |
| 449 | 538 |
| 450 // Push and pop all registers that can hold pointers. | 539 // Push and pop all registers that can hold pointers. |
| 451 void MacroAssembler::PushSafepointRegisters() { | 540 void MacroAssembler::PushSafepointRegisters() { |
| 452 // Safepoints expect a block of contiguous register values starting with r0: | 541 // Safepoints expect a block of contiguous register values starting with r0: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 479 | 568 |
| 480 void MacroAssembler::PopSafepointRegistersAndDoubles() { | 569 void MacroAssembler::PopSafepointRegistersAndDoubles() { |
| 481 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) { | 570 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) { |
| 482 vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize); | 571 vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize); |
| 483 } | 572 } |
| 484 add(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters * | 573 add(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters * |
| 485 kDoubleSize)); | 574 kDoubleSize)); |
| 486 PopSafepointRegisters(); | 575 PopSafepointRegisters(); |
| 487 } | 576 } |
| 488 | 577 |
| 489 void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register reg) { | 578 void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register src, |
| 490 str(reg, SafepointRegistersAndDoublesSlot(reg)); | 579 Register dst) { |
| 580 str(src, SafepointRegistersAndDoublesSlot(dst)); |
| 491 } | 581 } |
| 492 | 582 |
| 493 | 583 |
| 494 void MacroAssembler::StoreToSafepointRegisterSlot(Register reg) { | 584 void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { |
| 495 str(reg, SafepointRegisterSlot(reg)); | 585 str(src, SafepointRegisterSlot(dst)); |
| 496 } | 586 } |
| 497 | 587 |
| 498 | 588 |
| 499 void MacroAssembler::LoadFromSafepointRegisterSlot(Register reg) { | 589 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { |
| 500 ldr(reg, SafepointRegisterSlot(reg)); | 590 ldr(dst, SafepointRegisterSlot(src)); |
| 501 } | 591 } |
| 502 | 592 |
| 503 | 593 |
| 504 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { | 594 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { |
| 505 // The registers are pushed starting with the highest encoding, | 595 // The registers are pushed starting with the highest encoding, |
| 506 // which means that lowest encodings are closest to the stack pointer. | 596 // which means that lowest encodings are closest to the stack pointer. |
| 507 ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters); | 597 ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters); |
| 508 return reg_code; | 598 return reg_code; |
| 509 } | 599 } |
| 510 | 600 |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 | 725 |
| 636 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { | 726 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { |
| 637 // Setup the frame structure on the stack. | 727 // Setup the frame structure on the stack. |
| 638 ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); | 728 ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); |
| 639 ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); | 729 ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); |
| 640 ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); | 730 ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); |
| 641 Push(lr, fp); | 731 Push(lr, fp); |
| 642 mov(fp, Operand(sp)); // Setup new frame pointer. | 732 mov(fp, Operand(sp)); // Setup new frame pointer. |
| 643 // Reserve room for saved entry sp and code object. | 733 // Reserve room for saved entry sp and code object. |
| 644 sub(sp, sp, Operand(2 * kPointerSize)); | 734 sub(sp, sp, Operand(2 * kPointerSize)); |
| 645 if (FLAG_debug_code) { | 735 if (emit_debug_code()) { |
| 646 mov(ip, Operand(0)); | 736 mov(ip, Operand(0)); |
| 647 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 737 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 648 } | 738 } |
| 649 mov(ip, Operand(CodeObject())); | 739 mov(ip, Operand(CodeObject())); |
| 650 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); | 740 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); |
| 651 | 741 |
| 652 // Save the frame pointer and the context in top. | 742 // Save the frame pointer and the context in top. |
| 653 mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); | 743 mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
| 654 str(fp, MemOperand(ip)); | 744 str(fp, MemOperand(ip)); |
| 655 mov(ip, Operand(ExternalReference(Top::k_context_address))); | 745 mov(ip, Operand(ExternalReference(Top::k_context_address))); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 #endif | 829 #endif |
| 740 | 830 |
| 741 // Tear down the exit frame, pop the arguments, and return. | 831 // Tear down the exit frame, pop the arguments, and return. |
| 742 mov(sp, Operand(fp)); | 832 mov(sp, Operand(fp)); |
| 743 ldm(ia_w, sp, fp.bit() | lr.bit()); | 833 ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 744 if (argument_count.is_valid()) { | 834 if (argument_count.is_valid()) { |
| 745 add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2)); | 835 add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2)); |
| 746 } | 836 } |
| 747 } | 837 } |
| 748 | 838 |
| 839 void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) { |
| 840 #if !defined(USE_ARM_EABI) |
| 841 UNREACHABLE(); |
| 842 #else |
| 843 vmov(dst, r0, r1); |
| 844 #endif |
| 845 } |
| 846 |
| 749 | 847 |
| 750 void MacroAssembler::InvokePrologue(const ParameterCount& expected, | 848 void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
| 751 const ParameterCount& actual, | 849 const ParameterCount& actual, |
| 752 Handle<Code> code_constant, | 850 Handle<Code> code_constant, |
| 753 Register code_reg, | 851 Register code_reg, |
| 754 Label* done, | 852 Label* done, |
| 755 InvokeFlag flag, | 853 InvokeFlag flag, |
| 756 PostCallGenerator* post_call_generator) { | 854 CallWrapper* call_wrapper) { |
| 757 bool definitely_matches = false; | 855 bool definitely_matches = false; |
| 758 Label regular_invoke; | 856 Label regular_invoke; |
| 759 | 857 |
| 760 // Check whether the expected and actual arguments count match. If not, | 858 // Check whether the expected and actual arguments count match. If not, |
| 761 // setup registers according to contract with ArgumentsAdaptorTrampoline: | 859 // setup registers according to contract with ArgumentsAdaptorTrampoline: |
| 762 // r0: actual arguments count | 860 // r0: actual arguments count |
| 763 // r1: function (passed through to callee) | 861 // r1: function (passed through to callee) |
| 764 // r2: expected arguments count | 862 // r2: expected arguments count |
| 765 // r3: callee code entry | 863 // r3: callee code entry |
| 766 | 864 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 801 | 899 |
| 802 if (!definitely_matches) { | 900 if (!definitely_matches) { |
| 803 if (!code_constant.is_null()) { | 901 if (!code_constant.is_null()) { |
| 804 mov(r3, Operand(code_constant)); | 902 mov(r3, Operand(code_constant)); |
| 805 add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); | 903 add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 806 } | 904 } |
| 807 | 905 |
| 808 Handle<Code> adaptor = | 906 Handle<Code> adaptor = |
| 809 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | 907 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
| 810 if (flag == CALL_FUNCTION) { | 908 if (flag == CALL_FUNCTION) { |
| 909 if (call_wrapper != NULL) { |
| 910 call_wrapper->BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET)); |
| 911 } |
| 811 Call(adaptor, RelocInfo::CODE_TARGET); | 912 Call(adaptor, RelocInfo::CODE_TARGET); |
| 812 if (post_call_generator != NULL) post_call_generator->Generate(); | 913 if (call_wrapper != NULL) call_wrapper->AfterCall(); |
| 813 b(done); | 914 b(done); |
| 814 } else { | 915 } else { |
| 815 Jump(adaptor, RelocInfo::CODE_TARGET); | 916 Jump(adaptor, RelocInfo::CODE_TARGET); |
| 816 } | 917 } |
| 817 bind(®ular_invoke); | 918 bind(®ular_invoke); |
| 818 } | 919 } |
| 819 } | 920 } |
| 820 | 921 |
| 821 | 922 |
| 822 void MacroAssembler::InvokeCode(Register code, | 923 void MacroAssembler::InvokeCode(Register code, |
| 823 const ParameterCount& expected, | 924 const ParameterCount& expected, |
| 824 const ParameterCount& actual, | 925 const ParameterCount& actual, |
| 825 InvokeFlag flag, | 926 InvokeFlag flag, |
| 826 PostCallGenerator* post_call_generator) { | 927 CallWrapper* call_wrapper) { |
| 827 Label done; | 928 Label done; |
| 828 | 929 |
| 829 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, | 930 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, |
| 830 post_call_generator); | 931 call_wrapper); |
| 831 if (flag == CALL_FUNCTION) { | 932 if (flag == CALL_FUNCTION) { |
| 933 if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code)); |
| 832 Call(code); | 934 Call(code); |
| 833 if (post_call_generator != NULL) post_call_generator->Generate(); | 935 if (call_wrapper != NULL) call_wrapper->AfterCall(); |
| 834 } else { | 936 } else { |
| 835 ASSERT(flag == JUMP_FUNCTION); | 937 ASSERT(flag == JUMP_FUNCTION); |
| 836 Jump(code); | 938 Jump(code); |
| 837 } | 939 } |
| 838 | 940 |
| 839 // Continue here if InvokePrologue does handle the invocation due to | 941 // Continue here if InvokePrologue does handle the invocation due to |
| 840 // mismatched parameter counts. | 942 // mismatched parameter counts. |
| 841 bind(&done); | 943 bind(&done); |
| 842 } | 944 } |
| 843 | 945 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 858 | 960 |
| 859 // Continue here if InvokePrologue does handle the invocation due to | 961 // Continue here if InvokePrologue does handle the invocation due to |
| 860 // mismatched parameter counts. | 962 // mismatched parameter counts. |
| 861 bind(&done); | 963 bind(&done); |
| 862 } | 964 } |
| 863 | 965 |
| 864 | 966 |
| 865 void MacroAssembler::InvokeFunction(Register fun, | 967 void MacroAssembler::InvokeFunction(Register fun, |
| 866 const ParameterCount& actual, | 968 const ParameterCount& actual, |
| 867 InvokeFlag flag, | 969 InvokeFlag flag, |
| 868 PostCallGenerator* post_call_generator) { | 970 CallWrapper* call_wrapper) { |
| 869 // Contract with called JS functions requires that function is passed in r1. | 971 // Contract with called JS functions requires that function is passed in r1. |
| 870 ASSERT(fun.is(r1)); | 972 ASSERT(fun.is(r1)); |
| 871 | 973 |
| 872 Register expected_reg = r2; | 974 Register expected_reg = r2; |
| 873 Register code_reg = r3; | 975 Register code_reg = r3; |
| 874 | 976 |
| 875 ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | 977 ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 876 ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 978 ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
| 877 ldr(expected_reg, | 979 ldr(expected_reg, |
| 878 FieldMemOperand(code_reg, | 980 FieldMemOperand(code_reg, |
| 879 SharedFunctionInfo::kFormalParameterCountOffset)); | 981 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 880 mov(expected_reg, Operand(expected_reg, ASR, kSmiTagSize)); | 982 mov(expected_reg, Operand(expected_reg, ASR, kSmiTagSize)); |
| 881 ldr(code_reg, | 983 ldr(code_reg, |
| 882 FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); | 984 FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); |
| 883 | 985 |
| 884 ParameterCount expected(expected_reg); | 986 ParameterCount expected(expected_reg); |
| 885 InvokeCode(code_reg, expected, actual, flag, post_call_generator); | 987 InvokeCode(code_reg, expected, actual, flag, call_wrapper); |
| 886 } | 988 } |
| 887 | 989 |
| 888 | 990 |
| 889 void MacroAssembler::InvokeFunction(JSFunction* function, | 991 void MacroAssembler::InvokeFunction(JSFunction* function, |
| 890 const ParameterCount& actual, | 992 const ParameterCount& actual, |
| 891 InvokeFlag flag) { | 993 InvokeFlag flag) { |
| 892 ASSERT(function->is_compiled()); | 994 ASSERT(function->is_compiled()); |
| 893 | 995 |
| 894 // Get the function and setup the context. | 996 // Get the function and setup the context. |
| 895 mov(r1, Operand(Handle<JSFunction>(function))); | 997 mov(r1, Operand(Handle<JSFunction>(function))); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 | 1131 |
| 1030 // Before returning we restore the context from the frame pointer if | 1132 // Before returning we restore the context from the frame pointer if |
| 1031 // not NULL. The frame pointer is NULL in the exception handler of a | 1133 // not NULL. The frame pointer is NULL in the exception handler of a |
| 1032 // JS entry frame. | 1134 // JS entry frame. |
| 1033 cmp(fp, Operand(0, RelocInfo::NONE)); | 1135 cmp(fp, Operand(0, RelocInfo::NONE)); |
| 1034 // Set cp to NULL if fp is NULL. | 1136 // Set cp to NULL if fp is NULL. |
| 1035 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); | 1137 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
| 1036 // Restore cp otherwise. | 1138 // Restore cp otherwise. |
| 1037 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 1139 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
| 1038 #ifdef DEBUG | 1140 #ifdef DEBUG |
| 1039 if (FLAG_debug_code) { | 1141 if (emit_debug_code()) { |
| 1040 mov(lr, Operand(pc)); | 1142 mov(lr, Operand(pc)); |
| 1041 } | 1143 } |
| 1042 #endif | 1144 #endif |
| 1043 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 1145 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
| 1044 pop(pc); | 1146 pop(pc); |
| 1045 } | 1147 } |
| 1046 | 1148 |
| 1047 | 1149 |
| 1048 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 1150 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
| 1049 Register value) { | 1151 Register value) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1102 ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. | 1204 ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. |
| 1103 // Before returning we restore the context from the frame pointer if | 1205 // Before returning we restore the context from the frame pointer if |
| 1104 // not NULL. The frame pointer is NULL in the exception handler of a | 1206 // not NULL. The frame pointer is NULL in the exception handler of a |
| 1105 // JS entry frame. | 1207 // JS entry frame. |
| 1106 cmp(fp, Operand(0, RelocInfo::NONE)); | 1208 cmp(fp, Operand(0, RelocInfo::NONE)); |
| 1107 // Set cp to NULL if fp is NULL. | 1209 // Set cp to NULL if fp is NULL. |
| 1108 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); | 1210 mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
| 1109 // Restore cp otherwise. | 1211 // Restore cp otherwise. |
| 1110 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 1212 ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
| 1111 #ifdef DEBUG | 1213 #ifdef DEBUG |
| 1112 if (FLAG_debug_code) { | 1214 if (emit_debug_code()) { |
| 1113 mov(lr, Operand(pc)); | 1215 mov(lr, Operand(pc)); |
| 1114 } | 1216 } |
| 1115 #endif | 1217 #endif |
| 1116 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 1218 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
| 1117 pop(pc); | 1219 pop(pc); |
| 1118 } | 1220 } |
| 1119 | 1221 |
| 1120 | 1222 |
| 1121 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, | 1223 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
| 1122 Register scratch, | 1224 Register scratch, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1134 cmp(scratch, Operand(0, RelocInfo::NONE)); | 1236 cmp(scratch, Operand(0, RelocInfo::NONE)); |
| 1135 Check(ne, "we should not have an empty lexical context"); | 1237 Check(ne, "we should not have an empty lexical context"); |
| 1136 #endif | 1238 #endif |
| 1137 | 1239 |
| 1138 // Load the global context of the current context. | 1240 // Load the global context of the current context. |
| 1139 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 1241 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
| 1140 ldr(scratch, FieldMemOperand(scratch, offset)); | 1242 ldr(scratch, FieldMemOperand(scratch, offset)); |
| 1141 ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); | 1243 ldr(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); |
| 1142 | 1244 |
| 1143 // Check the context is a global context. | 1245 // Check the context is a global context. |
| 1144 if (FLAG_debug_code) { | 1246 if (emit_debug_code()) { |
| 1145 // TODO(119): avoid push(holder_reg)/pop(holder_reg) | 1247 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
| 1146 // Cannot use ip as a temporary in this verification code. Due to the fact | 1248 // Cannot use ip as a temporary in this verification code. Due to the fact |
| 1147 // that ip is clobbered as part of cmp with an object Operand. | 1249 // that ip is clobbered as part of cmp with an object Operand. |
| 1148 push(holder_reg); // Temporarily save holder on the stack. | 1250 push(holder_reg); // Temporarily save holder on the stack. |
| 1149 // Read the first word and compare to the global_context_map. | 1251 // Read the first word and compare to the global_context_map. |
| 1150 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); | 1252 ldr(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); |
| 1151 LoadRoot(ip, Heap::kGlobalContextMapRootIndex); | 1253 LoadRoot(ip, Heap::kGlobalContextMapRootIndex); |
| 1152 cmp(holder_reg, ip); | 1254 cmp(holder_reg, ip); |
| 1153 Check(eq, "JSGlobalObject::global_context should be a global context."); | 1255 Check(eq, "JSGlobalObject::global_context should be a global context."); |
| 1154 pop(holder_reg); // Restore holder. | 1256 pop(holder_reg); // Restore holder. |
| 1155 } | 1257 } |
| 1156 | 1258 |
| 1157 // Check if both contexts are the same. | 1259 // Check if both contexts are the same. |
| 1158 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); | 1260 ldr(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
| 1159 cmp(scratch, Operand(ip)); | 1261 cmp(scratch, Operand(ip)); |
| 1160 b(eq, &same_contexts); | 1262 b(eq, &same_contexts); |
| 1161 | 1263 |
| 1162 // Check the context is a global context. | 1264 // Check the context is a global context. |
| 1163 if (FLAG_debug_code) { | 1265 if (emit_debug_code()) { |
| 1164 // TODO(119): avoid push(holder_reg)/pop(holder_reg) | 1266 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
| 1165 // Cannot use ip as a temporary in this verification code. Due to the fact | 1267 // Cannot use ip as a temporary in this verification code. Due to the fact |
| 1166 // that ip is clobbered as part of cmp with an object Operand. | 1268 // that ip is clobbered as part of cmp with an object Operand. |
| 1167 push(holder_reg); // Temporarily save holder on the stack. | 1269 push(holder_reg); // Temporarily save holder on the stack. |
| 1168 mov(holder_reg, ip); // Move ip to its holding place. | 1270 mov(holder_reg, ip); // Move ip to its holding place. |
| 1169 LoadRoot(ip, Heap::kNullValueRootIndex); | 1271 LoadRoot(ip, Heap::kNullValueRootIndex); |
| 1170 cmp(holder_reg, ip); | 1272 cmp(holder_reg, ip); |
| 1171 Check(ne, "JSGlobalProxy::context() should not be null."); | 1273 Check(ne, "JSGlobalProxy::context() should not be null."); |
| 1172 | 1274 |
| 1173 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); | 1275 ldr(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1195 } | 1297 } |
| 1196 | 1298 |
| 1197 | 1299 |
| 1198 void MacroAssembler::AllocateInNewSpace(int object_size, | 1300 void MacroAssembler::AllocateInNewSpace(int object_size, |
| 1199 Register result, | 1301 Register result, |
| 1200 Register scratch1, | 1302 Register scratch1, |
| 1201 Register scratch2, | 1303 Register scratch2, |
| 1202 Label* gc_required, | 1304 Label* gc_required, |
| 1203 AllocationFlags flags) { | 1305 AllocationFlags flags) { |
| 1204 if (!FLAG_inline_new) { | 1306 if (!FLAG_inline_new) { |
| 1205 if (FLAG_debug_code) { | 1307 if (emit_debug_code()) { |
| 1206 // Trash the registers to simulate an allocation failure. | 1308 // Trash the registers to simulate an allocation failure. |
| 1207 mov(result, Operand(0x7091)); | 1309 mov(result, Operand(0x7091)); |
| 1208 mov(scratch1, Operand(0x7191)); | 1310 mov(scratch1, Operand(0x7191)); |
| 1209 mov(scratch2, Operand(0x7291)); | 1311 mov(scratch2, Operand(0x7291)); |
| 1210 } | 1312 } |
| 1211 jmp(gc_required); | 1313 jmp(gc_required); |
| 1212 return; | 1314 return; |
| 1213 } | 1315 } |
| 1214 | 1316 |
| 1215 ASSERT(!result.is(scratch1)); | 1317 ASSERT(!result.is(scratch1)); |
| 1216 ASSERT(!result.is(scratch2)); | 1318 ASSERT(!result.is(scratch2)); |
| 1217 ASSERT(!scratch1.is(scratch2)); | 1319 ASSERT(!scratch1.is(scratch2)); |
| 1320 ASSERT(!scratch1.is(ip)); |
| 1321 ASSERT(!scratch2.is(ip)); |
| 1218 | 1322 |
| 1219 // Make object size into bytes. | 1323 // Make object size into bytes. |
| 1220 if ((flags & SIZE_IN_WORDS) != 0) { | 1324 if ((flags & SIZE_IN_WORDS) != 0) { |
| 1221 object_size *= kPointerSize; | 1325 object_size *= kPointerSize; |
| 1222 } | 1326 } |
| 1223 ASSERT_EQ(0, object_size & kObjectAlignmentMask); | 1327 ASSERT_EQ(0, object_size & kObjectAlignmentMask); |
| 1224 | 1328 |
| 1225 // Check relative positions of allocation top and limit addresses. | 1329 // Check relative positions of allocation top and limit addresses. |
| 1226 // The values must be adjacent in memory to allow the use of LDM. | 1330 // The values must be adjacent in memory to allow the use of LDM. |
| 1227 // Also, assert that the registers are numbered such that the values | 1331 // Also, assert that the registers are numbered such that the values |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1242 Register obj_size_reg = scratch2; | 1346 Register obj_size_reg = scratch2; |
| 1243 mov(topaddr, Operand(new_space_allocation_top)); | 1347 mov(topaddr, Operand(new_space_allocation_top)); |
| 1244 mov(obj_size_reg, Operand(object_size)); | 1348 mov(obj_size_reg, Operand(object_size)); |
| 1245 | 1349 |
| 1246 // This code stores a temporary value in ip. This is OK, as the code below | 1350 // This code stores a temporary value in ip. This is OK, as the code below |
| 1247 // does not need ip for implicit literal generation. | 1351 // does not need ip for implicit literal generation. |
| 1248 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1352 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1249 // Load allocation top into result and allocation limit into ip. | 1353 // Load allocation top into result and allocation limit into ip. |
| 1250 ldm(ia, topaddr, result.bit() | ip.bit()); | 1354 ldm(ia, topaddr, result.bit() | ip.bit()); |
| 1251 } else { | 1355 } else { |
| 1252 if (FLAG_debug_code) { | 1356 if (emit_debug_code()) { |
| 1253 // Assert that result actually contains top on entry. ip is used | 1357 // Assert that result actually contains top on entry. ip is used |
| 1254 // immediately below so this use of ip does not cause difference with | 1358 // immediately below so this use of ip does not cause difference with |
| 1255 // respect to register content between debug and release mode. | 1359 // respect to register content between debug and release mode. |
| 1256 ldr(ip, MemOperand(topaddr)); | 1360 ldr(ip, MemOperand(topaddr)); |
| 1257 cmp(result, ip); | 1361 cmp(result, ip); |
| 1258 Check(eq, "Unexpected allocation top"); | 1362 Check(eq, "Unexpected allocation top"); |
| 1259 } | 1363 } |
| 1260 // Load allocation limit into ip. Result already contains allocation top. | 1364 // Load allocation limit into ip. Result already contains allocation top. |
| 1261 ldr(ip, MemOperand(topaddr, limit - top)); | 1365 ldr(ip, MemOperand(topaddr, limit - top)); |
| 1262 } | 1366 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1276 } | 1380 } |
| 1277 | 1381 |
| 1278 | 1382 |
| 1279 void MacroAssembler::AllocateInNewSpace(Register object_size, | 1383 void MacroAssembler::AllocateInNewSpace(Register object_size, |
| 1280 Register result, | 1384 Register result, |
| 1281 Register scratch1, | 1385 Register scratch1, |
| 1282 Register scratch2, | 1386 Register scratch2, |
| 1283 Label* gc_required, | 1387 Label* gc_required, |
| 1284 AllocationFlags flags) { | 1388 AllocationFlags flags) { |
| 1285 if (!FLAG_inline_new) { | 1389 if (!FLAG_inline_new) { |
| 1286 if (FLAG_debug_code) { | 1390 if (emit_debug_code()) { |
| 1287 // Trash the registers to simulate an allocation failure. | 1391 // Trash the registers to simulate an allocation failure. |
| 1288 mov(result, Operand(0x7091)); | 1392 mov(result, Operand(0x7091)); |
| 1289 mov(scratch1, Operand(0x7191)); | 1393 mov(scratch1, Operand(0x7191)); |
| 1290 mov(scratch2, Operand(0x7291)); | 1394 mov(scratch2, Operand(0x7291)); |
| 1291 } | 1395 } |
| 1292 jmp(gc_required); | 1396 jmp(gc_required); |
| 1293 return; | 1397 return; |
| 1294 } | 1398 } |
| 1295 | 1399 |
| 1296 // Assert that the register arguments are different and that none of | 1400 // Assert that the register arguments are different and that none of |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1320 // Set up allocation top address. | 1424 // Set up allocation top address. |
| 1321 Register topaddr = scratch1; | 1425 Register topaddr = scratch1; |
| 1322 mov(topaddr, Operand(new_space_allocation_top)); | 1426 mov(topaddr, Operand(new_space_allocation_top)); |
| 1323 | 1427 |
| 1324 // This code stores a temporary value in ip. This is OK, as the code below | 1428 // This code stores a temporary value in ip. This is OK, as the code below |
| 1325 // does not need ip for implicit literal generation. | 1429 // does not need ip for implicit literal generation. |
| 1326 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 1430 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1327 // Load allocation top into result and allocation limit into ip. | 1431 // Load allocation top into result and allocation limit into ip. |
| 1328 ldm(ia, topaddr, result.bit() | ip.bit()); | 1432 ldm(ia, topaddr, result.bit() | ip.bit()); |
| 1329 } else { | 1433 } else { |
| 1330 if (FLAG_debug_code) { | 1434 if (emit_debug_code()) { |
| 1331 // Assert that result actually contains top on entry. ip is used | 1435 // Assert that result actually contains top on entry. ip is used |
| 1332 // immediately below so this use of ip does not cause difference with | 1436 // immediately below so this use of ip does not cause difference with |
| 1333 // respect to register content between debug and release mode. | 1437 // respect to register content between debug and release mode. |
| 1334 ldr(ip, MemOperand(topaddr)); | 1438 ldr(ip, MemOperand(topaddr)); |
| 1335 cmp(result, ip); | 1439 cmp(result, ip); |
| 1336 Check(eq, "Unexpected allocation top"); | 1440 Check(eq, "Unexpected allocation top"); |
| 1337 } | 1441 } |
| 1338 // Load allocation limit into ip. Result already contains allocation top. | 1442 // Load allocation limit into ip. Result already contains allocation top. |
| 1339 ldr(ip, MemOperand(topaddr, limit - top)); | 1443 ldr(ip, MemOperand(topaddr, limit - top)); |
| 1340 } | 1444 } |
| 1341 | 1445 |
| 1342 // Calculate new top and bail out if new space is exhausted. Use result | 1446 // Calculate new top and bail out if new space is exhausted. Use result |
| 1343 // to calculate the new top. Object size may be in words so a shift is | 1447 // to calculate the new top. Object size may be in words so a shift is |
| 1344 // required to get the number of bytes. | 1448 // required to get the number of bytes. |
| 1345 if ((flags & SIZE_IN_WORDS) != 0) { | 1449 if ((flags & SIZE_IN_WORDS) != 0) { |
| 1346 add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC); | 1450 add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC); |
| 1347 } else { | 1451 } else { |
| 1348 add(scratch2, result, Operand(object_size), SetCC); | 1452 add(scratch2, result, Operand(object_size), SetCC); |
| 1349 } | 1453 } |
| 1350 b(cs, gc_required); | 1454 b(cs, gc_required); |
| 1351 cmp(scratch2, Operand(ip)); | 1455 cmp(scratch2, Operand(ip)); |
| 1352 b(hi, gc_required); | 1456 b(hi, gc_required); |
| 1353 | 1457 |
| 1354 // Update allocation top. result temporarily holds the new top. | 1458 // Update allocation top. result temporarily holds the new top. |
| 1355 if (FLAG_debug_code) { | 1459 if (emit_debug_code()) { |
| 1356 tst(scratch2, Operand(kObjectAlignmentMask)); | 1460 tst(scratch2, Operand(kObjectAlignmentMask)); |
| 1357 Check(eq, "Unaligned allocation in new space"); | 1461 Check(eq, "Unaligned allocation in new space"); |
| 1358 } | 1462 } |
| 1359 str(scratch2, MemOperand(topaddr)); | 1463 str(scratch2, MemOperand(topaddr)); |
| 1360 | 1464 |
| 1361 // Tag object if requested. | 1465 // Tag object if requested. |
| 1362 if ((flags & TAG_OBJECT) != 0) { | 1466 if ((flags & TAG_OBJECT) != 0) { |
| 1363 add(result, result, Operand(kHeapObjectTag)); | 1467 add(result, result, Operand(kHeapObjectTag)); |
| 1364 } | 1468 } |
| 1365 } | 1469 } |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1497 | 1601 |
| 1498 | 1602 |
| 1499 void MacroAssembler::CompareInstanceType(Register map, | 1603 void MacroAssembler::CompareInstanceType(Register map, |
| 1500 Register type_reg, | 1604 Register type_reg, |
| 1501 InstanceType type) { | 1605 InstanceType type) { |
| 1502 ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 1606 ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 1503 cmp(type_reg, Operand(type)); | 1607 cmp(type_reg, Operand(type)); |
| 1504 } | 1608 } |
| 1505 | 1609 |
| 1506 | 1610 |
| 1611 void MacroAssembler::CompareRoot(Register obj, |
| 1612 Heap::RootListIndex index) { |
| 1613 ASSERT(!obj.is(ip)); |
| 1614 LoadRoot(ip, index); |
| 1615 cmp(obj, ip); |
| 1616 } |
| 1617 |
| 1618 |
| 1507 void MacroAssembler::CheckMap(Register obj, | 1619 void MacroAssembler::CheckMap(Register obj, |
| 1508 Register scratch, | 1620 Register scratch, |
| 1509 Handle<Map> map, | 1621 Handle<Map> map, |
| 1510 Label* fail, | 1622 Label* fail, |
| 1511 bool is_heap_object) { | 1623 bool is_heap_object) { |
| 1512 if (!is_heap_object) { | 1624 if (!is_heap_object) { |
| 1513 JumpIfSmi(obj, fail); | 1625 JumpIfSmi(obj, fail); |
| 1514 } | 1626 } |
| 1515 ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); | 1627 ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); |
| 1516 mov(ip, Operand(map)); | 1628 mov(ip, Operand(map)); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1603 return result; | 1715 return result; |
| 1604 } | 1716 } |
| 1605 | 1717 |
| 1606 | 1718 |
| 1607 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { | 1719 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { |
| 1608 return ref0.address() - ref1.address(); | 1720 return ref0.address() - ref1.address(); |
| 1609 } | 1721 } |
| 1610 | 1722 |
| 1611 | 1723 |
| 1612 MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( | 1724 MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( |
| 1613 ApiFunction* function, int stack_space) { | 1725 ExternalReference function, int stack_space) { |
| 1614 ExternalReference next_address = | 1726 ExternalReference next_address = |
| 1615 ExternalReference::handle_scope_next_address(); | 1727 ExternalReference::handle_scope_next_address(); |
| 1616 const int kNextOffset = 0; | 1728 const int kNextOffset = 0; |
| 1617 const int kLimitOffset = AddressOffset( | 1729 const int kLimitOffset = AddressOffset( |
| 1618 ExternalReference::handle_scope_limit_address(), | 1730 ExternalReference::handle_scope_limit_address(), |
| 1619 next_address); | 1731 next_address); |
| 1620 const int kLevelOffset = AddressOffset( | 1732 const int kLevelOffset = AddressOffset( |
| 1621 ExternalReference::handle_scope_level_address(), | 1733 ExternalReference::handle_scope_level_address(), |
| 1622 next_address); | 1734 next_address); |
| 1623 | 1735 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1641 | 1753 |
| 1642 // If result is non-zero, dereference to get the result value | 1754 // If result is non-zero, dereference to get the result value |
| 1643 // otherwise set it to undefined. | 1755 // otherwise set it to undefined. |
| 1644 cmp(r0, Operand(0)); | 1756 cmp(r0, Operand(0)); |
| 1645 LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1757 LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
| 1646 ldr(r0, MemOperand(r0), ne); | 1758 ldr(r0, MemOperand(r0), ne); |
| 1647 | 1759 |
| 1648 // No more valid handles (the result handle was the last one). Restore | 1760 // No more valid handles (the result handle was the last one). Restore |
| 1649 // previous handle scope. | 1761 // previous handle scope. |
| 1650 str(r4, MemOperand(r7, kNextOffset)); | 1762 str(r4, MemOperand(r7, kNextOffset)); |
| 1651 if (FLAG_debug_code) { | 1763 if (emit_debug_code()) { |
| 1652 ldr(r1, MemOperand(r7, kLevelOffset)); | 1764 ldr(r1, MemOperand(r7, kLevelOffset)); |
| 1653 cmp(r1, r6); | 1765 cmp(r1, r6); |
| 1654 Check(eq, "Unexpected level after return from api call"); | 1766 Check(eq, "Unexpected level after return from api call"); |
| 1655 } | 1767 } |
| 1656 sub(r6, r6, Operand(1)); | 1768 sub(r6, r6, Operand(1)); |
| 1657 str(r6, MemOperand(r7, kLevelOffset)); | 1769 str(r6, MemOperand(r7, kLevelOffset)); |
| 1658 ldr(ip, MemOperand(r7, kLimitOffset)); | 1770 ldr(ip, MemOperand(r7, kLimitOffset)); |
| 1659 cmp(r5, ip); | 1771 cmp(r5, ip); |
| 1660 b(ne, &delete_allocated_handles); | 1772 b(ne, &delete_allocated_handles); |
| 1661 | 1773 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1803 // This code is faster for doubles that are in the ranges -0x7fffffff to | 1915 // This code is faster for doubles that are in the ranges -0x7fffffff to |
| 1804 // -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds almost to | 1916 // -0x40000000 or 0x40000000 to 0x7fffffff. This corresponds almost to |
| 1805 // the range of signed int32 values that are not Smis. Jumps to the label | 1917 // the range of signed int32 values that are not Smis. Jumps to the label |
| 1806 // 'not_int32' if the double isn't in the range -0x80000000.0 to | 1918 // 'not_int32' if the double isn't in the range -0x80000000.0 to |
| 1807 // 0x80000000.0 (excluding the endpoints). | 1919 // 0x80000000.0 (excluding the endpoints). |
| 1808 Label right_exponent, done; | 1920 Label right_exponent, done; |
| 1809 // Get exponent word. | 1921 // Get exponent word. |
| 1810 ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset)); | 1922 ldr(scratch, FieldMemOperand(source, HeapNumber::kExponentOffset)); |
| 1811 // Get exponent alone in scratch2. | 1923 // Get exponent alone in scratch2. |
| 1812 Ubfx(scratch2, | 1924 Ubfx(scratch2, |
| 1813 scratch, | 1925 scratch, |
| 1814 HeapNumber::kExponentShift, | 1926 HeapNumber::kExponentShift, |
| 1815 HeapNumber::kExponentBits); | 1927 HeapNumber::kExponentBits); |
| 1816 // Load dest with zero. We use this either for the final shift or | 1928 // Load dest with zero. We use this either for the final shift or |
| 1817 // for the answer. | 1929 // for the answer. |
| 1818 mov(dest, Operand(0, RelocInfo::NONE)); | 1930 mov(dest, Operand(0, RelocInfo::NONE)); |
| 1819 // Check whether the exponent matches a 32 bit signed int that is not a Smi. | 1931 // Check whether the exponent matches a 32 bit signed int that is not a Smi. |
| 1820 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is | 1932 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is |
| 1821 // the exponent that we are fastest at and also the highest exponent we can | 1933 // the exponent that we are fastest at and also the highest exponent we can |
| 1822 // handle here. | 1934 // handle here. |
| 1823 const uint32_t non_smi_exponent = HeapNumber::kExponentBias + 30; | 1935 const uint32_t non_smi_exponent = HeapNumber::kExponentBias + 30; |
| 1824 // The non_smi_exponent, 0x41d, is too big for ARM's immediate field so we | 1936 // The non_smi_exponent, 0x41d, is too big for ARM's immediate field so we |
| 1825 // split it up to avoid a constant pool entry. You can't do that in general | 1937 // split it up to avoid a constant pool entry. You can't do that in general |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1868 orr(scratch, scratch2, Operand(scratch, LSR, 32 - shift_distance)); | 1980 orr(scratch, scratch2, Operand(scratch, LSR, 32 - shift_distance)); |
| 1869 // Move down according to the exponent. | 1981 // Move down according to the exponent. |
| 1870 mov(dest, Operand(scratch, LSR, dest)); | 1982 mov(dest, Operand(scratch, LSR, dest)); |
| 1871 // Fix sign if sign bit was set. | 1983 // Fix sign if sign bit was set. |
| 1872 rsb(dest, dest, Operand(0, RelocInfo::NONE), LeaveCC, ne); | 1984 rsb(dest, dest, Operand(0, RelocInfo::NONE), LeaveCC, ne); |
| 1873 bind(&done); | 1985 bind(&done); |
| 1874 } | 1986 } |
| 1875 } | 1987 } |
| 1876 | 1988 |
| 1877 | 1989 |
| 1990 void MacroAssembler::EmitVFPTruncate(VFPRoundingMode rounding_mode, |
| 1991 SwVfpRegister result, |
| 1992 DwVfpRegister double_input, |
| 1993 Register scratch1, |
| 1994 Register scratch2, |
| 1995 CheckForInexactConversion check_inexact) { |
| 1996 ASSERT(CpuFeatures::IsSupported(VFP3)); |
| 1997 CpuFeatures::Scope scope(VFP3); |
| 1998 Register prev_fpscr = scratch1; |
| 1999 Register scratch = scratch2; |
| 2000 |
| 2001 int32_t check_inexact_conversion = |
| 2002 (check_inexact == kCheckForInexactConversion) ? kVFPInexactExceptionBit : 0; |
| 2003 |
| 2004 // Set custom FPCSR: |
| 2005 // - Set rounding mode. |
| 2006 // - Clear vfp cumulative exception flags. |
| 2007 // - Make sure Flush-to-zero mode control bit is unset. |
| 2008 vmrs(prev_fpscr); |
| 2009 bic(scratch, |
| 2010 prev_fpscr, |
| 2011 Operand(kVFPExceptionMask | |
| 2012 check_inexact_conversion | |
| 2013 kVFPRoundingModeMask | |
| 2014 kVFPFlushToZeroMask)); |
| 2015 // 'Round To Nearest' is encoded by 0b00 so no bits need to be set. |
| 2016 if (rounding_mode != kRoundToNearest) { |
| 2017 orr(scratch, scratch, Operand(rounding_mode)); |
| 2018 } |
| 2019 vmsr(scratch); |
| 2020 |
| 2021 // Convert the argument to an integer. |
| 2022 vcvt_s32_f64(result, |
| 2023 double_input, |
| 2024 (rounding_mode == kRoundToZero) ? kDefaultRoundToZero |
| 2025 : kFPSCRRounding); |
| 2026 |
| 2027 // Retrieve FPSCR. |
| 2028 vmrs(scratch); |
| 2029 // Restore FPSCR. |
| 2030 vmsr(prev_fpscr); |
| 2031 // Check for vfp exceptions. |
| 2032 tst(scratch, Operand(kVFPExceptionMask | check_inexact_conversion)); |
| 2033 } |
| 2034 |
| 2035 |
| 2036 void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, |
| 2037 Register input_high, |
| 2038 Register input_low, |
| 2039 Register scratch) { |
| 2040 Label done, normal_exponent, restore_sign; |
| 2041 |
| 2042 // Extract the biased exponent in result. |
| 2043 Ubfx(result, |
| 2044 input_high, |
| 2045 HeapNumber::kExponentShift, |
| 2046 HeapNumber::kExponentBits); |
| 2047 |
| 2048 // Check for Infinity and NaNs, which should return 0. |
| 2049 cmp(result, Operand(HeapNumber::kExponentMask)); |
| 2050 mov(result, Operand(0), LeaveCC, eq); |
| 2051 b(eq, &done); |
| 2052 |
| 2053 // Express exponent as delta to (number of mantissa bits + 31). |
| 2054 sub(result, |
| 2055 result, |
| 2056 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31), |
| 2057 SetCC); |
| 2058 |
| 2059 // If the delta is strictly positive, all bits would be shifted away, |
| 2060 // which means that we can return 0. |
| 2061 b(le, &normal_exponent); |
| 2062 mov(result, Operand(0)); |
| 2063 b(&done); |
| 2064 |
| 2065 bind(&normal_exponent); |
| 2066 const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1; |
| 2067 // Calculate shift. |
| 2068 add(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits), SetCC); |
| 2069 |
| 2070 // Save the sign. |
| 2071 Register sign = result; |
| 2072 result = no_reg; |
| 2073 and_(sign, input_high, Operand(HeapNumber::kSignMask)); |
| 2074 |
| 2075 // Set the implicit 1 before the mantissa part in input_high. |
| 2076 orr(input_high, |
| 2077 input_high, |
| 2078 Operand(1 << HeapNumber::kMantissaBitsInTopWord)); |
| 2079 // Shift the mantissa bits to the correct position. |
| 2080 // We don't need to clear non-mantissa bits as they will be shifted away. |
| 2081 // If they weren't, it would mean that the answer is in the 32bit range. |
| 2082 mov(input_high, Operand(input_high, LSL, scratch)); |
| 2083 |
| 2084 // Replace the shifted bits with bits from the lower mantissa word. |
| 2085 Label pos_shift, shift_done; |
| 2086 rsb(scratch, scratch, Operand(32), SetCC); |
| 2087 b(&pos_shift, ge); |
| 2088 |
| 2089 // Negate scratch. |
| 2090 rsb(scratch, scratch, Operand(0)); |
| 2091 mov(input_low, Operand(input_low, LSL, scratch)); |
| 2092 b(&shift_done); |
| 2093 |
| 2094 bind(&pos_shift); |
| 2095 mov(input_low, Operand(input_low, LSR, scratch)); |
| 2096 |
| 2097 bind(&shift_done); |
| 2098 orr(input_high, input_high, Operand(input_low)); |
| 2099 // Restore sign if necessary. |
| 2100 cmp(sign, Operand(0)); |
| 2101 result = sign; |
| 2102 sign = no_reg; |
| 2103 rsb(result, input_high, Operand(0), LeaveCC, ne); |
| 2104 mov(result, input_high, LeaveCC, eq); |
| 2105 bind(&done); |
| 2106 } |
| 2107 |
| 2108 |
| 2109 void MacroAssembler::EmitECMATruncate(Register result, |
| 2110 DwVfpRegister double_input, |
| 2111 SwVfpRegister single_scratch, |
| 2112 Register scratch, |
| 2113 Register input_high, |
| 2114 Register input_low) { |
| 2115 CpuFeatures::Scope scope(VFP3); |
| 2116 ASSERT(!input_high.is(result)); |
| 2117 ASSERT(!input_low.is(result)); |
| 2118 ASSERT(!input_low.is(input_high)); |
| 2119 ASSERT(!scratch.is(result) && |
| 2120 !scratch.is(input_high) && |
| 2121 !scratch.is(input_low)); |
| 2122 ASSERT(!single_scratch.is(double_input.low()) && |
| 2123 !single_scratch.is(double_input.high())); |
| 2124 |
| 2125 Label done; |
| 2126 |
| 2127 // Clear cumulative exception flags. |
| 2128 ClearFPSCRBits(kVFPExceptionMask, scratch); |
| 2129 // Try a conversion to a signed integer. |
| 2130 vcvt_s32_f64(single_scratch, double_input); |
| 2131 vmov(result, single_scratch); |
| 2132 // Retrieve he FPSCR. |
| 2133 vmrs(scratch); |
| 2134 // Check for overflow and NaNs. |
| 2135 tst(scratch, Operand(kVFPOverflowExceptionBit | |
| 2136 kVFPUnderflowExceptionBit | |
| 2137 kVFPInvalidOpExceptionBit)); |
| 2138 // If we had no exceptions we are done. |
| 2139 b(eq, &done); |
| 2140 |
| 2141 // Load the double value and perform a manual truncation. |
| 2142 vmov(input_low, input_high, double_input); |
| 2143 EmitOutOfInt32RangeTruncate(result, |
| 2144 input_high, |
| 2145 input_low, |
| 2146 scratch); |
| 2147 bind(&done); |
| 2148 } |
| 2149 |
| 2150 |
| 1878 void MacroAssembler::GetLeastBitsFromSmi(Register dst, | 2151 void MacroAssembler::GetLeastBitsFromSmi(Register dst, |
| 1879 Register src, | 2152 Register src, |
| 1880 int num_least_bits) { | 2153 int num_least_bits) { |
| 1881 if (CpuFeatures::IsSupported(ARMv7)) { | 2154 if (CpuFeatures::IsSupported(ARMv7)) { |
| 1882 ubfx(dst, src, kSmiTagSize, num_least_bits); | 2155 ubfx(dst, src, kSmiTagSize, num_least_bits); |
| 1883 } else { | 2156 } else { |
| 1884 mov(dst, Operand(src, ASR, kSmiTagSize)); | 2157 mov(dst, Operand(src, ASR, kSmiTagSize)); |
| 1885 and_(dst, dst, Operand((1 << num_least_bits) - 1)); | 2158 and_(dst, dst, Operand((1 << num_least_bits) - 1)); |
| 1886 } | 2159 } |
| 1887 } | 2160 } |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1989 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); | 2262 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); |
| 1990 #endif | 2263 #endif |
| 1991 mov(r1, Operand(builtin)); | 2264 mov(r1, Operand(builtin)); |
| 1992 CEntryStub stub(1); | 2265 CEntryStub stub(1); |
| 1993 return TryTailCallStub(&stub); | 2266 return TryTailCallStub(&stub); |
| 1994 } | 2267 } |
| 1995 | 2268 |
| 1996 | 2269 |
| 1997 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, | 2270 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
| 1998 InvokeJSFlags flags, | 2271 InvokeJSFlags flags, |
| 1999 PostCallGenerator* post_call_generator) { | 2272 CallWrapper* call_wrapper) { |
| 2000 GetBuiltinEntry(r2, id); | 2273 GetBuiltinEntry(r2, id); |
| 2001 if (flags == CALL_JS) { | 2274 if (flags == CALL_JS) { |
| 2275 if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(r2)); |
| 2002 Call(r2); | 2276 Call(r2); |
| 2003 if (post_call_generator != NULL) post_call_generator->Generate(); | 2277 if (call_wrapper != NULL) call_wrapper->AfterCall(); |
| 2004 } else { | 2278 } else { |
| 2005 ASSERT(flags == JUMP_JS); | 2279 ASSERT(flags == JUMP_JS); |
| 2006 Jump(r2); | 2280 Jump(r2); |
| 2007 } | 2281 } |
| 2008 } | 2282 } |
| 2009 | 2283 |
| 2010 | 2284 |
| 2011 void MacroAssembler::GetBuiltinFunction(Register target, | 2285 void MacroAssembler::GetBuiltinFunction(Register target, |
| 2012 Builtins::JavaScript id) { | 2286 Builtins::JavaScript id) { |
| 2013 // Load the builtins object into target register. | 2287 // Load the builtins object into target register. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2055 if (FLAG_native_code_counters && counter->Enabled()) { | 2329 if (FLAG_native_code_counters && counter->Enabled()) { |
| 2056 mov(scratch2, Operand(ExternalReference(counter))); | 2330 mov(scratch2, Operand(ExternalReference(counter))); |
| 2057 ldr(scratch1, MemOperand(scratch2)); | 2331 ldr(scratch1, MemOperand(scratch2)); |
| 2058 sub(scratch1, scratch1, Operand(value)); | 2332 sub(scratch1, scratch1, Operand(value)); |
| 2059 str(scratch1, MemOperand(scratch2)); | 2333 str(scratch1, MemOperand(scratch2)); |
| 2060 } | 2334 } |
| 2061 } | 2335 } |
| 2062 | 2336 |
| 2063 | 2337 |
| 2064 void MacroAssembler::Assert(Condition cond, const char* msg) { | 2338 void MacroAssembler::Assert(Condition cond, const char* msg) { |
| 2065 if (FLAG_debug_code) | 2339 if (emit_debug_code()) |
| 2066 Check(cond, msg); | 2340 Check(cond, msg); |
| 2067 } | 2341 } |
| 2068 | 2342 |
| 2069 | 2343 |
| 2070 void MacroAssembler::AssertRegisterIsRoot(Register reg, | 2344 void MacroAssembler::AssertRegisterIsRoot(Register reg, |
| 2071 Heap::RootListIndex index) { | 2345 Heap::RootListIndex index) { |
| 2072 if (FLAG_debug_code) { | 2346 if (emit_debug_code()) { |
| 2073 LoadRoot(ip, index); | 2347 LoadRoot(ip, index); |
| 2074 cmp(reg, ip); | 2348 cmp(reg, ip); |
| 2075 Check(eq, "Register did not match expected root"); | 2349 Check(eq, "Register did not match expected root"); |
| 2076 } | 2350 } |
| 2077 } | 2351 } |
| 2078 | 2352 |
| 2079 | 2353 |
| 2080 void MacroAssembler::AssertFastElements(Register elements) { | 2354 void MacroAssembler::AssertFastElements(Register elements) { |
| 2081 if (FLAG_debug_code) { | 2355 if (emit_debug_code()) { |
| 2082 ASSERT(!elements.is(ip)); | 2356 ASSERT(!elements.is(ip)); |
| 2083 Label ok; | 2357 Label ok; |
| 2084 push(elements); | 2358 push(elements); |
| 2085 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); | 2359 ldr(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 2086 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 2360 LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
| 2087 cmp(elements, ip); | 2361 cmp(elements, ip); |
| 2088 b(eq, &ok); | 2362 b(eq, &ok); |
| 2089 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); | 2363 LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); |
| 2090 cmp(elements, ip); | 2364 cmp(elements, ip); |
| 2091 b(eq, &ok); | 2365 b(eq, &ok); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2148 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 2422 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { |
| 2149 if (context_chain_length > 0) { | 2423 if (context_chain_length > 0) { |
| 2150 // Move up the chain of contexts to the context containing the slot. | 2424 // Move up the chain of contexts to the context containing the slot. |
| 2151 ldr(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX))); | 2425 ldr(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 2152 // Load the function context (which is the incoming, outer context). | 2426 // Load the function context (which is the incoming, outer context). |
| 2153 ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); | 2427 ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); |
| 2154 for (int i = 1; i < context_chain_length; i++) { | 2428 for (int i = 1; i < context_chain_length; i++) { |
| 2155 ldr(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); | 2429 ldr(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 2156 ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); | 2430 ldr(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); |
| 2157 } | 2431 } |
| 2158 // The context may be an intermediate context, not a function context. | 2432 } else { |
| 2159 ldr(dst, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 2433 // Slot is in the current function context. Move it into the |
| 2160 } else { // Slot is in the current function context. | 2434 // destination register in case we store into it (the write barrier |
| 2161 // The context may be an intermediate context, not a function context. | 2435 // cannot be allowed to destroy the context in esi). |
| 2162 ldr(dst, MemOperand(cp, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 2436 mov(dst, cp); |
| 2437 } |
| 2438 |
| 2439 // We should not have found a 'with' context by walking the context chain |
| 2440 // (i.e., the static scope chain and runtime context chain do not agree). |
| 2441 // A variable occurring in such a scope should have slot type LOOKUP and |
| 2442 // not CONTEXT. |
| 2443 if (emit_debug_code()) { |
| 2444 ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); |
| 2445 cmp(dst, ip); |
| 2446 Check(eq, "Yo dawg, I heard you liked function contexts " |
| 2447 "so I put function contexts in all your contexts"); |
| 2163 } | 2448 } |
| 2164 } | 2449 } |
| 2165 | 2450 |
| 2166 | 2451 |
| 2167 void MacroAssembler::LoadGlobalFunction(int index, Register function) { | 2452 void MacroAssembler::LoadGlobalFunction(int index, Register function) { |
| 2168 // Load the global or builtins object from the current context. | 2453 // Load the global or builtins object from the current context. |
| 2169 ldr(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 2454 ldr(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2170 // Load the global context from the global or builtins object. | 2455 // Load the global context from the global or builtins object. |
| 2171 ldr(function, FieldMemOperand(function, | 2456 ldr(function, FieldMemOperand(function, |
| 2172 GlobalObject::kGlobalContextOffset)); | 2457 GlobalObject::kGlobalContextOffset)); |
| 2173 // Load the function from the global context. | 2458 // Load the function from the global context. |
| 2174 ldr(function, MemOperand(function, Context::SlotOffset(index))); | 2459 ldr(function, MemOperand(function, Context::SlotOffset(index))); |
| 2175 } | 2460 } |
| 2176 | 2461 |
| 2177 | 2462 |
| 2178 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, | 2463 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, |
| 2179 Register map, | 2464 Register map, |
| 2180 Register scratch) { | 2465 Register scratch) { |
| 2181 // Load the initial map. The global functions all have initial maps. | 2466 // Load the initial map. The global functions all have initial maps. |
| 2182 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 2467 ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 2183 if (FLAG_debug_code) { | 2468 if (emit_debug_code()) { |
| 2184 Label ok, fail; | 2469 Label ok, fail; |
| 2185 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); | 2470 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); |
| 2186 b(&ok); | 2471 b(&ok); |
| 2187 bind(&fail); | 2472 bind(&fail); |
| 2188 Abort("Global functions must have initial map"); | 2473 Abort("Global functions must have initial map"); |
| 2189 bind(&ok); | 2474 bind(&ok); |
| 2190 } | 2475 } |
| 2191 } | 2476 } |
| 2192 | 2477 |
| 2193 | 2478 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2245 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); | 2530 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE); |
| 2246 pop(object); | 2531 pop(object); |
| 2247 Assert(lo, "Operand is not a string"); | 2532 Assert(lo, "Operand is not a string"); |
| 2248 } | 2533 } |
| 2249 | 2534 |
| 2250 | 2535 |
| 2251 | 2536 |
| 2252 void MacroAssembler::AbortIfNotRootValue(Register src, | 2537 void MacroAssembler::AbortIfNotRootValue(Register src, |
| 2253 Heap::RootListIndex root_value_index, | 2538 Heap::RootListIndex root_value_index, |
| 2254 const char* message) { | 2539 const char* message) { |
| 2255 ASSERT(!src.is(ip)); | 2540 CompareRoot(src, root_value_index); |
| 2256 LoadRoot(ip, root_value_index); | |
| 2257 cmp(src, ip); | |
| 2258 Assert(eq, message); | 2541 Assert(eq, message); |
| 2259 } | 2542 } |
| 2260 | 2543 |
| 2261 | 2544 |
| 2262 void MacroAssembler::JumpIfNotHeapNumber(Register object, | 2545 void MacroAssembler::JumpIfNotHeapNumber(Register object, |
| 2263 Register heap_number_map, | 2546 Register heap_number_map, |
| 2264 Register scratch, | 2547 Register scratch, |
| 2265 Label* on_not_heap_number) { | 2548 Label* on_not_heap_number) { |
| 2266 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 2549 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2267 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2550 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2363 } | 2646 } |
| 2364 ASSERT(!tmp.is(no_reg)); | 2647 ASSERT(!tmp.is(no_reg)); |
| 2365 | 2648 |
| 2366 for (int i = 0; i < field_count; i++) { | 2649 for (int i = 0; i < field_count; i++) { |
| 2367 ldr(tmp, FieldMemOperand(src, i * kPointerSize)); | 2650 ldr(tmp, FieldMemOperand(src, i * kPointerSize)); |
| 2368 str(tmp, FieldMemOperand(dst, i * kPointerSize)); | 2651 str(tmp, FieldMemOperand(dst, i * kPointerSize)); |
| 2369 } | 2652 } |
| 2370 } | 2653 } |
| 2371 | 2654 |
| 2372 | 2655 |
| 2656 void MacroAssembler::CopyBytes(Register src, |
| 2657 Register dst, |
| 2658 Register length, |
| 2659 Register scratch) { |
| 2660 Label align_loop, align_loop_1, word_loop, byte_loop, byte_loop_1, done; |
| 2661 |
| 2662 // Align src before copying in word size chunks. |
| 2663 bind(&align_loop); |
| 2664 cmp(length, Operand(0)); |
| 2665 b(eq, &done); |
| 2666 bind(&align_loop_1); |
| 2667 tst(src, Operand(kPointerSize - 1)); |
| 2668 b(eq, &word_loop); |
| 2669 ldrb(scratch, MemOperand(src, 1, PostIndex)); |
| 2670 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2671 sub(length, length, Operand(1), SetCC); |
| 2672 b(ne, &byte_loop_1); |
| 2673 |
| 2674 // Copy bytes in word size chunks. |
| 2675 bind(&word_loop); |
| 2676 if (emit_debug_code()) { |
| 2677 tst(src, Operand(kPointerSize - 1)); |
| 2678 Assert(eq, "Expecting alignment for CopyBytes"); |
| 2679 } |
| 2680 cmp(length, Operand(kPointerSize)); |
| 2681 b(lt, &byte_loop); |
| 2682 ldr(scratch, MemOperand(src, kPointerSize, PostIndex)); |
| 2683 #if CAN_USE_UNALIGNED_ACCESSES |
| 2684 str(scratch, MemOperand(dst, kPointerSize, PostIndex)); |
| 2685 #else |
| 2686 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2687 mov(scratch, Operand(scratch, LSR, 8)); |
| 2688 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2689 mov(scratch, Operand(scratch, LSR, 8)); |
| 2690 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2691 mov(scratch, Operand(scratch, LSR, 8)); |
| 2692 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2693 #endif |
| 2694 sub(length, length, Operand(kPointerSize)); |
| 2695 b(&word_loop); |
| 2696 |
| 2697 // Copy the last bytes if any left. |
| 2698 bind(&byte_loop); |
| 2699 cmp(length, Operand(0)); |
| 2700 b(eq, &done); |
| 2701 bind(&byte_loop_1); |
| 2702 ldrb(scratch, MemOperand(src, 1, PostIndex)); |
| 2703 strb(scratch, MemOperand(dst, 1, PostIndex)); |
| 2704 sub(length, length, Operand(1), SetCC); |
| 2705 b(ne, &byte_loop_1); |
| 2706 bind(&done); |
| 2707 } |
| 2708 |
| 2709 |
| 2373 void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. | 2710 void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. |
| 2374 Register source, // Input. | 2711 Register source, // Input. |
| 2375 Register scratch) { | 2712 Register scratch) { |
| 2376 ASSERT(!zeros.is(source) || !source.is(scratch)); | 2713 ASSERT(!zeros.is(source) || !source.is(scratch)); |
| 2377 ASSERT(!zeros.is(scratch)); | 2714 ASSERT(!zeros.is(scratch)); |
| 2378 ASSERT(!scratch.is(ip)); | 2715 ASSERT(!scratch.is(ip)); |
| 2379 ASSERT(!source.is(ip)); | 2716 ASSERT(!source.is(ip)); |
| 2380 ASSERT(!zeros.is(ip)); | 2717 ASSERT(!zeros.is(ip)); |
| 2381 #ifdef CAN_USE_ARMV5_INSTRUCTIONS | 2718 #ifdef CAN_USE_ARMV5_INSTRUCTIONS |
| 2382 clz(zeros, source); // This instruction is only supported after ARM5. | 2719 clz(zeros, source); // This instruction is only supported after ARM5. |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2459 mov(ip, Operand(function)); | 2796 mov(ip, Operand(function)); |
| 2460 CallCFunction(ip, num_arguments); | 2797 CallCFunction(ip, num_arguments); |
| 2461 } | 2798 } |
| 2462 | 2799 |
| 2463 | 2800 |
| 2464 void MacroAssembler::CallCFunction(Register function, int num_arguments) { | 2801 void MacroAssembler::CallCFunction(Register function, int num_arguments) { |
| 2465 // Make sure that the stack is aligned before calling a C function unless | 2802 // Make sure that the stack is aligned before calling a C function unless |
| 2466 // running in the simulator. The simulator has its own alignment check which | 2803 // running in the simulator. The simulator has its own alignment check which |
| 2467 // provides more information. | 2804 // provides more information. |
| 2468 #if defined(V8_HOST_ARCH_ARM) | 2805 #if defined(V8_HOST_ARCH_ARM) |
| 2469 if (FLAG_debug_code) { | 2806 if (emit_debug_code()) { |
| 2470 int frame_alignment = OS::ActivationFrameAlignment(); | 2807 int frame_alignment = OS::ActivationFrameAlignment(); |
| 2471 int frame_alignment_mask = frame_alignment - 1; | 2808 int frame_alignment_mask = frame_alignment - 1; |
| 2472 if (frame_alignment > kPointerSize) { | 2809 if (frame_alignment > kPointerSize) { |
| 2473 ASSERT(IsPowerOf2(frame_alignment)); | 2810 ASSERT(IsPowerOf2(frame_alignment)); |
| 2474 Label alignment_as_expected; | 2811 Label alignment_as_expected; |
| 2475 tst(sp, Operand(frame_alignment_mask)); | 2812 tst(sp, Operand(frame_alignment_mask)); |
| 2476 b(eq, &alignment_as_expected); | 2813 b(eq, &alignment_as_expected); |
| 2477 // Don't use Check here, as it will call Runtime_Abort possibly | 2814 // Don't use Check here, as it will call Runtime_Abort possibly |
| 2478 // re-entering here. | 2815 // re-entering here. |
| 2479 stop("Unexpected alignment"); | 2816 stop("Unexpected alignment"); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2493 add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); | 2830 add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); |
| 2494 } | 2831 } |
| 2495 } | 2832 } |
| 2496 | 2833 |
| 2497 | 2834 |
| 2498 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, | 2835 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, |
| 2499 Register result) { | 2836 Register result) { |
| 2500 const uint32_t kLdrOffsetMask = (1 << 12) - 1; | 2837 const uint32_t kLdrOffsetMask = (1 << 12) - 1; |
| 2501 const int32_t kPCRegOffset = 2 * kPointerSize; | 2838 const int32_t kPCRegOffset = 2 * kPointerSize; |
| 2502 ldr(result, MemOperand(ldr_location)); | 2839 ldr(result, MemOperand(ldr_location)); |
| 2503 if (FLAG_debug_code) { | 2840 if (emit_debug_code()) { |
| 2504 // Check that the instruction is a ldr reg, [pc + offset] . | 2841 // Check that the instruction is a ldr reg, [pc + offset] . |
| 2505 and_(result, result, Operand(kLdrPCPattern)); | 2842 and_(result, result, Operand(kLdrPCPattern)); |
| 2506 cmp(result, Operand(kLdrPCPattern)); | 2843 cmp(result, Operand(kLdrPCPattern)); |
| 2507 Check(eq, "The instruction to patch should be a load from pc."); | 2844 Check(eq, "The instruction to patch should be a load from pc."); |
| 2508 // Result was clobbered. Restore it. | 2845 // Result was clobbered. Restore it. |
| 2509 ldr(result, MemOperand(ldr_location)); | 2846 ldr(result, MemOperand(ldr_location)); |
| 2510 } | 2847 } |
| 2511 // Get the address of the constant. | 2848 // Get the address of the constant. |
| 2512 and_(result, result, Operand(kLdrOffsetMask)); | 2849 and_(result, result, Operand(kLdrOffsetMask)); |
| 2513 add(result, ldr_location, Operand(result)); | 2850 add(result, ldr_location, Operand(result)); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2550 void CodePatcher::EmitCondition(Condition cond) { | 2887 void CodePatcher::EmitCondition(Condition cond) { |
| 2551 Instr instr = Assembler::instr_at(masm_.pc_); | 2888 Instr instr = Assembler::instr_at(masm_.pc_); |
| 2552 instr = (instr & ~kCondMask) | cond; | 2889 instr = (instr & ~kCondMask) | cond; |
| 2553 masm_.emit(instr); | 2890 masm_.emit(instr); |
| 2554 } | 2891 } |
| 2555 | 2892 |
| 2556 | 2893 |
| 2557 } } // namespace v8::internal | 2894 } } // namespace v8::internal |
| 2558 | 2895 |
| 2559 #endif // V8_TARGET_ARCH_ARM | 2896 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |