Home | History | Annotate | Download | only in turbolizer
      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 
      5 "use strict";
      6 
      7 class DisassemblyView extends TextView {
      8   constructor(id, broker) {
      9     super(id, broker, null, false);
     10 
     11     let view = this;
     12     let ADDRESS_STYLE = {
     13       css: 'tag',
     14       location: function(text) {
     15         ADDRESS_STYLE.last_address = text;
     16         return undefined;
     17       }
     18     };
     19     let ADDRESS_LINK_STYLE = {
     20       css: 'tag',
     21       link: function(text) {
     22         view.select(function(location) { return location.address == text; }, true, true);
     23       }
     24     };
     25     let UNCLASSIFIED_STYLE = {
     26       css: 'com'
     27     };
     28     let NUMBER_STYLE = {
     29       css: 'lit'
     30     };
     31     let COMMENT_STYLE = {
     32       css: 'com'
     33     };
     34     let POSITION_STYLE = {
     35       css: 'com',
     36       location: function(text) {
     37         view.pos_start = Number(text);
     38       }
     39     };
     40     let OPCODE_STYLE = {
     41       css: 'kwd',
     42       location: function(text) {
     43         if (BLOCK_HEADER_STYLE.block_id != undefined) {
     44           return {
     45             address: ADDRESS_STYLE.last_address,
     46             block_id: BLOCK_HEADER_STYLE.block_id
     47           };
     48         } else {
     49           return {
     50             address: ADDRESS_STYLE.last_address
     51           };
     52         }
     53       }
     54     };
     55     const BLOCK_HEADER_STYLE = {
     56       css: 'com',
     57       block_id: -1,
     58       location: function(text) {
     59         let matches = /\d+/.exec(text);
     60         if (!matches) return undefined;
     61         BLOCK_HEADER_STYLE.block_id = Number(matches[0]);
     62         return {
     63           block_id: BLOCK_HEADER_STYLE.block_id
     64         };
     65       },
     66     };
     67     const SOURCE_POSITION_HEADER_STYLE = {
     68       css: 'com',
     69       location: function(text) {
     70         let matches = /(\d+):(\d+)/.exec(text);
     71         if (!matches) return undefined;
     72         let li = Number(matches[1]);
     73         if (view.pos_lines === null) return undefined;
     74         let pos = view.pos_lines[li-1] + Number(matches[2]);
     75         return {
     76           pos_start: pos,
     77           pos_end: pos + 1
     78         };
     79       },
     80     };
     81     view.SOURCE_POSITION_HEADER_REGEX = /^(\s*-- .+:)(\d+:\d+)( --)/;
     82     let patterns = [
     83       [
     84         [/^0x[0-9a-f]{8,16}/, ADDRESS_STYLE, 1],
     85         [view.SOURCE_POSITION_HEADER_REGEX, SOURCE_POSITION_HEADER_STYLE, -1],
     86         [/^\s+-- B\d+ start.*/, BLOCK_HEADER_STYLE, -1],
     87         [/^.*/, UNCLASSIFIED_STYLE, -1]
     88       ],
     89       [
     90         [/^\s+\d+\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
     91         [/^.*/, null, -1]
     92       ],
     93       [
     94         [/^\S+\s+/, OPCODE_STYLE, 3],
     95         [/^\S+$/, OPCODE_STYLE, -1],
     96         [/^.*/, null, -1]
     97       ],
     98       [
     99         [/^\s+/, null],
    100         [/^[^\(;]+$/, null, -1],
    101         [/^[^\(;]+/, null],
    102         [/^\(/, null, 4],
    103         [/^;/, COMMENT_STYLE, 5]
    104       ],
    105       [
    106         [/^0x[0-9a-f]{8,16}/, ADDRESS_LINK_STYLE],
    107         [/^[^\)]/, null],
    108         [/^\)$/, null, -1],
    109         [/^\)/, null, 3]
    110       ],
    111       [
    112         [/^; debug\: position /, COMMENT_STYLE, 6],
    113         [/^.+$/, COMMENT_STYLE, -1]
    114       ],
    115       [
    116         [/^\d+$/, POSITION_STYLE, -1],
    117       ]
    118     ];
    119     view.setPatterns(patterns);
    120   }
    121 
    122   lineLocation(li) {
    123     let view = this;
    124     let result = undefined;
    125     for (let i = 0; i < li.children.length; ++i) {
    126       let fragment = li.children[i];
    127       let location = fragment.location;
    128       if (location != null) {
    129         if (location.block_id != undefined) {
    130           if (result === undefined) result = {};
    131           result.block_id = location.block_id;
    132         }
    133         if (location.address != undefined) {
    134           if (result === undefined) result = {};
    135           result.address = location.address;
    136         }
    137         if (location.pos_start != undefined && location.pos_end != undefined) {
    138           if (result === undefined) result = {};
    139           result.pos_start = location.pos_start;
    140           result.pos_end = location.pos_end;
    141         }
    142         else if (view.pos_start != -1) {
    143           if (result === undefined) result = {};
    144           result.pos_start = view.pos_start;
    145           result.pos_end = result.pos_start + 1;
    146         }
    147       }
    148     }
    149     return result;
    150   }
    151 
    152   initializeContent(data, rememberedSelection) {
    153     this.data = data;
    154     super.initializeContent(data, rememberedSelection);
    155   }
    156 
    157   initializeCode(sourceText, sourcePosition) {
    158     let view = this;
    159     view.pos_start = -1;
    160     view.addr_event_counts = null;
    161     view.total_event_counts = null;
    162     view.max_event_counts = null;
    163     view.pos_lines = new Array();
    164     // Comment lines for line 0 include sourcePosition already, only need to
    165     // add sourcePosition for lines > 0.
    166     view.pos_lines[0] = sourcePosition;
    167     if (sourceText != "") {
    168       let base = sourcePosition;
    169       let current = 0;
    170       let source_lines = sourceText.split("\n");
    171       for (let i = 1; i < source_lines.length; i++) {
    172         // Add 1 for newline character that is split off.
    173         current += source_lines[i-1].length + 1;
    174         view.pos_lines[i] = base + current;
    175       }
    176     }
    177   }
    178 
    179   initializePerfProfile(eventCounts) {
    180     let view = this;
    181     if (eventCounts !== undefined) {
    182       view.addr_event_counts = eventCounts;
    183 
    184       view.total_event_counts = {};
    185       view.max_event_counts = {};
    186       for (let ev_name in view.addr_event_counts) {
    187         let keys = Object.keys(view.addr_event_counts[ev_name]);
    188         let values = keys.map(key => view.addr_event_counts[ev_name][key]);
    189         view.total_event_counts[ev_name] = values.reduce((a, b) => a + b);
    190         view.max_event_counts[ev_name] = values.reduce((a, b) => Math.max(a, b));
    191       }
    192     }
    193     else {
    194       view.addr_event_counts = null;
    195       view.total_event_counts = null;
    196       view.max_event_counts = null;
    197     }
    198   }
    199 
    200   // Shorten decimals and remove trailing zeroes for readability.
    201   humanize(num) {
    202     return num.toFixed(3).replace(/\.?0+$/, "") + "%";
    203   }
    204 
    205   // Interpolate between the given start and end values by a fraction of val/max.
    206   interpolate(val, max, start, end) {
    207     return start + (end - start) * (val / max);
    208   }
    209 
    210   processLine(line) {
    211     let view = this;
    212     let func = function(match, p1, p2, p3) {
    213       let nums = p2.split(":");
    214       let li = Number(nums[0]);
    215       let pos = Number(nums[1]);
    216       if(li === 0)
    217         pos -= view.pos_lines[0];
    218       li++;
    219       return p1 + li + ":" + pos + p3;
    220     };
    221     line = line.replace(view.SOURCE_POSITION_HEADER_REGEX, func);
    222     let fragments = super.processLine(line);
    223 
    224     // Add profiling data per instruction if available.
    225     if (view.total_event_counts) {
    226       let matches = /^(0x[0-9a-fA-F]+)\s+\d+\s+[0-9a-fA-F]+/.exec(line);
    227       if (matches) {
    228         let newFragments = [];
    229         for (let event in view.addr_event_counts) {
    230           let count = view.addr_event_counts[event][matches[1]];
    231           let str = " ";
    232           let css_cls = "prof";
    233           if(count !== undefined) {
    234             let perc = count / view.total_event_counts[event] * 100;
    235 
    236             let col = { r: 255, g: 255, b: 255 };
    237             for (let i = 0; i < PROF_COLS.length; i++) {
    238               if (perc === PROF_COLS[i].perc) {
    239                 col = PROF_COLS[i].col;
    240                 break;
    241               }
    242               else if (perc > PROF_COLS[i].perc && perc < PROF_COLS[i + 1].perc) {
    243                 let col1 = PROF_COLS[i].col;
    244                 let col2 = PROF_COLS[i + 1].col;
    245 
    246                 let val = perc - PROF_COLS[i].perc;
    247                 let max = PROF_COLS[i + 1].perc - PROF_COLS[i].perc;
    248 
    249                 col.r = Math.round(view.interpolate(val, max, col1.r, col2.r));
    250                 col.g = Math.round(view.interpolate(val, max, col1.g, col2.g));
    251                 col.b = Math.round(view.interpolate(val, max, col1.b, col2.b));
    252                 break;
    253               }
    254             }
    255 
    256             str = UNICODE_BLOCK;
    257 
    258             let fragment = view.createFragment(str, css_cls);
    259             fragment.title = event + ": " + view.humanize(perc) + " (" + count + ")";
    260             fragment.style.color = "rgb(" + col.r + ", " + col.g + ", " + col.b + ")";
    261 
    262             newFragments.push(fragment);
    263           }
    264           else
    265             newFragments.push(view.createFragment(str, css_cls));
    266 
    267         }
    268         fragments = newFragments.concat(fragments);
    269       }
    270     }
    271     return fragments;
    272   }
    273 }
    274