--- old/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp 2015-01-29 10:54:36.853557888 +0100 +++ new/src/share/vm/gc_implementation/g1/g1PageBasedVirtualSpace.cpp 2015-01-29 10:54:36.778555697 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,36 +45,42 @@ #include "utilities/bitMap.inline.hpp" G1PageBasedVirtualSpace::G1PageBasedVirtualSpace() : _low_boundary(NULL), - _high_boundary(NULL), _committed(), _page_size(0), _special(false), + _high_boundary(NULL), _committed(), _commit_size(0), _special(false), _dirty(), _executable(false) { } -bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t page_size) { +bool G1PageBasedVirtualSpace::initialize_with_granularity(ReservedSpace rs, size_t actual_size, size_t commit_size) { if (!rs.is_reserved()) { return false; // Allocation failed. } assert(_low_boundary == NULL, "VirtualSpace already initialized"); - assert(page_size > 0, "Granularity must be non-zero."); + assert(commit_size > 0, "Granularity must be non-zero."); + + guarantee(is_ptr_aligned(rs.base(), commit_size), + err_msg("Reserved space base " PTR_FORMAT" is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), commit_size)); + guarantee(is_size_aligned(actual_size, os::vm_page_size()), + err_msg("Given actual reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), actual_size)); + guarantee(actual_size <= rs.size(), + err_msg("Actual size of reserved space " SIZE_FORMAT" bytes is smaller than reservation at " SIZE_FORMAT" bytes", actual_size, rs.size())); _low_boundary = rs.base(); - _high_boundary = _low_boundary + rs.size(); + _high_boundary = _low_boundary + actual_size; _special = rs.special(); _executable = rs.executable(); - _page_size = page_size; + _commit_size = commit_size; assert(_committed.size() == 0, "virtual space initialized more than once"); - uintx size_in_bits = rs.size() / page_size; - _committed.resize(size_in_bits, /* in_resource_area */ false); + BitMap::idx_t size_in_pages = align_size_up(rs.size(), commit_size) / commit_size; + _committed.resize(size_in_pages, /* in_resource_area */ false); if (_special) { - _dirty.resize(size_in_bits, /* in_resource_area */ false); + _dirty.resize(size_in_pages, /* in_resource_area */ false); } return true; } - G1PageBasedVirtualSpace::~G1PageBasedVirtualSpace() { release(); } @@ -86,13 +92,18 @@ _high_boundary = NULL; _special = false; _executable = false; - _page_size = 0; + _commit_size = 0; _committed.resize(0, false); _dirty.resize(0, false); } size_t G1PageBasedVirtualSpace::committed_size() const { - return _committed.count_one_bits() * _page_size; + size_t result = _committed.count_one_bits() * _commit_size; + // The last page might not be in full. + if (_committed.at(_committed.size()-1)) { + result -= pointer_delta((char*)align_ptr_up(_high_boundary, _commit_size), _high_boundary, sizeof(char)); + } + return result; } size_t G1PageBasedVirtualSpace::reserved_size() const { @@ -104,7 +115,7 @@ } uintptr_t G1PageBasedVirtualSpace::addr_to_page_index(char* addr) const { - return (addr - _low_boundary) / _page_size; + return (addr - _low_boundary) / _commit_size; } bool G1PageBasedVirtualSpace::is_area_committed(uintptr_t start, size_t size_in_pages) const { @@ -118,11 +129,48 @@ } char* G1PageBasedVirtualSpace::page_start(uintptr_t index) { - return _low_boundary + index * _page_size; + return _low_boundary + index * _commit_size; } -size_t G1PageBasedVirtualSpace::byte_size_for_pages(size_t num) { - return num * _page_size; +char* G1PageBasedVirtualSpace::page_end(uintptr_t index) { + guarantee(index < _committed.size(), "invariant"); + if (index != (_committed.size() - 1)) { + return page_start(index + 1); + } + return _high_boundary; +} + +void G1PageBasedVirtualSpace::commit_int(char* start, char* end) { + guarantee(start >= _low_boundary && start < _high_boundary, + err_msg("Start address " PTR_FORMAT" is outside of reserved space.", p2i(start))); + guarantee(is_ptr_aligned(start, _commit_size), + err_msg("Start address should be aligned to commit size " SIZE_FORMAT" but got " PTR_FORMAT".", + _commit_size, p2i(start))); + + guarantee(end >= _low_boundary && end <= _high_boundary, + err_msg("End address " PTR_FORMAT" is outside of reserved space.", p2i(end))); + bool is_high_aligned_to_commit_size = is_ptr_aligned(_high_boundary, _commit_size); + guarantee(is_ptr_aligned(end, is_high_aligned_to_commit_size ? _commit_size : os::vm_page_size()), + err_msg("End address should be aligned to page size " SIZE_FORMAT" but got " PTR_FORMAT".", + is_high_aligned_to_commit_size ? _commit_size : os::vm_page_size(), + p2i(end))); + // First try to commit in commit_size chunks. + char* const aligned_end_address = (char*)align_ptr_down(end, _commit_size); + size_t const size = pointer_delta(aligned_end_address, start, sizeof(char)); + if (size != 0) { + os::commit_memory_or_exit(start, size, _commit_size, _executable, + err_msg("Failed to commit area from " PTR_FORMAT" to " PTR_FORMAT" of length " SIZE_FORMAT".", + p2i(start), p2i(aligned_end_address), size)); + } + // Finally, commit any remaining tail. + if (end != aligned_end_address) { + size_t const tail_size = pointer_delta(end, aligned_end_address, sizeof(char)); + guarantee(tail_size < _commit_size, + err_msg("Remaining size " SIZE_FORMAT "must be smaller than commit size of " SIZE_FORMAT, tail_size, _commit_size)); + os::commit_memory_or_exit(start, tail_size, _executable, + err_msg("Failed to commit remainder pages from " PTR_FORMAT" to " PTR_FORMAT" of length "SIZE_FORMAT".", + p2i(aligned_end_address), p2i(end), tail_size)); + } } bool G1PageBasedVirtualSpace::commit(uintptr_t start, size_t size_in_pages) { @@ -139,29 +187,33 @@ _dirty.clear_range(start, end); } } else { - os::commit_memory_or_exit(page_start(start), byte_size_for_pages(size_in_pages), _executable, - err_msg("Failed to commit pages from "SIZE_FORMAT" of length "SIZE_FORMAT, start, size_in_pages)); + commit_int(page_start(start), page_end(end - 1)); } _committed.set_range(start, end); if (AlwaysPreTouch) { - os::pretouch_memory(page_start(start), page_start(end)); + os::pretouch_memory(page_start(start), page_end(end - 1)); } return zero_filled; } +void G1PageBasedVirtualSpace::uncommit_int(char* start, char* end) { + os::uncommit_memory(start, pointer_delta(end, start, sizeof(char))); +} + void G1PageBasedVirtualSpace::uncommit(uintptr_t start, size_t size_in_pages) { guarantee(is_area_committed(start, size_in_pages), "checking"); + uintptr_t end = start + size_in_pages; if (_special) { // Mark that memory is dirty. If committed again the memory might // need to be cleared explicitly. - _dirty.set_range(start, start + size_in_pages); + _dirty.set_range(start, end); } else { - os::uncommit_memory(page_start(start), byte_size_for_pages(size_in_pages)); + uncommit_int(page_start(start), page_end(end - 1)); } - _committed.clear_range(start, start + size_in_pages); + _committed.clear_range(start, end); } bool G1PageBasedVirtualSpace::contains(const void* p) const { @@ -175,7 +227,7 @@ out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(_low_boundary), p2i(_high_boundary)); + out->print_cr(" - [low_b, high_b]: [" PTR_FORMAT", " PTR_FORMAT"]", p2i(_low_boundary), p2i(_high_boundary)); } void G1PageBasedVirtualSpace::print() {