[turbolizer] Display block names in disassembly pane

Bug: v8:7327
Change-Id: Ia8e5d51b12cc86734523860af88d4c3948e0f0c0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1660614
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Daniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63371}
This commit is contained in:
Sigurd Schneider 2019-08-23 15:50:33 +02:00 committed by Commit Bot
parent 5812aabb0b
commit 98dfac7526
6 changed files with 103 additions and 68 deletions

View File

@ -2433,6 +2433,23 @@ MaybeHandle<Code> Pipeline::GenerateCodeForCodeStub(
return code;
}
struct BlockStartsAsJSON {
const ZoneVector<int>* block_starts;
};
std::ostream& operator<<(std::ostream& out, const BlockStartsAsJSON& s) {
out << ", \"blockIdToOffset\": {";
bool need_comma = false;
for (size_t i = 0; i < s.block_starts->size(); ++i) {
if (need_comma) out << ", ";
int offset = (*s.block_starts)[i];
out << "\"" << i << "\":" << offset;
need_comma = true;
}
out << "},";
return out;
}
// static
wasm::WasmCompilationResult Pipeline::GenerateCodeForWasmNativeStub(
wasm::WasmEngine* wasm_engine, CallDescriptor* call_descriptor,
@ -2503,7 +2520,9 @@ wasm::WasmCompilationResult Pipeline::GenerateCodeForWasmNativeStub(
if (info.trace_turbo_json_enabled()) {
TurboJsonFile json_of(&info, std::ios_base::app);
json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\",\"data\":\"";
json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\""
<< BlockStartsAsJSON{&code_generator->block_starts()}
<< "\"data\":\"";
#ifdef ENABLE_DISASSEMBLER
std::stringstream disassembler_stream;
Disassembler::Decode(
@ -2696,7 +2715,9 @@ void Pipeline::GenerateCodeForWasmFunction(
if (data.info()->trace_turbo_json_enabled()) {
TurboJsonFile json_of(data.info(), std::ios_base::app);
json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\",\"data\":\"";
json_of << "{\"name\":\"disassembly\",\"type\":\"disassembly\""
<< BlockStartsAsJSON{&code_generator->block_starts()}
<< "\"data\":\"";
#ifdef ENABLE_DISASSEMBLER
std::stringstream disassembler_stream;
Disassembler::Decode(
@ -2934,23 +2955,6 @@ void PipelineImpl::AssembleCode(Linkage* linkage,
data->EndPhaseKind();
}
struct BlockStartsAsJSON {
const ZoneVector<int>* block_starts;
};
std::ostream& operator<<(std::ostream& out, const BlockStartsAsJSON& s) {
out << ", \"blockIdToOffset\": {";
bool need_comma = false;
for (size_t i = 0; i < s.block_starts->size(); ++i) {
if (need_comma) out << ", ";
int offset = (*s.block_starts)[i];
out << "\"" << i << "\":" << offset;
need_comma = true;
}
out << "},";
return out;
}
MaybeHandle<Code> PipelineImpl::FinalizeCode(bool retire_broker) {
PipelineData* data = this->data_;
if (data->broker() && retire_broker) {

View File

@ -1687,9 +1687,9 @@
"dev": true
},
"js-yaml": {
"version": "3.12.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
"integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@ -2344,9 +2344,9 @@
"dev": true
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"requires": {
"for-in": "^1.0.2",
"is-extendable": "^1.0.1"
@ -2872,9 +2872,9 @@
}
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
@ -3407,35 +3407,14 @@
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"universalify": {

View File

@ -32,7 +32,7 @@ export class DisassemblyView extends TextView {
pane.setAttribute('id', "disassembly");
pane.innerHTML =
`<pre id='disassembly-text-pre' class='prettyprint prettyprinted'>
<ul id='disassembly-list' class='nolinenums noindent'>
<ul class='disassembly-list nolinenums noindent'>
</ul>
</pre>`;
@ -46,6 +46,16 @@ export class DisassemblyView extends TextView {
associateData: (text, fragment: HTMLElement) => {
const matches = text.match(/(?<address>0?x?[0-9a-fA-F]{8,16})(?<addressSpace>\s+)(?<offset>[0-9a-f]+)(?<offsetSpace>\s*)/);
const offset = Number.parseInt(matches.groups["offset"], 16);
const blockIds = view.sourceResolver.getBlockIdsForOffset(offset);
const blockIdElement = document.createElement("SPAN");
blockIdElement.className = "block-id com linkable-text";
blockIdElement.innerText = "";
if (blockIds && blockIds.length > 0) {
blockIds.forEach(blockId => view.addHtmlElementForBlockId(blockId, fragment));
blockIdElement.innerText = `B${blockIds.join(",")}:`;
blockIdElement.dataset.blockId = `${blockIds.join(",")}`;
}
fragment.appendChild(blockIdElement);
const addressElement = document.createElement("SPAN");
addressElement.className = "instruction-address";
addressElement.innerText = matches.groups["address"];
@ -58,11 +68,13 @@ export class DisassemblyView extends TextView {
fragment.classList.add('tag');
if (!Number.isNaN(offset)) {
const pcOffset = view.sourceResolver.getKeyPcOffset(offset);
let pcOffset = view.sourceResolver.getKeyPcOffset(offset);
if (pcOffset == -1) pcOffset = Number(offset);
fragment.dataset.pcOffset = `${pcOffset}`;
addressElement.classList.add('linkable-text');
offsetElement.classList.add('linkable-text');
}
return true;
}
};
const UNCLASSIFIED_STYLE = {
@ -79,11 +91,20 @@ export class DisassemblyView extends TextView {
fragment.innerHTML = text;
const replacer = (match, hexOffset) => {
const offset = Number.parseInt(hexOffset, 16);
const keyOffset = view.sourceResolver.getKeyPcOffset(offset);
return `<span class="tag linkable-text" data-pc-offset="${keyOffset}">${match}</span>`;
let keyOffset = view.sourceResolver.getKeyPcOffset(offset);
if (keyOffset == -1) keyOffset = Number(offset);
const blockIds = view.sourceResolver.getBlockIdsForOffset(offset);
let block = "";
let blockIdData = "";
if (blockIds && blockIds.length > 0) {
block = `B${blockIds.join(",")} `;
blockIdData = `data-block-id="${blockIds.join(",")}"`;
}
return `<span class="tag linkable-text" data-pc-offset="${keyOffset}" ${blockIdData}>${block}${match}</span>`;
};
const html = text.replace(/<.0?x?([0-9a-fA-F]+)>/g, replacer);
fragment.innerHTML = html;
return true;
}
};
const OPCODE_STYLE = {
@ -91,12 +112,14 @@ export class DisassemblyView extends TextView {
};
const BLOCK_HEADER_STYLE = {
associateData: function (text, fragment) {
if (view.sourceResolver.hasBlockStartInfo()) return false;
const matches = /\d+/.exec(text);
if (!matches) return;
if (!matches) return true;
const blockId = matches[0];
fragment.dataset.blockId = blockId;
fragment.innerHTML = text;
fragment.className = "com block";
return true;
}
};
const SOURCE_POSITION_HEADER_STYLE = {
@ -135,7 +158,7 @@ export class DisassemblyView extends TextView {
const linkHandler = (e: MouseEvent) => {
if (!(e.target instanceof HTMLElement)) return;
const offsetAsString = e.target.dataset.pcOffset ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset;
const offsetAsString = typeof e.target.dataset.pcOffset != "undefined" ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset;
const offset = Number.parseInt(offsetAsString, 10);
if ((typeof offsetAsString) != "undefined" && !Number.isNaN(offset)) {
view.offsetSelection.select([offset], true);
@ -156,12 +179,12 @@ export class DisassemblyView extends TextView {
const linkHandlerBlock = e => {
const blockId = e.target.dataset.blockId;
if (typeof blockId != "undefined" && !Number.isNaN(blockId)) {
e.stopPropagation();
if (typeof blockId != "undefined") {
const blockIds = blockId.split(",");
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.blockSelectionHandler.select([blockId], true);
view.blockSelectionHandler.select(blockIds, true);
}
};
view.divNode.addEventListener('click', linkHandlerBlock);

View File

@ -118,6 +118,8 @@ export class SourceResolver {
instructionToPCOffset: Array<number>;
pcOffsetToInstructions: Map<number, Array<number>>;
pcOffsets: Array<number>;
blockIdToPCOffset: Array<number>;
blockStartPCtoBlockIds: Map<number, Array<number>>;
constructor() {
// Maps node ids to source positions.
@ -147,6 +149,16 @@ export class SourceResolver {
// Maps PC offsets to instructions.
this.pcOffsetToInstructions = new Map();
this.pcOffsets = [];
this.blockIdToPCOffset = [];
this.blockStartPCtoBlockIds = new Map();
}
getBlockIdsForOffset(offset): Array<number> {
return this.blockStartPCtoBlockIds.get(offset);
}
hasBlockStartInfo() {
return this.blockIdToPCOffset.length > 0;
}
setSources(sources, mainBackup) {
@ -447,6 +459,15 @@ export class SourceResolver {
switch (phase.type) {
case 'disassembly':
this.disassemblyPhase = phase;
if (phase['blockIdToOffset']) {
for (const [blockId, pc] of Object.entries<number>(phase['blockIdToOffset'])) {
this.blockIdToPCOffset[blockId] = pc;
if (!this.blockStartPCtoBlockIds.has(pc)) {
this.blockStartPCtoBlockIds.set(pc, []);
}
this.blockStartPCtoBlockIds.get(pc).push(Number(blockId));
}
}
break;
case 'schedule':
this.phaseNames.set(phase.name, this.phases.length);

View File

@ -129,6 +129,10 @@ export abstract class TextView extends PhaseView {
if (this.divNode.parentNode == null) return;
const mkVisible = new ViewElements(this.divNode.parentNode as HTMLElement);
const view = this;
const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`);
for (const el of elementsToSelect) {
el.classList.toggle("selected", false);
}
for (const [blockId, elements] of this.blockIdToHtmlElementsMap.entries()) {
const isSelected = view.blockSelection.isSelected(blockId);
for (const element of elements) {
@ -136,10 +140,6 @@ export abstract class TextView extends PhaseView {
element.classList.toggle("selected", isSelected);
}
}
const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`);
for (const el of elementsToSelect) {
el.classList.toggle("selected", false);
}
for (const key of this.nodeIdToHtmlElementsMap.keys()) {
for (const element of this.nodeIdToHtmlElementsMap.get(key)) {
element.classList.toggle("selected", false);
@ -170,7 +170,9 @@ export abstract class TextView extends PhaseView {
const fragment = document.createElement("SPAN");
if (typeof style.associateData == 'function') {
style.associateData(text, fragment);
if (style.associateData(text, fragment) === false) {
return null;
}
} else {
if (style.css != undefined) {
const css = isIterable(style.css) ? style.css : [style.css];
@ -198,7 +200,7 @@ export abstract class TextView extends PhaseView {
const text = matches[0];
if (text != '') {
const fragment = view.createFragment(matches[0], style);
result.push(fragment);
if (fragment !== null) result.push(fragment);
}
line = line.substr(matches[0].length);
}

View File

@ -696,3 +696,9 @@ text {
padding-left: .5ex;
outline: 1px dotted grey;
}
ul.disassembly-list .block-id {
width: 4ex;
display: block;
padding-top: 2px;
}