~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to erts/emulator/beam/erl_gc.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * %CopyrightBegin%
3
 
 * 
4
 
 * Copyright Ericsson AB 2002-2009. All Rights Reserved.
5
 
 * 
 
3
 *
 
4
 * Copyright Ericsson AB 2002-2011. All Rights Reserved.
 
5
 *
6
6
 * The contents of this file are subject to the Erlang Public License,
7
7
 * Version 1.1, (the "License"); you may not use this file except in
8
8
 * compliance with the License. You should have received a copy of the
9
9
 * Erlang Public License along with this software. If not, it can be
10
10
 * retrieved online at http://www.erlang.org/.
11
 
 * 
 
11
 *
12
12
 * Software distributed under the License is distributed on an "AS IS"
13
13
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
 * the License for the specific language governing rights and limitations
15
15
 * under the License.
16
 
 * 
 
16
 *
17
17
 * %CopyrightEnd%
18
18
 */
19
19
#ifdef HAVE_CONFIG_H
33
33
#include "erl_gc.h"
34
34
#if HIPE
35
35
#include "hipe_stack.h"
 
36
#include "hipe_mode_switch.h"
36
37
#endif
37
38
 
38
39
#define ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT 1
110
111
                                   int need, Eterm *objv, int nobj);
111
112
static void shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj);
112
113
static void grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj);
113
 
static void sweep_proc_bins(Process *p, int fullsweep);
114
 
static void sweep_proc_funs(Process *p, int fullsweep);
115
 
static void sweep_proc_externals(Process *p, int fullsweep);
 
114
static void sweep_off_heap(Process *p, int fullsweep);
116
115
static void offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
117
116
static void offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
118
117
static void offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
126
125
static void disallow_heap_frag_ref(Process* p, Eterm* n_htop, Eterm* objv, int nobj);
127
126
#endif
128
127
 
129
 
#ifdef ARCH_64
 
128
#if defined(ARCH_64) && !HALFWORD_HEAP
130
129
# define MAX_HEAP_SIZES 154
131
130
#else
132
131
# define MAX_HEAP_SIZES 55
145
144
{
146
145
    int i = 0;
147
146
 
 
147
    ASSERT(offsetof(ProcBin,thing_word) == offsetof(struct erl_off_heap_header,thing_word));
 
148
    ASSERT(offsetof(ProcBin,thing_word) == offsetof(ErlFunThing,thing_word));
 
149
    ASSERT(offsetof(ProcBin,thing_word) == offsetof(ExternalThing,header));
 
150
    ASSERT(offsetof(ProcBin,size) == offsetof(struct erl_off_heap_header,size));
 
151
    ASSERT(offsetof(ProcBin,size) == offsetof(ErlSubBin,size));
 
152
    ASSERT(offsetof(ProcBin,size) == offsetof(ErlHeapBin,size));
 
153
    ASSERT(offsetof(ProcBin,next) == offsetof(struct erl_off_heap_header,next));
 
154
    ASSERT(offsetof(ProcBin,next) == offsetof(ErlFunThing,next));
 
155
    ASSERT(offsetof(ProcBin,next) == offsetof(ExternalThing,next));
 
156
 
148
157
    erts_smp_spinlock_init(&info_lck, "gc_info");
149
158
    garbage_cols = 0;
150
159
    reclaimed = 0;
286
295
    offset_heap_ptr(hp, sz, offs, (char *) low, ((char *)high)-((char *)low));
287
296
}
288
297
 
 
298
 
289
299
#define ptr_within(ptr, low, high) ((ptr) < (high) && (ptr) >= (low))
290
300
 
