| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/disassembler.h" | 5 #include "vm/disassembler.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 #include "vm/deopt_instructions.h" | 8 #include "vm/deopt_instructions.h" |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 #include "vm/il_printer.h" | 10 #include "vm/il_printer.h" |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 jsarr_.AddValueNull(); // Not a reference to null. | 74 jsarr_.AddValueNull(); // Not a reference to null. |
| 75 } | 75 } |
| 76 } | 76 } |
| 77 | 77 |
| 78 | 78 |
| 79 void DisassembleToJSONStream::Print(const char* format, ...) { | 79 void DisassembleToJSONStream::Print(const char* format, ...) { |
| 80 va_list args; | 80 va_list args; |
| 81 va_start(args, format); | 81 va_start(args, format); |
| 82 intptr_t len = OS::VSNPrint(NULL, 0, format, args); | 82 intptr_t len = OS::VSNPrint(NULL, 0, format, args); |
| 83 va_end(args); | 83 va_end(args); |
| 84 char* p = reinterpret_cast<char*>(malloc(len+1)); | 84 char* p = reinterpret_cast<char*>(malloc(len + 1)); |
| 85 va_start(args, format); | 85 va_start(args, format); |
| 86 intptr_t len2 = OS::VSNPrint(p, len, format, args); | 86 intptr_t len2 = OS::VSNPrint(p, len, format, args); |
| 87 va_end(args); | 87 va_end(args); |
| 88 ASSERT(len == len2); | 88 ASSERT(len == len2); |
| 89 for (intptr_t i = 0; i < len; i++) { | 89 for (intptr_t i = 0; i < len; i++) { |
| 90 if (p[i] == '\n' || p[i] == '\r') { | 90 if (p[i] == '\n' || p[i] == '\r') { |
| 91 p[i] = ' '; | 91 p[i] = ' '; |
| 92 } | 92 } |
| 93 } | 93 } |
| 94 // Instructions are represented as four consecutive values in a JSON array. | 94 // Instructions are represented as four consecutive values in a JSON array. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 f.Print(" -> %s", name); | 139 f.Print(" -> %s", name); |
| 140 } | 140 } |
| 141 } | 141 } |
| 142 if (!first) { | 142 if (!first) { |
| 143 f.Print("]\n"); | 143 f.Print("]\n"); |
| 144 formatter->Print(str); | 144 formatter->Print(str); |
| 145 } | 145 } |
| 146 } | 146 } |
| 147 int instruction_length; | 147 int instruction_length; |
| 148 Object* object; | 148 Object* object; |
| 149 DecodeInstruction(hex_buffer, | 149 DecodeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer, |
| 150 sizeof(hex_buffer), | 150 sizeof(human_buffer), &instruction_length, code, &object, |
| 151 human_buffer, | 151 pc); |
| 152 sizeof(human_buffer), | 152 formatter->ConsumeInstruction(code, hex_buffer, sizeof(hex_buffer), |
| 153 &instruction_length, code, &object, pc); | 153 human_buffer, sizeof(human_buffer), object, |
| 154 formatter->ConsumeInstruction(code, | |
| 155 hex_buffer, | |
| 156 sizeof(hex_buffer), | |
| 157 human_buffer, | |
| 158 sizeof(human_buffer), | |
| 159 object, | |
| 160 pc); | 154 pc); |
| 161 pc += instruction_length; | 155 pc += instruction_length; |
| 162 } | 156 } |
| 163 } | 157 } |
| 164 | 158 |
| 165 | 159 |
| 166 void Disassembler::DisassembleCodeHelper( | 160 void Disassembler::DisassembleCodeHelper(const char* function_fullname, |
| 167 const char* function_fullname, const Code& code, bool optimized) { | 161 const Code& code, |
| 162 bool optimized) { |
| 168 LocalVarDescriptors& var_descriptors = LocalVarDescriptors::Handle(); | 163 LocalVarDescriptors& var_descriptors = LocalVarDescriptors::Handle(); |
| 169 if (FLAG_print_variable_descriptors) { | 164 if (FLAG_print_variable_descriptors) { |
| 170 var_descriptors = code.GetLocalVarDescriptors(); | 165 var_descriptors = code.GetLocalVarDescriptors(); |
| 171 } | 166 } |
| 172 THR_Print("Code for %sfunction '%s' {\n", | 167 THR_Print("Code for %sfunction '%s' {\n", optimized ? "optimized " : "", |
| 173 optimized ? "optimized " : "", | |
| 174 function_fullname); | 168 function_fullname); |
| 175 code.Disassemble(); | 169 code.Disassemble(); |
| 176 THR_Print("}\n"); | 170 THR_Print("}\n"); |
| 177 | 171 |
| 178 #if defined(TARGET_ARCH_IA32) | 172 #if defined(TARGET_ARCH_IA32) |
| 179 THR_Print("Pointer offsets for function: {\n"); | 173 THR_Print("Pointer offsets for function: {\n"); |
| 180 // Pointer offsets are stored in descending order. | 174 // Pointer offsets are stored in descending order. |
| 181 Object& obj = Object::Handle(); | 175 Object& obj = Object::Handle(); |
| 182 for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) { | 176 for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) { |
| 183 const uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart(); | 177 const uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart(); |
| 184 obj = *reinterpret_cast<RawObject**>(addr); | 178 obj = *reinterpret_cast<RawObject**>(addr); |
| 185 THR_Print(" %d : %#" Px " '%s'\n", | 179 THR_Print(" %d : %#" Px " '%s'\n", code.GetPointerOffsetAt(i), addr, |
| 186 code.GetPointerOffsetAt(i), addr, obj.ToCString()); | 180 obj.ToCString()); |
| 187 } | 181 } |
| 188 THR_Print("}\n"); | 182 THR_Print("}\n"); |
| 189 #else | 183 #else |
| 190 ASSERT(code.pointer_offsets_length() == 0); | 184 ASSERT(code.pointer_offsets_length() == 0); |
| 191 #endif | 185 #endif |
| 192 | 186 |
| 193 const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool()); | 187 const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool()); |
| 194 object_pool.DebugPrint(); | 188 object_pool.DebugPrint(); |
| 195 | 189 |
| 196 THR_Print("PC Descriptors for function '%s' {\n", function_fullname); | 190 THR_Print("PC Descriptors for function '%s' {\n", function_fullname); |
| 197 PcDescriptors::PrintHeaderString(); | 191 PcDescriptors::PrintHeaderString(); |
| 198 const PcDescriptors& descriptors = | 192 const PcDescriptors& descriptors = |
| 199 PcDescriptors::Handle(code.pc_descriptors()); | 193 PcDescriptors::Handle(code.pc_descriptors()); |
| 200 THR_Print("%s}\n", descriptors.ToCString()); | 194 THR_Print("%s}\n", descriptors.ToCString()); |
| 201 | 195 |
| 202 uword start = Instructions::Handle(code.instructions()).PayloadStart(); | 196 uword start = Instructions::Handle(code.instructions()).PayloadStart(); |
| 203 const Array& deopt_table = Array::Handle(code.deopt_info_array()); | 197 const Array& deopt_table = Array::Handle(code.deopt_info_array()); |
| 204 intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table); | 198 intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table); |
| 205 if (deopt_table_length > 0) { | 199 if (deopt_table_length > 0) { |
| 206 THR_Print("DeoptInfo: {\n"); | 200 THR_Print("DeoptInfo: {\n"); |
| 207 Smi& offset = Smi::Handle(); | 201 Smi& offset = Smi::Handle(); |
| 208 TypedData& info = TypedData::Handle(); | 202 TypedData& info = TypedData::Handle(); |
| 209 Smi& reason_and_flags = Smi::Handle(); | 203 Smi& reason_and_flags = Smi::Handle(); |
| 210 for (intptr_t i = 0; i < deopt_table_length; ++i) { | 204 for (intptr_t i = 0; i < deopt_table_length; ++i) { |
| 211 DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags); | 205 DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags); |
| 212 const intptr_t reason = | 206 const intptr_t reason = |
| 213 DeoptTable::ReasonField::decode(reason_and_flags.Value()); | 207 DeoptTable::ReasonField::decode(reason_and_flags.Value()); |
| 214 ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons)); | 208 ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons)); |
| 215 THR_Print("%4" Pd ": 0x%" Px " %s (%s)\n", | 209 THR_Print( |
| 216 i, | 210 "%4" Pd ": 0x%" Px " %s (%s)\n", i, start + offset.Value(), |
| 217 start + offset.Value(), | 211 DeoptInfo::ToCString(deopt_table, info), |
| 218 DeoptInfo::ToCString(deopt_table, info), | 212 DeoptReasonToCString(static_cast<ICData::DeoptReasonId>(reason))); |
| 219 DeoptReasonToCString( | |
| 220 static_cast<ICData::DeoptReasonId>(reason))); | |
| 221 } | 213 } |
| 222 THR_Print("}\n"); | 214 THR_Print("}\n"); |
| 223 } | 215 } |
| 224 | 216 |
| 225 THR_Print("Stackmaps for function '%s' {\n", function_fullname); | 217 THR_Print("Stackmaps for function '%s' {\n", function_fullname); |
| 226 if (code.stackmaps() != Array::null()) { | 218 if (code.stackmaps() != Array::null()) { |
| 227 const Array& stackmap_table = Array::Handle(code.stackmaps()); | 219 const Array& stackmap_table = Array::Handle(code.stackmaps()); |
| 228 Stackmap& map = Stackmap::Handle(); | 220 Stackmap& map = Stackmap::Handle(); |
| 229 for (intptr_t i = 0; i < stackmap_table.Length(); ++i) { | 221 for (intptr_t i = 0; i < stackmap_table.Length(); ++i) { |
| 230 map ^= stackmap_table.At(i); | 222 map ^= stackmap_table.At(i); |
| 231 THR_Print("%s\n", map.ToCString()); | 223 THR_Print("%s\n", map.ToCString()); |
| 232 } | 224 } |
| 233 } | 225 } |
| 234 THR_Print("}\n"); | 226 THR_Print("}\n"); |
| 235 | 227 |
| 236 if (FLAG_print_variable_descriptors) { | 228 if (FLAG_print_variable_descriptors) { |
| 237 THR_Print("Variable Descriptors for function '%s' {\n", | 229 THR_Print("Variable Descriptors for function '%s' {\n", function_fullname); |
| 238 function_fullname); | |
| 239 intptr_t var_desc_length = | 230 intptr_t var_desc_length = |
| 240 var_descriptors.IsNull() ? 0 : var_descriptors.Length(); | 231 var_descriptors.IsNull() ? 0 : var_descriptors.Length(); |
| 241 String& var_name = String::Handle(); | 232 String& var_name = String::Handle(); |
| 242 for (intptr_t i = 0; i < var_desc_length; i++) { | 233 for (intptr_t i = 0; i < var_desc_length; i++) { |
| 243 var_name = var_descriptors.GetName(i); | 234 var_name = var_descriptors.GetName(i); |
| 244 RawLocalVarDescriptors::VarInfo var_info; | 235 RawLocalVarDescriptors::VarInfo var_info; |
| 245 var_descriptors.GetInfo(i, &var_info); | 236 var_descriptors.GetInfo(i, &var_info); |
| 246 const int8_t kind = var_info.kind(); | 237 const int8_t kind = var_info.kind(); |
| 247 if (kind == RawLocalVarDescriptors::kSavedCurrentContext) { | 238 if (kind == RawLocalVarDescriptors::kSavedCurrentContext) { |
| 248 THR_Print(" saved current CTX reg offset %d\n", var_info.index()); | 239 THR_Print(" saved current CTX reg offset %d\n", var_info.index()); |
| 249 } else { | 240 } else { |
| 250 if (kind == RawLocalVarDescriptors::kContextLevel) { | 241 if (kind == RawLocalVarDescriptors::kContextLevel) { |
| 251 THR_Print(" context level %d scope %d", var_info.index(), | 242 THR_Print(" context level %d scope %d", var_info.index(), |
| 252 var_info.scope_id); | 243 var_info.scope_id); |
| 253 } else if (kind == RawLocalVarDescriptors::kStackVar) { | 244 } else if (kind == RawLocalVarDescriptors::kStackVar) { |
| 254 THR_Print(" stack var '%s' offset %d", | 245 THR_Print(" stack var '%s' offset %d", var_name.ToCString(), |
| 255 var_name.ToCString(), var_info.index()); | 246 var_info.index()); |
| 256 } else { | 247 } else { |
| 257 ASSERT(kind == RawLocalVarDescriptors::kContextVar); | 248 ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
| 258 THR_Print(" context var '%s' level %d offset %d", | 249 THR_Print(" context var '%s' level %d offset %d", |
| 259 var_name.ToCString(), var_info.scope_id, var_info.index()); | 250 var_name.ToCString(), var_info.scope_id, var_info.index()); |
| 260 } | 251 } |
| 261 THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(), | 252 THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(), |
| 262 var_info.end_pos.ToCString()); | 253 var_info.end_pos.ToCString()); |
| 263 } | 254 } |
| 264 } | 255 } |
| 265 THR_Print("}\n"); | 256 THR_Print("}\n"); |
| 266 } | 257 } |
| 267 | 258 |
| 268 THR_Print("Exception Handlers for function '%s' {\n", function_fullname); | 259 THR_Print("Exception Handlers for function '%s' {\n", function_fullname); |
| 269 const ExceptionHandlers& handlers = | 260 const ExceptionHandlers& handlers = |
| 270 ExceptionHandlers::Handle(code.exception_handlers()); | 261 ExceptionHandlers::Handle(code.exception_handlers()); |
| 271 THR_Print("%s}\n", handlers.ToCString()); | 262 THR_Print("%s}\n", handlers.ToCString()); |
| 272 | 263 |
| 273 { | 264 { |
| 274 THR_Print("Static call target functions {\n"); | 265 THR_Print("Static call target functions {\n"); |
| 275 const Array& table = Array::Handle(code.static_calls_target_table()); | 266 const Array& table = Array::Handle(code.static_calls_target_table()); |
| 276 Smi& offset = Smi::Handle(); | 267 Smi& offset = Smi::Handle(); |
| 277 Function& function = Function::Handle(); | 268 Function& function = Function::Handle(); |
| 278 Code& code = Code::Handle(); | 269 Code& code = Code::Handle(); |
| 279 for (intptr_t i = 0; i < table.Length(); | 270 for (intptr_t i = 0; i < table.Length(); |
| 280 i += Code::kSCallTableEntryLength) { | 271 i += Code::kSCallTableEntryLength) { |
| 281 offset ^= table.At(i + Code::kSCallTableOffsetEntry); | 272 offset ^= table.At(i + Code::kSCallTableOffsetEntry); |
| 282 function ^= table.At(i + Code::kSCallTableFunctionEntry); | 273 function ^= table.At(i + Code::kSCallTableFunctionEntry); |
| 283 code ^= table.At(i + Code::kSCallTableCodeEntry); | 274 code ^= table.At(i + Code::kSCallTableCodeEntry); |
| 284 if (function.IsNull()) { | 275 if (function.IsNull()) { |
| 285 Class& cls = Class::Handle(); | 276 Class& cls = Class::Handle(); |
| 286 cls ^= code.owner(); | 277 cls ^= code.owner(); |
| 287 if (cls.IsNull()) { | 278 if (cls.IsNull()) { |
| 288 THR_Print(" 0x%" Px ": %s, %p\n", | 279 THR_Print(" 0x%" Px ": %s, %p\n", start + offset.Value(), |
| 289 start + offset.Value(), | 280 code.Name(), code.raw()); |
| 290 code.Name(), | |
| 291 code.raw()); | |
| 292 } else { | 281 } else { |
| 293 THR_Print(" 0x%" Px ": allocation stub for %s, %p\n", | 282 THR_Print(" 0x%" Px ": allocation stub for %s, %p\n", |
| 294 start + offset.Value(), | 283 start + offset.Value(), cls.ToCString(), code.raw()); |
| 295 cls.ToCString(), | |
| 296 code.raw()); | |
| 297 } | 284 } |
| 298 } else { | 285 } else { |
| 299 THR_Print(" 0x%" Px ": %s, %p\n", | 286 THR_Print(" 0x%" Px ": %s, %p\n", start + offset.Value(), |
| 300 start + offset.Value(), | 287 function.ToFullyQualifiedCString(), code.raw()); |
| 301 function.ToFullyQualifiedCString(), | |
| 302 code.raw()); | |
| 303 } | 288 } |
| 304 } | 289 } |
| 305 THR_Print("}\n"); | 290 THR_Print("}\n"); |
| 306 } | 291 } |
| 307 if (optimized && FLAG_trace_inlining_intervals) { | 292 if (optimized && FLAG_trace_inlining_intervals) { |
| 308 code.DumpInlinedIntervals(); | 293 code.DumpInlinedIntervals(); |
| 309 } | 294 } |
| 310 } | 295 } |
| 311 | 296 |
| 312 | 297 |
| 313 void Disassembler::DisassembleCode(const Function& function, bool optimized) { | 298 void Disassembler::DisassembleCode(const Function& function, bool optimized) { |
| 314 const char* function_fullname = function.ToFullyQualifiedCString(); | 299 const char* function_fullname = function.ToFullyQualifiedCString(); |
| 315 const Code& code = Code::Handle(function.CurrentCode()); | 300 const Code& code = Code::Handle(function.CurrentCode()); |
| 316 DisassembleCodeHelper(function_fullname, code, optimized); | 301 DisassembleCodeHelper(function_fullname, code, optimized); |
| 317 } | 302 } |
| 318 | 303 |
| 319 | 304 |
| 320 void Disassembler::DisassembleCodeUnoptimized( | 305 void Disassembler::DisassembleCodeUnoptimized(const Function& function, |
| 321 const Function& function, bool optimized) { | 306 bool optimized) { |
| 322 const char* function_fullname = function.ToFullyQualifiedCString(); | 307 const char* function_fullname = function.ToFullyQualifiedCString(); |
| 323 const Code& code = Code::Handle(function.unoptimized_code()); | 308 const Code& code = Code::Handle(function.unoptimized_code()); |
| 324 DisassembleCodeHelper(function_fullname, code, optimized); | 309 DisassembleCodeHelper(function_fullname, code, optimized); |
| 325 } | 310 } |
| 326 | 311 |
| 327 | 312 |
| 328 #endif // !PRODUCT | 313 #endif // !PRODUCT |
| 329 | 314 |
| 330 } // namespace dart | 315 } // namespace dart |
| OLD | NEW |