AutoWriteBarrier.cpp   [plain text]


/*
 * Copyright (c) 2004-2008 Apple Inc. All rights reserved.
 *
 * @APPLE_APACHE_LICENSE_HEADER_START@
 * 
 * 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
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * 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.
 * 
 * @APPLE_APACHE_LICENSE_HEADER_END@
 */

#include "AutoConfiguration.h"
#include "AutoDefs.h"
#include "AutoRange.h"
#include "AutoMemoryScanner.h"
#include "AutoWriteBarrier.h"
#include "AutoZone.h"


namespace Auto {

    //----- WriteBarrier -----//
    
    
    //
    // scan_ranges
    //
    // Scan ranges in block that are marked in the write barrier.
    //
    void WriteBarrier::scan_ranges(void *address, const usword_t size, MemoryScanner &scanner) {
        // determine the end address
        void *end = displace(address, size);
        // determine the last used address
        void *last = displace(address, size - 1);
        // get the write barrier index for the begining of the block
        usword_t i = card_index(address);
        // get the write barrier index for the end of the block
        const usword_t j = card_index(last);
        
        WriteBarrier *wb = scanner.zone()->repair_write_barrier() ? this : NULL;
        while (true) {
            // skip over unmarked ranges
            for ( ; i <= j && !is_card_marked(i); i++) {}
            
            // if no marks then we are done
            if (i > j) break;
            
            // scan the marks
            usword_t k = i;
            for ( ; i <= j && is_card_marked(i); i++) {}
            
            // set up the begin and end of the marked range
            void *range_begin = card_address(k);
            void *range_end = card_address(i);
            
            // truncate the range to reflect address range
            if (range_begin < address) range_begin = address;
            if (range_end > end) range_end = end;

            // scan range
            Range range(range_begin, range_end);
            scanner.scan_range(range, wb);
        }
    }

    // this is only called from Zone::mark_write_barriers_untouched().
    void WriteBarrier::mark_cards_untouched() {
        for (unsigned char *card = (unsigned char*)address() + _protect, *limit = (unsigned char *)end(); card != limit; ++card) {
            if (*card == card_marked_untouched) *card = card_marked_untouched;
        }
    }
    
    // this is only called from Zone::clear_untouched_write_barriers().
    void WriteBarrier::clear_untouched_cards() {
        for (unsigned char *card = (unsigned char*)address() + _protect, *limit = (unsigned char *)end(); card != limit; ++card) {
            if (*card == card_marked_untouched) *card = card_unmarked;
        }
    }
};