| OLD | NEW |
| 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. | 1 // Copyright (c) 1994-2006 Sun Microsystems Inc. |
| 2 // All Rights Reserved. | 2 // All Rights Reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions | 5 // modification, are permitted provided that the following conditions |
| 6 // are met: | 6 // are met: |
| 7 // | 7 // |
| 8 // - Redistributions of source code must retain the above copyright notice, | 8 // - Redistributions of source code must retain the above copyright notice, |
| 9 // this list of conditions and the following disclaimer. | 9 // this list of conditions and the following disclaimer. |
| 10 // | 10 // |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 ASSERT(buffer_size > 0); | 314 ASSERT(buffer_size > 0); |
| 315 buffer_ = static_cast<byte*>(buffer); | 315 buffer_ = static_cast<byte*>(buffer); |
| 316 buffer_size_ = buffer_size; | 316 buffer_size_ = buffer_size; |
| 317 own_buffer_ = false; | 317 own_buffer_ = false; |
| 318 } | 318 } |
| 319 | 319 |
| 320 // Setup buffer pointers. | 320 // Setup buffer pointers. |
| 321 ASSERT(buffer_ != NULL); | 321 ASSERT(buffer_ != NULL); |
| 322 pc_ = buffer_; | 322 pc_ = buffer_; |
| 323 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); | 323 reloc_info_writer.Reposition(buffer_ + buffer_size, pc_); |
| 324 num_prinfo_ = 0; | 324 num_pending_reloc_info_ = 0; |
| 325 next_buffer_check_ = 0; | 325 next_buffer_check_ = 0; |
| 326 const_pool_blocked_nesting_ = 0; | 326 const_pool_blocked_nesting_ = 0; |
| 327 no_const_pool_before_ = 0; | 327 no_const_pool_before_ = 0; |
| 328 last_const_pool_end_ = 0; | 328 first_const_pool_use_ = -1; |
| 329 last_bound_pos_ = 0; | 329 last_bound_pos_ = 0; |
| 330 ast_id_for_reloc_info_ = kNoASTId; | 330 ast_id_for_reloc_info_ = kNoASTId; |
| 331 } | 331 } |
| 332 | 332 |
| 333 | 333 |
| 334 Assembler::~Assembler() { | 334 Assembler::~Assembler() { |
| 335 ASSERT(const_pool_blocked_nesting_ == 0); | 335 ASSERT(const_pool_blocked_nesting_ == 0); |
| 336 if (own_buffer_) { | 336 if (own_buffer_) { |
| 337 if (isolate()->assembler_spare_buffer() == NULL && | 337 if (isolate()->assembler_spare_buffer() == NULL && |
| 338 buffer_size_ == kMinimalBufferSize) { | 338 buffer_size_ == kMinimalBufferSize) { |
| 339 isolate()->set_assembler_spare_buffer(buffer_); | 339 isolate()->set_assembler_spare_buffer(buffer_); |
| 340 } else { | 340 } else { |
| 341 DeleteArray(buffer_); | 341 DeleteArray(buffer_); |
| 342 } | 342 } |
| 343 } | 343 } |
| 344 } | 344 } |
| 345 | 345 |
| 346 | 346 |
| 347 void Assembler::GetCode(CodeDesc* desc) { | 347 void Assembler::GetCode(CodeDesc* desc) { |
| 348 // Emit constant pool if necessary. | 348 // Emit constant pool if necessary. |
| 349 CheckConstPool(true, false); | 349 CheckConstPool(true, false); |
| 350 ASSERT(num_prinfo_ == 0); | 350 ASSERT(num_pending_reloc_info_ == 0); |
| 351 | 351 |
| 352 // Setup code descriptor. | 352 // Setup code descriptor. |
| 353 desc->buffer = buffer_; | 353 desc->buffer = buffer_; |
| 354 desc->buffer_size = buffer_size_; | 354 desc->buffer_size = buffer_size_; |
| 355 desc->instr_size = pc_offset(); | 355 desc->instr_size = pc_offset(); |
| 356 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); | 356 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); |
| 357 } | 357 } |
| 358 | 358 |
| 359 | 359 |
| 360 void Assembler::Align(int m) { | 360 void Assembler::Align(int m) { |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 // Immediate shift. | 867 // Immediate shift. |
| 868 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); | 868 instr |= x.shift_imm_*B7 | x.shift_op_ | x.rm_.code(); |
| 869 } else { | 869 } else { |
| 870 // Register shift. | 870 // Register shift. |
| 871 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc)); | 871 ASSERT(!rn.is(pc) && !rd.is(pc) && !x.rm_.is(pc) && !x.rs_.is(pc)); |
| 872 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code(); | 872 instr |= x.rs_.code()*B8 | x.shift_op_ | B4 | x.rm_.code(); |
| 873 } | 873 } |
| 874 emit(instr | rn.code()*B16 | rd.code()*B12); | 874 emit(instr | rn.code()*B16 | rd.code()*B12); |
| 875 if (rn.is(pc) || x.rm_.is(pc)) { | 875 if (rn.is(pc) || x.rm_.is(pc)) { |
| 876 // Block constant pool emission for one instruction after reading pc. | 876 // Block constant pool emission for one instruction after reading pc. |
| 877 BlockConstPoolBefore(pc_offset() + kInstrSize); | 877 BlockConstPoolFor(1); |
| 878 } | 878 } |
| 879 } | 879 } |
| 880 | 880 |
| 881 | 881 |
| 882 void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { | 882 void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) { |
| 883 ASSERT((instr & ~(kCondMask | B | L)) == B26); | 883 ASSERT((instr & ~(kCondMask | B | L)) == B26); |
| 884 int am = x.am_; | 884 int am = x.am_; |
| 885 if (!x.rm_.is_valid()) { | 885 if (!x.rm_.is_valid()) { |
| 886 // Immediate offset. | 886 // Immediate offset. |
| 887 int offset_12 = x.offset_; | 887 int offset_12 = x.offset_; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 991 if (L->is_linked()) { | 991 if (L->is_linked()) { |
| 992 target_pos = L->pos(); // L's link | 992 target_pos = L->pos(); // L's link |
| 993 } else { | 993 } else { |
| 994 target_pos = kEndOfChain; | 994 target_pos = kEndOfChain; |
| 995 } | 995 } |
| 996 L->link_to(pc_offset()); | 996 L->link_to(pc_offset()); |
| 997 } | 997 } |
| 998 | 998 |
| 999 // Block the emission of the constant pool, since the branch instruction must | 999 // Block the emission of the constant pool, since the branch instruction must |
| 1000 // be emitted at the pc offset recorded by the label. | 1000 // be emitted at the pc offset recorded by the label. |
| 1001 BlockConstPoolBefore(pc_offset() + kInstrSize); | 1001 BlockConstPoolFor(1); |
| 1002 return target_pos - (pc_offset() + kPcLoadDelta); | 1002 return target_pos - (pc_offset() + kPcLoadDelta); |
| 1003 } | 1003 } |
| 1004 | 1004 |
| 1005 | 1005 |
| 1006 void Assembler::label_at_put(Label* L, int at_offset) { | 1006 void Assembler::label_at_put(Label* L, int at_offset) { |
| 1007 int target_pos; | 1007 int target_pos; |
| 1008 if (L->is_bound()) { | 1008 if (L->is_bound()) { |
| 1009 target_pos = L->pos(); | 1009 target_pos = L->pos(); |
| 1010 } else { | 1010 } else { |
| 1011 if (L->is_linked()) { | 1011 if (L->is_linked()) { |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1487 addrmod4(cond | B27 | am, base, src); | 1487 addrmod4(cond | B27 | am, base, src); |
| 1488 } | 1488 } |
| 1489 | 1489 |
| 1490 | 1490 |
| 1491 // Exception-generating instructions and debugging support. | 1491 // Exception-generating instructions and debugging support. |
| 1492 // Stops with a non-negative code less than kNumOfWatchedStops support | 1492 // Stops with a non-negative code less than kNumOfWatchedStops support |
| 1493 // enabling/disabling and a counter feature. See simulator-arm.h . | 1493 // enabling/disabling and a counter feature. See simulator-arm.h . |
| 1494 void Assembler::stop(const char* msg, Condition cond, int32_t code) { | 1494 void Assembler::stop(const char* msg, Condition cond, int32_t code) { |
| 1495 #ifndef __arm__ | 1495 #ifndef __arm__ |
| 1496 ASSERT(code >= kDefaultStopCode); | 1496 ASSERT(code >= kDefaultStopCode); |
| 1497 // The Simulator will handle the stop instruction and get the message address. | 1497 { |
| 1498 // It expects to find the address just after the svc instruction. | 1498 // The Simulator will handle the stop instruction and get the message |
| 1499 BlockConstPoolFor(2); | 1499 // address. It expects to find the address just after the svc instruction. |
| 1500 if (code >= 0) { | 1500 BlockConstPoolScope block_const_pool(this); |
| 1501 svc(kStopCode + code, cond); | 1501 if (code >= 0) { |
| 1502 } else { | 1502 svc(kStopCode + code, cond); |
| 1503 svc(kStopCode + kMaxStopCode, cond); | 1503 } else { |
| 1504 svc(kStopCode + kMaxStopCode, cond); |
| 1505 } |
| 1506 emit(reinterpret_cast<Instr>(msg)); |
| 1504 } | 1507 } |
| 1505 emit(reinterpret_cast<Instr>(msg)); | |
| 1506 #else // def __arm__ | 1508 #else // def __arm__ |
| 1507 #ifdef CAN_USE_ARMV5_INSTRUCTIONS | 1509 #ifdef CAN_USE_ARMV5_INSTRUCTIONS |
| 1508 if (cond != al) { | 1510 if (cond != al) { |
| 1509 Label skip; | 1511 Label skip; |
| 1510 b(&skip, NegateCondition(cond)); | 1512 b(&skip, NegateCondition(cond)); |
| 1511 bkpt(0); | 1513 bkpt(0); |
| 1512 bind(&skip); | 1514 bind(&skip); |
| 1513 } else { | 1515 } else { |
| 1514 bkpt(0); | 1516 bkpt(0); |
| 1515 } | 1517 } |
| (...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2400 } | 2402 } |
| 2401 | 2403 |
| 2402 | 2404 |
| 2403 bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) { | 2405 bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) { |
| 2404 uint32_t dummy1; | 2406 uint32_t dummy1; |
| 2405 uint32_t dummy2; | 2407 uint32_t dummy2; |
| 2406 return fits_shifter(imm32, &dummy1, &dummy2, NULL); | 2408 return fits_shifter(imm32, &dummy1, &dummy2, NULL); |
| 2407 } | 2409 } |
| 2408 | 2410 |
| 2409 | 2411 |
| 2410 void Assembler::BlockConstPoolFor(int instructions) { | |
| 2411 BlockConstPoolBefore(pc_offset() + instructions * kInstrSize); | |
| 2412 } | |
| 2413 | |
| 2414 | |
| 2415 // Debugging. | 2412 // Debugging. |
| 2416 void Assembler::RecordJSReturn() { | 2413 void Assembler::RecordJSReturn() { |
| 2417 positions_recorder()->WriteRecordedPositions(); | 2414 positions_recorder()->WriteRecordedPositions(); |
| 2418 CheckBuffer(); | 2415 CheckBuffer(); |
| 2419 RecordRelocInfo(RelocInfo::JS_RETURN); | 2416 RecordRelocInfo(RelocInfo::JS_RETURN); |
| 2420 } | 2417 } |
| 2421 | 2418 |
| 2422 | 2419 |
| 2423 void Assembler::RecordDebugBreakSlot() { | 2420 void Assembler::RecordDebugBreakSlot() { |
| 2424 positions_recorder()->WriteRecordedPositions(); | 2421 positions_recorder()->WriteRecordedPositions(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2468 buffer_size_ = desc.buffer_size; | 2465 buffer_size_ = desc.buffer_size; |
| 2469 pc_ += pc_delta; | 2466 pc_ += pc_delta; |
| 2470 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, | 2467 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, |
| 2471 reloc_info_writer.last_pc() + pc_delta); | 2468 reloc_info_writer.last_pc() + pc_delta); |
| 2472 | 2469 |
| 2473 // None of our relocation types are pc relative pointing outside the code | 2470 // None of our relocation types are pc relative pointing outside the code |
| 2474 // buffer nor pc absolute pointing inside the code buffer, so there is no need | 2471 // buffer nor pc absolute pointing inside the code buffer, so there is no need |
| 2475 // to relocate any emitted relocation entries. | 2472 // to relocate any emitted relocation entries. |
| 2476 | 2473 |
| 2477 // Relocate pending relocation entries. | 2474 // Relocate pending relocation entries. |
| 2478 for (int i = 0; i < num_prinfo_; i++) { | 2475 for (int i = 0; i < num_pending_reloc_info_; i++) { |
| 2479 RelocInfo& rinfo = prinfo_[i]; | 2476 RelocInfo& rinfo = pending_reloc_info_[i]; |
| 2480 ASSERT(rinfo.rmode() != RelocInfo::COMMENT && | 2477 ASSERT(rinfo.rmode() != RelocInfo::COMMENT && |
| 2481 rinfo.rmode() != RelocInfo::POSITION); | 2478 rinfo.rmode() != RelocInfo::POSITION); |
| 2482 if (rinfo.rmode() != RelocInfo::JS_RETURN) { | 2479 if (rinfo.rmode() != RelocInfo::JS_RETURN) { |
| 2483 rinfo.set_pc(rinfo.pc() + pc_delta); | 2480 rinfo.set_pc(rinfo.pc() + pc_delta); |
| 2484 } | 2481 } |
| 2485 } | 2482 } |
| 2486 } | 2483 } |
| 2487 | 2484 |
| 2488 | 2485 |
| 2489 void Assembler::db(uint8_t data) { | 2486 void Assembler::db(uint8_t data) { |
| 2490 // No relocation info should be pending while using db. db is used | 2487 // No relocation info should be pending while using db. db is used |
| 2491 // to write pure data with no pointers and the constant pool should | 2488 // to write pure data with no pointers and the constant pool should |
| 2492 // be emitted before using db. | 2489 // be emitted before using db. |
| 2493 ASSERT(num_prinfo_ == 0); | 2490 ASSERT(num_pending_reloc_info_ == 0); |
| 2494 CheckBuffer(); | 2491 CheckBuffer(); |
| 2495 *reinterpret_cast<uint8_t*>(pc_) = data; | 2492 *reinterpret_cast<uint8_t*>(pc_) = data; |
| 2496 pc_ += sizeof(uint8_t); | 2493 pc_ += sizeof(uint8_t); |
| 2497 } | 2494 } |
| 2498 | 2495 |
| 2499 | 2496 |
| 2500 void Assembler::dd(uint32_t data) { | 2497 void Assembler::dd(uint32_t data) { |
| 2501 // No relocation info should be pending while using dd. dd is used | 2498 // No relocation info should be pending while using dd. dd is used |
| 2502 // to write pure data with no pointers and the constant pool should | 2499 // to write pure data with no pointers and the constant pool should |
| 2503 // be emitted before using dd. | 2500 // be emitted before using dd. |
| 2504 ASSERT(num_prinfo_ == 0); | 2501 ASSERT(num_pending_reloc_info_ == 0); |
| 2505 CheckBuffer(); | 2502 CheckBuffer(); |
| 2506 *reinterpret_cast<uint32_t*>(pc_) = data; | 2503 *reinterpret_cast<uint32_t*>(pc_) = data; |
| 2507 pc_ += sizeof(uint32_t); | 2504 pc_ += sizeof(uint32_t); |
| 2508 } | 2505 } |
| 2509 | 2506 |
| 2510 | 2507 |
| 2511 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { | 2508 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
| 2512 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants | 2509 RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants |
| 2513 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) { | 2510 if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) { |
| 2514 // Adjust code for new modes. | 2511 // Adjust code for new modes. |
| 2515 ASSERT(RelocInfo::IsDebugBreakSlot(rmode) | 2512 ASSERT(RelocInfo::IsDebugBreakSlot(rmode) |
| 2516 || RelocInfo::IsJSReturn(rmode) | 2513 || RelocInfo::IsJSReturn(rmode) |
| 2517 || RelocInfo::IsComment(rmode) | 2514 || RelocInfo::IsComment(rmode) |
| 2518 || RelocInfo::IsPosition(rmode)); | 2515 || RelocInfo::IsPosition(rmode)); |
| 2519 // These modes do not need an entry in the constant pool. | 2516 // These modes do not need an entry in the constant pool. |
| 2520 } else { | 2517 } else { |
| 2521 ASSERT(num_prinfo_ < kMaxNumPRInfo); | 2518 ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo); |
| 2522 prinfo_[num_prinfo_++] = rinfo; | 2519 if (num_pending_reloc_info_ == 0) { |
| 2520 first_const_pool_use_ = pc_offset(); |
| 2521 } |
| 2522 pending_reloc_info_[num_pending_reloc_info_++] = rinfo; |
| 2523 // Make sure the constant pool is not emitted in place of the next | 2523 // Make sure the constant pool is not emitted in place of the next |
| 2524 // instruction for which we just recorded relocation info. | 2524 // instruction for which we just recorded relocation info. |
| 2525 BlockConstPoolBefore(pc_offset() + kInstrSize); | 2525 BlockConstPoolFor(1); |
| 2526 } | 2526 } |
| 2527 if (rinfo.rmode() != RelocInfo::NONE) { | 2527 if (rinfo.rmode() != RelocInfo::NONE) { |
| 2528 // Don't record external references unless the heap will be serialized. | 2528 // Don't record external references unless the heap will be serialized. |
| 2529 if (rmode == RelocInfo::EXTERNAL_REFERENCE) { | 2529 if (rmode == RelocInfo::EXTERNAL_REFERENCE) { |
| 2530 #ifdef DEBUG | 2530 #ifdef DEBUG |
| 2531 if (!Serializer::enabled()) { | 2531 if (!Serializer::enabled()) { |
| 2532 Serializer::TooLateToEnableNow(); | 2532 Serializer::TooLateToEnableNow(); |
| 2533 } | 2533 } |
| 2534 #endif | 2534 #endif |
| 2535 if (!Serializer::enabled() && !emit_debug_code()) { | 2535 if (!Serializer::enabled() && !emit_debug_code()) { |
| 2536 return; | 2536 return; |
| 2537 } | 2537 } |
| 2538 } | 2538 } |
| 2539 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here | 2539 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here |
| 2540 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { | 2540 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { |
| 2541 ASSERT(ast_id_for_reloc_info_ != kNoASTId); | 2541 ASSERT(ast_id_for_reloc_info_ != kNoASTId); |
| 2542 RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_); | 2542 RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_); |
| 2543 ast_id_for_reloc_info_ = kNoASTId; | 2543 ast_id_for_reloc_info_ = kNoASTId; |
| 2544 reloc_info_writer.Write(&reloc_info_with_ast_id); | 2544 reloc_info_writer.Write(&reloc_info_with_ast_id); |
| 2545 } else { | 2545 } else { |
| 2546 reloc_info_writer.Write(&rinfo); | 2546 reloc_info_writer.Write(&rinfo); |
| 2547 } | 2547 } |
| 2548 } | 2548 } |
| 2549 } | 2549 } |
| 2550 | 2550 |
| 2551 | 2551 |
| 2552 void Assembler::BlockConstPoolFor(int instructions) { |
| 2553 int pc_limit = pc_offset() + instructions * kInstrSize; |
| 2554 if (no_const_pool_before_ < pc_limit) { |
| 2555 // If there are some pending entries, the constant pool cannot be blocked |
| 2556 // further than first_const_pool_use_ + kMaxDistToPool |
| 2557 ASSERT((num_pending_reloc_info_ == 0) || |
| 2558 (pc_limit < (first_const_pool_use_ + kMaxDistToPool))); |
| 2559 no_const_pool_before_ = pc_limit; |
| 2560 } |
| 2561 |
| 2562 if (next_buffer_check_ < no_const_pool_before_) { |
| 2563 next_buffer_check_ = no_const_pool_before_; |
| 2564 } |
| 2565 } |
| 2566 |
| 2567 |
| 2552 void Assembler::CheckConstPool(bool force_emit, bool require_jump) { | 2568 void Assembler::CheckConstPool(bool force_emit, bool require_jump) { |
| 2553 // Calculate the offset of the next check. It will be overwritten | 2569 // Some short sequence of instruction mustn't be broken up by constant pool |
| 2554 // when a const pool is generated or when const pools are being | 2570 // emission, such sequences are protected by calls to BlockConstPoolFor and |
| 2555 // blocked for a specific range. | 2571 // BlockConstPoolScope. |
| 2556 next_buffer_check_ = pc_offset() + kCheckConstInterval; | 2572 if (is_const_pool_blocked()) { |
| 2557 | |
| 2558 // There is nothing to do if there are no pending relocation info entries. | |
| 2559 if (num_prinfo_ == 0) return; | |
| 2560 | |
| 2561 // We emit a constant pool at regular intervals of about kDistBetweenPools | |
| 2562 // or when requested by parameter force_emit (e.g. after each function). | |
| 2563 // We prefer not to emit a jump unless the max distance is reached or if we | |
| 2564 // are running low on slots, which can happen if a lot of constants are being | |
| 2565 // emitted (e.g. --debug-code and many static references). | |
| 2566 int dist = pc_offset() - last_const_pool_end_; | |
| 2567 if (!force_emit && dist < kMaxDistBetweenPools && | |
| 2568 (require_jump || dist < kDistBetweenPools) && | |
| 2569 // TODO(1236125): Cleanup the "magic" number below. We know that | |
| 2570 // the code generation will test every kCheckConstIntervalInst. | |
| 2571 // Thus we are safe as long as we generate less than 7 constant | |
| 2572 // entries per instruction. | |
| 2573 (num_prinfo_ < (kMaxNumPRInfo - (7 * kCheckConstIntervalInst)))) { | |
| 2574 return; | |
| 2575 } | |
| 2576 | |
| 2577 // If we did not return by now, we need to emit the constant pool soon. | |
| 2578 | |
| 2579 // However, some small sequences of instructions must not be broken up by the | |
| 2580 // insertion of a constant pool; such sequences are protected by setting | |
| 2581 // either const_pool_blocked_nesting_ or no_const_pool_before_, which are | |
| 2582 // both checked here. Also, recursive calls to CheckConstPool are blocked by | |
| 2583 // no_const_pool_before_. | |
| 2584 if (const_pool_blocked_nesting_ > 0 || pc_offset() < no_const_pool_before_) { | |
| 2585 // Emission is currently blocked; make sure we try again as soon as | |
| 2586 // possible. | |
| 2587 if (const_pool_blocked_nesting_ > 0) { | |
| 2588 next_buffer_check_ = pc_offset() + kInstrSize; | |
| 2589 } else { | |
| 2590 next_buffer_check_ = no_const_pool_before_; | |
| 2591 } | |
| 2592 | |
| 2593 // Something is wrong if emission is forced and blocked at the same time. | 2573 // Something is wrong if emission is forced and blocked at the same time. |
| 2594 ASSERT(!force_emit); | 2574 ASSERT(!force_emit); |
| 2595 return; | 2575 return; |
| 2596 } | 2576 } |
| 2597 | 2577 |
| 2598 int jump_instr = require_jump ? kInstrSize : 0; | 2578 // There is nothing to do if there are no pending constant pool entries. |
| 2579 if (num_pending_reloc_info_ == 0) { |
| 2580 // Calculate the offset of the next check. |
| 2581 next_buffer_check_ = pc_offset() + kCheckPoolInterval; |
| 2582 return; |
| 2583 } |
| 2584 |
| 2585 // We emit a constant pool when: |
| 2586 // * requested to do so by parameter force_emit (e.g. after each function). |
| 2587 // * the distance to the first instruction accessing the constant pool is |
| 2588 // kAvgDistToPool or more. |
| 2589 // * no jump is required and the distance to the first instruction accessing |
| 2590 // the constant pool is at least kMaxDistToPool / 2. |
| 2591 ASSERT(first_const_pool_use_ >= 0); |
| 2592 int dist = pc_offset() - first_const_pool_use_; |
| 2593 if (!force_emit && dist < kAvgDistToPool && |
| 2594 (require_jump || (dist < (kMaxDistToPool / 2)))) { |
| 2595 return; |
| 2596 } |
| 2599 | 2597 |
| 2600 // Check that the code buffer is large enough before emitting the constant | 2598 // Check that the code buffer is large enough before emitting the constant |
| 2601 // pool and relocation information (include the jump over the pool and the | 2599 // pool (include the jump over the pool and the constant pool marker and |
| 2602 // constant pool marker). | 2600 // the gap to the relocation information). |
| 2603 int max_needed_space = | 2601 int jump_instr = require_jump ? kInstrSize : 0; |
| 2604 jump_instr + kInstrSize + num_prinfo_*(kInstrSize + kMaxRelocSize); | 2602 int needed_space = jump_instr + kInstrSize + |
| 2605 while (buffer_space() <= (max_needed_space + kGap)) GrowBuffer(); | 2603 num_pending_reloc_info_ * kInstrSize + kGap; |
| 2604 while (buffer_space() <= needed_space) GrowBuffer(); |
| 2606 | 2605 |
| 2607 // Block recursive calls to CheckConstPool. | 2606 { |
| 2608 BlockConstPoolBefore(pc_offset() + jump_instr + kInstrSize + | 2607 // Block recursive calls to CheckConstPool. |
| 2609 num_prinfo_*kInstrSize); | 2608 BlockConstPoolScope block_const_pool(this); |
| 2610 // Don't bother to check for the emit calls below. | |
| 2611 next_buffer_check_ = no_const_pool_before_; | |
| 2612 | 2609 |
| 2613 // Emit jump over constant pool if necessary. | 2610 // Emit jump over constant pool if necessary. |
| 2614 Label after_pool; | 2611 Label after_pool; |
| 2615 if (require_jump) b(&after_pool); | 2612 if (require_jump) { |
| 2613 b(&after_pool); |
| 2614 } |
| 2616 | 2615 |
| 2617 RecordComment("[ Constant Pool"); | 2616 RecordComment("[ Constant Pool"); |
| 2618 | 2617 |
| 2619 // Put down constant pool marker "Undefined instruction" as specified by | 2618 // Put down constant pool marker "Undefined instruction" as specified by |
| 2620 // A5.6 (ARMv7) Instruction set encoding. | 2619 // A5.6 (ARMv7) Instruction set encoding. |
| 2621 emit(kConstantPoolMarker | num_prinfo_); | 2620 emit(kConstantPoolMarker | num_pending_reloc_info_); |
| 2622 | 2621 |
| 2623 // Emit constant pool entries. | 2622 // Emit constant pool entries. |
| 2624 for (int i = 0; i < num_prinfo_; i++) { | 2623 for (int i = 0; i < num_pending_reloc_info_; i++) { |
| 2625 RelocInfo& rinfo = prinfo_[i]; | 2624 RelocInfo& rinfo = pending_reloc_info_[i]; |
| 2626 ASSERT(rinfo.rmode() != RelocInfo::COMMENT && | 2625 ASSERT(rinfo.rmode() != RelocInfo::COMMENT && |
| 2627 rinfo.rmode() != RelocInfo::POSITION && | 2626 rinfo.rmode() != RelocInfo::POSITION && |
| 2628 rinfo.rmode() != RelocInfo::STATEMENT_POSITION); | 2627 rinfo.rmode() != RelocInfo::STATEMENT_POSITION); |
| 2629 Instr instr = instr_at(rinfo.pc()); | |
| 2630 | 2628 |
| 2631 // Instruction to patch must be a ldr/str [pc, #offset]. | 2629 Instr instr = instr_at(rinfo.pc()); |
| 2632 // P and U set, B and W clear, Rn == pc, offset12 still 0. | 2630 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0. |
| 2633 ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | kOff12Mask)) == | 2631 ASSERT(IsLdrPcImmediateOffset(instr) && |
| 2634 (2*B25 | P | U | pc.code()*B16)); | 2632 GetLdrRegisterImmediateOffset(instr) == 0); |
| 2635 int delta = pc_ - rinfo.pc() - 8; | 2633 |
| 2636 ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32 | 2634 int delta = pc_ - rinfo.pc() - kPcLoadDelta; |
| 2637 if (delta < 0) { | 2635 // 0 is the smallest delta: |
| 2638 instr &= ~U; | 2636 // ldr rd, [pc, #0] |
| 2639 delta = -delta; | 2637 // constant pool marker |
| 2638 // data |
| 2639 ASSERT(is_uint12(delta)); |
| 2640 |
| 2641 instr_at_put(rinfo.pc(), SetLdrRegisterImmediateOffset(instr, delta)); |
| 2642 emit(rinfo.data()); |
| 2640 } | 2643 } |
| 2641 ASSERT(is_uint12(delta)); | |
| 2642 instr_at_put(rinfo.pc(), instr + delta); | |
| 2643 emit(rinfo.data()); | |
| 2644 } | |
| 2645 num_prinfo_ = 0; | |
| 2646 last_const_pool_end_ = pc_offset(); | |
| 2647 | 2644 |
| 2648 RecordComment("]"); | 2645 num_pending_reloc_info_ = 0; |
| 2646 first_const_pool_use_ = -1; |
| 2649 | 2647 |
| 2650 if (after_pool.is_linked()) { | 2648 RecordComment("]"); |
| 2651 bind(&after_pool); | 2649 |
| 2650 if (after_pool.is_linked()) { |
| 2651 bind(&after_pool); |
| 2652 } |
| 2652 } | 2653 } |
| 2653 | 2654 |
| 2654 // Since a constant pool was just emitted, move the check offset forward by | 2655 // Since a constant pool was just emitted, move the check offset forward by |
| 2655 // the standard interval. | 2656 // the standard interval. |
| 2656 next_buffer_check_ = pc_offset() + kCheckConstInterval; | 2657 next_buffer_check_ = pc_offset() + kCheckPoolInterval; |
| 2657 } | 2658 } |
| 2658 | 2659 |
| 2659 | 2660 |
| 2660 } } // namespace v8::internal | 2661 } } // namespace v8::internal |
| 2661 | 2662 |
| 2662 #endif // V8_TARGET_ARCH_ARM | 2663 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |