Write spans out in a separate object file section. This allows to merge

duplicate spans in an object file and more extensions to come.


git-svn-id: svn://svn.cc65.org/cc65/trunk@5250 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz
2011-08-21 19:08:23 +00:00
parent 37ac033370
commit 358ccf236e
18 changed files with 396 additions and 111 deletions

View File

@@ -34,21 +34,107 @@
/* common */
#include "hashfunc.h"
#include "hashtab.h"
#include "xmalloc.h"
/* ca65 */
#include "global.h"
#include "objfile.h"
#include "segment.h"
#include "span.h"
/*****************************************************************************/
/* Forwards */
/*****************************************************************************/
static unsigned HT_GenHash (const void* Key);
/* Generate the hash over a key. */
static const void* HT_GetKey (const void* Entry);
/* Given a pointer to the user entry data, return a pointer to the key */
static int HT_Compare (const void* Key1, const void* Key2);
/* Compare two keys. The function must return a value less than zero if
* Key1 is smaller than Key2, zero if both are equal, and a value greater
* than zero if Key1 is greater then Key2.
*/
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Hash table functions */
static const HashFunctions HashFunc = {
HT_GenHash,
HT_GetKey,
HT_Compare
};
/* Span hash table */
static HashTable SpanTab = STATIC_HASHTABLE_INITIALIZER (1051, &HashFunc);
/*****************************************************************************/
/* Hash table functions */
/*****************************************************************************/
static unsigned HT_GenHash (const void* Key)
/* Generate the hash over a key. */
{
/* Key is a Span pointer */
const Span* S = Key;
/* Hash over a combination of segment number, start and end */
return HashInt ((S->Seg->Num << 28) ^ (S->Start << 14) ^ S->End);
}
static const void* HT_GetKey (const void* Entry)
/* Given a pointer to the user entry data, return a pointer to the key */
{
return Entry;
}
static int HT_Compare (const void* Key1, const void* Key2)
/* Compare two keys. The function must return a value less than zero if
* Key1 is smaller than Key2, zero if both are equal, and a value greater
* than zero if Key1 is greater then Key2.
*/
{
/* Convert both parameters to Span pointers */
const Span* S1 = Key1;
const Span* S2 = Key2;
/* Compare segment number, then start and end */
int Res = (int)S2->Seg->Num - (int)S1->Seg->Num;
if (Res == 0) {
Res = (int)S2->Start - (int)S1->Start;
if (Res == 0) {
Res = (int)S2->End - (int)S1->End;
}
}
/* Done */
return Res;
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@@ -64,9 +150,12 @@ static Span* NewSpan (Segment* Seg, unsigned long Start, unsigned long End)
Span* S = xmalloc (sizeof (Span));
/* Initialize the struct */
InitHashNode (&S->Node);
S->Id = ~0U;
S->Seg = Seg;
S->Start = Start;
S->End = End;
S->Type = 0;
/* Return the new struct */
return S;
@@ -82,7 +171,68 @@ static void FreeSpan (Span* S)
void OpenSpans (Collection* Spans)
static Span* MergeSpan (Span* S)
/* Check if we have a span with the same data as S already. If so, free S and
* return the already existing one. If not, remember S and return it.
*/
{
/* Check if we have such a span already. If so use the existing
* one and free the one from the collection. If not, add the one to
* the hash table and return it.
*/
Span* E = HT_Find (&SpanTab, S);
if (E) {
/* If S has a type and E not, move the type */
CHECK (E->Type == 0);
E->Type = S->Type;
S->Type = 0;
/* Free S and return E */
FreeSpan (S);
return E;
} else {
/* Assign the id, insert S, then return it */
S->Id = HT_GetCount (&SpanTab);
HT_Insert (&SpanTab, S);
return S;
}
}
Span* OpenSpan (void)
/* Open a span for the active segment and return it. */
{
return NewSpan (ActiveSeg, ActiveSeg->PC, ActiveSeg->PC);
}
Span* CloseSpan (Span* S)
/* Close the given span. Be sure to replace the passed span by the one
* returned, since the span will get deleted if it is empty or may be
* replaced if a duplicate exists.
*/
{
/* Set the end offset */
if (S->Start == S->Seg->PC) {
/* Span is empty */
FreeSpan (S);
return 0;
} else {
/* Span is not empty */
S->End = S->Seg->PC;
/* Check if we have such a span already. If so use the existing
* one and free the one from the collection. If not, add the one to
* the hash table and return it.
*/
return MergeSpan (S);
}
}
void OpenSpanList (Collection* Spans)
/* Open a list of spans for all existing segments to the given collection of
* spans. The currently active segment will be inserted first with all others
* following.
@@ -109,7 +259,7 @@ void OpenSpans (Collection* Spans)
void CloseSpans (Collection* Spans)
void CloseSpanList (Collection* Spans)
/* Close a list of spans. This will add new segments to the list, mark the end
* of existing ones, and remove empty spans from the list.
*/
@@ -141,7 +291,9 @@ void CloseSpans (Collection* Spans)
} else {
/* Span is not empty */
S->End = S->Seg->PC;
CollReplace (Spans, S, J++);
/* Merge duplicate spans, then insert it at the new position */
CollReplace (Spans, MergeSpan (S), J++);
}
}
@@ -151,37 +303,96 @@ void CloseSpans (Collection* Spans)
static void WriteSpan (const Span* S)
/* Write one span to the output file */
{
/* Done accept empty spans */
CHECK (S->End > S->Start);
/* Write data for the span We will write the size instead of the end
* offset to save some bytes, since most spans are expected to be
* rather small.
*/
ObjWriteVar (S->Seg->Num);
ObjWriteVar (S->Start);
ObjWriteVar (S->End - S->Start);
}
void WriteSpans (const Collection* Spans)
void WriteSpanList (const Collection* Spans)
/* Write a list of spans to the output file */
{
unsigned I;
/* Write the number of spans */
ObjWriteVar (CollCount (Spans));
/* We only write spans if debug info is enabled */
if (DbgSyms == 0) {
/* Number of spans is zero */
ObjWriteVar (0);
} else {
/* Write the number of spans */
ObjWriteVar (CollCount (Spans));
/* Write the spans */
for (I = 0; I < CollCount (Spans); ++I) {
/* Write the next span */
WriteSpan (CollConstAt (Spans, I));
/* Write the spans */
for (I = 0; I < CollCount (Spans); ++I) {
/* Write the id of the next span */
ObjWriteVar (((const Span*)CollConstAt (Spans, I))->Id);
}
}
}
static int CollectSpans (void* Entry, void* Data)
/* Collect all spans in a collection sorted by id */
{
/* Cast the pointers to real objects */
Span* S = Entry;
Collection* C = Data;
/* Place the entry into the collection */
CollReplaceExpand (C, S, S->Id);
/* Keep the span */
return 0;
}
void WriteSpans (void)
/* Write all spans to the object file */
{
/* Tell the object file module that we're about to start the spans */
ObjStartSpans ();
/* We will write scopes only if debug symbols are requested */
if (DbgSyms) {
unsigned I;
/* We must first collect all items in a collection sorted by id */
Collection SpanList = STATIC_COLLECTION_INITIALIZER;
CollGrow (&SpanList, HT_GetCount (&SpanTab));
/* Walk over the hash table and fill the span list */
HT_Walk (&SpanTab, CollectSpans, &SpanList);
/* Write the span count to the file */
ObjWriteVar (CollCount (&SpanList));
/* Write all spans */
for (I = 0; I < CollCount (&SpanList); ++I) {
/* Get the span and check it */
const Span* S = CollAtUnchecked (&SpanList, I);
CHECK (S->End > S->Start);
/* Write data for the span We will write the size instead of the
* end offset to save some bytes, since most spans are expected
* to be rather small.
*/
ObjWriteVar (S->Seg->Num);
ObjWriteVar (S->Start);
ObjWriteVar (S->End - S->Start);
}
/* Free the collection with the spans */
DoneCollection (&SpanList);
} else {
/* No debug info requested */
ObjWriteVar (0);
}
/* Done writing the spans */
ObjEndSpans ();
}