public Object readObject()
          throws IOException {
    final int cfaslOpcode = readCfaslOpcode();
    Object o = null;
    if (trace == API_TRACE_DETAILED) {
      debugNote("reading opcode = " + cfaslOpcode + " ("
              + CFASL_OPCODE_DESCRIPTIONS.get(cfaslOpcode) + ")");
    }
    if (cfaslOpcode >= CFASL_IMMEDIATE_FIXNUM_OFFSET) {
      o = cfaslOpcode - CFASL_IMMEDIATE_FIXNUM_OFFSET;
      if (trace == API_TRACE_DETAILED) {
        debugNote("Reading Immediate Fixnum: " + o);
      }
    }
    if (o == null) {
      o = maybeReadNumber(cfaslOpcode);
    }
    if (o == null) {
      o = maybeReadSymbol(cfaslOpcode);
    }
    if (o == null) {
      o = maybeReadSequence(cfaslOpcode);
    }
    if (o == null) {
      o = maybeReadOther(cfaslOpcode);
    }

    if (trace == API_TRACE_DETAILED) {
      try {
        // If object o understands the safeToString method, then use it.
        Method safeToString = o.getClass().getMethod("safeToString");
        debugNote("readObject = " + safeToString.invoke(o) + " (" + o.getClass() + ")");
      } catch (Exception e) {
        debugNote("readObject = " + o + " (" + o.getClass() + ")");
      }
    }

    return o;
  }