diff options
Diffstat (limited to 'builtin/index-pack.c')
| -rw-r--r-- | builtin/index-pack.c | 327 | 
1 files changed, 202 insertions, 125 deletions
| diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 723fe8e11d..1ad1bde696 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -18,16 +18,14 @@ static const char index_pack_usage[] =  struct object_entry {  	struct pack_idx_entry idx;  	unsigned long size; -	unsigned int hdr_size; -	enum object_type type; -	enum object_type real_type; -	unsigned delta_depth; -	int base_object_no; +	unsigned char hdr_size; +	signed char type; +	signed char real_type;  }; -union delta_base { -	unsigned char sha1[20]; -	off_t offset; +struct object_stat { +	unsigned delta_depth; +	int base_object_no;  };  struct base_data { @@ -49,31 +47,35 @@ struct thread_local {  	int pack_fd;  }; -/* - * Even if sizeof(union delta_base) == 24 on 64-bit archs, we really want - * to memcmp() only the first 20 bytes. - */ -#define UNION_BASE_SZ	20 -  #define FLAG_LINK (1u<<20)  #define FLAG_CHECKED (1u<<21) -struct delta_entry { -	union delta_base base; +struct ofs_delta_entry { +	off_t offset; +	int obj_no; +}; + +struct ref_delta_entry { +	unsigned char sha1[20];  	int obj_no;  };  static struct object_entry *objects; -static struct delta_entry *deltas; +static struct object_stat *obj_stat; +static struct ofs_delta_entry *ofs_deltas; +static struct ref_delta_entry *ref_deltas;  static struct thread_local nothread_data;  static int nr_objects; -static int nr_deltas; +static int nr_ofs_deltas; +static int nr_ref_deltas; +static int ref_deltas_alloc;  static int nr_resolved_deltas;  static int nr_threads;  static int from_stdin;  static int strict;  static int do_fsck_object; +static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;  static int verbose;  static int show_stat;  static int check_self_contained_and_connected; @@ -191,7 +193,7 @@ static void cleanup_thread(void)  #endif -static int mark_link(struct object *obj, int type, void *data) +static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options)  {  	if (!obj)  		return -1; @@ -439,7 +441,7 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size,  	int hdrlen;  	if (!is_delta_type(type)) { -		hdrlen = sprintf(hdr, "%s %lu", typename(type), size) + 1; +		hdrlen = xsnprintf(hdr, sizeof(hdr), "%s %lu", typename(type), size) + 1;  		git_SHA1_Init(&c);  		git_SHA1_Update(&c, hdr, hdrlen);  	} else @@ -476,7 +478,8 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size,  }  static void *unpack_raw_entry(struct object_entry *obj, -			      union delta_base *delta_base, +			      off_t *ofs_offset, +			      unsigned char *ref_sha1,  			      unsigned char *sha1)  {  	unsigned char *p; @@ -505,11 +508,10 @@ static void *unpack_raw_entry(struct object_entry *obj,  	switch (obj->type) {  	case OBJ_REF_DELTA: -		hashcpy(delta_base->sha1, fill(20)); +		hashcpy(ref_sha1, fill(20));  		use(20);  		break;  	case OBJ_OFS_DELTA: -		memset(delta_base, 0, sizeof(*delta_base));  		p = fill(1);  		c = *p;  		use(1); @@ -523,8 +525,8 @@ static void *unpack_raw_entry(struct object_entry *obj,  			use(1);  			base_offset = (base_offset << 7) + (c & 127);  		} -		delta_base->offset = obj->idx.offset - base_offset; -		if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset) +		*ofs_offset = obj->idx.offset - base_offset; +		if (*ofs_offset <= 0 || *ofs_offset >= obj->idx.offset)  			bad_object(obj->idx.offset, _("delta base offset is out of bound"));  		break;  	case OBJ_COMMIT: @@ -608,55 +610,110 @@ static void *get_data_from_pack(struct object_entry *obj)  	return unpack_data(obj, NULL, NULL);  } -static int compare_delta_bases(const union delta_base *base1, -			       const union delta_base *base2, -			       enum object_type type1, -			       enum object_type type2) +static int compare_ofs_delta_bases(off_t offset1, off_t offset2, +				   enum object_type type1, +				   enum object_type type2) +{ +	int cmp = type1 - type2; +	if (cmp) +		return cmp; +	return offset1 < offset2 ? -1 : +	       offset1 > offset2 ?  1 : +	       0; +} + +static int find_ofs_delta(const off_t offset, enum object_type type) +{ +	int first = 0, last = nr_ofs_deltas; + +	while (first < last) { +		int next = (first + last) / 2; +		struct ofs_delta_entry *delta = &ofs_deltas[next]; +		int cmp; + +		cmp = compare_ofs_delta_bases(offset, delta->offset, +					      type, objects[delta->obj_no].type); +		if (!cmp) +			return next; +		if (cmp < 0) { +			last = next; +			continue; +		} +		first = next+1; +	} +	return -first-1; +} + +static void find_ofs_delta_children(off_t offset, +				    int *first_index, int *last_index, +				    enum object_type type) +{ +	int first = find_ofs_delta(offset, type); +	int last = first; +	int end = nr_ofs_deltas - 1; + +	if (first < 0) { +		*first_index = 0; +		*last_index = -1; +		return; +	} +	while (first > 0 && ofs_deltas[first - 1].offset == offset) +		--first; +	while (last < end && ofs_deltas[last + 1].offset == offset) +		++last; +	*first_index = first; +	*last_index = last; +} + +static int compare_ref_delta_bases(const unsigned char *sha1, +				   const unsigned char *sha2, +				   enum object_type type1, +				   enum object_type type2)  {  	int cmp = type1 - type2;  	if (cmp)  		return cmp; -	return memcmp(base1, base2, UNION_BASE_SZ); +	return hashcmp(sha1, sha2);  } -static int find_delta(const union delta_base *base, enum object_type type) +static int find_ref_delta(const unsigned char *sha1, enum object_type type)  { -	int first = 0, last = nr_deltas; - -        while (first < last) { -                int next = (first + last) / 2; -                struct delta_entry *delta = &deltas[next]; -                int cmp; - -		cmp = compare_delta_bases(base, &delta->base, -					  type, objects[delta->obj_no].type); -                if (!cmp) -                        return next; -                if (cmp < 0) { -                        last = next; -                        continue; -                } -                first = next+1; -        } -        return -first-1; +	int first = 0, last = nr_ref_deltas; + +	while (first < last) { +		int next = (first + last) / 2; +		struct ref_delta_entry *delta = &ref_deltas[next]; +		int cmp; + +		cmp = compare_ref_delta_bases(sha1, delta->sha1, +					      type, objects[delta->obj_no].type); +		if (!cmp) +			return next; +		if (cmp < 0) { +			last = next; +			continue; +		} +		first = next+1; +	} +	return -first-1;  } -static void find_delta_children(const union delta_base *base, -				int *first_index, int *last_index, -				enum object_type type) +static void find_ref_delta_children(const unsigned char *sha1, +				    int *first_index, int *last_index, +				    enum object_type type)  { -	int first = find_delta(base, type); +	int first = find_ref_delta(sha1, type);  	int last = first; -	int end = nr_deltas - 1; +	int end = nr_ref_deltas - 1;  	if (first < 0) {  		*first_index = 0;  		*last_index = -1;  		return;  	} -	while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ)) +	while (first > 0 && !hashcmp(ref_deltas[first - 1].sha1, sha1))  		--first; -	while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ)) +	while (last < end && !hashcmp(ref_deltas[last + 1].sha1, sha1))  		++last;  	*first_index = first;  	*last_index = last; @@ -782,10 +839,9 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,  			if (!obj)  				die(_("invalid %s"), typename(type));  			if (do_fsck_object && -			    fsck_object(obj, buf, size, 1, -				    fsck_error_function)) +			    fsck_object(obj, buf, size, &fsck_options))  				die(_("Error in object")); -			if (fsck_walk(obj, mark_link, NULL)) +			if (fsck_walk(obj, NULL, &fsck_options))  				die(_("Not all child objects of %s are reachable"), sha1_to_hex(obj->sha1));  			if (obj->type == OBJ_TREE) { @@ -873,13 +929,15 @@ static void resolve_delta(struct object_entry *delta_obj,  	void *base_data, *delta_data;  	if (show_stat) { -		delta_obj->delta_depth = base->obj->delta_depth + 1; +		int i = delta_obj - objects; +		int j = base->obj - objects; +		obj_stat[i].delta_depth = obj_stat[j].delta_depth + 1;  		deepest_delta_lock(); -		if (deepest_delta < delta_obj->delta_depth) -			deepest_delta = delta_obj->delta_depth; +		if (deepest_delta < obj_stat[i].delta_depth) +			deepest_delta = obj_stat[i].delta_depth;  		deepest_delta_unlock(); +		obj_stat[i].base_object_no = j;  	} -	delta_obj->base_object_no = base->obj - objects;  	delta_data = get_data_from_pack(delta_obj);  	base_data = get_base_data(base);  	result->obj = delta_obj; @@ -902,7 +960,7 @@ static void resolve_delta(struct object_entry *delta_obj,   * "want"; if so, swap in "set" and return true. Otherwise, leave it untouched   * and return false.   */ -static int compare_and_swap_type(enum object_type *type, +static int compare_and_swap_type(signed char *type,  				 enum object_type want,  				 enum object_type set)  { @@ -921,16 +979,13 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,  						  struct base_data *prev_base)  {  	if (base->ref_last == -1 && base->ofs_last == -1) { -		union delta_base base_spec; +		find_ref_delta_children(base->obj->idx.sha1, +					&base->ref_first, &base->ref_last, +					OBJ_REF_DELTA); -		hashcpy(base_spec.sha1, base->obj->idx.sha1); -		find_delta_children(&base_spec, -				    &base->ref_first, &base->ref_last, OBJ_REF_DELTA); - -		memset(&base_spec, 0, sizeof(base_spec)); -		base_spec.offset = base->obj->idx.offset; -		find_delta_children(&base_spec, -				    &base->ofs_first, &base->ofs_last, OBJ_OFS_DELTA); +		find_ofs_delta_children(base->obj->idx.offset, +					&base->ofs_first, &base->ofs_last, +					OBJ_OFS_DELTA);  		if (base->ref_last == -1 && base->ofs_last == -1) {  			free(base->data); @@ -941,7 +996,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,  	}  	if (base->ref_first <= base->ref_last) { -		struct object_entry *child = objects + deltas[base->ref_first].obj_no; +		struct object_entry *child = objects + ref_deltas[base->ref_first].obj_no;  		struct base_data *result = alloc_base_data();  		if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA, @@ -957,7 +1012,7 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,  	}  	if (base->ofs_first <= base->ofs_last) { -		struct object_entry *child = objects + deltas[base->ofs_first].obj_no; +		struct object_entry *child = objects + ofs_deltas[base->ofs_first].obj_no;  		struct base_data *result = alloc_base_data();  		assert(child->real_type == OBJ_OFS_DELTA); @@ -993,15 +1048,22 @@ static void find_unresolved_deltas(struct base_data *base)  	}  } -static int compare_delta_entry(const void *a, const void *b) +static int compare_ofs_delta_entry(const void *a, const void *b) +{ +	const struct ofs_delta_entry *delta_a = a; +	const struct ofs_delta_entry *delta_b = b; + +	return delta_a->offset < delta_b->offset ? -1 : +	       delta_a->offset > delta_b->offset ?  1 : +	       0; +} + +static int compare_ref_delta_entry(const void *a, const void *b)  { -	const struct delta_entry *delta_a = a; -	const struct delta_entry *delta_b = b; +	const struct ref_delta_entry *delta_a = a; +	const struct ref_delta_entry *delta_b = b; -	/* group by type (ref vs ofs) and then by value (sha-1 or offset) */ -	return compare_delta_bases(&delta_a->base, &delta_b->base, -				   objects[delta_a->obj_no].type, -				   objects[delta_b->obj_no].type); +	return hashcmp(delta_a->sha1, delta_b->sha1);  }  static void resolve_base(struct object_entry *obj) @@ -1047,7 +1109,8 @@ static void *threaded_second_pass(void *data)  static void parse_pack_objects(unsigned char *sha1)  {  	int i, nr_delays = 0; -	struct delta_entry *delta = deltas; +	struct ofs_delta_entry *ofs_delta = ofs_deltas; +	unsigned char ref_delta_sha1[20];  	struct stat st;  	if (verbose) @@ -1056,12 +1119,18 @@ static void parse_pack_objects(unsigned char *sha1)  				nr_objects);  	for (i = 0; i < nr_objects; i++) {  		struct object_entry *obj = &objects[i]; -		void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1); +		void *data = unpack_raw_entry(obj, &ofs_delta->offset, +					      ref_delta_sha1, obj->idx.sha1);  		obj->real_type = obj->type; -		if (is_delta_type(obj->type)) { -			nr_deltas++; -			delta->obj_no = i; -			delta++; +		if (obj->type == OBJ_OFS_DELTA) { +			nr_ofs_deltas++; +			ofs_delta->obj_no = i; +			ofs_delta++; +		} else if (obj->type == OBJ_REF_DELTA) { +			ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc); +			hashcpy(ref_deltas[nr_ref_deltas].sha1, ref_delta_sha1); +			ref_deltas[nr_ref_deltas].obj_no = i; +			nr_ref_deltas++;  		} else if (!data) {  			/* large blobs, check later */  			obj->real_type = OBJ_BAD; @@ -1112,15 +1181,18 @@ static void resolve_deltas(void)  {  	int i; -	if (!nr_deltas) +	if (!nr_ofs_deltas && !nr_ref_deltas)  		return;  	/* Sort deltas by base SHA1/offset for fast searching */ -	qsort(deltas, nr_deltas, sizeof(struct delta_entry), -	      compare_delta_entry); +	qsort(ofs_deltas, nr_ofs_deltas, sizeof(struct ofs_delta_entry), +	      compare_ofs_delta_entry); +	qsort(ref_deltas, nr_ref_deltas, sizeof(struct ref_delta_entry), +	      compare_ref_delta_entry);  	if (verbose) -		progress = start_progress(_("Resolving deltas"), nr_deltas); +		progress = start_progress(_("Resolving deltas"), +					  nr_ref_deltas + nr_ofs_deltas);  #ifndef NO_PTHREADS  	nr_dispatched = 0; @@ -1155,10 +1227,10 @@ static void resolve_deltas(void)   * - append objects to convert thin pack to full pack if required   * - write the final 20-byte SHA-1   */ -static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved); +static void fix_unresolved_deltas(struct sha1file *f);  static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_sha1)  { -	if (nr_deltas == nr_resolved_deltas) { +	if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {  		stop_progress(&progress);  		/* Flush remaining pack final 20-byte SHA1. */  		flush(); @@ -1169,7 +1241,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha  		struct sha1file *f;  		unsigned char read_sha1[20], tail_sha1[20];  		struct strbuf msg = STRBUF_INIT; -		int nr_unresolved = nr_deltas - nr_resolved_deltas; +		int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;  		int nr_objects_initial = nr_objects;  		if (nr_unresolved <= 0)  			die(_("confusion beyond insanity")); @@ -1177,7 +1249,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha  		memset(objects + nr_objects + 1, 0,  		       nr_unresolved * sizeof(*objects));  		f = sha1fd(output_fd, curr_pack); -		fix_unresolved_deltas(f, nr_unresolved); +		fix_unresolved_deltas(f);  		strbuf_addf(&msg, _("completed with %d local objects"),  			    nr_objects - nr_objects_initial);  		stop_progress_msg(&progress, msg.buf); @@ -1191,11 +1263,11 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha  			die(_("Unexpected tail checksum for %s "  			      "(disk corruption?)"), curr_pack);  	} -	if (nr_deltas != nr_resolved_deltas) +	if (nr_ofs_deltas + nr_ref_deltas != nr_resolved_deltas)  		die(Q_("pack has %d unresolved delta",  		       "pack has %d unresolved deltas", -		       nr_deltas - nr_resolved_deltas), -		    nr_deltas - nr_resolved_deltas); +		       nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas), +		    nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);  }  static int write_compressed(struct sha1file *f, void *in, unsigned int size) @@ -1254,15 +1326,15 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,  static int delta_pos_compare(const void *_a, const void *_b)  { -	struct delta_entry *a = *(struct delta_entry **)_a; -	struct delta_entry *b = *(struct delta_entry **)_b; +	struct ref_delta_entry *a = *(struct ref_delta_entry **)_a; +	struct ref_delta_entry *b = *(struct ref_delta_entry **)_b;  	return a->obj_no - b->obj_no;  } -static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved) +static void fix_unresolved_deltas(struct sha1file *f)  { -	struct delta_entry **sorted_by_pos; -	int i, n = 0; +	struct ref_delta_entry **sorted_by_pos; +	int i;  	/*  	 * Since many unresolved deltas may well be themselves base objects @@ -1274,29 +1346,26 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)  	 * before deltas depending on them, a good heuristic is to start  	 * resolving deltas in the same order as their position in the pack.  	 */ -	sorted_by_pos = xmalloc(nr_unresolved * sizeof(*sorted_by_pos)); -	for (i = 0; i < nr_deltas; i++) { -		if (objects[deltas[i].obj_no].real_type != OBJ_REF_DELTA) -			continue; -		sorted_by_pos[n++] = &deltas[i]; -	} -	qsort(sorted_by_pos, n, sizeof(*sorted_by_pos), delta_pos_compare); +	sorted_by_pos = xmalloc(nr_ref_deltas * sizeof(*sorted_by_pos)); +	for (i = 0; i < nr_ref_deltas; i++) +		sorted_by_pos[i] = &ref_deltas[i]; +	qsort(sorted_by_pos, nr_ref_deltas, sizeof(*sorted_by_pos), delta_pos_compare); -	for (i = 0; i < n; i++) { -		struct delta_entry *d = sorted_by_pos[i]; +	for (i = 0; i < nr_ref_deltas; i++) { +		struct ref_delta_entry *d = sorted_by_pos[i];  		enum object_type type;  		struct base_data *base_obj = alloc_base_data();  		if (objects[d->obj_no].real_type != OBJ_REF_DELTA)  			continue; -		base_obj->data = read_sha1_file(d->base.sha1, &type, &base_obj->size); +		base_obj->data = read_sha1_file(d->sha1, &type, &base_obj->size);  		if (!base_obj->data)  			continue; -		if (check_sha1_signature(d->base.sha1, base_obj->data, +		if (check_sha1_signature(d->sha1, base_obj->data,  				base_obj->size, typename(type))) -			die(_("local object %s is corrupt"), sha1_to_hex(d->base.sha1)); -		base_obj->obj = append_obj_to_pack(f, d->base.sha1, +			die(_("local object %s is corrupt"), sha1_to_hex(d->sha1)); +		base_obj->obj = append_obj_to_pack(f, d->sha1,  					base_obj->data, base_obj->size, type);  		find_unresolved_deltas(base_obj);  		display_progress(progress, nr_resolved_deltas); @@ -1352,7 +1421,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,  				 get_object_directory(), sha1_to_hex(sha1));  			final_pack_name = name;  		} -		if (move_temp_to_file(curr_pack_name, final_pack_name)) +		if (finalize_object_file(curr_pack_name, final_pack_name))  			die(_("cannot store pack file"));  	} else if (from_stdin)  		chmod(final_pack_name, 0444); @@ -1363,7 +1432,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,  				 get_object_directory(), sha1_to_hex(sha1));  			final_index_name = name;  		} -		if (move_temp_to_file(curr_index_name, final_index_name)) +		if (finalize_object_file(curr_index_name, final_index_name))  			die(_("cannot store index file"));  	} else  		chmod(final_index_name, 0444); @@ -1488,7 +1557,7 @@ static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)  static void show_pack_info(int stat_only)  { -	int i, baseobjects = nr_objects - nr_deltas; +	int i, baseobjects = nr_objects - nr_ref_deltas - nr_ofs_deltas;  	unsigned long *chain_histogram = NULL;  	if (deepest_delta) @@ -1498,7 +1567,7 @@ static void show_pack_info(int stat_only)  		struct object_entry *obj = &objects[i];  		if (is_delta_type(obj->type)) -			chain_histogram[obj->delta_depth - 1]++; +			chain_histogram[obj_stat[i].delta_depth - 1]++;  		if (stat_only)  			continue;  		printf("%s %-6s %lu %lu %"PRIuMAX, @@ -1507,8 +1576,8 @@ static void show_pack_info(int stat_only)  		       (unsigned long)(obj[1].idx.offset - obj->idx.offset),  		       (uintmax_t)obj->idx.offset);  		if (is_delta_type(obj->type)) { -			struct object_entry *bobj = &objects[obj->base_object_no]; -			printf(" %u %s", obj->delta_depth, sha1_to_hex(bobj->idx.sha1)); +			struct object_entry *bobj = &objects[obj_stat[i].base_object_no]; +			printf(" %u %s", obj_stat[i].delta_depth, sha1_to_hex(bobj->idx.sha1));  		}  		putchar('\n');  	} @@ -1546,6 +1615,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)  		usage(index_pack_usage);  	check_replace_refs = 0; +	fsck_options.walk = mark_link;  	reset_pack_idx_option(&opts);  	git_config(git_index_pack_config, &opts); @@ -1563,6 +1633,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)  			} else if (!strcmp(arg, "--strict")) {  				strict = 1;  				do_fsck_object = 1; +			} else if (skip_prefix(arg, "--strict=", &arg)) { +				strict = 1; +				do_fsck_object = 1; +				fsck_set_msg_types(&fsck_options, arg);  			} else if (!strcmp(arg, "--check-self-contained-and-connected")) {  				strict = 1;  				check_self_contained_and_connected = 1; @@ -1671,11 +1745,14 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)  	curr_pack = open_pack_file(pack_name);  	parse_pack_header();  	objects = xcalloc(nr_objects + 1, sizeof(struct object_entry)); -	deltas = xcalloc(nr_objects, sizeof(struct delta_entry)); +	if (show_stat) +		obj_stat = xcalloc(nr_objects + 1, sizeof(struct object_stat)); +	ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));  	parse_pack_objects(pack_sha1);  	resolve_deltas();  	conclude_pack(fix_thin_pack, curr_pack, pack_sha1); -	free(deltas); +	free(ofs_deltas); +	free(ref_deltas);  	if (strict)  		foreign_nr = check_objects(); | 
