• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {PROF_COLS, UNICODE_BLOCK} from "./constants.js"
6import {SelectionBroker} from "./selection-broker.js"
7import {TextView} from "./text-view.js"
8
9export class DisassemblyView extends TextView {
10  SOURCE_POSITION_HEADER_REGEX: any;
11  addr_event_counts: any;
12  total_event_counts: any;
13  max_event_counts: any;
14  pos_lines: Array<any>;
15
16  createViewElement() {
17    const pane = document.createElement('div');
18    pane.setAttribute('id', "disassembly");
19    pane.innerHTML =
20      `<pre id='disassembly-text-pre' class='prettyprint prettyprinted'>
21       <ul id='disassembly-list' class='nolinenums noindent'>
22       </ul>
23     </pre>`;
24    return pane;
25  }
26
27  constructor(parentId, broker: SelectionBroker) {
28    super(parentId, broker, null);
29    let view = this;
30    const sourceResolver = broker.sourceResolver;
31    let ADDRESS_STYLE = {
32      css: 'tag',
33      linkHandler: function (text, fragment) {
34        const matches = text.match(/0x[0-9a-f]{8,16}\s*(?<offset>[0-9a-f]+)/);
35        const offset = Number.parseInt(matches.groups["offset"], 16);
36        if (!Number.isNaN(offset)) {
37          const [nodes, blockId] = sourceResolver.nodesForPCOffset(offset)
38          console.log("nodes for", offset, offset.toString(16), " are ", nodes);
39          if (nodes.length > 0) {
40            for (const nodeId of nodes) {
41              view.addHtmlElementForNodeId(nodeId, fragment);
42            }
43            return (e) => {
44              console.log(offset, nodes);
45              e.stopPropagation();
46              if (!e.shiftKey) {
47                view.selectionHandler.clear();
48              }
49              view.selectionHandler.select(nodes, true);
50            };
51          }
52        }
53        return undefined;
54      }
55    };
56    let ADDRESS_LINK_STYLE = {
57      css: 'tag'
58    };
59    let UNCLASSIFIED_STYLE = {
60      css: 'com'
61    };
62    let NUMBER_STYLE = {
63      css: 'lit'
64    };
65    let COMMENT_STYLE = {
66      css: 'com'
67    };
68    let POSITION_STYLE = {
69      css: 'com',
70    };
71    let OPCODE_STYLE = {
72      css: 'kwd',
73    };
74    const BLOCK_HEADER_STYLE = {
75      css: ['com', 'block'],
76      block_id: null,
77      blockId: function (text) {
78        let matches = /\d+/.exec(text);
79        if (!matches) return undefined;
80        BLOCK_HEADER_STYLE.block_id = Number(matches[0]);
81        return BLOCK_HEADER_STYLE.block_id;
82      },
83      linkHandler: function (text) {
84        let matches = /\d+/.exec(text);
85        if (!matches) return undefined;
86        const blockId = matches[0];
87        return function (e) {
88          e.stopPropagation();
89          if (!e.shiftKey) {
90            view.selectionHandler.clear();
91          }
92          view.blockSelectionHandler.select([blockId], true);
93        };
94      }
95    };
96    const SOURCE_POSITION_HEADER_STYLE = {
97      css: 'com'
98    };
99    view.SOURCE_POSITION_HEADER_REGEX = /^\s*--[^<]*<.*(not inlined|inlined\((\d+)\)):(\d+)>\s*--/;
100    let patterns = [
101      [
102        [/^0x[0-9a-f]{8,16}\s*[0-9a-f]+\ /, ADDRESS_STYLE, 1],
103        [view.SOURCE_POSITION_HEADER_REGEX, SOURCE_POSITION_HEADER_STYLE, -1],
104        [/^\s+-- B\d+ start.*/, BLOCK_HEADER_STYLE, -1],
105        [/^.*/, UNCLASSIFIED_STYLE, -1]
106      ],
107      [
108        [/^\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
109        [/^\s+[0-9a-f]+\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
110        [/^.*/, null, -1]
111      ],
112      [
113        [/^\S+\s+/, OPCODE_STYLE, 3],
114        [/^\S+$/, OPCODE_STYLE, -1],
115        [/^.*/, null, -1]
116      ],
117      [
118        [/^\s+/, null],
119        [/^[^\(;]+$/, null, -1],
120        [/^[^\(;]+/, null],
121        [/^\(/, null, 4],
122        [/^;/, COMMENT_STYLE, 5]
123      ],
124      [
125        [/^0x[0-9a-f]{8,16}/, ADDRESS_LINK_STYLE],
126        [/^[^\)]/, null],
127        [/^\)$/, null, -1],
128        [/^\)/, null, 3]
129      ],
130      [
131        [/^; debug\: position /, COMMENT_STYLE, 6],
132        [/^.+$/, COMMENT_STYLE, -1]
133      ],
134      [
135        [/^\d+$/, POSITION_STYLE, -1],
136      ]
137    ];
138    view.setPatterns(patterns);
139  }
140
141  initializeCode(sourceText, sourcePosition) {
142    let view = this;
143    view.addr_event_counts = null;
144    view.total_event_counts = null;
145    view.max_event_counts = null;
146    view.pos_lines = new Array();
147    // Comment lines for line 0 include sourcePosition already, only need to
148    // add sourcePosition for lines > 0.
149    view.pos_lines[0] = sourcePosition;
150    if (sourceText && sourceText != "") {
151      let base = sourcePosition;
152      let current = 0;
153      let source_lines = sourceText.split("\n");
154      for (let i = 1; i < source_lines.length; i++) {
155        // Add 1 for newline character that is split off.
156        current += source_lines[i - 1].length + 1;
157        view.pos_lines[i] = base + current;
158      }
159    }
160  }
161
162  initializePerfProfile(eventCounts) {
163    let view = this;
164    if (eventCounts !== undefined) {
165      view.addr_event_counts = eventCounts;
166
167      view.total_event_counts = {};
168      view.max_event_counts = {};
169      for (let ev_name in view.addr_event_counts) {
170        let keys = Object.keys(view.addr_event_counts[ev_name]);
171        let values = keys.map(key => view.addr_event_counts[ev_name][key]);
172        view.total_event_counts[ev_name] = values.reduce((a, b) => a + b);
173        view.max_event_counts[ev_name] = values.reduce((a, b) => Math.max(a, b));
174      }
175    }
176    else {
177      view.addr_event_counts = null;
178      view.total_event_counts = null;
179      view.max_event_counts = null;
180    }
181  }
182
183  // Shorten decimals and remove trailing zeroes for readability.
184  humanize(num) {
185    return num.toFixed(3).replace(/\.?0+$/, "") + "%";
186  }
187
188  // Interpolate between the given start and end values by a fraction of val/max.
189  interpolate(val, max, start, end) {
190    return start + (end - start) * (val / max);
191  }
192
193  processLine(line) {
194    let view = this;
195    let fragments = super.processLine(line);
196
197    // Add profiling data per instruction if available.
198    if (view.total_event_counts) {
199      let matches = /^(0x[0-9a-fA-F]+)\s+\d+\s+[0-9a-fA-F]+/.exec(line);
200      if (matches) {
201        let newFragments = [];
202        for (let event in view.addr_event_counts) {
203          let count = view.addr_event_counts[event][matches[1]];
204          let str = " ";
205          let css_cls = "prof";
206          if (count !== undefined) {
207            let perc = count / view.total_event_counts[event] * 100;
208
209            let col = { r: 255, g: 255, b: 255 };
210            for (let i = 0; i < PROF_COLS.length; i++) {
211              if (perc === PROF_COLS[i].perc) {
212                col = PROF_COLS[i].col;
213                break;
214              }
215              else if (perc > PROF_COLS[i].perc && perc < PROF_COLS[i + 1].perc) {
216                let col1 = PROF_COLS[i].col;
217                let col2 = PROF_COLS[i + 1].col;
218
219                let val = perc - PROF_COLS[i].perc;
220                let max = PROF_COLS[i + 1].perc - PROF_COLS[i].perc;
221
222                col.r = Math.round(view.interpolate(val, max, col1.r, col2.r));
223                col.g = Math.round(view.interpolate(val, max, col1.g, col2.g));
224                col.b = Math.round(view.interpolate(val, max, col1.b, col2.b));
225                break;
226              }
227            }
228
229            str = UNICODE_BLOCK;
230
231            let fragment = view.createFragment(str, css_cls);
232            fragment.title = event + ": " + view.humanize(perc) + " (" + count + ")";
233            fragment.style.color = "rgb(" + col.r + ", " + col.g + ", " + col.b + ")";
234
235            newFragments.push(fragment);
236          }
237          else
238            newFragments.push(view.createFragment(str, css_cls));
239
240        }
241        fragments = newFragments.concat(fragments);
242      }
243    }
244    return fragments;
245  }
246
247  detachSelection() { return null; }
248}
249