void read_trace_file(ifstream & in, CCNode * root)
{
  HeapObject * heapObject;
  HeapObject * targetObject;

  // CCNode * current_node = root;
  theStack[0] = root;
  threadStarts[0] = root;
  CCNode * node;
  int depth = 0;
  int time = 0;
  bool in_death_records = false;
  int last_epoch_time = 0;
  int last_thread_id = 0;

  while (in.good()) {
    char kind;
    string line;
    int object_id;
    int dtime;
    int size;
    string type;
    int method_id;
    string class_name;
    string method_name;
    string signature;
    int old_target;
    int new_target;
    int thread_id;

    Method * method;

    in >> kind;
    // in >> hex >> time;

    /*
    if (in_death_records && (kind != 'D')) {
      in_death_records = false;
      last_epoch_time = time;
    }
    */

    switch (kind) {
    case 'A':
      {
        in >> hex >> object_id;
        in >> hex >> size;
        in >> type;
        in >> hex >> thread_id;
        
        CCNode * curContext = 0;
        
        if (thread_id == object_id) {
          // -- Spawning a new thread -- make it a child of the root
          curContext = root; // theStack[last_thread_id];        
          CCNode * newContext = curContext->demand_child(method_id, thread_id, time);
          newContext->incCalls();
          theStack[thread_id] = newContext;
          if (debug > 0)
            cout << "Spawn thread 0x" << hex << thread_id << dec << endl;
        }
        
        curContext = theStack[thread_id];
        
        curContext->incAllocBytes(size);
        curContext->incAllocObjects();
        heapObject = HeapObject::DemandHeapObject(object_id);
        heapObject->setAlloc(time, size, type);
        heapObject->setAllocCC(curContext);
        
        if (debug > 0) {
          cout << "Allocate 0x" << hex << object_id << " size 0x" << size << dec << " at time " << time << endl;
          if (debug > 1) curContext->printStack();
	}	

	last_thread_id = thread_id;
      }
      objects.push_back(object_id);
      break;
    case 'D':
      {
        in >> hex >> object_id;
        
        heapObject = HeapObject::DemandHeapObject(object_id);
        heapObject->setDead(time);
        (HeapObject::Find(heapObject))->incNumDead();
        
        CCNode * curContext = theStack[last_thread_id];
        
        curContext->incDeadBytes(heapObject->getSize());
        curContext->incDeadObjects();
        heapObject->setDeathCC(curContext);
      }
      break;
    case 'U':
      in >> hex >> old_target;
      in >> hex >> object_id;
      in >> hex >> new_target;
      if (new_target != 0) {
	heapObject = HeapObject::DemandHeapObject(object_id);
	targetObject = HeapObject::DemandHeapObject(new_target);
	HeapObject::Union(heapObject, targetObject);
	if (debug > 0) {
	  cout << "Pointer from 0x" << hex << object_id << " to 0x" << new_target << dec << " at time " << time << endl;
	  if (debug > 1) {
	    CCNode * curContext = theStack[last_thread_id];
	    curContext->printStack();
	  }
	}
      }
      break;
    case 'M':
      {
        in >> hex >> method_id;
        in >> hex >> object_id;
        in >> hex >> thread_id;
        
        CCNode * curContext = theStack[thread_id];
        
        bool new_thread = false;
        if (curContext == 0) {
          // -- Spawning a new thread -- look up the place where the thread was started
          //    Relies on the fact that the thread_id is the same as the object_id of
          //    the Thread object instance.
          new_thread = true;
          curContext = threadStarts[thread_id];
          if (curContext) {
          // if (debug > 0)
            cout << "Spawn thread 0x" << hex << thread_id << dec << " -- started at " << curContext->getMethodFullName() << endl;
            cout << "   in context" << endl;
            curContext->printStack();
          } else {
            cout << "Problem: no threadStart for thread id 0x" << hex << thread_id << dec << endl;
            curContext = root;
          }
        }
        
        time++;
        depth++;
        
        curContext = curContext->demand_child(method_id, thread_id, time);
        curContext->incCalls();
        theStack[thread_id] = curContext;
        
        if (debug > 0 or new_thread) {
          cout << "Enter " << curContext->getMethodFullName() << " 0x" << hex << method_id << " thread 0x" << thread_id << " at time " << time << endl;
          if (debug > 1) curContext->printStack();
	}
	
	if (method_id == thread_start_method_id) {
	  // -- Found a new thread start
	  threadStarts[object_id] = curContext;
	  thread_number++;
	  threadIdNumbering[object_id] = thread_number;
	  if (true) {
	    cout << "Found Thread.start at " << endl;
	    curContext->printStack();
	  }
	}
        
        last_thread_id = thread_id;
      }
      break;
    case 'E':
      {
        in >> hex >> method_id;
        in >> hex >> object_id;
        in >> hex >> thread_id;
        
        CCNode * curContext = theStack[thread_id];

        if (debug > 0) {
	  cout << hex <<  "E " << method_id << " " << object_id << " " << thread_id << endl;
          //cout << "Exit  " << curContext->getMethodFullName() << " 0x" << hex << method_id << " thread 0x" << thread_id << " at time " << time << endl;
	  cout << "Exit: Looking for " << "0x" << hex << method_id <<  " reciever:  0x" << object_id <<  " thread: 0x" << thread_id << endl;
          if (debug > 1) curContext->printStack();
	}	

        time++;
        
        CCNode * returning = curContext;
        int cur_id = returning->getMethodId();
        int orig_depth = depth;
        while (returning and returning->getMethodId() != method_id) {
          returning = returning->getParent();
          depth--;
        }
        
        if (returning == 0) {
          cout << "THIS IS BAD: looking for " 
               << hex << "0x" << method_id << " but found 0x" 
               << cur_id << dec << endl;
          returning->printStack();
          // current_node unchanged
          depth = orig_depth;
        } else {
          // cout << "Return " << current_node->getMethodFullName() << "(" << hex << current_node->getMethodId() << dec << ")" << endl;
          returning->setLastCall(time);
          theStack[thread_id] = returning->getParent();
          depth--;
        }
        
        last_thread_id = thread_id;
      }
      break;
    default:
      cout << "UNKNOWN" << endl;
      break;
    }

    getline(in, line);

    record_count++;
    if (record_count % 1000000 == 0) {
      cerr << "At " << record_count << endl;
    }
  }
}