final int skipObjectReference(byte[] obj, int offs) throws Exception {
		int oid = Bytes.unpack4(obj, offs);
		int len;
		offs += 4;
		if (oid < 0) {
			int tid = -1 - oid;

			switch (tid) {
			case ClassDescriptor.tpString:
			case ClassDescriptor.tpClass:
				offs = Bytes.skipString(obj, offs);
				break;
			case ClassDescriptor.tpArrayOfByte:
				len = Bytes.unpack4(obj, offs);
				offs += len + 4;
				break;
			case ClassDescriptor.tpArrayOfObject:
				len = Bytes.unpack4(obj, offs);
				offs += 4;

				for (int i = 0; i < len; i++) {
					offs = skipObjectReference(obj, offs);
				}

				break;
			case ClassDescriptor.tpArrayOfRaw:
				len = Bytes.unpack4(obj, offs);
				offs += 8;

				for (int i = 0; i < len; i++) {
					offs = skipObjectReference(obj, offs);
				}

				break;
			default:
				if (tid >= ClassDescriptor.tpValueTypeBias) {
					int typeOid = -ClassDescriptor.tpValueTypeBias - oid;
					ClassDescriptor desc = findClassDescriptor(typeOid);

					if (desc.isCollection) {
						len = Bytes.unpack4(obj, offs);
						offs += 4;

						for (int i = 0; i < len; i++) {
							offs = skipObjectReference(obj, offs);
						}
					}
					else if (desc.isMap) {
						len = Bytes.unpack4(obj, offs);
						offs += 4;

						for (int i = 0; i < len; i++) {
							offs = skipObjectReference(obj, offs);
							offs = skipObjectReference(obj, offs);
						}
					}
					else {
						offs = unpackObject(null, findClassDescriptor(typeOid),
								false, obj, offs, null);
					}
				}
				else {
					offs += ClassDescriptor.sizeof[tid];
				}
			}
		}

		return offs;
	}