From: yangguo@chromium.org Date: Thu, 14 Jun 2012 11:16:47 +0000 (+0000) Subject: ARM: Fix literal pool handling for breakpoints in debugger. X-Git-Tag: upstream/4.7.83~16537 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fb81da2e5fbfe0f72ce22f304d5dfe68673d409f;p=platform%2Fupstream%2Fv8.git ARM: Fix literal pool handling for breakpoints in debugger. BUG=2177 TEST=none Review URL: https://chromiumcodereview.appspot.com/10449047 Patch from Martyn Capewell . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11812 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index ec28da4..68fcc28 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -2435,6 +2435,14 @@ void Assembler::RecordComment(const char* msg) { } +void Assembler::RecordConstPool(int size) { + // We only need this for debugger support, to correctly compute offsets in the + // code. +#ifdef ENABLE_DEBUGGER_SUPPORT + RecordRelocInfo(RelocInfo::CONST_POOL, static_cast(size)); +#endif +} + void Assembler::GrowBuffer() { if (!own_buffer_) FATAL("external code buffer is too small"); @@ -2511,12 +2519,15 @@ void Assembler::dd(uint32_t data) { void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { // We do not try to reuse pool constants. RelocInfo rinfo(pc_, rmode, data, NULL); - if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) { + if (((rmode >= RelocInfo::JS_RETURN) && + (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) || + (rmode == RelocInfo::CONST_POOL)) { // Adjust code for new modes. ASSERT(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsJSReturn(rmode) || RelocInfo::IsComment(rmode) - || RelocInfo::IsPosition(rmode)); + || RelocInfo::IsPosition(rmode) + || RelocInfo::IsConstPool(rmode)); // These modes do not need an entry in the constant pool. } else { ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo); @@ -2602,13 +2613,15 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { // pool (include the jump over the pool and the constant pool marker and // the gap to the relocation information). int jump_instr = require_jump ? kInstrSize : 0; - int needed_space = jump_instr + kInstrSize + - num_pending_reloc_info_ * kInstrSize + kGap; + int size = jump_instr + kInstrSize + num_pending_reloc_info_ * kPointerSize; + int needed_space = size + kGap; while (buffer_space() <= needed_space) GrowBuffer(); { // Block recursive calls to CheckConstPool. BlockConstPoolScope block_const_pool(this); + RecordComment("[ Constant Pool"); + RecordConstPool(size); // Emit jump over constant pool if necessary. Label after_pool; @@ -2616,8 +2629,6 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { b(&after_pool); } - RecordComment("[ Constant Pool"); - // Put down constant pool marker "Undefined instruction" as specified by // A5.6 (ARMv7) Instruction set encoding. emit(kConstantPoolMarker | num_pending_reloc_info_); @@ -2627,7 +2638,8 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) { RelocInfo& rinfo = pending_reloc_info_[i]; ASSERT(rinfo.rmode() != RelocInfo::COMMENT && rinfo.rmode() != RelocInfo::POSITION && - rinfo.rmode() != RelocInfo::STATEMENT_POSITION); + rinfo.rmode() != RelocInfo::STATEMENT_POSITION && + rinfo.rmode() != RelocInfo::CONST_POOL); Instr instr = instr_at(rinfo.pc()); // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0. diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index e2d5f59..497d0d4 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -1219,6 +1219,25 @@ class Assembler : public AssemblerBase { // Use --code-comments to enable. void RecordComment(const char* msg); + // Record the emission of a constant pool. + // + // The emission of constant pool depends on the size of the code generated and + // the number of RelocInfo recorded. + // The Debug mechanism needs to map code offsets between two versions of a + // function, compiled with and without debugger support (see for example + // Debug::PrepareForBreakPoints()). + // Compiling functions with debugger support generates additional code + // (Debug::GenerateSlot()). This may affect the emission of the constant + // pools and cause the version of the code with debugger support to have + // constant pools generated in different places. + // Recording the position and size of emitted constant pools allows to + // correctly compute the offset mappings between the different versions of a + // function in all situations. + // + // The parameter indicates the size of the constant pool (in bytes), including + // the marker and branch over the data. + void RecordConstPool(int size); + // Writes a single byte or word of data in the code stream. Used // for inline tables, e.g., jump-tables. The constant pool should be // emitted before any use of db and dd to ensure that constant pools diff --git a/src/assembler.cc b/src/assembler.cc index d4c49dd..eebfc97 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -141,7 +141,7 @@ int Label::pos() const { // an iteration. // // The encoding relies on the fact that there are fewer than 14 -// different non-compactly encoded relocation modes. +// different relocation modes using standard non-compact encoding. // // The first byte of a relocation record has a tag in its low 2 bits: // Here are the record schemes, depending on the low tag and optional higher @@ -173,7 +173,9 @@ int Label::pos() const { // 00 [4 bit middle_tag] 11 followed by // 00 [6 bit pc delta] // -// 1101: not used (would allow one more relocation mode to be added) +// 1101: constant pool. Used on ARM only for now. +// The format is: 11 1101 11 +// signed int (size of the constant pool). // 1110: long_data_record // The format is: [2-bit data_type_tag] 1110 11 // signed intptr_t, lowest byte written first @@ -194,7 +196,7 @@ int Label::pos() const { // dropped, and last non-zero chunk tagged with 1.) -const int kMaxRelocModes = 14; +const int kMaxStandardNonCompactModes = 14; const int kTagBits = 2; const int kTagMask = (1 << kTagBits) - 1; @@ -228,6 +230,9 @@ const int kNonstatementPositionTag = 1; const int kStatementPositionTag = 2; const int kCommentTag = 3; +const int kConstPoolExtraTag = kPCJumpExtraTag - 2; +const int kConstPoolTag = 3; + uint32_t RelocInfoWriter::WriteVariableLengthPCJump(uint32_t pc_delta) { // Return if the pc_delta can fit in kSmallPCDeltaBits bits. @@ -285,6 +290,15 @@ void RelocInfoWriter::WriteExtraTaggedIntData(int data_delta, int top_tag) { } } +void RelocInfoWriter::WriteExtraTaggedConstPoolData(int data) { + WriteExtraTag(kConstPoolExtraTag, kConstPoolTag); + for (int i = 0; i < kIntSize; i++) { + *--pos_ = static_cast(data); + // Signed right shift is arithmetic shift. Tested in test-utils.cc. + data = data >> kBitsPerByte; + } +} + void RelocInfoWriter::WriteExtraTaggedData(intptr_t data_delta, int top_tag) { WriteExtraTag(kDataJumpExtraTag, top_tag); for (int i = 0; i < kIntptrSize; i++) { @@ -300,8 +314,8 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) { byte* begin_pos = pos_; #endif ASSERT(rinfo->pc() - last_pc_ >= 0); - ASSERT(RelocInfo::NUMBER_OF_MODES - RelocInfo::LAST_COMPACT_ENUM <= - kMaxRelocModes); + ASSERT(RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM - RelocInfo::LAST_COMPACT_ENUM + <= kMaxStandardNonCompactModes); // Use unsigned delta-encoding for pc. uint32_t pc_delta = static_cast(rinfo->pc() - last_pc_); RelocInfo::Mode rmode = rinfo->rmode(); @@ -347,6 +361,9 @@ void RelocInfoWriter::Write(const RelocInfo* rinfo) { WriteExtraTaggedPC(pc_delta, kPCJumpExtraTag); WriteExtraTaggedData(rinfo->data(), kCommentTag); ASSERT(begin_pos - pos_ >= RelocInfo::kMinRelocCommentSize); + } else if (RelocInfo::IsConstPool(rmode)) { + WriteExtraTaggedPC(pc_delta, kPCJumpExtraTag); + WriteExtraTaggedConstPoolData(rinfo->data()); } else { ASSERT(rmode > RelocInfo::LAST_COMPACT_ENUM); int saved_mode = rmode - RelocInfo::LAST_COMPACT_ENUM; @@ -397,6 +414,15 @@ void RelocIterator::AdvanceReadId() { } +void RelocIterator::AdvanceReadConstPoolData() { + int x = 0; + for (int i = 0; i < kIntSize; i++) { + x |= static_cast(*--pos_) << i * kBitsPerByte; + } + rinfo_.data_ = x; +} + + void RelocIterator::AdvanceReadPosition() { int x = 0; for (int i = 0; i < kIntSize; i++) { @@ -500,8 +526,7 @@ void RelocIterator::next() { ASSERT(tag == kDefaultTag); int extra_tag = GetExtraTag(); if (extra_tag == kPCJumpExtraTag) { - int top_tag = GetTopTag(); - if (top_tag == kVariableLengthPCJumpTopTag) { + if (GetTopTag() == kVariableLengthPCJumpTopTag) { AdvanceReadVariableLengthPCJump(); } else { AdvanceReadPC(); @@ -531,6 +556,13 @@ void RelocIterator::next() { } Advance(kIntptrSize); } + } else if ((extra_tag == kConstPoolExtraTag) && + (GetTopTag() == kConstPoolTag)) { + if (SetMode(RelocInfo::CONST_POOL)) { + AdvanceReadConstPoolData(); + return; + } + Advance(kIntSize); } else { AdvanceReadPC(); int rmode = extra_tag + RelocInfo::LAST_COMPACT_ENUM; @@ -613,6 +645,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) { return "external reference"; case RelocInfo::INTERNAL_REFERENCE: return "internal reference"; + case RelocInfo::CONST_POOL: + return "constant pool"; case RelocInfo::DEBUG_BREAK_SLOT: #ifndef ENABLE_DEBUGGER_SUPPORT UNREACHABLE(); @@ -698,6 +732,7 @@ void RelocInfo::Verify() { case STATEMENT_POSITION: case EXTERNAL_REFERENCE: case INTERNAL_REFERENCE: + case CONST_POOL: case DEBUG_BREAK_SLOT: case NONE: break; diff --git a/src/assembler.h b/src/assembler.h index 619c69c..fb5ac1f 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -204,14 +204,19 @@ class RelocInfo BASE_EMBEDDED { EXTERNAL_REFERENCE, // The address of an external C++ function. INTERNAL_REFERENCE, // An address inside the same function. + // Marks a constant pool. Only used on ARM. + // It uses a custom noncompact encoding. + CONST_POOL, + // add more as needed // Pseudo-types - NUMBER_OF_MODES, // There are at most 14 modes with noncompact encoding. + NUMBER_OF_MODES, // There are at most 15 modes with noncompact encoding. NONE, // never recorded LAST_CODE_ENUM = DEBUG_BREAK, LAST_GCED_ENUM = GLOBAL_PROPERTY_CELL, // Modes <= LAST_COMPACT_ENUM are guaranteed to have compact encoding. - LAST_COMPACT_ENUM = CODE_TARGET_WITH_ID + LAST_COMPACT_ENUM = CODE_TARGET_WITH_ID, + LAST_STANDARD_NONCOMPACT_ENUM = INTERNAL_REFERENCE }; @@ -240,6 +245,9 @@ class RelocInfo BASE_EMBEDDED { static inline bool IsComment(Mode mode) { return mode == COMMENT; } + static inline bool IsConstPool(Mode mode) { + return mode == CONST_POOL; + } static inline bool IsPosition(Mode mode) { return mode == POSITION || mode == STATEMENT_POSITION; } @@ -416,6 +424,7 @@ class RelocInfoWriter BASE_EMBEDDED { inline void WriteTaggedPC(uint32_t pc_delta, int tag); inline void WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag); inline void WriteExtraTaggedIntData(int data_delta, int top_tag); + inline void WriteExtraTaggedConstPoolData(int data); inline void WriteExtraTaggedData(intptr_t data_delta, int top_tag); inline void WriteTaggedData(intptr_t data_delta, int tag); inline void WriteExtraTag(int extra_tag, int top_tag); @@ -466,6 +475,7 @@ class RelocIterator: public Malloced { void ReadTaggedPC(); void AdvanceReadPC(); void AdvanceReadId(); + void AdvanceReadConstPoolData(); void AdvanceReadPosition(); void AdvanceReadData(); void AdvanceReadVariableLengthPCJump(); diff --git a/src/debug.cc b/src/debug.cc index 543ce9f..083f38f 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1868,29 +1868,48 @@ static void RedirectActivationsToRecompiledCodeOnThread( continue; } - intptr_t delta = frame->pc() - frame_code->instruction_start(); - int debug_break_slot_count = 0; - int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT); + // Iterate over the RelocInfo in the original code to compute the sum of the + // constant pools sizes. (See Assembler::CheckConstPool()) + // Note that this is only useful for architectures using constant pools. + int constpool_mask = RelocInfo::ModeMask(RelocInfo::CONST_POOL); + int frame_const_pool_size = 0; + for (RelocIterator it(*frame_code, constpool_mask); !it.done(); it.next()) { + RelocInfo* info = it.rinfo(); + if (info->pc() >= frame->pc()) break; + frame_const_pool_size += info->data(); + } + intptr_t frame_offset = + frame->pc() - frame_code->instruction_start() - frame_const_pool_size; + + // Iterate over the RelocInfo for new code to find the number of bytes + // generated for debug slots and constant pools. + int debug_break_slot_bytes = 0; + int new_code_const_pool_size = 0; + int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) | + RelocInfo::ModeMask(RelocInfo::CONST_POOL); for (RelocIterator it(*new_code, mask); !it.done(); it.next()) { // Check if the pc in the new code with debug break // slots is before this slot. RelocInfo* info = it.rinfo(); - int debug_break_slot_bytes = - debug_break_slot_count * Assembler::kDebugBreakSlotLength; - intptr_t new_delta = - info->pc() - - new_code->instruction_start() - - debug_break_slot_bytes; - if (new_delta > delta) { + intptr_t new_offset = info->pc() - new_code->instruction_start() - + new_code_const_pool_size - debug_break_slot_bytes; + if (new_offset >= frame_offset) { break; } - // Passed a debug break slot in the full code with debug - // break slots. - debug_break_slot_count++; + if (RelocInfo::IsDebugBreakSlot(info->rmode())) { + debug_break_slot_bytes += Assembler::kDebugBreakSlotLength; + } else { + ASSERT(RelocInfo::IsConstPool(info->rmode())); + // The size of the constant pool is encoded in the data. + new_code_const_pool_size += info->data(); + } } - int debug_break_slot_bytes = - debug_break_slot_count * Assembler::kDebugBreakSlotLength; + + // Compute the equivalent pc in the new code. + byte* new_pc = new_code->instruction_start() + frame_offset + + debug_break_slot_bytes + new_code_const_pool_size; + if (FLAG_trace_deopt) { PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " @@ -1907,14 +1926,12 @@ static void RedirectActivationsToRecompiledCodeOnThread( new_code->instruction_size(), new_code->instruction_size(), reinterpret_cast(frame->pc()), - reinterpret_cast(new_code->instruction_start()) + - delta + debug_break_slot_bytes); + reinterpret_cast(new_pc)); } // Patch the return address to return into the code with // debug break slots. - frame->set_pc( - new_code->instruction_start() + delta + debug_break_slot_bytes); + frame->set_pc(new_pc); } } diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index e311ffb..5ae1274 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status @@ -34,9 +34,6 @@ bugs/*: FAIL # Fails. regress/regress-1119: FAIL -# Issue 2177: Debugger on ARM broken due to variable literal pool size. -debug-liveedit-breakpoints: PASS, SKIP if ($arch == arm) - # Issue 1719: Slow to collect arrays over several contexts. regress/regress-524: SKIP # When that bug is fixed, revert the expectation to: