Revision: 6801
Author: [email protected]
Date: Tue Feb 15 13:11:31 2011
Log: Added gdb-jit interface support for ARM. Compressed .debug_line table by 1) removing duplicate adjacent entries having the same line number, and 2) using special opcodes to encode multiple machine register state changes in one byte. Also made a fix involving the order in which static initializers are performed.

Patch by Shasank Chavan of Hewlett-Packard Development Company, LP

BUG=none
TEST=Try building for arm

Review URL: http://codereview.chromium.org/6524020
http://code.google.com/p/v8/source/detail?r=6801

Modified:
 /branches/bleeding_edge/SConstruct
 /branches/bleeding_edge/src/flag-definitions.h
 /branches/bleeding_edge/src/gdb-jit.cc

=======================================
--- /branches/bleeding_edge/SConstruct  Fri Feb 11 04:25:41 2011
+++ /branches/bleeding_edge/SConstruct  Tue Feb 15 13:11:31 2011
@@ -890,7 +890,7 @@
     return False
if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on':
     Abort("Profiling on windows only supported for static library.")
- if env['gdbjit'] == 'on' and (env['os'] != 'linux' or (env['arch'] != 'ia32' and env['arch'] != 'x64')): + if env['gdbjit'] == 'on' and (env['os'] != 'linux' or (env['arch'] != 'ia32' and env['arch'] != 'x64' and env['arch'] != 'arm')): Abort("GDBJIT interface is supported only for Intel-compatible (ia32 or x64) Linux target.")
   if env['os'] == 'win32' and env['soname'] == 'on':
     Abort("Shared Object soname not applicable for Windows.")
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h      Tue Feb 15 00:47:14 2011
+++ /branches/bleeding_edge/src/flag-definitions.h      Tue Feb 15 13:11:31 2011
@@ -378,6 +378,7 @@