291
301
void
292
302
erts_offset_off_heap(ErlOffHeap *ohp, Sint offs, Eterm* low, Eterm* high)
293
303
{
294
 
    if (ohp->mso && ptr_within((Eterm *)ohp->mso, low, high)) {
295
 
        Eterm** uptr = (Eterm**) (void *) &ohp->mso;
296
 
        *uptr += offs;
297
 
    }
298
 
 
299
 
#ifndef HYBRID /* FIND ME! */
300
 
    if (ohp->funs && ptr_within((Eterm *)ohp->funs, low, high)) {
301
 
        Eterm** uptr = (Eterm**) (void *) &ohp->funs;
302
 
        *uptr += offs;
303
 
    }
304
 
#endif
305
 
 
306
 
    if (ohp->externals && ptr_within((Eterm *)ohp->externals, low, high)) {
307
 
        Eterm** uptr = (Eterm**) (void *) &ohp->externals;
 
304
    if (ohp->first && ptr_within((Eterm *)ohp->first, low, high)) {
 
305
        Eterm** uptr = (Eterm**) (void *) &ohp->first;
308
306
        *uptr += offs;
309
307
    }
310
308
}
489
487
    htop = heap;
490
488
 
491
489
    n = setup_rootset(p, p->arg_reg, p->arity, &rootset);
 
490
#if HIPE
 
491
    hipe_empty_nstack(p);
 
492
#endif
492
493
 
493
494
    src = (char *) p->heap;
494
495
    src_size = (char *) p->htop - src;
504
505
 
505
506
    cleanup_rootset(&rootset);
506
507
 
507
 
    if (MSO(p).mso) {
508
 
        sweep_proc_bins(p, 1);
509
 
    }
510
 
    if (MSO(p).funs) {
511
 
        sweep_proc_funs(p, 1);
512
 
    }
513
 
    if (MSO(p).externals) {
514
 
        sweep_proc_externals(p, 1);
 
508
    if (MSO(p).first) {
 
509
        sweep_off_heap(p, 1);
515
510
    }
516
511
 
517
512
    /*
667
662
            case TAG_PRIMARY_BOXED:
668
663
                ptr = boxed_val(gval);
669
664
                val = *ptr;
670
 
                if (IS_MOVED(val)) {
 
665
                if (IS_MOVED_BOXED(val)) {
671
666
                    ASSERT(is_boxed(val));
672
667
                    *g_ptr++ = val;
673
668
                } else if (in_area(ptr, area, area_size)) {
679
674
            case TAG_PRIMARY_LIST:
680
675
                ptr = list_val(gval);
681
676
                val = *ptr;
682
 
                if (is_non_value(val)) { /* Moved */
 
677
                if (IS_MOVED_CONS(val)) { /* Moved */
683
678
                    *g_ptr++ = ptr[1];
684
679
                } else if (in_area(ptr, area, area_size)) {
685
680
                    MOVE_CONS(ptr,val,old_htop,g_ptr++);
752
747
     * is large enough.
753
748
     */
754
749
 
755
 
    if (OLD_HEAP(p) && mature <= OLD_HEND(p) - OLD_HTOP(p)) {
 
750
    if (OLD_HEAP(p) &&
 
751
            ((mature <= OLD_HEND(p) - OLD_HTOP(p)) &&
 
752
            ((BIN_VHEAP_MATURE(p) < ( BIN_OLD_VHEAP_SZ(p) - BIN_OLD_VHEAP(p)))) &&
 
753
            ((BIN_OLD_VHEAP_SZ(p) > BIN_OLD_VHEAP(p))) ) ) {
756
754
        ErlMessage *msgp;
757
755
        Uint size_after;
758
756
        Uint need_after;
913
911
            case TAG_PRIMARY_BOXED: {
914
912
                ptr = boxed_val(gval);
915
913
                val = *ptr;
916
 
                if (IS_MOVED(val)) {
 
914
                if (IS_MOVED_BOXED(val)) {
917
915
                    ASSERT(is_boxed(val));
918
916
                    *g_ptr++ = val;
919
917
                } else if (in_area(ptr, heap, mature_size)) {
929
927
            case TAG_PRIMARY_LIST: {
930
928
                ptr = list_val(gval);
931
929
                val = *ptr;
932
 
                if (is_non_value(val)) { /* Moved */
 
930
                if (IS_MOVED_CONS(val)) { /* Moved */
933
931
                    *g_ptr++ = ptr[1];
934
932
                } else if (in_area(ptr, heap, mature_size)) {
935
933
                    MOVE_CONS(ptr,val,old_htop,g_ptr++);
961
959
        n_htop = sweep_one_area(n_heap, n_htop, heap, heap_size);
962
960
    } else {
963
961
        Eterm* n_hp = n_heap;
 
962
        Eterm* ptr;
 
963
        Eterm val;
 
964
        Eterm gval;
964
965
 
965
966
        while (n_hp != n_htop) {
966
 
            Eterm* ptr;
967
 
            Eterm val;
968
 
            Eterm gval = *n_hp;
969
 
 
 
967
            ASSERT(n_hp < n_htop);
 
968
            gval = *n_hp;
970
969
            switch (primary_tag(gval)) {
971
970
            case TAG_PRIMARY_BOXED: {
972
971
                ptr = boxed_val(gval);
973
972
                val = *ptr;
974
 
                if (IS_MOVED(val)) {
 
973
                if (IS_MOVED_BOXED(val)) {
975
974
                    ASSERT(is_boxed(val));
976
975
                    *n_hp++ = val;
977
976
                } else if (in_area(ptr, heap, mature_size)) {
986
985
            case TAG_PRIMARY_LIST: {
987
986
                ptr = list_val(gval);
988
987
                val = *ptr;
989
 
                if (is_non_value(val)) {
 
988
                if (IS_MOVED_CONS(val)) {
990
989
                    *n_hp++ = ptr[1];
991
990
                } else if (in_area(ptr, heap, mature_size)) {
992
991
                    MOVE_CONS(ptr,val,old_htop,n_hp++);
1007
1006
                        Eterm* origptr = &(mb->orig);
1008
1007
                        ptr = boxed_val(*origptr);
1009
1008
                        val = *ptr;
1010
 
                        if (IS_MOVED(val)) {
 
1009
                        if (IS_MOVED_BOXED(val)) {
1011
1010
                            *origptr = val;
1012
1011
                            mb->base = binary_bytes(val);
1013
1012
                        } else if (in_area(ptr, heap, mature_size)) {
1040
1039
    OLD_HTOP(p) = old_htop;
1041
1040
    HIGH_WATER(p) = (HEAP_START(p) != HIGH_WATER(p)) ? n_heap : n_htop;
1042
1041
 
1043
 
    if (MSO(p).mso) {
1044
 
        sweep_proc_bins(p, 0);
1045
 
    }
1046
 
 
1047
 
    if (MSO(p).funs) {
1048
 
        sweep_proc_funs(p, 0);
1049
 
    }
1050
 
    if (MSO(p).externals) {
1051
 
        sweep_proc_externals(p, 0);
 
1042
    if (MSO(p).first) {
 
1043
        sweep_off_heap(p, 0);
1052
1044
    }
1053
1045
 
1054
1046
#ifdef HARDDEBUG
1160
1152
            case TAG_PRIMARY_BOXED: {
1161
1153
                ptr = boxed_val(gval);
1162
1154
                val = *ptr;
1163
 
                if (IS_MOVED(val)) {
 
1155
                if (IS_MOVED_BOXED(val)) {
1164
1156
                    ASSERT(is_boxed(val));
1165
1157
                    *g_ptr++ = val;
1166
1158
                } else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
1174
1166
            case TAG_PRIMARY_LIST: {
1175
1167
                ptr = list_val(gval);
1176
1168
                val = *ptr;
1177
 
                if (is_non_value(val)) {
 
1169
                if (IS_MOVED_CONS(val)) {
1178
1170
                    *g_ptr++ = ptr[1];
1179
1171
                } else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
1180
1172
                    MOVE_CONS(ptr,val,n_htop,g_ptr++);
1215
1207
            case TAG_PRIMARY_BOXED: {
1216
1208
                ptr = boxed_val(gval);
1217
1209
                val = *ptr;
1218
 
                if (IS_MOVED(val)) {
 
1210
                if (IS_MOVED_BOXED(val)) {
1219
1211
                    ASSERT(is_boxed(val));
1220
1212
                    *n_hp++ = val;
1221
1213
                } else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
1228
1220
            case TAG_PRIMARY_LIST: {
1229
1221
                ptr = list_val(gval);
1230
1222
                val = *ptr;
1231
 
                if (is_non_value(val)) {
 
1223
                if (IS_MOVED_CONS(val)) {
1232
1224
                    *n_hp++ = ptr[1];
1233
1225
                } else if (in_area(ptr, src, src_size) || in_area(ptr, oh, oh_size)) {
1234
1226
                    MOVE_CONS(ptr,val,n_htop,n_hp++);
1248
1240
                        origptr = &(mb->orig);
1249
1241
                        ptr = boxed_val(*origptr);
1250
1242
                        val = *ptr;
1251
 
                        if (IS_MOVED(val)) {
 
1243
                        if (IS_MOVED_BOXED(val)) {
1252
1244
                            *origptr = val;
1253
1245
                            mb->base = binary_bytes(*origptr);
1254
1246
                        } else if (in_area(ptr, src, src_size) ||
1270
1262
        }
1271
1263
    }
1272
1264
 
1273
 
    if (MSO(p).mso) {
1274
 
        sweep_proc_bins(p, 1);
1275
 
    }
1276
 
    if (MSO(p).funs) {
1277
 
        sweep_proc_funs(p, 1);
1278
 
    }
1279
 
    if (MSO(p).externals) {
1280
 
        sweep_proc_externals(p, 1);
 
1265
    if (MSO(p).first) {
 
1266
        sweep_off_heap(p, 1);
1281
1267
    }
1282
1268
 
1283
 
    if (OLD_HEAP(p) != NULL) {
 
1269
    if (OLD_HEAP(p) != NULL) {       
1284
1270
        ERTS_HEAP_FREE(ERTS_ALC_T_OLD_HEAP,
1285
1271
                       OLD_HEAP(p),
1286
1272
                       (OLD_HEND(p) - OLD_HEAP(p)) * sizeof(Eterm));
1304
1290
    HIGH_WATER(p) = HEAP_TOP(p);
1305
1291
 
1306
1292
    ErtsGcQuickSanityCheck(p);
 
1293
 
1307
1294
    /*
1308
1295
     * Copy newly received message onto the end of the new heap.
1309
1296
     */
1391
1378
static void
1392
1379
remove_message_buffers(Process* p)
1393
1380
{
1394
 
    ErlHeapFragment* bp = MBUF(p);
1395
 
 
1396
 
    MBUF(p) = NULL;
1397
 
    MBUF_SIZE(p) = 0;
1398
 
    while (bp != NULL) {
1399
 
        ErlHeapFragment* next_bp = bp->next;
1400
 
        free_message_buffer(bp);
1401
 
        bp = next_bp;
1402
 
    }
1403
 
}
1404
 
 
1405
 
/*
1406
 
 * Go through one root set array, move everything that it is one of the
1407
 
 * heap fragments to our new heap.
1408
 
 */
1409
 
static Eterm*
1410
 
collect_root_array(Process* p, Eterm* n_htop, Eterm* objv, int nobj)
1411
 
{
1412
 
    ErlHeapFragment* qb;
1413
 
    Eterm gval;
1414
 
    Eterm* ptr;
1415
 
    Eterm val;
1416
 
 
1417
 
    ASSERT(p->htop != NULL);
1418
 
    while (nobj--) {
1419
 
        gval = *objv;
1420
 
        
1421
 
        switch (primary_tag(gval)) {
1422
 
 
1423
 
        case TAG_PRIMARY_BOXED: {
1424
 
            ptr = boxed_val(gval);
1425
 
            val = *ptr;
1426
 
            if (IS_MOVED(val)) {
1427
 
                ASSERT(is_boxed(val));
1428
 
                *objv++ = val;
1429
 
            } else {
1430
 
                for (qb = MBUF(p); qb != NULL; qb = qb->next) {
1431
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
1432
 
                        MOVE_BOXED(ptr,val,n_htop,objv);
1433
 
                        break;
1434
 
                    }
1435
 
                }
1436
 
                objv++;
1437
 
            }
1438
 
            break;
1439
 
        }
1440
 
 
1441
 
        case TAG_PRIMARY_LIST: {
1442
 
            ptr = list_val(gval);
1443
 
            val = *ptr;
1444
 
            if (is_non_value(val)) {
1445
 
                *objv++ = ptr[1];
1446
 
            } else {
1447
 
                for (qb = MBUF(p); qb != NULL; qb = qb->next) {
1448
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
1449
 
                        MOVE_CONS(ptr,val,n_htop,objv);
1450
 
                        break;
1451
 
                    }
1452
 
                }
1453
 
                objv++;
1454
 
            }
1455
 
            break;
1456
 
        }
1457
 
 
1458
 
        default: {
1459
 
            objv++;
1460
 
            break;
1461
 
        }
1462
 
        }
1463
 
    }
1464
 
    return n_htop;
1465
 
}
1466
 
 
 
1381
    if (MBUF(p) != NULL) {
 
1382
        free_message_buffer(MBUF(p));
 
1383
        MBUF(p) = NULL;
 
1384
    }    
 
1385
    MBUF_SIZE(p) = 0;    
 
1386
}
1467
1387
#ifdef HARDDEBUG
1468
1388
 
1469
1389
/*
1494
1414
        case TAG_PRIMARY_BOXED: {
1495
1415
            ptr = _unchecked_boxed_val(gval);
1496
1416
            val = *ptr;
1497
 
            if (IS_MOVED(val)) {
 
1417
            if (IS_MOVED_BOXED(val)) {
1498
1418
                ASSERT(is_boxed(val));
1499
1419
                objv++;
1500
1420
            } else {
1501
1421
                for (qb = mbuf; qb != NULL; qb = qb->next) {
1502
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
 
1422
                    if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
1503
1423
                        abort();
1504
1424
                    }
1505
1425
                }
1511
1431
        case TAG_PRIMARY_LIST: {
1512
1432
            ptr = _unchecked_list_val(gval);
1513
1433
            val = *ptr;
1514
 
            if (is_non_value(val)) {
 
1434
            if (IS_MOVED_CONS(val)) {
1515
1435
                objv++;
1516
1436
            } else {
1517
1437
                for (qb = mbuf; qb != NULL; qb = qb->next) {
1518
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
 
1438
                    if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
1519
1439
                        abort();
1520
1440
                    }
1521
1441
                }
1560
1480
            ptr = _unchecked_boxed_val(val);
1561
1481
            if (!in_area(ptr, heap, heap_size)) {
1562
1482
                for (qb = MBUF(p); qb != NULL; qb = qb->next) {
1563
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
 
1483
                    if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
1564
1484
                        abort();
1565
1485
                    }
1566
1486
                }
1570
1490
            ptr = _unchecked_list_val(val);
1571
1491
            if (!in_area(ptr, heap, heap_size)) {
1572
1492
                for (qb = MBUF(p); qb != NULL; qb = qb->next) {
1573
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
 
1493
                    if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
1574
1494
                        abort();
1575
1495
                    }
1576
1496
                }
1612
1532
        val = *hp++;
1613
1533
        switch (primary_tag(val)) {
1614
1534
        case TAG_PRIMARY_BOXED:
1615
 
            ptr = (Eterm *) val;
 
1535
            ptr = (Eterm *) EXPAND_POINTER(val);
1616
1536
            if (!in_area(ptr, old_heap, old_heap_size)) {
1617
1537
                if (in_area(ptr, new_heap, new_heap_size)) {
1618
1538
                    abort();
1619
1539
                }
1620
1540
                for (qb = MBUF(p); qb != NULL; qb = qb->next) {
1621
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
 
1541
                    if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
1622
1542
                        abort();
1623
1543
                    }
1624
1544
                }
1625
1545
            }
1626
1546
            break;
1627
1547
        case TAG_PRIMARY_LIST:
1628
 
            ptr = (Eterm *) val;
 
1548
            ptr = (Eterm *) EXPAND_POINTER(val);
1629
1549
            if (!in_area(ptr, old_heap, old_heap_size)) {
1630
1550
                if (in_area(ptr, new_heap, new_heap_size)) {
1631
1551
                    abort();
1632
1552
                }
1633
1553
                for (qb = MBUF(p); qb != NULL; qb = qb->next) {
1634
 
                    if (in_area(ptr, qb->mem, qb->size*sizeof(Eterm))) {
 
1554
                    if (in_area(ptr, qb->mem, qb->alloc_size*sizeof(Eterm))) {
1635
1555
                        abort();
1636
1556
                    }
1637
1557
                }
1671
1591
            case TAG_PRIMARY_BOXED: {
1672
1592
                ptr = boxed_val(gval);
1673
1593
                val = *ptr;
1674
 
                if (IS_MOVED(val)) {
 
1594
                if (IS_MOVED_BOXED(val)) {
1675
1595
                    ASSERT(is_boxed(val));
1676
1596
                    *g_ptr++ = val;
1677
1597
                } else if (in_area(ptr, src, src_size)) {
1684
1604
            case TAG_PRIMARY_LIST: {
1685
1605
                ptr = list_val(gval);
1686
1606
                val = *ptr;
1687
 
                if (is_non_value(val)) { /* Moved */
 
1607
                if (IS_MOVED_CONS(val)) {
1688
1608
                    *g_ptr++ = ptr[1];
1689
1609
                } else if (in_area(ptr, src, src_size)) {
1690
1610
                    MOVE_CONS(ptr,val,htop,g_ptr++);
1707
1627
static Eterm*
1708
1628
sweep_one_area(Eterm* n_hp, Eterm* n_htop, char* src, Uint src_size)
1709
1629
{
 
1630
    Eterm* ptr;
 
1631
    Eterm val;
 
1632
    Eterm gval;
 
1633
 
1710
1634
    while (n_hp != n_htop) {
1711
 
        Eterm* ptr;
1712
 
        Eterm val;
1713
 
        Eterm gval = *n_hp;
1714
 
 
 
1635
        ASSERT(n_hp < n_htop);
 
1636
        gval = *n_hp;
1715
1637
        switch (primary_tag(gval)) {
1716
1638
        case TAG_PRIMARY_BOXED: {
1717
1639
            ptr = boxed_val(gval);
1718
1640
            val = *ptr;
1719
 
            if (IS_MOVED(val)) {
 
1641
            if (IS_MOVED_BOXED(val)) {
1720
1642
                ASSERT(is_boxed(val));
1721
1643
                *n_hp++ = val;
1722
1644
            } else if (in_area(ptr, src, src_size)) {
1729
1651
        case TAG_PRIMARY_LIST: {
1730
1652
            ptr = list_val(gval);
1731
1653
            val = *ptr;
1732
 
            if (is_non_value(val)) {
 
1654
            if (IS_MOVED_CONS(val)) {
1733
1655
                *n_hp++ = ptr[1];
1734
1656
            } else if (in_area(ptr, src, src_size)) {
1735
1657
                MOVE_CONS(ptr,val,n_htop,n_hp++);
1749
1671
                    origptr = &(mb->orig);
1750
1672
                    ptr = boxed_val(*origptr);
1751
1673
                    val = *ptr;
1752
 
                    if (IS_MOVED(val)) {
 
1674
                    if (IS_MOVED_BOXED(val)) {
1753
1675
                        *origptr = val;
1754
1676
                        mb->base = binary_bytes(*origptr);
1755
1677
                    } else if (in_area(ptr, src, src_size)) {
1781
1703
        case TAG_PRIMARY_BOXED: {
1782
1704
            ptr = boxed_val(gval);
1783
1705
            val = *ptr;
1784
 
            if (IS_MOVED(val)) {
 
1706
            if (IS_MOVED_BOXED(val)) {
1785
1707
                ASSERT(is_boxed(val));
1786
1708
                *heap_ptr++ = val;
1787
1709
            } else if (in_area(ptr, src, src_size)) {
1794
1716
        case TAG_PRIMARY_LIST: {
1795
1717
            ptr = list_val(gval);
1796
1718
            val = *ptr;
1797
 
            if (is_non_value(val)) {
 
1719
            if (IS_MOVED_CONS(val)) {
1798
1720
                *heap_ptr++ = ptr[1];
1799
1721
            } else if (in_area(ptr, src, src_size)) {
1800
1722
                MOVE_CONS(ptr,val,htop,heap_ptr++);
1820
1742
}
1821
1743
 
1822
1744
/*
 
1745
 * Move an area (heap fragment) by sweeping over it and set move markers.
 
1746
 */
 
1747
static Eterm*
 
1748
move_one_area(Eterm* n_htop, char* src, Uint src_size)
 
1749
{
 
1750
    Eterm* ptr = (Eterm*) src;
 
1751
    Eterm* end = ptr + src_size/sizeof(Eterm);
 
1752
    Eterm dummy_ref;
 
1753
 
 
1754
    while (ptr != end) {
 
1755
        Eterm val;
 
1756
        ASSERT(ptr < end);
 
1757
        val = *ptr;
 
1758
        ASSERT(val != ERTS_HOLE_MARKER);
 
1759
        if (is_header(val)) {
 
1760
            ASSERT(ptr + header_arity(val) < end);
 
1761
            MOVE_BOXED(ptr, val, n_htop, &dummy_ref);       
 
1762
        }
 
1763
        else { /* must be a cons cell */
 
1764
            ASSERT(ptr+1 < end);
 
1765
            MOVE_CONS(ptr, val, n_htop, &dummy_ref);
 
1766
            ptr += 2;
 
1767
        }
 
1768
    }
 
1769
 
 
1770
    return n_htop;
 
1771
}
 
1772
 
 
1773
/*
1823
1774
 * Collect heap fragments and check that they point in the correct direction.
1824
1775
 */
1825
1776
 
1830
1781
    ErlHeapFragment* qb;
1831
1782
    char* frag_begin;
1832
1783
    Uint frag_size;
1833
 
    ErlMessage* mp;
1834
1784
 
1835
1785
    /*
1836
1786
     * We don't allow references to a heap fragments from the stack, heap,
1845
1795
#endif
1846
1796
 
1847
1797
    /*
1848
 
     * Go through the subset of the root set that is allowed to
1849
 
     * reference data in heap fragments and move data from heap fragments
1850
 
     * to our new heap.
1851
 
     */
1852
 
 
1853
 
    if (nobj != 0) {
1854
 
        n_htop = collect_root_array(p, n_htop, objv, nobj);
1855
 
    }
1856
 
    if (is_not_immed(p->fvalue)) {
1857
 
        n_htop = collect_root_array(p, n_htop, &p->fvalue, 1);
1858
 
    }
1859
 
    if (is_not_immed(p->ftrace)) {
1860
 
        n_htop = collect_root_array(p, n_htop, &p->ftrace, 1);
1861
 
    }
1862
 
    if (is_not_immed(p->seq_trace_token)) {
1863
 
        n_htop = collect_root_array(p, n_htop, &p->seq_trace_token, 1);
1864
 
    }
1865
 
    if (is_not_immed(p->group_leader)) {
1866
 
        n_htop = collect_root_array(p, n_htop, &p->group_leader, 1);
1867
 
    }
1868
 
 
1869
 
    /*
1870
 
     * Go through the message queue, move everything that is in one of the
1871
 
     * heap fragments to our new heap.
1872
 
     */
1873
 
 
1874
 
    for (mp = p->msg.first; mp != NULL; mp = mp->next) {
1875
 
        /*
1876
 
         * In most cases, mp->data.attached points to a heap fragment which is
1877
 
         * self-contained and we will copy it to the heap at the
1878
 
         * end of the GC to avoid scanning it.
1879
 
         *
1880
 
         * In a few cases, however, such as in process_info(Pid, messages)
1881
 
         * and trace_delivered/1, a new message points to a term that has
1882
 
         * been allocated by HAlloc() and mp->data.attached is NULL. Therefore
1883
 
         * we need this loop.
1884
 
         */
1885
 
        if (mp->data.attached == NULL) {
1886
 
            n_htop = collect_root_array(p, n_htop, mp->m, 2);
1887
 
        }
1888
 
    }
1889
 
 
1890
 
    /*
1891
 
     * Now all references in the root set point to the new heap. However,
1892
 
     * many references on the new heap point to heap fragments.
1893
 
     */
1894
 
 
 
1798
     * Move the heap fragments to the new heap. Note that no GC is done on
 
1799
     * the heap fragments. Any garbage will thus be moved as well and survive
 
1800
     * until next GC.  
 
1801
     */ 
1895
1802
    qb = MBUF(p);
1896
 
    while (qb != NULL) {
1897
 
        frag_begin = (char *) qb->mem;
1898
 
        frag_size = qb->size * sizeof(Eterm);
 
1803
    while (qb != NULL) {      
 
1804
        frag_size = qb->used_size * sizeof(Eterm);
1899
1805
        if (frag_size != 0) {
1900
 
            n_htop = sweep_one_area(n_hstart, n_htop, frag_begin, frag_size);
 
1806
            frag_begin = (char *) qb->mem;
 
1807
            n_htop = move_one_area(n_htop, frag_begin, frag_size);
1901
1808
        }
1902
1809
        qb = qb->next;
1903
1810
    }
1932
1839
    }
1933
1840
 
1934
1841
    ASSERT((is_nil(p->seq_trace_token) ||
1935
 
            is_tuple(p->seq_trace_token) ||
 
1842
            is_tuple(follow_moved(p->seq_trace_token)) ||
1936
1843
            is_atom(p->seq_trace_token)));
1937
1844
    if (is_not_immed(p->seq_trace_token)) {
1938
1845
        roots[n].v = &p->seq_trace_token;
1944
1851
           is_internal_pid(p->tracer_proc) ||
1945
1852
           is_internal_port(p->tracer_proc));
1946
1853
 
1947
 
    ASSERT(is_pid(p->group_leader));
 
1854
    ASSERT(is_pid(follow_moved(p->group_leader)));
1948
1855
    if (is_not_immed(p->group_leader)) {
1949
1856
        roots[n].v  = &p->group_leader;
1950
1857
        roots[n].sz = 1;
2082
1989
    HEAP_SIZE(p) = new_sz;
2083
1990
}
2084
1991
 
2085
 
static Uint
2086
 
next_vheap_size(Uint vheap, Uint vheap_sz) {
2087
 
    if (vheap < H_MIN_SIZE) {
2088
 
        return H_MIN_SIZE;
2089
 
    }
2090
 
 
2091
 
    /* grow */
2092
 
    if (vheap > vheap_sz) {
2093
 
        return erts_next_heap_size(2*vheap, 0);
2094
 
    }
2095
 
    /* shrink */
2096
 
    if ( vheap < vheap_sz/2) {
2097
 
        return (Uint)vheap_sz*3/4;
 
1992
static Uint64
 
1993
do_next_vheap_size(Uint64 vheap, Uint64 vheap_sz) {
 
1994
 
 
1995
    /*                grow
 
1996
     *
 
1997
     * vheap_sz ======================
 
1998
     *
 
1999
     * vheap 75% +    grow
 
2000
     *          ----------------------
 
2001
     *
 
2002
     * vheap 25 - 75% same
 
2003
     *          ----------------------
 
2004
     *
 
2005
     * vheap ~ - 25% shrink
 
2006
     *
 
2007
     *          ----------------------
 
2008
     */
 
2009
 
 
2010
    if ((Uint64) vheap/3 > (Uint64) (vheap_sz/4)) {
 
2011
        Uint64 new_vheap_sz = vheap_sz;
 
2012
 
 
2013
        while((Uint64) vheap/3 > (Uint64) (vheap_sz/4)) {
 
2014
            /* the golden ratio = 1.618 */
 
2015
            new_vheap_sz = (Uint64) vheap_sz * 1.618;
 
2016
            if (new_vheap_sz < vheap_sz ) {
 
2017
                return vheap_sz;
 
2018
            }
 
2019
            vheap_sz = new_vheap_sz;
 
2020
        }
 
2021
 
 
2022
        return vheap_sz;
 
2023
    }
 
2024
 
 
2025
    if (vheap < (Uint64) (vheap_sz/4)) {
 
2026
        return (vheap_sz >> 1);
2098
2027
    }
2099
2028
 
2100
2029
    return vheap_sz;
2101
 
}
2102
 
 
2103
 
 
2104
 
static void
2105
 
sweep_proc_externals(Process *p, int fullsweep)
2106
 
{
2107
 
    ExternalThing** prev;
2108
 
    ExternalThing* ptr;
2109
 
    char* oh = 0;
2110
 
    Uint oh_size = 0;
2111
 
 
2112
 
    if (fullsweep == 0) {
2113
 
        oh = (char *) OLD_HEAP(p);
2114
 
        oh_size = (char *) OLD_HEND(p) - oh;
2115
 
    }
2116
 
 
2117
 
    prev = &MSO(p).externals;
2118
 
    ptr = MSO(p).externals;
2119
 
 
2120
 
    while (ptr) {
2121
 
        Eterm* ppt = (Eterm *) ptr;
2122
 
 
2123
 
        if (IS_MOVED(*ppt)) {        /* Object is alive */
2124
 
            ExternalThing* ro = external_thing_ptr(*ppt);
2125
 
 
2126
 
            *prev = ro;         /* Patch to moved pos */
2127
 
            prev = &ro->next;
2128
 
            ptr = ro->next;
2129
 
        } else if (in_area(ppt, oh, oh_size)) {
2130
 
            /*
2131
 
             * Object resides on old heap, and we just did a
2132
 
             * generational collection - keep object in list.
2133
 
             */
2134
 
            prev = &ptr->next;
2135
 
            ptr = ptr->next;
2136
 
        } else {                /* Object has not been moved - deref it */
2137
 
            erts_deref_node_entry(ptr->node);
2138
 
            *prev = ptr = ptr->next;
2139
 
        }
2140
 
    }
2141
 
    ASSERT(*prev == NULL);
2142
 
}
2143
 
 
2144
 
static void
2145
 
sweep_proc_funs(Process *p, int fullsweep)
2146
 
{
2147
 
    ErlFunThing** prev;
2148
 
    ErlFunThing* ptr;
2149
 
    char* oh = 0;
2150
 
    Uint oh_size = 0;
2151
 
 
2152
 
    if (fullsweep == 0) {
2153
 
        oh = (char *) OLD_HEAP(p);
2154
 
        oh_size = (char *) OLD_HEND(p) - oh;
2155
 
    }
2156
 
                      
2157
 
    prev = &MSO(p).funs;
2158
 
    ptr = MSO(p).funs;
2159
 
 
2160
 
    while (ptr) {
2161
 
        Eterm* ppt = (Eterm *) ptr;
2162
 
 
2163
 
        if (IS_MOVED(*ppt)) {        /* Object is alive */
2164
 
            ErlFunThing* ro = (ErlFunThing *) fun_val(*ppt);
2165
 
 
2166
 
            *prev = ro;         /* Patch to moved pos */
2167
 
            prev = &ro->next;
2168
 
            ptr = ro->next;
2169
 
        } else if (in_area(ppt, oh, oh_size)) {
2170
 
            /*
2171
 
             * Object resides on old heap, and we just did a
2172
 
             * generational collection - keep object in list.
2173
 
             */
2174
 
            prev = &ptr->next;
2175
 
            ptr = ptr->next;
2176
 
        } else {                /* Object has not been moved - deref it */
2177
 
            ErlFunEntry* fe = ptr->fe;
2178
 
 
2179
 
            *prev = ptr = ptr->next;
2180
 
            if (erts_refc_dectest(&fe->refc, 0) == 0) {
2181
 
                erts_erase_fun_entry(fe);
2182
 
            }
2183
 
        }
2184
 
    }
2185
 
    ASSERT(*prev == NULL);
 
2030
 
 
2031
}
 
2032
 
 
2033
static Uint64
 
2034
next_vheap_size(Process* p, Uint64 vheap, Uint64 vheap_sz) {
 
2035
    Uint64 new_vheap_sz = do_next_vheap_size(vheap, vheap_sz);
 
2036
    return new_vheap_sz < p->min_vheap_size ? p->min_vheap_size : new_vheap_sz;
2186
2037
}
2187
2038
 
2188
2039
struct shrink_cand_data {
2189
 
    ProcBin* new_candidates;
2190
 
    ProcBin* new_candidates_end;
2191
 
    ProcBin* old_candidates;
 
2040
    struct erl_off_heap_header* new_candidates;
 
2041
    struct erl_off_heap_header* new_candidates_end;
 
2042
    struct erl_off_heap_header* old_candidates;
2192
2043
    Uint no_of_candidates;
2193
2044
    Uint no_of_active;
2194
2045
};
2195
2046
 
2196
2047
static ERTS_INLINE void
2197
2048
link_live_proc_bin(struct shrink_cand_data *shrink,
2198
 
                   ProcBin ***prevppp,
2199
 
                   ProcBin **pbpp,
 
2049
                   struct erl_off_heap_header*** prevppp,
 
2050
                   struct erl_off_heap_header** currpp,
2200
2051
                   int new_heap)
2201
2052
{
2202
 
    ProcBin *pbp = *pbpp;
2203
 
 
2204
 
    *pbpp = pbp->next;
2205
 
 
 
2053
    ProcBin *pbp = (ProcBin*) *currpp;
 
2054
    ASSERT(**prevppp == *currpp);
 
2055
 
 
2056
    *currpp = pbp->next;
2206
2057
    if (pbp->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE)) {
2207
2058
        ASSERT(((pbp->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE))
2208
2059
                == (PB_ACTIVE_WRITER|PB_IS_WRITABLE))
2219
2070
            /* Our allocators are 8 byte aligned, i.e., shrinking with
2220
2071
               less than 8 bytes will have no real effect */
2221
2072
            if (unused >= 8) { /* A shrink candidate; save in candidate list */
 
2073
                **prevppp = pbp->next;
2222
2074
                if (new_heap) {
2223
2075
                    if (!shrink->new_candidates)
2224
 
                        shrink->new_candidates_end = pbp;
 
2076
                        shrink->new_candidates_end = (struct erl_off_heap_header*)pbp;
2225
2077
                    pbp->next = shrink->new_candidates;
2226
 
                    shrink->new_candidates = pbp;
 
2078
                    shrink->new_candidates = (struct erl_off_heap_header*)pbp;
2227
2079
                }
2228
2080
                else {
2229
2081
                    pbp->next = shrink->old_candidates;
2230
 
                    shrink->old_candidates = pbp;
 
2082
                    shrink->old_candidates = (struct erl_off_heap_header*)pbp;
2231
2083
                }
2232
2084
                shrink->no_of_candidates++;
2233
2085
                return;
2235
2087
        }
2236
2088
    }
2237
2089
 
2238
 
    /* Not a shrink candidate; keep in original mso list */
2239
 
    **prevppp = pbp;
 
2090
    /* Not a shrink candidate; keep in original mso list */ 
2240
2091
    *prevppp = &pbp->next;
2241
 
 
2242
2092
}
2243
2093
 
2244
2094
 
2245
 
static void 
2246
 
sweep_proc_bins(Process *p, int fullsweep)
 
2095
static void
 
2096
sweep_off_heap(Process *p, int fullsweep)
2247
2097
{
2248
2098
    struct shrink_cand_data shrink = {0};
2249
 
    ProcBin** prev;
2250
 
    ProcBin* ptr;
2251
 
    Binary* bptr;
2252
 
    char* oh = NULL;
2253
 
    Uint oh_size = 0;
2254
 
    Uint bin_vheap = 0;
 
2099
    struct erl_off_heap_header* ptr;
 
2100
    struct erl_off_heap_header** prev;
 
2101
    char* oheap = NULL;
 
2102
    Uint oheap_sz = 0;
 
2103
    Uint64 bin_vheap = 0;
 
2104
#ifdef DEBUG
 
2105
    int seen_mature = 0;
 
2106
#endif
2255
2107
 
2256
2108
    if (fullsweep == 0) {
2257
 
        oh = (char *) OLD_HEAP(p);
2258
 
        oh_size = (char *) OLD_HEND(p) - oh;
 
2109
        oheap = (char *) OLD_HEAP(p);
 
2110
        oheap_sz = (char *) OLD_HEND(p) - oheap;
2259
2111
    }
2260
2112
 
2261
2113
    BIN_OLD_VHEAP(p) = 0;
2262
2114
 
2263
 
    prev = &MSO(p).mso;
2264
 
    ptr = MSO(p).mso;
2265
 
 
2266
 
    /*
2267
 
     * Note: In R7 we no longer force a fullsweep when we find binaries
2268
 
     * on the old heap. The reason is that with the introduction of the
2269
 
     * bit syntax we can expect binaries to be used a lot more. Note that
2270
 
     * in earlier releases a brand new binary (or any other term) could
2271
 
     * be put on the old heap during a gen-gc fullsweep, but this is
2272
 
     * no longer the case in R7.
2273
 
     */
2274
 
    while (ptr) {
2275
 
        Eterm* ppt = (Eterm *) ptr;
2276
 
 
2277
 
        if (IS_MOVED(*ppt)) {        /* Object is alive */
2278
 
            bin_vheap += ptr->size / sizeof(Eterm);
2279
 
            ptr = (ProcBin*) binary_val(*ppt);             
2280
 
            link_live_proc_bin(&shrink,
2281
 
                               &prev,
2282
 
                               &ptr,
2283
 
                               !in_area(ptr, oh, oh_size)); 
2284
 
        } else if (in_area(ppt, oh, oh_size)) {
2285
 
            /*
2286
 
             * Object resides on old heap, and we just did a
2287
 
             * generational collection - keep object in list.
2288
 
             */
2289
 
            BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/
2290
 
            link_live_proc_bin(&shrink, &prev, &ptr, 0); 
2291
 
        } else {                /* Object has not been moved - deref it */
2292
 
 
2293
 
            *prev = ptr->next;
2294
 
            bptr = ptr->val;
2295
 
            if (erts_refc_dectest(&bptr->refc, 0) == 0)
2296
 
                erts_bin_free(bptr);
2297
 
            ptr = *prev;
2298
 
        }
2299
 
    }
2300
 
 
2301
 
    if (BIN_OLD_VHEAP(p) >= BIN_OLD_VHEAP_SZ(p)) {
2302
 
        FLAGS(p) |= F_NEED_FULLSWEEP;
2303
 
    }
2304
 
 
2305
 
    BIN_VHEAP_SZ(p) = next_vheap_size(bin_vheap, BIN_VHEAP_SZ(p));
2306
 
    BIN_OLD_VHEAP_SZ(p) = next_vheap_size(BIN_OLD_VHEAP(p), BIN_OLD_VHEAP_SZ(p));
2307
 
    MSO(p).overhead = bin_vheap;
 
2115
    prev = &MSO(p).first;
 
2116
    ptr = MSO(p).first;
 
2117
 
 
2118
    /* Firts part of the list will reside on the (old) new-heap.
 
2119
     * Keep if moved, otherwise deref.
 
2120
     */
 
2121
    while (ptr) {
 
2122
        if (IS_MOVED_BOXED(ptr->thing_word)) {
 
2123
            ASSERT(!in_area(ptr, oheap, oheap_sz));
 
2124
            *prev = ptr = (struct erl_off_heap_header*) boxed_val(ptr->thing_word);
 
2125
            ASSERT(!IS_MOVED_BOXED(ptr->thing_word));
 
2126
            if (ptr->thing_word == HEADER_PROC_BIN) {
 
2127
                int to_new_heap = !in_area(ptr, oheap, oheap_sz);
 
2128
                ASSERT(to_new_heap == !seen_mature || (!to_new_heap && (seen_mature=1)));
 
2129
                if (to_new_heap) {
 
2130
                    bin_vheap += ptr->size / sizeof(Eterm);
 
2131
                } else {
 
2132
                    BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/
 
2133
                }               
 
2134
                link_live_proc_bin(&shrink, &prev, &ptr, to_new_heap);
 
2135
            }
 
2136
            else {
 
2137
                prev = &ptr->next;
 
2138
                ptr = ptr->next;
 
2139
            }
 
2140
        }
 
2141
        else if (!in_area(ptr, oheap, oheap_sz)) {
 
2142
            /* garbage */
 
2143
            switch (thing_subtag(ptr->thing_word)) {
 
2144
            case REFC_BINARY_SUBTAG:
 
2145
                {
 
2146
                    Binary* bptr = ((ProcBin*)ptr)->val;        
 
2147
                    if (erts_refc_dectest(&bptr->refc, 0) == 0) {
 
2148
                        erts_bin_free(bptr);
 
2149
                    }
 
2150
                    break;
 
2151
                }
 
2152
            case FUN_SUBTAG:
 
2153
                {
 
2154
                    ErlFunEntry* fe = ((ErlFunThing*)ptr)->fe;
 
2155
                    if (erts_refc_dectest(&fe->refc, 0) == 0) {
 
2156
                        erts_erase_fun_entry(fe);
 
2157
                    }
 
2158
                    break;
 
2159
                }
 
2160
            default:
 
2161
                ASSERT(is_external_header(ptr->thing_word));
 
2162
                erts_deref_node_entry(((ExternalThing*)ptr)->node);
 
2163
            }
 
2164
            *prev = ptr = ptr->next;
 
2165
        }
 
2166
        else break; /* and let old-heap loop continue */
 
2167
    }
 
2168
 
 
2169
    /* The rest of the list resides on old-heap, and we just did a
 
2170
     * generational collection - keep objects in list.
 
2171
     */
 
2172
    while (ptr) {
 
2173
        ASSERT(in_area(ptr, oheap, oheap_sz));
 
2174
        ASSERT(!IS_MOVED_BOXED(ptr->thing_word));       
 
2175
        if (ptr->thing_word == HEADER_PROC_BIN) {
 
2176
            BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/
 
2177
            link_live_proc_bin(&shrink, &prev, &ptr, 0);
 
2178
        }
 
2179
        else {
 
2180
            ASSERT(is_fun_header(ptr->thing_word) ||
 
2181
                   is_external_header(ptr->thing_word));
 
2182
            prev = &ptr->next;
 
2183
            ptr = ptr->next;
 
2184
        }
 
2185
    }
 
2186
 
 
2187
    if (fullsweep) {
 
2188
        BIN_OLD_VHEAP_SZ(p) = next_vheap_size(p, BIN_OLD_VHEAP(p) + MSO(p).overhead, BIN_OLD_VHEAP_SZ(p));
 
2189
    }
 
2190
    BIN_VHEAP_SZ(p)     = next_vheap_size(p, bin_vheap, BIN_VHEAP_SZ(p));
 
2191
    MSO(p).overhead     = bin_vheap;
 
2192
    BIN_VHEAP_MATURE(p) = bin_vheap;
2308
2193
 
2309
2194
    /*
2310
2195
     * If we got any shrink candidates, check them out.
2311
2196
     */
2312
2197
 
2313
2198
    if (shrink.no_of_candidates) {
2314
 
        ProcBin *candlist[] = {shrink.new_candidates, shrink.old_candidates};
 
2199
        ProcBin *candlist[] = { (ProcBin*)shrink.new_candidates,
 
2200
                                (ProcBin*)shrink.old_candidates };
2315
2201
        Uint leave_unused = 0;
2316
2202
        int i;
2317
2203
 
2323
2209
        }
2324
2210
 
2325
2211
        for (i = 0; i < sizeof(candlist)/sizeof(candlist[0]); i++) {
2326
 
 
2327
 
            for (ptr = candlist[i]; ptr; ptr = ptr->next) {
2328
 
                Uint new_size = ptr->size;
 
2212
            ProcBin* pb;
 
2213
            for (pb = candlist[i]; pb; pb = (ProcBin*)pb->next) {
 
2214
                Uint new_size = pb->size;
2329
2215
 
2330
2216
                if (leave_unused) {
2331
2217
                    new_size += (new_size * 100) / leave_unused;
2332
2218
                    /* Our allocators are 8 byte aligned, i.e., shrinking with
2333
2219
                       less than 8 bytes will have no real effect */
2334
 
                    if (new_size + 8 >= ptr->val->orig_size)
 
2220
                    if (new_size + 8 >= pb->val->orig_size)
2335
2221
                        continue;
2336
2222
                }
2337
2223
 
2338
 
                ptr->val = erts_bin_realloc(ptr->val, new_size);
2339
 
                ptr->val->orig_size = new_size;
2340
 
                ptr->bytes = (byte *) ptr->val->orig_bytes;
 
2224
                pb->val = erts_bin_realloc(pb->val, new_size);
 
2225
                pb->val->orig_size = new_size;
 
2226
                pb->bytes = (byte *) pb->val->orig_bytes;
2341
2227
            }
2342
2228
        }
2343
2229
 
2346
2232
         * We now potentially have the mso list divided into three lists:
2347
2233
         * - shrink candidates on new heap (inactive writable with unused data)
2348
2234
         * - shrink candidates on old heap (inactive writable with unused data)
2349
 
         * - other binaries (read only + active writable ...)
 
2235
         * - other binaries (read only + active writable ...) + funs and externals
2350
2236
         *
2351
2237
         * Put them back together: new candidates -> other -> old candidates
2352
2238
         * This order will ensure that the list only refers from new
2353
2239
         * generation to old and never from old to new *which is important*.
2354
2240
         */
2355
2241
        if (shrink.new_candidates) {
2356
 
            if (prev == &MSO(p).mso) /* empty other binaries list */
 
2242
            if (prev == &MSO(p).first) /* empty other binaries list */
2357
2243
                prev = &shrink.new_candidates_end->next;
2358
2244
            else
2359
 
                shrink.new_candidates_end->next = MSO(p).mso;
2360
 
            MSO(p).mso = shrink.new_candidates;
 
2245
                shrink.new_candidates_end->next = MSO(p).first;
 
2246
            MSO(p).first = shrink.new_candidates;
2361
2247
        }
2362
2248
    }
2363
 
 
2364
2249
    *prev = shrink.old_candidates;
2365
2250
}
2366
2251
 
2391
2276
              tari = thing_arityval(val);
2392
2277
              switch (thing_subtag(val)) {
2393
2278
              case REFC_BINARY_SUBTAG:
 
2279
              case FUN_SUBTAG:
 
2280
              case EXTERNAL_PID_SUBTAG:
 
2281
              case EXTERNAL_PORT_SUBTAG:
 
2282
              case EXTERNAL_REF_SUBTAG:
2394
2283
                  {
2395
 
                      ProcBin* pb = (ProcBin*) hp;
2396
 
                      Eterm** uptr = (Eterm **) (void *) &pb->next;
 
2284
                      struct erl_off_heap_header* oh = (struct erl_off_heap_header*) hp;
2397
2285
 
2398
 
                      if (*uptr && in_area((Eterm *)pb->next, area, area_size)) {
 
2286
                      if (in_area(oh->next, area, area_size)) {
 
2287
                          Eterm** uptr = (Eterm **) (void *) &oh->next;
2399
2288
                          *uptr += offs; /* Patch the mso chain */
2400
2289
                      }
2401
 
                      sz -= tari;
2402
 
                      hp += tari + 1;
2403
2290
                  }
2404
2291
                  break;
2405
2292
              case BIN_MATCHSTATE_SUBTAG:
2410
2297
                      mb->orig = offset_ptr(mb->orig, offs);
2411
2298
                      mb->base = binary_bytes(mb->orig);
2412
2299
                  }
2413
 
                  sz -= tari;
2414
 
                  hp += tari + 1;
2415
2300
                }
2416
2301
                break;
2417
 
              case FUN_SUBTAG:
2418
 
                  {
2419
 
                      ErlFunThing* funp = (ErlFunThing *) hp;
2420
 
                      Eterm** uptr = (Eterm **) (void *) &funp->next;
2421
 
 
2422
 
                      if (*uptr && in_area((Eterm *)funp->next, area, area_size)) {
2423
 
                          *uptr += offs;
2424
 
                      }
2425
 
                      sz -= tari;
2426
 
                      hp += tari + 1;
2427
 
                  }
2428
 
                  break;
2429
 
              case EXTERNAL_PID_SUBTAG:
2430
 
              case EXTERNAL_PORT_SUBTAG:
2431
 
              case EXTERNAL_REF_SUBTAG:
2432
 
                  {
2433
 
                      ExternalThing* etp = (ExternalThing *) hp;
2434
 
                      Eterm** uptr = (Eterm **) (void *) &etp->next;
2435
 
 
2436
 
                      if (*uptr && in_area((Eterm *)etp->next, area, area_size)) {
2437
 
                          *uptr += offs;
2438
 
                      }
2439
 
                      sz -= tari;
2440
 
                      hp += tari + 1;
2441
 
                  }
2442
 
                  break;
2443
 
              default:
2444
 
                  sz -= tari;
2445
 
                  hp += tari + 1;
2446
2302
              }
 
2303
              sz -= tari;
 
2304
              hp += tari + 1;
2447
2305
              break;
2448
2306
          }
2449
2307
          default:
2480
2338
static void
2481
2339
offset_off_heap(Process* p, Sint offs, char* area, Uint area_size)
2482
2340
{
2483
 
    if (MSO(p).mso && in_area((Eterm *)MSO(p).mso, area, area_size)) {
2484
 
        Eterm** uptr = (Eterm**) (void *) &MSO(p).mso;
2485
 
        *uptr += offs;
2486
 
    }
2487
 
 
2488
 
    if (MSO(p).funs && in_area((Eterm *)MSO(p).funs, area, area_size)) {
2489
 
        Eterm** uptr = (Eterm**) (void *) &MSO(p).funs;
2490
 
        *uptr += offs;
2491
 
    }
2492
 
 
2493
 
    if (MSO(p).externals && in_area((Eterm *)MSO(p).externals, area, area_size)) {
2494
 
        Eterm** uptr = (Eterm**) (void *) &MSO(p).externals;
 
2341
    if (MSO(p).first && in_area((Eterm *)MSO(p).first, area, area_size)) {
 
2342
        Eterm** uptr = (Eterm**) (void *) &MSO(p).first;
2495
2343
        *uptr += offs;
2496
2344
    }
2497
2345
}
2572
2420
        return 1;
2573
2421
    }
2574
2422
    while (bp != NULL) {
2575
 
        if (bp->mem <= ptr && ptr < bp->mem + bp->size) {
 
2423
        if (bp->mem <= ptr && ptr < bp->mem + bp->used_size) {
2576
2424
            return 1;
2577
2425
        }
2578
2426
        bp = bp->next;
2586
2434
                hfp = erts_dist_ext_trailer(mp->data.dist_ext);
2587
2435
            else
2588
2436
                hfp = NULL;
2589
 
            if (hfp && hfp->mem <= ptr && ptr < hfp->mem + hfp->size)
 
2437
            if (hfp && hfp->mem <= ptr && ptr < hfp->mem + hfp->used_size)
2590
2438
                return 1;
2591
2439
        }
2592
2440
        mp = mp->next;
2612
2460
                 __FILE__, __LINE__, #EXP);             \
2613
2461
} while (0)
2614
2462
 
2615
 
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
2616
 
#  define ERTS_EXTERNAL_VISITED_BIT ((Eterm) 1 << 31)
 
2463
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_LIST
 
2464
#  define ERTS_OFFHEAP_VISITED_BIT ((Eterm) 1 << 31)
2617
2465
#endif
2618
2466
 
2619
2467
 
2623
2471
    Eterm *oheap = (Eterm *) OLD_HEAP(p);
2624
2472
    Eterm *ohtop = (Eterm *) OLD_HTOP(p);
2625
2473
    int old;
2626
 
    ProcBin *pb;
2627
 
    ErlFunThing *eft;
2628
 
    ExternalThing *et;
 
2474
    union erl_off_heap_ptr u;
2629
2475
 
2630
2476
    old = 0;
2631
 
    for (pb = MSO(p).mso; pb; pb = pb->next) {
2632
 
        Eterm *ptr = (Eterm *) pb;
2633
 
        long refc = erts_refc_read(&pb->val->refc, 1);
 
2477
    for (u.hdr = MSO(p).first; u.hdr; u.hdr = u.hdr->next) {
 
2478
        erts_aint_t refc;
 
2479
        switch (thing_subtag(u.hdr->thing_word)) {
 
2480
        case REFC_BINARY_SUBTAG:
 
2481
            refc = erts_refc_read(&u.pb->val->refc, 1);         
 
2482
            break;
 
2483
        case FUN_SUBTAG:
 
2484
            refc = erts_refc_read(&u.fun->fe->refc, 1);
 
2485
            break;
 
2486
        case EXTERNAL_PID_SUBTAG:
 
2487
        case EXTERNAL_PORT_SUBTAG:
 
2488
        case EXTERNAL_REF_SUBTAG:
 
2489
            refc = erts_refc_read(&u.ext->node->refc, 1);
 
2490
            break;
 
2491
        default:
 
2492
            ASSERT(!!"erts_check_off_heap2: Invalid thing_word");
 
2493
        }
2634
2494
        ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
 
2495
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_LIST
 
2496
        ERTS_CHK_OFFHEAP_ASSERT(!(u.hdr->thing_word & ERTS_EXTERNAL_VISITED_BIT));
 
2497
        u.hdr->thing_word |= ERTS_OFFHEAP_VISITED_BIT;
 
2498
#endif
2635
2499
        if (old) {
2636
 
            ERTS_CHK_OFFHEAP_ASSERT(oheap <= ptr && ptr < ohtop);
 
2500
            ERTS_CHK_OFFHEAP_ASSERT(oheap <= u.ep && u.ep < ohtop);
2637
2501
        }
2638
 
        else if (oheap <= ptr && ptr < ohtop)
 
2502
        else if (oheap <= u.ep && u.ep < ohtop)
2639
2503
            old = 1;
2640
2504
        else {
2641
 
            ERTS_CHK_OFFHEAP_ASSERT(within2(ptr, p, htop));
 
2505
            ERTS_CHK_OFFHEAP_ASSERT(within2(u.ep, p, htop));
2642
2506
        }
2643
2507
    }
2644
2508
 
2645
 
    old = 0;
2646
 
    for (eft = MSO(p).funs; eft; eft = eft->next) {
2647
 
        Eterm *ptr = (Eterm *) eft;
2648
 
        long refc = erts_refc_read(&eft->fe->refc, 1);
2649
 
        ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
2650
 
        if (old)
2651
 
            ERTS_CHK_OFFHEAP_ASSERT(oheap <= ptr && ptr < ohtop);
2652
 
        else if (oheap <= ptr && ptr < ohtop)
2653
 
            old = 1;
2654
 
        else
2655
 
            ERTS_CHK_OFFHEAP_ASSERT(within2(ptr, p, htop));
2656
 
    }
2657
 
 
2658
 
    old = 0;
2659
 
    for (et = MSO(p).externals; et; et = et->next) {
2660
 
        Eterm *ptr = (Eterm *) et;
2661
 
        long refc = erts_refc_read(&et->node->refc, 1);
2662
 
        ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
2663
 
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
2664
 
        ERTS_CHK_OFFHEAP_ASSERT(!(et->header & ERTS_EXTERNAL_VISITED_BIT));
2665
 
#endif
2666
 
        if (old)
2667
 
            ERTS_CHK_OFFHEAP_ASSERT(oheap <= ptr && ptr < ohtop);
2668
 
        else if (oheap <= ptr && ptr < ohtop)
2669
 
            old = 1;
2670
 
        else
2671
 
            ERTS_CHK_OFFHEAP_ASSERT(within2(ptr, p, htop));
2672
 
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
2673
 
        et->header |= ERTS_EXTERNAL_VISITED_BIT;
2674
 
#endif
2675
 
    }
2676
 
 
2677
 
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
2678
 
    for (et = MSO(p).externals; et; et = et->next)
2679
 
        et->header &= ~ERTS_EXTERNAL_VISITED_BIT;
2680
 
#endif
2681
 
        
 
2509
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
 
2510
    for (u.hdr = MSO(p).first; u.hdr; u.hdr = u.hdr->next)
 
2511
        u.hdr->thing_word &= ~ERTS_OFFHEAP_VISITED_BIT;
 
2512
#endif
2682
2513
}
2683
2514
 
2684
2515
void