Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Remove dependency from ui_utils on polymer, move graph-pane into a se…
…parate package. Remove decency on polymer from Saga, use liquid to build code_pane.
  • Loading branch information
mraleph committed Mar 15, 2015
1 parent ad128d1 commit 40c2b40
Show file tree
Hide file tree
Showing 19 changed files with 472 additions and 476 deletions.
2 changes: 1 addition & 1 deletion irhydra/lib/src/ui/hydra.html
Expand Up @@ -7,7 +7,7 @@
<link rel="import" href="compilation-timeline.html">
<link rel="import" href="dropdown-element.html">
<link rel="import" href="deopt-links.html">
<link rel="import" href="../../../../packages/ui_utils/components/graph-pane.html">
<link rel="import" href="../../../../packages/ui_components/components/graph-pane.html">
<link rel="import" href="ir-pane.html">
<link rel="import" href="method-list.html">
<link rel="import" href="open-file-button.html">
Expand Down
6 changes: 6 additions & 0 deletions irhydra/pubspec.lock
Expand Up @@ -133,6 +133,12 @@ packages:
description: template_binding
source: hosted
version: "0.14.0+1"
ui_components:
description:
path: "../ui_components"
relative: true
source: path
version: "0.0.1"
ui_utils:
description:
path: "../ui_utils"
Expand Down
2 changes: 2 additions & 0 deletions irhydra/pubspec.yaml
Expand Up @@ -9,6 +9,8 @@ dependencies:
sass: any
ui_utils:
path: ../ui_utils
ui_components:
path: ../ui_components
transformers:
- sass
- polymer:
Expand Down
20 changes: 18 additions & 2 deletions saga/lib/src/parser.dart
Expand Up @@ -14,7 +14,10 @@

library parser;

import 'dart:async';

import 'package:petitparser/petitparser.dart' as p;

import 'package:saga/src/flow/node.dart' show BB;

final codeRe = new RegExp(r"^\s+(0x[0-9a-f]+):\s+(?:data32 |rep )?(\w+)([^;#]*)([;#].*)?$");
Expand Down Expand Up @@ -100,10 +103,21 @@ class CallTargetAttribute {
}