DEFINE_bool(gdbjit, false, "enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false, "enable GDBJIT interface for all code objects")
+DEFINE_bool(gdbjit_dump, false, "dump elf objects with debug info to disk")

 //
 // Debug only flags
=======================================
--- /branches/bleeding_edge/src/gdb-jit.cc      Wed Feb  2 05:32:18 2011
+++ /branches/bleeding_edge/src/gdb-jit.cc      Tue Feb 15 13:11:31 2011
@@ -395,7 +395,7 @@
   void WriteHeader(Writer* w) {
     ASSERT(w->position() == 0);
     Writer::Slot<ELFHeader> header = w->CreateSlotHere<ELFHeader>();
-#if defined(V8_TARGET_ARCH_IA32)
+#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_ARM)
     const uint8_t ident[16] =
         { 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #elif defined(V8_TARGET_ARCH_X64)
@@ -413,6 +413,10 @@
     //    System V ABI, AMD64 Supplement
     //    http://www.x86-64.org/documentation/abi.pdf
     header->machine = 62;
+#elif defined(V8_TARGET_ARCH_ARM)
+    // Set to EM_ARM, defined as 40, in "ARM ELF File Format" at
+    // infocenter.arm.com/help/topic/com.arm.doc.dui0101a/DUI0101A_Elf.pdf
+    header->machine = 40;
 #else
 #error Unsupported target architecture.
 #endif
@@ -503,8 +507,7 @@
   Binding binding() const {
     return static_cast<Binding>(info >> 4);
   }
-
-#if defined(V8_TARGET_ARCH_IA32)
+#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_ARM)
   struct SerializedLayout {
     SerializedLayout(uint32_t name,
                      uintptr_t value,
@@ -857,14 +860,20 @@
     Writer::Slot<uint32_t> total_length = w->CreateSlotHere<uint32_t>();
     uintptr_t start = w->position();

+    // Used for special opcodes
+    const int8_t line_base = 1;
+    const uint8_t line_range = 7;
+    const int8_t max_line_incr = (line_base + line_range - 1);
+    const uint8_t opcode_base = DW_LNS_NEGATE_STMT + 1;
+
     w->Write<uint16_t>(2);  // Field version.
     Writer::Slot<uint32_t> prologue_length = w->CreateSlotHere<uint32_t>();
     uintptr_t prologue_start = w->position();
     w->Write<uint8_t>(1);  // Field minimum_instruction_length.
     w->Write<uint8_t>(1);  // Field default_is_stmt.
-    w->Write<int8_t>(0);  // Field line_base.
-    w->Write<uint8_t>(2);  // Field line_range.
-    w->Write<uint8_t>(DW_LNS_NEGATE_STMT + 1);  // Field opcode_base.
+    w->Write<int8_t>(line_base);  // Field line_base.
+    w->Write<uint8_t>(line_range);  // Field line_range.
+    w->Write<uint8_t>(opcode_base);  // Field opcode_base.
     w->Write<uint8_t>(0);  // DW_LNS_COPY operands count.
     w->Write<uint8_t>(1);  // DW_LNS_ADVANCE_PC operands count.
     w->Write<uint8_t>(1);  // DW_LNS_ADVANCE_LINE operands count.
@@ -881,6 +890,7 @@

     WriteExtendedOpcode(w, DW_LNE_SET_ADDRESS, sizeof(intptr_t));
     w->Write<intptr_t>(desc_->CodeStart());
+    w->Write<uint8_t>(DW_LNS_COPY);

     intptr_t pc = 0;
     intptr_t line = 1;
@@ -888,29 +898,66 @@

     List<GDBJITLineInfo::PCInfo>* pc_info = desc_->lineinfo()->pc_info();
     pc_info->Sort(&ComparePCInfo);
-    for (int i = 0; i < pc_info->length(); i++) {
+
+    int pc_info_length = pc_info->length();
+    for (int i = 0; i < pc_info_length; i++) {
       GDBJITLineInfo::PCInfo* info = &pc_info->at(i);
-      uintptr_t pc_diff = info->pc_ - pc;
       ASSERT(info->pc_ >= pc);
-      if (pc_diff != 0) {
-        w->Write<uint8_t>(DW_LNS_ADVANCE_PC);
-        w->WriteSLEB128(pc_diff);
-        pc += pc_diff;
-      }
-      intptr_t line_diff = desc_->GetScriptLineNumber(info->pos_) - line;
-      if (line_diff != 0) {
-        w->Write<uint8_t>(DW_LNS_ADVANCE_LINE);
-        w->WriteSLEB128(line_diff);
-        line += line_diff;
-      }
-      if (is_statement != info->is_statement_) {
+
+      // Reduce bloating in the debug line table by removing duplicate line
+      // entries (per DWARF2 standard).
+      intptr_t  new_line = desc_->GetScriptLineNumber(info->pos_);
+      if (new_line == line) {
+        continue;
+      }
+
+ // Mark statement boundaries. For a better debugging experience, mark + // the last pc address in the function as a statement (e.g. "}"), so that + // a user can see the result of the last line executed in the function,
+      // should control reach the end.
+      if ((i+1) == pc_info_length) {
+        if (!is_statement) {
+          w->Write<uint8_t>(DW_LNS_NEGATE_STMT);
+        }
+      } else if (is_statement != info->is_statement_) {
         w->Write<uint8_t>(DW_LNS_NEGATE_STMT);
         is_statement = !is_statement;
       }
-      if (pc_diff != 0 || i == 0) {
+
+ // Generate special opcodes, if possible. This results in more compact
+      // debug line tables.  See the DWARF 2.0 standard to learn more about
+      // special opcodes.
+      uintptr_t pc_diff = info->pc_ - pc;
+      intptr_t line_diff = new_line - line;
+
+      // Compute special opcode (see DWARF 2.0 standard)
+      intptr_t special_opcode = (line_diff - line_base) +
+                                (line_range * pc_diff) + opcode_base;
+
+ // If special_opcode is less than or equal to 255, it can be used as a + // special opcode. If line_diff is larger than the max line increment + // allowed for a special opcode, or if line_diff is less than the minimum
+      // line that can be added to the line register (i.e. line_base), then
+      // special_opcode can't be used.
+      if ((special_opcode >= opcode_base) && (special_opcode <= 255) &&
+          (line_diff <= max_line_incr) && (line_diff >= line_base)) {
+        w->Write<uint8_t>(special_opcode);
+      } else {
+        w->Write<uint8_t>(DW_LNS_ADVANCE_PC);
+        w->WriteSLEB128(pc_diff);
+        w->Write<uint8_t>(DW_LNS_ADVANCE_LINE);
+        w->WriteSLEB128(line_diff);
         w->Write<uint8_t>(DW_LNS_COPY);
       }
-    }
+
+      // Increment the pc and line operands.
+      pc += pc_diff;
+      line += line_diff;
+    }
+ // Advance the pc to the end of the routine, since the end sequence opcode
+    // requires this.
+    w->Write<uint8_t>(DW_LNS_ADVANCE_PC);
+    w->WriteSLEB128(desc_->CodeSize() - pc);
     WriteExtendedOpcode(w, DW_LNE_END_SEQUENCE, 0);
     total_length.set(static_cast<uint32_t>(w->position() - start));
     return true;
@@ -1237,6 +1284,20 @@


 static void RegisterCodeEntry(JITCodeEntry* entry) {
+#if defined(DEBUG) && !defined(WIN32)
+  static int file_num = 0;
+  if (FLAG_gdbjit_dump) {
+    static const int kMaxFileNameSize = 64;
+    static const char* kElfFilePrefix = "/tmp/elfdump";
+    static const char* kObjFileExt = ".o";
+    char file_name[64];
+
+    OS::SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "%s%d%s",
+                 kElfFilePrefix, file_num++, kObjFileExt);
+    WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_);
+  }
+#endif
+
   entry->next_ = __jit_debug_descriptor.first_entry_;
   if (entry->next_ != NULL) entry->next_->prev_ = entry;
   __jit_debug_descriptor.first_entry_ =
@@ -1294,7 +1355,13 @@
 }


-static HashMap entries(&SameCodeObjects);
+static HashMap* GetEntries() {
+  static HashMap* entries = NULL;
+  if (entries == NULL) {
+    entries = new HashMap(&SameCodeObjects);
+  }
+  return entries;
+}


 static uint32_t HashForCodeObject(Code* code) {
@@ -1398,7 +1465,7 @@
   if (!FLAG_gdbjit) return;
   AssertNoAllocation no_gc;

-  HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true);
+ HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
   if (e->value != NULL && !IsLineInfoTagged(e->value)) return;

   GDBJITLineInfo* lineinfo = UntagLineInfo(e->value);
@@ -1411,7 +1478,7 @@

   if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) {
     delete lineinfo;
-    entries.Remove(code, HashForCodeObject(code));
+    GetEntries()->Remove(code, HashForCodeObject(code));
     return;
   }

@@ -1464,7 +1531,9 @@
 void GDBJITInterface::RemoveCode(Code* code) {
   if (!FLAG_gdbjit) return;

-  HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), false);
+  HashMap::Entry* e = GetEntries()->Lookup(code,
+                                           HashForCodeObject(code),
+                                           false);
   if (e == NULL) return;

   if (IsLineInfoTagged(e->value)) {
@@ -1475,14 +1544,14 @@
     DestroyCodeEntry(entry);
   }
   e->value = NULL;
-  entries.Remove(code, HashForCodeObject(code));
+  GetEntries()->Remove(code, HashForCodeObject(code));
 }


 void GDBJITInterface::RegisterDetailedLineInfo(Code* code,
                                                GDBJITLineInfo* line_info) {
   ASSERT(!IsLineInfoTagged(line_info));
-  HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true);
+ HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
   ASSERT(e->value == NULL);
   e->value = TagLineInfo(line_info);
 }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to