collector.cpp 4.57 KB
Newer Older
Kevin Modzelewski's avatar
Kevin Modzelewski committed
1
// Copyright (c) 2014 Dropbox, Inc.
Kevin Modzelewski's avatar
Kevin Modzelewski committed
2
//
Kevin Modzelewski's avatar
Kevin Modzelewski committed
3 4 5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Kevin Modzelewski's avatar
Kevin Modzelewski committed
6
//
Kevin Modzelewski's avatar
Kevin Modzelewski committed
7
//    http://www.apache.org/licenses/LICENSE-2.0
Kevin Modzelewski's avatar
Kevin Modzelewski committed
8
//
Kevin Modzelewski's avatar
Kevin Modzelewski committed
9 10 11 12 13 14
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15 16
#include "gc/collector.h"

Kevin Modzelewski's avatar
Kevin Modzelewski committed
17 18 19 20
#include <cassert>
#include <cstdio>
#include <cstdlib>

21
#include "codegen/codegen.h"
Kevin Modzelewski's avatar
Kevin Modzelewski committed
22
#include "core/common.h"
23
#include "core/threading.h"
Kevin Modzelewski's avatar
Kevin Modzelewski committed
24
#include "core/types.h"
25
#include "core/util.h"
Kevin Modzelewski's avatar
Kevin Modzelewski committed
26 27 28
#include "gc/heap.h"
#include "gc/root_finder.h"

29 30 31 32
#ifndef NVALGRIND
#include "valgrind.h"
#endif

Kevin Modzelewski's avatar
Kevin Modzelewski committed
33 34 35
//#undef VERBOSITY
//#define VERBOSITY(x) 2

Kevin Modzelewski's avatar
Kevin Modzelewski committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
namespace pyston {
namespace gc {

static TraceStack roots;
void registerStaticRootObj(void* obj) {
    assert(global_heap.getAllocationFromInteriorPointer(obj));
    roots.push(obj);
}

bool TraceStackGCVisitor::isValid(void* p) {
    return global_heap.getAllocationFromInteriorPointer(p);
}

inline void TraceStackGCVisitor::_visit(void* p) {
    assert(isValid(p));
    stack->push(p);
}

void TraceStackGCVisitor::visit(void* p) {
    _visit(p);
}

58
void TraceStackGCVisitor::visitRange(void* const* start, void* const* end) {
59
#ifndef NDEBUG
60
    void* const* cur = start;
Kevin Modzelewski's avatar
Kevin Modzelewski committed
61 62 63
    while (cur < end) {
        assert(isValid(*cur));
        cur++;
Kevin Modzelewski's avatar
Kevin Modzelewski committed
64
    }
65 66
#endif
    stack->pushall(start, end);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
67 68 69 70 71 72 73 74 75
}

void TraceStackGCVisitor::visitPotential(void* p) {
    void* a = global_heap.getAllocationFromInteriorPointer(p);
    if (a) {
        visit(a);
    }
}

76
void TraceStackGCVisitor::visitPotentialRange(void* const* start, void* const* end) {
Kevin Modzelewski's avatar
Kevin Modzelewski committed
77 78 79 80 81 82 83 84 85 86 87
    while (start < end) {
        visitPotential(*start);
        start++;
    }
}

#define MAX_KINDS 1024
#define KIND_OFFSET 0x111
static kindid_t num_kinds = 0;
static AllocationKind::GCHandler handlers[MAX_KINDS];

88
extern "C" kindid_t registerKind(const AllocationKind* kind) {
Kevin Modzelewski's avatar
Kevin Modzelewski committed
89 90 91 92 93 94 95 96
    assert(kind == &untracked_kind || kind->gc_handler);
    assert(num_kinds < MAX_KINDS);
    assert(handlers[num_kinds] == NULL);
    handlers[num_kinds] = kind->gc_handler;
    return KIND_OFFSET + num_kinds++;
}

static void markPhase() {
97 98 99 100 101 102
#ifndef NVALGRIND
    // Have valgrind close its eyes while we do the conservative stack and data scanning,
    // since we'll be looking at potentially-uninitialized values:
    VALGRIND_DISABLE_ERROR_REPORTING;
#endif

Kevin Modzelewski's avatar
Kevin Modzelewski committed
103 104 105 106 107
    TraceStack stack(roots);
    collectStackRoots(&stack);

    TraceStackGCVisitor visitor(&stack);

108
    // if (VERBOSITY()) printf("Found %d roots\n", stack.size());
Kevin Modzelewski's avatar
Kevin Modzelewski committed
109 110 111
    while (void* p = stack.pop()) {
        assert(((intptr_t)p) % 8 == 0);
        GCObjectHeader* header = headerFromObject(p);
112
        // printf("%p\n", p);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
113 114

        if (isMarked(header)) {
115
            // printf("Already marked, skipping\n");
Kevin Modzelewski's avatar
Kevin Modzelewski committed
116 117 118
            continue;
        }

119
        // printf("Marking + scanning %p\n", p);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
120 121 122

        setMark(header);

123 124 125 126
        // is being made
        if (header->kind_id == 0)
            continue;

127 128
        ASSERT(KIND_OFFSET <= header->kind_id && header->kind_id < KIND_OFFSET + num_kinds, "%p %d", header,
               header->kind_id);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
129 130 131 132

        if (header->kind_id == untracked_kind.kind_id)
            continue;

133 134
        // ASSERT(kind->_cookie == AllocationKind::COOKIE, "%lx %lx", kind->_cookie, AllocationKind::COOKIE);
        // AllocationKind::GCHandler gcf = kind->gc_handler;
Kevin Modzelewski's avatar
Kevin Modzelewski committed
135 136 137
        AllocationKind::GCHandler gcf = handlers[header->kind_id - KIND_OFFSET];

        assert(gcf);
138 139 140
        // if (!gcf) {
        // std::string name = g.func_addr_registry.getFuncNameAtAddress((void*)kind, true);
        // ASSERT(gcf, "%p %s", kind, name.c_str());
Kevin Modzelewski's avatar
Kevin Modzelewski committed
141 142 143 144
        //}

        gcf(&visitor, p);
    }
145 146 147 148

#ifndef NVALGRIND
    VALGRIND_ENABLE_ERROR_REPORTING;
#endif
Kevin Modzelewski's avatar
Kevin Modzelewski committed
149 150 151 152 153 154 155 156 157 158 159
}

static void sweepPhase() {
    global_heap.freeUnmarked();
}

static int ncollections = 0;
void runCollection() {
    static StatCounter sc("gc_collections");
    sc.log();

160 161
    if (VERBOSITY("gc") >= 2)
        printf("Collection #%d\n", ++ncollections);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
162

163 164 165 166 167
    threading::GLPromoteRegion _lock;

    Timer _t("collecting", /*min_usec=*/10000);


168 169
    // if (ncollections == 754) {
    // raise(SIGTRAP);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
170 171 172 173
    //}

    markPhase();
    sweepPhase();
174 175 176 177 178 179
    if (VERBOSITY("gc") >= 2)
        printf("Collection #%d done\n", ++ncollections);

    long us = _t.end();
    static StatCounter sc_us("gc_collections_us");
    sc_us.log(us);
Kevin Modzelewski's avatar
Kevin Modzelewski committed
180 181 182 183
}

} // namespace gc
} // namespace pyston