| 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 struct SplayTreeConfig { |
| 1937 typedef AddressRange Key; |
| 1938 typedef JITCodeEntry* Value; |
| 1939 static const AddressRange kNoKey; |
| 1940 static Value NoValue() { return NULL; } |
| 1941 static int Compare(const AddressRange& a, const AddressRange& b) { |
| 1942 // ptrdiff_t probably doesn't fit in an int. |
| 1943 if (a.start < b.start) return -1; |
| 1944 if (a.start == b.start) return 0; |
| 1945 return 1; |
| 1946 } |
| 1947 }; |
| 1948 |
| 1949 const AddressRange SplayTreeConfig::kNoKey = {0, 0}; |
| 1950 typedef SplayTree<SplayTreeConfig> CodeMap; |
| 1951 |
| 1952 static CodeMap* GetCodeMap() { |
| 1953 static CodeMap* code_map = NULL; |
| 1954 if (code_map == NULL) code_map = new CodeMap(); |
| 1955 return code_map; |
| 1960 } | 1956 } |
| 1961 | 1957 |
| 1962 | 1958 |
| 1963 static HashMap* GetEntries() { | 1959 static uint32_t HashCodeAddress(Address addr) { |
| 1964 static HashMap* entries = NULL; | 1960 static const uintptr_t kGoldenRatio = 2654435761u; |
| 1965 if (entries == NULL) { | 1961 uintptr_t offset = OffsetFrom(addr); |
| 1966 entries = new HashMap(&SameCodeObjects); | 1962 return static_cast<uint32_t>((offset >> kCodeAlignmentBits) * kGoldenRatio); |
| 1967 } | |
| 1968 return entries; | |
| 1969 } | 1963 } |
| 1970 | 1964 |
| 1971 | 1965 |
| 1972 static uint32_t HashForCodeObject(Code* code) { | 1966 static HashMap* GetLineMap() { |
| 1973 static const uintptr_t kGoldenRatio = 2654435761u; | 1967 static HashMap* line_map = NULL; |
| 1974 uintptr_t hash = reinterpret_cast<uintptr_t>(code->address()); | 1968 if (line_map == NULL) line_map = new HashMap(&HashMap::PointersMatch); |
| 1975 return static_cast<uint32_t>((hash >> kCodeAlignmentBits) * kGoldenRatio); | 1969 return line_map; |
| 1976 } | 1970 } |
| 1977 | 1971 |
| 1978 | 1972 |
| 1979 static const intptr_t kLineInfoTag = 0x1; | 1973 static void PutLineInfo(Address addr, LineInfo* info) { |
| 1980 | 1974 HashMap* line_map = GetLineMap(); |
| 1981 | 1975 HashMap::Entry* e = line_map->Lookup(addr, HashCodeAddress(addr), true); |
| 1982 static bool IsLineInfoTagged(void* ptr) { | 1976 if (e->value != NULL) delete static_cast<LineInfo*>(e->value); |
| 1983 return 0 != (reinterpret_cast<intptr_t>(ptr) & kLineInfoTag); | 1977 e->value = info; |
| 1984 } | 1978 } |
| 1985 | 1979 |
| 1986 | 1980 |
| 1987 static void* TagLineInfo(LineInfo* ptr) { | 1981 static LineInfo* GetLineInfo(Address addr) { |
| 1988 return reinterpret_cast<void*>( | 1982 void* value = GetLineMap()->Remove(addr, HashCodeAddress(addr)); |
| 1989 reinterpret_cast<intptr_t>(ptr) | kLineInfoTag); | 1983 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 } | 1984 } |
| 2016 | 1985 |
| 2017 | 1986 |
| 2018 static void AddUnwindInfo(CodeDescription* desc) { | 1987 static void AddUnwindInfo(CodeDescription* desc) { |
| 2019 #if V8_TARGET_ARCH_X64 | 1988 #if V8_TARGET_ARCH_X64 |
| 2020 if (desc->tag() == GDBJITInterface::FUNCTION) { | 1989 if (desc->is_function()) { |
| 2021 // To avoid propagating unwinding information through | 1990 // To avoid propagating unwinding information through |
| 2022 // compilation pipeline we use an approximation. | 1991 // compilation pipeline we use an approximation. |
| 2023 // For most use cases this should not affect usability. | 1992 // For most use cases this should not affect usability. |
| 2024 static const int kFramePointerPushOffset = 1; | 1993 static const int kFramePointerPushOffset = 1; |
| 2025 static const int kFramePointerSetOffset = 4; | 1994 static const int kFramePointerSetOffset = 4; |
| 2026 static const int kFramePointerPopOffset = -3; | 1995 static const int kFramePointerPopOffset = -3; |
| 2027 | 1996 |
| 2028 uintptr_t frame_pointer_push_address = | 1997 uintptr_t frame_pointer_push_address = |
| 2029 desc->CodeStart() + kFramePointerPushOffset; | 1998 desc->CodeStart() + kFramePointerPushOffset; |
| 2030 | 1999 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2048 desc->SetStackStateStartAddress(CodeDescription::POST_RBP_POP, | 2017 desc->SetStackStateStartAddress(CodeDescription::POST_RBP_POP, |
| 2049 desc->CodeEnd()); | 2018 desc->CodeEnd()); |
| 2050 } | 2019 } |
| 2051 #endif // V8_TARGET_ARCH_X64 | 2020 #endif // V8_TARGET_ARCH_X64 |
| 2052 } | 2021 } |
| 2053 | 2022 |
| 2054 | 2023 |
| 2055 static base::LazyMutex mutex = LAZY_MUTEX_INITIALIZER; | 2024 static base::LazyMutex mutex = LAZY_MUTEX_INITIALIZER; |
| 2056 | 2025 |
| 2057 | 2026 |
| 2058 void GDBJITInterface::AddCode(const char* name, | 2027 // Remove entries from the splay tree that intersect the given address range, |
| 2059 Code* code, | 2028 // and deregister them from GDB. |
| 2060 GDBJITInterface::CodeTag tag, | 2029 static void RemoveJITCodeEntries(CodeMap* map, const AddressRange& range) { |
| 2061 Script* script, | 2030 DCHECK(range.start < range.end); |
| 2062 CompilationInfo* info) { | 2031 CodeMap::Locator cur; |
| 2063 base::LockGuard<base::Mutex> lock_guard(mutex.Pointer()); | 2032 if (map->FindGreatestLessThan(range, &cur) || map->FindLeast(&cur)) { |
| 2033 // Skip entries that are entirely less than the range of interest. |
| 2034 while (cur.key().end <= range.start) { |
| 2035 // CodeMap::FindLeastGreaterThan succeeds for entries whose key is greater |
| 2036 // than _or equal to_ the given key, so we have to advance our key to get |
| 2037 // the next one. |
| 2038 AddressRange new_key; |
| 2039 new_key.start = cur.key().end; |
| 2040 new_key.end = 0; |
| 2041 if (!map->FindLeastGreaterThan(new_key, &cur)) return; |
| 2042 } |
| 2043 // Evict intersecting ranges. |
| 2044 while (cur.key().start < range.end) { |
| 2045 AddressRange old_range = cur.key(); |
| 2046 JITCodeEntry* old_entry = cur.value(); |
| 2047 |
| 2048 UnregisterCodeEntry(old_entry); |
| 2049 DestroyCodeEntry(old_entry); |
| 2050 |
| 2051 CHECK(map->Remove(old_range)); |
| 2052 if (!map->FindLeastGreaterThan(old_range, &cur)) return; |
| 2053 } |
| 2054 } |
| 2055 } |
| 2056 |
| 2057 |
| 2058 // Insert the entry into the splay tree and register it with GDB. |
| 2059 static void AddJITCodeEntry(CodeMap* map, const AddressRange& range, |
| 2060 JITCodeEntry* entry, bool dump_if_enabled, |
| 2061 const char* name_hint) { |
| 2062 #if defined(DEBUG) && !V8_OS_WIN |
| 2063 static int file_num = 0; |
| 2064 if (FLAG_gdbjit_dump && dump_if_enabled) { |
| 2065 static const int kMaxFileNameSize = 64; |
| 2066 char file_name[64]; |
| 2067 |
| 2068 SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "/tmp/elfdump%s%d.o", |
| 2069 (name_hint != NULL) ? name_hint : "", file_num++); |
| 2070 WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_); |
| 2071 } |
| 2072 #endif |
| 2073 |
| 2074 CodeMap::Locator cur; |
| 2075 CHECK(map->Insert(range, &cur)); |
| 2076 cur.set_value(entry); |
| 2077 |
| 2078 RegisterCodeEntry(entry); |
| 2079 } |
| 2080 |
| 2081 |
| 2082 static void AddCode(const char* name, Code* code, SharedFunctionInfo* shared, |
| 2083 LineInfo* lineinfo) { |
| 2064 DisallowHeapAllocation no_gc; | 2084 DisallowHeapAllocation no_gc; |
| 2065 | 2085 |
| 2066 HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true); | 2086 CodeMap* code_map = GetCodeMap(); |
| 2067 if (e->value != NULL && !IsLineInfoTagged(e->value)) return; | 2087 AddressRange range; |
| 2088 range.start = code->address(); |
| 2089 range.end = code->address() + code->CodeSize(); |
| 2090 RemoveJITCodeEntries(code_map, range); |
| 2068 | 2091 |
| 2069 LineInfo* lineinfo = UntagLineInfo(e->value); | 2092 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 | 2093 |
| 2078 if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { | 2094 if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { |
| 2079 delete lineinfo; | 2095 delete lineinfo; |
| 2080 GetEntries()->Remove(code, HashForCodeObject(code)); | |
| 2081 return; | 2096 return; |
| 2082 } | 2097 } |
| 2083 | 2098 |
| 2084 AddUnwindInfo(&code_desc); | 2099 AddUnwindInfo(&code_desc); |
| 2085 Isolate* isolate = code->GetIsolate(); | 2100 Isolate* isolate = code->GetIsolate(); |
| 2086 JITCodeEntry* entry = CreateELFObject(&code_desc, isolate); | 2101 JITCodeEntry* entry = CreateELFObject(&code_desc, isolate); |
| 2087 DCHECK(!IsLineInfoTagged(entry)); | |
| 2088 | 2102 |
| 2089 delete lineinfo; | 2103 delete lineinfo; |
| 2090 e->value = entry; | |
| 2091 | 2104 |
| 2092 const char* name_hint = NULL; | 2105 const char* name_hint = NULL; |
| 2093 bool should_dump = false; | 2106 bool should_dump = false; |
| 2094 if (FLAG_gdbjit_dump) { | 2107 if (FLAG_gdbjit_dump) { |
| 2095 if (strlen(FLAG_gdbjit_dump_filter) == 0) { | 2108 if (strlen(FLAG_gdbjit_dump_filter) == 0) { |
| 2096 name_hint = name; | 2109 name_hint = name; |
| 2097 should_dump = true; | 2110 should_dump = true; |
| 2098 } else if (name != NULL) { | 2111 } else if (name != NULL) { |
| 2099 name_hint = strstr(name, FLAG_gdbjit_dump_filter); | 2112 name_hint = strstr(name, FLAG_gdbjit_dump_filter); |
| 2100 should_dump = (name_hint != NULL); | 2113 should_dump = (name_hint != NULL); |
| 2101 } | 2114 } |
| 2102 } | 2115 } |
| 2103 RegisterCodeEntry(entry, should_dump, name_hint); | 2116 AddJITCodeEntry(code_map, range, entry, should_dump, name_hint); |
| 2104 } | 2117 } |
| 2105 | 2118 |
| 2106 | 2119 |
| 2107 void GDBJITInterface::RemoveCode(Code* code) { | 2120 void EventHandler(const v8::JitCodeEvent* event) { |
| 2108 if (!FLAG_gdbjit) return; | 2121 if (!FLAG_gdbjit) return; |
| 2109 | |
| 2110 base::LockGuard<base::Mutex> lock_guard(mutex.Pointer()); | 2122 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) { | 2123 switch (event->type) { |
| 2158 case v8::JitCodeEvent::CODE_ADDED: { | 2124 case v8::JitCodeEvent::CODE_ADDED: { |
| 2159 Code* code = Code::GetCodeFromTargetAddress( | 2125 Address addr = reinterpret_cast<Address>(event->code_start); |
| 2160 reinterpret_cast<Address>(event->code_start)); | 2126 Code* code = Code::GetCodeFromTargetAddress(addr); |
| 2161 if (code->kind() == Code::OPTIMIZED_FUNCTION || | 2127 LineInfo* lineinfo = GetLineInfo(addr); |
| 2162 code->kind() == Code::FUNCTION) { | |
| 2163 break; | |
| 2164 } | |
| 2165 EmbeddedVector<char, 256> buffer; | 2128 EmbeddedVector<char, 256> buffer; |
| 2166 StringBuilder builder(buffer.start(), buffer.length()); | 2129 StringBuilder builder(buffer.start(), buffer.length()); |
| 2167 builder.AddSubstring(event->name.str, static_cast<int>(event->name.len)); | 2130 builder.AddSubstring(event->name.str, static_cast<int>(event->name.len)); |
| 2168 AddCode(builder.Finalize(), code, NON_FUNCTION, NULL, NULL); | 2131 // It's called UnboundScript in the API but it's a SharedFunctionInfo. |
| 2132 SharedFunctionInfo* shared = |
| 2133 event->script.IsEmpty() ? NULL : *Utils::OpenHandle(*event->script); |
| 2134 AddCode(builder.Finalize(), code, shared, lineinfo); |
| 2169 break; | 2135 break; |
| 2170 } | 2136 } |
| 2171 case v8::JitCodeEvent::CODE_MOVED: | 2137 case v8::JitCodeEvent::CODE_MOVED: |
| 2138 // Enabling the GDB JIT interface should disable code compaction. |
| 2139 UNREACHABLE(); |
| 2172 break; | 2140 break; |
| 2173 case v8::JitCodeEvent::CODE_REMOVED: { | 2141 case v8::JitCodeEvent::CODE_REMOVED: |
| 2174 Code* code = Code::GetCodeFromTargetAddress( | 2142 // Do nothing. Instead, adding code causes eviction of any entry whose |
| 2175 reinterpret_cast<Address>(event->code_start)); | 2143 // address range intersects the address range of the added code. |
| 2176 RemoveCode(code); | |
| 2177 break; | 2144 break; |
| 2178 } | |
| 2179 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { | 2145 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { |
| 2180 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); | 2146 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); |
| 2181 line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset), | 2147 line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset), |
| 2182 static_cast<int>(event->line_info.pos), | 2148 static_cast<int>(event->line_info.pos), |
| 2183 event->line_info.position_type == | 2149 event->line_info.position_type == |
| 2184 v8::JitCodeEvent::STATEMENT_POSITION); | 2150 v8::JitCodeEvent::STATEMENT_POSITION); |
| 2185 break; | 2151 break; |
| 2186 } | 2152 } |
| 2187 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { | 2153 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { |
| 2188 v8::JitCodeEvent* mutable_event = const_cast<v8::JitCodeEvent*>(event); | 2154 v8::JitCodeEvent* mutable_event = const_cast<v8::JitCodeEvent*>(event); |
| 2189 mutable_event->user_data = new LineInfo(); | 2155 mutable_event->user_data = new LineInfo(); |
| 2190 break; | 2156 break; |
| 2191 } | 2157 } |
| 2192 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { | 2158 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { |
| 2193 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); | 2159 LineInfo* line_info = reinterpret_cast<LineInfo*>(event->user_data); |
| 2194 Code* code = Code::GetCodeFromTargetAddress( | 2160 PutLineInfo(reinterpret_cast<Address>(event->code_start), line_info); |
| 2195 reinterpret_cast<Address>(event->code_start)); | |
| 2196 RegisterDetailedLineInfo(code, line_info); | |
| 2197 break; | 2161 break; |
| 2198 } | 2162 } |
| 2199 } | 2163 } |
| 2200 } | 2164 } |
| 2201 | |
| 2202 | |
| 2203 } } // namespace v8::internal | |
| 2204 #endif | 2165 #endif |
| 2166 } // namespace GDBJITInterface |
| 2167 } // namespace internal |
| 2168 } // namespace v8 |
| OLD | NEW |