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