241
241
# if align_packed_per_ref == 4
242
242
# define marked ((*rp & lp_mark) + (rp[1] & lp_mark) +\
243
(rp[2] & lp_mark) + (rp[3] & lp_mark))
243
(rp[2] & lp_mark) + (rp[3] & lp_mark))
246
* The value of marked is logically a uint, not an int:
247
* we declare it as int only to avoid a compiler warning
248
* message about using a non-int value in a switch statement.
250
int marked = *rp & lp_mark;
246
* The value of marked is logically a uint, not an int:
247
* we declare it as int only to avoid a compiler warning
248
* message about using a non-int value in a switch statement.
250
int marked = *rp & lp_mark;
252
for (i = 1; i < align_packed_per_ref; i++)
253
marked += rp[i] & lp_mark;
252
for (i = 1; i < align_packed_per_ref; i++)
253
marked += rp[i] & lp_mark;
257
* Now marked is lp_mark * the number of marked
258
* packed refs in the aligned block, except for
259
* a couple of special cases above.
264
" [8]packed refs 0x%lx..0x%lx are marked\n",
266
(ulong) (rp + (align_packed_per_ref - 1)));
267
rp += align_packed_per_ref;
270
/* At least one packed ref in the block */
271
/* is marked: Keep the whole block. */
272
for (i = align_packed_per_ref; i--; rp++) {
275
" [8]packed ref 0x%lx is marked\n",
257
* Now marked is lp_mark * the number of marked
258
* packed refs in the aligned block, except for
259
* a couple of special cases above.
264
" [8]packed refs 0x%lx..0x%lx are marked\n",
266
(ulong) (rp + (align_packed_per_ref - 1)));
267
rp += align_packed_per_ref;
270
/* At least one packed ref in the block */
271
/* is marked: Keep the whole block. */
272
for (i = align_packed_per_ref; i--; rp++) {
275
" [8]packed ref 0x%lx is marked\n",
281
if_debug2('8', " [8]%d packed ref(s) at 0x%lx are unmarked\n",
282
align_packed_per_ref, (ulong) rp);
284
uint rel = reloc + freed;
286
/* Change this to an integer so we can */
287
/* store the relocation here. */
288
*rp = pt_tag(pt_integer) +
289
min(rel, packed_max_value);
291
rp += align_packed_per_ref;
292
freed += sizeof(ref_packed) * align_packed_per_ref;
294
} else { /* full-size ref */
295
uint rel = reloc + freed;
297
/* The following assignment is logically */
298
/* unnecessary; we do it only for convenience */
300
ref *pref = (ref *) rp;
302
if (!r_has_attr(pref, l_mark)) {
303
if_debug1('8', " [8]ref 0x%lx is unmarked\n",
305
/* Change this to a mark so we can */
306
/* store the relocation. */
307
r_set_type(pref, t_mark);
308
r_set_size(pref, rel);
309
freed += sizeof(ref);
311
if_debug1('8', " [8]ref 0x%lx is marked\n",
313
/* Store the relocation here if possible. */
314
if (!ref_type_uses_size_or_null(r_type(pref))) {
315
if_debug2('8', " [8]storing reloc %u at 0x%lx\n",
317
r_set_size(pref, rel);
320
rp += packed_per_ref;
281
if_debug2('8', " [8]%d packed ref(s) at 0x%lx are unmarked\n",
282
align_packed_per_ref, (ulong) rp);
284
uint rel = reloc + freed;
286
/* Change this to an integer so we can */
287
/* store the relocation here. */
288
*rp = pt_tag(pt_integer) +
289
min(rel, packed_max_value);
291
rp += align_packed_per_ref;
292
freed += sizeof(ref_packed) * align_packed_per_ref;
294
} else { /* full-size ref */
295
uint rel = reloc + freed;
297
/* The following assignment is logically */
298
/* unnecessary; we do it only for convenience */
300
ref *pref = (ref *) rp;
302
if (!r_has_attr(pref, l_mark)) {
303
if_debug1('8', " [8]ref 0x%lx is unmarked\n",
305
/* Change this to a mark so we can */
306
/* store the relocation. */
307
r_set_type(pref, t_mark);
308
r_set_size(pref, rel);
309
freed += sizeof(ref);
311
if_debug1('8', " [8]ref 0x%lx is marked\n",
313
/* Store the relocation here if possible. */
314
if (!ref_type_uses_size_or_null(r_type(pref))) {
315
if_debug2('8', " [8]storing reloc %u at 0x%lx\n",
317
r_set_size(pref, rel);
320
rp += packed_per_ref;
323
323
if_debug3('7', " [7]at end of refs 0x%lx, size = %u, freed = %u\n",
324
(ulong) (hdr + 1), size, freed);
324
(ulong) (hdr + 1), size, freed);
325
325
if (freed == size)
327
327
#if arch_sizeof_int > arch_sizeof_short
329
329
* If the final relocation can't fit in the r_size field
404
404
# define SET_RELOC(var, expr) var = expr
407
if (r_is_packed(rp)) {
411
/* The following assignment is logically unnecessary; */
412
/* we do it only for convenience in debugging. */
414
if_debug3('8', " [8]relocating %s %d ref at 0x%lx\n",
415
(r_has_attr(pref, l_mark) ? "marked" : "unmarked"),
416
r_btype(pref), (ulong) pref);
417
if ((r_has_attr(pref, l_mark) || do_all) &&
418
r_space(pref) >= min_trace
420
switch (r_type(pref)) {
423
DO_RELOC(pref->value.pfile, RELOC_VAR(pref->value.pfile));
426
DO_RELOC(pref->value.pdevice,
427
RELOC_VAR(pref->value.pdevice));
432
DO_RELOC(pref->value.pstruct,
433
RELOC_VAR(pref->value.pstruct));
435
/* Non-trivial non-struct cases */
438
SET_RELOC(pref->value.pdict,
439
(dict *)igc_reloc_ref_ptr((ref_packed *)pref->value.pdict, gcst));
443
uint size = r_size(pref);
445
if (size != 0) { /* value.refs might be NULL */
448
* If the array is large, we allocated it in its
449
* own object (at least originally -- this might
450
* be a pointer to a subarray.) In this case,
451
* we know it is the only object in its
452
* containing st_refs object, so we know that
453
* the mark containing the relocation appears
456
if (size < max_size_st_refs / sizeof(ref)) {
458
SET_RELOC(pref->value.refs,
459
(ref *) igc_reloc_ref_ptr(
460
(ref_packed *) pref->value.refs, gcst));
464
* See the t_shortarray case below for why we
468
SET_RELOC(pref->value.refs,
469
(ref *) igc_reloc_ref_ptr(
470
(ref_packed *) (pref->value.refs + size),
477
if (r_size(pref) != 0) { /* value.refs might be NULL */
479
SET_RELOC(pref->value.packed,
480
igc_reloc_ref_ptr(pref->value.packed, gcst));
485
uint size = r_size(pref);
488
* Since we know that igc_reloc_ref_ptr works by
489
* scanning forward, and we know that all the
490
* elements of this array itself are marked, we can
491
* save some scanning time by relocating the pointer
492
* to the end of the array rather than the
495
if (size != 0) { /* value.refs might be NULL */
498
* igc_reloc_ref_ptr has to be able to determine
499
* whether the pointer points into a space that
500
* isn't being collected. It does this by
501
* checking whether the referent of the pointer
502
* is marked. For this reason, we have to pass
503
* a pointer to the last real element of the
504
* array, rather than just beyond it.
507
SET_RELOC(pref->value.packed,
508
igc_reloc_ref_ptr(pref->value.packed + size,
515
void *psub = name_ref_sub_table(cmem, pref);
516
void *rsub = RELOC_OBJ(psub); /* gcst implicit */
518
SET_RELOC(pref->value.pname,
520
((char *)rsub + ((char *)pref->value.pname -
527
str.data = pref->value.bytes;
528
str.size = r_size(pref);
530
DO_RELOC(str.data, RELOC_STRING_VAR(str));
531
pref->value.bytes = str.data;
536
SET_RELOC(pref->value.const_refs,
537
(const ref *)igc_reloc_ref_ptr((const ref_packed *)pref->value.const_refs, gcst));
540
goto no_reloc; /* don't print trace message */
542
if_debug2('8', " [8]relocated 0x%lx => 0x%lx\n",
543
(ulong)before, (ulong)after);
407
if (r_is_packed(rp)) {
411
/* The following assignment is logically unnecessary; */
412
/* we do it only for convenience in debugging. */
414
if_debug3('8', " [8]relocating %s %d ref at 0x%lx\n",
415
(r_has_attr(pref, l_mark) ? "marked" : "unmarked"),
416
r_btype(pref), (ulong) pref);
417
if ((r_has_attr(pref, l_mark) || do_all) &&
418
r_space(pref) >= min_trace
420
switch (r_type(pref)) {
423
DO_RELOC(pref->value.pfile, RELOC_VAR(pref->value.pfile));
426
DO_RELOC(pref->value.pdevice,
427
RELOC_VAR(pref->value.pdevice));
432
DO_RELOC(pref->value.pstruct,
433
RELOC_VAR(pref->value.pstruct));
435
/* Non-trivial non-struct cases */
438
SET_RELOC(pref->value.pdict,
439
(dict *)igc_reloc_ref_ptr((ref_packed *)pref->value.pdict, gcst));
443
uint size = r_size(pref);
445
if (size != 0) { /* value.refs might be NULL */
448
* If the array is large, we allocated it in its
449
* own object (at least originally -- this might
450
* be a pointer to a subarray.) In this case,
451
* we know it is the only object in its
452
* containing st_refs object, so we know that
453
* the mark containing the relocation appears
456
if (size < max_size_st_refs / sizeof(ref)) {
458
SET_RELOC(pref->value.refs,
459
(ref *) igc_reloc_ref_ptr(
460
(ref_packed *) pref->value.refs, gcst));
464
* See the t_shortarray case below for why we
468
SET_RELOC(pref->value.refs,
469
(ref *) igc_reloc_ref_ptr(
470
(ref_packed *) (pref->value.refs + size),
477
if (r_size(pref) != 0) { /* value.refs might be NULL */
479
SET_RELOC(pref->value.packed,
480
igc_reloc_ref_ptr(pref->value.packed, gcst));
485
uint size = r_size(pref);
488
* Since we know that igc_reloc_ref_ptr works by
489
* scanning forward, and we know that all the
490
* elements of this array itself are marked, we can
491
* save some scanning time by relocating the pointer
492
* to the end of the array rather than the
495
if (size != 0) { /* value.refs might be NULL */
498
* igc_reloc_ref_ptr has to be able to determine
499
* whether the pointer points into a space that
500
* isn't being collected. It does this by
501
* checking whether the referent of the pointer
502
* is marked. For this reason, we have to pass
503
* a pointer to the last real element of the
504
* array, rather than just beyond it.
507
SET_RELOC(pref->value.packed,
508
igc_reloc_ref_ptr(pref->value.packed + size,
515
void *psub = name_ref_sub_table(cmem, pref);
516
void *rsub = RELOC_OBJ(psub); /* gcst implicit */
518
SET_RELOC(pref->value.pname,
520
((char *)rsub + ((char *)pref->value.pname -
527
str.data = pref->value.bytes;
528
str.size = r_size(pref);
530
DO_RELOC(str.data, RELOC_STRING_VAR(str));
531
pref->value.bytes = str.data;
536
SET_RELOC(pref->value.const_refs,
537
(const ref *)igc_reloc_ref_ptr((const ref_packed *)pref->value.const_refs, gcst));
540
goto no_reloc; /* don't print trace message */
542
if_debug2('8', " [8]relocated 0x%lx => 0x%lx\n",
543
(ulong)before, (ulong)after);
546
rp += packed_per_ref;
546
rp += packed_per_ref;
569
if (r_is_packed(rp)) {
571
* Normally, an unmarked packed ref will be an
572
* integer whose value is the amount of relocation.
573
* However, the relocation value might have been
574
* too large to fit. If this is the case, for
575
* each such unmarked packed ref we pass over,
576
* we have to decrement the final relocation.
578
rputc((*rp & lp_mark ? '1' : '0'));
579
if (!(*rp & lp_mark)) {
580
if (*rp != pt_tag(pt_integer) + packed_max_value) {
581
/* This is a stored relocation value. */
583
rp = print_reloc(prp, "ref",
586
(*rp & packed_value_mask) + dec));
590
* We know this is the first of an aligned block
591
* of packed refs. Skip over the entire block,
592
* decrementing the final relocation.
594
dec += sizeof(ref_packed) * align_packed_per_ref;
595
rp += align_packed_per_ref;
600
if (!ref_type_uses_size_or_null(r_type(RP_REF(rp)))) {
601
/* reloc is in r_size */
603
rp = print_reloc(prp, "ref",
605
(r_size(RP_REF(rp)) == 0 ? prp :
606
(const ref_packed *)((const char *)prp -
607
r_size(RP_REF(rp)) + dec)));
611
rp += packed_per_ref;
569
if (r_is_packed(rp)) {
571
* Normally, an unmarked packed ref will be an
572
* integer whose value is the amount of relocation.
573
* However, the relocation value might have been
574
* too large to fit. If this is the case, for
575
* each such unmarked packed ref we pass over,
576
* we have to decrement the final relocation.
578
rputc((*rp & lp_mark ? '1' : '0'));
579
if (!(*rp & lp_mark)) {
580
if (*rp != pt_tag(pt_integer) + packed_max_value) {
581
/* This is a stored relocation value. */
583
rp = print_reloc(prp, "ref",
586
(*rp & packed_value_mask) + dec));
590
* We know this is the first of an aligned block
591
* of packed refs. Skip over the entire block,
592
* decrementing the final relocation.
594
dec += sizeof(ref_packed) * align_packed_per_ref;
595
rp += align_packed_per_ref;
600
if (!ref_type_uses_size_or_null(r_type(RP_REF(rp)))) {
601
/* reloc is in r_size */
603
rp = print_reloc(prp, "ref",
605
(r_size(RP_REF(rp)) == 0 ? prp :
606
(const ref_packed *)((const char *)prp -
607
r_size(RP_REF(rp)) + dec)));
611
rp += packed_per_ref;
613
613
/* Use a severely deprecated pun to remove the const property. */
615
union { const ref_packed *r; ref_packed *w; } u;
615
union { const ref_packed *r; ref_packed *w; } u;
682
682
* of the block when we see one of those.
684
684
if (dpre == pre) /* Loop while we don't need to copy. */
686
if (r_is_packed(src)) {
687
if (!r_has_pmark(src))
689
if_debug1('8', " [8]packed ref 0x%lx \"copied\"\n",
693
} else { /* full-size ref */
694
ref *const pref = (ref *)src;
686
if (r_is_packed(src)) {
687
if (!r_has_pmark(src))
689
if_debug1('8', " [8]packed ref 0x%lx \"copied\"\n",
693
} else { /* full-size ref */
694
ref *const pref = (ref *)src;
696
if (!r_has_attr(pref, l_mark))
698
if_debug1('8', " [8]ref 0x%lx \"copied\"\n", (ulong) src);
699
r_clear_attrs(pref, l_mark);
700
src += packed_per_ref;
696
if (!r_has_attr(pref, l_mark))
698
if_debug1('8', " [8]ref 0x%lx \"copied\"\n", (ulong) src);
699
r_clear_attrs(pref, l_mark);
700
src += packed_per_ref;
704
704
dest = (ref_packed *) ((char *)dpre + ((char *)src - (char *)pre));
706
if (r_is_packed(src)) {
707
if (r_has_pmark(src)) {
708
if_debug2('8', " [8]packed ref 0x%lx copied to 0x%lx\n",
709
(ulong) src, (ulong) dest);
710
*dest++ = *src & ~lp_mark;
713
} else { /* full-size ref */
714
if (r_has_attr((ref *) src, l_mark)) {
706
if (r_is_packed(src)) {
707
if (r_has_pmark(src)) {
708
if_debug2('8', " [8]packed ref 0x%lx copied to 0x%lx\n",
709
(ulong) src, (ulong) dest);
710
*dest++ = *src & ~lp_mark;
713
} else { /* full-size ref */
714
if (r_has_attr((ref *) src, l_mark)) {
717
if_debug2('8', " [8]ref 0x%lx copied to 0x%lx\n",
718
(ulong) src, (ulong) dest);
719
/* We can't just use ref_assign_inline, */
720
/* because the source and destination */
722
ref_assign_inline(&rtemp, (ref *) src);
723
r_clear_attrs(&rtemp, l_mark);
724
ref_assign_inline((ref *) dest, &rtemp);
725
src += packed_per_ref;
726
dest += packed_per_ref;
727
} else { /* check for end of block */
728
src += packed_per_ref;
717
if_debug2('8', " [8]ref 0x%lx copied to 0x%lx\n",
718
(ulong) src, (ulong) dest);
719
/* We can't just use ref_assign_inline, */
720
/* because the source and destination */
722
ref_assign_inline(&rtemp, (ref *) src);
723
r_clear_attrs(&rtemp, l_mark);
724
ref_assign_inline((ref *) dest, &rtemp);
725
src += packed_per_ref;
726
dest += packed_per_ref;
727
} else { /* check for end of block */
728
src += packed_per_ref;
734
734
new_size = (byte *) dest - (byte *) (dpre + 1) + sizeof(ref);
736
736
/* Check that the relocation came out OK. */
737
737
/* NOTE: this check only works within a single chunk. */
738
738
if ((byte *) src - (byte *) dest != r_size((ref *) src - 1) + sizeof(ref)) {
739
lprintf3("Reloc error for refs 0x%lx: reloc = %lu, stored = %u\n",
740
(ulong) dpre, (ulong) ((byte *) src - (byte *) dest),
741
(uint) r_size((ref *) src - 1));
739
lprintf3("Reloc error for refs 0x%lx: reloc = %lu, stored = %u\n",
740
(ulong) dpre, (ulong) ((byte *) src - (byte *) dest),
741
(uint) r_size((ref *) src - 1));
745
745
/* Pad to a multiple of sizeof(ref). */
746
746
while (new_size & (sizeof(ref) - 1))
747
*dest++ = pt_tag(pt_integer),
748
new_size += sizeof(ref_packed);
747
*dest++ = pt_tag(pt_integer),
748
new_size += sizeof(ref_packed);
749
749
/* We want to make the newly freed space into a free block, */
750
750
/* but we can only do this if we have enough room. */
751
751
if (size - new_size < sizeof(obj_header_t)) { /* Not enough room. Pad to original size. */
752
while (new_size < size)
753
*dest++ = pt_tag(pt_integer),
754
new_size += sizeof(ref_packed);
752
while (new_size < size)
753
*dest++ = pt_tag(pt_integer),
754
new_size += sizeof(ref_packed);
756
obj_header_t *pfree = (obj_header_t *) ((ref *) dest + 1);
756
obj_header_t *pfree = (obj_header_t *) ((ref *) dest + 1);
759
pfree->o_size = size - new_size - sizeof(obj_header_t);
760
pfree->o_type = &st_bytes;
759
pfree->o_size = size - new_size - sizeof(obj_header_t);
760
pfree->o_type = &st_bytes;
762
762
/* Re-create the final ref. */
763
763
r_set_type((ref *) dest, t_integer);