class CallTarget {
final ParsedCode owner;

final target;
final attributes = new Set<CallTargetAttribute>();

CallTarget(this.target);
CallTarget(this.owner, this.target);

toggleAttribute(attr) {
if (attributes.contains(attr)) {
attributes.remove(attr);
} else {
attributes.add(attr);
}
owner._changesController.add(null);
}

toString() => "CallTarget($target)";
}
Expand All @@ -119,7 +133,7 @@ class ParsedCode {
final addrMap = new Map<String, int>.fromIterables(code.map((op) => op.addr), new Iterable.generate(code.length));

toCallTarget(addr) =>
callTargets.putIfAbsent(addr, () => new CallTarget(addr));
callTargets.putIfAbsent(addr, () => new CallTarget(this, addr));

var blockStarted = false;
for (var i = 0; i < code.length; i++) {
Expand Down Expand Up @@ -202,6 +216,8 @@ class ParsedCode {
return new Ir(new Map.fromIterable(blocks.values, key: (block) => block.name, value: (block) => block), blocks);
}

final _changesController = new StreamController.broadcast();
get changes => _changesController.stream;
}

parse(String text) => new ParsedCode(text);
Expand Down
217 changes: 217 additions & 0 deletions saga/lib/src/ui/code_pane.dart
@@ -0,0 +1,217 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

library saga.ui.code_pane;

import 'dart:html';

import 'package:liquid/liquid.dart';
import 'package:liquid/vdom.dart' as v;
import 'package:ui_utils/bootstrap.dart' as bs;
import 'package:ui_utils/delayed_reaction.dart';
import 'package:ui_utils/xref.dart';

import 'package:saga/src/parser.dart' as parser;
import 'package:saga/src/util.dart';


render(Element pane, flowData, {keepScroll: false}) {
final codePane = new CodePane()..flowData = flowData;
if (keepScroll) {
final scroll = pane.scrollTop;
codePane.whenRendered = () => pane.scrollTop = scroll;
}

pane.nodes.clear();
injectComponent(codePane, pane);
}

vLabel(txt) => v.span(classes: const ['asm-label'])(txt);
vKeyword(txt) => v.span(classes: const ['asm-opcode'])(txt);

final vCallTarget = v.componentFactory(CallTargetComponent);
class CallTargetComponent extends Component {
@property() parser.CallTarget callTarget;

create() {
element = new SpanElement();
}

var menuVisible = false;
final delayedHide = new DelayedReaction(delay: const Duration(milliseconds: 150));

hideMenu() {
delayedHide.schedule(() {
bs.popover(element).destroy();
menuVisible = false;
});
}

init() {
element.onMouseOver.listen((_) {
if (!menuVisible) {
var po = bs.popover(element, {
"title": '',
"content": parser.CallTargetAttribute.values.map((attr) => "<button class='${callTarget.attributes.contains(attr) ? 'set' : ''}' data-attr='${attr.name}'>((${attr}))</button>"),
"trigger": "manual",
"placement": "top",
"html": true,
"container": element
})..show();
po.tip.onMouseOver.listen((_) => delayedHide.cancel());
po.tip.onMouseOut.listen((_) => hideMenu());
menuVisible = true;
} else {
delayedHide.cancel();
}
});
element.onMouseOut.listen((_) => hideMenu());

element.onClick.listen((e) {
final attrName = e.target.attributes['data-attr'];
if (attrName != null) {
final attr = parser.CallTargetAttribute.parse(attrName);
callTarget.toggleAttribute(attr);
}
});
}

build() =>
v.root(classes: const ['asm-call-target'])(callTarget.target);
}

class CodePane extends Component {
var flowData;

var whenRendered;
rendered() => whenRendered();

var entities = {};
var entitiesArray = [];

void init() {
lookup(def) {
/*if (def is flow.Use) {
return lookup(def.def);
} if (def is flow.Phi) {
return "<small>${def}</small>\n" + def.inputs.where((v) => v.def != def).map(lookup).join('\n');
} else if (def is flow.Select) {
return [lookup(def.thenValue),
lookup(def.elseValue),
lookup(def.inputs[0].def),
"${def.origin} in ${def.block.origin.name}"].join('\n');
} else if (def.origin != null) {
return "${def.origin} in ${def.block.origin.name}";
}*/
return def.toString();
}

element.onMouseOver.listen((e) {
final key = e.target.attributes['data-entity'];
if (key != null) {
final use = flowData.refUses[entities[key]];
if (use != null && use.def != null) {
final text = lookup(use.def);
if (text != null) {
POPOVER.show(e.target, "<pre>${text}</pre>");
}
}
}
});

element.onMouseOut.listen((e) {
final key = e.target.attributes['data-entity'];
if (key != null) {
POPOVER.destroy(e.target);
}
});
}

build() {
entities.clear();
var children = [];
for (var block in flowData.blocks.values) buildBlock(children, block);
return v.root()(children);
}

toEntity(ref) {
final key = "${entities.length}";
entities[key] = ref;
return key;
}

List<v.VNode> formatOperand(val) {
if (val is parser.RegRef) {
return [v.span(classes: const ['asm-register'], attributes: {"data-entity": toEntity(val)})(val.name)];
} else if (val is parser.Addr) {
final List<v.VNode> result = [v.text("[")];
if (val.base != null) result.addAll(formatOperand(val.base));
if (val.index != null) {
if (val.base != null) result.add(v.text(" + "));
result.addAll(formatOperand(val.index));
if (val.scale != 1) {
result.add(v.text("*"));
result.add(v.span(classes: const ['asm-immediate'])("${val.scale}"));
}
}
if (val.offset != null && val.offset != 0) {
final isAbsolute = val.base == null && val.index == null;
var offset = val.offset;
if (!isAbsolute) {
var negative = false;
if (offset.startsWith("-")) {
negative = true;
offset = offset.substring(1);
}
result.add(v.text(" ${negative ? '-' : '+'} "));
}
result.add(v.span(classes: const ['asm-immediate'])(offset));
}
result.add(v.text(']'));
return result;
} else if (val is parser.Imm) {
return [v.span(classes: const ['asm-immediate'])(val.value)];
} else if (val is parser.CallTarget) {
return [vCallTarget(callTarget: val)];
} else {
throw "error: ${val.runtimeType}";
}
}

List<v.VNode> format(op) {
if (op.opcode.startsWith("j")) {
return [vKeyword(op.opcode), v.text(" "), vLabel("->${op.operands.first}")];
} else {
return [vKeyword(op.opcode), v.text(" ")]
..addAll(intersperse(op.operands.reversed.map(formatOperand), () => [v.text(', ')]).expand((l) => l));
}
}

buildBlock(List<v.VNode> result, block) {
result.add(vLabel("${block.name}:"));
if (block.predecessors.length > 1) {
result.add(v.text(" ("));
result.addAll(intersperse(block.predecessors.map((p) => vLabel("${p.name}")), () => v.text(", ")));
result.add(v.text(")"));
}
result.add(v.text("\n"));
for (var op in block.asm) {
result
..add(v.text(" "))
..addAll(format(op))
..add(v.text("\n"));
}
result.add(v.text("\n"));
}
}
19 changes: 2 additions & 17 deletions saga/lib/src/ui/ir_pane/ir_pane.dart
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

library ir_pane;
library saga.ui.ir_pane;

import 'dart:html' as html;

Expand All @@ -22,22 +22,7 @@ import 'package:liquid/vdom.dart' as v;

import 'package:saga/src/flow/cpu_register.dart';
import 'package:saga/src/flow/node.dart' as node;

intersperseValue(it, val) sync* {
var comma = false;
for (var v in it) {
if (comma) yield val; else comma = true;
yield v;
}
}

intersperse(it, f) sync* {
var comma = false;
for (var v in it) {
if (comma) yield f(); else comma = true;
yield v;
}
}
import 'package:saga/src/util.dart';

render(html.Element pane, Map<String, node.BB> blocks) {
pane.children.clear();
Expand Down

0 comments on commit 40c2b40

Please sign in to comment.