OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifdef ENABLE_GDB_JIT_INTERFACE | |
6 #include "src/v8.h" | 5 #include "src/v8.h" |
7 | 6 |
8 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
9 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
10 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
11 #include "src/compiler.h" | 10 #include "src/compiler.h" |
12 #include "src/frames-inl.h" | 11 #include "src/frames-inl.h" |
13 #include "src/frames.h" | 12 #include "src/frames.h" |
14 #include "src/gdb-jit.h" | 13 #include "src/gdb-jit.h" |
15 #include "src/global-handles.h" | 14 #include "src/global-handles.h" |
16 #include "src/messages.h" | 15 #include "src/messages.h" |
17 #include "src/natives.h" | 16 #include "src/natives.h" |
| 17 #include "src/objects.h" |
18 #include "src/ostreams.h" | 18 #include "src/ostreams.h" |
19 #include "src/scopes.h" | |
20 | 19 |
21 namespace v8 { | 20 namespace v8 { |
22 namespace internal { | 21 namespace internal { |
| 22 namespace GDBJITInterface { |
| 23 |
| 24 #ifdef ENABLE_GDB_JIT_INTERFACE |
23 | 25 |
24 #ifdef __APPLE__ | 26 #ifdef __APPLE__ |
25 #define __MACH_O | 27 #define __MACH_O |
26 class MachO; | 28 class MachO; |
27 class MachOSection; | 29 class MachOSection; |
28 typedef MachO DebugObject; | 30 typedef MachO DebugObject; |
29 typedef MachOSection DebugSection; | 31 typedef MachOSection DebugSection; |
30 #else | 32 #else |
31 #define __ELF | 33 #define __ELF |
32 class ELF; | 34 class ELF; |
(...skipping 893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
926 public: | 928 public: |
927 #if V8_TARGET_ARCH_X64 | 929 #if V8_TARGET_ARCH_X64 |
928 enum StackState { | 930 enum StackState { |
929 POST_RBP_PUSH, | 931 POST_RBP_PUSH, |
930 POST_RBP_SET, | 932 POST_RBP_SET, |
931 POST_RBP_POP, | 933 POST_RBP_POP, |
932 STACK_STATE_MAX | 934 STACK_STATE_MAX |
933 }; | 935 }; |
934 #endif | 936 #endif |
935 | 937 |
936 CodeDescription(const char* name, Code* code, Handle<Script> script, | 938 CodeDescription(const char* name, Code* code, SharedFunctionInfo* shared, |
937 LineInfo* lineinfo, GDBJITInterface::CodeTag tag, | 939 LineInfo* lineinfo) |
938 CompilationInfo* info) | 940 : name_(name), code_(code), shared_info_(shared), lineinfo_(lineinfo) {} |
939 : name_(name), | |
940 code_(code), | |
941 script_(script), | |
942 lineinfo_(lineinfo), | |
943 tag_(tag), | |
944 info_(info) {} | |
945 | 941 |
946 const char* name() const { | 942 const char* name() const { |
947 return name_; | 943 return name_; |
948 } | 944 } |
949 | 945 |
950 LineInfo* lineinfo() const { return lineinfo_; } | 946 LineInfo* lineinfo() const { return lineinfo_; } |
951 | 947 |
952 GDBJITInterface::CodeTag tag() const { | 948 bool is_function() const { |
953 return tag_; | 949 Code::Kind kind = code_->kind(); |
| 950 return kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION; |
954 } | 951 } |
955 | 952 |
956 CompilationInfo* info() const { | 953 bool has_scope_info() const { return shared_info_ != NULL; } |
957 return info_; | |
958 } | |
959 | 954 |
960 bool IsInfoAvailable() const { | 955 ScopeInfo* scope_info() const { |
961 return info_ != NULL; | 956 DCHECK(has_scope_info()); |
| 957 return shared_info_->scope_info(); |
962 } | 958 } |
963 | 959 |
964 uintptr_t CodeStart() const { | 960 uintptr_t CodeStart() const { |
965 return reinterpret_cast<uintptr_t>(code_->instruction_start()); | 961 return reinterpret_cast<uintptr_t>(code_->instruction_start()); |
966 } | 962 } |
967 | 963 |
968 uintptr_t CodeEnd() const { | 964 uintptr_t CodeEnd() const { |
969 return reinterpret_cast<uintptr_t>(code_->instruction_end()); | 965 return reinterpret_cast<uintptr_t>(code_->instruction_end()); |
970 } | 966 } |
971 | 967 |
972 uintptr_t CodeSize() const { | 968 uintptr_t CodeSize() const { |
973 return CodeEnd() - CodeStart(); | 969 return CodeEnd() - CodeStart(); |
974 } | 970 } |
975 | 971 |
| 972 bool has_script() { |
| 973 return shared_info_ != NULL && shared_info_->script()->IsScript(); |
| 974 } |
| 975 |
| 976 Script* script() { return Script::cast(shared_info_->script()); } |
| 977 |
976 bool IsLineInfoAvailable() { | 978 bool IsLineInfoAvailable() { |
977 return !script_.is_null() && | 979 return has_script() && script()->source()->IsString() && |
978 script_->source()->IsString() && | 980 script()->HasValidSource() && script()->name()->IsString() && |
979 script_->HasValidSource() && | 981 lineinfo_ != NULL; |
980 script_->name()->IsString() && | |
981 lineinfo_ != NULL; | |
982 } | 982 } |
983 | 983 |
984 #if V8_TARGET_ARCH_X64 | 984 #if V8_TARGET_ARCH_X64 |
985 uintptr_t GetStackStateStartAddress(StackState state) const { | 985 uintptr_t GetStackStateStartAddress(StackState state) const { |
986 DCHECK(state < STACK_STATE_MAX); | 986 DCHECK(state < STACK_STATE_MAX); |
987 return stack_state_start_addresses_[state]; | 987 return stack_state_start_addresses_[state]; |
988 } | 988 } |
989 | 989 |
990 void SetStackStateStartAddress(StackState state, uintptr_t addr) { | 990 void SetStackStateStartAddress(StackState state, uintptr_t addr) { |
991 DCHECK(state < STACK_STATE_MAX); | 991 DCHECK(state < STACK_STATE_MAX); |
992 stack_state_start_addresses_[state] = addr; | 992 stack_state_start_addresses_[state] = addr; |
993 } | 993 } |
994 #endif | 994 #endif |
995 | 995 |
996 SmartArrayPointer<char> GetFilename() { | 996 SmartArrayPointer<char> GetFilename() { |
997 return String::cast(script_->name())->ToCString(); | 997 return String::cast(script()->name())->ToCString(); |
998 } | 998 } |
999 | 999 |
1000 int GetScriptLineNumber(int pos) { | 1000 int GetScriptLineNumber(int pos) { return script()->GetLineNumber(pos) + 1; } |
1001 return script_->GetLineNumber(pos) + 1; | |
1002 } | |
1003 | 1001 |
1004 | 1002 |
1005 private: | 1003 private: |
1006 const char* name_; | 1004 const char* name_; |
1007 Code* code_; | 1005 Code* code_; |
1008 Handle<Script> script_; | 1006 SharedFunctionInfo* shared_info_; |
1009 LineInfo* lineinfo_; | 1007 LineInfo* lineinfo_; |
1010 GDBJITInterface::CodeTag tag_; | |
1011 CompilationInfo* info_; | |
1012 #if V8_TARGET_ARCH_X64 | 1008 #if V8_TARGET_ARCH_X64 |
1013 uintptr_t stack_state_start_addresses_[STACK_STATE_MAX]; | 1009 uintptr_t stack_state_start_addresses_[STACK_STATE_MAX]; |
1014 #endif | 1010 #endif |
1015 }; | 1011 }; |
1016 | 1012 |
1017 #if defined(__ELF) | 1013 #if defined(__ELF) |
1018 static void CreateSymbolsTable(CodeDescription* desc, | 1014 static void CreateSymbolsTable(CodeDescription* desc, |
1019 Zone* zone, | 1015 Zone* zone, |
1020 ELF* elf, | 1016 ELF* elf, |
1021 int text_section_index) { | 1017 int text_section_index) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1088 w->WriteString(desc_->GetFilename().get()); | 1084 w->WriteString(desc_->GetFilename().get()); |
1089 w->Write<intptr_t>(desc_->CodeStart()); | 1085 w->Write<intptr_t>(desc_->CodeStart()); |
1090 w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); | 1086 w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); |
1091 w->Write<uint32_t>(0); | 1087 w->Write<uint32_t>(0); |
1092 | 1088 |
1093 uint32_t ty_offset = static_cast<uint32_t>(w->position() - cu_start); | 1089 uint32_t ty_offset = static_cast<uint32_t>(w->position() - cu_start); |
1094 w->WriteULEB128(3); | 1090 w->WriteULEB128(3); |
1095 w->Write<uint8_t>(kPointerSize); | 1091 w->Write<uint8_t>(kPointerSize); |
1096 w->WriteString("v8value"); | 1092 w->WriteString("v8value"); |
1097 | 1093 |
1098 if (desc_->IsInfoAvailable()) { | 1094 if (desc_->has_scope_info()) { |
1099 Scope* scope = desc_->info()->scope(); | 1095 ScopeInfo* scope = desc_->scope_info(); |
1100 w->WriteULEB128(2); | 1096 w->WriteULEB128(2); |
1101 w->WriteString(desc_->name()); | 1097 w->WriteString(desc_->name()); |
1102 w->Write<intptr_t>(desc_->CodeStart()); | 1098 w->Write<intptr_t>(desc_->CodeStart()); |
1103 w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); | 1099 w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); |
1104 Writer::Slot<uint32_t> fb_block_size = w->CreateSlotHere<uint32_t>(); | 1100 Writer::Slot<uint32_t> fb_block_size = w->CreateSlotHere<uint32_t>(); |
1105 uintptr_t fb_block_start = w->position(); | 1101 uintptr_t fb_block_start = w->position(); |
1106 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 | 1102 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 |
1107 w->Write<uint8_t>(DW_OP_reg5); // The frame pointer's here on ia32 | 1103 w->Write<uint8_t>(DW_OP_reg5); // The frame pointer's here on ia32 |
1108 #elif V8_TARGET_ARCH_X64 | 1104 #elif V8_TARGET_ARCH_X64 |
1109 w->Write<uint8_t>(DW_OP_reg6); // and here on x64. | 1105 w->Write<uint8_t>(DW_OP_reg6); // and here on x64. |
1110 #elif V8_TARGET_ARCH_ARM | 1106 #elif V8_TARGET_ARCH_ARM |
1111 UNIMPLEMENTED(); | 1107 UNIMPLEMENTED(); |
1112 #elif V8_TARGET_ARCH_MIPS | 1108 #elif V8_TARGET_ARCH_MIPS |
1113 UNIMPLEMENTED(); | 1109 UNIMPLEMENTED(); |
1114 #elif V8_TARGET_ARCH_MIPS64 | 1110 #elif V8_TARGET_ARCH_MIPS64 |
1115 UNIMPLEMENTED(); | 1111 UNIMPLEMENTED(); |
1116 #else | 1112 #else |
1117 #error Unsupported target architecture. | 1113 #error Unsupported target architecture. |
1118 #endif | 1114 #endif |
1119 fb_block_size.set(static_cast<uint32_t>(w->position() - fb_block_start)); | 1115 fb_block_size.set(static_cast<uint32_t>(w->position() - fb_block_start)); |
1120 | 1116 |
1121 int params = scope->num_parameters(); | 1117 int params = scope->ParameterCount(); |
1122 int slots = scope->num_stack_slots(); | 1118 int slots = scope->StackLocalCount(); |
1123 int context_slots = scope->ContextLocalCount(); | 1119 int context_slots = scope->ContextLocalCount(); |
1124 // The real slot ID is internal_slots + context_slot_id. | 1120 // The real slot ID is internal_slots + context_slot_id. |
1125 int internal_slots = Context::MIN_CONTEXT_SLOTS; | 1121 int internal_slots = Context::MIN_CONTEXT_SLOTS; |
1126 int locals = scope->StackLocalCount(); | 1122 int locals = scope->StackLocalCount(); |
1127 int current_abbreviation = 4; | 1123 int current_abbreviation = 4; |
1128 | 1124 |
1129 for (int param = 0; param < params; ++param) { | 1125 for (int param = 0; param < params; ++param) { |
1130 w->WriteULEB128(current_abbreviation++); | 1126 w->WriteULEB128(current_abbreviation++); |
1131 w->WriteString( | 1127 w->WriteString( |
1132 scope->parameter(param)->name()->ToCString(DISALLOW_NULLS).get()); | 1128 scope->ParameterName(param)->ToCString(DISALLOW_NULLS).get()); |
1133 w->Write<uint32_t>(ty_offset); | 1129 w->Write<uint32_t>(ty_offset); |
1134 Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); | 1130 Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); |
1135 uintptr_t block_start = w->position(); | 1131 uintptr_t block_start = w->position(); |
1136 w->Write<uint8_t>(DW_OP_fbreg); | 1132 w->Write<uint8_t>(DW_OP_fbreg); |
1137 w->WriteSLEB128( | 1133 w->WriteSLEB128( |
1138 JavaScriptFrameConstants::kLastParameterOffset + | 1134 JavaScriptFrameConstants::kLastParameterOffset + |
1139 kPointerSize * (params - param - 1)); | 1135 kPointerSize * (params - param - 1)); |
1140 block_size.set(static_cast<uint32_t>(w->position() - block_start)); | 1136 block_size.set(static_cast<uint32_t>(w->position() - block_start)); |
1141 } | 1137 } |
1142 | 1138 |
(...skipping 24 matching lines...) Expand all Loading... |
1167 | 1163 |
1168 for (int context_slot = 0; | 1164 for (int context_slot = 0; |
1169 context_slot < context_slots; | 1165 context_slot < context_slots; |
1170 ++context_slot) { | 1166 ++context_slot) { |
1171 w->WriteULEB128(current_abbreviation++); | 1167 w->WriteULEB128(current_abbreviation++); |
1172 builder.Reset(); | 1168 builder.Reset(); |
1173 builder.AddFormatted("context_slot%d", context_slot + internal_slots); | 1169 builder.AddFormatted("context_slot%d", context_slot + internal_slots); |
1174 w->WriteString(builder.Finalize()); | 1170 w->WriteString(builder.Finalize()); |
1175 } | 1171 } |
1176 | 1172 |
1177 ZoneList<Variable*> stack_locals(locals, scope->zone()); | |
1178 ZoneList<Variable*> context_locals(context_slots, scope->zone()); | |
1179 scope->CollectStackAndContextLocals(&stack_locals, &context_locals); | |
1180 for (int local = 0; local < locals; ++local) { | 1173 for (int local = 0; local < locals; ++local) { |
1181 w->WriteULEB128(current_abbreviation++); | 1174 w->WriteULEB128(current_abbreviation++); |
1182 w->WriteString( | 1175 w->WriteString( |
1183 stack_locals[local]->name()->ToCString(DISALLOW_NULLS).get()); | 1176 scope->StackLocalName(local)->ToCString(DISALLOW_NULLS).get()); |
1184 w->Write<uint32_t>(ty_offset); | 1177 w->Write<uint32_t>(ty_offset); |
1185 Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); | 1178 Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); |
1186 uintptr_t block_start = w->position(); | 1179 uintptr_t block_start = w->position(); |
1187 w->Write<uint8_t>(DW_OP_fbreg); | 1180 w->Write<uint8_t>(DW_OP_fbreg); |
1188 w->WriteSLEB128( | 1181 w->WriteSLEB128( |
1189 JavaScriptFrameConstants::kLocal0Offset - | 1182 JavaScriptFrameConstants::kLocal0Offset - |
1190 kPointerSize * local); | 1183 kPointerSize * local); |
1191 block_size.set(static_cast<uint32_t>(w->position() - block_start)); | 1184 block_size.set(static_cast<uint32_t>(w->position() - block_start)); |
1192 } | 1185 } |
1193 | 1186 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1295 w->WriteULEB128(DW_FORM_REF4); | 1288 w->WriteULEB128(DW_FORM_REF4); |
1296 w->WriteULEB128(DW_AT_LOCATION); | 1289 w->WriteULEB128(DW_AT_LOCATION); |
1297 w->WriteULEB128(DW_FORM_BLOCK4); | 1290 w->WriteULEB128(DW_FORM_BLOCK4); |
1298 } | 1291 } |
1299 w->WriteULEB128(0); | 1292 w->WriteULEB128(0); |
1300 w->WriteULEB128(0); | 1293 w->WriteULEB128(0); |
1301 } | 1294 } |
1302 | 1295 |
1303 bool WriteBodyInternal(Writer* w) { | 1296 bool WriteBodyInternal(Writer* w) { |
1304 int current_abbreviation = 1; | 1297 int current_abbreviation = 1; |
1305 bool extra_info = desc_->IsInfoAvailable(); | 1298 bool extra_info = desc_->has_scope_info(); |
1306 DCHECK(desc_->IsLineInfoAvailable()); | 1299 DCHECK(desc_->IsLineInfoAvailable()); |
1307 w->WriteULEB128(current_abbreviation++); | 1300 w->WriteULEB128(current_abbreviation++); |
1308 w->WriteULEB128(DW_TAG_COMPILE_UNIT); | 1301 w->WriteULEB128(DW_TAG_COMPILE_UNIT); |
1309 w->Write<uint8_t>(extra_info ? DW_CHILDREN_YES : DW_CHILDREN_NO); | 1302 w->Write<uint8_t>(extra_info ? DW_CHILDREN_YES : DW_CHILDREN_NO); |
1310 w->WriteULEB128(DW_AT_NAME); | 1303 w->WriteULEB128(DW_AT_NAME); |
1311 w->WriteULEB128(DW_FORM_STRING); | 1304 w->WriteULEB128(DW_FORM_STRING); |
1312 w->WriteULEB128(DW_AT_LOW_PC); | 1305 w->WriteULEB128(DW_AT_LOW_PC); |
1313 w->WriteULEB128(DW_FORM_ADDR); | 1306 w->WriteULEB128(DW_FORM_ADDR); |
1314 w->WriteULEB128(DW_AT_HIGH_PC); | 1307 w->WriteULEB128(DW_AT_HIGH_PC); |
1315 w->WriteULEB128(DW_FORM_ADDR); | 1308 w->WriteULEB128(DW_FORM_ADDR); |
1316 w->WriteULEB128(DW_AT_STMT_LIST); | 1309 w->WriteULEB128(DW_AT_STMT_LIST); |
1317 w->WriteULEB128(DW_FORM_DATA4); | 1310 w->WriteULEB128(DW_FORM_DATA4); |
1318 w->WriteULEB128(0); | 1311 w->WriteULEB128(0); |
1319 w->WriteULEB128(0); | 1312 w->WriteULEB128(0); |
1320 | 1313 |
1321 if (extra_info) { | 1314 if (extra_info) { |
1322 Scope* scope = desc_->info()->scope(); | 1315 ScopeInfo* scope = desc_->scope_info(); |
1323 int params = scope->num_parameters(); | 1316 int params = scope->ParameterCount(); |
1324 int slots = scope->num_stack_slots(); | 1317 int slots = scope->StackLocalCount(); |
1325 int context_slots = scope->ContextLocalCount(); | 1318 int context_slots = scope->ContextLocalCount(); |
1326 // The real slot ID is internal_slots + context_slot_id. | 1319 // The real slot ID is internal_slots + context_slot_id. |
1327 int internal_slots = Context::MIN_CONTEXT_SLOTS; | 1320 int internal_slots = Context::MIN_CONTEXT_SLOTS; |
1328 int locals = scope->StackLocalCount(); | 1321 int locals = scope->StackLocalCount(); |
1329 // Total children is params + slots + context_slots + internal_slots + | 1322 // Total children is params + slots + context_slots + internal_slots + |
1330 // locals + 2 (__function and __context). | 1323 // locals + 2 (__function and __context). |
1331 | 1324 |
1332 // The extra duplication below seems to be necessary to keep | 1325 // The extra duplication below seems to be necessary to keep |
1333 // gdb from getting upset on OSX. | 1326 // gdb from getting upset on OSX. |
1334 w->WriteULEB128(current_abbreviation++); // Abbreviation code. | 1327 w->WriteULEB128(current_abbreviation++); // Abbreviation code. |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1861 | 1854 |
1862 return entry; | 1855 return entry; |
1863 } | 1856 } |
1864 | 1857 |
1865 | 1858 |
1866 static void DestroyCodeEntry(JITCodeEntry* entry) { | 1859 static void DestroyCodeEntry(JITCodeEntry* entry) { |
1867 free(entry); | 1860 free(entry); |
1868 } | 1861 } |
1869 | 1862 |
1870 | 1863 |
1871 static void RegisterCodeEntry(JITCodeEntry* entry, | 1864 static void RegisterCodeEntry(JITCodeEntry* entry) { |
1872 bool dump_if_enabled, | |
1873 const char* name_hint) { | |
1874 #if defined(DEBUG) && !V8_OS_WIN | |
1875 static int file_num = 0; | |
1876 if (FLAG_gdbjit_dump && dump_if_enabled) { | |
1877 static const int kMaxFileNameSize = 64; | |
1878 static const char* kElfFilePrefix = "/tmp/elfdump"; | |
1879 static const char* kObjFileExt = ".o"; | |
1880 char file_name[64]; | |
1881 | |
1882 SNPrintF(Vector<char>(file_name, kMaxFileNameSize), | |
1883 "%s%s%d%s", | |
1884 kElfFilePrefix, | |
1885 (name_hint != NULL) ? name_hint : "", | |
1886 file_num++, | |
1887 kObjFileExt); | |
1888 WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_); | |
1889 } | |
1890 #endif | |
1891 | |
1892 entry->next_ = __jit_debug_descriptor.first_entry_; | 1865 entry->next_ = __jit_debug_descriptor.first_entry_; |
1893 if (entry->next_ != NULL) entry->next_->prev_ = entry; | 1866 if (entry->next_ != NULL) entry->next_->prev_ = entry; |
1894 __jit_debug_descriptor.first_entry_ = | 1867 __jit_debug_descriptor.first_entry_ = |
1895 __jit_debug_descriptor.relevant_entry_ = entry; | 1868 __jit_debug_descriptor.relevant_entry_ = entry; |
1896 | 1869 |
1897 __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN; | 1870 __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN; |
1898 __jit_debug_register_code(); | 1871 __jit_debug_register_code(); |
1899 } | 1872 } |
1900 | 1873 |
1901 | 1874 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1948 | 1921 |
1949 CreateDWARFSections(desc, &zone, &elf); | 1922 CreateDWARFSections(desc, &zone, &elf); |
1950 | 1923 |
1951 elf.Write(&w); | 1924 elf.Write(&w); |
1952 #endif | 1925 #endif |
1953 | 1926 |
1954 return CreateCodeEntry(w.buffer(), w.position()); | 1927 return CreateCodeEntry(w.buffer(), w.position()); |
1955 } | 1928 } |
1956 | 1929 |
1957 | 1930 |
1958 static bool SameCodeObjects(void* key1, void* key2) { | 1931 struct AddressRange { |
1959 return key1 == key2; | 1932 Address start; |
| 1933 Address end; |
| 1934 }; |
| 1935 |
| 1936 class JITCodeEntry; |
| 1937 |
| 1938 struct SplayTreeConfig { |
| 1939 typedef AddressRange Key; |
| 1940 typedef JITCodeEntry* Value; |
| 1941 static const AddressRange kNoKey; |
| 1942 static Value NoValue() { return NULL; } |
| 1943 static int Compare(const AddressRange& a, const AddressRange& b) { |
| 1944 // ptrdiff_t probably doesn't fit in an int. |
| 1945 if (a.start < b.start) return -1; |
| 1946 if (a.start == b.start) return 0; |
| 1947 return 1; |
| 1948 } |
| 1949 }; |
| 1950 |
| 1951 const AddressRange SplayTreeConfig::kNoKey = {0, 0}; |
| 1952 typedef SplayTree<SplayTreeConfig> CodeMap; |
| 1953 |
| 1954 static CodeMap* GetCodeMap() { |
| 1955 static CodeMap* code_map = NULL; |
| 1956 if (code_map == NULL) code_map = new CodeMap(); |
| 1957 return code_map; |
1960 } | 1958 } |
1961 | 1959 |
1962 | 1960 |
1963 static HashMap* GetEntries() { | 1961 static uint32_t HashCodeAddress(Address addr) { |
1964 static HashMap* entries = NULL; | 1962 static const intptr_t kGoldenRatio = 2654435761; |
1965 if (entries == NULL) { | 1963 uintptr_t offset = OffsetFrom(addr); |
1966 entries = new HashMap(&SameCodeObjects); | 1964 return static_cast<uint32_t>((offset >> kCodeAlignmentBits) * kGoldenRatio); |
1967 } | |
1968 return entries; | |
1969 } | 1965 } |
1970 | 1966 |
1971 | 1967 |
1972 static uint32_t HashForCodeObject(Code* code) { | 1968 static HashMap* GetLineMap() { |
1973 static const uintptr_t kGoldenRatio = 2654435761u; | 1969 static HashMap* line_map = NULL; |
1974 uintptr_t hash = reinterpret_cast<uintptr_t>(code->address()); | 1970 if (line_map == NULL) line_map = new HashMap(&HashMap::PointersMatch); |
1975 return static_cast<uint32_t>((hash >> kCodeAlignmentBits) * kGoldenRatio); | 1971 return line_map; |
1976 } | 1972 } |
1977 | 1973 |
1978 | 1974 |
1979 static const intptr_t kLineInfoTag = 0x1; | 1975 static void PutLineInfo(Address addr, LineInfo* info) { |
1980 | 1976 HashMap* line_map = GetLineMap(); |
1981 | 1977 HashMap::Entry* e = line_map->Lookup(addr, HashCodeAddress(addr), true); |
1982 static bool IsLineInfoTagged(void* ptr) { | 1978 if (e->value != NULL) delete static_cast<LineInfo*>(e->value); |
1983 return 0 != (reinterpret_cast<intptr_t>(ptr) & kLineInfoTag); | 1979 e->value = info; |
1984 } | 1980 } |
1985 | 1981 |
1986 | 1982 |
1987 static void* TagLineInfo(LineInfo* ptr) { | 1983 static LineInfo* GetLineInfo(Address addr) { |
1988 return reinterpret_cast<void*>( | 1984 void* value = GetLineMap()->Remove(addr, HashCodeAddress(addr)); |
1989 reinterpret_cast<intptr_t>(ptr) | kLineInfoTag); | 1985 return static_cast<LineInfo*>(value); |
1990 } | |
1991 | |
1992 | |
1993 static LineInfo* UntagLineInfo(void* ptr) { | |
1994 return reinterpret_cast<LineInfo*>(reinterpret_cast<intptr_t>(ptr) & | |
1995 ~kLineInfoTag); | |
1996 } | |
1997 | |
1998 | |
1999 void GDBJITInterface::AddCode(Handle<Name> name, | |
2000 Handle<Script> script, | |
2001 Handle<Code> code, | |
2002 CompilationInfo* info) { | |
2003 if (!FLAG_gdbjit) return; | |
2004 | |
2005 Script::InitLineEnds(script); | |
2006 | |
2007 if (!name.is_null() && name->IsString()) { | |
2008 SmartArrayPointer<char> name_cstring = | |
2009 Handle<String>::cast(name)->ToCString(DISALLOW_NULLS); | |
2010 AddCode(name_cstring.get(), *code, GDBJITInterface::FUNCTION, *script, | |
2011 info); | |
2012 } else { | |
2013 AddCode("", *code, GDBJITInterface::FUNCTION, *script, info); | |
2014 } | |
2015 } | 1986 } |
2016 | 1987 |
2017 | 1988 |
2018 static void AddUnwindInfo(CodeDescription* desc) { | 1989 static void AddUnwindInfo(CodeDescription* desc) { |
2019 #if V8_TARGET_ARCH_X64 | 1990 #if V8_TARGET_ARCH_X64 |
2020 if (desc->tag() == GDBJITInterface::FUNCTION) { | 1991 if (desc->is_function()) { |
2021 // To avoid propagating unwinding information through | 1992 // To avoid propagating unwinding information through |
2022 // compilation pipeline we use an approximation. | 1993 // compilation pipeline we use an approximation. |
2023 // For most use cases this should not affect usability. | 1994 // For most use cases this should not affect usability. |
2024 static const int kFramePointerPushOffset = 1; | 1995 static const int kFramePointerPushOffset = 1; |
2025 static const int kFramePointerSetOffset = 4; | 1996 static const int kFramePointerSetOffset = 4; |
2026 static const int kFramePointerPopOffset = -3; | 1997 static const int kFramePointerPopOffset = -3; |
2027 | 1998 |
2028 uintptr_t frame_pointer_push_address = | 1999 uintptr_t frame_pointer_push_address = |
2029 desc->CodeStart() + kFramePointerPushOffset; | 2000 desc->CodeStart() + kFramePointerPushOffset; |
2030 | 2001 |
(...skipping 17 matching lines...) Expand all Loading... |
2048 desc->SetStackStateStartAddress(CodeDescription::POST_RBP_POP, | 2019 desc->SetStackStateStartAddress(CodeDescription::POST_RBP_POP, |
2049 desc->CodeEnd()); | 2020 desc->CodeEnd()); |
2050 } | 2021 } |
2051 #endif // V8_TARGET_ARCH_X64 | 2022 #endif // V8_TARGET_ARCH_X64 |
2052 } | 2023 } |
2053 | 2024 |
2054 | 2025 |
2055 static base::LazyMutex mutex = LAZY_MUTEX_INITIALIZER; | 2026 static base::LazyMutex mutex = LAZY_MUTEX_INITIALIZER; |
2056 | 2027 |
2057 | 2028 |
2058 void GDBJITInterface::AddCode(const char* name, | 2029 // Remove entries from the splay tree that intersect the given address range, |
2059 Code* code, | 2030 // and deregister them from GDB. |
2060 GDBJITInterface::CodeTag tag, | 2031 static void RemoveJITCodeEntries(CodeMap* map, const AddressRange& range) { |
2061 Script* script, | 2032 DCHECK(range.start < range.end); |
2062 CompilationInfo* info) { | 2033 CodeMap::Locator cur; |
2063 base::LockGuard<base::Mutex> lock_guard(mutex.Pointer()); | 2034 if (map->FindGreatestLessThan(range, &cur) || map->FindLeast(&cur)) { |
| 2035 // Skip entries that are entirely less than the range of interest. |
| 2036 while (cur.key().end <= range.start) { |
| 2037 // CodeMap::FindLeastGreaterThan succeeds for entries whose key is greater |
| 2038 // than _or equal to_ the given key, so we have to advance our key to get |
| 2039 // the next one. |
| 2040 AddressRange new_key; |
| 2041 new_key.start = cur.key().end; |
| 2042 new_key.end = 0; |
| 2043 if (!map->FindLeastGreaterThan(new_key, &cur)) return; |
| 2044 } |
| 2045 // Evict intersecting ranges. |
| 2046 while (cur.key().start < range.end) { |
| 2047 AddressRange old_range = cur.key(); |
| 2048 JITCodeEntry* old_entry = cur.value(); |
| 2049 |
| 2050 UnregisterCodeEntry(old_entry); |
| 2051 DestroyCodeEntry(old_entry); |
| 2052 |
| 2053 CHECK(map->Remove(old_range)); |
| 2054 if (!map->FindLeastGreaterThan(old_range, &cur)) return; |
| 2055 } |
| 2056 } |
| 2057 } |
| 2058 |
| 2059 |
| 2060 // Insert the entry into the splay tree and register it with GDB. |
| 2061 static void AddJITCodeEntry(CodeMap* map, const AddressRange& range, |
| 2062 JITCodeEntry* entry, bool dump_if_enabled, |
| 2063 const char* name_hint) { |
| 2064 #if defined(DEBUG) && !V8_OS_WIN |
| 2065 static int file_num = 0; |
| 2066 if (FLAG_gdbjit_dump && dump_if_enabled) { |
| 2067 static const int kMaxFileNameSize = 64; |
| 2068 char file_name[64]; |
| 2069 |
| 2070 SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "/tmp/elfdump%s%d.o", |
| 2071 (name_hint != NULL) ? name_hint : "", file_num++); |
| 2072 WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_); |
| 2073 } |
| 2074 #endif |
| 2075 |
| 2076 CodeMap::Locator cur; |
| 2077 CHECK(map->Insert(range, &cur)); |
| 2078 cur.set_value(entry); |
| 2079 |
| 2080 RegisterCodeEntry(entry); |
| 2081 } |
| 2082 |
| 2083 |
| 2084 static void AddCode(const char* name, Code* code, SharedFunctionInfo* shared, |
| 2085 LineInfo* lineinfo) { |
2064 DisallowHeapAllocation no_gc; | 2086 DisallowHeapAllocation no_gc; |
2065 | 2087 |
2066 HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true); | 2088 CodeMap* code_map = GetCodeMap(); |
2067 if (e->value != NULL && !IsLineInfoTagged(e->value)) return; | 2089 AddressRange range; |
| 2090 range.start = code->address(); |
| 2091 range.end = code->address() + code->CodeSize(); |
| 2092 RemoveJITCodeEntries(code_map, range); |
2068 | 2093 |
2069 LineInfo* lineinfo = UntagLineInfo(e->value); | 2094 CodeDescription code_desc(name, code, shared, lineinfo); |
2070 CodeDescription code_desc(name, | |
2071 code, | |
2072 script != NULL ? Handle<Script>(script) | |
2073 : Handle<Script>(), | |
2074 lineinfo, | |
2075 tag, | |
2076 info); | |
2077 | 2095 |
2078 if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { | 2096 if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { |
2079 delete lineinfo; | 2097 delete lineinfo; |
2080 GetEntries()->Remove(code, HashForCodeObject(code)); | |
2081 return; | 2098 return; |
2082 } | 2099 } |
2083 | 2100 |
2084 AddUnwindInfo(&code_desc); | 2101 AddUnwindInfo(&code_desc); |
2085 Isolate* isolate = code->GetIsolate(); | 2102 Isolate* isolate = code->GetIsolate(); |
2086 JITCodeEntry* entry = CreateELFObject(&code_desc, isolate); | 2103 JITCodeEntry* entry = CreateELFObject(&code_desc, isolate); |
2087 DCHECK(!IsLineInfoTagged(entry)); | |
2088 | 2104 |
2089 delete lineinfo; | 2105 delete lineinfo; |
2090 e->value = entry; | |
2091 | 2106 |
2092 const char* name_hint = NULL; | 2107 const char* name_hint = NULL; |
2093 bool should_dump = false; | 2108 bool should_dump = false; |
2094 if (FLAG_gdbjit_dump) { | 2109 if (FLAG_gdbjit_dump) { |
2095 if (strlen(FLAG_gdbjit_dump_filter) == 0) { | 2110 if (strlen(FLAG_gdbjit_dump_filter) == 0) { |
2096 name_hint = name; | 2111 name_hint = name; |
2097 should_dump = true; | 2112 should_dump = true; |
2098 } else if (name != NULL) { | 2113 } else if (name != NULL) { |
2099 name_hint = strstr(name, FLAG_gdbjit_dump_filter); | 2114 name_hint = strstr(name, FLAG_gdbjit_dump_filter); |
2100 should_dump = (name_hint != NULL); | 2115 should_dump = (name_hint != NULL); |
2101 } | 2116 } |
2102 } | 2117 } |
2103 RegisterCodeEntry(entry, should_dump, name_hint); | 2118 AddJITCodeEntry(code_map, range, entry, should_dump, name_hint); |
2104 } | 2119 } |
2105 | 2120 |
2106 | 2121 |
2107 void GDBJITInterface::RemoveCode(Code* code) { | 2122 void EventHandler(const v8::JitCodeEvent* event) { |
2108 if (!FLAG_gdbjit) return; | 2123 if (!FLAG_gdbjit) return; |
2109 | |
2110 base::LockGuard<base::Mutex> lock_guard(mutex.Pointer()); | 2124 base::LockGuard<base::Mutex> lock_guard(mutex.Pointer()); |
2111 HashMap::Entry* e = GetEntries()->Lookup(code, | |
2112 HashForCodeObject(code), | |
2113 false); | |
2114 if (e == NULL) return; | |
2115 | |
2116 if (IsLineInfoTagged(e->value)) { | |
2117 delete UntagLineInfo(e->value); | |
2118 } else { | |
2119 JITCodeEntry* entry = static_cast<JITCodeEntry*>(e->value); | |
2120 UnregisterCodeEntry(entry); | |
2121 DestroyCodeEntry(entry); | |
2122 } | |
2123 e->value = NULL; | |
2124 GetEntries()->Remove(code, HashForCodeObject(code)); | |
2125 } | |
2126 | |
2127 | |
2128 void GDBJITInterface::RemoveCodeRange(Address start, Address end) { | |
2129 HashMap* entries = GetEntries(); | |
2130 Zone zone; | |
2131 ZoneList<Code*> dead_codes(1, &zone); | |
2132 | |
2133 for (HashMap::Entry* e = entries->Start(); e != NULL; e = entries->Next(e)) { | |
2134 Code* code = reinterpret_cast<Code*>(e->key); | |
2135 if (code->address() >= start && code->address() < end) { | |
2136 dead_codes.Add(code, &zone); | |
2137 } | |
2138 } | |
2139 | |
2140 for (int i = 0; i < dead_codes.length(); i++) { | |
2141 RemoveCode(dead_codes.at(i)); | |
2142 } | |
2143 } | |
2144 | |
2145 | |
2146 static void RegisterDetailedLineInfo(Code* code, LineInfo* line_info) { | |
2147 base::LockGuard<base::Mutex> lock_guard(mutex.Pointer()); | |
2148 DCHECK(!IsLineInfoTagged(line_info)); | |
2149 HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true); | |
2150 DCHECK(e->value == NULL); | |
2151 e->value = TagLineInfo(line_info); | |
2152 } | |
2153 | |
2154 | |
2155 void GDBJITInterface::EventHandler(const v8::JitCodeEvent* event) { | |
2156 if (!FLAG_gdbjit) return; | |
2157 switch (event->type) { | 2125 switch (event->type) { |
2158 case v8::JitCodeEvent::CODE_ADDED: { | 2126 case v8::JitCodeEvent::CODE_ADDED: { |
2159 Code* code = Code::GetCodeFromTargetAddress( | 2127 Address addr = reinterpret_cast<Address>(event->code_start); |
2160 reinterpret_cast<Address>(event->code_start)); | 2128 Code* code = Code::GetCodeFromTargetAddress(addr); |
2161 if (code->kind() == Code::OPTIMIZED_FUNCTION || | 2129 LineInfo* lineinfo = GetLineInfo(addr); |
2162 code->kind() == Code::FUNCTION) { | |
2163 break; | |
2164 } | |
2165 EmbeddedVector<char, 256> buffer; | 2130 EmbeddedVector<char, 256> buffer; |
2166 StringBuilder builder(buffer.start(), buffer.length()); | 2131 StringBuilder builder(buffer.start(), buffer.length()); |
2167 builder.AddSubstring(event->name.str, static_cast<int>(event->name.len)); | 2132 builder.AddSubstring(event->name.str, static_cast<int>(event->name.len)); |
2168 AddCode(builder.Finalize(), code, NON_FUNCTION, NULL, NULL); | 2133 // It's called UnboundScript in the API but it's a SharedFunctionInfo. |
| 2134 SharedFunctionInfo* shared = |
| 2135 event->script.IsEmpty() ? NULL : *Utils::OpenHandle(*event->script); |
| 2136 AddCode(builder.Finalize(), code, shared, lineinfo); |
2169 break; | 2137 break; |
2170 } | 2138 } |
2171 case v8::JitCodeEvent::CODE_MOVED: | 2139 case v8::JitCodeEvent::CODE_MOVED: |
| 2140 // Enabling the GDB JIT interface should disable code compaction. |
| 2141 UNREACHABLE(); |
2172 break; | 2142 break; |
2173 case v8::JitCodeEvent::CODE_REMOVED: { | 2143 case v8::JitCodeEvent::CODE_REMOVED: |
2174 Code* code = Code::GetCodeFromTargetAddress( | 2144 // Do nothing. Instead, adding code causes eviction of any entry whose |
2175 reinterpret_cast<Address>(event->code_start)); | 2145 // address range intersects the address range of the added code. |
2176 RemoveCode(code); | |
2177 break; | 2146 break; |
2178 } | |
2179 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { | 2147 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { |
2180 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); | 2148 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); |
2181 line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset), | 2149 line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset), |
2182 static_cast<int>(event->line_info.pos), | 2150 static_cast<int>(event->line_info.pos), |
2183 event->line_info.position_type == | 2151 event->line_info.position_type == |
2184 v8::JitCodeEvent::STATEMENT_POSITION); | 2152 v8::JitCodeEvent::STATEMENT_POSITION); |
2185 break; | 2153 break; |
2186 } | 2154 } |
2187 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { | 2155 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { |
2188 v8::JitCodeEvent* mutable_event = const_cast<v8::JitCodeEvent*>(event); | 2156 v8::JitCodeEvent* mutable_event = const_cast<v8::JitCodeEvent*>(event); |
2189 mutable_event->user_data = new LineInfo(); | 2157 mutable_event->user_data = new LineInfo(); |
2190 break; | 2158 break; |
2191 } | 2159 } |
2192 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { | 2160 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { |
2193 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); | 2161 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); |
2194 Code* code = Code::GetCodeFromTargetAddress( | 2162 PutLineInfo(reinterpret_cast<Address>(event->code_start), line_info); |
2195 reinterpret_cast<Address>(event->code_start)); | |
2196 RegisterDetailedLineInfo(code, line_info); | |
2197 break; | 2163 break; |
2198 } | 2164 } |
2199 } | 2165 } |
2200 } | 2166 } |
2201 | |
2202 | |
2203 } } // namespace v8::internal | |
2204 #endif | 2167 #endif |
| 2168 } // namespace GDBJITInterface |
| 2169 } // namespace internal |
| 2170 } // namespace v8 |
OLD | NEW |