/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (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.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ // // File: HTMLMethodDump.cpp // Author: Simon Holmes a Court // #include "Fundamentals.h" #ifdef DEBUG_LOG #include "LogModule.h" #include "HTMLMethodDump.h" #include "NativeFormatter.h" #include "FieldOrMethod.h" #include "ExceptionTable.h" #include "ControlGraph.h" #include //----------------------------------------------------------------------------------------------------------- // Native Formatter method UT_DEFINE_LOG_MODULE(MethodToHtml); void dumpDissasembly(LogModuleObject &f, Uint8* start, Uint8* end) { if (end <= start) // this happens for the last node, or nodes without code return; Uint8* curAddr = start; while ((curAddr != NULL) && (curAddr < end)) curAddr = (Uint8*) disassemble1(f, curAddr); } static void dumpHTMLByteCode(MethodToHTML output, Method* inMethod) { UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n
\n")); output.heading("ByteCode"); UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n
\n
\n"));
	inMethod->dumpBytecodeDisassembly(output.mFile);
	UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("
\n")); } static void dumpHTMLExceptionTable(MethodToHTML output, ExceptionTable& inExceptionTable, ControlNode** nodes, Uint32 nNodes) { UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n
\n")); output.heading("Exception Table"); UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n
\n
"));
	inExceptionTable.print(output.mFile);
	UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("
\n")); inExceptionTable.printFormatted(output.mFile, nodes, nNodes, true); } void NativeFormatter:: dumpMethodToHTML(FormattedCodeInfo& fci, ExceptionTable& inExceptionTable) { // create and prepare the output file MethodToHTML output; output.mFile.setLogLevel(PR_LOG_ALWAYS); output.mFile.setOptions(PR_LOG_OPTION_NIL); assert(fci.method); #if defined(XP_PC) || defined(LINUX) if (*fci.methodStart == 0xcc) fci.methodStart++; #endif // get clean name const char* oldname = fci.method->getName(); char* name = new char[strlen(oldname) + 1]; strcpy(name, oldname); char* q = name; while(*q) { switch(*q) { case ':': case '<': case '>': case '/': case ' ': *q = '_'; } q++; } const char* filename = fci.method->getHTMLName(); // open file a clean filename output.openFile(filename); output.pageBegin(name); // stats const char* className = fci.method->getDeclaringClass()->getName(); output.statsBegin(); output.bigstatsLine("Name", name); output.statsLine("Class/Name/Sig", className, name, fci.method->getSignatureString()); output.statsLine("Fully qualified name", fci.method->toString()); output.statsLine("HTML File Name", filename); output.statsLine("Native Code Bytes", fci.methodEnd - fci.methodStart); time_t currentTime; // output the time time(¤tTime); output.statsLine("Created", ctime(¤tTime)); output.statsEnd(); // disassemble bytecode dumpHTMLByteCode(output, fci.method); // disassemble output.heading("Generated Code"); output.disassemblyTableBegin(); // dump prolog Uint8* curOffset; curOffset = fci.methodStart; output.disassemblyRowBegin("Pre"); dumpDissasembly(output.mFile, curOffset, curOffset + fci.preMethodSize); curOffset += fci.preMethodSize; output.disassemblyColumnSeparator(0xeeeeee); output.disassemblyColumnSeparator(0xdddddd); output.disassemblyRowEnd(); output.disassemblyRowBegin("Pro"); dumpDissasembly(output.mFile, curOffset, curOffset + fci.prologSize); curOffset += fci.prologSize; output.disassemblyColumnSeparator(0xeeeeee); output.disassemblyColumnSeparator(0xdddddd); output.disassemblyRowEnd(); // dump methods nodes[0]->controlGraph.dfsSearch(); nodes[0]->controlGraph.assignProducerNumbers(1); // now go through and print out the high level representation (w/o prolog etc) for (Uint32 n = 0; n < nNodes; n++) { ControlNode& node = *nodes[n]; output.disassemblyRowBegin(node.dfsNum); // actual disassembly Uint8* nodeStart; Uint8* nodeEnd; nodeStart = curOffset; if (n != (nNodes - 1)) nodeEnd = fci.methodStart + nodes[n+1]->getNativeOffset(); else // last node nodeEnd = fci.methodEnd; curOffset = nodeEnd; dumpDissasembly(output.mFile, nodeStart, nodeEnd); output.disassemblyColumnSeparator(0xeeeeee); // intended disassembly InstructionList& instructions = node.getInstructions(); for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) { instructions.get(i).printPretty(output.mFile); UT_OBJECTLOG(output.mFile, PR_LOG_ALWAYS, ("\n")); } // primitive graph output.disassemblyColumnSeparator(0xdddddd); node.printPretty(output.mFile, 0); output.disassemblyRowEnd(); } output.disassemblyTableEnd(); // exception table dumpHTMLExceptionTable(output, inExceptionTable, nodes, nNodes); output.pageEnd(); output.closeFile(); // add this file reference to the index file FileIndex::insertFile(filename, name, className); FileIndex::output(); // FIX FIX FIX for now we output this file EVERY time we generate code } //----------------------------------------------------------------------------------------------------------- FileIndex FileIndex::sFileIndex; void FileIndex:: outputHelper() { // open the index file FILE* f = fopen("index.html","w"); assert(f); // print the header fprintf(f, "\n\nGenerated Code Index\n\n" "\n\n" ); // output links ClassNode* c = classes; while(c) { fprintf(f, "\n
%s
\n", c->className); FileNode* n = c->files; while(n) { fprintf(f, "\t%s
\n", n->fileName, n->methodName); n = n->next; } c = c->next; } // output footers fprintf(f, "\n\n\n"); fclose(f); } ClassNode* FileIndex:: findClassName(const char* className) { if(classes == NULL) { classes = new ClassNode(className); return classes; } // search for a class object if there is one ClassNode* foundClass = classes; while(true) { if(strncmp(foundClass->className, className, 512) == 0) return foundClass; // no match, if end, make new node if(foundClass->next == NULL) { foundClass->next = new ClassNode(className); return foundClass->next; } else foundClass = foundClass->next; } } void FileIndex:: insertFileHelper(const char* inFileName, const char* inMethodName, const char* inClassName) { ClassNode* classnode = findClassName(inClassName); FileNode* firstNode = classnode->files; FileNode* newNode = new FileNode(inFileName, inMethodName); if(firstNode == NULL) { classnode->files = newNode; return; } // is it before the first? if(strncmp(inMethodName, firstNode->methodName, 512) < 0) { classnode->files = newNode; newNode->next = firstNode; return; } // otherwise iterate through until we are after a node and then insert FileNode* node = firstNode; while(true) { if( node->next == NULL || // at end (strncmp(inMethodName, node->next->methodName, 512) < 0) ) // lexically before next name { FileNode* tempNode = node->next; node->next = newNode; newNode->next = tempNode; return; } node = node->next; } } //----------------------------------------------------------------------------------------------------------- // Debugging Code for outputting Exception Tables static void tableBegin(LogModuleObject &f, bool isHTML) { if(isHTML) UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("
\n\n")); } static void tableEnd(LogModuleObject &f, bool isHTML) { isHTML ? UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("
\n
\n")) : UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n\n\n")); } static void heading(LogModuleObject &f, Uint32 num, bool isHTML) { if(isHTML) UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%d", num)); else UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" %02d ", num)); } static void rowBegin(LogModuleObject &f, bool isHTML) { if(isHTML) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Node")); UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("Offset")); } else UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N ")); } static void nodeRowBegin(LogModuleObject &f, Uint32 node, Uint32 offset, bool isHTML) { if(isHTML) { UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N%d", node)); UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("%d ", offset)); } else UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("N%02d: %4d ", node, offset)); } static void rowEnd(LogModuleObject &f, bool isHTML) { isHTML ? UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n")) : UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("\n")); } static void printInside(LogModuleObject &f, bool isHTML) { isHTML ? UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" ")) : UT_OBJECTLOG(f, PR_LOG_ALWAYS, ("| ")); } static void printOutside(LogModuleObject &f, Uint32 col, bool isHTML) { if(isHTML) if(col&1) UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" ")); else UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" ")); else UT_OBJECTLOG(f, PR_LOG_ALWAYS, (" ")); } void ExceptionTable:: printFormatted(LogModuleObject &f, ControlNode** inNodes, Uint32 numNodes, bool isHTML) { Uint32 col; if(numberofEntries == 0) return; // print headers tableBegin(f, isHTML); rowBegin(f, isHTML); for(col = 0; col < numberofEntries; col++) heading(f, col, isHTML); rowEnd(f, isHTML); // print table for (Uint32 i = 0; i < numNodes; i++) { ControlNode* node = inNodes[i]; Uint32 pc = node->getNativeOffset(); nodeRowBegin(f, node->dfsNum, pc, isHTML); for(col = 0; col < numberofEntries; col++) if (pc >= mEntries[col].pStart && pc < mEntries[col].pEnd) printInside(f, isHTML); else printOutside(f, col, isHTML); rowEnd(f, isHTML); } tableEnd(f, isHTML); } //----------------------------------------------------------------------------------------------------------- // Debugging Code for outputting HTML pages void MethodToHTML:: openFile(const char* fileName) { // open the file if (!mFile.setLogFile(fileName)) trespass("opening log file failed"); } void MethodToHTML:: closeFile() { mFile.flushLogFile(); // fclose(mFile); } void MethodToHTML:: pageBegin(const char* name) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n%s\n\n", name)); UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n")); } // Heading void MethodToHTML:: heading(const char* label) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("%s
\n", label)); } // Stats void MethodToHTML:: statsBegin() { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n\n\n")); } void MethodToHTML:: statsLine(const char* label, const char* value) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n", label, value)); } void MethodToHTML:: bigstatsLine(const char* label, const char* value) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n" "\n\n", label, value)); } void MethodToHTML:: statsLine(const char* label, const int value) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n", label, value)); } void MethodToHTML:: statsLine(const char* label, const char* value1, const char* value2, const char* value3) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n", label, value1, value2, value3)); } void MethodToHTML:: statsEnd() { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("
%s%s
%s%s
%s%d
%s%s %s %s
\n
\n
 \n
 \n\ngo to index\n
 \n
 \n\n")); } // disassembly void MethodToHTML:: disassemblyTableBegin() { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n")); UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n")); UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n")); UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n")); UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n" )); } void MethodToHTML:: disassemblyRowBegin(Uint32 nodeNum) { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n\n\n\n\n\n\n\n\n\n\n")); } void MethodToHTML:: disassemblyTableEnd() { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("
Node
Disassembly
Intended Code
Primitives
N%d" "
", nodeNum, nodeNum));
}

void MethodToHTML::
disassemblyRowBegin(const char* label)
{
	UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n\n
%s" "
", label, label));
}

void MethodToHTML::
disassemblyColumnSeparator(Uint32 color)
{
	UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, (" 
", color));
}

void MethodToHTML::
disassemblyRowEnd()
{
	UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, (" 
\n\n")); } void MethodToHTML:: pageEnd() { UT_OBJECTLOG(mFile, PR_LOG_ALWAYS, ("\n\n\n")); } //----------------------------------------------------------------------------------------------------------- #endif // DEBUG_LOG