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