1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is [Open Source Virtual Machine].
16 * The Initial Developer of the Original Code is
17 * Adobe System Incorporated.
18 * Portions created by the Initial Developer are Copyright (C) 2004-2007
19 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
41 #define verbose_draw_only(x)
45 #ifdef AVMPLUS_VERBOSE
46 using namespace avmplus
;
48 TraceTreeDrawer::TraceTreeDrawer(Fragmento
*frago
, AvmCore
*core
, char *fileName
) {
51 this->_labels
= frago
->labels
;
52 this->_fileName
= fileName
;
55 TraceTreeDrawer::~TraceTreeDrawer() {
58 void TraceTreeDrawer::addNode(Fragment
*fragment
, const char *color
) {
59 fprintf(_fstream
, "<node id=\"%d\">\n"
60 "<data key=\"nodeGraphicsID\">\n"
62 "<y:Shape type=\"roundrectangle\"/>\n"
63 "<y:NodeLabel alignment=\"center\">%s"
66 "<y:Fill color=\"#%s\" transparent=\"false\"/>\n"
71 _labels
->format(fragment
),
72 _labels
->format(fragment
->ip
), color
);
75 void TraceTreeDrawer::addNode(Fragment
*fragment
) {
76 if (!fragment
->isAnchor())
77 addNode(fragment
, "FFCC99"); // standard color
79 addNode(fragment
, "CCFFFF"); // Root node
82 void TraceTreeDrawer::addEdge(Fragment
*from
, Fragment
*to
) {
87 fprintf(_fstream
, "<edge directed=\"true\" source=\"%d\" target=\"%d\">\n", (int)from
, (int)to
);
89 fprintf(_fstream
, "</edge>\n");
92 void TraceTreeDrawer::recursiveDraw(Fragment
*root
) {
93 if (!isCompiled(root
)) {
99 Fragment
*lastDrawnBranch
= root
;
100 for (Fragment
*treeBranch
= root
->branches
; treeBranch
!= 0; treeBranch
= treeBranch
->nextbranch
) {
101 if (!isMergeFragment(treeBranch
)) {
102 struct SideExit
* exit
= treeBranch
->spawnedFrom
->exit();
103 if (isValidSideExit(exit
) && isCompiled(treeBranch
)) {
104 verbose_draw_only(printf("Adding edge between %s and %s\n", _labels
->format(lastDrawnBranch
), _labels
->format(treeBranch
)));
106 this->addEdge(lastDrawnBranch
, treeBranch
);
107 lastDrawnBranch
= treeBranch
;
110 recursiveDraw(treeBranch
);
113 addMergeNode(treeBranch
);
118 void TraceTreeDrawer::addBackEdges(Fragment
*root
) {
119 // At the end of a tree, find out where it goes
120 if (isCrossFragment(root
)) {
121 if (root
->eot_target
) {
122 verbose_draw_only(printf("Found a cross fragment %s TO %s \n", _labels
->format(root
), _labels
->format(root
->eot_target
)));
123 this->addEdge(root
, root
->eot_target
);
126 else if (isBackEdgeSideExit(root
)) {
127 verbose_draw_only(printf("Adding anchor branch edge from %s TO %s\n", _labels
->format(root
), _labels
->format(root
->anchor
)));
128 this->addEdge(root
, root
->anchor
);
130 else if (isSingleTrace(root
)) {
131 verbose_draw_only(printf("Found a single trace %s\n", _labels
->format(root
)));
132 this->addEdge(root
, root
);
134 else if (isSpawnedTrace(root
)) {
135 struct SideExit
*exit
= root
->spawnedFrom
->exit();
136 if (isValidSideExit(exit
) && isCompiled(root
)) {
137 verbose_draw_only(printf("Found a spawned side exit from %s that is a spawn and compiled %s\n", _labels
->format(root
), _labels
->format(exit
->from
)));
138 this->addEdge(root
, root
->parent
);
141 else if (hasEndOfTraceFrag(root
)) {
142 verbose_draw_only(printf("%s has an EOT to %s\n", _labels
->format(root
), _labels
->format(root
->eot_target
)));
143 addEdge(root
, root
->eot_target
);
147 void TraceTreeDrawer::addMergeNode(Fragment
*mergeRoot
) {
148 verbose_draw_only(printf("Found a merge fragment %s and anchor %s\n", _labels
->format(mergeRoot
), _labels
->format(mergeRoot
->anchor
)));
150 if (hasCompiledBranch(mergeRoot
)) {
151 verbose_draw_only(printf("Found a branch to %s\n", _labels
->format(mergeRoot
->branches
)));
152 addEdge(mergeRoot
, mergeRoot
->branches
);
153 recursiveDraw(mergeRoot
->branches
);
156 if (hasEndOfTraceFrag(mergeRoot
)) {
157 verbose_draw_only(printf("Merge with an EOT to %s\n", _labels
->format(mergeRoot
->eot_target
)));
158 addEdge(mergeRoot
, mergeRoot
->eot_target
);
161 verbose_draw_only(printf("Merge to anchor %s\n", _labels
->format(mergeRoot
->anchor
)));
162 addEdge(mergeRoot
, mergeRoot
->anchor
);
166 void TraceTreeDrawer::draw(Fragment
*root
) {
167 this->recursiveDraw(root
);
169 verbose_draw_only(printf("\nFinished drawing, printing status\n"));
170 verbose_draw_only(this->printTreeStatus(root
));
173 void TraceTreeDrawer::createGraphHeader() {
174 char outputFileName
[128];
175 const char *graphMLExtension
= ".graphml";
177 int fileNameLength
= strlen(this->_fileName
);
178 memset(outputFileName
, 0, sizeof(outputFileName
));
179 strncat(outputFileName
, this->_fileName
, 128);
180 strncat(outputFileName
+ fileNameLength
- 1, graphMLExtension
, 128); // -1 to overwrite the \0
182 verbose_draw_only(printf("output file name is %s\n", outputFileName
));
183 this->_fstream
= fopen(outputFileName
, "w");
185 fprintf(_fstream
, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
186 "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns/graphml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:y=\"http://www.yworks.com/xml/graphml\" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns/graphml http://www.yworks.com/xml/schema/graphml/1.0/ygraphml.xsd\">\n"
187 "<key for=\"node\" id=\"nodeGraphicsID\" yfiles.type=\"nodegraphics\"/>\n"
188 "<key attr.name=\"description\" attr.type=\"string\" for=\"node\" id=\"nodeDescID\"/>\n"
189 "<key for=\"edge\" id=\"edgeGraphicsID\" yfiles.type=\"edgegraphics\"/>\n"
190 "<key attr.name=\"description\" attr.type=\"string\" for=\"edge\" id=\"edgeDescID\"/>\n"
191 "<graph edgedefault=\"directed\" id=\"rootGraph\">\n");
195 void TraceTreeDrawer::createGraphFooter() {
196 fprintf(_fstream
, " </graph></graphml>");
197 fclose(this->_fstream
);
200 bool TraceTreeDrawer::isValidSideExit(struct SideExit
*exit
) {
204 bool TraceTreeDrawer::isCompiled(Fragment
*f
) {
205 return f
->compileNbr
!= 0;
208 bool TraceTreeDrawer::isLoopFragment(Fragment
*f
) {
209 return f
->kind
== LoopTrace
;
212 bool TraceTreeDrawer::isCrossFragment(Fragment
*f
) {
213 return f
->kind
== BranchTrace
;
216 bool TraceTreeDrawer::isMergeFragment(Fragment
*f
) {
217 return f
->kind
== MergeTrace
;
220 bool TraceTreeDrawer::isSingleTrace(Fragment
*f
) {
221 return f
->isAnchor() && !hasCompiledBranch(f
);
224 bool TraceTreeDrawer::hasCompiledBranch(Fragment
*f
) {
225 for (Fragment
*current
= f
->branches
; current
!= 0; current
= current
->nextbranch
) {
226 if (isCompiled(current
)) {
234 bool TraceTreeDrawer::isSpawnedTrace(Fragment
*f
) {
235 return f
->spawnedFrom
!= 0;
238 bool TraceTreeDrawer::isBackEdgeSideExit(Fragment
*f
) {
239 return !f
->branches
&& !f
->isAnchor();
242 bool TraceTreeDrawer::hasEndOfTraceFrag(Fragment
*f
) {
243 return (f
->eot_target
) && (f
!= f
->eot_target
);
246 void TraceTreeDrawer::drawDirectedEdge() {
248 fprintf(_fstream
, "<data key=\"edgeGraphicsID\">\n"
250 "<y:Arrows source=\"none\" target=\"standard\"/>\n"
251 "</y:PolyLineEdge>\n"
255 void TraceTreeDrawer::printTreeStatus(Fragment
*root
) {
256 if (!isCompiled(root
)) {
260 printf("\nRoot is %s\n", _labels
->format(root
));
261 if (root
->spawnedFrom
) {
262 if (root
->compileNbr
) {
263 printf("Found a root that is a spawn and compiled %s\n", _labels
->format(root
->parent
));
267 for (Fragment
*x
= root
->branches
; x
!= 0; x
= x
->nextbranch
) {
268 if (x
->kind
!= MergeTrace
) {
269 struct SideExit
* exit
= x
->spawnedFrom
->exit();
270 if (exit
&& x
->compileNbr
) {
271 printf("Found one with an SID and compiled %s\n", _labels
->format(x
));
283 void drawTraceTrees(nanojit::Fragmento
*frago
, nanojit::FragmentMap
* _frags
, avmplus::AvmCore
*core
, char *fileName
) {
284 #ifdef AVMPLUS_VERBOSE
285 nanojit::TraceTreeDrawer
*traceDrawer
= new (core
->gc
) nanojit::TraceTreeDrawer(frago
, core
, fileName
);
286 traceDrawer
->createGraphHeader();
288 int32_t count
= _frags
->size();
289 for (int32_t i
=0; i
<count
; i
++)
291 Fragment
*frag
= _frags
->at(i
);
292 // Count only fragments which have something compiled. Needs the -Dverbose flag
293 if (frag
->compileNbr
) {
294 traceDrawer
->draw(frag
);
298 traceDrawer
->createGraphFooter();