| OLD | NEW |
| 1 # Copyright 2017 The Chromium Authors. All rights reserved. | 1 # Copyright 2017 The Chromium 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 """Logic for diffing two SizeInfo objects.""" | 4 """Logic for diffing two SizeInfo objects.""" |
| 5 | 5 |
| 6 import collections | 6 import collections |
| 7 import re |
| 7 | 8 |
| 8 import models | 9 import models |
| 9 | 10 |
| 10 | 11 |
| 12 def _SymbolKey(symbol): |
| 13 """Returns a tuple that can be used to see if two Symbol are the same. |
| 14 |
| 15 Keys are not guaranteed to be unique within a SymbolGroup. When multiple |
| 16 symbols have the same key, they will be matched up in order of appearance. |
| 17 We do this because the numbering of these generated symbols is not stable. |
| 18 |
| 19 Examples of symbols with shared keys: |
| 20 "** merge strings" |
| 21 "** symbol gap 3", "** symbol gap 5" |
| 22 "foo() [clone ##]" |
| 23 "CSWTCH.61", "CSWTCH.62" |
| 24 "._468", "._467" |
| 25 ".L__unnamed_1193", ".L__unnamed_712" |
| 26 """ |
| 27 name = symbol.full_name or symbol.name |
| 28 clone_idx = name.find(' [clone ') |
| 29 if clone_idx != -1: |
| 30 name = name[:clone_idx] |
| 31 if name.startswith('*'): |
| 32 # "symbol gap 3 (bar)" -> "symbol gaps" |
| 33 name = re.sub(r'\s+\d+( \(.*\))?$', 's', name) |
| 34 |
| 35 if '.' not in name: |
| 36 return (symbol.section_name, name) |
| 37 # Compiler or Linker generated symbol. |
| 38 name = re.sub(r'[.0-9]', '', name) # Strip out all numbers and dots. |
| 39 return (symbol.section_name, name, symbol.object_path) |
| 40 |
| 41 |
| 11 def _CloneSymbol(sym, size): | 42 def _CloneSymbol(sym, size): |
| 12 """Returns a copy of |sym| with an updated |size|. | 43 """Returns a copy of |sym| with an updated |size|. |
| 13 | 44 |
| 14 Padding and aliases are not copied. | 45 Padding and aliases are not copied. |
| 15 """ | 46 """ |
| 16 return models.Symbol( | 47 return models.Symbol( |
| 17 sym.section_name, size, address=sym.address, name=sym.name, | 48 sym.section_name, size, address=sym.address, name=sym.name, |
| 18 source_path=sym.source_path, object_path=sym.object_path, | 49 source_path=sym.source_path, object_path=sym.object_path, |
| 19 full_name=sym.full_name, flags=sym.flags) | 50 full_name=sym.full_name, flags=sym.flags) |
| 20 | 51 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 else: | 125 else: |
| 95 cloned = _CloneSymbol(sym, -sym.size_without_padding) | 126 cloned = _CloneSymbol(sym, -sym.size_without_padding) |
| 96 cloned.padding = -sym.padding | 127 cloned.padding = -sym.padding |
| 97 ret[i] = cloned | 128 ret[i] = cloned |
| 98 return ret | 129 return ret |
| 99 | 130 |
| 100 | 131 |
| 101 def _DiffSymbolGroups(before, after): | 132 def _DiffSymbolGroups(before, after): |
| 102 before_symbols_by_key = collections.defaultdict(list) | 133 before_symbols_by_key = collections.defaultdict(list) |
| 103 for s in before: | 134 for s in before: |
| 104 before_symbols_by_key[s._Key()].append(s) | 135 before_symbols_by_key[_SymbolKey(s)].append(s) |
| 105 | 136 |
| 106 similar = [] | 137 similar = [] |
| 107 diffed_symbol_by_after_aliases = {} | 138 diffed_symbol_by_after_aliases = {} |
| 108 matched_before_aliases = set() | 139 matched_before_aliases = set() |
| 109 unmatched_after_syms = [] | 140 unmatched_after_syms = [] |
| 110 # For similar symbols, padding is zeroed out. In order to not lose the | 141 # For similar symbols, padding is zeroed out. In order to not lose the |
| 111 # information entirely, store it in aggregate. | 142 # information entirely, store it in aggregate. |
| 112 padding_by_section_name = collections.defaultdict(int) | 143 padding_by_section_name = collections.defaultdict(int) |
| 113 | 144 |
| 114 # Step 1: Create all delta symbols and record unmatched symbols. | 145 # Step 1: Create all delta symbols and record unmatched symbols. |
| 115 for after_sym in after: | 146 for after_sym in after: |
| 116 matching_syms = before_symbols_by_key.get(after_sym._Key()) | 147 matching_syms = before_symbols_by_key.get(_SymbolKey(after_sym)) |
| 117 if matching_syms: | 148 if matching_syms: |
| 118 before_sym = matching_syms.pop(0) | 149 before_sym = matching_syms.pop(0) |
| 119 if before_sym.IsGroup() and after_sym.IsGroup(): | 150 if before_sym.IsGroup() and after_sym.IsGroup(): |
| 120 similar.append(_DiffSymbolGroups(before_sym, after_sym)) | 151 similar.append(_DiffSymbolGroups(before_sym, after_sym)) |
| 121 else: | 152 else: |
| 122 if before_sym.aliases: | 153 if before_sym.aliases: |
| 123 matched_before_aliases.add(id(before_sym.aliases)) | 154 matched_before_aliases.add(id(before_sym.aliases)) |
| 124 similar.append( | 155 similar.append( |
| 125 _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases, | 156 _DiffSymbol(before_sym, after_sym, diffed_symbol_by_after_aliases, |
| 126 padding_by_section_name)) | 157 padding_by_section_name)) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 """ | 189 """ |
| 159 assert isinstance(before, models.SizeInfo) | 190 assert isinstance(before, models.SizeInfo) |
| 160 assert isinstance(after, models.SizeInfo) | 191 assert isinstance(after, models.SizeInfo) |
| 161 section_sizes = {k: after.section_sizes[k] - v | 192 section_sizes = {k: after.section_sizes[k] - v |
| 162 for k, v in before.section_sizes.iteritems()} | 193 for k, v in before.section_sizes.iteritems()} |
| 163 symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols) | 194 symbol_diff = _DiffSymbolGroups(before.symbols, after.symbols) |
| 164 if cluster: | 195 if cluster: |
| 165 symbol_diff = symbol_diff.Cluster() | 196 symbol_diff = symbol_diff.Cluster() |
| 166 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata, | 197 return models.SizeInfoDiff(section_sizes, symbol_diff, before.metadata, |
| 167 after.metadata) | 198 after.metadata) |
| OLD | NEW |