Princeton University
COS 217: Introduction to Programming Systems

The SymTable ADT and the Execution Profiler

The Problem

Your execution profiler's __count function should be a client of your SymTable ADT.  Specifically, you will find it convenient to define your __count function so it creates and uses a SymTable object that relates each assembly language function name (of type string) to a unique index (of type int).  Thus your SymTable object should contain bindings whose values are integers. However, a SymTable object stores its values as void pointers. So the problem is this: how can you store integers as values within a SymTable object when it expects them to be void pointers? 

There are two solutions...

Solution 1

On the hats cluster, it happens that the amount memory required to store an integer (4 bytes) is the same as the amount of memory required to store a void pointer, or a pointer of any type. Thus you can use the cast operator to "trick" the compiler into generating code that will store integers as void pointers, using statements similar to these:

SymTable_put(oSymTable, "main", (void*)0);
...
SymTable_put(oSymTable, "quicksort", (void*)1);
...
iIndex = (int)SymTable_get(oSymTable, "main");
...
iIndex = (int)SymTable_get(oSymTable, "quicksort");

Note that solution1 works on only those systems for which sizeof(int) <= sizeof(void*).

Solution 2

The second solution is to place each integer in memory, and then store memory addresses in the SymTable object. Since you do not know a priori how many integers you will need, you must allocate that memory dynamically.  The code will be similar to this:

pi = (int*)malloc(sizeof(int));
*pi = 0;
SymTable_put(oSymTable, "main", pi);
...
pi = (int*)malloc(sizeof(int));
*pi = 1;
SymTable_put(oSymTable, "quicksort", pi);
...
iIndex = *(int*)SymTable_get(oSymTable, "main");
...
iIndex = *(int*)SymTable_get(oSymTable, "quicksort");

Of course you must free the memory in which each integer resides when that memory is no longer needed.  You can do that by mapping a "freeInt" function (which you must define) across all values in the SymTable object:

SymTable_map(oSymTable, freeInt, NULL);

Note that solution 2 works on any system.

Which Solution is Better?

Solution 1 is more efficient but less portable. Solution 2 is less efficient but completely portable.

Usually portability is more important than efficiency, so in the general case we recommend Solution 2.  However, the execution profiler for this assignment is inherently specific to the IA-32 architecture, and so is inherently non-portable.  So for this assignment it is acceptable to use Solution 1.