final int markObject(byte[] obj, int offs, ClassDescriptor desc) {
		ClassDescriptor.FieldDescriptor[] all = desc.allFields;

		for (int i = 0, n = all.length; i < n; i++) {
			ClassDescriptor.FieldDescriptor fd = all[i];

			switch (fd.type) {
			case ClassDescriptor.tpBoolean:
			case ClassDescriptor.tpByte:
				offs += 1;
				continue;
			case ClassDescriptor.tpChar:
			case ClassDescriptor.tpShort:
				offs += 2;
				continue;
			case ClassDescriptor.tpInt:
			case ClassDescriptor.tpEnum:
			case ClassDescriptor.tpFloat:
				offs += 4;
				continue;
			case ClassDescriptor.tpLong:
			case ClassDescriptor.tpDouble:
			case ClassDescriptor.tpDate:
				offs += 8;
				continue;
			case ClassDescriptor.tpString:
			case ClassDescriptor.tpClass:
				offs = Bytes.skipString(obj, offs);
				continue;
			case ClassDescriptor.tpObject:
				offs = markObjectReference(obj, offs);
				continue;
			case ClassDescriptor.tpValue:
				offs = markObject(obj, offs, fd.valueDesc);
				continue;
			case ClassDescriptor.tpRaw: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				if (len > 0) {
					offs += len;
				}
				else if (len == -2 - ClassDescriptor.tpObject) {
					markOid(Bytes.unpack4(obj, offs));
					offs += 4;
				}
				else if (len < -1) {
					offs += ClassDescriptor.sizeof[-2 - len];
				}
				continue;
			}
			case ClassDescriptor.tpCustom:
				try {
					ByteArrayObjectInputStream in = new ByteArrayObjectInputStream(
							obj, offs, null, false, true);
					serializer.unpack(in);
					offs = in.getPosition();
				}
				catch (IOException x) {
					throw new StorageError(StorageError.ACCESS_VIOLATION, x);
				}
				continue;
			case ClassDescriptor.tpArrayOfByte:
			case ClassDescriptor.tpArrayOfBoolean: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				if (len > 0) {
					offs += len;
				}
				else if (len < -1) {
					offs += ClassDescriptor.sizeof[-2 - len];
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfShort:
			case ClassDescriptor.tpArrayOfChar: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				if (len > 0) {
					offs += len * 2;
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfInt:
			case ClassDescriptor.tpArrayOfEnum:
			case ClassDescriptor.tpArrayOfFloat: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				if (len > 0) {
					offs += len * 4;
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfLong:
			case ClassDescriptor.tpArrayOfDouble:
			case ClassDescriptor.tpArrayOfDate: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				if (len > 0) {
					offs += len * 8;
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfString: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				while (--len >= 0) {
					offs = Bytes.skipString(obj, offs);
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfObject: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				while (--len >= 0) {
					offs = markObjectReference(obj, offs);
				}
				continue;
			}
			case ClassDescriptor.tpLink: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				while (--len >= 0) {
					markOid(Bytes.unpack4(obj, offs));
					offs += 4;
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfValue: {
				int len = Bytes.unpack4(obj, offs);
				offs += 4;
				ClassDescriptor valueDesc = fd.valueDesc;
				while (--len >= 0) {
					offs = markObject(obj, offs, valueDesc);
				}
				continue;
			}
			case ClassDescriptor.tpArrayOfRaw: {
				int len = Bytes.unpack4(obj, offs);
				offs += 8;
				while (--len >= 0) {
					offs = markObjectReference(obj, offs);
				}
				continue;
			}
			}
		}

		return offs;
	}