From 0e76458fca8c289d1e0349757d78ab152b7a6ed6 Mon Sep 17 00:00:00 2001 From: Kirill Zhaldybin Date: Mon, 14 Mar 2016 20:00:57 +0300 Subject: [PATCH 01/24] 8144073: Refactor hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java Reviewed-by: tschatzl, dfazunen --- .../humongousObjects/TestHumongousThreshold.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java b/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java index a9a83728195..3b66bc7507c 100644 --- a/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java +++ b/hotspot/test/gc/g1/humongousObjects/TestHumongousThreshold.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015,2016 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 @@ -70,7 +70,7 @@ public class TestHumongousThreshold { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); private static final int REGION_SIZE = WHITE_BOX.g1RegionSize(); private static final int MAX_CONTINUOUS_SIZE_CHECK = 129; - private static final int NON_HUMONGOUS_DIVIDER = 10; + private static final int NON_HUMONGOUS_STEPS = 10; /** * The method allocates byte[] with specified size and checks that: @@ -84,7 +84,7 @@ public class TestHumongousThreshold { * @return allocated byte array */ - private static byte[] allocateAndCheck(int arraySize, boolean expectedHumongous) { + private static void allocateAndCheck(int arraySize, boolean expectedHumongous) { byte[] storage = new byte[arraySize]; long objectSize = WHITE_BOX.getObjectSize(storage); boolean shouldBeHumongous = objectSize > (REGION_SIZE / 2); @@ -98,7 +98,6 @@ public class TestHumongousThreshold { "Object should be allocated as " + (shouldBeHumongous ? "humongous" : "non-humongous") + " but it wasn't; Allocation size = " + arraySize + "; Object size = " + objectSize + "; region size = " + REGION_SIZE); - return storage; } public static void main(String[] args) { @@ -108,7 +107,7 @@ public class TestHumongousThreshold { int maxByteArrayNonHumongousSize = (REGION_SIZE / 2) - byteArrayMemoryOverhead; // Increment for non-humongous testing - int nonHumongousStep = maxByteArrayNonHumongousSize / NON_HUMONGOUS_DIVIDER; + int nonHumongousStep = maxByteArrayNonHumongousSize / NON_HUMONGOUS_STEPS; // Maximum byte[] that takes one region int maxByteArrayOneRegionSize = REGION_SIZE - byteArrayMemoryOverhead; @@ -131,10 +130,10 @@ public class TestHumongousThreshold { allocateAndCheck(i, false); } - // Testing allocations with byte[] with length from 0 to nonHumongousStep * NON_HUMONGOUS_DIVIDER + // Testing allocations with byte[] with length from 0 to nonHumongousStep * NON_HUMONGOUS_STEPS System.out.format("Testing allocations with byte[] with length from 0 to %d with step %d%n", - nonHumongousStep * NON_HUMONGOUS_DIVIDER, nonHumongousStep); - for (int i = 0; i < NON_HUMONGOUS_DIVIDER; ++i) { + nonHumongousStep * NON_HUMONGOUS_STEPS, nonHumongousStep); + for (int i = 0; i < NON_HUMONGOUS_STEPS; ++i) { allocateAndCheck(i * nonHumongousStep, false); } From b51a55a78cb36b057e1ee217f2b634a9773fbb5c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 6 Apr 2016 10:50:19 +0300 Subject: [PATCH 02/24] 8153277: [TESTBUG] gc/arguments/TestMaxMinHeapFreeRatioFlags is too sensitive for stray allocations in verifyRatio Reviewed-by: mgerdin, dfazunen --- hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java b/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java index 055ea672adb..af37af4947c 100644 --- a/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java +++ b/hotspot/test/gc/arguments/TestMaxMinHeapFreeRatioFlags.java @@ -168,6 +168,11 @@ public class TestMaxMinHeapFreeRatioFlags { long maxHeapSize = getMax(); int gcTries = (shrinkHeapInSteps ? GC_TRIES : 1); + // Initial checks. This also links up everything in these helper methods, + // in case it brings more garbage. + forceGC(gcTries); + verifyRatio(minRatio, maxRatio); + // commit 0.5 of total heap size to have enough space // to both shink and expand while (getCommitted() < maxHeapSize / 2) { @@ -215,7 +220,6 @@ public class TestMaxMinHeapFreeRatioFlags { if (previouslyCommitted <= getCommitted()) { throw new RuntimeException("Heap was not shrinked."); } - } public static void forceGC(int gcTries) { From 0c06163b35d78b2ef3c006593fc241528b796a20 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 6 Apr 2016 13:32:48 +0200 Subject: [PATCH 03/24] 8077144: Concurrent mark initialization takes too long Remove per-marking thread liveness bitmaps and recreate liveness bitmap concurrently after the cleanup pause. Reviewed-by: mgerdin, ehelin, kbarrett --- .../share/vm/gc/g1/concurrentMarkThread.cpp | 5 + .../src/share/vm/gc/g1/g1ConcurrentMark.cpp | 817 ++++++++---------- .../src/share/vm/gc/g1/g1ConcurrentMark.hpp | 151 +--- .../vm/gc/g1/g1ConcurrentMark.inline.hpp | 147 +--- hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp | 7 +- .../share/vm/gc/g1/g1OopClosures.inline.hpp | 6 +- hotspot/src/share/vm/gc/g1/g1_globals.hpp | 3 + hotspot/src/share/vm/utilities/bitMap.cpp | 4 + hotspot/src/share/vm/utilities/bitMap.hpp | 7 + hotspot/test/gc/g1/Test2GbHeap.java | 16 +- 10 files changed, 452 insertions(+), 711 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp index c72cbae1474..7eef582e3db 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp @@ -183,6 +183,11 @@ void ConcurrentMarkThread::run_service() { } } while (cm()->restart_for_overflow()); + if (!cm()->has_aborted()) { + G1ConcPhaseTimer t(_cm, "Concurrent Create Live Data"); + cm()->create_live_data(); + } + double end_time = os::elapsedVTime(); // Update the total virtual time before doing this, since it will try // to measure it to get the vtime for this marking. We purposely diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index 2ed3dd0f4ed..a181b467c7d 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -48,6 +48,7 @@ #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/vmGCOperations.hpp" #include "logging/log.hpp" +#include "logging/logTag.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" @@ -355,10 +356,8 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* _sleep_factor(0.0), _marking_task_overhead(1.0), _cleanup_list("Cleanup List"), - _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/), - _card_bm((g1h->reserved_region().byte_size() + CardTableModRefBS::card_size - 1) >> - CardTableModRefBS::card_shift, - false /* in_resource_area*/), + _region_live_bm(), + _card_live_bm(), _prevMarkBitMap(&_markBitMap1), _nextMarkBitMap(&_markBitMap2), @@ -390,8 +389,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* _parallel_workers(NULL), - _count_card_bitmaps(NULL), - _count_marked_bytes(NULL), _completed_initialization(false) { _markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage); @@ -502,43 +499,28 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* return; } + allocate_internal_bitmaps(); + + if (G1PretouchAuxiliaryMemory) { + pretouch_internal_bitmaps(); + } + _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC); _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC); - _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_worker_id, mtGC); - _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_worker_id, mtGC); - - BitMap::idx_t card_bm_size = _card_bm.size(); - // so that the assertion in MarkingTaskQueue::task_queue doesn't fail _active_tasks = _max_worker_id; - uint max_regions = _g1h->max_regions(); for (uint i = 0; i < _max_worker_id; ++i) { G1CMTaskQueue* task_queue = new G1CMTaskQueue(); task_queue->initialize(); _task_queues->register_queue(i, task_queue); - _count_card_bitmaps[i] = BitMap(card_bm_size, false); - _count_marked_bytes[i] = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC); - - _tasks[i] = new G1CMTask(i, this, - _count_marked_bytes[i], - &_count_card_bitmaps[i], - task_queue, _task_queues); + _tasks[i] = new G1CMTask(i, this, task_queue, _task_queues); _accum_task_vtime[i] = 0.0; } - // Calculate the card number for the bottom of the heap. Used - // in biasing indexes into the accounting card bitmaps. - _heap_bottom_card_num = - intptr_t(uintptr_t(_g1h->reserved_region().start()) >> - CardTableModRefBS::card_shift); - - // Clear all the liveness counting data - clear_all_count_data(); - // so that the call below can read a sensible value _heap_start = g1h->reserved_region().start(); set_non_marking_state(); @@ -716,10 +698,11 @@ void G1ConcurrentMark::cleanup_for_next_mark() { clear_bitmap(_nextMarkBitMap, _parallel_workers, true); - // Clear the liveness counting data. If the marking has been aborted, the abort() + // Clear the live count data. If the marking has been aborted, the abort() // call already did that. if (!has_aborted()) { - clear_all_count_data(); + clear_all_live_data(_parallel_workers); + DEBUG_ONLY(verify_all_live_data()); } // Repeat the asserts from above. @@ -1107,14 +1090,6 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { // marking due to overflowing the global mark stack. reset_marking_state(); } else { - { - GCTraceTime(Debug, gc, phases) trace("Aggregate Data", _gc_timer_cm); - - // Aggregate the per-task counting data that we have accumulated - // while marking. - aggregate_count_data(); - } - SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); // We're done with marking. // This is the end of the marking cycle, we're expected all @@ -1150,17 +1125,81 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { _gc_tracer_cm->report_object_count_after_gc(&is_alive); } -// Base class of the closures that finalize and verify the -// liveness counting data. -class G1CMCountDataClosureBase: public HeapRegionClosure { -protected: - G1CollectedHeap* _g1h; - G1ConcurrentMark* _cm; - CardTableModRefBS* _ct_bs; - +// Helper class that provides functionality to generate the Live Data Count +// information. +class G1LiveDataHelper VALUE_OBJ_CLASS_SPEC { +private: BitMap* _region_bm; BitMap* _card_bm; + // The card number of the bottom of the G1 heap. Used for converting addresses + // to bitmap indices quickly. + BitMap::idx_t _heap_card_bias; + + // Utility routine to set an exclusive range of bits on the given + // bitmap, optimized for very small ranges. + // There must be at least one bit to set. + inline void set_card_bitmap_range(BitMap* bm, + BitMap::idx_t start_idx, + BitMap::idx_t end_idx) { + + // Set the exclusive bit range [start_idx, end_idx). + assert((end_idx - start_idx) > 0, "at least one bit"); + assert(end_idx <= bm->size(), "sanity"); + + // For small ranges use a simple loop; otherwise use set_range or + // use par_at_put_range (if parallel). The range is made up of the + // cards that are spanned by an object/mem region so 8 cards will + // allow up to object sizes up to 4K to be handled using the loop. + if ((end_idx - start_idx) <= 8) { + for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) { + bm->set_bit(i); + } + } else { + bm->set_range(start_idx, end_idx); + } + } + + // We cache the last mark set. This avoids setting the same bit multiple times. + // This is particularly interesting for dense bitmaps, as this avoids doing + // lots of work most of the time. + BitMap::idx_t _last_marked_bit_idx; + + // Mark the card liveness bitmap for the object spanning from start to end. + void mark_card_bitmap_range(HeapWord* start, HeapWord* end) { + BitMap::idx_t start_idx = card_live_bitmap_index_for(start); + BitMap::idx_t end_idx = card_live_bitmap_index_for((HeapWord*)align_ptr_up(end, CardTableModRefBS::card_size)); + + assert((end_idx - start_idx) > 0, "Trying to mark zero sized range."); + + if (start_idx == _last_marked_bit_idx) { + start_idx++; + } + if (start_idx == end_idx) { + return; + } + + // Set the bits in the card bitmap for the cards spanned by this object. + set_card_bitmap_range(_card_bm, start_idx, end_idx); + _last_marked_bit_idx = end_idx - 1; + } + + void reset_mark_cache() { + _last_marked_bit_idx = (BitMap::idx_t)-1; + } + +public: + // Returns the index in the per-card liveness count bitmap + // for the given address + inline BitMap::idx_t card_live_bitmap_index_for(HeapWord* addr) { + // Below, the term "card num" means the result of shifting an address + // by the card shift -- address 0 corresponds to card number 0. One + // must subtract the card num of the bottom of the heap to obtain a + // card table index. + BitMap::idx_t card_num = (BitMap::idx_t)(uintptr_t(addr) >> CardTableModRefBS::card_shift); + return card_num - _heap_card_bias; + } + // Takes a region that's not empty (i.e., it has at least one // live object in it and sets its corresponding bit on the region // bitmap to 1. @@ -1169,136 +1208,128 @@ protected: _region_bm->par_at_put(index, true); } -public: - G1CMCountDataClosureBase(G1CollectedHeap* g1h, - BitMap* region_bm, BitMap* card_bm): - _g1h(g1h), _cm(g1h->concurrent_mark()), - _ct_bs(barrier_set_cast(g1h->barrier_set())), - _region_bm(region_bm), _card_bm(card_bm) { } -}; + // Mark the range of bits covered by allocations done since the last marking + // in the given heap region, i.e. from NTAMS to top of the given region. + // Returns if there has been some allocation in this region since the last marking. + bool mark_allocated_since_marking(HeapRegion* hr) { + reset_mark_cache(); -// Closure that calculates the # live objects per region. Used -// for verification purposes during the cleanup pause. -class CalcLiveObjectsClosure: public G1CMCountDataClosureBase { - G1CMBitMapRO* _bm; - size_t _region_marked_bytes; + HeapWord* ntams = hr->next_top_at_mark_start(); + HeapWord* top = hr->top(); -public: - CalcLiveObjectsClosure(G1CMBitMapRO *bm, G1CollectedHeap* g1h, - BitMap* region_bm, BitMap* card_bm) : - G1CMCountDataClosureBase(g1h, region_bm, card_bm), - _bm(bm), _region_marked_bytes(0) { } + assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions."); + + // Mark the allocated-since-marking portion... + if (ntams < top) { + mark_card_bitmap_range(ntams, top); + return true; + } else { + return false; + } + } + + // Mark the range of bits covered by live objects on the mark bitmap between + // bottom and NTAMS of the given region. + // Returns the number of live bytes marked within that area for the given + // heap region. + size_t mark_marked_during_marking(G1CMBitMap* mark_bitmap, HeapRegion* hr) { + reset_mark_cache(); + + size_t marked_bytes = 0; - bool doHeapRegion(HeapRegion* hr) { HeapWord* ntams = hr->next_top_at_mark_start(); HeapWord* start = hr->bottom(); + if (ntams <= start) { + // Skip empty regions. + return 0; + } else if (hr->is_humongous()) { + mark_card_bitmap_range(start, hr->top()); + return pointer_delta(hr->top(), start, 1); + } + assert(start <= hr->end() && start <= ntams && ntams <= hr->end(), "Preconditions not met - " "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, p2i(start), p2i(ntams), p2i(hr->end())); // Find the first marked object at or after "start". - start = _bm->getNextMarkedWordAddress(start, ntams); - - size_t marked_bytes = 0; - + start = mark_bitmap->getNextMarkedWordAddress(start, ntams); while (start < ntams) { oop obj = oop(start); int obj_sz = obj->size(); HeapWord* obj_end = start + obj_sz; - BitMap::idx_t start_idx = _cm->card_bitmap_index_for(start); - BitMap::idx_t end_idx = _cm->card_bitmap_index_for(obj_end); + assert(obj_end <= hr->end(), "Humongous objects must have been handled elsewhere."); - // Note: if we're looking at the last region in heap - obj_end - // could be actually just beyond the end of the heap; end_idx - // will then correspond to a (non-existent) card that is also - // just beyond the heap. - if (_g1h->is_in_g1_reserved(obj_end) && !_ct_bs->is_card_aligned(obj_end)) { - // end of object is not card aligned - increment to cover - // all the cards spanned by the object - end_idx += 1; - } - - // Set the bits in the card BM for the cards spanned by this object. - _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */); + mark_card_bitmap_range(start, obj_end); // Add the size of this object to the number of marked bytes. marked_bytes += (size_t)obj_sz * HeapWordSize; - // This will happen if we are handling a humongous object that spans - // several heap regions. - if (obj_end > hr->end()) { - break; - } // Find the next marked object after this one. - start = _bm->getNextMarkedWordAddress(obj_end, ntams); + start = mark_bitmap->getNextMarkedWordAddress(obj_end, ntams); } - // Mark the allocated-since-marking portion... - HeapWord* top = hr->top(); - if (ntams < top) { - BitMap::idx_t start_idx = _cm->card_bitmap_index_for(ntams); - BitMap::idx_t end_idx = _cm->card_bitmap_index_for(top); - - // Note: if we're looking at the last region in heap - top - // could be actually just beyond the end of the heap; end_idx - // will then correspond to a (non-existent) card that is also - // just beyond the heap. - if (_g1h->is_in_g1_reserved(top) && !_ct_bs->is_card_aligned(top)) { - // end of object is not card aligned - increment to cover - // all the cards spanned by the object - end_idx += 1; - } - _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */); - - // This definitely means the region has live objects. - set_bit_for_region(hr); - } - - // Update the live region bitmap. - if (marked_bytes > 0) { - set_bit_for_region(hr); - } - - // Set the marked bytes for the current region so that - // it can be queried by a calling verification routine - _region_marked_bytes = marked_bytes; - - return false; + return marked_bytes; } - size_t region_marked_bytes() const { return _region_marked_bytes; } + G1LiveDataHelper(BitMap* region_bm, + BitMap* card_bm): + _region_bm(region_bm), + _card_bm(card_bm) { + //assert(region_bm != NULL, ""); + assert(card_bm != NULL, ""); + // Calculate the card number for the bottom of the heap. Used + // in biasing indexes into the accounting card bitmaps. + _heap_card_bias = + (BitMap::idx_t)(uintptr_t(G1CollectedHeap::heap()->reserved_region().start()) >> CardTableModRefBS::card_shift); + } }; -// Heap region closure used for verifying the counting data -// that was accumulated concurrently and aggregated during +// Heap region closure used for verifying the live count data +// that was created concurrently and finalized during // the remark pause. This closure is applied to the heap // regions during the STW cleanup pause. - -class VerifyLiveObjectDataHRClosure: public HeapRegionClosure { +class G1VerifyLiveDataHRClosure: public HeapRegionClosure { +private: G1CollectedHeap* _g1h; - G1ConcurrentMark* _cm; - CalcLiveObjectsClosure _calc_cl; - BitMap* _region_bm; // Region BM to be verified - BitMap* _card_bm; // Card BM to be verified + G1CMBitMap* _mark_bitmap; + G1LiveDataHelper _calc_helper; + + BitMap* _act_region_bm; // Region BM to be verified + BitMap* _act_card_bm; // Card BM to be verified BitMap* _exp_region_bm; // Expected Region BM values BitMap* _exp_card_bm; // Expected card BM values int _failures; + // Updates the live data count for the given heap region and returns the number + // of bytes marked. + size_t create_live_data_count(HeapRegion* hr) { + size_t bytes_marked = _calc_helper.mark_marked_during_marking(_mark_bitmap, hr); + bool allocated_since_marking = _calc_helper.mark_allocated_since_marking(hr); + if (allocated_since_marking || bytes_marked > 0) { + _calc_helper.set_bit_for_region(hr); + } + return bytes_marked; + } + public: - VerifyLiveObjectDataHRClosure(G1CollectedHeap* g1h, - BitMap* region_bm, - BitMap* card_bm, - BitMap* exp_region_bm, - BitMap* exp_card_bm) : - _g1h(g1h), _cm(g1h->concurrent_mark()), - _calc_cl(_cm->nextMarkBitMap(), g1h, exp_region_bm, exp_card_bm), - _region_bm(region_bm), _card_bm(card_bm), - _exp_region_bm(exp_region_bm), _exp_card_bm(exp_card_bm), + G1VerifyLiveDataHRClosure(G1CollectedHeap* g1h, + G1CMBitMap* mark_bitmap, + BitMap* act_region_bm, + BitMap* act_card_bm, + BitMap* exp_region_bm, + BitMap* exp_card_bm) : + _g1h(g1h), + _mark_bitmap(mark_bitmap), + _calc_helper(exp_region_bm, exp_card_bm), + _act_region_bm(act_region_bm), + _act_card_bm(act_card_bm), + _exp_region_bm(exp_region_bm), + _exp_card_bm(exp_card_bm), _failures(0) { } int failures() const { return _failures; } @@ -1306,35 +1337,16 @@ public: bool doHeapRegion(HeapRegion* hr) { int failures = 0; - // Call the CalcLiveObjectsClosure to walk the marking bitmap for - // this region and set the corresponding bits in the expected region - // and card bitmaps. - bool res = _calc_cl.doHeapRegion(hr); - assert(res == false, "should be continuing"); - - // Verify the marked bytes for this region. - size_t exp_marked_bytes = _calc_cl.region_marked_bytes(); + // Walk the marking bitmap for this region and set the corresponding bits + // in the expected region and card bitmaps. + size_t exp_marked_bytes = create_live_data_count(hr); size_t act_marked_bytes = hr->next_marked_bytes(); + // Verify the marked bytes for this region. - if (exp_marked_bytes > act_marked_bytes) { - if (hr->is_starts_humongous()) { - // For start_humongous regions, the size of the whole object will be - // in exp_marked_bytes. - HeapRegion* region = hr; - int num_regions; - for (num_regions = 0; region != NULL; num_regions++) { - region = _g1h->next_region_in_humongous(region); - } - if ((num_regions-1) * HeapRegion::GrainBytes >= exp_marked_bytes) { - failures += 1; - } else if (num_regions * HeapRegion::GrainBytes < exp_marked_bytes) { - failures += 1; - } - } else { - // We're not OK if expected marked bytes > actual marked bytes. It means - // we have missed accounting some objects during the actual marking. - failures += 1; - } + if (exp_marked_bytes != act_marked_bytes) { + failures += 1; + } else if (exp_marked_bytes > HeapRegion::GrainBytes) { + failures += 1; } // Verify the bit, for this region, in the actual and expected @@ -1344,7 +1356,7 @@ public: BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index(); bool expected = _exp_region_bm->at(index); - bool actual = _region_bm->at(index); + bool actual = _act_region_bm->at(index); if (expected && !actual) { failures += 1; } @@ -1353,12 +1365,12 @@ public: // region match. We have an error if we have a set bit in the expected // bit map and the corresponding bit in the actual bitmap is not set. - BitMap::idx_t start_idx = _cm->card_bitmap_index_for(hr->bottom()); - BitMap::idx_t end_idx = _cm->card_bitmap_index_for(hr->top()); + BitMap::idx_t start_idx = _calc_helper.card_live_bitmap_index_for(hr->bottom()); + BitMap::idx_t end_idx = _calc_helper.card_live_bitmap_index_for(hr->top()); for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) { expected = _exp_card_bm->at(i); - actual = _card_bm->at(i); + actual = _act_card_bm->at(i); if (expected && !actual) { failures += 1; @@ -1373,137 +1385,100 @@ public: } }; -class G1ParVerifyFinalCountTask: public AbstractGangTask { +class G1VerifyLiveDataTask: public AbstractGangTask { protected: G1CollectedHeap* _g1h; - G1ConcurrentMark* _cm; + G1CMBitMap* _mark_bitmap; BitMap* _actual_region_bm; BitMap* _actual_card_bm; - uint _n_workers; - - BitMap* _expected_region_bm; - BitMap* _expected_card_bm; + BitMap _expected_region_bm; + BitMap _expected_card_bm; int _failures; - HeapRegionClaimer _hrclaimer; + HeapRegionClaimer _hr_claimer; public: - G1ParVerifyFinalCountTask(G1CollectedHeap* g1h, - BitMap* region_bm, BitMap* card_bm, - BitMap* expected_region_bm, BitMap* expected_card_bm) - : AbstractGangTask("G1 verify final counting"), - _g1h(g1h), _cm(_g1h->concurrent_mark()), - _actual_region_bm(region_bm), _actual_card_bm(card_bm), - _expected_region_bm(expected_region_bm), _expected_card_bm(expected_card_bm), - _failures(0), - _n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) { + G1VerifyLiveDataTask(G1CollectedHeap* g1h, + G1CMBitMap* bitmap, + BitMap* region_bm, + BitMap* card_bm, + uint n_workers) + : AbstractGangTask("G1 verify final counting"), + _g1h(g1h), + _mark_bitmap(bitmap), + _actual_region_bm(region_bm), + _actual_card_bm(card_bm), + _expected_region_bm(region_bm->size(), true /* in_resource_area */), + _expected_card_bm(card_bm->size(), true /* in_resource_area */), + _failures(0), + _hr_claimer(n_workers) { assert(VerifyDuringGC, "don't call this otherwise"); - assert(_expected_card_bm->size() == _actual_card_bm->size(), "sanity"); - assert(_expected_region_bm->size() == _actual_region_bm->size(), "sanity"); } void work(uint worker_id) { - assert(worker_id < _n_workers, "invariant"); + G1VerifyLiveDataHRClosure cl(_g1h, + _mark_bitmap, + _actual_region_bm, + _actual_card_bm, + &_expected_region_bm, + &_expected_card_bm); + _g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); - VerifyLiveObjectDataHRClosure verify_cl(_g1h, - _actual_region_bm, _actual_card_bm, - _expected_region_bm, - _expected_card_bm); - - _g1h->heap_region_par_iterate(&verify_cl, worker_id, &_hrclaimer); - - Atomic::add(verify_cl.failures(), &_failures); + Atomic::add(cl.failures(), &_failures); } int failures() const { return _failures; } }; -// Closure that finalizes the liveness counting data. -// Used during the cleanup pause. -// Sets the bits corresponding to the interval [NTAMS, top] -// (which contains the implicitly live objects) in the -// card liveness bitmap. Also sets the bit for each region, -// containing live data, in the region liveness bitmap. +class G1FinalizeLiveDataTask: public AbstractGangTask { + // Finalizes the liveness counting data. + // Sets the bits corresponding to the interval [NTAMS, top] + // (which contains the implicitly live objects) in the + // card liveness bitmap. Also sets the bit for each region + // containing live data, in the region liveness bitmap. + class G1FinalizeCountDataClosure: public HeapRegionClosure { + private: + G1LiveDataHelper _helper; + public: + G1FinalizeCountDataClosure(G1CMBitMap* bitmap, + BitMap* region_bm, + BitMap* card_bm) : + HeapRegionClosure(), + _helper(region_bm, card_bm) { } -class FinalCountDataUpdateClosure: public G1CMCountDataClosureBase { - public: - FinalCountDataUpdateClosure(G1CollectedHeap* g1h, - BitMap* region_bm, - BitMap* card_bm) : - G1CMCountDataClosureBase(g1h, region_bm, card_bm) { } - - bool doHeapRegion(HeapRegion* hr) { - HeapWord* ntams = hr->next_top_at_mark_start(); - HeapWord* top = hr->top(); - - assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions."); - - // Mark the allocated-since-marking portion... - if (ntams < top) { - // This definitely means the region has live objects. - set_bit_for_region(hr); - - // Now set the bits in the card bitmap for [ntams, top) - BitMap::idx_t start_idx = _cm->card_bitmap_index_for(ntams); - BitMap::idx_t end_idx = _cm->card_bitmap_index_for(top); - - // Note: if we're looking at the last region in heap - top - // could be actually just beyond the end of the heap; end_idx - // will then correspond to a (non-existent) card that is also - // just beyond the heap. - if (_g1h->is_in_g1_reserved(top) && !_ct_bs->is_card_aligned(top)) { - // end of object is not card aligned - increment to cover - // all the cards spanned by the object - end_idx += 1; + bool doHeapRegion(HeapRegion* hr) { + bool allocated_since_marking = _helper.mark_allocated_since_marking(hr); + if (allocated_since_marking || hr->next_marked_bytes() > 0) { + _helper.set_bit_for_region(hr); } - - assert(end_idx <= _card_bm->size(), - "oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, - end_idx, _card_bm->size()); - assert(start_idx < _card_bm->size(), - "oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, - start_idx, _card_bm->size()); - - _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */); + return false; } + }; - // Set the bit for the region if it contains live data - if (hr->next_marked_bytes() > 0) { - set_bit_for_region(hr); - } + G1CMBitMap* _bitmap; - return false; - } -}; - -class G1ParFinalCountTask: public AbstractGangTask { -protected: - G1CollectedHeap* _g1h; - G1ConcurrentMark* _cm; BitMap* _actual_region_bm; BitMap* _actual_card_bm; - uint _n_workers; - HeapRegionClaimer _hrclaimer; + HeapRegionClaimer _hr_claimer; public: - G1ParFinalCountTask(G1CollectedHeap* g1h, BitMap* region_bm, BitMap* card_bm) - : AbstractGangTask("G1 final counting"), - _g1h(g1h), _cm(_g1h->concurrent_mark()), - _actual_region_bm(region_bm), _actual_card_bm(card_bm), - _n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) { + G1FinalizeLiveDataTask(G1CMBitMap* bitmap, BitMap* region_bm, BitMap* card_bm, uint n_workers) : + AbstractGangTask("G1 final counting"), + _bitmap(bitmap), + _actual_region_bm(region_bm), + _actual_card_bm(card_bm), + _hr_claimer(n_workers) { } void work(uint worker_id) { - assert(worker_id < _n_workers, "invariant"); + G1FinalizeCountDataClosure cl(_bitmap, + _actual_region_bm, + _actual_card_bm); - FinalCountDataUpdateClosure final_update_cl(_g1h, - _actual_region_bm, - _actual_card_bm); - - _g1h->heap_region_par_iterate(&final_update_cl, worker_id, &_hrclaimer); + G1CollectedHeap::heap()->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); } }; @@ -1637,31 +1612,29 @@ void G1ConcurrentMark::cleanup() { HeapRegionRemSet::reset_for_cleanup_tasks(); - // Do counting once more with the world stopped for good measure. - G1ParFinalCountTask g1_par_count_task(g1h, &_region_bm, &_card_bm); - - g1h->workers()->run_task(&g1_par_count_task); - - if (VerifyDuringGC) { - // Verify that the counting data accumulated during marking matches - // that calculated by walking the marking bitmap. - - // Bitmaps to hold expected values - BitMap expected_region_bm(_region_bm.size(), true); - BitMap expected_card_bm(_card_bm.size(), true); - - G1ParVerifyFinalCountTask g1_par_verify_task(g1h, - &_region_bm, - &_card_bm, - &expected_region_bm, - &expected_card_bm); - - g1h->workers()->run_task(&g1_par_verify_task); - - guarantee(g1_par_verify_task.failures() == 0, "Unexpected accounting failures"); + { + // Finalize the live data. + G1FinalizeLiveDataTask cl(_nextMarkBitMap, + &_region_live_bm, + &_card_live_bm, + g1h->workers()->active_workers()); + g1h->workers()->run_task(&cl); + } + + if (VerifyDuringGC) { + // Verify that the liveness count data created concurrently matches one created + // during this safepoint. + ResourceMark rm; + G1VerifyLiveDataTask cl(G1CollectedHeap::heap(), + _nextMarkBitMap, + &_region_live_bm, + &_card_live_bm, + g1h->workers()->active_workers()); + g1h->workers()->run_task(&cl); + + guarantee(cl.failures() == 0, "Unexpected accounting failures"); } - size_t start_used_bytes = g1h->used(); g1h->collector_state()->set_mark_in_progress(false); double count_end = os::elapsedTime(); @@ -1696,7 +1669,7 @@ void G1ConcurrentMark::cleanup() { // regions. if (G1ScrubRemSets) { double rs_scrub_start = os::elapsedTime(); - g1h->scrub_rem_set(&_region_bm, &_card_bm); + g1h->scrub_rem_set(&_region_live_bm, &_card_live_bm); _total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start); } @@ -2142,6 +2115,35 @@ void G1ConcurrentMark::swapMarkBitMaps() { _nextMarkBitMap = (G1CMBitMap*) temp; } +BitMap G1ConcurrentMark::allocate_large_bitmap(BitMap::idx_t size_in_bits) { + size_t size_in_words = BitMap::size_in_words(size_in_bits); + + BitMap::bm_word_t* map = MmapArrayAllocator::allocate(size_in_words); + + return BitMap(map, size_in_bits); +} + +void G1ConcurrentMark::allocate_internal_bitmaps() { + double start_time = os::elapsedTime(); + + _region_live_bm = allocate_large_bitmap(_g1h->max_regions()); + + guarantee(_g1h->max_capacity() % CardTableModRefBS::card_size == 0, + "Heap capacity must be aligned to card size."); + _card_live_bm = allocate_large_bitmap(_g1h->max_capacity() / CardTableModRefBS::card_size); + + log_debug(gc, marking)("Allocating internal bitmaps took %1.2f seconds.", os::elapsedTime() - start_time); +} + +void G1ConcurrentMark::pretouch_internal_bitmaps() { + double start_time = os::elapsedTime(); + + _region_live_bm.pretouch(); + _card_live_bm.pretouch(); + + log_debug(gc, marking)("Pre-touching internal bitmaps took %1.2f seconds.", os::elapsedTime() - start_time); +} + // Closure for marking entries in SATB buffers. class G1CMSATBBufferClosure : public SATBBufferClosure { private: @@ -2160,7 +2162,7 @@ private: oop obj = static_cast(entry); assert(obj->is_oop(true /* ignore mark word */), "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj)); - _task->make_reference_grey(obj, hr); + _task->make_reference_grey(obj); } } @@ -2402,165 +2404,117 @@ void G1ConcurrentMark::verify_no_cset_oops() { } #endif // PRODUCT -// Aggregate the counting data that was constructed concurrently -// with marking. -class AggregateCountDataHRClosure: public HeapRegionClosure { - G1CollectedHeap* _g1h; - G1ConcurrentMark* _cm; - CardTableModRefBS* _ct_bs; - BitMap* _cm_card_bm; - uint _max_worker_id; +class G1CreateLiveDataTask: public AbstractGangTask { + // Aggregate the counting data that was constructed concurrently + // with marking. + class G1CreateLiveDataHRClosure: public HeapRegionClosure { + G1LiveDataHelper _helper; - public: - AggregateCountDataHRClosure(G1CollectedHeap* g1h, - BitMap* cm_card_bm, - uint max_worker_id) : - _g1h(g1h), _cm(g1h->concurrent_mark()), - _ct_bs(barrier_set_cast(g1h->barrier_set())), - _cm_card_bm(cm_card_bm), _max_worker_id(max_worker_id) { } + G1CMBitMap* _mark_bitmap; - bool doHeapRegion(HeapRegion* hr) { - HeapWord* start = hr->bottom(); - HeapWord* limit = hr->next_top_at_mark_start(); - HeapWord* end = hr->end(); + G1ConcurrentMark* _cm; + public: + G1CreateLiveDataHRClosure(G1ConcurrentMark* cm, + G1CMBitMap* mark_bitmap, + BitMap* cm_card_bm) : + HeapRegionClosure(), + _helper(NULL, cm_card_bm), + _mark_bitmap(mark_bitmap), + _cm(cm) { } - assert(start <= limit && limit <= hr->top() && hr->top() <= hr->end(), - "Preconditions not met - " - "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", " - "top: " PTR_FORMAT ", end: " PTR_FORMAT, - p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end())); + bool doHeapRegion(HeapRegion* hr) { + size_t marked_bytes = _helper.mark_marked_during_marking(_mark_bitmap, hr); + if (marked_bytes > 0) { + hr->add_to_marked_bytes(marked_bytes); + } - assert(hr->next_marked_bytes() == 0, "Precondition"); - - if (start == limit) { - // NTAMS of this region has not been set so nothing to do. + if (_cm->do_yield_check() && _cm->has_aborted()) { + return true; + } return false; } + }; - // 'start' should be in the heap. - assert(_g1h->is_in_g1_reserved(start) && _ct_bs->is_card_aligned(start), "sanity"); - // 'end' *may* be just beyond the end of the heap (if hr is the last region) - assert(!_g1h->is_in_g1_reserved(end) || _ct_bs->is_card_aligned(end), "sanity"); - - BitMap::idx_t start_idx = _cm->card_bitmap_index_for(start); - BitMap::idx_t limit_idx = _cm->card_bitmap_index_for(limit); - BitMap::idx_t end_idx = _cm->card_bitmap_index_for(end); - - // If ntams is not card aligned then we bump card bitmap index - // for limit so that we get the all the cards spanned by - // the object ending at ntams. - // Note: if this is the last region in the heap then ntams - // could be actually just beyond the end of the the heap; - // limit_idx will then correspond to a (non-existent) card - // that is also outside the heap. - if (_g1h->is_in_g1_reserved(limit) && !_ct_bs->is_card_aligned(limit)) { - limit_idx += 1; - } - - assert(limit_idx <= end_idx, "or else use atomics"); - - // Aggregate the "stripe" in the count data associated with hr. - uint hrm_index = hr->hrm_index(); - size_t marked_bytes = 0; - - for (uint i = 0; i < _max_worker_id; i += 1) { - size_t* marked_bytes_array = _cm->count_marked_bytes_array_for(i); - BitMap* task_card_bm = _cm->count_card_bitmap_for(i); - - // Fetch the marked_bytes in this region for task i and - // add it to the running total for this region. - marked_bytes += marked_bytes_array[hrm_index]; - - // Now union the bitmaps[0,max_worker_id)[start_idx..limit_idx) - // into the global card bitmap. - BitMap::idx_t scan_idx = task_card_bm->get_next_one_offset(start_idx, limit_idx); - - while (scan_idx < limit_idx) { - assert(task_card_bm->at(scan_idx) == true, "should be"); - _cm_card_bm->set_bit(scan_idx); - assert(_cm_card_bm->at(scan_idx) == true, "should be"); - - // BitMap::get_next_one_offset() can handle the case when - // its left_offset parameter is greater than its right_offset - // parameter. It does, however, have an early exit if - // left_offset == right_offset. So let's limit the value - // passed in for left offset here. - BitMap::idx_t next_idx = MIN2(scan_idx + 1, limit_idx); - scan_idx = task_card_bm->get_next_one_offset(next_idx, limit_idx); - } - } - - // Update the marked bytes for this region. - hr->add_to_marked_bytes(marked_bytes); - - // Next heap region - return false; - } -}; - -class G1AggregateCountDataTask: public AbstractGangTask { -protected: G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; BitMap* _cm_card_bm; - uint _max_worker_id; - uint _active_workers; - HeapRegionClaimer _hrclaimer; + HeapRegionClaimer _hr_claimer; public: - G1AggregateCountDataTask(G1CollectedHeap* g1h, - G1ConcurrentMark* cm, - BitMap* cm_card_bm, - uint max_worker_id, - uint n_workers) : - AbstractGangTask("Count Aggregation"), - _g1h(g1h), _cm(cm), _cm_card_bm(cm_card_bm), - _max_worker_id(max_worker_id), - _active_workers(n_workers), - _hrclaimer(_active_workers) { + G1CreateLiveDataTask(G1CollectedHeap* g1h, + BitMap* cm_card_bm, + uint n_workers) : + AbstractGangTask("Create Live Data"), + _g1h(g1h), + _cm_card_bm(cm_card_bm), + _hr_claimer(n_workers) { } void work(uint worker_id) { - AggregateCountDataHRClosure cl(_g1h, _cm_card_bm, _max_worker_id); + SuspendibleThreadSetJoiner sts_join; - _g1h->heap_region_par_iterate(&cl, worker_id, &_hrclaimer); + G1CreateLiveDataHRClosure cl(_g1h->concurrent_mark(), _g1h->concurrent_mark()->nextMarkBitMap(), _cm_card_bm); + _g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); } }; -void G1ConcurrentMark::aggregate_count_data() { - uint n_workers = _g1h->workers()->active_workers(); +void G1ConcurrentMark::create_live_data() { + uint n_workers = _parallel_workers->active_workers(); - G1AggregateCountDataTask g1_par_agg_task(_g1h, this, &_card_bm, - _max_worker_id, n_workers); - - _g1h->workers()->run_task(&g1_par_agg_task); + G1CreateLiveDataTask cl(_g1h, + &_card_live_bm, + n_workers); + _parallel_workers->run_task(&cl); } -// Clear the per-worker arrays used to store the per-region counting data -void G1ConcurrentMark::clear_all_count_data() { - // Clear the global card bitmap - it will be filled during - // liveness count aggregation (during remark) and the - // final counting task. - _card_bm.clear(); - - // Clear the global region bitmap - it will be filled as part - // of the final counting task. - _region_bm.clear(); - - uint max_regions = _g1h->max_regions(); - assert(_max_worker_id > 0, "uninitialized"); - - for (uint i = 0; i < _max_worker_id; i += 1) { - BitMap* task_card_bm = count_card_bitmap_for(i); - size_t* marked_bytes_array = count_marked_bytes_array_for(i); - - assert(task_card_bm->size() == _card_bm.size(), "size mismatch"); - assert(marked_bytes_array != NULL, "uninitialized"); - - memset(marked_bytes_array, 0, (size_t) max_regions * sizeof(size_t)); - task_card_bm->clear(); +class G1ClearAllLiveDataTask : public AbstractGangTask { + BitMap* _bitmap; + size_t _num_tasks; + size_t _cur_task; +public: + G1ClearAllLiveDataTask(BitMap* bitmap, size_t num_tasks) : + AbstractGangTask("Clear All Live Data"), + _bitmap(bitmap), + _num_tasks(num_tasks), + _cur_task(0) { } + + virtual void work(uint worker_id) { + while (true) { + size_t to_process = Atomic::add(1, &_cur_task) - 1; + if (to_process >= _num_tasks) { + break; + } + + BitMap::idx_t start = M * BitsPerByte * to_process; + BitMap::idx_t end = MIN2(start + M * BitsPerByte, _bitmap->size()); + _bitmap->clear_range(start, end); + } + } +}; + +void G1ConcurrentMark::clear_all_live_data(WorkGang* workers) { + double start_time = os::elapsedTime(); + + guarantee(Universe::is_fully_initialized(), "Should not call this during initialization."); + + size_t const num_chunks = align_size_up(_card_live_bm.size_in_words() * HeapWordSize, M) / M; + + G1ClearAllLiveDataTask cl(&_card_live_bm, num_chunks); + workers->run_task(&cl); + + // The region live bitmap is always very small, even for huge heaps. Clear + // directly. + _region_live_bm.clear(); + + + log_debug(gc, marking)("Clear Live Data took %.3fms", (os::elapsedTime() - start_time) * 1000.0); +} + +void G1ConcurrentMark::verify_all_live_data() { + assert(_card_live_bm.count_one_bits() == 0, "Master card bitmap not clear"); + assert(_region_live_bm.count_one_bits() == 0, "Master region bitmap not clear"); } void G1ConcurrentMark::print_stats() { @@ -2574,7 +2528,6 @@ void G1ConcurrentMark::print_stats() { } } -// abandon current marking iteration due to a Full GC void G1ConcurrentMark::abort() { if (!cmThread()->during_cycle() || _has_aborted) { // We haven't started a concurrent cycle or we have already aborted it. No need to do anything. @@ -2589,8 +2542,8 @@ void G1ConcurrentMark::abort() { // since VerifyDuringGC verifies the objects marked during // a full GC against the previous bitmap. - // Clear the liveness counting data - clear_all_count_data(); + clear_all_live_data(_g1h->workers()); + DEBUG_ONLY(verify_all_live_data()); // Empty mark stack reset_marking_state(); for (uint i = 0; i < _max_worker_id; ++i) { @@ -2634,7 +2587,7 @@ void G1ConcurrentMark::print_summary_info() { } print_ms_time_info(" ", "cleanups", _cleanup_times); - log.trace(" Final counting total time = %8.2f s (avg = %8.2f ms).", + log.trace(" Finalize live data total time = %8.2f s (avg = %8.2f ms).", _total_counting_time, (_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 / (double)_cleanup_times.num() : 0.0)); if (G1ScrubRemSets) { log.trace(" RS scrub total time = %8.2f s (avg = %8.2f ms).", @@ -3473,8 +3426,6 @@ void G1CMTask::do_marking_step(double time_target_ms, G1CMTask::G1CMTask(uint worker_id, G1ConcurrentMark* cm, - size_t* marked_bytes, - BitMap* card_bm, G1CMTaskQueue* task_queue, G1CMTaskQueueSet* task_queues) : _g1h(G1CollectedHeap::heap()), @@ -3483,9 +3434,7 @@ G1CMTask::G1CMTask(uint worker_id, _nextMarkBitMap(NULL), _hash_seed(17), _task_queue(task_queue), _task_queues(task_queues), - _cm_oop_closure(NULL), - _marked_bytes_array(marked_bytes), - _card_bm(card_bm) { + _cm_oop_closure(NULL) { guarantee(task_queue != NULL, "invariant"); guarantee(task_queues != NULL, "invariant"); diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp index 1608c81f96f..fb621e34980 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp @@ -266,7 +266,7 @@ class ConcurrentMarkThread; class G1ConcurrentMark: public CHeapObj { friend class ConcurrentMarkThread; friend class G1ParNoteEndTask; - friend class CalcLiveObjectsClosure; + friend class G1VerifyLiveDataClosure; friend class G1CMRefProcTaskProxy; friend class G1CMRefProcTaskExecutor; friend class G1CMKeepAliveAndDrainClosure; @@ -298,8 +298,14 @@ protected: G1CMBitMapRO* _prevMarkBitMap; // Completed mark bitmap G1CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap - BitMap _region_bm; - BitMap _card_bm; + // Liveness count data. After marking G1 iterates over the recently gathered mark + // bitmap and records rough information about liveness on card and region basis. + // This information can be used for e.g. remembered set scrubbing. + + // A set bit indicates whether the given region contains any live object. + BitMap _region_live_bm; + // A set bit indicates that the given card contains a live object. + BitMap _card_live_bm; // Heap bounds HeapWord* _heap_start; @@ -373,6 +379,14 @@ protected: void swapMarkBitMaps(); + // Allocates and returns a zero-ed out "large" bitmap of the given size in bits. + // It is always allocated using virtual memory. + BitMap allocate_large_bitmap(BitMap::idx_t size_in_bits); + // Allocates the memory for all bitmaps used by the concurrent marking. + void allocate_internal_bitmaps(); + // Pre-touches the internal bitmaps. + void pretouch_internal_bitmaps(); + // It resets the global marking data structures, as well as the // task local ones; should be called during initial mark. void reset(); @@ -461,23 +475,6 @@ protected: void enter_first_sync_barrier(uint worker_id); void enter_second_sync_barrier(uint worker_id); - // Live Data Counting data structures... - // These data structures are initialized at the start of - // marking. They are written to while marking is active. - // They are aggregated during remark; the aggregated values - // are then used to populate the _region_bm, _card_bm, and - // the total live bytes, which are then subsequently updated - // during cleanup. - - // An array of bitmaps (one bit map per task). Each bitmap - // is used to record the cards spanned by the live objects - // marked by that task/worker. - BitMap* _count_card_bitmaps; - - // Used to record the number of marked live bytes - // (for each region, by worker thread). - size_t** _count_marked_bytes; - // Card index of the bottom of the G1 heap. Used for biasing indices into // the card bitmaps. intptr_t _heap_bottom_card_num; @@ -563,18 +560,10 @@ public: // G1CollectedHeap // This notifies CM that a root during initial-mark needs to be - // grayed. It is MT-safe. word_size is the size of the object in - // words. It is passed explicitly as sometimes we cannot calculate - // it from the given object because it might be in an inconsistent - // state (e.g., in to-space and being copied). So the caller is - // responsible for dealing with this issue (e.g., get the size from - // the from-space image when the to-space image might be - // inconsistent) and always passing the size. hr is the region that + // grayed. It is MT-safe. hr is the region that // contains the object and it's passed optionally from callers who // might already have it (no point in recalculating it). inline void grayRoot(oop obj, - size_t word_size, - uint worker_id, HeapRegion* hr = NULL); // Prepare internal data structures for the next mark cycle. This includes clearing @@ -641,7 +630,7 @@ public: inline bool do_yield_check(uint worker_i = 0); - // Called to abort the marking cycle after a Full GC takes place. + // Abandon current marking iteration due to a Full GC. void abort(); bool has_aborted() { return _has_aborted; } @@ -652,75 +641,8 @@ public: void print_on_error(outputStream* st) const; - // Liveness counting - - // Utility routine to set an exclusive range of cards on the given - // card liveness bitmap - inline void set_card_bitmap_range(BitMap* card_bm, - BitMap::idx_t start_idx, - BitMap::idx_t end_idx, - bool is_par); - - // Returns the card number of the bottom of the G1 heap. - // Used in biasing indices into accounting card bitmaps. - intptr_t heap_bottom_card_num() const { - return _heap_bottom_card_num; - } - - // Returns the card bitmap for a given task or worker id. - BitMap* count_card_bitmap_for(uint worker_id) { - assert(worker_id < _max_worker_id, "oob"); - assert(_count_card_bitmaps != NULL, "uninitialized"); - BitMap* task_card_bm = &_count_card_bitmaps[worker_id]; - assert(task_card_bm->size() == _card_bm.size(), "size mismatch"); - return task_card_bm; - } - - // Returns the array containing the marked bytes for each region, - // for the given worker or task id. - size_t* count_marked_bytes_array_for(uint worker_id) { - assert(worker_id < _max_worker_id, "oob"); - assert(_count_marked_bytes != NULL, "uninitialized"); - size_t* marked_bytes_array = _count_marked_bytes[worker_id]; - assert(marked_bytes_array != NULL, "uninitialized"); - return marked_bytes_array; - } - - // Returns the index in the liveness accounting card table bitmap - // for the given address - inline BitMap::idx_t card_bitmap_index_for(HeapWord* addr); - - // Counts the size of the given memory region in the the given - // marked_bytes array slot for the given HeapRegion. - // Sets the bits in the given card bitmap that are associated with the - // cards that are spanned by the memory region. - inline void count_region(MemRegion mr, - HeapRegion* hr, - size_t* marked_bytes_array, - BitMap* task_card_bm); - - // Counts the given object in the given task/worker counting - // data structures. - inline void count_object(oop obj, - HeapRegion* hr, - size_t* marked_bytes_array, - BitMap* task_card_bm, - size_t word_size); - - // Attempts to mark the given object and, if successful, counts - // the object in the given task/worker counting structures. - inline bool par_mark_and_count(oop obj, - HeapRegion* hr, - size_t* marked_bytes_array, - BitMap* task_card_bm); - - // Attempts to mark the given object and, if successful, counts - // the object in the task/worker counting structures for the - // given worker id. - inline bool par_mark_and_count(oop obj, - size_t word_size, - HeapRegion* hr, - uint worker_id); + // Attempts to mark the given object on the next mark bitmap. + inline bool par_mark(oop obj); // Returns true if initialization was successfully completed. bool completed_initialization() const { @@ -730,19 +652,19 @@ public: ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; } G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; } -protected: - // Clear all the per-task bitmaps and arrays used to store the - // counting data. - void clear_all_count_data(); +private: + // Clear (Reset) all liveness count data. + void clear_all_live_data(WorkGang* workers); - // Aggregates the counting data for each worker/task - // that was constructed while marking. Also sets - // the amount of marked bytes for each region and - // the top at concurrent mark count. - void aggregate_count_data(); + // Verify all of the above data structures that they are in initial state. + void verify_all_live_data(); + + // Aggregates the per-card liveness data based on the current marking. Also sets + // the amount of marked bytes for each region. + void create_live_data(); // Verification routine - void verify_count_data(); + void verify_live_data(); }; // A class representing a marking task. @@ -844,12 +766,6 @@ private: TruncatedSeq _marking_step_diffs_ms; - // Counting data structures. Embedding the task's marked_bytes_array - // and card bitmap into the actual task saves having to go through - // the ConcurrentMark object. - size_t* _marked_bytes_array; - BitMap* _card_bm; - // it updates the local fields after this task has claimed // a new region to scan void setup_for_region(HeapRegion* hr); @@ -936,9 +852,8 @@ public: // Grey the object by marking it. If not already marked, push it on // the local queue if below the finger. - // Precondition: obj is in region. // Precondition: obj is below region's NTAMS. - inline void make_reference_grey(oop obj, HeapRegion* region); + inline void make_reference_grey(oop obj); // Grey the object (by calling make_grey_reference) if required, // e.g. obj is below its containing region's NTAMS. @@ -976,8 +891,6 @@ public: G1CMTask(uint worker_id, G1ConcurrentMark *cm, - size_t* marked_bytes, - BitMap* card_bm, G1CMTaskQueue* task_queue, G1CMTaskQueueSet* task_queues); diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp index 4a934e0b15e..053de4b9673 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp @@ -29,138 +29,8 @@ #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/shared/taskqueue.inline.hpp" -// Utility routine to set an exclusive range of cards on the given -// card liveness bitmap -inline void G1ConcurrentMark::set_card_bitmap_range(BitMap* card_bm, - BitMap::idx_t start_idx, - BitMap::idx_t end_idx, - bool is_par) { - - // Set the exclusive bit range [start_idx, end_idx). - assert((end_idx - start_idx) > 0, "at least one card"); - assert(end_idx <= card_bm->size(), "sanity"); - - // Silently clip the end index - end_idx = MIN2(end_idx, card_bm->size()); - - // For small ranges use a simple loop; otherwise use set_range or - // use par_at_put_range (if parallel). The range is made up of the - // cards that are spanned by an object/mem region so 8 cards will - // allow up to object sizes up to 4K to be handled using the loop. - if ((end_idx - start_idx) <= 8) { - for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) { - if (is_par) { - card_bm->par_set_bit(i); - } else { - card_bm->set_bit(i); - } - } - } else { - // Note BitMap::par_at_put_range() and BitMap::set_range() are exclusive. - if (is_par) { - card_bm->par_at_put_range(start_idx, end_idx, true); - } else { - card_bm->set_range(start_idx, end_idx); - } - } -} - -// Returns the index in the liveness accounting card bitmap -// for the given address -inline BitMap::idx_t G1ConcurrentMark::card_bitmap_index_for(HeapWord* addr) { - // Below, the term "card num" means the result of shifting an address - // by the card shift -- address 0 corresponds to card number 0. One - // must subtract the card num of the bottom of the heap to obtain a - // card table index. - intptr_t card_num = intptr_t(uintptr_t(addr) >> CardTableModRefBS::card_shift); - return card_num - heap_bottom_card_num(); -} - -// Counts the given memory region in the given task/worker -// counting data structures. -inline void G1ConcurrentMark::count_region(MemRegion mr, HeapRegion* hr, - size_t* marked_bytes_array, - BitMap* task_card_bm) { - G1CollectedHeap* g1h = _g1h; - CardTableModRefBS* ct_bs = g1h->g1_barrier_set(); - - HeapWord* start = mr.start(); - HeapWord* end = mr.end(); - size_t region_size_bytes = mr.byte_size(); - uint index = hr->hrm_index(); - - assert(hr == g1h->heap_region_containing(start), "sanity"); - assert(marked_bytes_array != NULL, "pre-condition"); - assert(task_card_bm != NULL, "pre-condition"); - - // Add to the task local marked bytes for this region. - marked_bytes_array[index] += region_size_bytes; - - BitMap::idx_t start_idx = card_bitmap_index_for(start); - BitMap::idx_t end_idx = card_bitmap_index_for(end); - - // Note: if we're looking at the last region in heap - end - // could be actually just beyond the end of the heap; end_idx - // will then correspond to a (non-existent) card that is also - // just beyond the heap. - if (g1h->is_in_g1_reserved(end) && !ct_bs->is_card_aligned(end)) { - // end of region is not card aligned - increment to cover - // all the cards spanned by the region. - end_idx += 1; - } - // The card bitmap is task/worker specific => no need to use - // the 'par' BitMap routines. - // Set bits in the exclusive bit range [start_idx, end_idx). - set_card_bitmap_range(task_card_bm, start_idx, end_idx, false /* is_par */); -} - -// Counts the given object in the given task/worker counting data structures. -inline void G1ConcurrentMark::count_object(oop obj, - HeapRegion* hr, - size_t* marked_bytes_array, - BitMap* task_card_bm, - size_t word_size) { - assert(!hr->is_continues_humongous(), "Cannot enter count_object with continues humongous"); - if (!hr->is_starts_humongous()) { - MemRegion mr((HeapWord*)obj, word_size); - count_region(mr, hr, marked_bytes_array, task_card_bm); - } else { - do { - MemRegion mr(hr->bottom(), hr->top()); - count_region(mr, hr, marked_bytes_array, task_card_bm); - hr = _g1h->next_region_in_humongous(hr); - } while (hr != NULL); - } -} - -// Attempts to mark the given object and, if successful, counts -// the object in the given task/worker counting structures. -inline bool G1ConcurrentMark::par_mark_and_count(oop obj, - HeapRegion* hr, - size_t* marked_bytes_array, - BitMap* task_card_bm) { - if (_nextMarkBitMap->parMark((HeapWord*)obj)) { - // Update the task specific count data for the object. - count_object(obj, hr, marked_bytes_array, task_card_bm, obj->size()); - return true; - } - return false; -} - -// Attempts to mark the given object and, if successful, counts -// the object in the task/worker counting structures for the -// given worker id. -inline bool G1ConcurrentMark::par_mark_and_count(oop obj, - size_t word_size, - HeapRegion* hr, - uint worker_id) { - if (_nextMarkBitMap->parMark((HeapWord*)obj)) { - size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id); - BitMap* task_card_bm = count_card_bitmap_for(worker_id); - count_object(obj, hr, marked_bytes_array, task_card_bm, word_size); - return true; - } - return false; +inline bool G1ConcurrentMark::par_mark(oop obj) { + return _nextMarkBitMap->parMark((HeapWord*)obj); } inline bool G1CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) { @@ -294,10 +164,8 @@ inline void G1CMTask::process_grey_object(oop obj) { check_limits(); } - - -inline void G1CMTask::make_reference_grey(oop obj, HeapRegion* hr) { - if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) { +inline void G1CMTask::make_reference_grey(oop obj) { + if (_cm->par_mark(obj)) { // No OrderAccess:store_load() is needed. It is implicit in the // CAS done in G1CMBitMap::parMark() call in the routine above. HeapWord* global_finger = _cm->finger(); @@ -348,7 +216,7 @@ inline void G1CMTask::deal_with_reference(oop obj) { // anything with it). HeapRegion* hr = _g1h->heap_region_containing(obj); if (!hr->obj_allocated_since_next_marking(obj)) { - make_reference_grey(obj, hr); + make_reference_grey(obj); } } } @@ -370,8 +238,7 @@ bool G1ConcurrentMark::isPrevMarked(oop p) const { return _prevMarkBitMap->isMarked(addr); } -inline void G1ConcurrentMark::grayRoot(oop obj, size_t word_size, - uint worker_id, HeapRegion* hr) { +inline void G1ConcurrentMark::grayRoot(oop obj, HeapRegion* hr) { assert(obj != NULL, "pre-condition"); HeapWord* addr = (HeapWord*) obj; if (hr == NULL) { @@ -386,7 +253,7 @@ inline void G1ConcurrentMark::grayRoot(oop obj, size_t word_size, if (addr < hr->next_top_at_mark_start()) { if (!_nextMarkBitMap->isMarked(addr)) { - par_mark_and_count(obj, word_size, hr, worker_id); + par_mark(obj); } } } diff --git a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp index 06721ee9295..82d655ed232 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp @@ -95,8 +95,6 @@ public: void do_object(oop obj) { HeapWord* obj_addr = (HeapWord*) obj; assert(_hr->is_in(obj_addr), "sanity"); - size_t obj_size = obj->size(); - HeapWord* obj_end = obj_addr + obj_size; if (obj->is_forwarded() && obj->forwardee() == obj) { // The object failed to move. @@ -119,8 +117,10 @@ public: // explicitly and all objects in the CSet are considered // (implicitly) live. So, we won't mark them explicitly and // we'll leave them over NTAMS. - _cm->grayRoot(obj, obj_size, _worker_id, _hr); + _cm->grayRoot(obj, _hr); } + size_t obj_size = obj->size(); + _marked_bytes += (obj_size * HeapWordSize); obj->set_mark(markOopDesc::prototype()); @@ -138,6 +138,7 @@ public: // the collection set. So, we'll recreate such entries now. obj->oop_iterate(_update_rset_cl); + HeapWord* obj_end = obj_addr + obj_size; _last_forwarded_object_end = obj_end; _hr->cross_threshold(obj_addr, obj_end); } diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp index 932bcbbfc4c..34db8d6c207 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp @@ -131,7 +131,7 @@ inline void G1RootRegionScanClosure::do_oop_nv(T* p) { if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); HeapRegion* hr = _g1h->heap_region_containing((HeapWord*) obj); - _cm->grayRoot(obj, obj->size(), _worker_id, hr); + _cm->grayRoot(obj, hr); } } @@ -246,7 +246,7 @@ void G1ParCopyHelper::mark_object(oop obj) { assert(!_g1->heap_region_containing(obj)->in_collection_set(), "should not mark objects in the CSet"); // We know that the object is not moving so it's safe to read its size. - _cm->grayRoot(obj, (size_t) obj->size(), _worker_id); + _cm->grayRoot(obj); } void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { @@ -261,7 +261,7 @@ void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { // worker so we cannot trust that its to-space image is // well-formed. So we have to read its size from its from-space // image which we know should not be changing. - _cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id); + _cm->grayRoot(to_obj); } template diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index ac78d2b0e8a..f015e4e9ee1 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -260,6 +260,9 @@ "The target number of mixed GCs after a marking cycle.") \ range(0, max_uintx) \ \ + experimental(bool, G1PretouchAuxiliaryMemory, false, \ + "Pre-touch large auxiliary data structures used by the GC.") \ + \ experimental(bool, G1EagerReclaimHumongousObjects, true, \ "Try to reclaim dead large objects at every young GC.") \ \ diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp index fced8fbb522..7804c988487 100644 --- a/hotspot/src/share/vm/utilities/bitMap.cpp +++ b/hotspot/src/share/vm/utilities/bitMap.cpp @@ -68,6 +68,10 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { } } +void BitMap::pretouch() { + os::pretouch_memory((char*)word_addr(0), (char*)word_addr(size())); +} + void BitMap::set_range_within_word(idx_t beg, idx_t end) { // With a valid range (beg <= end), this test ensures that end != 0, as // required by inverted_bit_mask_for_range. Also avoids an unnecessary write. diff --git a/hotspot/src/share/vm/utilities/bitMap.hpp b/hotspot/src/share/vm/utilities/bitMap.hpp index e57264b2e9a..0e46cea9917 100644 --- a/hotspot/src/share/vm/utilities/bitMap.hpp +++ b/hotspot/src/share/vm/utilities/bitMap.hpp @@ -135,12 +135,19 @@ class BitMap VALUE_OBJ_CLASS_SPEC { // use the same value for "in_resource_area".) void resize(idx_t size_in_bits, bool in_resource_area = true); + // Pretouch the entire range of memory this BitMap covers. + void pretouch(); + // Accessing idx_t size() const { return _size; } idx_t size_in_words() const { return word_index(size() + BitsPerWord - 1); } + static idx_t size_in_words(size_t size_in_bits) { + return word_index(size_in_bits + BitsPerWord - 1); + } + bool at(idx_t index) const { verify_index(index); return (*word_addr(index) & bit_mask(index)) != 0; diff --git a/hotspot/test/gc/g1/Test2GbHeap.java b/hotspot/test/gc/g1/Test2GbHeap.java index 8aa2c4828ce..c0c6afa5f89 100644 --- a/hotspot/test/gc/g1/Test2GbHeap.java +++ b/hotspot/test/gc/g1/Test2GbHeap.java @@ -25,6 +25,9 @@ * @test Test2GbHeap * @bug 8031686 * @summary Regression test to ensure we can start G1 with 2gb heap. + * Skip test on 32 bit Windows: it typically does not support the many and large virtual memory reservations needed. + * @requires (vm.gc == "G1" | vm.gc == "null") + * @requires !((sun.arch.data.model == "32") & (os.family == "windows")) * @key gc * @key regression * @library /testlibrary @@ -48,17 +51,6 @@ public class Test2GbHeap { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(testArguments.toArray(new String[0])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - // Avoid failing test for setups not supported. - if (output.getOutput().contains("Could not reserve enough space for 2097152KB object heap")) { - // Will fail on machines with too little memory (and Windows 32-bit VM), ignore such failures. - output.shouldHaveExitValue(1); - } else if (output.getOutput().contains("-XX:+UseG1GC not supported in this VM")) { - // G1 is not supported on embedded, ignore such failures. - output.shouldHaveExitValue(1); - } else { - // Normally everything should be fine. - output.shouldHaveExitValue(0); - } + output.shouldHaveExitValue(0); } } From 2904ea7d45992a6973374e4852e308bf5b38212b Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Wed, 6 Apr 2016 07:37:15 -0400 Subject: [PATCH 04/24] 8152846: Creation of ModuleEntryTable Investigate Need For OrderAccess::storestore() Remove the unneeded OrderAccess::storestore() call Reviewed-by: acorn, coleenp --- hotspot/src/share/vm/classfile/classLoaderData.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 0fb7a86af4f..0c0eb37196f 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -373,13 +373,10 @@ PackageEntryTable* ClassLoaderData::packages() { // Lazily create the package entry table at first request. if (_packages == NULL) { MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); - // Check again if _packages has been allocated while we were getting this lock. - if (_packages != NULL) { - return _packages; + // Check if _packages got allocated while we were waiting for this lock. + if (_packages == NULL) { + _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); } - // Ensure _packages is stable, since it is examined without a lock - OrderAccess::storestore(); - _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); } return _packages; } From a009aa9ca73241bc8740e3056bce2918f17f12b3 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 6 Apr 2016 13:41:59 +0200 Subject: [PATCH 05/24] 8151386: Extract card live data out of G1ConcurrentMark Move card live data management out of G1ConcurrentMark into extra class G1CardLiveData managed by G1RemSet Reviewed-by: mgerdin, kbarrett --- .../share/vm/gc/g1/concurrentMarkThread.cpp | 1 + hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp | 552 +++++++++++++++++ hotspot/src/share/vm/gc/g1/g1CardLiveData.hpp | 99 +++ .../share/vm/gc/g1/g1CardLiveData.inline.hpp | 52 ++ .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 15 +- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +- .../share/vm/gc/g1/g1CollectedHeap.inline.hpp | 2 +- .../src/share/vm/gc/g1/g1ConcurrentMark.cpp | 579 ++---------------- .../src/share/vm/gc/g1/g1ConcurrentMark.hpp | 32 +- .../vm/gc/g1/g1ConcurrentMark.inline.hpp | 10 + hotspot/src/share/vm/gc/g1/g1OopClosures.hpp | 6 +- hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 50 +- hotspot/src/share/vm/gc/g1/g1RemSet.hpp | 21 +- .../src/share/vm/gc/g1/heapRegionRemSet.cpp | 22 +- .../src/share/vm/gc/g1/heapRegionRemSet.hpp | 8 +- hotspot/src/share/vm/utilities/bitMap.cpp | 2 +- hotspot/src/share/vm/utilities/bitMap.hpp | 7 +- 17 files changed, 848 insertions(+), 613 deletions(-) create mode 100644 hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp create mode 100644 hotspot/src/share/vm/gc/g1/g1CardLiveData.hpp create mode 100644 hotspot/src/share/vm/gc/g1/g1CardLiveData.inline.hpp diff --git a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp index 7eef582e3db..9727b023268 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp @@ -28,6 +28,7 @@ #include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp b/hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp new file mode 100644 index 00000000000..009179150a9 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1CardLiveData.cpp @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1ConcurrentMark.inline.hpp" +#include "gc/g1/g1CardLiveData.inline.hpp" +#include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/workgroup.hpp" +#include "memory/universe.hpp" +#include "runtime/atomic.inline.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "utilities/bitMap.inline.hpp" +#include "utilities/debug.hpp" + +G1CardLiveData::G1CardLiveData() : + _max_capacity(0), + _cards_per_region(0), + _live_regions(NULL), + _live_regions_size_in_bits(0), + _live_cards(NULL), + _live_cards_size_in_bits(0) { +} + +G1CardLiveData::~G1CardLiveData() { + free_large_bitmap(_live_cards, _live_cards_size_in_bits); + free_large_bitmap(_live_regions, _live_regions_size_in_bits); +} + +G1CardLiveData::bm_word_t* G1CardLiveData::allocate_large_bitmap(size_t size_in_bits) { + size_t size_in_words = BitMap::calc_size_in_words(size_in_bits); + + bm_word_t* map = MmapArrayAllocator::allocate(size_in_words); + + return map; +} + +void G1CardLiveData::free_large_bitmap(bm_word_t* bitmap, size_t size_in_bits) { + MmapArrayAllocator::free(bitmap, size_in_bits / BitsPerWord); +} + +void G1CardLiveData::initialize(size_t max_capacity, uint num_max_regions) { + assert(max_capacity % num_max_regions == 0, + "Given capacity must be evenly divisible by region size."); + size_t region_size = max_capacity / num_max_regions; + assert(region_size % (G1SATBCardTableModRefBS::card_size * BitsPerWord) == 0, + "Region size must be evenly divisible by area covered by a single word."); + _max_capacity = max_capacity; + _cards_per_region = region_size / G1SATBCardTableModRefBS::card_size; + + _live_regions_size_in_bits = live_region_bitmap_size_in_bits(); + _live_regions = allocate_large_bitmap(_live_regions_size_in_bits); + _live_cards_size_in_bits = live_card_bitmap_size_in_bits(); + _live_cards = allocate_large_bitmap(_live_cards_size_in_bits); +} + +void G1CardLiveData::pretouch() { + live_cards_bm().pretouch(); + live_regions_bm().pretouch(); +} + +size_t G1CardLiveData::live_region_bitmap_size_in_bits() const { + return _max_capacity / (_cards_per_region << G1SATBCardTableModRefBS::card_shift); +} + +size_t G1CardLiveData::live_card_bitmap_size_in_bits() const { + return _max_capacity >> G1SATBCardTableModRefBS::card_shift; +} + +// Helper class that provides functionality to generate the Live Data Count +// information. +class G1CardLiveDataHelper VALUE_OBJ_CLASS_SPEC { +private: + BitMap _region_bm; + BitMap _card_bm; + + // The card number of the bottom of the G1 heap. + // Used in biasing indices into accounting card bitmaps. + BitMap::idx_t _heap_card_bias; + + // Utility routine to set an exclusive range of bits on the given + // bitmap, optimized for very small ranges. + // There must be at least one bit to set. + void set_card_bitmap_range(BitMap::idx_t start_idx, + BitMap::idx_t end_idx) { + + // Set the exclusive bit range [start_idx, end_idx). + assert((end_idx - start_idx) > 0, "at least one bit"); + + // For small ranges use a simple loop; otherwise use set_range. + // The range is made up of the cards that are spanned by an object/mem + // region so 8 cards will allow up to object sizes up to 4K to be handled + // using the loop. + if ((end_idx - start_idx) <= 8) { + for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) { + _card_bm.set_bit(i); + } + } else { + _card_bm.set_range(start_idx, end_idx); + } + } + + // We cache the last mark set. This avoids setting the same bit multiple times. + // This is particularly interesting for dense bitmaps, as this avoids doing + // lots of work most of the time. + BitMap::idx_t _last_marked_bit_idx; + + // Mark the card liveness bitmap for the object spanning from start to end. + void mark_card_bitmap_range(HeapWord* start, HeapWord* end) { + BitMap::idx_t start_idx = card_live_bitmap_index_for(start); + BitMap::idx_t end_idx = card_live_bitmap_index_for((HeapWord*)align_ptr_up(end, CardTableModRefBS::card_size)); + + assert((end_idx - start_idx) > 0, "Trying to mark zero sized range."); + + if (start_idx == _last_marked_bit_idx) { + start_idx++; + } + if (start_idx == end_idx) { + return; + } + + // Set the bits in the card bitmap for the cards spanned by this object. + set_card_bitmap_range(start_idx, end_idx); + _last_marked_bit_idx = end_idx - 1; + } + + void reset_mark_cache() { + _last_marked_bit_idx = (BitMap::idx_t)-1; + } + +public: + // Returns the index in the per-card liveness count bitmap + // for the given address + inline BitMap::idx_t card_live_bitmap_index_for(HeapWord* addr) { + // Below, the term "card num" means the result of shifting an address + // by the card shift -- address 0 corresponds to card number 0. One + // must subtract the card num of the bottom of the heap to obtain a + // card table index. + BitMap::idx_t card_num = uintptr_t(addr) >> CardTableModRefBS::card_shift; + return card_num - _heap_card_bias; + } + + // Takes a region that's not empty (i.e., it has at least one + // live object in it and sets its corresponding bit on the region + // bitmap to 1. + void set_bit_for_region(HeapRegion* hr) { + _region_bm.par_set_bit(hr->hrm_index()); + } + + // Mark the range of bits covered by allocations done since the last marking + // in the given heap region, i.e. from NTAMS to top of the given region. + // Returns if there has been some allocation in this region since the last marking. + bool mark_allocated_since_marking(HeapRegion* hr) { + reset_mark_cache(); + + HeapWord* ntams = hr->next_top_at_mark_start(); + HeapWord* top = hr->top(); + + assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions."); + + // Mark the allocated-since-marking portion... + if (ntams < top) { + mark_card_bitmap_range(ntams, top); + return true; + } else { + return false; + } + } + + // Mark the range of bits covered by live objects on the mark bitmap between + // bottom and NTAMS of the given region. + // Returns the number of live bytes marked within that area for the given + // heap region. + size_t mark_marked_during_marking(G1CMBitMap* mark_bitmap, HeapRegion* hr) { + reset_mark_cache(); + + size_t marked_bytes = 0; + + HeapWord* ntams = hr->next_top_at_mark_start(); + HeapWord* start = hr->bottom(); + + if (ntams <= start) { + // Skip empty regions. + return 0; + } + if (hr->is_humongous()) { + mark_card_bitmap_range(start, hr->top()); + return pointer_delta(hr->top(), start, 1); + } + + assert(start <= hr->end() && start <= ntams && ntams <= hr->end(), + "Preconditions not met - " + "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, + p2i(start), p2i(ntams), p2i(hr->end())); + + // Find the first marked object at or after "start". + start = mark_bitmap->getNextMarkedWordAddress(start, ntams); + while (start < ntams) { + oop obj = oop(start); + size_t obj_size = obj->size(); + HeapWord* obj_end = start + obj_size; + + assert(obj_end <= hr->end(), "Humongous objects must have been handled elsewhere."); + + mark_card_bitmap_range(start, obj_end); + + // Add the size of this object to the number of marked bytes. + marked_bytes += obj_size * HeapWordSize; + + // Find the next marked object after this one. + start = mark_bitmap->getNextMarkedWordAddress(obj_end, ntams); + } + + return marked_bytes; + } + + G1CardLiveDataHelper(G1CardLiveData* live_data, HeapWord* base_address) : + _region_bm(live_data->live_regions_bm()), + _card_bm(live_data->live_cards_bm()) { + // Calculate the card number for the bottom of the heap. Used + // in biasing indexes into the accounting card bitmaps. + _heap_card_bias = + uintptr_t(base_address) >> CardTableModRefBS::card_shift; + } +}; + +class G1CreateCardLiveDataTask: public AbstractGangTask { + // Aggregate the counting data that was constructed concurrently + // with marking. + class G1CreateLiveDataClosure : public HeapRegionClosure { + G1CardLiveDataHelper _helper; + + G1CMBitMap* _mark_bitmap; + + G1ConcurrentMark* _cm; + public: + G1CreateLiveDataClosure(G1CollectedHeap* g1h, + G1ConcurrentMark* cm, + G1CMBitMap* mark_bitmap, + G1CardLiveData* live_data) : + HeapRegionClosure(), + _helper(live_data, g1h->reserved_region().start()), + _mark_bitmap(mark_bitmap), + _cm(cm) { } + + bool doHeapRegion(HeapRegion* hr) { + size_t marked_bytes = _helper.mark_marked_during_marking(_mark_bitmap, hr); + if (marked_bytes > 0) { + hr->add_to_marked_bytes(marked_bytes); + } + + return (_cm->do_yield_check() && _cm->has_aborted()); + } + }; + + G1ConcurrentMark* _cm; + G1CardLiveData* _live_data; + HeapRegionClaimer _hr_claimer; + +public: + G1CreateCardLiveDataTask(G1CMBitMap* bitmap, + G1CardLiveData* live_data, + uint n_workers) : + AbstractGangTask("G1 Create Live Data"), + _live_data(live_data), + _hr_claimer(n_workers) { + } + + void work(uint worker_id) { + SuspendibleThreadSetJoiner sts_join; + + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + G1ConcurrentMark* cm = g1h->concurrent_mark(); + G1CreateLiveDataClosure cl(g1h, cm, cm->nextMarkBitMap(), _live_data); + g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); + } +}; + +void G1CardLiveData::create(WorkGang* workers, G1CMBitMap* mark_bitmap) { + uint n_workers = workers->active_workers(); + + G1CreateCardLiveDataTask cl(mark_bitmap, + this, + n_workers); + workers->run_task(&cl); +} + +class G1FinalizeCardLiveDataTask: public AbstractGangTask { + // Finalizes the liveness counting data. + // Sets the bits corresponding to the interval [NTAMS, top] + // (which contains the implicitly live objects) in the + // card liveness bitmap. Also sets the bit for each region + // containing live data, in the region liveness bitmap. + class G1FinalizeCardLiveDataClosure: public HeapRegionClosure { + private: + G1CardLiveDataHelper _helper; + public: + G1FinalizeCardLiveDataClosure(G1CollectedHeap* g1h, + G1CMBitMap* bitmap, + G1CardLiveData* live_data) : + HeapRegionClosure(), + _helper(live_data, g1h->reserved_region().start()) { } + + bool doHeapRegion(HeapRegion* hr) { + bool allocated_since_marking = _helper.mark_allocated_since_marking(hr); + if (allocated_since_marking || hr->next_marked_bytes() > 0) { + _helper.set_bit_for_region(hr); + } + return false; + } + }; + + G1CMBitMap* _bitmap; + + G1CardLiveData* _live_data; + + HeapRegionClaimer _hr_claimer; + +public: + G1FinalizeCardLiveDataTask(G1CMBitMap* bitmap, G1CardLiveData* live_data, uint n_workers) : + AbstractGangTask("G1 Finalize Card Live Data"), + _bitmap(bitmap), + _live_data(live_data), + _hr_claimer(n_workers) { + } + + void work(uint worker_id) { + G1FinalizeCardLiveDataClosure cl(G1CollectedHeap::heap(), _bitmap, _live_data); + + G1CollectedHeap::heap()->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); + } +}; + +void G1CardLiveData::finalize(WorkGang* workers, G1CMBitMap* mark_bitmap) { + // Finalize the live data. + G1FinalizeCardLiveDataTask cl(mark_bitmap, + this, + workers->active_workers()); + workers->run_task(&cl); +} + +class G1ClearCardLiveDataTask : public AbstractGangTask { + BitMap _bitmap; + size_t _num_chunks; + size_t _cur_chunk; +public: + G1ClearCardLiveDataTask(BitMap bitmap, size_t num_tasks) : + AbstractGangTask("G1 Clear Card Live Data"), + _bitmap(bitmap), + _num_chunks(num_tasks), + _cur_chunk(0) { + } + + static size_t chunk_size() { return M; } + + virtual void work(uint worker_id) { + while (true) { + size_t to_process = Atomic::add(1, &_cur_chunk) - 1; + if (to_process >= _num_chunks) { + break; + } + + BitMap::idx_t start = M * BitsPerByte * to_process; + BitMap::idx_t end = MIN2(start + M * BitsPerByte, _bitmap.size()); + _bitmap.clear_range(start, end); + } + } +}; + +void G1CardLiveData::clear(WorkGang* workers) { + guarantee(Universe::is_fully_initialized(), "Should not call this during initialization."); + + size_t const num_chunks = align_size_up(live_cards_bm().size_in_bytes(), G1ClearCardLiveDataTask::chunk_size()) / G1ClearCardLiveDataTask::chunk_size(); + + G1ClearCardLiveDataTask cl(live_cards_bm(), num_chunks); + workers->run_task(&cl); + + // The region live bitmap is always very small, even for huge heaps. Clear + // directly. + live_regions_bm().clear(); +} + +class G1VerifyCardLiveDataTask: public AbstractGangTask { + // Heap region closure used for verifying the live count data + // that was created concurrently and finalized during + // the remark pause. This closure is applied to the heap + // regions during the STW cleanup pause. + class G1VerifyCardLiveDataClosure: public HeapRegionClosure { + private: + G1CollectedHeap* _g1h; + G1CMBitMap* _mark_bitmap; + G1CardLiveDataHelper _helper; + + G1CardLiveData* _act_live_data; + + G1CardLiveData* _exp_live_data; + + int _failures; + + // Completely recreates the live data count for the given heap region and + // returns the number of bytes marked. + size_t create_live_data_count(HeapRegion* hr) { + size_t bytes_marked = _helper.mark_marked_during_marking(_mark_bitmap, hr); + bool allocated_since_marking = _helper.mark_allocated_since_marking(hr); + if (allocated_since_marking || bytes_marked > 0) { + _helper.set_bit_for_region(hr); + } + return bytes_marked; + } + public: + G1VerifyCardLiveDataClosure(G1CollectedHeap* g1h, + G1CMBitMap* mark_bitmap, + G1CardLiveData* act_live_data, + G1CardLiveData* exp_live_data) : + _g1h(g1h), + _mark_bitmap(mark_bitmap), + _helper(exp_live_data, g1h->reserved_region().start()), + _act_live_data(act_live_data), + _exp_live_data(exp_live_data), + _failures(0) { } + + int failures() const { return _failures; } + + bool doHeapRegion(HeapRegion* hr) { + int failures = 0; + + // Walk the marking bitmap for this region and set the corresponding bits + // in the expected region and card bitmaps. + size_t exp_marked_bytes = create_live_data_count(hr); + size_t act_marked_bytes = hr->next_marked_bytes(); + // Verify the marked bytes for this region. + + if (exp_marked_bytes != act_marked_bytes) { + failures += 1; + } else if (exp_marked_bytes > HeapRegion::GrainBytes) { + failures += 1; + } + + // Verify the bit, for this region, in the actual and expected + // (which was just calculated) region bit maps. + // We're not OK if the bit in the calculated expected region + // bitmap is set and the bit in the actual region bitmap is not. + uint index = hr->hrm_index(); + + bool expected = _exp_live_data->is_region_live(index); + bool actual = _act_live_data->is_region_live(index); + if (expected && !actual) { + failures += 1; + } + + // Verify that the card bit maps for the cards spanned by the current + // region match. We have an error if we have a set bit in the expected + // bit map and the corresponding bit in the actual bitmap is not set. + + BitMap::idx_t start_idx = _helper.card_live_bitmap_index_for(hr->bottom()); + BitMap::idx_t end_idx = _helper.card_live_bitmap_index_for(hr->top()); + + for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) { + expected = _exp_live_data->is_card_live_at(i); + actual = _act_live_data->is_card_live_at(i); + + if (expected && !actual) { + failures += 1; + } + } + + _failures += failures; + + // We could stop iteration over the heap when we + // find the first violating region by returning true. + return false; + } + }; +protected: + G1CollectedHeap* _g1h; + G1CMBitMap* _mark_bitmap; + + G1CardLiveData* _act_live_data; + + G1CardLiveData _exp_live_data; + + int _failures; + + HeapRegionClaimer _hr_claimer; + +public: + G1VerifyCardLiveDataTask(G1CMBitMap* bitmap, + G1CardLiveData* act_live_data, + uint n_workers) + : AbstractGangTask("G1 Verify Card Live Data"), + _g1h(G1CollectedHeap::heap()), + _mark_bitmap(bitmap), + _act_live_data(act_live_data), + _exp_live_data(), + _failures(0), + _hr_claimer(n_workers) { + assert(VerifyDuringGC, "don't call this otherwise"); + _exp_live_data.initialize(_g1h->max_capacity(), _g1h->max_regions()); + } + + void work(uint worker_id) { + G1VerifyCardLiveDataClosure cl(_g1h, + _mark_bitmap, + _act_live_data, + &_exp_live_data); + _g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); + + Atomic::add(cl.failures(), &_failures); + } + + int failures() const { return _failures; } +}; + +void G1CardLiveData::verify(WorkGang* workers, G1CMBitMap* actual_bitmap) { + ResourceMark rm; + + G1VerifyCardLiveDataTask cl(actual_bitmap, + this, + workers->active_workers()); + workers->run_task(&cl); + + guarantee(cl.failures() == 0, "Unexpected accounting failures"); +} + +#ifndef PRODUCT +void G1CardLiveData::verify_is_clear() { + assert(live_cards_bm().count_one_bits() == 0, "Live cards bitmap must be clear."); + assert(live_regions_bm().count_one_bits() == 0, "Live regions bitmap must be clear."); +} +#endif diff --git a/hotspot/src/share/vm/gc/g1/g1CardLiveData.hpp b/hotspot/src/share/vm/gc/g1/g1CardLiveData.hpp new file mode 100644 index 00000000000..d76fa66d3c4 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1CardLiveData.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1CARDLIVEDATA_HPP +#define SHARE_VM_GC_G1_G1CARDLIVEDATA_HPP + +#include "gc/g1/g1CollectedHeap.hpp" +#include "utilities/bitMap.hpp" +#include "utilities/globalDefinitions.hpp" + +class G1CollectedHeap; +class G1CMBitMap; +class WorkGang; + +// Information about object liveness on the Java heap on a "card" basis. +// Can be used for various purposes, like as remembered set for completely +// coarsened remembered sets, scrubbing remembered sets or estimating liveness. +// This information is created as part of the concurrent marking cycle. +class G1CardLiveData VALUE_OBJ_CLASS_SPEC { + friend class G1CardLiveDataHelper; + friend class G1VerifyCardLiveDataTask; +private: + typedef BitMap::bm_word_t bm_word_t; + // Store some additional information about the covered area to be able to test. + size_t _max_capacity; + size_t _cards_per_region; + + // The per-card liveness bitmap. + bm_word_t* _live_cards; + size_t _live_cards_size_in_bits; + // The per-region liveness bitmap. + bm_word_t* _live_regions; + size_t _live_regions_size_in_bits; + // The bits in this bitmap contain for every card whether it contains + // at least part of at least one live object. + BitMap live_cards_bm() const { return BitMap(_live_cards, _live_cards_size_in_bits); } + // The bits in this bitmap indicate that a given region contains some live objects. + BitMap live_regions_bm() const { return BitMap(_live_regions, _live_regions_size_in_bits); } + + // Allocate a "large" bitmap from virtual memory with the given size in bits. + bm_word_t* allocate_large_bitmap(size_t size_in_bits); + void free_large_bitmap(bm_word_t* map, size_t size_in_bits); + + inline BitMap live_card_bitmap(uint region); + + inline bool is_card_live_at(BitMap::idx_t idx) const; + + size_t live_region_bitmap_size_in_bits() const; + size_t live_card_bitmap_size_in_bits() const; +public: + inline bool is_region_live(uint region) const; + + inline void remove_nonlive_cards(uint region, BitMap* bm); + inline void remove_nonlive_regions(BitMap* bm); + + G1CardLiveData(); + ~G1CardLiveData(); + + void initialize(size_t max_capacity, uint num_max_regions); + void pretouch(); + + // Create the initial liveness data based on the marking result from the bottom + // to the ntams of every region in the heap and the marks in the given bitmap. + void create(WorkGang* workers, G1CMBitMap* mark_bitmap); + // Finalize the liveness data. + void finalize(WorkGang* workers, G1CMBitMap* mark_bitmap); + + // Verify that the liveness count data created concurrently matches one created + // during this safepoint. + void verify(WorkGang* workers, G1CMBitMap* actual_bitmap); + // Clear all data structures, prepare for next processing. + void clear(WorkGang* workers); + + void verify_is_clear() PRODUCT_RETURN; +}; + +#endif /* SHARE_VM_GC_G1_G1CARDLIVEDATA_HPP */ + diff --git a/hotspot/src/share/vm/gc/g1/g1CardLiveData.inline.hpp b/hotspot/src/share/vm/gc/g1/g1CardLiveData.inline.hpp new file mode 100644 index 00000000000..fc14ed8bcf3 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1CardLiveData.inline.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1CARDLIVEDATA_INLINE_HPP +#define SHARE_VM_GC_G1_G1CARDLIVEDATA_INLINE_HPP + +#include "gc/g1/g1CardLiveData.hpp" +#include "utilities/bitMap.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +inline BitMap G1CardLiveData::live_card_bitmap(uint region) { + return BitMap(_live_cards + ((size_t)region * _cards_per_region >> LogBitsPerWord), _cards_per_region); +} + +inline bool G1CardLiveData::is_card_live_at(BitMap::idx_t idx) const { + return live_cards_bm().at(idx); +} + +inline bool G1CardLiveData::is_region_live(uint region) const { + return live_regions_bm().at(region); +} + +inline void G1CardLiveData::remove_nonlive_cards(uint region, BitMap* bm) { + bm->set_intersection(live_card_bitmap(region)); +} + +inline void G1CardLiveData::remove_nonlive_regions(BitMap* bm) { + bm->set_intersection(live_regions_bm()); +} + +#endif /* SHARE_VM_GC_G1_G1CARDLIVEDATA_INLINE_HPP */ diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 03d4e76f3a8..2861baf232d 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1425,6 +1425,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, // the full GC has compacted objects and updated TAMS but not updated // the prev bitmap. if (G1VerifyBitmaps) { + GCTraceTime(Debug, gc)("Clear Bitmap for Verification"); _cm->clear_prev_bitmap(workers()); } _verifier->check_bitmaps("Full GC End"); @@ -1944,7 +1945,7 @@ jint G1CollectedHeap::initialize() { const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1; guarantee((max_regions() - 1) <= max_region_idx, "too many regions"); - G1RemSet::initialize(max_regions()); + g1_rem_set()->initialize(max_capacity(), max_regions()); size_t max_cards_per_region = ((size_t)1 << (sizeof(CardIdx_t)*BitsPerByte-1)) - 1; guarantee(HeapRegion::CardsPerRegion > 0, "make sure it's initialized"); @@ -4787,27 +4788,23 @@ public: class G1ParScrubRemSetTask: public AbstractGangTask { protected: G1RemSet* _g1rs; - BitMap* _region_bm; - BitMap* _card_bm; HeapRegionClaimer _hrclaimer; public: - G1ParScrubRemSetTask(G1RemSet* g1_rs, BitMap* region_bm, BitMap* card_bm, uint num_workers) : + G1ParScrubRemSetTask(G1RemSet* g1_rs, uint num_workers) : AbstractGangTask("G1 ScrubRS"), _g1rs(g1_rs), - _region_bm(region_bm), - _card_bm(card_bm), _hrclaimer(num_workers) { } void work(uint worker_id) { - _g1rs->scrub(_region_bm, _card_bm, worker_id, &_hrclaimer); + _g1rs->scrub(worker_id, &_hrclaimer); } }; -void G1CollectedHeap::scrub_rem_set(BitMap* region_bm, BitMap* card_bm) { +void G1CollectedHeap::scrub_rem_set() { uint num_workers = workers()->active_workers(); - G1ParScrubRemSetTask g1_par_scrub_rs_task(g1_rem_set(), region_bm, card_bm, num_workers); + G1ParScrubRemSetTask g1_par_scrub_rs_task(g1_rem_set(), num_workers); workers()->run_task(&g1_par_scrub_rs_task); } diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 4bde7c70d04..e98d57af7fb 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -992,7 +992,8 @@ public: // The rem set and barrier set. G1RemSet* g1_rem_set() const { return _g1_rem_set; } - void scrub_rem_set(BitMap* region_bm, BitMap* card_bm); + // Try to minimize the remembered set. + void scrub_rem_set(); unsigned get_gc_time_stamp() { return _gc_time_stamp; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp index eaf329b3acd..040367b5be1 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp @@ -28,7 +28,7 @@ #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorState.hpp" -#include "gc/g1/g1ConcurrentMark.hpp" +#include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionSet.inline.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index a181b467c7d..526387c018e 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -33,6 +33,7 @@ #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1OopClosures.inline.hpp" +#include "gc/g1/g1CardLiveData.inline.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" @@ -48,7 +49,6 @@ #include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/vmGCOperations.hpp" #include "logging/log.hpp" -#include "logging/logTag.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" @@ -356,8 +356,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* _sleep_factor(0.0), _marking_task_overhead(1.0), _cleanup_list("Cleanup List"), - _region_live_bm(), - _card_live_bm(), _prevMarkBitMap(&_markBitMap1), _nextMarkBitMap(&_markBitMap2), @@ -499,12 +497,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* return; } - allocate_internal_bitmaps(); - - if (G1PretouchAuxiliaryMemory) { - pretouch_internal_bitmaps(); - } - _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC); _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC); @@ -701,8 +693,8 @@ void G1ConcurrentMark::cleanup_for_next_mark() { // Clear the live count data. If the marking has been aborted, the abort() // call already did that. if (!has_aborted()) { - clear_all_live_data(_parallel_workers); - DEBUG_ONLY(verify_all_live_data()); + clear_live_data(_parallel_workers); + DEBUG_ONLY(verify_live_data_clear()); } // Repeat the asserts from above. @@ -884,7 +876,7 @@ public: double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; _cm->clear_has_overflown(); - _cm->do_yield_check(worker_id); + _cm->do_yield_check(); jlong sleep_time_ms; if (!_cm->has_aborted() && the_task->has_aborted()) { @@ -934,10 +926,10 @@ uint G1ConcurrentMark::calc_parallel_marking_threads() { return n_conc_workers; } -void G1ConcurrentMark::scanRootRegion(HeapRegion* hr, uint worker_id) { +void G1ConcurrentMark::scanRootRegion(HeapRegion* hr) { // Currently, only survivors can be root regions. assert(hr->next_top_at_mark_start() == hr->bottom(), "invariant"); - G1RootRegionScanClosure cl(_g1h, this, worker_id); + G1RootRegionScanClosure cl(_g1h, this); const uintx interval = PrefetchScanIntervalInBytes; HeapWord* curr = hr->bottom(); @@ -966,7 +958,7 @@ public: G1CMRootRegions* root_regions = _cm->root_regions(); HeapRegion* hr = root_regions->claim_next(); while (hr != NULL) { - _cm->scanRootRegion(hr, worker_id); + _cm->scanRootRegion(hr); hr = root_regions->claim_next(); } } @@ -1125,363 +1117,6 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { _gc_tracer_cm->report_object_count_after_gc(&is_alive); } -// Helper class that provides functionality to generate the Live Data Count -// information. -class G1LiveDataHelper VALUE_OBJ_CLASS_SPEC { -private: - BitMap* _region_bm; - BitMap* _card_bm; - - // The card number of the bottom of the G1 heap. Used for converting addresses - // to bitmap indices quickly. - BitMap::idx_t _heap_card_bias; - - // Utility routine to set an exclusive range of bits on the given - // bitmap, optimized for very small ranges. - // There must be at least one bit to set. - inline void set_card_bitmap_range(BitMap* bm, - BitMap::idx_t start_idx, - BitMap::idx_t end_idx) { - - // Set the exclusive bit range [start_idx, end_idx). - assert((end_idx - start_idx) > 0, "at least one bit"); - assert(end_idx <= bm->size(), "sanity"); - - // For small ranges use a simple loop; otherwise use set_range or - // use par_at_put_range (if parallel). The range is made up of the - // cards that are spanned by an object/mem region so 8 cards will - // allow up to object sizes up to 4K to be handled using the loop. - if ((end_idx - start_idx) <= 8) { - for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) { - bm->set_bit(i); - } - } else { - bm->set_range(start_idx, end_idx); - } - } - - // We cache the last mark set. This avoids setting the same bit multiple times. - // This is particularly interesting for dense bitmaps, as this avoids doing - // lots of work most of the time. - BitMap::idx_t _last_marked_bit_idx; - - // Mark the card liveness bitmap for the object spanning from start to end. - void mark_card_bitmap_range(HeapWord* start, HeapWord* end) { - BitMap::idx_t start_idx = card_live_bitmap_index_for(start); - BitMap::idx_t end_idx = card_live_bitmap_index_for((HeapWord*)align_ptr_up(end, CardTableModRefBS::card_size)); - - assert((end_idx - start_idx) > 0, "Trying to mark zero sized range."); - - if (start_idx == _last_marked_bit_idx) { - start_idx++; - } - if (start_idx == end_idx) { - return; - } - - // Set the bits in the card bitmap for the cards spanned by this object. - set_card_bitmap_range(_card_bm, start_idx, end_idx); - _last_marked_bit_idx = end_idx - 1; - } - - void reset_mark_cache() { - _last_marked_bit_idx = (BitMap::idx_t)-1; - } - -public: - // Returns the index in the per-card liveness count bitmap - // for the given address - inline BitMap::idx_t card_live_bitmap_index_for(HeapWord* addr) { - // Below, the term "card num" means the result of shifting an address - // by the card shift -- address 0 corresponds to card number 0. One - // must subtract the card num of the bottom of the heap to obtain a - // card table index. - BitMap::idx_t card_num = (BitMap::idx_t)(uintptr_t(addr) >> CardTableModRefBS::card_shift); - return card_num - _heap_card_bias; - } - - // Takes a region that's not empty (i.e., it has at least one - // live object in it and sets its corresponding bit on the region - // bitmap to 1. - void set_bit_for_region(HeapRegion* hr) { - BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index(); - _region_bm->par_at_put(index, true); - } - - // Mark the range of bits covered by allocations done since the last marking - // in the given heap region, i.e. from NTAMS to top of the given region. - // Returns if there has been some allocation in this region since the last marking. - bool mark_allocated_since_marking(HeapRegion* hr) { - reset_mark_cache(); - - HeapWord* ntams = hr->next_top_at_mark_start(); - HeapWord* top = hr->top(); - - assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions."); - - // Mark the allocated-since-marking portion... - if (ntams < top) { - mark_card_bitmap_range(ntams, top); - return true; - } else { - return false; - } - } - - // Mark the range of bits covered by live objects on the mark bitmap between - // bottom and NTAMS of the given region. - // Returns the number of live bytes marked within that area for the given - // heap region. - size_t mark_marked_during_marking(G1CMBitMap* mark_bitmap, HeapRegion* hr) { - reset_mark_cache(); - - size_t marked_bytes = 0; - - HeapWord* ntams = hr->next_top_at_mark_start(); - HeapWord* start = hr->bottom(); - - if (ntams <= start) { - // Skip empty regions. - return 0; - } else if (hr->is_humongous()) { - mark_card_bitmap_range(start, hr->top()); - return pointer_delta(hr->top(), start, 1); - } - - assert(start <= hr->end() && start <= ntams && ntams <= hr->end(), - "Preconditions not met - " - "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, - p2i(start), p2i(ntams), p2i(hr->end())); - - // Find the first marked object at or after "start". - start = mark_bitmap->getNextMarkedWordAddress(start, ntams); - while (start < ntams) { - oop obj = oop(start); - int obj_sz = obj->size(); - HeapWord* obj_end = start + obj_sz; - - assert(obj_end <= hr->end(), "Humongous objects must have been handled elsewhere."); - - mark_card_bitmap_range(start, obj_end); - - // Add the size of this object to the number of marked bytes. - marked_bytes += (size_t)obj_sz * HeapWordSize; - - // Find the next marked object after this one. - start = mark_bitmap->getNextMarkedWordAddress(obj_end, ntams); - } - - return marked_bytes; - } - - G1LiveDataHelper(BitMap* region_bm, - BitMap* card_bm): - _region_bm(region_bm), - _card_bm(card_bm) { - //assert(region_bm != NULL, ""); - assert(card_bm != NULL, ""); - // Calculate the card number for the bottom of the heap. Used - // in biasing indexes into the accounting card bitmaps. - _heap_card_bias = - (BitMap::idx_t)(uintptr_t(G1CollectedHeap::heap()->reserved_region().start()) >> CardTableModRefBS::card_shift); - } -}; - -// Heap region closure used for verifying the live count data -// that was created concurrently and finalized during -// the remark pause. This closure is applied to the heap -// regions during the STW cleanup pause. -class G1VerifyLiveDataHRClosure: public HeapRegionClosure { -private: - G1CollectedHeap* _g1h; - G1CMBitMap* _mark_bitmap; - G1LiveDataHelper _calc_helper; - - BitMap* _act_region_bm; // Region BM to be verified - BitMap* _act_card_bm; // Card BM to be verified - - BitMap* _exp_region_bm; // Expected Region BM values - BitMap* _exp_card_bm; // Expected card BM values - - int _failures; - - // Updates the live data count for the given heap region and returns the number - // of bytes marked. - size_t create_live_data_count(HeapRegion* hr) { - size_t bytes_marked = _calc_helper.mark_marked_during_marking(_mark_bitmap, hr); - bool allocated_since_marking = _calc_helper.mark_allocated_since_marking(hr); - if (allocated_since_marking || bytes_marked > 0) { - _calc_helper.set_bit_for_region(hr); - } - return bytes_marked; - } - -public: - G1VerifyLiveDataHRClosure(G1CollectedHeap* g1h, - G1CMBitMap* mark_bitmap, - BitMap* act_region_bm, - BitMap* act_card_bm, - BitMap* exp_region_bm, - BitMap* exp_card_bm) : - _g1h(g1h), - _mark_bitmap(mark_bitmap), - _calc_helper(exp_region_bm, exp_card_bm), - _act_region_bm(act_region_bm), - _act_card_bm(act_card_bm), - _exp_region_bm(exp_region_bm), - _exp_card_bm(exp_card_bm), - _failures(0) { } - - int failures() const { return _failures; } - - bool doHeapRegion(HeapRegion* hr) { - int failures = 0; - - // Walk the marking bitmap for this region and set the corresponding bits - // in the expected region and card bitmaps. - size_t exp_marked_bytes = create_live_data_count(hr); - size_t act_marked_bytes = hr->next_marked_bytes(); - // Verify the marked bytes for this region. - - if (exp_marked_bytes != act_marked_bytes) { - failures += 1; - } else if (exp_marked_bytes > HeapRegion::GrainBytes) { - failures += 1; - } - - // Verify the bit, for this region, in the actual and expected - // (which was just calculated) region bit maps. - // We're not OK if the bit in the calculated expected region - // bitmap is set and the bit in the actual region bitmap is not. - BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index(); - - bool expected = _exp_region_bm->at(index); - bool actual = _act_region_bm->at(index); - if (expected && !actual) { - failures += 1; - } - - // Verify that the card bit maps for the cards spanned by the current - // region match. We have an error if we have a set bit in the expected - // bit map and the corresponding bit in the actual bitmap is not set. - - BitMap::idx_t start_idx = _calc_helper.card_live_bitmap_index_for(hr->bottom()); - BitMap::idx_t end_idx = _calc_helper.card_live_bitmap_index_for(hr->top()); - - for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) { - expected = _exp_card_bm->at(i); - actual = _act_card_bm->at(i); - - if (expected && !actual) { - failures += 1; - } - } - - _failures += failures; - - // We could stop iteration over the heap when we - // find the first violating region by returning true. - return false; - } -}; - -class G1VerifyLiveDataTask: public AbstractGangTask { -protected: - G1CollectedHeap* _g1h; - G1CMBitMap* _mark_bitmap; - BitMap* _actual_region_bm; - BitMap* _actual_card_bm; - - BitMap _expected_region_bm; - BitMap _expected_card_bm; - - int _failures; - - HeapRegionClaimer _hr_claimer; - -public: - G1VerifyLiveDataTask(G1CollectedHeap* g1h, - G1CMBitMap* bitmap, - BitMap* region_bm, - BitMap* card_bm, - uint n_workers) - : AbstractGangTask("G1 verify final counting"), - _g1h(g1h), - _mark_bitmap(bitmap), - _actual_region_bm(region_bm), - _actual_card_bm(card_bm), - _expected_region_bm(region_bm->size(), true /* in_resource_area */), - _expected_card_bm(card_bm->size(), true /* in_resource_area */), - _failures(0), - _hr_claimer(n_workers) { - assert(VerifyDuringGC, "don't call this otherwise"); - } - - void work(uint worker_id) { - G1VerifyLiveDataHRClosure cl(_g1h, - _mark_bitmap, - _actual_region_bm, - _actual_card_bm, - &_expected_region_bm, - &_expected_card_bm); - _g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); - - Atomic::add(cl.failures(), &_failures); - } - - int failures() const { return _failures; } -}; - -class G1FinalizeLiveDataTask: public AbstractGangTask { - // Finalizes the liveness counting data. - // Sets the bits corresponding to the interval [NTAMS, top] - // (which contains the implicitly live objects) in the - // card liveness bitmap. Also sets the bit for each region - // containing live data, in the region liveness bitmap. - class G1FinalizeCountDataClosure: public HeapRegionClosure { - private: - G1LiveDataHelper _helper; - public: - G1FinalizeCountDataClosure(G1CMBitMap* bitmap, - BitMap* region_bm, - BitMap* card_bm) : - HeapRegionClosure(), - _helper(region_bm, card_bm) { } - - bool doHeapRegion(HeapRegion* hr) { - bool allocated_since_marking = _helper.mark_allocated_since_marking(hr); - if (allocated_since_marking || hr->next_marked_bytes() > 0) { - _helper.set_bit_for_region(hr); - } - return false; - } - }; - - G1CMBitMap* _bitmap; - - BitMap* _actual_region_bm; - BitMap* _actual_card_bm; - - HeapRegionClaimer _hr_claimer; - -public: - G1FinalizeLiveDataTask(G1CMBitMap* bitmap, BitMap* region_bm, BitMap* card_bm, uint n_workers) : - AbstractGangTask("G1 final counting"), - _bitmap(bitmap), - _actual_region_bm(region_bm), - _actual_card_bm(card_bm), - _hr_claimer(n_workers) { - } - - void work(uint worker_id) { - G1FinalizeCountDataClosure cl(_bitmap, - _actual_region_bm, - _actual_card_bm); - - G1CollectedHeap::heap()->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); - } -}; - class G1NoteEndOfConcMarkClosure : public HeapRegionClosure { G1CollectedHeap* _g1; size_t _freed_bytes; @@ -1613,26 +1248,13 @@ void G1ConcurrentMark::cleanup() { HeapRegionRemSet::reset_for_cleanup_tasks(); { - // Finalize the live data. - G1FinalizeLiveDataTask cl(_nextMarkBitMap, - &_region_live_bm, - &_card_live_bm, - g1h->workers()->active_workers()); - g1h->workers()->run_task(&cl); + GCTraceTime(Debug, gc)("Finalize Live Data"); + finalize_live_data(); } if (VerifyDuringGC) { - // Verify that the liveness count data created concurrently matches one created - // during this safepoint. - ResourceMark rm; - G1VerifyLiveDataTask cl(G1CollectedHeap::heap(), - _nextMarkBitMap, - &_region_live_bm, - &_card_live_bm, - g1h->workers()->active_workers()); - g1h->workers()->run_task(&cl); - - guarantee(cl.failures() == 0, "Unexpected accounting failures"); + GCTraceTime(Debug, gc)("Verify Live Data"); + verify_live_data(); } g1h->collector_state()->set_mark_in_progress(false); @@ -1669,7 +1291,7 @@ void G1ConcurrentMark::cleanup() { // regions. if (G1ScrubRemSets) { double rs_scrub_start = os::elapsedTime(); - g1h->scrub_rem_set(&_region_live_bm, &_card_live_bm); + g1h->scrub_rem_set(); _total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start); } @@ -2115,35 +1737,6 @@ void G1ConcurrentMark::swapMarkBitMaps() { _nextMarkBitMap = (G1CMBitMap*) temp; } -BitMap G1ConcurrentMark::allocate_large_bitmap(BitMap::idx_t size_in_bits) { - size_t size_in_words = BitMap::size_in_words(size_in_bits); - - BitMap::bm_word_t* map = MmapArrayAllocator::allocate(size_in_words); - - return BitMap(map, size_in_bits); -} - -void G1ConcurrentMark::allocate_internal_bitmaps() { - double start_time = os::elapsedTime(); - - _region_live_bm = allocate_large_bitmap(_g1h->max_regions()); - - guarantee(_g1h->max_capacity() % CardTableModRefBS::card_size == 0, - "Heap capacity must be aligned to card size."); - _card_live_bm = allocate_large_bitmap(_g1h->max_capacity() / CardTableModRefBS::card_size); - - log_debug(gc, marking)("Allocating internal bitmaps took %1.2f seconds.", os::elapsedTime() - start_time); -} - -void G1ConcurrentMark::pretouch_internal_bitmaps() { - double start_time = os::elapsedTime(); - - _region_live_bm.pretouch(); - _card_live_bm.pretouch(); - - log_debug(gc, marking)("Pre-touching internal bitmaps took %1.2f seconds.", os::elapsedTime() - start_time); -} - // Closure for marking entries in SATB buffers. class G1CMSATBBufferClosure : public SATBBufferClosure { private: @@ -2403,120 +1996,28 @@ void G1ConcurrentMark::verify_no_cset_oops() { } } #endif // PRODUCT - -class G1CreateLiveDataTask: public AbstractGangTask { - // Aggregate the counting data that was constructed concurrently - // with marking. - class G1CreateLiveDataHRClosure: public HeapRegionClosure { - G1LiveDataHelper _helper; - - G1CMBitMap* _mark_bitmap; - - G1ConcurrentMark* _cm; - public: - G1CreateLiveDataHRClosure(G1ConcurrentMark* cm, - G1CMBitMap* mark_bitmap, - BitMap* cm_card_bm) : - HeapRegionClosure(), - _helper(NULL, cm_card_bm), - _mark_bitmap(mark_bitmap), - _cm(cm) { } - - bool doHeapRegion(HeapRegion* hr) { - size_t marked_bytes = _helper.mark_marked_during_marking(_mark_bitmap, hr); - if (marked_bytes > 0) { - hr->add_to_marked_bytes(marked_bytes); - } - - if (_cm->do_yield_check() && _cm->has_aborted()) { - return true; - } - return false; - } - }; - - G1CollectedHeap* _g1h; - G1ConcurrentMark* _cm; - BitMap* _cm_card_bm; - HeapRegionClaimer _hr_claimer; - -public: - G1CreateLiveDataTask(G1CollectedHeap* g1h, - BitMap* cm_card_bm, - uint n_workers) : - AbstractGangTask("Create Live Data"), - _g1h(g1h), - _cm_card_bm(cm_card_bm), - _hr_claimer(n_workers) { - } - - void work(uint worker_id) { - SuspendibleThreadSetJoiner sts_join; - - G1CreateLiveDataHRClosure cl(_g1h->concurrent_mark(), _g1h->concurrent_mark()->nextMarkBitMap(), _cm_card_bm); - _g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); - } -}; - - void G1ConcurrentMark::create_live_data() { - uint n_workers = _parallel_workers->active_workers(); - - G1CreateLiveDataTask cl(_g1h, - &_card_live_bm, - n_workers); - _parallel_workers->run_task(&cl); + _g1h->g1_rem_set()->create_card_live_data(_parallel_workers, _nextMarkBitMap); } -class G1ClearAllLiveDataTask : public AbstractGangTask { - BitMap* _bitmap; - size_t _num_tasks; - size_t _cur_task; -public: - G1ClearAllLiveDataTask(BitMap* bitmap, size_t num_tasks) : - AbstractGangTask("Clear All Live Data"), - _bitmap(bitmap), - _num_tasks(num_tasks), - _cur_task(0) { - } - - virtual void work(uint worker_id) { - while (true) { - size_t to_process = Atomic::add(1, &_cur_task) - 1; - if (to_process >= _num_tasks) { - break; - } - - BitMap::idx_t start = M * BitsPerByte * to_process; - BitMap::idx_t end = MIN2(start + M * BitsPerByte, _bitmap->size()); - _bitmap->clear_range(start, end); - } - } -}; - -void G1ConcurrentMark::clear_all_live_data(WorkGang* workers) { - double start_time = os::elapsedTime(); - - guarantee(Universe::is_fully_initialized(), "Should not call this during initialization."); - - size_t const num_chunks = align_size_up(_card_live_bm.size_in_words() * HeapWordSize, M) / M; - - G1ClearAllLiveDataTask cl(&_card_live_bm, num_chunks); - workers->run_task(&cl); - - // The region live bitmap is always very small, even for huge heaps. Clear - // directly. - _region_live_bm.clear(); - - - log_debug(gc, marking)("Clear Live Data took %.3fms", (os::elapsedTime() - start_time) * 1000.0); +void G1ConcurrentMark::finalize_live_data() { + _g1h->g1_rem_set()->finalize_card_live_data(_g1h->workers(), _nextMarkBitMap); } -void G1ConcurrentMark::verify_all_live_data() { - assert(_card_live_bm.count_one_bits() == 0, "Master card bitmap not clear"); - assert(_region_live_bm.count_one_bits() == 0, "Master region bitmap not clear"); +void G1ConcurrentMark::verify_live_data() { + _g1h->g1_rem_set()->verify_card_live_data(_g1h->workers(), _nextMarkBitMap); } +void G1ConcurrentMark::clear_live_data(WorkGang* workers) { + _g1h->g1_rem_set()->clear_card_live_data(workers); +} + +#ifdef ASSERT +void G1ConcurrentMark::verify_live_data_clear() { + _g1h->g1_rem_set()->verify_card_live_data_is_clear(); +} +#endif + void G1ConcurrentMark::print_stats() { if (!log_is_enabled(Debug, gc, stats)) { return; @@ -2536,14 +2037,22 @@ void G1ConcurrentMark::abort() { // Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next // concurrent bitmap clearing. - clear_bitmap(_nextMarkBitMap, _g1h->workers(), false); - + { + GCTraceTime(Debug, gc)("Clear Next Bitmap"); + clear_bitmap(_nextMarkBitMap, _g1h->workers(), false); + } // Note we cannot clear the previous marking bitmap here // since VerifyDuringGC verifies the objects marked during // a full GC against the previous bitmap. - clear_all_live_data(_g1h->workers()); - DEBUG_ONLY(verify_all_live_data()); + { + GCTraceTime(Debug, gc)("Clear Live Data"); + clear_live_data(_g1h->workers()); + } + DEBUG_ONLY({ + GCTraceTime(Debug, gc)("Verify Live Data Clear"); + verify_live_data_clear(); + }) // Empty mark stack reset_marking_state(); for (uint i = 0; i < _max_worker_id; ++i) { @@ -2610,16 +2119,6 @@ void G1ConcurrentMark::print_on_error(outputStream* st) const { _nextMarkBitMap->print_on_error(st, " Next Bits: "); } -// We take a break if someone is trying to stop the world. -bool G1ConcurrentMark::do_yield_check(uint worker_id) { - if (SuspendibleThreadSet::should_yield()) { - SuspendibleThreadSet::yield(); - return true; - } else { - return false; - } -} - // Closure for iteration over bitmaps class G1CMBitMapClosure : public BitMapClosure { private: diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp index fb621e34980..36fb602de82 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp @@ -298,15 +298,6 @@ protected: G1CMBitMapRO* _prevMarkBitMap; // Completed mark bitmap G1CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap - // Liveness count data. After marking G1 iterates over the recently gathered mark - // bitmap and records rough information about liveness on card and region basis. - // This information can be used for e.g. remembered set scrubbing. - - // A set bit indicates whether the given region contains any live object. - BitMap _region_live_bm; - // A set bit indicates that the given card contains a live object. - BitMap _card_live_bm; - // Heap bounds HeapWord* _heap_start; HeapWord* _heap_end; @@ -379,14 +370,6 @@ protected: void swapMarkBitMaps(); - // Allocates and returns a zero-ed out "large" bitmap of the given size in bits. - // It is always allocated using virtual memory. - BitMap allocate_large_bitmap(BitMap::idx_t size_in_bits); - // Allocates the memory for all bitmaps used by the concurrent marking. - void allocate_internal_bitmaps(); - // Pre-touches the internal bitmaps. - void pretouch_internal_bitmaps(); - // It resets the global marking data structures, as well as the // task local ones; should be called during initial mark. void reset(); @@ -592,7 +575,7 @@ public: void scan_root_regions(); // Scan a single root region and mark everything reachable from it. - void scanRootRegion(HeapRegion* hr, uint worker_id); + void scanRootRegion(HeapRegion* hr); // Do concurrent phase of marking, to a tentative transitive closure. void mark_from_roots(); @@ -628,7 +611,7 @@ public: inline bool isPrevMarked(oop p) const; - inline bool do_yield_check(uint worker_i = 0); + inline bool do_yield_check(); // Abandon current marking iteration due to a Full GC. void abort(); @@ -654,16 +637,19 @@ public: private: // Clear (Reset) all liveness count data. - void clear_all_live_data(WorkGang* workers); + void clear_live_data(WorkGang* workers); +#ifdef ASSERT // Verify all of the above data structures that they are in initial state. - void verify_all_live_data(); + void verify_live_data_clear(); +#endif // Aggregates the per-card liveness data based on the current marking. Also sets // the amount of marked bytes for each region. void create_live_data(); - // Verification routine + void finalize_live_data(); + void verify_live_data(); }; @@ -852,7 +838,7 @@ public: // Grey the object by marking it. If not already marked, push it on // the local queue if below the finger. - // Precondition: obj is below region's NTAMS. + // obj is below its region's NTAMS. inline void make_reference_grey(oop obj); // Grey the object (by calling make_grey_reference) if required, diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp index 053de4b9673..b0401d35935 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp @@ -27,6 +27,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.hpp" +#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/shared/taskqueue.inline.hpp" inline bool G1ConcurrentMark::par_mark(oop obj) { @@ -258,4 +259,13 @@ inline void G1ConcurrentMark::grayRoot(oop obj, HeapRegion* hr) { } } +inline bool G1ConcurrentMark::do_yield_check() { + if (SuspendibleThreadSet::should_yield()) { + SuspendibleThreadSet::yield(); + return true; + } else { + return false; + } +} + #endif // SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp index 05f90f75f4e..5de38f71bd2 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp @@ -186,11 +186,9 @@ class G1RootRegionScanClosure : public MetadataAwareOopClosure { private: G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; - uint _worker_id; public: - G1RootRegionScanClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm, - uint worker_id) : - _g1h(g1h), _cm(cm), _worker_id(worker_id) { } + G1RootRegionScanClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm) : + _g1h(g1h), _cm(cm) { } template void do_oop_nv(T* p); virtual void do_oop( oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index eb091443887..12ed0506d94 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -38,6 +38,7 @@ #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" @@ -84,8 +85,16 @@ uint G1RemSet::num_par_rem_sets() { return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); } -void G1RemSet::initialize(uint max_regions) { +void G1RemSet::initialize(size_t capacity, uint max_regions) { G1FromCardCache::initialize(num_par_rem_sets(), max_regions); + { + GCTraceTime(Debug, gc, marking)("Initialize Card Live Data"); + _card_live_data.initialize(capacity, max_regions); + } + if (G1PretouchAuxiliaryMemory) { + GCTraceTime(Debug, gc, marking)("Pre-Touch Card Live Data"); + _card_live_data.pretouch(); + } } ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc, @@ -312,27 +321,24 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { _into_cset_dirty_card_queue_set.clear_n_completed_buffers(); } -class ScrubRSClosure: public HeapRegionClosure { +class G1ScrubRSClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; - BitMap* _region_bm; - BitMap* _card_bm; - CardTableModRefBS* _ctbs; + G1CardLiveData* _live_data; public: - ScrubRSClosure(BitMap* region_bm, BitMap* card_bm) : + G1ScrubRSClosure(G1CardLiveData* live_data) : _g1h(G1CollectedHeap::heap()), - _region_bm(region_bm), _card_bm(card_bm), - _ctbs(_g1h->g1_barrier_set()) {} + _live_data(live_data) { } bool doHeapRegion(HeapRegion* r) { if (!r->is_continues_humongous()) { - r->rem_set()->scrub(_ctbs, _region_bm, _card_bm); + r->rem_set()->scrub(_live_data); } return false; } }; -void G1RemSet::scrub(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer *hrclaimer) { - ScrubRSClosure scrub_cl(region_bm, card_bm); +void G1RemSet::scrub(uint worker_num, HeapRegionClaimer *hrclaimer) { + G1ScrubRSClosure scrub_cl(&_card_live_data); _g1->heap_region_par_iterate(&scrub_cl, worker_num, hrclaimer); } @@ -580,3 +586,25 @@ void G1RemSet::prepare_for_verify() { assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); } } + +void G1RemSet::create_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap) { + _card_live_data.create(workers, mark_bitmap); +} + +void G1RemSet::finalize_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap) { + _card_live_data.finalize(workers, mark_bitmap); +} + +void G1RemSet::verify_card_live_data(WorkGang* workers, G1CMBitMap* bitmap) { + _card_live_data.verify(workers, bitmap); +} + +void G1RemSet::clear_card_live_data(WorkGang* workers) { + _card_live_data.clear(workers); +} + +#ifdef ASSERT +void G1RemSet::verify_card_live_data_is_clear() { + _card_live_data.verify_is_clear(); +} +#endif diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp index 8aab4ca498c..381d5fd8f72 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_G1REMSET_HPP #include "gc/g1/dirtyCardQueue.hpp" +#include "gc/g1/g1CardLiveData.hpp" #include "gc/g1/g1RemSetSummary.hpp" #include "gc/g1/heapRegion.hpp" #include "memory/allocation.hpp" @@ -48,9 +49,10 @@ class HeapRegionClaimer; // A G1RemSet in which each heap region has a rem set that records the // external heap references into it. Uses a mod ref bs to track updates, // so that they can be used to update the individual region remsets. - class G1RemSet: public CHeapObj { private: + G1CardLiveData _card_live_data; + G1RemSetSummary _prev_period_summary; // A DirtyCardQueueSet that is used to hold cards that contain @@ -83,7 +85,7 @@ public: static uint num_par_rem_sets(); // Initialize data that depends on the heap size being known. - static void initialize(uint max_regions); + void initialize(size_t capacity, uint max_regions); // This is called to reset dual hash tables after the gc pause // is finished and the initial hash table is no longer being @@ -140,7 +142,7 @@ public: // set entries that correspond to dead heap ranges. "worker_num" is the // parallel thread id of the current thread, and "hrclaimer" is the // HeapRegionClaimer that should be used. - void scrub(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer* hrclaimer); + void scrub(uint worker_num, HeapRegionClaimer* hrclaimer); // Refine the card corresponding to "card_ptr". // If check_for_refs_into_cset is true, a true result is returned @@ -162,6 +164,19 @@ public: size_t conc_refine_cards() const { return _conc_refine_cards; } + + void create_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap); + void finalize_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap); + + // Verify that the liveness count data created concurrently matches one created + // during this safepoint. + void verify_card_live_data(WorkGang* workers, G1CMBitMap* actual_bitmap); + + void clear_card_live_data(WorkGang* workers); + +#ifdef ASSERT + void verify_card_live_data_is_clear(); +#endif }; class ScanRSClosure : public HeapRegionClosure { diff --git a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp index 26d5ce3e7e0..4fee9c4ecfc 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp @@ -26,6 +26,7 @@ #include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/g1BlockOffsetTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CardLiveData.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/space.inline.hpp" @@ -141,10 +142,8 @@ public: add_reference_work(from, /*parallel*/ false); } - void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) { - HeapWord* hr_bot = hr()->bottom(); - size_t hr_first_card_index = ctbs->index_for(hr_bot); - bm()->set_intersection_at_offset(*card_bm, hr_first_card_index); + void scrub(G1CardLiveData* live_data) { + live_data->remove_nonlive_cards(hr()->hrm_index(), &_bm); recount_occupied(); } @@ -515,14 +514,12 @@ PerRegionTable* OtherRegionsTable::delete_region_table() { return max; } -void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, - BitMap* region_bm, BitMap* card_bm) { +void OtherRegionsTable::scrub(G1CardLiveData* live_data) { // First eliminated garbage regions from the coarse map. log_develop_trace(gc, remset, scrub)("Scrubbing region %u:", _hr->hrm_index()); - assert(_coarse_map.size() == region_bm->size(), "Precondition"); log_develop_trace(gc, remset, scrub)(" Coarse map: before = " SIZE_FORMAT "...", _n_coarse_entries); - _coarse_map.set_intersection(*region_bm); + live_data->remove_nonlive_regions(&_coarse_map); _n_coarse_entries = _coarse_map.count_one_bits(); log_develop_trace(gc, remset, scrub)(" after = " SIZE_FORMAT ".", _n_coarse_entries); @@ -534,7 +531,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, PerRegionTable* nxt = cur->collision_list_next(); // If the entire region is dead, eliminate. log_develop_trace(gc, remset, scrub)(" For other region %u:", cur->hr()->hrm_index()); - if (!region_bm->at((size_t) cur->hr()->hrm_index())) { + if (!live_data->is_region_live(cur->hr()->hrm_index())) { *prev = nxt; cur->set_collision_list_next(NULL); _n_fine_entries--; @@ -544,7 +541,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, } else { // Do fine-grain elimination. log_develop_trace(gc, remset, scrub)(" occ: before = %4d.", cur->occupied()); - cur->scrub(ctbs, card_bm); + cur->scrub(live_data); log_develop_trace(gc, remset, scrub)(" after = %4d.", cur->occupied()); // Did that empty the table completely? if (cur->occupied() == 0) { @@ -773,9 +770,8 @@ void HeapRegionRemSet::reset_for_par_iteration() { assert(verify_ready_for_par_iteration(), "post-condition"); } -void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, - BitMap* region_bm, BitMap* card_bm) { - _other_regions.scrub(ctbs, region_bm, card_bm); +void HeapRegionRemSet::scrub(G1CardLiveData* live_data) { + _other_regions.scrub(live_data); } // Code roots support diff --git a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp index 5a286bc2836..c884dab2484 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.hpp @@ -35,6 +35,7 @@ class G1CollectedHeap; class G1BlockOffsetTable; +class G1CardLiveData; class HeapRegion; class HeapRegionRemSetIterator; class PerRegionTable; @@ -143,7 +144,7 @@ public: // Removes any entries shown by the given bitmaps to contain only dead // objects. Not thread safe. // Set bits in the bitmaps indicate that the given region or card is live. - void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); + void scrub(G1CardLiveData* live_data); // Returns whether this remembered set (and all sub-sets) does not contain any entry. bool is_empty() const; @@ -230,10 +231,9 @@ public: _other_regions.add_reference(from, tid); } - // Removes any entries in the remembered set shown by the given bitmaps to + // Removes any entries in the remembered set shown by the given card live data to // contain only dead objects. Not thread safe. - // One bits in the bitmaps indicate that the given region or card is live. - void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); + void scrub(G1CardLiveData* live_data); // The region is being reclaimed; clear its remset, and any mention of // entries for this region in other remsets. diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp index 7804c988487..bb7ae8ede14 100644 --- a/hotspot/src/share/vm/utilities/bitMap.cpp +++ b/hotspot/src/share/vm/utilities/bitMap.cpp @@ -69,7 +69,7 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { } void BitMap::pretouch() { - os::pretouch_memory((char*)word_addr(0), (char*)word_addr(size())); + os::pretouch_memory(word_addr(0), word_addr(size())); } void BitMap::set_range_within_word(idx_t beg, idx_t end) { diff --git a/hotspot/src/share/vm/utilities/bitMap.hpp b/hotspot/src/share/vm/utilities/bitMap.hpp index 0e46cea9917..b925d66442f 100644 --- a/hotspot/src/share/vm/utilities/bitMap.hpp +++ b/hotspot/src/share/vm/utilities/bitMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -140,11 +140,12 @@ class BitMap VALUE_OBJ_CLASS_SPEC { // Accessing idx_t size() const { return _size; } + idx_t size_in_bytes() const { return size_in_words() * BytesPerWord; } idx_t size_in_words() const { - return word_index(size() + BitsPerWord - 1); + return calc_size_in_words(size()); } - static idx_t size_in_words(size_t size_in_bits) { + static idx_t calc_size_in_words(size_t size_in_bits) { return word_index(size_in_bits + BitsPerWord - 1); } From af3081628b5fbb42ed672b4a035fab3f66e109c3 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Wed, 6 Apr 2016 20:43:03 +0900 Subject: [PATCH 06/24] 8152435: (CL)HSDB should be started with no argument Reviewed-by: dsamersoff --- .../classes/sun/jvm/hotspot/SAGetopt.java | 12 +++--- .../sun/jvm/hotspot/SAGetoptException.java | 33 ++++++++++++++++ .../classes/sun/jvm/hotspot/SALauncher.java | 39 +++++++++---------- 3 files changed, 57 insertions(+), 27 deletions(-) create mode 100644 hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetoptException.java diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java index 3d4ffb0171b..d23a057f584 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java @@ -55,11 +55,11 @@ public class SAGetopt { private void extractOptarg(String opt) { // Argument expected if (_optind > _argv.length) { - throw new RuntimeException("Not enough arguments for '" + opt + "'"); + throw new SAGetoptException("Not enough arguments for '" + opt + "'"); } if (! _argv[_optind].isEmpty() && _argv[_optind].charAt(0) == '-') { - throw new RuntimeException("Argument is expected for '" + opt + "'"); + throw new SAGetoptException("Argument is expected for '" + opt + "'"); } _optarg = _argv[_optind]; @@ -72,7 +72,7 @@ public class SAGetopt { if (los.contains(ca[0])) { if (ca.length > 1) { - throw new RuntimeException("Argument is not expected for '" + ca[0] + "'"); + throw new SAGetoptException("Argument is not expected for '" + ca[0] + "'"); } return carg; } @@ -87,14 +87,14 @@ public class SAGetopt { try { extractOptarg(ca[0]); } catch (ArrayIndexOutOfBoundsException e) { - throw new RuntimeException("Argument is expected for '" + ca[0] + "'"); + throw new SAGetoptException("Argument is expected for '" + ca[0] + "'"); } } return ca[0]; } - throw new RuntimeException("Invalid option '" + ca[0] + "'"); + throw new SAGetoptException("Invalid option '" + ca[0] + "'"); } public String next(String optStr, String[] longOptStr) { @@ -148,7 +148,7 @@ public class SAGetopt { int chIndex = optStr.indexOf(ch); if (chIndex == -1) { - throw new RuntimeException("Invalid option '" + ch + "'"); + throw new SAGetoptException("Invalid option '" + ch + "'"); } if (_optopt >= carg.length()) { diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetoptException.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetoptException.java new file mode 100644 index 00000000000..f6ba480ca33 --- /dev/null +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetoptException.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot; + +public class SAGetoptException extends IllegalArgumentException { + + public SAGetoptException(String message) { + super(message); + } + +} diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java index 4b1f280a6d7..dfbbb6ff440 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java @@ -111,34 +111,31 @@ public class SALauncher { return launcherHelp(); } - private static void buildAttachArgs(ArrayList newArgs, - String pid, String exe, String core) { - if ((pid == null) && (exe == null)) { - throw new IllegalArgumentException( - "You have to set --pid or --exe."); + private static void buildAttachArgs(ArrayList newArgs, String pid, + String exe, String core, boolean allowEmpty) { + if (!allowEmpty && (pid == null) && (exe == null)) { + throw new SAGetoptException("You have to set --pid or --exe."); } if (pid != null) { // Attach to live process if (exe != null) { - throw new IllegalArgumentException( - "Unnecessary argument: --exe"); + throw new SAGetoptException("Unnecessary argument: --exe"); } else if (core != null) { - throw new IllegalArgumentException( - "Unnecessary argument: --core"); + throw new SAGetoptException("Unnecessary argument: --core"); } else if (!pid.matches("^\\d+$")) { - throw new IllegalArgumentException("Invalid pid: " + pid); + throw new SAGetoptException("Invalid pid: " + pid); } newArgs.add(pid); - } else { + } else if (exe != null) { if (exe.length() == 0) { - throw new IllegalArgumentException("You have to set --exe."); + throw new SAGetoptException("You have to set --exe."); } newArgs.add(exe); if ((core == null) || (core.length() == 0)) { - throw new IllegalArgumentException("You have to set --core."); + throw new SAGetoptException("You have to set --core."); } newArgs.add(core); @@ -170,7 +167,7 @@ public class SALauncher { } } - buildAttachArgs(newArgs, pid, exe, core); + buildAttachArgs(newArgs, pid, exe, core, true); CLHSDB.main(newArgs.toArray(new String[newArgs.size()])); } @@ -199,7 +196,7 @@ public class SALauncher { } } - buildAttachArgs(newArgs, pid, exe, core); + buildAttachArgs(newArgs, pid, exe, core, true); HSDB.main(newArgs.toArray(new String[newArgs.size()])); } @@ -237,7 +234,7 @@ public class SALauncher { } } - buildAttachArgs(newArgs, pid, exe, core); + buildAttachArgs(newArgs, pid, exe, core, false); JStack.main(newArgs.toArray(new String[newArgs.size()])); } @@ -287,7 +284,7 @@ public class SALauncher { } } - buildAttachArgs(newArgs, pid, exe, core); + buildAttachArgs(newArgs, pid, exe, core, false); JMap.main(newArgs.toArray(new String[newArgs.size()])); } @@ -325,7 +322,7 @@ public class SALauncher { } } - buildAttachArgs(newArgs, pid, exe, core); + buildAttachArgs(newArgs, pid, exe, core, false); JInfo.main(newArgs.toArray(new String[newArgs.size()])); } @@ -358,7 +355,7 @@ public class SALauncher { } } - buildAttachArgs(newArgs, pid, exe, core); + buildAttachArgs(newArgs, pid, exe, core, false); JSnap.main(newArgs.toArray(new String[newArgs.size()])); } @@ -416,8 +413,8 @@ public class SALauncher { return; } - throw new IllegalArgumentException("Unknown tool: " + args[0]); - } catch (Exception e) { + throw new SAGetoptException("Unknown tool: " + args[0]); + } catch (SAGetoptException e) { System.err.println(e.getMessage()); toolHelp(args[0]); } From c282f259646f0648c1dabe0252de7572cd78e3ba Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Wed, 6 Apr 2016 11:40:45 -0700 Subject: [PATCH 07/24] 8152329: jvm should treat the "Multi-Release" jar manifest attribute name as case insensitive Reviewed-by: iklam, jiangli, mseledtsov --- hotspot/src/share/vm/classfile/classLoader.cpp | 12 ++++++++++-- hotspot/src/share/vm/classfile/classLoader.hpp | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index bdf18bc55e0..a8a86765970 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -233,6 +233,7 @@ ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_ strcpy(copy, zip_name); _zip_name = copy; _is_boot_append = is_boot_append; + _multi_versioned = _unknown; } ClassPathZipEntry::~ClassPathZipEntry() { @@ -330,13 +331,20 @@ u1* ClassPathZipEntry::open_versioned_entry(const char* name, jint* filesize, TR bool ClassPathZipEntry::is_multiple_versioned(TRAPS) { assert(DumpSharedSpaces, "called only at dump time"); + if (_multi_versioned != _unknown) { + return (_multi_versioned == _yes) ? true : false; + } jint size; - char* buffer = (char*)open_entry("META-INF/MANIFEST.MF", &size, false, CHECK_false); + char* buffer = (char*)open_entry("META-INF/MANIFEST.MF", &size, true, CHECK_false); if (buffer != NULL) { - if (strstr(buffer, "Multi-Release: true") != NULL) { + char* p = buffer; + for ( ; *p; ++p) *p = tolower(*p); + if (strstr(buffer, "multi-release: true") != NULL) { + _multi_versioned = _yes; return true; } } + _multi_versioned = _no; return false; } #endif // INCLUDE_CDS diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 8ac282727d5..fc1d335b7ab 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -101,10 +101,17 @@ typedef struct { class ClassPathZipEntry: public ClassPathEntry { + enum { + _unknown = 0, + _yes = 1, + _no = 2 + }; private: jzfile* _zip; // The zip archive const char* _zip_name; // Name of zip archive bool _is_boot_append; // entry coming from -Xbootclasspath/a + u1 _multi_versioned; // indicates if the jar file has multi-versioned entries. + // It can have value of "_unknown", "_yes", or "_no" public: bool is_jrt() { return false; } bool is_jar_file() const { return true; } From f22c068365fdb645e21786cd190874021f89b4b5 Mon Sep 17 00:00:00 2001 From: Antonios Printezis Date: Thu, 7 Apr 2016 10:55:54 +0200 Subject: [PATCH 08/24] 8152312: ParNew: Restore preserved marks in parallel Reviewed-by: tschatzl --- .../share/vm/gc/serial/defNewGeneration.cpp | 5 +- .../src/share/vm/gc/shared/preservedMarks.cpp | 75 ++++++++++++++----- .../src/share/vm/gc/shared/preservedMarks.hpp | 37 +++++++-- .../vm/gc/shared/preservedMarks.inline.hpp | 52 ++++++++++++- 4 files changed, 137 insertions(+), 32 deletions(-) diff --git a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp index a9b404604b0..247c7e3e49a 100644 --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp @@ -692,7 +692,7 @@ void DefNewGeneration::collect(bool full, _promo_failure_scan_stack.clear(true); // Clear cached segments. remove_forwarding_pointers(); - log_debug(gc)("Promotion failed"); + log_info(gc, promotion)("Promotion failed"); // Add to-space to the list of space to compact // when a promotion failure has occurred. In that // case there can be live objects in to-space @@ -739,8 +739,7 @@ void DefNewGeneration::remove_forwarding_pointers() { eden()->object_iterate(&rspc); from()->object_iterate(&rspc); - // Now restore saved marks, if any. - _preserved_marks_set.restore(); + _preserved_marks_set.restore(GenCollectedHeap::heap()->workers()); } void DefNewGeneration::handle_promotion_failure(oop old) { diff --git a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp index e6950ff78b6..96d124e2259 100644 --- a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp +++ b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp @@ -24,24 +24,30 @@ #include "precompiled.hpp" #include "gc/shared/preservedMarks.inline.hpp" +#include "gc/shared/workgroup.hpp" #include "memory/allocation.inline.hpp" -#include "oops/oop.inline.hpp" void PreservedMarks::restore() { - // First, iterate over the stack and restore all marks. - StackIterator iter(_stack); - while (!iter.is_empty()) { - OopAndMarkOop elem = iter.next(); + while (!_stack.is_empty()) { + const OopAndMarkOop elem = _stack.pop(); elem.set_mark(); } - - // Second, reclaim all the stack memory - _stack.clear(true /* clear_cache */); + assert_empty(); } +#ifndef PRODUCT +void PreservedMarks::assert_empty() { + assert(_stack.is_empty(), "stack expected to be empty, size = "SIZE_FORMAT, + _stack.size()); + assert(_stack.cache_size() == 0, + "stack expected to have no cached segments, cache size = "SIZE_FORMAT, + _stack.cache_size()); +} +#endif // ndef PRODUCT + void RemoveForwardedPointerClosure::do_object(oop obj) { if (obj->is_forwarded()) { - obj->init_mark(); + PreservedMarks::init_forwarded_mark(obj); } } @@ -61,15 +67,48 @@ void PreservedMarksSet::init(uint num) { assert_empty(); } -void PreservedMarksSet::restore() { - size_t total_size = 0; - for (uint i = 0; i < _num; i += 1) { - total_size += get(i)->size(); - get(i)->restore(); - } - assert_empty(); +class ParRestoreTask : public AbstractGangTask { +private: + PreservedMarksSet* const _preserved_marks_set; + SequentialSubTasksDone _sub_tasks; + volatile size_t* const _total_size_addr; - log_trace(gc)("Restored " SIZE_FORMAT " marks", total_size); +public: + virtual void work(uint worker_id) { + uint task_id = 0; + while (!_sub_tasks.is_task_claimed(/* reference */ task_id)) { + PreservedMarks* const preserved_marks = _preserved_marks_set->get(task_id); + const size_t size = preserved_marks->size(); + preserved_marks->restore(); + // Only do the atomic add if the size is > 0. + if (size > 0) { + Atomic::add(size, _total_size_addr); + } + } + _sub_tasks.all_tasks_completed(); + } + + ParRestoreTask(uint worker_num, + PreservedMarksSet* preserved_marks_set, + volatile size_t* total_size_addr) + : AbstractGangTask("Parallel Preserved Mark Restoration"), + _preserved_marks_set(preserved_marks_set), + _total_size_addr(total_size_addr) { + _sub_tasks.set_n_threads(worker_num); + _sub_tasks.set_n_tasks(preserved_marks_set->num()); + } +}; + +void PreservedMarksSet::restore_internal(WorkGang* workers, + volatile size_t* total_size_addr) { + assert(workers != NULL, "pre-condition"); + ParRestoreTask task(workers->active_workers(), this, total_size_addr); + workers->run_task(&task); +} + +// temporary, used by PS +void PreservedMarksSet::restore() { + restore(NULL); } void PreservedMarksSet::reclaim() { @@ -92,7 +131,7 @@ void PreservedMarksSet::reclaim() { void PreservedMarksSet::assert_empty() { assert(_stacks != NULL && _num > 0, "should have been initialized"); for (uint i = 0; i < _num; i += 1) { - assert(get(i)->is_empty(), "stack should be empty"); + get(i)->assert_empty(); } } #endif // ndef PRODUCT diff --git a/hotspot/src/share/vm/gc/shared/preservedMarks.hpp b/hotspot/src/share/vm/gc/shared/preservedMarks.hpp index 729f0666b17..6ab52ba0fb4 100644 --- a/hotspot/src/share/vm/gc/shared/preservedMarks.hpp +++ b/hotspot/src/share/vm/gc/shared/preservedMarks.hpp @@ -44,6 +44,8 @@ public: }; typedef Stack OopAndMarkOopStack; +class WorkGang; + class PreservedMarks VALUE_OBJ_CLASS_SPEC { private: OopAndMarkOopStack _stack; @@ -52,13 +54,19 @@ private: inline void push(oop obj, markOop m); public: - bool is_empty() const { return _stack.is_empty(); } size_t size() const { return _stack.size(); } inline void push_if_necessary(oop obj, markOop m); - // Iterate over the stack, restore the preserved marks, then reclaim - // the memory taken up by stack chunks. + // Iterate over the stack, restore all preserved marks, and + // reclaim the memory taken up by the stack segments. void restore(); - ~PreservedMarks() { assert(is_empty(), "should have been cleared"); } + + inline static void init_forwarded_mark(oop obj); + + // Assert the stack is empty and has no cached segments. + void assert_empty() PRODUCT_RETURN; + + inline PreservedMarks(); + ~PreservedMarks() { assert_empty(); } }; class RemoveForwardedPointerClosure: public ObjectClosure { @@ -82,7 +90,12 @@ private: // or == NULL if they have not. Padded* _stacks; + // Internal version of restore() that uses a WorkGang for parallelism. + void restore_internal(WorkGang* workers, volatile size_t* total_size_addr); + public: + uint num() const { return _num; } + // Return the i'th stack. PreservedMarks* get(uint i = 0) const { assert(_num > 0 && _stacks != NULL, "stacks should have been initialized"); @@ -92,13 +105,23 @@ public: // Allocate stack array. void init(uint num); - // Iterate over all stacks, restore all preserved marks, then - // reclaim the memory taken up by stack chunks. + + // Itrerate over all stacks, restore all presered marks, and reclaim + // the memory taken up by the stack segments. If the executor is + // NULL, restoration will be done serially. If the executor is not + // NULL, restoration could be done in parallel (when it makes + // sense). Supported executors: WorkGang (Serial, CMS, G1) + template + inline void restore(E* executor); + + // Do the restoration serially. Temporary, to be used by PS until we + // can support GCTaskManager in restore(E*). void restore(); + // Reclaim stack array. void reclaim(); - // Assert all the stacks are empty. + // Assert all the stacks are empty and have no cached segments. void assert_empty() PRODUCT_RETURN; PreservedMarksSet(bool in_c_heap) diff --git a/hotspot/src/share/vm/gc/shared/preservedMarks.inline.hpp b/hotspot/src/share/vm/gc/shared/preservedMarks.inline.hpp index 32c83115a69..fc1039ad40b 100644 --- a/hotspot/src/share/vm/gc/shared/preservedMarks.inline.hpp +++ b/hotspot/src/share/vm/gc/shared/preservedMarks.inline.hpp @@ -22,13 +22,13 @@ * */ -#include "gc/shared/preservedMarks.hpp" -#include "oops/markOop.inline.hpp" -#include "utilities/stack.inline.hpp" - #ifndef SHARE_VM_GC_SHARED_PRESERVEDMARKS_INLINE_HPP #define SHARE_VM_GC_SHARED_PRESERVEDMARKS_INLINE_HPP +#include "gc/shared/preservedMarks.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/stack.inline.hpp" + inline bool PreservedMarks::should_preserve_mark(oop obj, markOop m) const { return m->must_be_preserved_for_promotion_failure(obj); } @@ -45,4 +45,48 @@ inline void PreservedMarks::push_if_necessary(oop obj, markOop m) { } } +inline void PreservedMarks::init_forwarded_mark(oop obj) { + obj->init_mark(); +} + +template +inline void PreservedMarksSet::restore(E* executor) { + volatile size_t total_size = 0; + +#ifdef ASSERT + // This is to make sure the total_size we'll calculate below is correct. + size_t total_size_before = 0; + for (uint i = 0; i < _num; i += 1) { + total_size_before += get(i)->size(); + } +#endif // def ASSERT + + if (executor == NULL) { + for (uint i = 0; i < _num; i += 1) { + total_size += get(i)->size(); + get(i)->restore(); + } + } else { + // Right now, if the executor is not NULL we do the work in + // parallel. In the future we might want to do the restoration + // serially, if there's only a small number of marks per stack. + restore_internal(executor, &total_size); + } + assert_empty(); + + assert(total_size == total_size_before, + "total_size = " SIZE_FORMAT " before = " SIZE_FORMAT, + total_size, total_size_before); + + log_trace(gc)("Restored " SIZE_FORMAT " marks", total_size); +} + +inline PreservedMarks::PreservedMarks() + : _stack(OopAndMarkOopStack::default_segment_size(), + // This stack should be used very infrequently so there's + // no point in caching stack segments (there will be a + // waste of space most of the time). So we set the max + // cache size to 0. + 0 /* max_cache_size */) { } + #endif // SHARE_VM_GC_SHARED_PRESERVEDMARKS_INLINE_HPP From 2b7a70a9d3d9b4ca94605d22d3d4f3c78a5c8d8b Mon Sep 17 00:00:00 2001 From: Dmitry Fazunenko Date: Thu, 7 Apr 2016 17:42:30 +0400 Subject: [PATCH 09/24] 8152432: Implement setting jtreg @requires properties vm.flavor, vm.bits, vm.compMode Reviewed-by: iignatyev --- hotspot/test/TEST.ROOT | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT index 55979b0a554..29c9696e7be 100644 --- a/hotspot/test/TEST.ROOT +++ b/hotspot/test/TEST.ROOT @@ -30,6 +30,10 @@ keys=cte_test jcmd nmt regression gc stress groups=TEST.groups [closed/TEST.groups] + +# Source files for classes that will be used at the beginning of each test suite run, +# to determine additional characteristics of the system for use with the @requires tag. +requires.extraPropDefns = ../../test/jtreg-ext/requires/VMProps.java requires.properties=sun.arch.data.model # Tests using jtreg 4.2 b01 features From 412ce42184a379abe9a75b8ffb25055073d4b23d Mon Sep 17 00:00:00 2001 From: Michail Chernov Date: Thu, 7 Apr 2016 15:58:24 +0300 Subject: [PATCH 10/24] 8148376: Test for PLAB behavior at evacuation failure Reviewed-by: tschatzl, dfazunen --- .../gc/g1/plab/TestPLABEvacuationFailure.java | 203 ++++++++++++++++++ .../g1/plab/lib/AppPLABEvacuationFailure.java | 54 +++++ 2 files changed, 257 insertions(+) create mode 100644 hotspot/test/gc/g1/plab/TestPLABEvacuationFailure.java create mode 100644 hotspot/test/gc/g1/plab/lib/AppPLABEvacuationFailure.java diff --git a/hotspot/test/gc/g1/plab/TestPLABEvacuationFailure.java b/hotspot/test/gc/g1/plab/TestPLABEvacuationFailure.java new file mode 100644 index 00000000000..5bcad7f2404 --- /dev/null +++ b/hotspot/test/gc/g1/plab/TestPLABEvacuationFailure.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test TestPLABEvacuationFailure + * @bug 8148376 + * @summary Checks PLAB statistics on evacuation failure + * @requires vm.gc=="G1" | vm.gc=="null" + * @library /testlibrary / + * @modules java.management + * @build gc.g1.plab.lib.LogParser + * gc.g1.plab.lib.AppPLABEvacuationFailure + * @run main gc.g1.plab.TestPLABEvacuationFailure + */ +package gc.g1.plab; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.Collections; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.Utils; + +import gc.g1.plab.lib.LogParser; +import gc.g1.plab.lib.AppPLABEvacuationFailure; +import gc.g1.plab.lib.PlabInfo; + +/** + * The test runs the AppPLABEvacuationFailure application to provoke a number of + * Evacuation Failures, parses GC log and analyzes PLAB statistics. The test checks + * that both fields 'failure_waste' and 'failure_used' for Evacuation Failure statistic + * are non zero, and zero for other statistics. + */ +public class TestPLABEvacuationFailure { + + /* PLAB statistics fields which are checked. + * Test expects to find 0 in this fields in survivor statistics. + * Expects to find 0 in old statistics for GC when evacuation failure + * did not happen. And expects to find not 0 in old statistics in case when + * GC causes to evacuation failure. + */ + private static final List FAILURE_STAT_FIELDS = new ArrayList<>(Arrays.asList( + "failure used", + "failure wasted")); + + private static final String[] COMMON_OPTIONS = { + "-Xlog:gc=debug,gc+plab=debug,gc+phases=trace", + "-XX:+UseG1GC", + "-XX:InitiatingHeapOccupancyPercent=100", + "-XX:-G1UseAdaptiveIHOP", + "-XX:G1HeapRegionSize=1m"}; + + private static final Pattern GC_ID_PATTERN = Pattern.compile("GC\\((\\d+)\\)"); + private static List evacuationFailureIDs; + private static LogParser logParser; + private static String appPlabEvacFailureOutput; + + public static void main(String[] args) throws Throwable { + // ParallelGCBufferWastePct, PLAB Size, ParallelGCBufferWastePct, MaxHeapSize, is plab fixed. + runTest(10, 1024, 3, 16, true); + runTest(15, 2048, 4, 256, true); + runTest(20, 65536, 7, 128, false); + runTest(25, 1024, 3, 16, true); + runTest(30, 16384, 7, 256, false); + runTest(10, 65536, 4, 32, false); + } + + private static void runTest(int wastePct, int plabSize, int parGCThreads, int heapSize, boolean plabIsFixed) throws Throwable { + System.out.println("Test case details:"); + System.out.println(" Heap size : " + heapSize + "M"); + System.out.println(" Initial PLAB size : " + plabSize); + System.out.println(" Parallel GC buffer waste pct : " + wastePct); + System.out.println(" Parallel GC threads : " + parGCThreads); + System.out.println(" PLAB size is fixed: " + (plabIsFixed ? "yes" : "no")); + // Set up test GC and PLAB options + List testOptions = new ArrayList<>(); + Collections.addAll(testOptions, COMMON_OPTIONS); + Collections.addAll(testOptions, Utils.getTestJavaOpts()); + Collections.addAll(testOptions, + "-XX:ParallelGCThreads=" + parGCThreads, + "-XX:ParallelGCBufferWastePct=" + wastePct, + "-XX:OldPLABSize=" + plabSize, + "-XX:YoungPLABSize=" + plabSize, + "-XX:" + (plabIsFixed ? "-" : "+") + "ResizePLAB", + "-XX:MaxHeapSize=" + heapSize + "m"); + testOptions.add(AppPLABEvacuationFailure.class.getName()); + OutputAnalyzer out = ProcessTools.executeTestJvm(testOptions.toArray(new String[testOptions.size()])); + + appPlabEvacFailureOutput = out.getOutput(); + if (out.getExitValue() != 0) { + System.out.println(appPlabEvacFailureOutput); + throw new RuntimeException("Expect exit code 0."); + } + // Get list of GC ID on evacuation failure + evacuationFailureIDs = getGcIdPlabEvacFailures(out); + logParser = new LogParser(appPlabEvacFailureOutput); + checkResults(); + } + + private static void checkResults() { + + if (evacuationFailureIDs.isEmpty()) { + System.out.println(appPlabEvacFailureOutput); + throw new RuntimeException("AppPLABEvacuationFailure did not reach Evacuation Failure."); + } + + Map valuesToCheck = getNonEvacFailureSurvivorStats(); + checkValuesIsZero(valuesToCheck, "Expect that SURVIVOR PLAB failure statistics should be 0 when no evacuation failure"); + + valuesToCheck = getNonEvacFailureOldStats(); + checkValuesIsZero(valuesToCheck, "Expect that OLD PLAB failure statistics should be 0 when no evacuation failure"); + + valuesToCheck = getEvacFailureSurvivorStats(); + checkValuesIsZero(valuesToCheck, "Expect that failure statistics should be 0 in SURVIVOR PLAB statistics at evacuation failure"); + + valuesToCheck = getEvacFailureOldStats(); + checkValuesIsNotZero(valuesToCheck, "Expect that failure statistics should not be 0 in OLD PLAB statistics at evacuation failure"); + } + + /** + * Checks logItems for non-zero values. Throws RuntimeException if found. + * + * @param logItems + * @param errorMessage + */ + private static void checkValuesIsZero(Map logItems, String errorMessage) { + checkValues(logItems, errorMessage, true); + } + + /** + * Checks logItems for zero values. Throws RuntimeException if found. + * + * @param logItems + * @param errorMessage + */ + private static void checkValuesIsNotZero(Map logItems, String errorMessage) { + checkValues(logItems, errorMessage, false); + } + + private static void checkValues(Map logItems, String errorMessage, boolean expectZero) { + logItems.entrySet() + .forEach(item -> item.getValue() + .values() + .forEach(items -> { + if (expectZero != (items == 0)) { + System.out.println(appPlabEvacFailureOutput); + throw new RuntimeException(errorMessage); + } + }) + ); + } + + /** + * For tracking PLAB statistics for specified PLAB type - survivor and old + */ + private static Map getNonEvacFailureSurvivorStats() { + return logParser.getExcludedSpecifiedStats(evacuationFailureIDs, LogParser.ReportType.SURVIVOR_STATS, FAILURE_STAT_FIELDS); + } + + private static Map getNonEvacFailureOldStats() { + return logParser.getExcludedSpecifiedStats(evacuationFailureIDs, LogParser.ReportType.OLD_STATS, FAILURE_STAT_FIELDS); + } + + private static Map getEvacFailureSurvivorStats() { + return logParser.getSpecifiedStats(evacuationFailureIDs, LogParser.ReportType.SURVIVOR_STATS, FAILURE_STAT_FIELDS); + } + + private static Map getEvacFailureOldStats() { + return logParser.getSpecifiedStats(evacuationFailureIDs, LogParser.ReportType.OLD_STATS, FAILURE_STAT_FIELDS); + } + + private static List getGcIdPlabEvacFailures(OutputAnalyzer out) { + return out.asLines().stream() + .filter(line -> line.contains("Evacuation Failure")) + .map(line -> LogParser.getGcIdFromLine(line, GC_ID_PATTERN)) + .collect(Collectors.toList()); + } +} diff --git a/hotspot/test/gc/g1/plab/lib/AppPLABEvacuationFailure.java b/hotspot/test/gc/g1/plab/lib/AppPLABEvacuationFailure.java new file mode 100644 index 00000000000..25d797ecda5 --- /dev/null +++ b/hotspot/test/gc/g1/plab/lib/AppPLABEvacuationFailure.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package gc.g1.plab.lib; + +import java.util.ArrayList; + +/** + * Application that provokes Evacuation Failure + */ +public class AppPLABEvacuationFailure { + + public static final int CHUNK = 10000; + public static ArrayList arr = new ArrayList<>(); + + public static void main(String[] args) { + System.gc(); + // First attempt. + try { + while (true) { + arr.add(new byte[CHUNK]); + } + } catch (OutOfMemoryError oome) { + arr.clear(); + } + // Second attempt. + try { + while (true) { + arr.add(new byte[CHUNK]); + } + } catch (OutOfMemoryError oome) { + arr.clear(); + } + } +} From 0202ef201cc0bc4a2d209e8fd978dbea9b7c4bc5 Mon Sep 17 00:00:00 2001 From: Michail Chernov Date: Thu, 7 Apr 2016 16:01:16 +0300 Subject: [PATCH 11/24] 8153516: Hotspot TEST.group has error in GC groups definition Reviewed-by: tschatzl, dfazunen --- hotspot/test/TEST.groups | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 527de350443..fd320ecf20f 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -386,7 +386,8 @@ hotspot_jprt = \ :hotspot_fast_compiler_2 \ :hotspot_fast_compiler_3 \ :hotspot_fast_compiler_closed \ - :hotspot_fast_gc \ + :hotspot_fast_gc_1 \ + :hotspot_fast_gc_2 \ :hotspot_fast_gc_closed \ :hotspot_fast_gc_gcold \ :hotspot_fast_runtime \ From a9cf95480ff53ae3345554488298297aba0f3345 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 7 Apr 2016 15:17:08 +0200 Subject: [PATCH 12/24] 8153734: TestHumongousReferenceObject.java occasionally crashes with "unable to allocate heap of 1g" on win32 Decrease the heap size used in the test from 1g to 128M. Reviewed-by: dfazunen, sjohanss --- .../test/gc/TestHumongousReferenceObject.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hotspot/test/gc/TestHumongousReferenceObject.java b/hotspot/test/gc/TestHumongousReferenceObject.java index 728b8911de8..7e09abfe274 100644 --- a/hotspot/test/gc/TestHumongousReferenceObject.java +++ b/hotspot/test/gc/TestHumongousReferenceObject.java @@ -27,26 +27,26 @@ import jdk.internal.vm.annotation.Contended; * @test * @summary Test that verifies that iteration over large, plain Java objects, that potentially cross region boundaries on G1, with references in them works. * @requires vm.gc == "null" - * @bug 8151499 + * @bug 8151499 8153734 * @modules java.base/jdk.internal.vm.annotation - * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseParallelGC -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject - * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=1M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject - * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=2M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject - * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject - * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx1g -XX:+UseG1GC -XX:G1HeapRegionSize=8M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx128m -XX:+UseParallelGC -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx128m -XX:+UseG1GC -XX:G1HeapRegionSize=1M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx128m -XX:+UseG1GC -XX:G1HeapRegionSize=2M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx128m -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject + * @run main/othervm -XX:+EnableContended -XX:-RestrictContended -Xmx128m -XX:+UseG1GC -XX:G1HeapRegionSize=8M -XX:ContendedPaddingWidth=8192 TestHumongousReferenceObject */ public class TestHumongousReferenceObject { /* Due to 300 fields with 8K @Contended padding around each field, it takes 2.4M bytes per instance. With small G1 regions, it is bound to cross regions. G1 should properly (card) mark the object nevertheless. - With 1G heap, it is enough to allocate ~400 of these objects to provoke at least one GC. + With 128M heap, it is enough to allocate ~100 of these objects to provoke at least one GC. */ static volatile Object instance; public static void main(String[] args) { - for (int c = 0; c < 400; c++) { + for (int c = 0; c < 100; c++) { instance = new TestHumongousReferenceObject(); } } From 02d268d76065f5c12d79bca25ed95482e812b17d Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Thu, 7 Apr 2016 13:11:15 -0400 Subject: [PATCH 13/24] 8152896: Convert PrintCompressedOopsMode to Unified Logging Converted -XX:+PrintCompressedOopsMode to -Xlog:gc+heap+coops and aliased old option Reviewed-by: coleenp, sjohanss, kvn, hseigel --- hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/memory/universe.cpp | 10 ++- hotspot/src/share/vm/memory/virtualspace.cpp | 38 ++++----- hotspot/src/share/vm/runtime/arguments.cpp | 16 ++-- hotspot/src/share/vm/runtime/globals.hpp | 3 - .../CompressedClassPointers.java | 5 +- .../CompressedOops/UseCompressedOops.java | 3 +- .../runtime/logging/CompressedOopsTest.java | 82 +++++++++++++++++++ 8 files changed, 113 insertions(+), 45 deletions(-) create mode 100644 hotspot/test/runtime/logging/CompressedOopsTest.java diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 78cb944c345..5e4fcc6a142 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -48,6 +48,7 @@ LOG_TAG(classpath) \ LOG_TAG(compaction) \ LOG_TAG(constraints) \ + LOG_TAG(coops) \ LOG_TAG(cpu) \ LOG_TAG(cset) \ LOG_TAG(defaultmethods) \ diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index f33afa87ea2..11037c539f0 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -747,8 +747,10 @@ jint Universe::initialize_heap() { Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); - if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { - Universe::print_compressed_oops_mode(tty); + if (log_is_enabled(Info, gc, heap, coops)) { + ResourceMark rm; + outputStream* logst = Log(gc, heap, coops)::info_stream(); + Universe::print_compressed_oops_mode(logst); } // Tell tests in which mode we run. @@ -776,8 +778,8 @@ jint Universe::initialize_heap() { } void Universe::print_compressed_oops_mode(outputStream* st) { - st->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", - p2i(Universe::heap()->base()), Universe::heap()->reserved_region().byte_size()/M); + st->print("Heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", + p2i(Universe::heap()->base()), Universe::heap()->reserved_region().byte_size()/M); st->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode())); diff --git a/hotspot/src/share/vm/memory/virtualspace.cpp b/hotspot/src/share/vm/memory/virtualspace.cpp index 76f45090ec2..31fddb745c7 100644 --- a/hotspot/src/share/vm/memory/virtualspace.cpp +++ b/hotspot/src/share/vm/memory/virtualspace.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "code/codeCacheExtensions.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "memory/virtualspace.hpp" #include "oops/markOop.hpp" #include "oops/oop.inline.hpp" @@ -78,10 +80,7 @@ static bool failed_to_reserve_as_requested(char* base, char* requested_address, // Different reserve address may be acceptable in other cases // but for compressed oops heap should be at requested address. assert(UseCompressedOops, "currently requested address used only for compressed oops"); - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, p2i(base), p2i(requested_address)); - } + log_debug(gc, heap, coops)("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, p2i(base), p2i(requested_address)); // OS ignored requested address. Try different address. if (special) { if (!os::release_memory_special(base, size)) { @@ -143,10 +142,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, // failed; try to reserve regular memory below if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Reserve regular memory without large pages."); - } + log_debug(gc, heap, coops)("Reserve regular memory without large pages"); } } } @@ -286,11 +282,10 @@ void ReservedHeapSpace::establish_noaccess_prefix() { if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) { fatal("cannot protect protection page"); } - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Protected page at the reserved heap base: " - PTR_FORMAT " / " INTX_FORMAT " bytes", p2i(_base), _noaccess_prefix); - } + log_debug(gc, heap, coops)("Protected page at the reserved heap base: " + PTR_FORMAT " / " INTX_FORMAT " bytes", + p2i(_base), + _noaccess_prefix); assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?"); } else { Universe::set_narrow_oop_use_implicit_null_checks(false); @@ -321,10 +316,10 @@ void ReservedHeapSpace::try_reserve_heap(size_t size, bool special = large && !os::can_commit_large_page_memory(); char* base = NULL; - if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " SIZE_FORMAT_HEX ".\n", - p2i(requested_address), size); - } + log_trace(gc, heap, coops)("Trying to allocate at address " PTR_FORMAT + " heap of size " SIZE_FORMAT_HEX, + p2i(requested_address), + size); if (special) { base = os::reserve_memory_special(size, alignment, requested_address, false); @@ -343,10 +338,7 @@ void ReservedHeapSpace::try_reserve_heap(size_t size, // Failed; try to reserve regular memory below if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { - if (PrintCompressedOopsMode) { - tty->cr(); - tty->print_cr("Reserve regular memory without large pages."); - } + log_debug(gc, heap, coops)("Reserve regular memory without large pages"); } // Optimistically assume that the OSes returns an aligned base pointer. @@ -558,9 +550,7 @@ void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t ali // Last, desperate try without any placement. if (_base == NULL) { - if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address NULL heap of size " SIZE_FORMAT_HEX ".\n", size + noaccess_prefix); - } + log_trace(gc, heap, coops)("Trying to allocate at address NULL heap of size " SIZE_FORMAT_HEX, size + noaccess_prefix); initialize(size + noaccess_prefix, alignment, large, NULL, false); } } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index d82452bceeb..67cf5784d0d 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -407,7 +407,9 @@ static AliasedFlag const aliased_jvm_flags[] = { { NULL, NULL} }; +// NOTE: A compatibility request will be necessary for each alias to be removed. static AliasedLoggingFlag const aliased_logging_flags[] = { + { "PrintCompressedOopsMode", LogLevel::Info, true, LOG_TAGS(gc, heap, coops) }, { "TraceBiasedLocking", LogLevel::Info, true, LOG_TAGS(biasedlocking) }, { "TraceClassLoading", LogLevel::Info, true, LOG_TAGS(classload) }, { "TraceClassLoadingPreorder", LogLevel::Debug, true, LOG_TAGS(classload, preorder) }, @@ -2184,15 +2186,11 @@ void Arguments::set_heap_size() { if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) { // matches compressed oops printing flags - if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { - jio_fprintf(defaultStream::error_stream(), - "HeapBaseMinAddress must be at least " SIZE_FORMAT - " (" SIZE_FORMAT "G) which is greater than value given " - SIZE_FORMAT "\n", - DefaultHeapBaseMinAddress, - DefaultHeapBaseMinAddress/G, - HeapBaseMinAddress); - } + log_debug(gc, heap, coops)("HeapBaseMinAddress must be at least " SIZE_FORMAT + " (" SIZE_FORMAT "G) which is greater than value given " SIZE_FORMAT, + DefaultHeapBaseMinAddress, + DefaultHeapBaseMinAddress/G, + HeapBaseMinAddress); FLAG_SET_ERGO(size_t, HeapBaseMinAddress, DefaultHeapBaseMinAddress); } } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 105e02d8be5..12408be3ab9 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -641,9 +641,6 @@ public: "region.") \ range(1, max_uintx) \ \ - diagnostic(bool, PrintCompressedOopsMode, false, \ - "Print compressed oops base address and encoding mode") \ - \ lp64_product(intx, ObjectAlignmentInBytes, 8, \ "Default object alignment in bytes, 8 is minimum") \ range(8, 256) \ diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java index 54616e4b176..158f2fc90cd 100644 --- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java +++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -85,8 +85,7 @@ public class CompressedClassPointers { public static void heapBaseMinAddressTest() throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:HeapBaseMinAddress=1m", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+heap+coops=debug", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("HeapBaseMinAddress must be at least"); diff --git a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java index ac60e764e75..707bf2f4a6e 100644 --- a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java +++ b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -169,7 +169,6 @@ public class UseCompressedOops { ArrayList args = new ArrayList<>(); // Always run with these three: - args.add("-XX:+UnlockDiagnosticVMOptions"); args.add("-XX:+PrintCompressedOopsMode"); args.add("-Xms32m"); diff --git a/hotspot/test/runtime/logging/CompressedOopsTest.java b/hotspot/test/runtime/logging/CompressedOopsTest.java new file mode 100644 index 00000000000..fed2233674c --- /dev/null +++ b/hotspot/test/runtime/logging/CompressedOopsTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8149991 + * @requires (sun.arch.data.model == "64") + * @summary -Xlog:gc+heap+coops=info should have output from the code + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.Platform jdk.test.lib.ProcessTools + * @run driver CompressedOopsTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; + +public class CompressedOopsTest { + static void analyzeOutputOn(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[gc,heap,coops] Heap address"); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputOff(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[gc,heap,coops]"); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseCompressedOops", + "-Xlog:gc+heap+coops=info", + InnerClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseCompressedOops", + "-XX:+PrintCompressedOopsMode", + InnerClass.class.getName()); + analyzeOutputOn(pb); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseCompressedOops", + "-XX:+PrintCompressedOopsMode", + "-Xlog:gc+heap+coops=off", + InnerClass.class.getName()); + analyzeOutputOff(pb); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseCompressedOops", + "-Xlog:gc+heap+coops=info", + "-XX:-PrintCompressedOopsMode", + InnerClass.class.getName()); + analyzeOutputOff(pb); + } + + public static class InnerClass { + public static void main(String[] args) throws Exception { + System.out.println("Compressed Oops (gc+heap+coops) test"); + } + } +} From 0d3e7977aebcb1eb717735cb5faf0903c728fdd7 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 7 Apr 2016 16:37:35 -0400 Subject: [PATCH 14/24] 8151939: VM_Version_init() print buffer is too small Increase buffer size, use logging to print out version and os information Reviewed-by: kvn, rprotacio, mockner --- hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 41 +++++---- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 46 +++++----- hotspot/src/os/aix/vm/os_aix.cpp | 6 +- hotspot/src/os/bsd/vm/os_bsd.cpp | 24 +----- hotspot/src/os/linux/vm/os_linux.cpp | 32 ++----- hotspot/src/os/solaris/vm/os_solaris.cpp | 40 +++------ hotspot/src/os/windows/vm/os_windows.cpp | 86 +++++-------------- hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp | 6 +- hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp | 20 ++--- .../src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp | 8 +- .../linux_aarch64/vm/os_linux_aarch64.cpp | 8 +- .../src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp | 6 +- .../os_cpu/linux_sparc/vm/os_linux_sparc.cpp | 8 +- .../linux_sparc/vm/vm_version_linux_sparc.cpp | 6 +- .../src/os_cpu/linux_x86/vm/os_linux_x86.cpp | 30 ++----- .../os_cpu/linux_zero/vm/os_linux_zero.cpp | 6 +- .../solaris_sparc/vm/os_solaris_sparc.cpp | 9 +- .../vm/vm_version_solaris_sparc.cpp | 20 ++--- .../os_cpu/solaris_x86/vm/os_solaris_x86.cpp | 21 ++--- hotspot/src/share/vm/logging/log.cpp | 8 +- hotspot/src/share/vm/runtime/vm_version.cpp | 11 +-- .../runtime/logging/OsCpuLoggingTest.java | 64 ++++++++++++++ 22 files changed, 206 insertions(+), 300 deletions(-) create mode 100644 hotspot/test/runtime/logging/OsCpuLoggingTest.java diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 34041ed9943..93c8d40891e 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" @@ -368,36 +369,38 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseUnalignedAccesses, false); } - if (PrintMiscellaneous && Verbose) { - tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); - tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); - tty->print("Allocation"); + if (log_is_enabled(Info, os, cpu)) { + ResourceMark rm; + outputStream* log = Log(os, cpu)::info_stream(); + log->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); + log->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); + log->print("Allocation"); if (AllocatePrefetchStyle <= 0) { - tty->print_cr(": no prefetching"); + log->print(": no prefetching"); } else { - tty->print(" prefetching: "); + log->print(" prefetching: "); if (AllocatePrefetchInstr == 0) { - tty->print("PREFETCH"); + log->print("PREFETCH"); } else if (AllocatePrefetchInstr == 1) { - tty->print("BIS"); + log->print("BIS"); } if (AllocatePrefetchLines > 1) { - tty->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize); + log->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize); } else { - tty->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize); + log->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize); } } if (PrefetchCopyIntervalInBytes > 0) { - tty->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); + log->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); } if (PrefetchScanIntervalInBytes > 0) { - tty->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); + log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); } if (PrefetchFieldsAhead > 0) { - tty->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); + log->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); } if (ContendedPaddingWidth > 0) { - tty->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); + log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); } } } @@ -408,7 +411,7 @@ void VM_Version::print_features() { int VM_Version::determine_features() { if (UseV8InstrsOnly) { - if (PrintMiscellaneous && Verbose) { tty->print_cr("Version is Forced-V8"); } + log_info(os, cpu)("Version is Forced-V8"); return generic_v8_m; } @@ -416,7 +419,7 @@ int VM_Version::determine_features() { if (features == unknown_m) { features = generic_v9_m; - warning("Cannot recognize SPARC version. Default to V9"); + log_info(os)("Cannot recognize SPARC version. Default to V9"); } assert(is_T_family(features) == is_niagara(features), "Niagara should be T series"); @@ -424,12 +427,12 @@ int VM_Version::determine_features() { if (is_T_family(features)) { // Happy to accomodate... } else { - if (PrintMiscellaneous && Verbose) { tty->print_cr("Version is Forced-Niagara"); } + log_info(os, cpu)("Version is Forced-Niagara"); features |= T_family_m; } } else { if (is_T_family(features) && !FLAG_IS_DEFAULT(UseNiagaraInstrs)) { - if (PrintMiscellaneous && Verbose) { tty->print_cr("Version is Forced-Not-Niagara"); } + log_info(os, cpu)("Version is Forced-Not-Niagara"); features &= ~(T_family_m | T1_model_m); } else { // Happy to accomodate... diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index 94c7e156d7e..6d871ce92de 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" @@ -1223,59 +1224,60 @@ void VM_Version::get_processor_features() { } #ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print_cr("Logical CPUs per core: %u", + if (log_is_enabled(Info, os, cpu)) { + outputStream* log = Log(os, cpu)::info_stream(); + log->print_cr("Logical CPUs per core: %u", logical_processors_per_package()); - tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); - tty->print("UseSSE=%d", (int) UseSSE); + log->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); + log->print("UseSSE=%d", (int) UseSSE); if (UseAVX > 0) { - tty->print(" UseAVX=%d", (int) UseAVX); + log->print(" UseAVX=%d", (int) UseAVX); } if (UseAES) { - tty->print(" UseAES=1"); + log->print(" UseAES=1"); } #ifdef COMPILER2 if (MaxVectorSize > 0) { - tty->print(" MaxVectorSize=%d", (int) MaxVectorSize); + log->print(" MaxVectorSize=%d", (int) MaxVectorSize); } #endif - tty->cr(); - tty->print("Allocation"); + log->cr(); + log->print("Allocation"); if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) { - tty->print_cr(": no prefetching"); + log->print_cr(": no prefetching"); } else { - tty->print(" prefetching: "); + log->print(" prefetching: "); if (UseSSE == 0 && supports_3dnow_prefetch()) { - tty->print("PREFETCHW"); + log->print("PREFETCHW"); } else if (UseSSE >= 1) { if (AllocatePrefetchInstr == 0) { - tty->print("PREFETCHNTA"); + log->print("PREFETCHNTA"); } else if (AllocatePrefetchInstr == 1) { - tty->print("PREFETCHT0"); + log->print("PREFETCHT0"); } else if (AllocatePrefetchInstr == 2) { - tty->print("PREFETCHT2"); + log->print("PREFETCHT2"); } else if (AllocatePrefetchInstr == 3) { - tty->print("PREFETCHW"); + log->print("PREFETCHW"); } } if (AllocatePrefetchLines > 1) { - tty->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize); + log->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize); } else { - tty->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize); + log->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize); } } if (PrefetchCopyIntervalInBytes > 0) { - tty->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); + log->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); } if (PrefetchScanIntervalInBytes > 0) { - tty->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); + log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); } if (PrefetchFieldsAhead > 0) { - tty->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); + log->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); } if (ContendedPaddingWidth > 0) { - tty->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); + log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); } } #endif // !PRODUCT diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 31002c5bd60..22e016b65f2 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -3612,14 +3612,12 @@ jint os::init_2(void) { struct rlimit nbr_files; int status = getrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) - perror("os::init_2 getrlimit failed"); + log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); } else { nbr_files.rlim_cur = nbr_files.rlim_max; status = setrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) - perror("os::init_2 setrlimit failed"); + log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); } } } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 9cf4f74d2cf..ce3f6e005fd 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -3459,25 +3459,13 @@ jint os::init_2(void) { guarantee(polling_page != MAP_FAILED, "os::init_2: failed to allocate polling page"); os::set_polling_page(polling_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", - (intptr_t)polling_page); - } -#endif + log_info(os)("SafePoint Polling address: " INTPTR_FORMAT, p2i(polling_page)); if (!UseMembar) { address mem_serialize_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); guarantee(mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page"); os::set_memory_serialize_page(mem_serialize_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", - (intptr_t)mem_serialize_page); - } -#endif + log_info(os)("Memory Serialize Page address: " INTPTR_FORMAT, p2i(mem_serialize_page)); } // initialize suspend/resume support - must do this before signal_sets_init() @@ -3519,9 +3507,7 @@ jint os::init_2(void) { struct rlimit nbr_files; int status = getrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::init_2 getrlimit failed"); - } + log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); } else { nbr_files.rlim_cur = nbr_files.rlim_max; @@ -3534,9 +3520,7 @@ jint os::init_2(void) { status = setrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::init_2 setrlimit failed"); - } + log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); } } } diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index d8811d46528..228ac835ffb 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2163,7 +2163,7 @@ static bool print_model_name_and_flags(outputStream* st, char* buf, size_t bufle bool model_name_printed = false; if (strstr(buf, "model name") != NULL) { if (!model_name_printed) { - st->print_raw("\nCPU Model and flags from /proc/cpuinfo:\n"); + st->print_raw("CPU Model and flags from /proc/cpuinfo:\n"); st->print_raw(buf); model_name_printed = true; } else { @@ -4671,25 +4671,13 @@ jint os::init_2(void) { guarantee(polling_page != MAP_FAILED, "os::init_2: failed to allocate polling page"); os::set_polling_page(polling_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", - (intptr_t)polling_page); - } -#endif + log_info(os)("SafePoint Polling address: " INTPTR_FORMAT, p2i(polling_page)); if (!UseMembar) { address mem_serialize_page = (address) ::mmap(NULL, Linux::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); guarantee(mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page"); os::set_memory_serialize_page(mem_serialize_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", - (intptr_t)mem_serialize_page); - } -#endif + log_info(os)("Memory Serialize Page address: " INTPTR_FORMAT, p2i(mem_serialize_page)); } // initialize suspend/resume support - must do this before signal_sets_init() @@ -4732,10 +4720,8 @@ jint os::init_2(void) { #endif Linux::libpthread_init(); - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("[HotSpot is running with %s, %s]\n", - Linux::glibc_version(), Linux::libpthread_version()); - } + log_info(os)("HotSpot is running with %s, %s", + Linux::glibc_version(), Linux::libpthread_version()); if (UseNUMA) { if (!Linux::libnuma_init()) { @@ -4776,16 +4762,12 @@ jint os::init_2(void) { struct rlimit nbr_files; int status = getrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::init_2 getrlimit failed"); - } + log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); } else { nbr_files.rlim_cur = nbr_files.rlim_max; status = setrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::init_2 setrlimit failed"); - } + log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); } } } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index d64b56a3a5a..68f4a58c30a 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -2754,13 +2754,13 @@ char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { pd_unmap_memory(addr, bytes); } - if (PrintMiscellaneous && Verbose) { + if (log_is_enabled(Warning, os)) { char buf[256]; buf[0] = '\0'; if (addr == NULL) { jio_snprintf(buf, sizeof(buf), ": %s", os::strerror(err)); } - warning("attempt_reserve_memory_at: couldn't reserve " SIZE_FORMAT " bytes at " + log_info(os)("attempt_reserve_memory_at: couldn't reserve " SIZE_FORMAT " bytes at " PTR_FORMAT ": reserve_memory_helper returned " PTR_FORMAT "%s", bytes, requested_addr, addr, buf); } @@ -2790,9 +2790,7 @@ char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { assert(i > 0, "gap adjustment code problem"); have_adjusted_gap = true; // adjust the gap only once, just in case gap = actual_gap; - if (PrintMiscellaneous && Verbose) { - warning("attempt_reserve_memory_at: adjusted gap to 0x%lx", gap); - } + log_info(os)("attempt_reserve_memory_at: adjusted gap to 0x%lx", gap); unmap_memory(base[i], bytes); unmap_memory(base[i-1], size[i-1]); i-=2; @@ -2824,8 +2822,8 @@ char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { } else { size_t bottom_overlap = base[i] + bytes - requested_addr; if (bottom_overlap >= 0 && bottom_overlap < bytes) { - if (PrintMiscellaneous && Verbose && bottom_overlap == 0) { - warning("attempt_reserve_memory_at: possible alignment bug"); + if (bottom_overlap == 0) { + log_info(os)("attempt_reserve_memory_at: possible alignment bug"); } unmap_memory(requested_addr, bottom_overlap); size[i] = bytes - bottom_overlap; @@ -4355,8 +4353,8 @@ static pset_getloadavg_type pset_getloadavg_ptr = NULL; void init_pset_getloadavg_ptr(void) { pset_getloadavg_ptr = (pset_getloadavg_type)dlsym(RTLD_DEFAULT, "pset_getloadavg"); - if (PrintMiscellaneous && Verbose && pset_getloadavg_ptr == NULL) { - warning("pset_getloadavg function not found"); + if (pset_getloadavg_ptr == NULL) { + log_warning(os)("pset_getloadavg function not found"); } } @@ -4439,25 +4437,13 @@ jint os::init_2(void) { } os::set_polling_page(polling_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", - (intptr_t)polling_page); - } -#endif + log_info(os)("SafePoint Polling address: " INTPTR_FORMAT, p2i(polling_page)); if (!UseMembar) { address mem_serialize_page = (address)Solaris::mmap_chunk(NULL, page_size, MAP_PRIVATE, PROT_READ | PROT_WRITE); guarantee(mem_serialize_page != NULL, "mmap Failed for memory serialize page"); os::set_memory_serialize_page(mem_serialize_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", - (intptr_t)mem_serialize_page); - } -#endif + log_info(os)("Memory Serialize Page address: " INTPTR_FORMAT, p2i(mem_serialize_page)); } // Check minimum allowable stack size for thread creation and to initialize @@ -4537,16 +4523,12 @@ jint os::init_2(void) { struct rlimit nbr_files; int status = getrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::init_2 getrlimit failed"); - } + log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); } else { nbr_files.rlim_cur = nbr_files.rlim_max; status = setrlimit(RLIMIT_NOFILE, &nbr_files); if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::init_2 setrlimit failed"); - } + log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); } } } diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index f85eb0f273c..53e4528c0cc 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2436,14 +2436,10 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { bool res = os::protect_memory((char*) page_start, page_size, os::MEM_PROT_RWX); - if (PrintMiscellaneous && Verbose) { - char buf[256]; - jio_snprintf(buf, sizeof(buf), "Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s", addr, - page_start, (res ? "success" : os::strerror(errno))); - tty->print_raw_cr(buf); - } + log_debug(os)("Execution protection violation " + "at " INTPTR_FORMAT + ", unguarding " INTPTR_FORMAT ": %s", p2i(addr), + p2i(page_start), (res ? "success" : os::strerror(errno))); // Set last_addr so if we fault again at the same address, we don't // end up in an endless loop. @@ -2896,12 +2892,12 @@ static bool numa_interleaving_init() { NUMAInterleaveGranularity = align_size_up(NUMAInterleaveGranularity, min_interleave_granularity); if (numa_node_list_holder.build()) { - if (PrintMiscellaneous && Verbose) { - tty->print("NUMA UsedNodeCount=%d, namely ", numa_node_list_holder.get_count()); + if (log_is_enabled(Debug, os, cpu)) { + Log(os, cpu) log; + log.debug("NUMA UsedNodeCount=%d, namely ", numa_node_list_holder.get_count()); for (int i = 0; i < numa_node_list_holder.get_count(); i++) { - tty->print("%d ", numa_node_list_holder.get_node_list_entry(i)); + log.debug(" %d ", numa_node_list_holder.get_node_list_entry(i)); } - tty->print("\n"); } success = true; } else { @@ -4119,13 +4115,7 @@ jint os::init_2(void) { guarantee(return_page != NULL, "Commit Failed for polling page"); os::set_polling_page(polling_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[SafePoint Polling address: " INTPTR_FORMAT "]\n", - (intptr_t)polling_page); - } -#endif + log_info(os)("SafePoint Polling address: " INTPTR_FORMAT, p2i(polling_page)); if (!UseMembar) { address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_READWRITE); @@ -4135,13 +4125,7 @@ jint os::init_2(void) { guarantee(return_page != NULL, "Commit Failed for memory serialize page"); os::set_memory_serialize_page(mem_serialize_page); - -#ifndef PRODUCT - if (Verbose && PrintMiscellaneous) { - tty->print("[Memory Serialize Page address: " INTPTR_FORMAT "]\n", - (intptr_t)mem_serialize_page); - } -#endif + log_info(os)("Memory Serialize Page address: " INTPTR_FORMAT, p2i(mem_serialize_page)); } // Setup Windows Exceptions @@ -4769,10 +4753,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, hFile = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == NULL) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("CreateFile() failed: GetLastError->%ld.", err); - } + log_info(os)("CreateFile() failed: GetLastError->%ld.", GetLastError()); return NULL; } @@ -4790,10 +4771,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, base = (char*) VirtualAlloc(addr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (base == NULL) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("VirtualAlloc() failed: GetLastError->%ld.", err); - } + log_info(os)("VirtualAlloc() failed: GetLastError->%ld.", GetLastError()); CloseHandle(hFile); return NULL; } @@ -4807,10 +4785,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, // number of bytes were read before returning. bool res = ReadFile(hFile, base, (DWORD)bytes, &bytes_read, &overlapped) != 0; if (!res) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("ReadFile() failed: GetLastError->%ld.", err); - } + log_info(os)("ReadFile() failed: GetLastError->%ld.", GetLastError()); release_memory(base, bytes); CloseHandle(hFile); return NULL; @@ -4819,10 +4794,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL /* file_name */); if (hMap == NULL) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("CreateFileMapping() failed: GetLastError->%ld.", err); - } + log_info(os)("CreateFileMapping() failed: GetLastError->%ld.", GetLastError()); CloseHandle(hFile); return NULL; } @@ -4831,20 +4803,14 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, base = (char*)MapViewOfFileEx(hMap, access, 0, (DWORD)file_offset, (DWORD)bytes, addr); if (base == NULL) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("MapViewOfFileEx() failed: GetLastError->%ld.", err); - } + log_info(os)("MapViewOfFileEx() failed: GetLastError->%ld.", GetLastError()); CloseHandle(hMap); CloseHandle(hFile); return NULL; } if (CloseHandle(hMap) == 0) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("CloseHandle(hMap) failed: GetLastError->%ld.", err); - } + log_info(os)("CloseHandle(hMap) failed: GetLastError->%ld.", GetLastError()); CloseHandle(hFile); return base; } @@ -4856,10 +4822,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, bool res = VirtualProtect(base, bytes, exec_access, &old_protect) != 0; if (!res) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("VirtualProtect() failed: GetLastError->%ld.", err); - } + log_info(os)("VirtualProtect() failed: GetLastError->%ld.", GetLastError()); // Don't consider this a hard error, on IA32 even if the // VirtualProtect fails, we should still be able to execute CloseHandle(hFile); @@ -4868,10 +4831,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, } if (CloseHandle(hFile) == 0) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("CloseHandle(hFile) failed: GetLastError->%ld.", err); - } + log_info(os)("CloseHandle(hFile) failed: GetLastError->%ld.", GetLastError()); return base; } @@ -4904,10 +4864,7 @@ char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset, bool os::pd_unmap_memory(char* addr, size_t bytes) { MEMORY_BASIC_INFORMATION mem_info; if (VirtualQuery(addr, &mem_info, sizeof(mem_info)) == 0) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("VirtualQuery() failed: GetLastError->%ld.", err); - } + log_info(os)("VirtualQuery() failed: GetLastError->%ld.", GetLastError()); return false; } @@ -4924,10 +4881,7 @@ bool os::pd_unmap_memory(char* addr, size_t bytes) { BOOL result = UnmapViewOfFile(addr); if (result == 0) { - if (PrintMiscellaneous && Verbose) { - DWORD err = GetLastError(); - tty->print_cr("UnmapViewOfFile() failed: GetLastError->%ld.", err); - } + log_info(os)("UnmapViewOfFile() failed: GetLastError->%ld.", GetLastError()); return false; } return true; diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp index f109a111047..537595f95ad 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -184,9 +184,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec if (os::Aix::chained_handler(sig, info, ucVoid)) { return 1; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - warning("Ignoring SIGPIPE - see bug 4229104"); - } + // Ignoring SIGPIPE - see bugs 4229104 return 1; } } diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index f8e7dc509b9..73acdebfb47 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -469,11 +469,7 @@ JVM_handle_bsd_signal(int sig, if (os::Bsd::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see bugs 4229104 or 646499219", - os::exception_name(sig, buf, sizeof(buf))); - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } @@ -728,14 +724,10 @@ JVM_handle_bsd_signal(int sig, bool res = os::protect_memory((char*) page_start, page_size, os::MEM_PROT_RWX); - if (PrintMiscellaneous && Verbose) { - char buf[256]; - jio_snprintf(buf, sizeof(buf), "Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", addr, - page_start, (res ? "success" : "failed"), errno); - tty->print_raw_cr(buf); - } + log_debug(os)("Execution protection violation " + "at " INTPTR_FORMAT + ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), + p2i(page_start), (res ? "success" : "failed"), errno); stub = pc; // Set last_addr so if we fault again at the same address, we don't end diff --git a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp index c3801dfab64..72d57858e09 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -159,11 +159,7 @@ JVM_handle_bsd_signal(int sig, if (os::Bsd::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see bugs 4229104 or 646499219", - os::exception_name(sig, buf, sizeof(buf))); - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp index 4e47e27628f..2a354fbb72c 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -270,11 +270,7 @@ JVM_handle_linux_signal(int sig, if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see bugs 4229104 or 646499219", - os::exception_name(sig, buf, sizeof(buf))); - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } diff --git a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp index b7318c22c08..117bf1067f3 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -198,9 +198,7 @@ JVM_handle_linux_signal(int sig, if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - warning("Ignoring SIGPIPE - see bug 4229104"); - } + // Ignoring SIGPIPE - see bugs 4229104 return true; } } diff --git a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp index 30b321dc228..44a5a7df1f9 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -561,11 +561,7 @@ JVM_handle_linux_signal(int sig, if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see bugs 4229104 or 646499219", - os::exception_name(sig, buf, sizeof(buf))); - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } diff --git a/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp index f9c596e4d79..c6bb5033db6 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, 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 @@ -66,12 +66,12 @@ int VM_Version::platform_features(int features) { features = generic_v9_m; if (detect_niagara()) { - if (PrintMiscellaneous && Verbose) { tty->print_cr("Detected Linux on Niagara"); } + log_info(os, cpu)("Detected Linux on Niagara"); features = niagara1_m | T_family_m; } if (detect_M_family()) { - if (PrintMiscellaneous && Verbose) { tty->print_cr("Detected Linux on M family"); } + log_info(os, cpu)("Detected Linux on M family"); features = sun4v_m | generic_v9_m | M_family_m | T_family_m; } diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index ec6ba97235a..0eb7a9e511f 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -287,11 +287,7 @@ JVM_handle_linux_signal(int sig, if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see bugs 4229104 or 646499219", - os::exception_name(sig, buf, sizeof(buf))); - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } @@ -542,14 +538,10 @@ JVM_handle_linux_signal(int sig, bool res = os::protect_memory((char*) page_start, page_size, os::MEM_PROT_RWX); - if (PrintMiscellaneous && Verbose) { - char buf[256]; - jio_snprintf(buf, sizeof(buf), "Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", addr, - page_start, (res ? "success" : "failed"), errno); - tty->print_raw_cr(buf); - } + log_debug(os)("Execution protection violation " + "at " INTPTR_FORMAT + ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), + p2i(page_start), (res ? "success" : "failed"), errno); stub = pc; // Set last_addr so if we fault again at the same address, we don't end @@ -645,12 +637,8 @@ bool os::supports_sse() { int major = strtol(uts.release,&minor_string,10); int minor = strtol(minor_string+1,NULL,10); bool result = (major > 2 || (major==2 && minor >= 4)); -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print("OS version is %d.%d, which %s support SSE/SSE2\n", + log_info(os)("OS version is %d.%d, which %s support SSE/SSE2", major,minor, result ? "DOES" : "does NOT"); - } -#endif return result; #endif // AMD64 } @@ -939,9 +927,7 @@ void os::workaround_expand_exec_shield_cs_limit() { MemTracker::record_virtual_memory_type((address)codebuf, mtInternal); - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("[CS limit NX emulation work-around, exec code at: %p]", codebuf); - } + log_info(os)("[CS limit NX emulation work-around, exec code at: %p]", codebuf); // Some code to exec: the 'ret' instruction codebuf[0] = 0xC3; diff --git a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp index b1e93a82dc8..abd52961976 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp @@ -154,11 +154,7 @@ JVM_handle_linux_signal(int sig, if (os::Linux::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see bugs 4229104 or 646499219", - os::exception_name(sig, buf, sizeof(buf))); - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp index 5fd0e0a78af..da39ee79790 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -338,12 +338,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, if (os::Solaris::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see 4229104 or 6499219", - os::exception_name(sig, buf, sizeof(buf))); - - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 837607e6781..def37cd0b63 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, 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 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "runtime/os.hpp" @@ -361,15 +362,10 @@ int VM_Version::platform_features(int features) { assert(avn <= 2, "should return two or less av's"); uint_t av = avs[0]; -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print("getisax(2) returned: " PTR32_FORMAT, av); - if (avn > 1) { - tty->print(", " PTR32_FORMAT, avs[1]); - } - tty->cr(); + log_info(os, cpu)("getisax(2) returned: " PTR32_FORMAT, av); + if (avn > 1) { + log_info(os, cpu)(" " PTR32_FORMAT, avs[1]); } -#endif if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; if (av & AV_SPARC_DIV32) features |= hardware_div32_m; @@ -464,11 +460,7 @@ int VM_Version::platform_features(int features) { if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { implementation = KSTAT_NAMED_STR_PTR(&knm[i]); has_implementation = true; -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - tty->print_cr("cpu_info.implementation: %s", implementation); - } -#endif + log_info(os, cpu)("cpu_info.implementation: %s", implementation); features |= parse_features(implementation); break; } diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index 79a7f19a281..0784f3f25f7 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, 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 @@ -403,12 +403,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, if (os::Solaris::chained_handler(sig, info, ucVoid)) { return true; } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - char buf[64]; - warning("Ignoring %s - see 4229104 or 6499219", - os::exception_name(sig, buf, sizeof(buf))); - - } + // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 return true; } } @@ -640,14 +635,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, bool res = os::protect_memory((char*) page_start, page_size, os::MEM_PROT_RWX); - if (PrintMiscellaneous && Verbose) { - char buf[256]; - jio_snprintf(buf, sizeof(buf), "Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", addr, - page_start, (res ? "success" : "failed"), errno); - tty->print_raw_cr(buf); - } + log_debug(os)("Execution protection violation " + "at " INTPTR_FORMAT + ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), + p2i(page_start), (res ? "success" : "failed"), errno); stub = pc; // Set last_addr so if we fault again at the same address, we don't end diff --git a/hotspot/src/share/vm/logging/log.cpp b/hotspot/src/share/vm/logging/log.cpp index 3d676219d89..6c6566b386e 100644 --- a/hotspot/src/share/vm/logging/log.cpp +++ b/hotspot/src/share/vm/logging/log.cpp @@ -377,7 +377,7 @@ void Test_loghandle_on() { assert(log_handle.is_debug(), "assert"); - // Try to log trough a LogHandle. + // Try to log through a LogHandle. log_handle.debug("%d workers", 3); FILE* fp = fopen(log_file.name(), "r"); @@ -408,7 +408,7 @@ void Test_loghandle_off() { return; } - // Try to log trough a LogHandle. Should fail, since only info is turned on. + // Try to log through a LogHandle. Should fail, since only info is turned on. log_handle.debug("%d workers", 3); // Log a dummy line so that fgets doesn't return NULL because the file is empty. @@ -440,7 +440,7 @@ static void Test_logtargethandle_on() { assert(log_handle.is_enabled(), "assert"); - // Try to log trough a LogHandle. + // Try to log through a LogHandle. log_handle.print("%d workers", 3); FILE* fp = fopen(log_file.name(), "r"); @@ -471,7 +471,7 @@ static void Test_logtargethandle_off() { return; } - // Try to log trough a LogHandle. Should fail, since only info is turned on. + // Try to log through a LogHandle. Should fail, since only info is turned on. log_handle.print("%d workers", 3); // Log a dummy line so that fgets doesn't return NULL because the file is empty. diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index cf2bf5a4644..c36098a31f7 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "code/codeCacheExtensions.hpp" +#include "logging/log.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" @@ -274,12 +275,12 @@ unsigned int Abstract_VM_Version::jvm_version() { void VM_Version_init() { VM_Version::initialize(); -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) { - char buf[512]; - os::print_cpu_info(tty, buf, sizeof(buf)); + if (log_is_enabled(Info, os, cpu)) { + char buf[1024]; + ResourceMark rm; + outputStream* log = Log(os, cpu)::info_stream(); + os::print_cpu_info(log, buf, sizeof(buf)); } -#endif } unsigned int Abstract_VM_Version::nof_parallel_worker_threads( diff --git a/hotspot/test/runtime/logging/OsCpuLoggingTest.java b/hotspot/test/runtime/logging/OsCpuLoggingTest.java new file mode 100644 index 00000000000..ab23e194f8f --- /dev/null +++ b/hotspot/test/runtime/logging/OsCpuLoggingTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8151939 + * @summary os+cpu output should contain some os,cpu information + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver OsCpuLoggingTest + */ + +import java.io.File; +import java.util.Map; +import jdk.test.lib.*; + +public class OsCpuLoggingTest { + + static void analyzeOutputForOsLog(OutputAnalyzer output) throws Exception { + // Aix has it's own logging + if (!Platform.isAix()) { + output.shouldContain("SafePoint Polling address"); + } + output.shouldHaveExitValue(0); + } + + static void analyzeOutputForOsCpuLog(OutputAnalyzer output) throws Exception { + output.shouldContain("CPU:total"); + output.shouldHaveExitValue(0); + } + + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+cpu", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + analyzeOutputForOsCpuLog(output); + + pb = ProcessTools.createJavaProcessBuilder("-Xlog:os", "-version"); + output = new OutputAnalyzer(pb.start()); + analyzeOutputForOsLog(output); + } +} From 10c7cac93e527336865caa6398572766487a22d4 Mon Sep 17 00:00:00 2001 From: Sangheon Kim Date: Thu, 7 Apr 2016 15:33:25 -0700 Subject: [PATCH 15/24] 8152180: SIGFPE in CMSCollector::preclean with big CMSScheduleRemarkSamplingRatio Rephrased the calculation routine to avoid an overflow for CMSScheduleRemarkSamplingRatio Reviewed-by: jwilhelm, drwhite --- hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp index 42fd21dc65d..1e7a4991dd3 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp @@ -3598,7 +3598,7 @@ void CMSCollector::preclean() { size_t capacity = get_eden_capacity(); // Don't start sampling unless we will get sufficiently // many samples. - if (used < (capacity/(CMSScheduleRemarkSamplingRatio * 100) + if (used < (((capacity / CMSScheduleRemarkSamplingRatio) / 100) * CMSScheduleRemarkEdenPenetration)) { _start_sampling = true; } else { From 25f35cda7d82c3c1fd3d0b4470806e48cd6dca99 Mon Sep 17 00:00:00 2001 From: Sangheon Kim Date: Thu, 7 Apr 2016 15:34:21 -0700 Subject: [PATCH 16/24] 8152182: Possible overflow in initialzation of _rescan_task_size and _marking_task_size Add constraints for CMSRescanMultiple and CMSConcMarkMultiple flags Reviewed-by: jwilhelm, jmasa --- .../vm/gc/cms/compactibleFreeListSpace.cpp | 5 +++ .../vm/gc/cms/compactibleFreeListSpace.hpp | 2 + .../runtime/commandLineFlagConstraintsGC.cpp | 45 +++++++++++++++++++ .../runtime/commandLineFlagConstraintsGC.hpp | 2 + hotspot/src/share/vm/runtime/globals.hpp | 8 +++- 5 files changed, 60 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp index ac9d84e5d12..c048f08b4a1 100644 --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp @@ -2836,6 +2836,11 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n par_get_chunk_of_blocks_dictionary(word_sz, n, fl); } +const size_t CompactibleFreeListSpace::max_flag_size_for_task_size() const { + const size_t ergo_max = _old_gen->reserved().word_size() / (CardTableModRefBS::card_size_in_words * BitsPerWord); + return ergo_max; +} + // Set up the space's par_seq_tasks structure for work claiming // for parallel rescan. See CMSParRemarkTask where this is currently used. // XXX Need to suitably abstract and generalize this and the next diff --git a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp index eeaa07ce280..92a2764afd0 100644 --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp @@ -345,6 +345,8 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Support for parallelization of rescan and marking. const size_t rescan_task_size() const { return _rescan_task_size; } const size_t marking_task_size() const { return _marking_task_size; } + // Return ergonomic max size for CMSRescanMultiple and CMSConcMarkMultiple. + const size_t max_flag_size_for_task_size() const; SequentialSubTasksDone* conc_par_seq_tasks() {return &_conc_par_seq_tasks; } void initialize_sequential_subtasks_for_rescan(int n_threads); void initialize_sequential_subtasks_for_marking(int n_threads, diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp index 4390644d708..5dce24113af 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp @@ -457,6 +457,51 @@ Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { } } +static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen(); + const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size(); + if (value > ergo_max) { + CommandLineError::print(verbose, + "%s (" SIZE_FORMAT ") must be " + "less than or equal to ergonomic maximum (" SIZE_FORMAT ") " + "which is based on the maximum size of the old generation of the Java heap\n", + name, value, ergo_max); + return Flag::VIOLATES_CONSTRAINT; + } + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) { + Flag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose); + +#if INCLUDE_ALL_GCS + if (status == Flag::SUCCESS && UseConcMarkSweepGC) { + // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size() + // to be aligned to CardTableModRefBS::card_size * BitsPerWord. + // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize' + // because rescan_task_size() is CardTableModRefBS::card_size / HeapWordSize * BitsPerWord. + if (value % HeapWordSize != 0) { + CommandLineError::print(verbose, + "CMSRescanMultiple (" SIZE_FORMAT ") must be " + "a multiple of " SIZE_FORMAT "\n", + value, HeapWordSize); + status = Flag::VIOLATES_CONSTRAINT; + } + } +#endif + + return status; +} + +Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) { + return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose); +} + Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { #if INCLUDE_ALL_GCS if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp index ee8bf3f668b..9470a1c4ec4 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp @@ -60,6 +60,8 @@ Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose); Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); +Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose); +Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose); Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index be97e61c9b0..49e24ed385a 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1806,13 +1806,17 @@ public: "enough work per iteration") \ range(0, max_intx) \ \ + /* 4096 = CardTableModRefBS::card_size_in_words * BitsPerWord */ \ product(size_t, CMSRescanMultiple, 32, \ "Size (in cards) of CMS parallel rescan task") \ - range(1, max_uintx) \ + range(1, SIZE_MAX / 4096) \ + constraint(CMSRescanMultipleConstraintFunc,AfterMemoryInit) \ \ + /* 4096 = CardTableModRefBS::card_size_in_words * BitsPerWord */ \ product(size_t, CMSConcMarkMultiple, 32, \ "Size (in cards) of CMS concurrent MT marking task") \ - range(1, max_uintx) \ + range(1, SIZE_MAX / 4096) \ + constraint(CMSConcMarkMultipleConstraintFunc,AfterMemoryInit) \ \ product(bool, CMSAbortSemantics, false, \ "Whether abort-on-overflow semantics is implemented") \ From 67ed0253791b39a59de25d70937b528186296b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Fri, 8 Apr 2016 08:51:45 +0200 Subject: [PATCH 17/24] 8152989: serviceability/tmtools/jstat/GcCauseTest02.java fails with OOME Reviewed-by: dsamersoff, sjohanss, dfazunen --- .../serviceability/tmtools/jstat/GcCapacityTest.java | 4 ++-- .../serviceability/tmtools/jstat/GcCauseTest01.java | 2 +- .../serviceability/tmtools/jstat/GcCauseTest02.java | 4 ++-- .../serviceability/tmtools/jstat/GcCauseTest03.java | 4 ++-- .../test/serviceability/tmtools/jstat/GcNewTest.java | 4 ++-- .../test/serviceability/tmtools/jstat/GcTest01.java | 2 +- .../test/serviceability/tmtools/jstat/GcTest02.java | 10 ++-------- 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java index 6ec4db9829b..ec6d1bc2f4d 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java @@ -27,13 +27,13 @@ import utils.*; * @test * @summary Test checks the consistency of the output * displayed with jstat -gccapacity. - * @ignore 8149778 * @library /test/lib/share/classes * @library ../share * @requires vm.opt.ExplicitGCInvokesConcurrent != true * @build common.* * @build utils.* - * @run main/othervm -XX:+UsePerfData GcCapacityTest + * @ignore 8149778 + * @run main/othervm -XX:+UsePerfData -Xmx128M GcCapacityTest */ public class GcCapacityTest { diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java index 55ee941e38c..508b7865a3c 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java @@ -34,7 +34,7 @@ * @build common.* * @build utils.* * - * @run main/othervm -XX:+UsePerfData GcCauseTest01 + * @run main/othervm -XX:+UsePerfData -Xmx128M GcCauseTest01 */ import utils.*; diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java index bc8f0058034..95200d453c5 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -32,7 +32,7 @@ * @build common.* * @build utils.* * - * @run main/othervm -XX:+UsePerfData -Xms128M -XX:MaxMetaspaceSize=128M GcCauseTest02 + * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcCauseTest02 */ import utils.*; diff --git a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java index 1ebb98b00b5..94514d4b634 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -32,7 +32,7 @@ * @build common.* * @build utils.* * - * @run main/othervm -XX:+UsePerfData -Xms128M -XX:MaxMetaspaceSize=128M GcCauseTest03 + * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcCauseTest03 */ import utils.*; diff --git a/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java b/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java index e91ee8ecdf6..bdb06c1e6b2 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -33,7 +33,7 @@ import utils.*; * @library ../share * @build common.* * @build utils.* - * @run main/othervm -XX:+UsePerfData GcNewTest + * @run main/othervm -XX:+UsePerfData -Xmx128M GcNewTest */ public class GcNewTest { diff --git a/hotspot/test/serviceability/tmtools/jstat/GcTest01.java b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java index ee731adb144..2a6b0c544a8 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcTest01.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java @@ -37,7 +37,7 @@ * @build common.* * @build utils.* * - * @run main/othervm -XX:+UsePerfData GcTest01 + * @run main/othervm -XX:+UsePerfData -Xmx128M GcTest01 */ import utils.*; diff --git a/hotspot/test/serviceability/tmtools/jstat/GcTest02.java b/hotspot/test/serviceability/tmtools/jstat/GcTest02.java index c2e55229688..bcdc258c934 100644 --- a/hotspot/test/serviceability/tmtools/jstat/GcTest02.java +++ b/hotspot/test/serviceability/tmtools/jstat/GcTest02.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -32,7 +32,7 @@ import utils.*; * @library ../share * @build common.* * @build utils.* - * @run main/othervm -XX:+UsePerfData -Xms128M -XX:MaxMetaspaceSize=128M GcTest02 + * @run main/othervm -XX:+UsePerfData -Xmx128M -XX:MaxMetaspaceSize=128M GcTest02 */ public class GcTest02 { @@ -58,10 +58,4 @@ public class GcTest02 { // Assert that space has been utilized acordingly JstatResults.assertSpaceUtilization(measurement2, targetMemoryUsagePercent); } - - private static void assertThat(boolean result, String message) { - if (!result) { - throw new RuntimeException(message); - }; - } } From 890207217fbce11ee25a3bc61643b9ece636458c Mon Sep 17 00:00:00 2001 From: Frederic Parain Date: Fri, 8 Apr 2016 00:38:00 -0700 Subject: [PATCH 18/24] 8146093: [sparc only] compiler/interpreter/7116216/StackOverflow.java Program terminates with signal 11, Segmentation fault. in __1cLRegisterMap2t6MpnKJavaThread_b_v_ () Reviewed-by: dcubed, coleenp --- .../sparc/vm/templateInterpreterGenerator_sparc.cpp | 2 +- .../src/share/vm/interpreter/interpreterRuntime.cpp | 13 +------------ .../src/share/vm/interpreter/interpreterRuntime.hpp | 2 -- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp index 153bd2b2319..008fcee7a6a 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp @@ -616,7 +616,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe // compute the beginning of the protected zone minus the requested frame size __ sub( Rscratch, Rscratch2, Rscratch ); - __ set( JavaThread::stack_red_zone_size() + JavaThread::stack_yellow_zone_size(), Rscratch2 ); + __ set(MAX2(JavaThread::stack_shadow_zone_size(), JavaThread::stack_guard_zone_size()), Rscratch2 ); __ add( Rscratch, Rscratch2, Rscratch ); // Add in the size of the frame (which is the same as subtracting it from the diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 2de3339c33e..4ddc09a77eb 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -313,18 +313,7 @@ IRT_ENTRY(void, InterpreterRuntime::throw_StackOverflowError(JavaThread* thread) THROW_HANDLE(exception); IRT_END -IRT_ENTRY(address, InterpreterRuntime::check_ReservedStackAccess_annotated_methods(JavaThread* thread)) - frame fr = thread->last_frame(); - assert(fr.is_java_frame(), "Must be a Java frame"); - frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); - if (activation.sp() != NULL) { - thread->disable_stack_reserved_zone(); - thread->set_reserved_stack_activation((address)activation.unextended_sp()); - } - return (address)activation.sp(); -IRT_END - - IRT_ENTRY(void, InterpreterRuntime::throw_delayed_StackOverflowError(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_delayed_StackOverflowError(JavaThread* thread)) Handle exception = get_preinitialized_exception( SystemDictionary::StackOverflowError_klass(), CHECK); diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp index 02fc2cf3b2e..2039adba2a0 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp @@ -91,8 +91,6 @@ class InterpreterRuntime: AllStatic { // Quicken instance-of and check-cast bytecodes static void quicken_io_cc(JavaThread* thread); - static address check_ReservedStackAccess_annotated_methods(JavaThread* thread); - // Exceptions thrown by the interpreter static void throw_AbstractMethodError(JavaThread* thread); static void throw_IncompatibleClassChangeError(JavaThread* thread); From 87d68625afddda5556bf5c9bcb274002fb34bb38 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 8 Apr 2016 13:14:23 +0200 Subject: [PATCH 19/24] 8152666: The new Hotspot Build System Co-authored-by: Magnus Ihse Bursie Co-authored-by: Ingemar Aberg Reviewed-by: ihse, dcubed, erikj --- hotspot/make/Makefile | 18 +- hotspot/make/aix/makefiles/trace.make | 10 +- hotspot/make/bsd/makefiles/trace.make | 10 +- hotspot/make/linux/makefiles/gcc.make | 4 +- hotspot/make/linux/makefiles/trace.make | 10 +- hotspot/make/linux/makefiles/zero.make | 5 + hotspot/make/solaris/makefiles/dtrace.make | 2 +- hotspot/make/solaris/makefiles/trace.make | 10 +- hotspot/make/windows/makefiles/debug.make | 6 +- hotspot/make/windows/makefiles/fastdebug.make | 6 +- hotspot/make/windows/makefiles/product.make | 7 +- hotspot/make/windows/makefiles/trace.make | 6 + hotspot/make/windows/makefiles/vm.make | 4 +- hotspot/makefiles/BuildHotspot.gmk | 54 ++++ hotspot/makefiles/Dist.gmk | 239 +++++++++++++++++ hotspot/makefiles/HotspotCommon.gmk | 45 ++++ hotspot/makefiles/gensrc/GenerateSources.gmk | 75 ++++++ hotspot/makefiles/gensrc/GensrcAdlc.gmk | 192 ++++++++++++++ hotspot/makefiles/gensrc/GensrcDtrace.gmk | 56 ++++ hotspot/makefiles/gensrc/GensrcJvmti.gmk | 174 +++++++++++++ hotspot/makefiles/ide/CreateVSProject.gmk | 153 +++++++++++ .../makefiles/lib/CompileDtracePostJvm.gmk | 217 ++++++++++++++++ hotspot/makefiles/lib/CompileDtracePreJvm.gmk | 36 +++ hotspot/makefiles/lib/CompileJvm.gmk | 242 ++++++++++++++++++ hotspot/makefiles/lib/CompileLibjsig.gmk | 106 ++++++++ hotspot/makefiles/lib/CompileLibraries.gmk | 42 +++ hotspot/makefiles/lib/JvmFeatures.gmk | 144 +++++++++++ hotspot/makefiles/lib/JvmMapfile.gmk | 172 +++++++++++++ hotspot/makefiles/lib/JvmOverrideFiles.gmk | 168 ++++++++++++ .../mapfiles/libjsig/mapfile-vers-solaris | 38 +++ .../makefiles/mapfiles/libjvm_db/mapfile-vers | 38 +++ .../mapfiles/libjvm_dtrace/mapfile-vers | 37 +++ hotspot/makefiles/symbols/symbols-aix | 27 ++ hotspot/makefiles/symbols/symbols-aix-debug | 26 ++ hotspot/makefiles/symbols/symbols-linux | 27 ++ hotspot/makefiles/symbols/symbols-macosx | 24 ++ hotspot/makefiles/symbols/symbols-shared | 35 +++ hotspot/makefiles/symbols/symbols-solaris | 25 ++ .../symbols/symbols-solaris-dtrace-compiler1 | 34 +++ .../symbols/symbols-solaris-dtrace-compiler2 | 36 +++ hotspot/makefiles/symbols/symbols-unix | 195 ++++++++++++++ 41 files changed, 2714 insertions(+), 41 deletions(-) create mode 100644 hotspot/makefiles/BuildHotspot.gmk create mode 100644 hotspot/makefiles/Dist.gmk create mode 100644 hotspot/makefiles/HotspotCommon.gmk create mode 100644 hotspot/makefiles/gensrc/GenerateSources.gmk create mode 100644 hotspot/makefiles/gensrc/GensrcAdlc.gmk create mode 100644 hotspot/makefiles/gensrc/GensrcDtrace.gmk create mode 100644 hotspot/makefiles/gensrc/GensrcJvmti.gmk create mode 100644 hotspot/makefiles/ide/CreateVSProject.gmk create mode 100644 hotspot/makefiles/lib/CompileDtracePostJvm.gmk create mode 100644 hotspot/makefiles/lib/CompileDtracePreJvm.gmk create mode 100644 hotspot/makefiles/lib/CompileJvm.gmk create mode 100644 hotspot/makefiles/lib/CompileLibjsig.gmk create mode 100644 hotspot/makefiles/lib/CompileLibraries.gmk create mode 100644 hotspot/makefiles/lib/JvmFeatures.gmk create mode 100644 hotspot/makefiles/lib/JvmMapfile.gmk create mode 100644 hotspot/makefiles/lib/JvmOverrideFiles.gmk create mode 100644 hotspot/makefiles/mapfiles/libjsig/mapfile-vers-solaris create mode 100644 hotspot/makefiles/mapfiles/libjvm_db/mapfile-vers create mode 100644 hotspot/makefiles/mapfiles/libjvm_dtrace/mapfile-vers create mode 100644 hotspot/makefiles/symbols/symbols-aix create mode 100644 hotspot/makefiles/symbols/symbols-aix-debug create mode 100644 hotspot/makefiles/symbols/symbols-linux create mode 100644 hotspot/makefiles/symbols/symbols-macosx create mode 100644 hotspot/makefiles/symbols/symbols-shared create mode 100644 hotspot/makefiles/symbols/symbols-solaris create mode 100644 hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler1 create mode 100644 hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler2 create mode 100644 hotspot/makefiles/symbols/symbols-unix diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index 4312c797579..db2b96e25e0 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -237,19 +237,21 @@ else $(MAKE_ARGS) $(VM_TARGET) endif +# NOTE: Changes in this file was just to facilitate comparison when +# developing the new build, and should not be integrated. generic_buildcore: $(HOTSPOT_SCRIPT) -ifeq ($(HS_ARCH),ppc) - ifeq ($(ARCH_DATA_MODEL),64) +#ifeq ($(HS_ARCH),ppc) +# ifeq ($(ARCH_DATA_MODEL),64) $(MKDIR) -p $(OUTPUTDIR) $(CD) $(OUTPUTDIR); \ $(MAKE) -f $(ABS_OS_MAKEFILE) \ $(MAKE_ARGS) $(VM_TARGET) - else - @$(ECHO) "No ($(VM_TARGET)) for ppc ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)" - endif -else - @$(ECHO) "No ($(VM_TARGET)) for $(HS_ARCH)" -endif +# else +# @$(ECHO) "No ($(VM_TARGET)) for ppc ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)" +# endif +#else +# @$(ECHO) "No ($(VM_TARGET)) for $(HS_ARCH)" +#endif generic_buildzero: $(HOTSPOT_SCRIPT) $(MKDIR) -p $(OUTPUTDIR) diff --git a/hotspot/make/aix/makefiles/trace.make b/hotspot/make/aix/makefiles/trace.make index f4f9e7f8e6c..f17e75e1f4f 100644 --- a/hotspot/make/aix/makefiles/trace.make +++ b/hotspot/make/aix/makefiles/trace.make @@ -53,13 +53,13 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) - TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) diff --git a/hotspot/make/bsd/makefiles/trace.make b/hotspot/make/bsd/makefiles/trace.make index af46df58ce0..37df4425f50 100644 --- a/hotspot/make/bsd/makefiles/trace.make +++ b/hotspot/make/bsd/makefiles/trace.make @@ -53,13 +53,13 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) - TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index a2e5c6c03b6..75dcaeb2c34 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -221,7 +221,7 @@ ifeq ($(USE_CLANG),) ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" # GCC < 4.3 WARNING_FLAGS += -Wconversion - endif + endif ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 8 \) \))" "1" # GCC >= 4.8 # This flag is only known since GCC 4.3. Gcc 4.8 contains a fix so that with templates no @@ -260,7 +260,7 @@ endif OPT_CFLAGS = $(OPT_CFLAGS/$(OPT_CFLAGS_DEFAULT)) $(OPT_EXTRAS) -# Variable tracking size limit exceeded for VMStructs::init() +# Variable tracking size limit exceeded for VMStructs::init() ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "1" # GCC >= 4.3 # Gcc 4.1.2 does not support this flag, nor does it have problems compiling the file. diff --git a/hotspot/make/linux/makefiles/trace.make b/hotspot/make/linux/makefiles/trace.make index 09cb921094e..2209716d35b 100644 --- a/hotspot/make/linux/makefiles/trace.make +++ b/hotspot/make/linux/makefiles/trace.make @@ -53,13 +53,13 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) - TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) diff --git a/hotspot/make/linux/makefiles/zero.make b/hotspot/make/linux/makefiles/zero.make index 0270711f5cb..622710f4dfa 100644 --- a/hotspot/make/linux/makefiles/zero.make +++ b/hotspot/make/linux/makefiles/zero.make @@ -30,3 +30,8 @@ TYPE = ZERO # Install libjvm.so, etc in in server directory. VM_SUBDIR = server + +# Disable trace for zero builds +# NOTE: This is used for simple comparison with the new build system, and +# should not be merged into mainline with build-infra. +INCLUDE_TRACE := false diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index 376732d0e6b..2c65059a213 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -270,7 +270,7 @@ $(DTRACE.o): $(DTRACE).d $(DTraced_Files) @echo $(LOG_INFO) Compiling $(DTRACE).d $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -G -xlazyload -o $@ -s $(DTRACE).d \ - $(DTraced_Files) ||\ + $(sort $(DTraced_Files)) ||\ STATUS=$$?;\ if [ x"$$STATUS" = x"1" ]; then \ if [ x`uname -r` = x"5.10" -a \ diff --git a/hotspot/make/solaris/makefiles/trace.make b/hotspot/make/solaris/makefiles/trace.make index ed7046295b3..effe34061ce 100644 --- a/hotspot/make/solaris/makefiles/trace.make +++ b/hotspot/make/solaris/makefiles/trace.make @@ -53,13 +53,13 @@ VPATH += $(Src_Dirs_V:%=%:) TraceGeneratedNames = \ traceEventClasses.hpp \ - traceEventIds.hpp \ - traceTypes.hpp + traceEventIds.hpp \ + traceTypes.hpp ifeq ($(HAS_ALT_SRC), true) - TraceGeneratedNames += \ - traceRequestables.hpp \ - traceEventControl.hpp +TraceGeneratedNames += \ + traceRequestables.hpp \ + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) diff --git a/hotspot/make/windows/makefiles/debug.make b/hotspot/make/windows/makefiles/debug.make index f2ecd269887..3ad45627467 100644 --- a/hotspot/make/windows/makefiles/debug.make +++ b/hotspot/make/windows/makefiles/debug.make @@ -48,10 +48,10 @@ HS_BUILD_ID=$(HOTSPOT_VERSION_STRING)-debug # Force resources to be rebuilt every time $(Res_Files): FORCE +# NOTE: Changes in this file was just to give a proper command line when linking +# for use when developing the new build, and should not be integrated. $(AOUT): $(Res_Files) $(Obj_Files) vm.def - $(LD) @<< - $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) -<< + $(LD) $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) !if "$(MT)" != "" # The previous link command created a .manifest file that we want to # insert into the linked artifact so we do not need to track it diff --git a/hotspot/make/windows/makefiles/fastdebug.make b/hotspot/make/windows/makefiles/fastdebug.make index cbcfd5abb04..ea6fc41a42a 100644 --- a/hotspot/make/windows/makefiles/fastdebug.make +++ b/hotspot/make/windows/makefiles/fastdebug.make @@ -47,10 +47,10 @@ HS_BUILD_ID=$(HOTSPOT_VERSION_STRING)-fastdebug # Force resources to be rebuilt every time $(Res_Files): FORCE +# NOTE: Changes in this file was just to give a proper command line when linking +# for use when developing the new build, and should not be integrated. $(AOUT): $(Res_Files) $(Obj_Files) vm.def - $(LD) @<< - $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) -<< + $(LD) $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) !if "$(MT)" != "" # The previous link command created a .manifest file that we want to # insert into the linked artifact so we do not need to track it diff --git a/hotspot/make/windows/makefiles/product.make b/hotspot/make/windows/makefiles/product.make index cd3a4e70bc5..09e750acc07 100644 --- a/hotspot/make/windows/makefiles/product.make +++ b/hotspot/make/windows/makefiles/product.make @@ -51,10 +51,11 @@ HS_BUILD_ID=$(HOTSPOT_VERSION_STRING) # Force resources to be rebuilt every time $(Res_Files): FORCE +# NOTE: Changes in this file was just to give a proper command line when linking +# for use when developing the new build, and should not be integrated. $(AOUT): $(Res_Files) $(Obj_Files) vm.def - $(LD) @<< - $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) -<< + $(LD) $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) + !if "$(MT)" != "" # The previous link command created a .manifest file that we want to # insert into the linked artifact so we do not need to track it diff --git a/hotspot/make/windows/makefiles/trace.make b/hotspot/make/windows/makefiles/trace.make index eecc890663f..d52391386d0 100644 --- a/hotspot/make/windows/makefiles/trace.make +++ b/hotspot/make/windows/makefiles/trace.make @@ -41,6 +41,12 @@ HAS_ALT_SRC = true !endif !endif +!ifndef OPENJDK +!if EXISTS($(TraceAltSrcDir)) +HAS_ALT_SRC = true +!endif +!endif + TraceGeneratedNames = \ traceEventClasses.hpp \ traceEventIds.hpp \ diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index fd42111866b..a1391a04413 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -305,8 +305,10 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi # This guy should remain a single colon rule because # otherwise we can't specify the output filename. +# NOTE: Changes in this file was just to give a proper command line when linking +# for use when developing the new build, and should not be integrated. {$(COMMONSRC)\os\windows\vm}.rc.res: - @$(RC) $(RC_FLAGS) /fo"$@" $< + $(RC) $(RC_FLAGS) /fo"$@" $< {$(COMMONSRC)\cpu\$(Platform_arch)\vm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< diff --git a/hotspot/makefiles/BuildHotspot.gmk b/hotspot/makefiles/BuildHotspot.gmk new file mode 100644 index 00000000000..4ae7b84c387 --- /dev/null +++ b/hotspot/makefiles/BuildHotspot.gmk @@ -0,0 +1,54 @@ +# +# Copyright (c) 2015, 2016 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# This must be the first rule +default: all + +include $(SPEC) +include MakeBase.gmk + +VARIANT_TARGETS := $(foreach v, $(JVM_VARIANTS), variant-$v) +VARIANT_GENSRC_TARGETS := $(addsuffix -gensrc, $(VARIANT_TARGETS)) +VARIANT_LIBS_TARGETS := $(addsuffix -libs, $(VARIANT_TARGETS)) + +$(VARIANT_GENSRC_TARGETS): variant-%-gensrc: + $(call LogWarn, Building JVM variant '$*' with features '$(JVM_FEATURES_$*)') + +$(MAKE) -f gensrc/GenerateSources.gmk JVM_VARIANT=$* + +$(VARIANT_LIBS_TARGETS): variant-%-libs: variant-%-gensrc + +$(MAKE) -f lib/CompileLibraries.gmk JVM_VARIANT=$* + +$(VARIANT_TARGETS): variant-%: variant-%-gensrc variant-%-libs + +jsig: + +$(MAKE) -f lib/CompileLibjsig.gmk + +dist: $(VARIANT_TARGETS) jsig + +$(MAKE) -f Dist.gmk + +all: dist + +.PHONY: $(VARIANT_TARGETS) $(VARIANT_GENSRC_TARGETS) $(VARIANT_LIBS_TARGETS) \ + jsig dist all diff --git a/hotspot/makefiles/Dist.gmk b/hotspot/makefiles/Dist.gmk new file mode 100644 index 00000000000..bfe3daf2062 --- /dev/null +++ b/hotspot/makefiles/Dist.gmk @@ -0,0 +1,239 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +################################################################################ +# Copy the generated output into well-defined places in the dist directory. + +# This must be the first rule +default: all + +include $(SPEC) +include MakeBase.gmk + +$(eval $(call IncludeCustomExtension, hotspot, Dist.gmk)) + +DIST_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/dist + +# Unfortunately, all platforms have different target subdirs. +ifeq ($(OPENJDK_TARGET_OS), windows) + LIB_SUBDIR := bin +else ifeq ($(OPENJDK_TARGET_OS), macosx) + LIB_SUBDIR := lib +else + LIB_SUBDIR := lib$(OPENJDK_TARGET_CPU_LIBDIR) +endif + +################################################################################ +# Functions to setup copying of files for variants + +# Support macro for SetupDistLibFile +define macosx_universalize + $(MKDIR) -p $(@D) + $(LIPO) -create -output $@ $< +endef + +################################################################################ +# Setup make rules to copy a native library and associated data. +# +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. +# +# Remaining parameters are named arguments. These include: +# NAME -- The base name of the native library (e.g. 'jvm') +# VARIANT -- The variant to copy from +# VARIANT_TARGET_DIR -- The variant target sub dir, with trailing slash, optional +SetupDistLibFile = $(NamedParamsMacroTemplate) +define SetupDistLibFileBody + ifneq ($$($1_VARIANT), ) + $1_SRC_DIR := $$(HOTSPOT_OUTPUTDIR)/variant-$$($1_VARIANT)/lib$$($1_NAME) + else + $1_SRC_DIR := $$(HOTSPOT_OUTPUTDIR)/lib$$($1_NAME) + endif + $1_LIB_NAME := $(LIBRARY_PREFIX)$$($1_NAME) + $1_TARGET_DIR := $$(DIST_OUTPUTDIR)/$$(LIB_SUBDIR)/$$($1_VARIANT_TARGET_DIR) + + ifeq ($(OPENJDK_TARGET_OS), macosx) + # We must use the 'universalize' macro to run lipo on shared libraries, at + # least until JDK-8069540 is fixed. + $1_MACRO := macosx_universalize + endif + + # Copy the the native library. + $$(eval $$(call SetupCopyFiles, $1_COPY_LIB, \ + DEST := $$($1_TARGET_DIR), \ + MACRO := $$($1_MACRO), \ + FILES := $$(wildcard \ + $$($1_SRC_DIR)/$$($1_LIB_NAME)$(SHARED_LIBRARY_SUFFIX)), \ + )) + + TARGETS += $$($1_COPY_LIB) + + # Copy related data (debug symbols, static-build symbols file etc) + $$(eval $$(call SetupCopyFiles, $1_COPY_FILES, \ + DEST := $$($1_TARGET_DIR), \ + FILES := $$(wildcard \ + $$(addprefix $$($1_SRC_DIR)/$$($1_LIB_NAME), \ + .diz .debuginfo .pdb .map .symbols)), \ + )) + + TARGETS += $$($1_COPY_FILES) + + ifeq ($(OPENJDK_TARGET_OS), macosx) + # Debug symbols on macosx is a directory, not a single file, per library. + $1_DSYM_SRC := $$($1_SRC_DIR)/$$($1_LIB_NAME)$(SHARED_LIBRARY_SUFFIX).dSYM) + ifneq ($$(wildcard $$($1_DSYM_SRC)), ) + $$(eval $$(call SetupCopyFiles, $1_COPY_DSYM_DIR, \ + DEST := $$($1_TARGET_DIR), \ + SRC := $$($1_SRC_DIR), \ + FILES := $$(shell $(FIND) $$($1_DSYM_SRC) -type f), \ + )) + TARGETS += $$($1_COPY_DSYM_DIR) + endif + endif +endef + +################################################################################ +# Copy common files, which are independent on the jvm variant(s) being built. +# For files that were generated during the build, we assume all versions of +# these files are identical, and just pick one arbitrarily to use as source. + +ANY_JVM_VARIANT := $(firstword $(JVM_VARIANTS)) +JVM_VARIANT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/variant-$(ANY_JVM_VARIANT) + +### Copy platform-independent .h files +INCLUDE_FILES_SRC_DIR := $(HOTSPOT_TOPDIR)/src/share/vm +$(eval $(call SetupCopyFiles, COPY_INCLUDE, \ + SRC := $(INCLUDE_FILES_SRC_DIR), \ + DEST := $(DIST_OUTPUTDIR)/include, \ + FLATTEN := true, \ + FILES := $(INCLUDE_FILES_SRC_DIR)/prims/jni.h \ + $(INCLUDE_FILES_SRC_DIR)/code/jvmticmlr.h \ + $(INCLUDE_FILES_SRC_DIR)/services/jmm.h)) + +TARGETS += $(COPY_INCLUDE) + +### Copy jni_md.h + +# This might have been defined in a custom extension +ifeq ($(JNI_MD_H_SRC), ) + JNI_MD_H_SRC := $(HOTSPOT_TOPDIR)/src/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/vm/jni_$(HOTSPOT_TARGET_CPU_ARCH).h +endif + +ifeq ($(OPENJDK_TARGET_OS), macosx) + # NOTE: This should most likely be darwin, but the old hotspot build uses bsd + JNI_MD_SUBDIR := bsd +else ifeq ($(OPENJDK_TARGET_OS), windows) + JNI_MD_SUBDIR := win32 +else + JNI_MD_SUBDIR := $(OPENJDK_TARGET_OS) +endif + +# SetupCopyFiles is not used here since it's non-trivial to copy a single +# file with a different target name. +$(DIST_OUTPUTDIR)/include/$(JNI_MD_SUBDIR)/jni_md.h: $(JNI_MD_H_SRC) + $(call LogInfo, Copying hotspot/dist/include/$(JNI_MD_SUBDIR)/jni_md.h) + $(install-file) + +TARGETS += $(DIST_OUTPUTDIR)/include/$(JNI_MD_SUBDIR)/jni_md.h + +$(eval $(call SetupCopyFiles, COPY_JVMTI_H, \ + DEST := $(DIST_OUTPUTDIR)/include, \ + FLATTEN := true, \ + FILES := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h)) + +TARGETS += $(COPY_JVMTI_H) + +# NOTE: In the old build, this file was not copied on Windows. +ifneq ($(OPENJDK_TARGET_OS), windows) + $(eval $(call SetupCopyFiles, COPY_JVMTI_HTML, \ + DEST := $(DIST_OUTPUTDIR)/docs/platform/jvmti, \ + FILES := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.html)) +endif + +TARGETS += $(COPY_JVMTI_HTML) + +ifeq ($(OPENJDK_TARGET_OS), windows) + $(eval $(call SetupCopyFiles, COPY_JVM_LIB, \ + DEST := $(DIST_OUTPUTDIR)/lib, \ + FILES :=$(JVM_VARIANT_OUTPUTDIR)/libjvm/objs/jvm.lib)) + + TARGETS += $(COPY_JVM_LIB) +endif + +# Copy libjsig, if it exists +$(eval $(call SetupDistLibFile, DIST_jsig, \ + NAME := jsig, \ +)) + +################################################################################ +# Copy variant-specific files + +# Setup make rules to copy a single variant to dist. +# $1: The name of the variant +define SetupDistForVariant + ifneq ($$(filter client minimal, $1), ) + VARIANT_TARGET_DIR := $1 + else + # Use 'server' as default target directory name for all other variants. + VARIANT_TARGET_DIR := server + endif + + $$(eval $$(call SetupDistLibFile, DIST_$(strip $1)_jvm, \ + NAME := jvm, \ + VARIANT := $1, \ + VARIANT_TARGET_DIR := $$(VARIANT_TARGET_DIR)/, \ + )) + + # Copy the dtrace libraries, if they exist + $$(eval $$(call SetupDistLibFile, DIST_$(strip $1)_jvm_db, \ + NAME := jvm_db, \ + VARIANT := $1, \ + VARIANT_TARGET_DIR := $$(VARIANT_TARGET_DIR)/, \ + )) + + $$(eval $$(call SetupDistLibFile, DIST_$(strip $1)_jvm_dtrace, \ + NAME := jvm_dtrace, \ + VARIANT := $1, \ + VARIANT_TARGET_DIR := $$(VARIANT_TARGET_DIR)/, \ + )) + + # Copy the Xusage.txt file + $$(eval $$(call SetupCopyFiles, DIST_$(strip $1)_Xusage, \ + DEST := $$(DIST_OUTPUTDIR)/$$(LIB_SUBDIR)/$(strip $1), \ + FILES := $$(HOTSPOT_OUTPUTDIR)/variant-$(strip $1)/support/misc/Xusage.txt, \ + )) + + TARGETS += $$(DIST_$(strip $1)_Xusage) +endef + +$(foreach variant, $(JVM_VARIANTS), \ + $(eval $(call SetupDistForVariant, $(variant))) \ +) + +################################################################################ + +all: $(TARGETS) + +.PHONY: all diff --git a/hotspot/makefiles/HotspotCommon.gmk b/hotspot/makefiles/HotspotCommon.gmk new file mode 100644 index 00000000000..1df3f4fa9b3 --- /dev/null +++ b/hotspot/makefiles/HotspotCommon.gmk @@ -0,0 +1,45 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +ifeq ($(JVM_VARIANT), ) + $(error This makefile must be called with JVM_VARIANT set) +endif + +JVM_VARIANT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/variant-$(JVM_VARIANT) +JVM_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm +JVM_SUPPORT_DIR := $(JVM_VARIANT_OUTPUTDIR)/support + +DTRACE_SUPPORT_DIR := $(JVM_SUPPORT_DIR)/dtrace + +################################################################################ + +# Test if a feature is available in the present build of JVM_VARIANT. Will return +# 'true' or 'false'. +# $1 - the feature to test for +check-jvm-feature = \ + $(strip \ + $(if $(filter-out $(VALID_JVM_FEATURES), $1), \ + $(error Internal error: Invalid feature tested: $1)) \ + $(if $(filter $1, $(JVM_FEATURES_$(JVM_VARIANT))), true, false)) diff --git a/hotspot/makefiles/gensrc/GenerateSources.gmk b/hotspot/makefiles/gensrc/GenerateSources.gmk new file mode 100644 index 00000000000..b91f2d0c864 --- /dev/null +++ b/hotspot/makefiles/gensrc/GenerateSources.gmk @@ -0,0 +1,75 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include NativeCompilation.gmk +include TextFileProcessing.gmk + +include HotspotCommon.gmk + +# The real work is done in these files + +include gensrc/GensrcAdlc.gmk +include gensrc/GensrcDtrace.gmk +include gensrc/GensrcJvmti.gmk + +$(eval $(call IncludeCustomExtension, hotspot, gensrc/GenerateSources.gmk)) + +# While technically the rules below are "gendata" which can be done in parallel +# with native compilation, let's keep it here for simplicity. + +# The Xusage.txt file needs to have platform specific path separator +$(eval $(call SetupTextFileProcessing, CREATE_XUSAGE, \ + SOURCE_FILES := $(HOTSPOT_TOPDIR)/src/share/vm/Xusage.txt, \ + OUTPUT_FILE := $(JVM_SUPPORT_DIR)/misc/Xusage.txt, \ + REPLACEMENTS := separated by ;> => separated by $(PATH_SEP)> ; , \ +)) + +TARGETS += $(CREATE_XUSAGE) + +# Setup the hotspot launcher script for developer use +$(eval $(call SetupTextFileProcessing, CREATE_HOTSPOT_LAUNCHER, \ + SOURCE_FILES := $(HOTSPOT_TOPDIR)/make/hotspot.script, \ + OUTPUT_FILE := $(JVM_OUTPUTDIR)/hotspot, \ + REPLACEMENTS := \ + @@LIBARCH@@ => $(OPENJDK_TARGET_CPU_LEGACY_LIB) ; \ + @@JDK_IMPORT_PATH@@ => $(JDK_OUTPUTDIR) ; , \ +)) + +CHMOD_HOTSPOT_LAUNCHER := $(JVM_VARIANT_OUTPUTDIR)/libjvm/_hotspot-script-chmod.marker + +$(CHMOD_HOTSPOT_LAUNCHER): $(CREATE_HOTSPOT_LAUNCHER) + $(CHMOD) +x $< + $(TOUCH) $@ + +TARGETS += $(CREATE_HOTSPOT_LAUNCHER) $(CHMOD_HOTSPOT_LAUNCHER) + +all: $(TARGETS) + +.PHONY: all diff --git a/hotspot/makefiles/gensrc/GensrcAdlc.gmk b/hotspot/makefiles/gensrc/GensrcAdlc.gmk new file mode 100644 index 00000000000..eb58ac7737c --- /dev/null +++ b/hotspot/makefiles/gensrc/GensrcAdlc.gmk @@ -0,0 +1,192 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +$(eval $(call IncludeCustomExtension, hotspot, gensrc/GensrcAdlc.gmk)) + +ifeq ($(call check-jvm-feature, compiler2), true) + + ADLC_SUPPORT_DIR := $(JVM_SUPPORT_DIR)/adlc + + ############################################################################## + # Build the ad compiler (the adlc build tool) + + # Flags depending on the build platform/tool chain + # NOTE: No optimization or debug flags set here + ifeq ($(OPENJDK_BUILD_OS), linux) + ADLC_CFLAGS := -fno-exceptions -DLINUX + else ifeq ($(OPENJDK_BUILD_OS), solaris) + ADLC_LDFLAGS := -m64 + ADLC_CFLAGS := -m64 + ADLC_CFLAGS_WARNINGS := +w + else ifeq ($(OPENJDK_BUILD_OS), aix) + # FIXME: Not implemented. These flags are likely, however + # ADLC_LDFLAGS := -q64 + # ADLC_CFLAGS := -qnortti -qnoeh -q64 + else ifeq ($(OPENJDK_BUILD_OS), windows) + ADLC_LDFLAGS := -nologo + ADLC_CFLAGS := -nologo -EHsc + # NOTE: The old build also have -D_CRT_SECURE_NO_DEPRECATE but it doesn't + # seem needed any more. + ADLC_CFLAGS_WARNINGS := -W3 -D_CRT_SECURE_NO_WARNINGS + endif + + # NOTE: The old build didn't set -DASSERT for windows but it doesn't seem to + # hurt. + ADLC_CFLAGS += -DASSERT + + ADLC_CFLAGS += -D$(HOTSPOT_TARGET_CPU_DEFINE) + + ADLC_CFLAGS += -I$(HOTSPOT_TOPDIR)/src/share/vm + + $(eval $(call SetupNativeCompilation, BUILD_ADLC, \ + TOOLCHAIN := TOOLCHAIN_BUILD_LINK_CXX, \ + SRC := $(HOTSPOT_TOPDIR)/src/share/vm/adlc, \ + EXTRA_FILES := $(HOTSPOT_TOPDIR)/src/share/vm/opto/opcodes.cpp, \ + CFLAGS := $(ADLC_CFLAGS) $(ADLC_CFLAGS_WARNINGS), \ + LDFLAGS := $(ADLC_LDFLAGS), \ + LIBS := $(ADLC_LIBS), \ + OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/adlc/objs, \ + OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/adlc, \ + PROGRAM := adlc, \ + DEBUG_SYMBOLS := false, \ + DISABLED_WARNINGS_clang := parentheses tautological-compare, \ + DISABLED_WARNINGS_solstudio := notemsource, \ + )) + + ADLC_TOOL := $(BUILD_ADLC_TARGET) + + ############################################################################## + # Transform the ad source files into C++ source files using adlc + + # Setup flags for the adlc build tool (ADLCFLAGS). + ADLCFLAGS += -q -T + + # ADLC flags depending on target OS + ifeq ($(OPENJDK_TARGET_OS), linux) + ADLCFLAGS += -DLINUX=1 -D_GNU_SOURCE=1 + else ifeq ($(OPENJDK_TARGET_OS), solaris) + ADLCFLAGS += -DSOLARIS=1 -DSPARC_WORKS=1 + else ifeq ($(OPENJDK_TARGET_OS), aix) + # FIXME: Not implemented + else ifeq ($(OPENJDK_TARGET_OS), macosx) + ADLCFLAGS += -D_ALLBSD_SOURCE=1 -D_GNU_SOURCE=1 + endif + + ifneq ($(OPENJDK_TARGET_OS), windows) + # NOTE: Windows adlc flags was different in the old build. Is this really + # correct? + + # -g makes #line directives in the generated C++ files. + ADLCFLAGS += -g + + ADLCFLAGS += -D$(HOTSPOT_TARGET_CPU_DEFINE)=1 + endif + + # This generates checks in the generated C++ files that _LP64 is correctly + # (un)defined when compiling them. + ifeq ($(OPENJDK_TARGET_CPU_BITS), 64) + ADLCFLAGS += -D_LP64=1 + else + ADLCFLAGS += -U_LP64 + endif + + ############################################################################## + # Concatenate all ad source files into a single file, which will be fed to + # adlc. Also include a #line directive at the start of every included file + # (after the initial header block), stating the original source file name. + # + # Normally, debugging is done directly on the ad_*.cpp files, but the + # #line directives in those files will be pointing back to .ad. + + # AD_SRC_ROOTS might have been added to by a custom extension + AD_SRC_ROOTS += $(HOTSPOT_TOPDIR)/src + + AD_SRC_FILES := $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/vm/$(HOTSPOT_TARGET_CPU).ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/vm/$(HOTSPOT_TARGET_CPU_ARCH).ad \ + $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH)/vm/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH).ad \ + ))) + + SINGLE_AD_SRCFILE := $(ADLC_SUPPORT_DIR)/all-ad-src.ad + + INSERT_FILENAME_AWK_SCRIPT := \ + '{ \ + if (CUR_FN != FILENAME) { CUR_FN=FILENAME; NR_BASE=NR-1; need_lineno=1 } \ + if (need_lineno && $$0 !~ /\/\//) \ + { print "\n\n\#line " (NR-NR_BASE) " \"" FILENAME "\""; need_lineno=0 }; \ + print \ + }' + + $(SINGLE_AD_SRCFILE): $(AD_SRC_FILES) + $(call LogInfo, Preprocessing adlc files $(^F)) + $(call MakeDir, $(@D)) + $(NAWK) $(INSERT_FILENAME_AWK_SCRIPT) $^ > $@ + + ############################################################################## + # Run the adlc tool on the single concatenated ad source file, and store the + # output in support/adlc for further processing. + ADLC_RUN_MARKER := $(ADLC_SUPPORT_DIR)/_adlc_run.marker + + $(ADLC_RUN_MARKER): $(BUILD_ADLC) $(SINGLE_AD_SRCFILE) + $(call LogInfo, Generating adlc files) + $(call MakeDir, $(@D)) + $(call ExecuteWithLog, $(ADLC_SUPPORT_DIR)/adlc_run, \ + $(FIXPATH) $(ADLC_TOOL) $(ADLCFLAGS) $(SINGLE_AD_SRCFILE) \ + -c$(ADLC_SUPPORT_DIR)/ad_$(HOTSPOT_TARGET_CPU).cpp \ + -h$(ADLC_SUPPORT_DIR)/ad_$(HOTSPOT_TARGET_CPU).hpp \ + -a$(ADLC_SUPPORT_DIR)/dfa_$(HOTSPOT_TARGET_CPU).cpp \ + -v$(ADLC_SUPPORT_DIR)/adGlobals_$(HOTSPOT_TARGET_CPU).hpp) + $(TOUCH) $@ + + ############################################################################## + # Finally copy the generated files from support/adlc into gensrc/adfiles, + # and postprocess them by fixing dummy #line directives. + + ADLC_GENERATED_FILES := $(addprefix $(JVM_VARIANT_OUTPUTDIR)/gensrc/adfiles/, \ + ad_$(HOTSPOT_TARGET_CPU).cpp \ + ad_$(HOTSPOT_TARGET_CPU).hpp \ + ad_$(HOTSPOT_TARGET_CPU)_clone.cpp \ + ad_$(HOTSPOT_TARGET_CPU)_expand.cpp \ + ad_$(HOTSPOT_TARGET_CPU)_format.cpp \ + ad_$(HOTSPOT_TARGET_CPU)_gen.cpp \ + ad_$(HOTSPOT_TARGET_CPU)_misc.cpp \ + ad_$(HOTSPOT_TARGET_CPU)_peephole.cpp \ + ad_$(HOTSPOT_TARGET_CPU)_pipeline.cpp \ + adGlobals_$(HOTSPOT_TARGET_CPU).hpp \ + dfa_$(HOTSPOT_TARGET_CPU).cpp \ + ) + + $(JVM_VARIANT_OUTPUTDIR)/gensrc/adfiles/%: $(ADLC_RUN_MARKER) + $(call LogInfo, Postprocessing adlc file $*) + $(call MakeDir, $(@D)) + $(NAWK) \ + 'BEGIN { print "#line 1 \"$*\""; } \ + /^#line 999999$$/ {print "#line " (NR+1) " \"$*\""; next} \ + {print}' \ + < $(ADLC_SUPPORT_DIR)/$* > $@ + + TARGETS := $(ADLC_GENERATED_FILES) + +endif diff --git a/hotspot/makefiles/gensrc/GensrcDtrace.gmk b/hotspot/makefiles/gensrc/GensrcDtrace.gmk new file mode 100644 index 00000000000..563f22112fb --- /dev/null +++ b/hotspot/makefiles/gensrc/GensrcDtrace.gmk @@ -0,0 +1,56 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +################################################################################ +# Gensrc support for dtrace. The files generated here are included by dtrace.hpp + +ifeq ($(call check-jvm-feature, dtrace), true) + + ifeq ($(OPENJDK_TARGET_OS), solaris) + DTRACE_FLAGS := -64 + DTRACE_CPP_FLAGS := -D_LP64 + else ifeq ($(OPENJDK_TARGET_OS), macosx) + DTRACE_CPP_FLAGS := -D_LP64 -x c + else ifeq ($(OPENJDK_TARGET_OS), linux) + DTRACE_CPP_FLAGS := -x c + endif + + DTRACE_SOURCE_DIR := $(HOTSPOT_TOPDIR)/src/os/posix/dtrace + DTRACE_GENSRC_DIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/dtracefiles + + # Make sure we run our selected compiler for preprocessing instead of letting + # the dtrace tool pick it on it's own. + $(DTRACE_GENSRC_DIR)/%.h: $(DTRACE_SOURCE_DIR)/%.d + $(call LogInfo, Generating dtrace header file $(@F)) + $(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR)) + $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + + # Process all .d files in DTRACE_SOURCE_DIR. They are: + # hotspot_jni.d hotspot.d hs_private.d + TARGETS += $(patsubst $(DTRACE_SOURCE_DIR)/%.d, \ + $(DTRACE_GENSRC_DIR)/%.h, $(wildcard $(DTRACE_SOURCE_DIR)/*.d)) + +endif diff --git a/hotspot/makefiles/gensrc/GensrcJvmti.gmk b/hotspot/makefiles/gensrc/GensrcJvmti.gmk new file mode 100644 index 00000000000..25f569dc119 --- /dev/null +++ b/hotspot/makefiles/gensrc/GensrcJvmti.gmk @@ -0,0 +1,174 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +$(eval $(call IncludeCustomExtension, hotspot, gensrc/GensrcJvmti.gmk)) + +################################################################################ +# Build tools needed for the JVMTI source code generation + +JVMTI_TOOLS_SRCDIR := $(HOTSPOT_TOPDIR)/src/share/vm/prims +JVMTI_TOOLS_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/tools/jvmti + +$(eval $(call SetupJavaCompiler, GENERATE_OLDBYTECODE, \ + JAVAC := $(JAVAC), \ + FLAGS := $(DISABLE_WARNINGS), \ + SERVER_DIR := $(SJAVAC_SERVER_DIR), \ + SERVER_JVM := $(SJAVAC_SERVER_JAVA), \ + DISABLE_SJAVAC := true, \ +)) + +$(eval $(call SetupJavaCompilation, BUILD_JVMTI_TOOLS, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(JVMTI_TOOLS_SRCDIR), \ + INCLUDE_FILES := jvmtiGen.java jvmtiEnvFill.java, \ + BIN := $(JVMTI_TOOLS_OUTPUTDIR), \ +)) + +TOOL_JVMTI_GEN := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiGen +TOOL_JVMTI_ENV_FILL := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiEnvFill + +################################################################################ +# Setup make rules for an xml transform for jvmti/trace file generation. +# +# Parameter 1 is the name of the rule. This name is used as variable prefix, +# and the targets generated are listed in a variable by that name. This name is +# also used as the name of the output file. +# +# Remaining parameters are named arguments. These include: +# XML_FILE -- The input source file to use +# XSL_FILE -- The xsl file to use +# OUTPUT_DIR -- The directory to put the generated file in +# ARGS -- Additional arguments to the jvmtiGen tool +# DEPS -- Additional dependencies +SetupXslTransform = $(NamedParamsMacroTemplate) +define SetupXslTransformBody + $$($1_OUTPUT_DIR)/$1: $$($1_XML_FILE) $$($1_XSL_FILE) $$($1_DEPS) $$(BUILD_JVMTI_TOOLS) + $$(call LogInfo, Generating $$(@F)) + $$(call MakeDir, $$(@D)) + $$(call ExecuteWithLog, $$@, $$(TOOL_JVMTI_GEN) -IN $$($1_XML_FILE) -XSL $$($1_XSL_FILE) -OUT $$@ $$($1_ARGS)) + # jvmtiGen does not return error code properly on fail. + # NOTE: We should really fix jvmtiGen.java instead. + test -f $$@ + + TARGETS += $$($1_OUTPUT_DIR)/$1 +endef + +################################################################################ +# Create JVMTI files in gensrc/jvmtifiles + +JVMTI_SRCDIR := $(HOTSPOT_TOPDIR)/src/share/vm/prims +JVMTI_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles + +# Setup rule for generating a jvmti file +# +# $1 is generated source file name in $(JVMTI_OUTPUTDIR) +# $2 is XSL file to use in $(JVMTI_SRCDIR) +# $3 is optional extra arguments to jvmtiGen +define SetupJvmtiGeneration + $$(eval $$(call SetupXslTransform, $1, \ + XML_FILE := $$(JVMTI_SRCDIR)/jvmti.xml, \ + XSL_FILE := $$(JVMTI_SRCDIR)/$(strip $2), \ + OUTPUT_DIR := $$(JVMTI_OUTPUTDIR), \ + ARGS := $3, \ + DEPS := $$(JVMTI_SRCDIR)/jvmtiLib.xsl, \ + )) +endef + +$(eval $(call SetupJvmtiGeneration, jvmtiEnter.cpp, jvmtiEnter.xsl, \ + -PARAM interface jvmti)) +$(eval $(call SetupJvmtiGeneration, jvmtiEnterTrace.cpp, jvmtiEnter.xsl, \ + -PARAM interface jvmti -PARAM trace Trace)) +$(eval $(call SetupJvmtiGeneration, jvmtiEnv.hpp, jvmtiHpp.xsl)) +$(eval $(call SetupJvmtiGeneration, jvmti.h, jvmtiH.xsl)) +$(eval $(call SetupJvmtiGeneration, jvmti.html, jvmti.xsl)) +$(eval $(call SetupJvmtiGeneration, jvmtiEnvStub.cpp, jvmtiEnv.xsl)) + +JVMTI_BC_SRCDIR := $(HOTSPOT_TOPDIR)/src/share/vm/interpreter + +$(eval $(call SetupXslTransform, bytecodeInterpreterWithChecks.cpp, \ + XML_FILE := $(JVMTI_BC_SRCDIR)/bytecodeInterpreterWithChecks.xml, \ + XSL_FILE := $(JVMTI_BC_SRCDIR)/bytecodeInterpreterWithChecks.xsl, \ + OUTPUT_DIR := $(JVMTI_OUTPUTDIR), \ + DEPS := $(JVMTI_BC_SRCDIR)/bytecodeInterpreter.cpp, \ +)) + +# We need $(JVMTI_OUTPUTDIR)/jvmtiEnvStub.cpp (generated above) as input +$(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp: $(JVMTI_SRCDIR)/jvmtiEnv.cpp \ + $(JVMTI_OUTPUTDIR)/jvmtiEnvStub.cpp $(BUILD_JVMTI_TOOLS) + $(call LogInfo, Generating $(@F)) + $(call MakeDir, $(@D)) + $(call ExecuteWithLog, $@, $(TOOL_JVMTI_ENV_FILL) $(JVMTI_SRCDIR)/jvmtiEnv.cpp \ + $(JVMTI_OUTPUTDIR)/jvmtiEnvStub.cpp \ + $(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp) + # jvmtiEnvFill does not necessarily return an error code on failure. + # NOTE: We should really fix jvmtiEnvFill.java instead. + test -f $@ + +TARGETS += $(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp + +################################################################################ +# Create trace files in gensrc/tracefiles + +TRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles +TRACE_SRCDIR := $(HOTSPOT_TOPDIR)/src/share/vm/trace + +# Append directories to search (might have been set by custom extensions) +TRACE_SEARCH_DIRS += $(TRACE_SRCDIR) + +TRACE_XML ?= $(TRACE_SRCDIR)/trace.xml + +# Changing these will trigger a rebuild of generated trace files. +TRACE_DEPS += \ + $(TRACE_XML) \ + $(TRACE_SRCDIR)/tracetypes.xml \ + $(TRACE_SRCDIR)/tracerelationdecls.xml \ + $(TRACE_SRCDIR)/traceevents.xml \ + $(TRACE_SRCDIR)/trace.dtd \ + $(TRACE_SRCDIR)/xinclude.mod \ + # + +# Setup rule for generating a trace file +# +# $1 is generated source file name in $(TRACE_OUTPUTDIR) +define SetupTraceGeneration + $$(eval $$(call SetupXslTransform, $1, \ + XML_FILE := $$(TRACE_XML), \ + XSL_FILE := $$(firstword $$(wildcard $$(addsuffix /$$(basename $1).xsl, $$(TRACE_SEARCH_DIRS)))), \ + OUTPUT_DIR := $$(TRACE_OUTPUTDIR), \ + DEPS := $$(TRACE_DEPS), \ + )) +endef + +# Append files to generated (might have been set by custom extensions) +TRACE_GENSRC_FILES += \ + traceEventClasses.hpp \ + traceEventIds.hpp \ + traceTypes.hpp \ + # + +# Call SetupTraceGeneration for all trace gensrc files +$(foreach tracefile, $(TRACE_GENSRC_FILES), \ + $(eval $(call SetupTraceGeneration, $(tracefile))) \ +) diff --git a/hotspot/makefiles/ide/CreateVSProject.gmk b/hotspot/makefiles/ide/CreateVSProject.gmk new file mode 100644 index 00000000000..d804dcce9a8 --- /dev/null +++ b/hotspot/makefiles/ide/CreateVSProject.gmk @@ -0,0 +1,153 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# This must be the first rule +default: all + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + +ifeq ($(OPENJDK_TARGET_OS), windows) + # The next part is a bit hacky. We include the CompileJvm.gmk to be + # able to extact flags, but we do not wish to execute the rules. + + # Use client as base for defines and includes + JVM_VARIANT=client + + include HotspotCommon.gmk + include lib/CompileJvm.gmk + + # Reset targets so we don't build libjvm. + TARGETS := + + # Helper macro to convert a unix path to a Windows path, suitable for + # inclusion in a command line. + FixPath = \ + $(strip $(subst \,\\,$(shell $(CYGPATH) -w $1))) + + JVM_DEFINES_client := $(patsubst -D%,%, $(filter -D%, $(JVM_CFLAGS))) + EXTRACTED_DEFINES_client := $(addprefix -define , $(JVM_DEFINES_client)) + + JVM_INCLUDES_client := $(patsubst -I%,%, $(filter -I%, $(JVM_CFLAGS))) + EXTRACTED_INCLUDES_client := $(foreach path, $(JVM_INCLUDES_client), -absoluteInclude $(call FixPath, $(path))) + + # Hand-code variant-specific arguments, based on the fact that we use + # client for general arguments. Not optimal but other solutions require + # major changes in ProjectCreator. + ADDITIONAL_VARIANT_ARGS := \ + -define_server COMPILER2 \ + -ignorePath_client adfiles \ + -ignorePath_client c2_ \ + -ignorePath_client runtime_ \ + -ignorePath_client libadt \ + -ignorePath_client opto \ + # + + IGNORED_PLATFORMS_ARGS := \ + -ignorePath aarch64 \ + -ignorePath aix \ + -ignorePath arm \ + -ignorePath bsd \ + -ignorePath linux \ + -ignorePath posix \ + -ignorePath ppc \ + -ignorePath shark \ + -ignorePath solaris \ + -ignorePath sparc \ + -ignorePath x86_32 \ + -ignorePath zero \ + # + + ################################################################################ + # Build the ProjectCreator java tool. + + TOOLS_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/support/tools_classes + + $(eval $(call SetupJavaCompilation, BUILD_PROJECT_CREATOR, \ + SETUP := GENERATE_OLDBYTECODE, \ + ADD_JAVAC_FLAGS := -Xlint:-auxiliaryclass, \ + SRC := $(HOTSPOT_TOPDIR)/makefiles/src/classes, \ + BIN := $(TOOLS_OUTPUTDIR), \ + )) + + TARGETS += $(BUILD_PROJECT_CREATOR) + + # Run the ProjectCreator tool + PROJECT_CREATOR_TOOL := $(JAVA_SMALL) -cp $(TOOLS_OUTPUTDIR) build.tools.projectcreator.ProjectCreator + + IDE_OUTPUTDIR := $(BUILD_OUTPUT)/ide/hotspot-visualstudio + + VCPROJ_FILE := $(IDE_OUTPUTDIR)/jvm.vcxproj + + PROJECT_CREATOR_CLASS := build.tools.projectcreator.WinGammaPlatformVC10 + + # We hard-code gensrc dir to server (since this includes adfiles) + PROJECT_CREATOR_ARGS := \ + -sourceBase $(call FixPath, $(HOTSPOT_TOPDIR)) \ + -startAt src \ + -relativeSrcInclude src \ + -hidePath .hg \ + -hidePath .jcheck \ + -hidePath jdk.hotspot.agent \ + -hidePath jdk.vm.ci \ + -hidePath jdk.jfr \ + -compiler VC10 \ + -jdkTargetRoot $(call FixPath, $(JDK_OUTPUTDIR)) \ + -platformName x64 \ + -buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \ + -buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \ + -makeBinary $(call FixPath, $(MAKE)) \ + -makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \ + -absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ + -absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ + $(EXTRACTED_DEFINES_client) \ + $(EXTRACTED_INCLUDES_client) \ + $(ADDITIONAL_VARIANT_ARGS) \ + $(IGNORED_PLATFORMS_ARGS) \ + # + + VCPROJ_VARDEPS := $(PROJECT_CREATOR_CLASS) $(PROJECT_CREATOR_ARGS) + VCPROJ_VARDEPS_FILE := $(call DependOnVariable, VCPROJ_VARDEPS, \ + $(VCPROJ_FILE).vardeps) + + $(VCPROJ_FILE): $(BUILD_PROJECT_CREATOR) $(VCPROJ_VARDEPS_FILE) + $(call MakeDir, $(@D)) + $(call ExecuteWithLog, $@, \ + $(PROJECT_CREATOR_TOOL) $(PROJECT_CREATOR_CLASS) \ + $(PROJECT_CREATOR_ARGS) -projectFileName $(call FixPath, $@)) \ + $(LOG_INFO) + + TARGETS += $(VCPROJ_FILE) + + all: $(TARGETS) + +else + all: + $(info Hotspot Visual Studio generation only supported on Windows) +endif + +.PHONY: all diff --git a/hotspot/makefiles/lib/CompileDtracePostJvm.gmk b/hotspot/makefiles/lib/CompileDtracePostJvm.gmk new file mode 100644 index 00000000000..127460a562e --- /dev/null +++ b/hotspot/makefiles/lib/CompileDtracePostJvm.gmk @@ -0,0 +1,217 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +################################################################################ +# Support for dtrace integration with libjvm, and stand-alone dtrace library +# compilation. + +ifeq ($(call check-jvm-feature, dtrace), true) + ############################################################################## + + ifeq ($(OPENJDK_TARGET_OS), solaris) + ############################################################################ + # Integrate with libjvm. Here we generate three object files which are + # linked with libjvm.so. This step is complicated from a dependency + # perspective, since it needs the rest of the compiled object files from the + # libjvm compilation, but the output is object files that are to be included + # when linking libjvm.so. So this generation must happen as a part of the + # libjvm compilation. + + # First we need to generate the dtraceGenOffsets tool. When run, this will + # produce more header files and a C++ file. + + # Note that generateJvmOffsets.cpp must be compiled as if it were a file + # in the libjvm.so, using JVM_CFLAGS as setup in CompileJvm.gmk. Otherwise + # this would preferrably have been done as a part of GensrcDtrace.gmk. + $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \ + SRC := $(HOTSPOT_TOPDIR)/src/os/$(OPENJDK_TARGET_OS)/dtrace, \ + INCLUDE_FILES := generateJvmOffsets.cpp generateJvmOffsetsMain.c, \ + CC := $(BUILD_CXX), \ + CXX := $(BUILD_CXX), \ + LDEXE := $(BUILD_CXX), \ + generateJvmOffsets.cpp_CXXFLAGS := $(JVM_CFLAGS) -mt -xnolib -norunpath, \ + generateJvmOffsetsMain.c_CFLAGS := -library=%none -mt -m64 -norunpath -z nodefs, \ + LDFLAGS := -m64, \ + LIBS := -lc, \ + OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \ + OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \ + PROGRAM := dtraceGenOffsets, \ + )) + + DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET) + + # Argument 1: Output filename + # Argument 2: dtrace-gen-offset tool command line option + define SetupDtraceOffsetsGeneration + $1: $$(BUILD_DTRACE_GEN_OFFSETS) + $$(call LogInfo, Generating dtrace $2 file $$(@F)) + $$(call MakeDir, $$(@D)) + $$(call ExecuteWithLog, $$@, $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@) + + TARGETS += $1 + endef + + JVM_OFFSETS_H := $(DTRACE_SUPPORT_DIR)/JvmOffsets.h + JVM_OFFSETS_CPP := $(DTRACE_SUPPORT_DIR)/JvmOffsets.cpp + JVM_OFFSETS_INDEX_H := $(DTRACE_SUPPORT_DIR)/JvmOffsetsIndex.h + + # Run the dtrace-gen-offset tool to generate these three files. + $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header)) + $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index)) + $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table)) + + ############################################################################ + # Compile JVM_OFFSETS_OBJ which is linked with libjvm.so. + + # JvmOffsets.cpp is compiled without the common JVM_CFLAGS. Otherwise, the + # natural way would have been to included this source code in BUILD_LIBJVM. + JVM_OFFSETS_CFLAGS := -m64 + ifeq ($(OPENJDK_TARGET_CPU), sparcv9) + JVM_OFFSETS_CFLAGS += -xarch=sparc + endif + + $(JVM_OFFSETS_OBJ): $(JVM_OFFSETS_CPP) $(JVM_OFFSETS_H) + $(call LogInfo, Compiling dtrace file JvmOffsets.cpp (for libjvm.so)) + $(call ExecuteWithLog, $@, $(CXX) -c -I$( $@ + + DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \ + ciEnv.o \ + classLoadingService.o \ + compileBroker.o \ + hashtable.o \ + instanceKlass.o \ + java.o \ + jni.o \ + jvm.o \ + memoryManager.o \ + nmethod.o \ + objectMonitor.o \ + runtimeService.o \ + sharedRuntime.o \ + synchronizer.o \ + thread.o \ + unsafe.o \ + vmThread.o \ + vmGCOperations.o \ + ) + + ifeq ($(call check-jvm-feature, all-gcs), true) + DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \ + vmCMSOperations.o \ + vmPSOperations.o \ + ) + endif + + DTRACE_FLAGS := -64 -G + DTRACE_CPP_FLAGS := -D_LP64 + + # Make sure we run our selected compiler for preprocessing instead of letting + # the dtrace tool pick it on it's own. + $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.d $(DTRACE_INSTRUMENTED_OBJS) + $(call LogInfo, Generating $(@F) from $( $(DTRACE_SUPPORT_DIR)/$(@F).d) + $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \ + -s $(DTRACE_SUPPORT_DIR)/$(@F).d $(sort $(DTRACE_INSTRUMENTED_OBJS))) + + ############################################################################ + # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so. + + # Unfortunately dtrace generates incorrect types for some symbols in + # dtrace_jhelper.o, resulting in "warning: symbol X has differing types" + # This is tracked in JDK-6890703. + $(DTRACE_JHELPER_OBJ): $(HOTSPOT_TOPDIR)/src/os/solaris/dtrace/jhelper.d \ + $(JVM_OFFSETS_INDEX_H) + $(call LogInfo, Running dtrace for $( $(DTRACE_SUPPORT_DIR)/$(@F).d) + # $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \ + # -s $(DTRACE_SUPPORT_DIR)/$(@F).d) + + ############################################################################ + # Build the stand-alone dtrace libraries + + LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace + + $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \ + LIBRARY := jvm_dtrace, \ + OUTPUT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR), \ + SRC := $(HOTSPOT_TOPDIR)/src/os/solaris/dtrace, \ + INCLUDE_FILES := jvm_dtrace.c, \ + CFLAGS := -m64 -G -mt -KPIC, \ + LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \ + LIBS := $(LIBDL) -lc -lthread -ldoor, \ + MAPFILE := $(HOTSPOT_TOPDIR)/makefiles/mapfiles/libjvm_dtrace/mapfile-vers, \ + OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \ + STRIP_SYMBOLS := true, \ + )) + + LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db + + # Note that libjvm_db.c has tests for COMPILER2, but this was never set by + # the old build. + $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \ + LIBRARY := jvm_db, \ + OUTPUT_DIR := $(LIBJVM_DB_OUTPUTDIR), \ + SRC := $(HOTSPOT_TOPDIR)/src/os/solaris/dtrace, \ + INCLUDE_FILES := libjvm_db.c, \ + CFLAGS := -I$(JVM_VARIANT_OUTPUTDIR)/gensrc -I$(DTRACE_SUPPORT_DIR) \ + -m64 -G -mt -KPIC, \ + LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \ + LIBS := -lc, \ + MAPFILE := $(HOTSPOT_TOPDIR)/makefiles/mapfiles/libjvm_db/mapfile-vers, \ + OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \ + STRIP_SYMBOLS := true, \ + )) + + # We need the generated JvmOffsets.h before we can compile the libjvm_db source code. + $(BUILD_LIBJVM_DB_ALL_OBJS): $(JVM_OFFSETS_H) + + TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB) + endif +endif diff --git a/hotspot/makefiles/lib/CompileDtracePreJvm.gmk b/hotspot/makefiles/lib/CompileDtracePreJvm.gmk new file mode 100644 index 00000000000..20e3aa9be7d --- /dev/null +++ b/hotspot/makefiles/lib/CompileDtracePreJvm.gmk @@ -0,0 +1,36 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +ifeq ($(call check-jvm-feature, dtrace), true) + ifeq ($(OPENJDK_TARGET_OS), solaris) + # These files are are generated by CompileDtrace.gmk but consumed by + # CompileJvm.gmk + DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o + DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o + JVM_OFFSETS_OBJ := $(JVM_OUTPUTDIR)/objs/JvmOffsets.o + + DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ) $(JVM_OFFSETS_OBJ) + endif +endif diff --git a/hotspot/makefiles/lib/CompileJvm.gmk b/hotspot/makefiles/lib/CompileJvm.gmk new file mode 100644 index 00000000000..b6404cf74b1 --- /dev/null +++ b/hotspot/makefiles/lib/CompileJvm.gmk @@ -0,0 +1,242 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Include support files that will setup compiler flags due to the selected +# jvm feature set, and specific file overrides. +include lib/JvmFeatures.gmk +include lib/JvmOverrideFiles.gmk + +$(eval $(call IncludeCustomExtension, hotspot, lib/CompileJvm.gmk)) + +################################################################################ +# Setup compilation of the main Hotspot native library (libjvm). + +JVM_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm +JVM_MAPFILE := $(JVM_OUTPUTDIR)/mapfile + +################################################################################ +# Platform independent setup + +# This variable may be added to by a custom extension +JVM_SRC_ROOTS += $(HOTSPOT_TOPDIR)/src + +JVM_SRC_DIRS += $(call uniq, $(wildcard $(foreach d, $(JVM_SRC_ROOTS), \ + $d/share/vm \ + $d/os/$(HOTSPOT_TARGET_OS)/vm \ + $d/os/$(HOTSPOT_TARGET_OS_TYPE)/vm \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/vm \ + $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH)/vm \ + ))) \ + $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles \ + $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles \ + # + +JVM_CFLAGS_INCLUDES += \ + $(patsubst %,-I%,$(filter-out $(JVM_VARIANT_OUTPUTDIR)/gensrc/%, $(JVM_SRC_DIRS))) \ + -I$(JVM_VARIANT_OUTPUTDIR)/gensrc \ + -I$(HOTSPOT_TOPDIR)/src/share/vm/precompiled \ + -I$(HOTSPOT_TOPDIR)/src/share/vm/prims \ + # + +JVM_CFLAGS_TARGET_DEFINES += \ + -DTARGET_OS_FAMILY_$(HOTSPOT_TARGET_OS) \ + -DTARGET_ARCH_MODEL_$(HOTSPOT_TARGET_CPU) \ + -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \ + -DTARGET_OS_ARCH_MODEL_$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU) \ + -DTARGET_OS_ARCH_$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH) \ + -DTARGET_COMPILER_$(HOTSPOT_TOOLCHAIN_TYPE) \ + -D$(HOTSPOT_TARGET_CPU_DEFINE) \ + -DHOTSPOT_LIB_ARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' \ + # + +ifeq ($(DEBUG_LEVEL), release) + # For hotspot, release builds differ internally between "optimized" and "product" + # in that "optimize" does not define PRODUCT. + ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized) + JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT + endif +else ifeq ($(DEBUG_LEVEL), fastdebug) + JVM_CFLAGS_DEBUGLEVEL := -DASSERT + ifeq ($(filter $(OPENJDK_TARGET_OS), windows aix), ) + # NOTE: Old build did not define CHECK_UNHANDLED_OOPS on Windows and AIX. + JVM_CFLAGS_DEBUGLEVEL += -DCHECK_UNHANDLED_OOPS + endif +else ifeq ($(DEBUG_LEVEL), slowdebug) + # _NMT_NOINLINE_ informs NMT that no inlining is done by the compiler + JVM_CFLAGS_DEBUGLEVEL := -DASSERT -D_NMT_NOINLINE_ +endif + +JVM_CFLAGS += \ + $(JVM_CFLAGS_DEBUGLEVEL) \ + $(JVM_CFLAGS_TARGET_DEFINES) \ + $(JVM_CFLAGS_FEATURES) \ + $(JVM_CFLAGS_INCLUDES) \ + $(EXTRA_CFLAGS) \ + # + +JVM_LDFLAGS += \ + $(SHARED_LIBRARY_FLAGS) \ + $(JVM_LDFLAGS_FEATURES) \ + $(EXTRA_LDFLAGS) \ + # + +JVM_LIBS += \ + $(JVM_LIBS_FEATURES) \ + # + +# These files and directories are always excluded +JVM_EXCLUDE_FILES += jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp args.cc +JVM_EXCLUDES += adlc + +# Needed by vm_version.cpp +ifeq ($(OPENJDK_TARGET_CPU), x86_64) + OPENJDK_TARGET_CPU_VM_VERSION := amd64 +else ifeq ($(OPENJDK_TARGET_CPU), sparcv9) + OPENJDK_TARGET_CPU_VM_VERSION := sparc +else + OPENJDK_TARGET_CPU_VM_VERSION := $(OPENJDK_TARGET_CPU) +endif + +CFLAGS_VM_VERSION := \ + $(VERSION_CFLAGS) \ + -DHOTSPOT_VERSION_STRING='"$(VERSION_STRING)"' \ + -DDEBUG_LEVEL='"$(DEBUG_LEVEL)"' \ + -DHOTSPOT_BUILD_USER='"$(USERNAME)"' \ + -DHOTSPOT_VM_DISTRO='"$(HOTSPOT_VM_DISTRO)"' \ + -DCPU='"$(OPENJDK_TARGET_CPU_VM_VERSION)"' \ + # + +# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp. +ifeq ($(USE_PRECOMPILED_HEADER), 0) + JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER +endif + +################################################################################ +# Platform specific setup + +ifneq ($(filter $(OPENJDK_TARGET_OS), linux macosx windows), ) + JVM_PRECOMPILED_HEADER := $(HOTSPOT_TOPDIR)/src/share/vm/precompiled/precompiled.hpp +endif + +ifneq ($(filter $(OPENJDK_TARGET_OS), macosx aix solaris), ) + # On macosx, aix and solaris we have to link with the C++ compiler + JVM_TOOLCHAIN := TOOLCHAIN_LINK_CXX +else + JVM_TOOLCHAIN := TOOLCHAIN_DEFAULT +endif + +ifeq ($(OPENJDK_TARGET_CPU), x86) + JVM_EXCLUDE_PATTERNS += x86_64 +else ifeq ($(OPENJDK_TARGET_CPU), x86_64) + JVM_EXCLUDE_PATTERNS += x86_32 +endif + +# Inline assembly for solaris +ifeq ($(OPENJDK_TARGET_OS), solaris) + ifeq ($(OPENJDK_TARGET_CPU), x86_64) + JVM_CFLAGS += $(HOTSPOT_TOPDIR)/src/os_cpu/solaris_x86/vm/solaris_x86_64.il + else ifeq ($(OPENJDK_TARGET_CPU), sparcv9) + JVM_CFLAGS += $(HOTSPOT_TOPDIR)/src/os_cpu/solaris_sparc/vm/solaris_sparc.il + endif +endif + +ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), solaris-sparcv9) + ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), false) + # NOTE: In the old build, we weirdly enough set -g/-g0 always, regardless + # of if debug symbols were needed. Without it, compilation fails on + # sparc! :-( + JVM_CFLAGS += -g0 + endif +endif + +ifeq ($(OPENJDK_TARGET_OS), windows) + ifeq ($(OPENJDK_TARGET_CPU_BITS), 64) + RC_DESC := 64-Bit$(SPACE) + endif + JVM_RCFLAGS += -D"HS_FILEDESC=$(HOTSPOT_VM_DISTRO) $(RC_DESC)$(JVM_VARIANT) VM" +endif + +ifeq ($(OPENJDK_TARGET_OS), macosx) + # NOTE: The old build did not strip binaries on macosx. + JVM_STRIP_SYMBOLS := false +else + JVM_STRIP_SYMBOLS := true +endif + +JVM_OPTIMIZATION ?= HIGHEST_JVM + +################################################################################ +# Now set up the actual compilation of the main hotspot native library + +$(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \ + TOOLCHAIN := $(JVM_TOOLCHAIN), \ + LIBRARY := jvm, \ + OUTPUT_DIR := $(JVM_OUTPUTDIR), \ + SRC := $(JVM_SRC_DIRS), \ + EXCLUDES := $(JVM_EXCLUDES), \ + EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \ + EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \ + EXTRA_OBJECT_FILES := $(DTRACE_EXTRA_OBJECT_FILES), \ + CFLAGS := $(JVM_CFLAGS), \ + CFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \ + CXXFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \ + vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ + DISABLED_WARNINGS_clang := delete-non-virtual-dtor dynamic-class-memaccess \ + empty-body format logical-op-parentheses parentheses \ + parentheses-equality switch tautological-compare, \ + DISABLED_WARNINGS_xlc := 1540-0216 1540-0198 1540-1090 1540-1639 \ + 1540-1088 1500-010, \ + ASFLAGS := $(JVM_ASFLAGS), \ + LDFLAGS := $(JVM_LDFLAGS), \ + LIBS := $(JVM_LIBS), \ + OPTIMIZATION := $(JVM_OPTIMIZATION), \ + OBJECT_DIR := $(JVM_OUTPUTDIR)/objs, \ + MAPFILE := $(JVM_MAPFILE), \ + USE_MAPFILE_FOR_SYMBOLS := true, \ + STRIP_SYMBOLS := $(JVM_STRIP_SYMBOLS), \ + EMBED_MANIFEST := true, \ + RC_FLAGS := $(JVM_RCFLAGS), \ + VERSIONINFO_RESOURCE := $(HOTSPOT_TOPDIR)/src/os/windows/vm/version.rc, \ + PRECOMPILED_HEADER := $(JVM_PRECOMPILED_HEADER), \ + PRECOMPILED_HEADER_EXCLUDE := $(JVM_PRECOMPILED_HEADER_EXCLUDE), \ +)) + +# AIX warning explanation: +# 1500-010 : (W) WARNING in ...: Infinite loop. Program may not stop. +# There are several infinite loops in the vm, so better suppress. +# 1540-0198 : (W) The omitted keyword "private" is assumed for base class "...". +# 1540-0216 : (W) An expression of type .. cannot be converted to type .. +# In hotspot this fires for functionpointer to pointer conversions +# 1540-1088 : (W) The exception specification is being ignored. +# In hotspot this is caused by throw() in declaration of new() in nmethod.hpp. +# 1540-1090 : (I) The destructor of "..." might not be called. +# 1540-1639 : (I) The behavior of long type bit fields has changed ... + +# Include mapfile generation. It relies on BUILD_LIBJVM_ALL_OBJS which is only +# defined after the above call to BUILD_LIBJVM. Mapfile will be generated +# after all object files are built, but before the jvm library is linked. +include lib/JvmMapfile.gmk + +TARGETS += $(BUILD_LIBJVM) diff --git a/hotspot/makefiles/lib/CompileLibjsig.gmk b/hotspot/makefiles/lib/CompileLibjsig.gmk new file mode 100644 index 00000000000..ba9791cdef8 --- /dev/null +++ b/hotspot/makefiles/lib/CompileLibjsig.gmk @@ -0,0 +1,106 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +################################################################################ +# Create the libjsig.so shared library + +default: all + +include $(SPEC) +include MakeBase.gmk +include NativeCompilation.gmk + +ifneq ($(OPENJDK_TARGET_OS), windows) + ifeq ($(STATIC_BUILD), false) + LIBJSIG_STRIP_SYMBOLS := true + ifeq ($(OPENJDK_TARGET_OS), linux) + LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS) + LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS) + LIBJSIG_LIBS := $(LIBDL) + + # NOTE: The old build compiled this library without -soname. + # To emulate this, we need to clear out SET_SHARED_LIBRARY_NAME. + SET_SHARED_LIBRARY_NAME := + + # Flags for other CPUs can be provided in EXTRA_CFLAGS + ifeq ($(OPENJDK_TARGET_CPU), x86_64) + LIBJSIG_CPU_FLAGS := -m64 + else ifeq ($(OPENJDK_TARGET_CPU), x86) + LIBJSIG_CPU_FLAGS := -m32 -march=i586 + endif + + else ifeq ($(OPENJDK_TARGET_OS), solaris) + LIBJSIG_CFLAGS := -m64 -KPIC -mt + LIBJSIG_LDFLAGS := -m64 -mt -xnolib + LIBJSIG_LIBS := $(LIBDL) + + # NOTE: The old build compiled this library without -soname. + # To emulate this, we need to clear out SET_SHARED_LIBRARY_NAME. + SET_SHARED_LIBRARY_NAME := + + else ifeq ($(OPENJDK_TARGET_OS), aix) + LIBJSIG_CFLAGS := -q64 -D_GNU_SOURCE -D_REENTRANT -qpic=large + LIBJSIG_LDFLAGS := -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath -bernotok + LIBJSIG_LIBS := $(LIBDL) + + # NOTE: The old build compiled this library without -soname. + # To emulate this, we need to clear out SET_SHARED_LIBRARY_NAME. + SET_SHARED_LIBRARY_NAME := + + else ifeq ($(OPENJDK_TARGET_OS), macosx) + LIBJSIG_CFLAGS := -m64 -D_GNU_SOURCE -pthread -mno-omit-leaf-frame-pointer -mstack-alignment=16 -fPIC + LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) + # NOTE: This lib is not stripped on macosx in old build. Looks like a mistake. + LIBJSIG_STRIP_SYMBOLS := false + else + $(error Unknown target OS $(OPENJDK_TARGET_OS) in CompileLibjsig.gmk) + endif + + LIBJSIG_SRC_FILE := $(HOTSPOT_TOPDIR)/src/os/$(HOTSPOT_TARGET_OS)/vm/jsig.c + LIBJSIG_MAPFILE := $(wildcard $(HOTSPOT_TOPDIR)/makefiles/mapfiles/libjsig/mapfile-vers-$(OPENJDK_TARGET_OS)) + LIBJSIG_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/libjsig + + LIBJSIG_LDFLAGS += $(SHARED_LIBRARY_FLAGS) + + $(eval $(call SetupNativeCompilation, BUILD_LIBJSIG, \ + LIBRARY := jsig, \ + EXTRA_FILES := $(LIBJSIG_SRC_FILE), \ + OUTPUT_DIR := $(LIBJSIG_OUTPUTDIR), \ + LANG := C, \ + CFLAGS := $(LIBJSIG_CFLAGS) $(LIBJSIG_CPU_FLAGS), \ + LDFLAGS := $(LIBJSIG_LDFLAGS) $(LIBJSIG_CPU_FLAGS), \ + LIBS := $(LIBJSIG_LIBS), \ + MAPFILE := $(LIBJSIG_MAPFILE), \ + OBJECT_DIR := $(LIBJSIG_OUTPUTDIR)/objs, \ + STRIP_SYMBOLS := $(LIBJSIG_STRIP_SYMBOLS), \ + )) + + TARGETS += $(BUILD_LIBJSIG) + endif +endif + +all: $(TARGETS) + +.PHONY: all diff --git a/hotspot/makefiles/lib/CompileLibraries.gmk b/hotspot/makefiles/lib/CompileLibraries.gmk new file mode 100644 index 00000000000..7a7a1651194 --- /dev/null +++ b/hotspot/makefiles/lib/CompileLibraries.gmk @@ -0,0 +1,42 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include NativeCompilation.gmk + +include HotspotCommon.gmk + +# The dtrace setup must be done both before and after CompileJvm.gmk, due to +# intricate dependencies. +include lib/CompileDtracePreJvm.gmk +include lib/CompileJvm.gmk +include lib/CompileDtracePostJvm.gmk + +all: $(TARGETS) + +.PHONY: all diff --git a/hotspot/makefiles/lib/JvmFeatures.gmk b/hotspot/makefiles/lib/JvmFeatures.gmk new file mode 100644 index 00000000000..40a3247c9a7 --- /dev/null +++ b/hotspot/makefiles/lib/JvmFeatures.gmk @@ -0,0 +1,144 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +$(eval $(call IncludeCustomExtension, hotspot, lib/JvmFeatures.gmk)) + +################################################################################ +# Setup CFLAGS and EXCLUDES for the libjvm compilation, depending on which +# jvm features are selected for this jvm variant. + +ifeq ($(call check-jvm-feature, compiler1), true) + JVM_CFLAGS_FEATURES += -DCOMPILER1 +else + JVM_EXCLUDE_PATTERNS += c1_ +endif + +ifeq ($(call check-jvm-feature, compiler2), true) + JVM_CFLAGS_FEATURES += -DCOMPILER2 + JVM_SRC_DIRS += $(JVM_VARIANT_OUTPUTDIR)/gensrc/adfiles +else + JVM_EXCLUDES += opto libadt + JVM_EXCLUDE_FILES += bcEscapeAnalyzer.cpp ciTypeFlow.cpp + JVM_EXCLUDE_PATTERNS += c2_ runtime_ +endif + +ifeq ($(call check-jvm-feature, zero), true) + JVM_CFLAGS_FEATURES += -DZERO -DCC_INTERP -DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS) + JVM_LIBS_FEATURES += $(LIBFFI_LIBS) +endif + +ifeq ($(call check-jvm-feature, shark), true) + JVM_CFLAGS_FEATURES += -DSHARK $(LLVM_CFLAGS) + JVM_LDFLAGS_FEATURES += $(LLVM_LDFLAGS) + JVM_LIBS_FEATURES += $(LLVM_LIBS) +else + JVM_EXCLUDES += shark +endif + +ifeq ($(call check-jvm-feature, minimal), true) + JVM_CFLAGS_FEATURES += -DMINIMAL_JVM -DVMTYPE=\"Minimal\" +endif + +ifeq ($(call check-jvm-feature, dtrace), true) + JVM_CFLAGS_FEATURES += -DDTRACE_ENABLED +endif + +ifeq ($(call check-jvm-feature, static-build), true) + JVM_CFLAGS_FEATURES += -DSTATIC_BUILD=1 +endif + +ifneq ($(call check-jvm-feature, jvmti), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_JVMTI=0 + JVM_EXCLUDE_FILES += jvmtiGetLoadedClasses.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ + jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ + jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ + jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ + jvmtiClassFileReconstituter.cpp +endif + +ifneq ($(call check-jvm-feature, jvmci), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_JVMCI=0 + JVM_EXCLUDES += jvmci + JVM_EXCLUDE_FILES += jvmciCodeInstaller_$(HOTSPOT_TARGET_CPU_ARCH).cpp +endif + +ifneq ($(call check-jvm-feature, fprof), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_FPROF=0 + JVM_EXCLUDE_FILES += fprofiler.cpp +endif + +ifneq ($(call check-jvm-feature, vm-structs), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_VM_STRUCTS=0 + JVM_EXCLUDE_FILES += vmStructs.cpp +endif + +ifneq ($(call check-jvm-feature, jni-check), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_JNI_CHECK=0 + JVM_EXCLUDE_FILES += jniCheck.cpp +endif + +ifneq ($(call check-jvm-feature, services), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_SERVICES=0 + JVM_EXCLUDE_FILES += heapDumper.cpp heapInspection.cpp \ + attachListener_$(HOTSPOT_TARGET_OS).cpp attachListener.cpp +endif + +ifneq ($(call check-jvm-feature, management), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_MANAGEMENT=0 +endif + +ifneq ($(call check-jvm-feature, cds), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_CDS=0 + JVM_EXCLUDE_FILES += \ + classListParser.cpp \ + classLoaderExt.cpp \ + filemap.cpp \ + metaspaceShared.cpp \ + metaspaceShared_$(HOTSPOT_TARGET_CPU).cpp \ + metaspaceShared_$(HOTSPOT_TARGET_CPU_ARCH).cpp \ + sharedClassUtil.cpp \ + sharedPathsMiscInfo.cpp \ + systemDictionaryShared.cpp \ + # +endif + +ifneq ($(call check-jvm-feature, all-gcs), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_ALL_GCS=0 + JVM_EXCLUDE_PATTERNS += \ + cms/ g1/ parallel/ + JVM_EXCLUDE_FILES += \ + concurrentGCThread.cpp \ + plab.cpp + JVM_EXCLUDE_FILES += \ + g1MemoryPool.cpp \ + psMemoryPool.cpp +endif + +ifneq ($(call check-jvm-feature, nmt), true) + JVM_CFLAGS_FEATURES += -DINCLUDE_NMT=0 + JVM_EXCLUDE_FILES += \ + memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \ + memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp +endif diff --git a/hotspot/makefiles/lib/JvmMapfile.gmk b/hotspot/makefiles/lib/JvmMapfile.gmk new file mode 100644 index 00000000000..9d7655b26ee --- /dev/null +++ b/hotspot/makefiles/lib/JvmMapfile.gmk @@ -0,0 +1,172 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +$(eval $(call IncludeCustomExtension, hotspot, lib/JvmMapfile.gmk)) + +################################################################################ +# Combine a list of static symbols + +ifneq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), windows-x86_64) + # On Windows x86_64, we should not have any symbols at all, since that + # results in duplicate warnings from the linker (JDK-8043491). + SYMBOLS_SRC += $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-shared +endif + +ifeq ($(OPENJDK_TARGET_OS_TYPE), unix) + SYMBOLS_SRC += $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-unix +endif + +ifneq ($(wildcard $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-$(OPENJDK_TARGET_OS)), ) + SYMBOLS_SRC += $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-$(OPENJDK_TARGET_OS) +endif + +ifneq ($(findstring debug, $(DEBUG_LEVEL)), ) + ifneq ($(wildcard $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-$(OPENJDK_TARGET_OS)-debug), ) + SYMBOLS_SRC += $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-$(OPENJDK_TARGET_OS)-debug + endif +endif + +ifeq ($(OPENJDK_TARGET_OS), solaris) + ifeq ($(call check-jvm-feature, dtrace), true) + # Additional mapfiles that are only used when dtrace is enabled + ifeq ($(call check-jvm-feature, compiler2), true) + # This also covers the case of compiler1+compiler2. + SYMBOLS_SRC += $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-solaris-dtrace-compiler2 + else ifeq ($(call check-jvm-feature, compiler1), true) + SYMBOLS_SRC += $(HOTSPOT_TOPDIR)/makefiles/symbols/symbols-solaris-dtrace-compiler1 + endif + endif +endif + +################################################################################ +# Create a dynamic list of symbols from the built object files. This is highly +# platform dependent. + +ifeq ($(OPENJDK_TARGET_OS), linux) + DUMP_SYMBOLS_CMD := $(NM) --defined-only *.o + ifneq ($(FILTER_SYMBOLS_PATTERN), ) + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| + endif + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^_ZTV|^gHotSpotVM|^UseSharedSpaces$$ + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^_ZN9Arguments17SharedArchivePathE$$ + FILTER_SYMBOLS_AWK_SCRIPT := \ + '{ \ + if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \ + }' + +else ifeq ($(OPENJDK_TARGET_OS), solaris) + DUMP_SYMBOLS_CMD := $(NM) -p *.o + ifneq ($(FILTER_SYMBOLS_PATTERN), ) + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| + endif + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^__1c.*__vtbl_$$|^gHotSpotVM + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^UseSharedSpaces$$ + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^__1cJArgumentsRSharedArchivePath_$$ + FILTER_SYMBOLS_AWK_SCRIPT := \ + '{ \ + if ($$2 == "U") next; \ + if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \ + }' + +else ifeq ($(OPENJDK_TARGET_OS), macosx) + # nm on macosx prints out "warning: nm: no name list" to stderr for + # files without symbols. Hide this, even at the expense of hiding real errors. + DUMP_SYMBOLS_CMD := $(NM) -Uj *.o 2> /dev/null + ifneq ($(FILTER_SYMBOLS_PATTERN), ) + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| + endif + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^_ZTV|^gHotSpotVM + FILTER_SYMBOLS_AWK_SCRIPT := \ + '{ \ + if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \ + }' + +# NOTE: The script is from the old build. It is broken and finds no symbols. +# The script below might be what was intended, but it failes to link with tons +# of 'cannot export hidden symbol vtable for X'. +# '{ if ($$1 ~ /^__ZTV/ || $$1 ~ /^_gHotSpotVM/) print substr($$1, 2) }' +else ifeq ($(OPENJDK_TARGET_OS), aix) + # NOTE: The old build had the solution below. This should to be fixed in + # configure instead. + + # On AIX we have to prevent that we pick up the 'nm' version from the GNU binutils + # which may be installed under /opt/freeware/bin. So better use an absolute path here! + # NM=/usr/bin/nm + + DUMP_SYMBOLS_CMD := $(NM) -X64 -B -C *.o + FILTER_SYMBOLS_AWK_SCRIPT := \ + '{ \ + if (($$2="d" || $$2="D") && ($$3 ~ /^__vft/ || $$3 ~ /^gHotSpotVM/)) print $$3; \ + if ($$3 ~ /^UseSharedSpaces$$/) print $$3; \ + if ($$3 ~ /^SharedArchivePath__9Arguments$$/) print $$3; \ + }' + +else ifeq ($(OPENJDK_TARGET_OS), windows) + DUMP_SYMBOLS_CMD := $(DUMPBIN) -symbols *.obj + FILTER_SYMBOLS_AWK_SCRIPT := \ + '{ \ + if ($$7 ~ /??_7.*@@6B@/ && $$7 !~ /type_info/) print $$7; \ + }' + +else + $(error Unknown target OS $(OPENJDK_TARGET_OS) in JvmMapfile.gmk) +endif + +# A more correct solution would be to send BUILD_LIBJVM_ALL_OBJS instead of +# cd && *.o, but this will result in very long command lines, which is +# problematic on some platforms. +$(JVM_OUTPUTDIR)/symbols-objects: $(BUILD_LIBJVM_ALL_OBJS) + $(call LogInfo, Generating symbol list from object files) + $(CD) $(JVM_OUTPUTDIR)/objs && \ + $(DUMP_SYMBOLS_CMD) | $(NAWK) $(FILTER_SYMBOLS_AWK_SCRIPT) | $(SORT) -u > $@ + +SYMBOLS_SRC += $(JVM_OUTPUTDIR)/symbols-objects + +################################################################################ +# Now concatenate all symbol lists into a single file and remove comments. + +$(JVM_OUTPUTDIR)/symbols: $(SYMBOLS_SRC) + $(SED) -e '/^#/d' $^ > $@ + +################################################################################ +# Finally convert the symbol list into a platform-specific mapfile + +$(JVM_MAPFILE): $(JVM_OUTPUTDIR)/symbols + $(call LogInfo, Creating mapfile) + $(RM) $@ + ifeq ($(OPENJDK_TARGET_OS), macosx) + # On macosx, we need to add a leading underscore + $(AWK) '{ if ($$0 ~ ".") { print " _" $$0 } }' < $^ > $@.tmp + else ifeq ($(OPENJDK_TARGET_OS), windows) + # On windows, add an 'EXPORTS' header + $(ECHO) "EXPORTS" > $@.tmp + $(AWK) '{ if ($$0 ~ ".") { print " " $$0 } }' < $^ >> $@.tmp + else + # Assume standard linker script + $(PRINTF) "SUNWprivate_1.1 { \n global: \n" > $@.tmp + $(AWK) '{ if ($$0 ~ ".") { print " " $$0 ";" } }' < $^ >> $@.tmp + $(PRINTF) " local: \n *; \n }; \n" >> $@.tmp + endif + $(MV) $@.tmp $@ diff --git a/hotspot/makefiles/lib/JvmOverrideFiles.gmk b/hotspot/makefiles/lib/JvmOverrideFiles.gmk new file mode 100644 index 00000000000..1ffcb7455ce --- /dev/null +++ b/hotspot/makefiles/lib/JvmOverrideFiles.gmk @@ -0,0 +1,168 @@ +# +# Copyright (c) 2013, 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +$(eval $(call IncludeCustomExtension, hotspot, lib/JvmOverrideFiles.gmk)) + +################################################################################ +# This file contains explicit overrides of CFLAGS and/or precompiled header +# status for individual files on specific platforms. + +ifeq ($(TOOLCHAIN_TYPE), gcc) + BUILD_LIBJVM_vmStructs.cpp_CXXFLAGS := -fno-var-tracking-assignments -O0 +endif + +ifeq ($(OPENJDK_TARGET_OS), linux) + BUILD_LIBJVM_ostream.cpp_CXXFLAGS := -D_FILE_OFFSET_BITS=64 + + ifeq ($(OPENJDK_TARGET_CPU_ARCH), x86) + BUILD_LIBJVM_sharedRuntimeTrig.cpp_CXXFLAGS := -DNO_PCH $(CXX_O_FLAG_NONE) + BUILD_LIBJVM_sharedRuntimeTrans.cpp_CXXFLAGS := -DNO_PCH $(CXX_O_FLAG_NONE) + + ifeq ($(TOOLCHAIN_TYPE), clang) + JVM_PRECOMPILED_HEADER_EXCLUDE := \ + sharedRuntimeTrig.cpp \ + sharedRuntimeTrans.cpp \ + # + endif + endif + + ifeq ($(OPENJDK_TARGET_CPU), x86) + # Performance measurements show that by compiling GC related code, we could + # significantly reduce the GC pause time on 32 bit Linux/Unix platforms by + # compiling without the PIC flag (-fPIC on linux). + # See 6454213 for more details. + ALL_SRC := $(filter %.cpp, $(call CacheFind, $(HOTSPOT_TOPDIR)/src/share/vm)) + NONPIC_FILTER := $(addsuffix %, $(addprefix $(HOTSPOT_TOPDIR)/src/share/vm/, \ + memory oops gc)) + # Due to what looks like a bug in the old build implementation of this, add a + # couple of more files that were accidentally matched as substrings of GC related + # files. + NONPIC_SRC := $(filter $(NONPIC_FILTER), $(ALL_SRC)) globals.cpp location.cpp + # Declare variables for each source file that needs the pic flag like this: + # BUILD_JVM__CXXFLAGS := -fno-PIC + # This will get implicitly picked up by SetupNativeCompilation below. + $(foreach s, $(NONPIC_SRC), $(eval BUILD_LIBJVM_$(notdir $s)_CXXFLAGS := -fno-PIC)) + endif + +else ifeq ($(OPENJDK_TARGET_OS), solaris) + ifneq ($(DEBUG_LEVEL), slowdebug) + # Workaround for a bug in dtrace. If ciEnv::post_compiled_method_load_event() + # is inlined, the resulting dtrace object file needs a reference to this + # function, whose symbol name is too long for dtrace. So disable inlining + # for this method for now. (fix this when dtrace bug 6258412 is fixed) + BUILD_LIBJVM_ciEnv.cpp_CXXFLAGS := \ + -xinline=no%__1cFciEnvbFpost_compiled_method_load_event6MpnHnmethod__v_ + # dtrace cannot handle tail call optimization (6672627, 6693876) + BUILD_LIBJVM_jni.cpp_CXXFLAGS := -Qoption ube -O~yz + BUILD_LIBJVM_stubGenerator_$(HOTSPOT_TARGET_CPU).cpp_CXXFLAGS := -xspace + + ifeq ($(OPENJDK_TARGET_CPU), x86_64) + # Temporary until SS10 C++ compiler is fixed + BUILD_LIBJVM_generateOptoStub.cpp_CXXFLAGS := -xO2 + # Temporary util SS12u1 C++ compiler is fixed + BUILD_LIBJVM_c1_LinearScan.cpp_CXXFLAGS := -xO2 + endif + endif + + # Need extra inlining to get oop_ps_push_contents functions to perform well enough. + ifeq ($(DEBUG_LEVEL),release) + BUILD_LIBJVM_psPromotionManager.cpp_CXXFLAGS := -W2,-Ainline:inc=1000 + endif + + ifeq ($(DEBUG_LEVEL), fastdebug) + # this hangs in iropt now (7113504) + BUILD_LIBJVM_compileBroker.cpp_CXXFLAGS := -xO2 + + # Frame size > 100k if we allow inlining via -g0! + BUILD_LIBJVM_bytecodeInterpreter.cpp_CXXFLAGS := +d + BUILD_LIBJVM_bytecodeInterpreterWithChecks.cpp_CXXFLAGS := +d + + ifeq ($(OPENJDK_TARGET_CPU_ARCH), x86) + # ube explodes on x86 + BUILD_LIBJVM_bytecodeInterpreter.cpp_CXXFLAGS += -xO1 + BUILD_LIBJVM_bytecodeInterpreterWithChecks.cpp_CXXFLAGS += -xO1 + endif + + endif + +else ifeq ($(OPENJDK_TARGET_OS), macosx) + # The copied fdlibm routines in these files must not be optimized + BUILD_LIBJVM_sharedRuntimeTrans.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE) + BUILD_LIBJVM_sharedRuntimeTrig.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE) + ifeq ($(TOOLCHAIN_TYPE), clang) + # NOTE: The old build tested clang version to make sure this workaround + # for the clang bug was still needed. + BUILD_LIBJVM_loopTransform.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE) + ifneq ($(DEBUG_LEVEL), slowdebug) + BUILD_LIBJVM_unsafe.cpp_CXXFLAGS := -O1 + endif + + # The following files are compiled at various optimization + # levels due to optimization issues encountered at the + # default level. The Clang compiler issues a compile + # time error if there is an optimization level specification + # skew between the PCH file and the C++ file. Especially if the + # PCH file is compiled at a higher optimization level than + # the C++ file. One solution might be to prepare extra optimization + # level specific PCH files for the opt build and use them here, but + # it's probably not worth the effort as long as only a few files + # need this special handling. + JVM_PRECOMPILED_HEADER_EXCLUDE := \ + sharedRuntimeTrig.cpp \ + sharedRuntimeTrans.cpp \ + loopTransform.cpp \ + unsafe.cpp \ + jvmciCompilerToVM.cpp \ + # + endif + +else ifeq ($(OPENJDK_TARGET_OS), aix) + BUILD_LIBJVM_synchronizer.cpp_CXXFLAGS := -qnoinline + BUILD_LIBJVM_sharedRuntimeTrans.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE) + # Disable aggressive optimizations for functions in sharedRuntimeTrig.cpp + # and sharedRuntimeTrans.cpp on ppc64. + # -qstrict turns off the following optimizations: + # * Performing code motion and scheduling on computations such as loads + # and floating-point computations that may trigger an exception. + # * Relaxing conformance to IEEE rules. + # * Reassociating floating-point expressions. + # When using '-qstrict' there still remains one problem + # in javasoft.sqe.tests.api.java.lang.Math.sin5Tests when run in compile-all + # mode, so don't optimize sharedRuntimeTrig.cpp at all. + BUILD_LIBJVM_sharedRuntimeTrig.cpp_CXXFLAGS := $(CXX_O_FLAG_NONE) + + # Disable ELF decoder on AIX (AIX uses XCOFF). + JVM_EXCLUDE_PATTERNS += elf + +else ifeq ($(OPENJDK_TARGET_OS), windows) + JVM_PRECOMPILED_HEADER_EXCLUDE := \ + bytecodeInterpreter.cpp \ + bytecodeInterpreterWithChecks.cpp \ + opcodes.cpp \ + os_windows.cpp \ + os_windows_x86.cpp \ + osThread_windows.cpp \ + # +endif diff --git a/hotspot/makefiles/mapfiles/libjsig/mapfile-vers-solaris b/hotspot/makefiles/mapfiles/libjsig/mapfile-vers-solaris new file mode 100644 index 00000000000..ddb46c050ec --- /dev/null +++ b/hotspot/makefiles/mapfiles/libjsig/mapfile-vers-solaris @@ -0,0 +1,38 @@ +# +# Copyright (c) 2005, 2013, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# + +# Define library interface. + +SUNWprivate_1.1 { + global: + JVM_begin_signal_setting; + JVM_end_signal_setting; + JVM_get_libjsig_version; + JVM_get_signal_action; + sigaction; + signal; + sigset; + local: + *; +}; diff --git a/hotspot/makefiles/mapfiles/libjvm_db/mapfile-vers b/hotspot/makefiles/mapfiles/libjvm_db/mapfile-vers new file mode 100644 index 00000000000..9ee418d01a2 --- /dev/null +++ b/hotspot/makefiles/mapfiles/libjvm_db/mapfile-vers @@ -0,0 +1,38 @@ +# + +# +# Copyright (c) 2005, 2008, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# + +# Define library interface. + +SUNWprivate_1.1 { + global: + Jagent_create; + Jagent_destroy; + Jframe_iter; + #Jget_vframe; + #Jlookup_by_regs; + local: + *; +}; diff --git a/hotspot/makefiles/mapfiles/libjvm_dtrace/mapfile-vers b/hotspot/makefiles/mapfiles/libjvm_dtrace/mapfile-vers new file mode 100644 index 00000000000..f9aaa19ba9d --- /dev/null +++ b/hotspot/makefiles/mapfiles/libjvm_dtrace/mapfile-vers @@ -0,0 +1,37 @@ +# + +# +# Copyright (c) 2006, 2008, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# + +# Define library interface for JVM-DTrace interface + +SUNWprivate_1.1 { + global: + jvm_attach; + jvm_get_last_error; + jvm_enable_dtprobes; + jvm_detach; + local: + *; +}; diff --git a/hotspot/makefiles/symbols/symbols-aix b/hotspot/makefiles/symbols/symbols-aix new file mode 100644 index 00000000000..0efd2dba97f --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-aix @@ -0,0 +1,27 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +JVM_handle_linux_signal +numa_error +numa_warn +sysThreadAvailableStackWithSlack diff --git a/hotspot/makefiles/symbols/symbols-aix-debug b/hotspot/makefiles/symbols/symbols-aix-debug new file mode 100644 index 00000000000..10887ab2b61 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-aix-debug @@ -0,0 +1,26 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +JVM_AccessVMBooleanFlag +JVM_AccessVMIntFlag +JVM_VMBreakPoint diff --git a/hotspot/makefiles/symbols/symbols-linux b/hotspot/makefiles/symbols/symbols-linux new file mode 100644 index 00000000000..0efd2dba97f --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-linux @@ -0,0 +1,27 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +JVM_handle_linux_signal +numa_error +numa_warn +sysThreadAvailableStackWithSlack diff --git a/hotspot/makefiles/symbols/symbols-macosx b/hotspot/makefiles/symbols/symbols-macosx new file mode 100644 index 00000000000..d0243562b67 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-macosx @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +JVM_handle_bsd_signal diff --git a/hotspot/makefiles/symbols/symbols-shared b/hotspot/makefiles/symbols/symbols-shared new file mode 100644 index 00000000000..5d26d1028c7 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-shared @@ -0,0 +1,35 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +AsyncGetCallTrace +jio_fprintf +jio_printf +jio_snprintf +jio_vfprintf +jio_vsnprintf +JNI_CreateJavaVM +JNI_GetCreatedJavaVMs +JNI_GetDefaultJavaVMInitArgs +JVM_FindClassFromBootLoader +JVM_GetVersionInfo +JVM_InitAgentProperties diff --git a/hotspot/makefiles/symbols/symbols-solaris b/hotspot/makefiles/symbols/symbols-solaris new file mode 100644 index 00000000000..bc6124f83a3 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-solaris @@ -0,0 +1,25 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +JVM_handle_solaris_signal +sysThreadAvailableStackWithSlack diff --git a/hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler1 b/hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler1 new file mode 100644 index 00000000000..4ce7d8e30b2 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler1 @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +__1cGMethodG__vtbl_ +__1cHnmethodG__vtbl_ +__1cICodeBlobG__vtbl_ +__1cIUniverseO_collectedHeap_ +__1cJCodeCacheG_heaps_ +__1cKBufferBlobG__vtbl_ +__1cLRuntimeStubG__vtbl_ +__1cNSafepointBlobG__vtbl_ +__1cSDeoptimizationBlobG__vtbl_ + +__JvmOffsets diff --git a/hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler2 b/hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler2 new file mode 100644 index 00000000000..306345e5c29 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-solaris-dtrace-compiler2 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +__1cGMethodG__vtbl_ +__1cHnmethodG__vtbl_ +__1cICodeBlobG__vtbl_ +__1cIUniverseO_collectedHeap_ +__1cJCodeCacheG_heaps_ +__1cKBufferBlobG__vtbl_ +__1cLRuntimeStubG__vtbl_ +__1cNSafepointBlobG__vtbl_ +__1cSDeoptimizationBlobG__vtbl_ +__1cNExceptionBlobG__vtbl_ +__1cQUncommonTrapBlobG__vtbl_ + +__JvmOffsets diff --git a/hotspot/makefiles/symbols/symbols-unix b/hotspot/makefiles/symbols/symbols-unix new file mode 100644 index 00000000000..5d876710e65 --- /dev/null +++ b/hotspot/makefiles/symbols/symbols-unix @@ -0,0 +1,195 @@ +# +# Copyright (c) 2016, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +JVM_ActiveProcessorCount +JVM_ArrayCopy +JVM_AssertionStatusDirectives +JVM_CallStackWalk +JVM_ClassDepth +JVM_ClassLoaderDepth +JVM_Clone +JVM_ConstantPoolGetClassAt +JVM_ConstantPoolGetClassAtIfLoaded +JVM_ConstantPoolGetClassRefIndexAt +JVM_ConstantPoolGetDoubleAt +JVM_ConstantPoolGetFieldAt +JVM_ConstantPoolGetFieldAtIfLoaded +JVM_ConstantPoolGetFloatAt +JVM_ConstantPoolGetIntAt +JVM_ConstantPoolGetLongAt +JVM_ConstantPoolGetMemberRefInfoAt +JVM_ConstantPoolGetMethodAt +JVM_ConstantPoolGetMethodAtIfLoaded +JVM_ConstantPoolGetNameAndTypeRefIndexAt +JVM_ConstantPoolGetNameAndTypeRefInfoAt +JVM_ConstantPoolGetSize +JVM_ConstantPoolGetStringAt +JVM_ConstantPoolGetTagAt +JVM_ConstantPoolGetUTF8At +JVM_CountStackFrames +JVM_CurrentClassLoader +JVM_CurrentLoadedClass +JVM_CurrentThread +JVM_CurrentTimeMillis +JVM_DefineClass +JVM_DefineClassWithSource +JVM_DesiredAssertionStatus +JVM_DoPrivileged +JVM_DumpAllStacks +JVM_DumpThreads +JVM_FillInStackTrace +JVM_FillStackFrames +JVM_FindClassFromCaller +JVM_FindClassFromClass +JVM_FindLibraryEntry +JVM_FindLoadedClass +JVM_FindPrimitiveClass +JVM_FindSignal +JVM_FreeMemory +JVM_GC +JVM_GetAllThreads +JVM_GetArrayElement +JVM_GetArrayLength +JVM_GetCallerClass +JVM_GetClassAccessFlags +JVM_GetClassAnnotations +JVM_GetClassConstantPool +JVM_GetClassContext +JVM_GetClassCPEntriesCount +JVM_GetClassCPTypes +JVM_GetClassDeclaredConstructors +JVM_GetClassDeclaredFields +JVM_GetClassDeclaredMethods +JVM_GetClassFieldsCount +JVM_GetClassInterfaces +JVM_GetClassMethodsCount +JVM_GetClassModifiers +JVM_GetClassName +JVM_GetClassNameUTF +JVM_GetClassSignature +JVM_GetClassSigners +JVM_GetClassTypeAnnotations +JVM_GetCPClassNameUTF +JVM_GetCPFieldClassNameUTF +JVM_GetCPFieldModifiers +JVM_GetCPFieldNameUTF +JVM_GetCPFieldSignatureUTF +JVM_GetCPMethodClassNameUTF +JVM_GetCPMethodModifiers +JVM_GetCPMethodNameUTF +JVM_GetCPMethodSignatureUTF +JVM_GetDeclaredClasses +JVM_GetDeclaringClass +JVM_GetEnclosingMethodInfo +JVM_GetFieldIxModifiers +JVM_GetFieldTypeAnnotations +JVM_GetInheritedAccessControlContext +JVM_GetInterfaceVersion +JVM_GetManagement +JVM_GetMethodIxArgsSize +JVM_GetMethodIxByteCode +JVM_GetMethodIxByteCodeLength +JVM_GetMethodIxExceptionIndexes +JVM_GetMethodIxExceptionsCount +JVM_GetMethodIxExceptionTableEntry +JVM_GetMethodIxExceptionTableLength +JVM_GetMethodIxLocalsCount +JVM_GetMethodIxMaxStack +JVM_GetMethodIxModifiers +JVM_GetMethodIxNameUTF +JVM_GetMethodIxSignatureUTF +JVM_GetMethodParameters +JVM_GetMethodTypeAnnotations +JVM_GetNanoTimeAdjustment +JVM_GetPrimitiveArrayElement +JVM_GetProtectionDomain +JVM_GetSimpleBinaryName +JVM_GetStackAccessControlContext +JVM_GetStackTraceElements +JVM_GetSystemPackage +JVM_GetSystemPackages +JVM_GetTemporaryDirectory +JVM_GetVmArguments +JVM_Halt +JVM_HoldsLock +JVM_IHashCode +JVM_InitProperties +JVM_InternString +JVM_Interrupt +JVM_InvokeMethod +JVM_IsArrayClass +JVM_IsConstructorIx +JVM_IsInterface +JVM_IsInterrupted +JVM_IsPrimitiveClass +JVM_IsSameClassPackage +JVM_IsSupportedJNIVersion +JVM_IsThreadAlive +JVM_IsVMGeneratedMethodIx +JVM_LatestUserDefinedLoader +JVM_LoadLibrary +JVM_MaxMemory +JVM_MaxObjectInspectionAge +JVM_MonitorNotify +JVM_MonitorNotifyAll +JVM_MonitorWait +JVM_MoreStackWalk +JVM_NanoTime +JVM_NativePath +JVM_NewArray +JVM_NewInstanceFromConstructor +JVM_NewMultiArray +JVM_RaiseSignal +JVM_RawMonitorCreate +JVM_RawMonitorDestroy +JVM_RawMonitorEnter +JVM_RawMonitorExit +JVM_RegisterSignal +JVM_ReleaseUTF +JVM_ResumeThread +JVM_SetArrayElement +JVM_SetClassSigners +JVM_SetMethodInfo +JVM_SetNativeThreadName +JVM_SetPrimitiveArrayElement +JVM_SetThreadPriority +JVM_Sleep +JVM_StartThread +JVM_StopThread +JVM_SupportsCX8 +JVM_SuspendThread +JVM_TotalMemory +JVM_UnloadLibrary +JVM_Yield + +# Module related API's +JVM_AddModuleExports +JVM_AddModuleExportsToAll +JVM_AddModuleExportsToAllUnnamed +JVM_AddModulePackage +JVM_AddReadsModule +JVM_CanReadModule +JVM_DefineModule +JVM_IsExportedToModule +JVM_SetBootLoaderUnnamedModule +JVM_GetModuleByPackageName From 2d2abce433c95b7edaf3e77b1a337650007750c1 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 8 Apr 2016 12:26:29 -0700 Subject: [PATCH 20/24] 8153123: Streamline StackWalker code Reviewed-by: coleenp, dfuchs, mchung, redestad --- hotspot/make/share/makefiles/mapfile-vers | 3 +- hotspot/makefiles/symbols/symbols-unix | 3 +- .../src/share/vm/classfile/javaClasses.cpp | 110 +++------------- .../src/share/vm/classfile/javaClasses.hpp | 22 +--- hotspot/src/share/vm/prims/jvm.cpp | 62 +++------ hotspot/src/share/vm/prims/jvm.h | 11 +- hotspot/src/share/vm/prims/stackwalk.cpp | 120 +++++++----------- hotspot/src/share/vm/prims/stackwalk.hpp | 19 ++- hotspot/src/share/vm/runtime/globals.hpp | 3 - 9 files changed, 91 insertions(+), 262 deletions(-) diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index a937f93b84c..f7d08e50b98 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -41,7 +41,6 @@ JVM_DumpAllStacks; JVM_DumpThreads; JVM_FillInStackTrace; - JVM_FillStackFrames; JVM_FindClassFromCaller; JVM_FindClassFromClass; JVM_FindClassFromBootLoader; @@ -157,13 +156,13 @@ JVM_SetClassSigners; JVM_SetNativeThreadName; JVM_SetPrimitiveArrayElement; - JVM_SetMethodInfo; JVM_SetThreadPriority; JVM_Sleep; JVM_StartThread; JVM_StopThread; JVM_SuspendThread; JVM_SupportsCX8; + JVM_ToStackTraceElement; JVM_TotalMemory; JVM_UnloadLibrary; JVM_Yield; diff --git a/hotspot/makefiles/symbols/symbols-unix b/hotspot/makefiles/symbols/symbols-unix index 5d876710e65..406d6f99db3 100644 --- a/hotspot/makefiles/symbols/symbols-unix +++ b/hotspot/makefiles/symbols/symbols-unix @@ -58,7 +58,6 @@ JVM_DoPrivileged JVM_DumpAllStacks JVM_DumpThreads JVM_FillInStackTrace -JVM_FillStackFrames JVM_FindClassFromCaller JVM_FindClassFromClass JVM_FindLibraryEntry @@ -169,7 +168,6 @@ JVM_ReleaseUTF JVM_ResumeThread JVM_SetArrayElement JVM_SetClassSigners -JVM_SetMethodInfo JVM_SetNativeThreadName JVM_SetPrimitiveArrayElement JVM_SetThreadPriority @@ -178,6 +176,7 @@ JVM_StartThread JVM_StopThread JVM_SupportsCX8 JVM_SuspendThread +JVM_ToStackTraceElement JVM_TotalMemory JVM_UnloadLibrary JVM_Yield diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index f61e466e8f2..5365e1df8d6 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -2187,43 +2187,19 @@ void java_lang_StackTraceElement::fill_in(Handle element, } Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) { - if (MemberNameInStackFrame) { - Handle mname(THREAD, stackFrame->obj_field(_memberName_offset)); - Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mname()); - // we should expand MemberName::name when Throwable uses StackTrace - // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL); - return method; - } else { - short mid = stackFrame->short_field(_mid_offset); - short version = stackFrame->short_field(_version_offset); - return holder->method_with_orig_idnum(mid, version); - } -} - -Symbol* java_lang_StackFrameInfo::get_file_name(Handle stackFrame, InstanceKlass* holder) { - if (MemberNameInStackFrame) { - return holder->source_file_name(); - } else { - short version = stackFrame->short_field(_version_offset); - return Backtrace::get_source_file_name(holder, version); - } + Handle mname(THREAD, stackFrame->obj_field(_memberName_offset)); + Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mname()); + // we should expand MemberName::name when Throwable uses StackTrace + // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL); + return method; } void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci) { // set Method* or mid/cpref - if (MemberNameInStackFrame) { - oop mname = stackFrame->obj_field(_memberName_offset); - InstanceKlass* ik = method->method_holder(); - CallInfo info(method(), ik); - MethodHandles::init_method_MemberName(mname, info); - } else { - int mid = method->orig_method_idnum(); - int cpref = method->name_index(); - assert((jushort)mid == mid, "mid should be short"); - assert((jushort)cpref == cpref, "cpref should be short"); - java_lang_StackFrameInfo::set_mid(stackFrame(), (short)mid); - java_lang_StackFrameInfo::set_cpref(stackFrame(), (short)cpref); - } + oop mname = stackFrame->obj_field(_memberName_offset); + InstanceKlass* ik = method->method_holder(); + CallInfo info(method(), ik); + MethodHandles::init_method_MemberName(mname, info); // set bci java_lang_StackFrameInfo::set_bci(stackFrame(), bci); // method may be redefined; store the version @@ -2232,52 +2208,23 @@ void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const metho java_lang_StackFrameInfo::set_version(stackFrame(), (short)version); } -void java_lang_StackFrameInfo::fill_methodInfo(Handle stackFrame, TRAPS) { +void java_lang_StackFrameInfo::to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS) { ResourceMark rm(THREAD); - oop k = stackFrame->obj_field(_declaringClass_offset); - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(k)); + Handle k (THREAD, stackFrame->obj_field(_declaringClass_offset)); + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(k())); Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK); - int bci = stackFrame->int_field(_bci_offset); - // The method can be NULL if the requested class version is gone - Symbol* sym = (method != NULL) ? method->name() : NULL; - if (MemberNameInStackFrame) { - assert(sym != NULL, "MemberName must have method name"); - } else { - // The method can be NULL if the requested class version is gone - if (sym == NULL) { - short cpref = stackFrame->short_field(_cpref_offset); - sym = holder->constants()->symbol_at(cpref); - } - } - - // set method name - oop methodname = StringTable::intern(sym, CHECK); - java_lang_StackFrameInfo::set_methodName(stackFrame(), methodname); - - // set file name and line number - Symbol* source = get_file_name(stackFrame, holder); - if (source != NULL) { - oop filename = StringTable::intern(source, CHECK); - java_lang_StackFrameInfo::set_fileName(stackFrame(), filename); - } - - // if the method has been redefined, the bci is no longer applicable short version = stackFrame->short_field(_version_offset); - if (version_matches(method, version)) { - int line_number = Backtrace::get_line_number(method, bci); - java_lang_StackFrameInfo::set_lineNumber(stackFrame(), line_number); - } + short bci = stackFrame->short_field(_bci_offset); + int cpref = method->name_index(); + java_lang_StackTraceElement::fill_in(stack_trace_element, holder, method, version, bci, cpref, CHECK); } void java_lang_StackFrameInfo::compute_offsets() { Klass* k = SystemDictionary::StackFrameInfo_klass(); compute_offset(_declaringClass_offset, k, vmSymbols::declaringClass_name(), vmSymbols::class_signature()); compute_offset(_memberName_offset, k, vmSymbols::memberName_name(), vmSymbols::object_signature()); - compute_offset(_bci_offset, k, vmSymbols::bci_name(), vmSymbols::int_signature()); - compute_offset(_methodName_offset, k, vmSymbols::methodName_name(), vmSymbols::string_signature()); - compute_offset(_fileName_offset, k, vmSymbols::fileName_name(), vmSymbols::string_signature()); - compute_offset(_lineNumber_offset, k, vmSymbols::lineNumber_name(), vmSymbols::int_signature()); + compute_offset(_bci_offset, k, vmSymbols::bci_name(), vmSymbols::short_signature()); STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } @@ -3690,12 +3637,7 @@ int java_lang_StackTraceElement::moduleVersion_offset; int java_lang_StackFrameInfo::_declaringClass_offset; int java_lang_StackFrameInfo::_memberName_offset; int java_lang_StackFrameInfo::_bci_offset; -int java_lang_StackFrameInfo::_methodName_offset; -int java_lang_StackFrameInfo::_fileName_offset; -int java_lang_StackFrameInfo::_lineNumber_offset; -int java_lang_StackFrameInfo::_mid_offset; int java_lang_StackFrameInfo::_version_offset; -int java_lang_StackFrameInfo::_cpref_offset; int java_lang_LiveStackFrameInfo::_monitors_offset; int java_lang_LiveStackFrameInfo::_locals_offset; int java_lang_LiveStackFrameInfo::_operands_offset; @@ -3741,34 +3683,14 @@ void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { element->obj_field_put(_declaringClass_offset, value); } -void java_lang_StackFrameInfo::set_mid(oop element, short value) { - element->short_field_put(_mid_offset, value); -} - void java_lang_StackFrameInfo::set_version(oop element, short value) { element->short_field_put(_version_offset, value); } -void java_lang_StackFrameInfo::set_cpref(oop element, short value) { - element->short_field_put(_cpref_offset, value); -} - void java_lang_StackFrameInfo::set_bci(oop element, int value) { element->int_field_put(_bci_offset, value); } -void java_lang_StackFrameInfo::set_fileName(oop element, oop value) { - element->obj_field_put(_fileName_offset, value); -} - -void java_lang_StackFrameInfo::set_methodName(oop element, oop value) { - element->obj_field_put(_methodName_offset, value); -} - -void java_lang_StackFrameInfo::set_lineNumber(oop element, int value) { - element->int_field_put(_lineNumber_offset, value); -} - void java_lang_LiveStackFrameInfo::set_monitors(oop element, oop value) { element->obj_field_put(_monitors_offset, value); } diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 560bab7d5f8..4ff32acd6c1 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1364,25 +1364,16 @@ class Backtrace: AllStatic { // Interface to java.lang.StackFrameInfo objects #define STACKFRAMEINFO_INJECTED_FIELDS(macro) \ - macro(java_lang_StackFrameInfo, mid, short_signature, false) \ - macro(java_lang_StackFrameInfo, version, short_signature, false) \ - macro(java_lang_StackFrameInfo, cpref, short_signature, false) + macro(java_lang_StackFrameInfo, version, short_signature, false) class java_lang_StackFrameInfo: AllStatic { private: static int _declaringClass_offset; static int _memberName_offset; static int _bci_offset; - static int _methodName_offset; - static int _fileName_offset; - static int _lineNumber_offset; - - static int _mid_offset; static int _version_offset; - static int _cpref_offset; static Method* get_method(Handle stackFrame, InstanceKlass* holder, TRAPS); - static Symbol* get_file_name(Handle stackFrame, InstanceKlass* holder); public: // Setters @@ -1390,19 +1381,12 @@ public: static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci); static void set_bci(oop info, int value); - // set method info in an instance of StackFrameInfo - static void fill_methodInfo(Handle info, TRAPS); - static void set_methodName(oop info, oop value); - static void set_fileName(oop info, oop value); - static void set_lineNumber(oop info, int value); - - // these injected fields are only used if -XX:-MemberNameInStackFrame set - static void set_mid(oop info, short value); static void set_version(oop info, short value); - static void set_cpref(oop info, short value); static void compute_offsets(); + static void to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS); + // Debugging friend class JavaClasses; }; diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 7665065c9df..2bf88e40b22 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -534,7 +534,6 @@ JVM_END JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jint skip_frames, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames)) JVMWrapper("JVM_CallStackWalk"); JavaThread* jt = (JavaThread*) THREAD; @@ -543,78 +542,51 @@ JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mod } Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); - objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); - objArrayHandle classes_array_h(THREAD, ca); - // frames array is null when only getting caller reference - objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); + // frames array is a Class[] array when only getting caller reference, + // and a StackFrameInfo[] array (or derivative) otherwise. It should never + // be null. + objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); objArrayHandle frames_array_h(THREAD, fa); int limit = start_index + frame_count; - if (classes_array_h->length() < limit) { + if (frames_array_h->length() < limit) { THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", NULL); } Handle result = StackWalk::walk(stackStream_h, mode, skip_frames, frame_count, - start_index, classes_array_h, - frames_array_h, CHECK_NULL); + start_index, frames_array_h, CHECK_NULL); return JNIHandles::make_local(env, result()); JVM_END JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames)) JVMWrapper("JVM_MoreStackWalk"); JavaThread* jt = (JavaThread*) THREAD; - objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); - objArrayHandle classes_array_h(THREAD, ca); - // frames array is null when only getting caller reference - objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); + // frames array is a Class[] array when only getting caller reference, + // and a StackFrameInfo[] array (or derivative) otherwise. It should never + // be null. + objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); objArrayHandle frames_array_h(THREAD, fa); int limit = start_index+frame_count; - if (classes_array_h->length() < limit) { + if (frames_array_h->length() < limit) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers"); } Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); return StackWalk::moreFrames(stackStream_h, mode, anchor, frame_count, - start_index, classes_array_h, - frames_array_h, THREAD); + start_index, frames_array_h, THREAD); JVM_END -JVM_ENTRY(void, JVM_FillStackFrames(JNIEnv *env, jclass stackStream, - jint start_index, - jobjectArray frames, - jint from_index, jint to_index)) - JVMWrapper("JVM_FillStackFrames"); - if (TraceStackWalk) { - tty->print("JVM_FillStackFrames() start_index=%d from_index=%d to_index=%d\n", - start_index, from_index, to_index); - } - - JavaThread* jt = (JavaThread*) THREAD; - - objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); - objArrayHandle frames_array_h(THREAD, fa); - - if (frames_array_h->length() < to_index) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "array length not matched"); - } - - for (int i = from_index; i < to_index; i++) { - Handle stackFrame(THREAD, frames_array_h->obj_at(i)); - java_lang_StackFrameInfo::fill_methodInfo(stackFrame, CHECK); - } -JVM_END - -JVM_ENTRY(void, JVM_SetMethodInfo(JNIEnv *env, jobject frame)) - JVMWrapper("JVM_SetMethodInfo"); - Handle stackFrame(THREAD, JNIHandles::resolve(frame)); - java_lang_StackFrameInfo::fill_methodInfo(stackFrame, THREAD); +JVM_ENTRY(void, JVM_ToStackTraceElement(JNIEnv *env, jobject frame, jobject stack)) + JVMWrapper("JVM_ToStackTraceElement"); + Handle stack_frame_info(THREAD, JNIHandles::resolve_non_null(frame)); + Handle stack_trace_element(THREAD, JNIHandles::resolve_non_null(stack)); + java_lang_StackFrameInfo::to_stack_trace_element(stack_frame_info, stack_trace_element, THREAD); JVM_END // java.lang.Object /////////////////////////////////////////////// diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index dafc3955101..5a055995d1c 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -209,7 +209,6 @@ JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements) */ enum { JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2, - JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10, JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20, JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100 }; @@ -217,23 +216,15 @@ enum { JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jint skip_frames, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames); JNIEXPORT jint JNICALL JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, jint frame_count, jint start_index, - jobjectArray classes, jobjectArray frames); JNIEXPORT void JNICALL -JVM_FillStackFrames(JNIEnv* env, jclass cls, - jint start_index, - jobjectArray frames, - jint from_index, jint toIndex); - -JNIEXPORT void JNICALL -JVM_SetMethodInfo(JNIEnv* env, jobject frame); +JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement); /* * java.lang.Thread diff --git a/hotspot/src/share/vm/prims/stackwalk.cpp b/hotspot/src/share/vm/prims/stackwalk.cpp index 3e292641a79..d772620dcf5 100644 --- a/hotspot/src/share/vm/prims/stackwalk.cpp +++ b/hotspot/src/share/vm/prims/stackwalk.cpp @@ -37,22 +37,22 @@ #include "utilities/globalDefinitions.hpp" // setup and cleanup actions -void StackWalkAnchor::setup_magic_on_entry(objArrayHandle classes_array) { - classes_array->obj_at_put(magic_pos, _thread->threadObj()); +void StackWalkAnchor::setup_magic_on_entry(objArrayHandle frames_array) { + frames_array->obj_at_put(magic_pos, _thread->threadObj()); _anchor = address_value(); - assert(check_magic(classes_array), "invalid magic"); + assert(check_magic(frames_array), "invalid magic"); } -bool StackWalkAnchor::check_magic(objArrayHandle classes_array) { - oop m1 = classes_array->obj_at(magic_pos); +bool StackWalkAnchor::check_magic(objArrayHandle frames_array) { + oop m1 = frames_array->obj_at(magic_pos); jlong m2 = _anchor; if (m1 == _thread->threadObj() && m2 == address_value()) return true; return false; } -bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle classes_array) { - bool ok = check_magic(classes_array); - classes_array->obj_at_put(magic_pos, NULL); +bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle frames_array) { + bool ok = check_magic(frames_array); + frames_array->obj_at_put(magic_pos, NULL); _anchor = 0L; return ok; } @@ -62,18 +62,18 @@ bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle classes_array) { // Parameters: // thread Current Java thread. // magic Magic value used for each stack walking -// classes_array User-supplied buffers. The 0th element is reserved +// frames_array User-supplied buffers. The 0th element is reserved // to this StackWalkAnchor to use // StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic, - objArrayHandle classes_array) + objArrayHandle frames_array) { assert(thread != NULL && thread->is_Java_thread(), ""); - oop m1 = classes_array->obj_at(magic_pos); + oop m1 = frames_array->obj_at(magic_pos); if (m1 != thread->threadObj()) return NULL; if (magic == 0L) return NULL; StackWalkAnchor* anchor = (StackWalkAnchor*) (intptr_t) magic; - if (!anchor->is_valid_in(thread, classes_array)) return NULL; + if (!anchor->is_valid_in(thread, frames_array)) return NULL; return anchor; } @@ -88,24 +88,24 @@ StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic, // vfst vFrameStream. // max_nframes Maximum number of frames to be filled. // start_index Start index to the user-supplied buffers. -// classes_array Buffer to store classes in, starting at start_index. -// frames_array Buffer to store StackFrame in, starting at start_index. -// NULL if not used. +// frames_array Buffer to store Class or StackFrame in, starting at start_index. +// frames array is a Class[] array when only getting caller +// reference, and a StackFrameInfo[] array (or derivative) +// otherwise. It should never be null. // end_index End index to the user-supplied buffers with unpacked frames. // // Returns the number of frames whose information was transferred into the buffers. // int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst, int max_nframes, int start_index, - objArrayHandle classes_array, objArrayHandle frames_array, int& end_index, TRAPS) { if (TraceStackWalk) { tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d", - max_nframes, start_index, classes_array->length()); + max_nframes, start_index, frames_array->length()); } assert(max_nframes > 0, "invalid max_nframes"); - assert(start_index + max_nframes <= classes_array->length(), "oob"); + assert(start_index + max_nframes <= frames_array->length(), "oob"); int frames_decoded = 0; for (; !vfst.at_end(); vfst.next()) { @@ -129,14 +129,18 @@ int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst, tty->print_cr(" bci=%d", bci); } - classes_array->obj_at_put(index, method->method_holder()->java_mirror()); // fill in StackFrameInfo and initialize MemberName if (live_frame_info(mode)) { + assert (use_frames_array(mode), "Bad mode for get live frame"); Handle stackFrame(frames_array->obj_at(index)); fill_live_stackframe(stackFrame, method, bci, vfst.java_frame(), CHECK_0); } else if (need_method_info(mode)) { + assert (use_frames_array(mode), "Bad mode for get stack frame"); Handle stackFrame(frames_array->obj_at(index)); fill_stackframe(stackFrame, method, bci); + } else { + assert (use_frames_array(mode) == false, "Bad mode for get caller class"); + frames_array->obj_at_put(index, method->method_holder()->java_mirror()); } if (++frames_decoded >= max_nframes) break; } @@ -279,15 +283,15 @@ void StackWalk::fill_live_stackframe(Handle stackFrame, const methodHandle& meth // skip_frames Number of frames to be skipped. // frame_count Number of frames to be traversed. // start_index Start index to the user-supplied buffers. -// classes_array Buffer to store classes in, starting at start_index. // frames_array Buffer to store StackFrame in, starting at start_index. -// NULL if not used. +// frames array is a Class[] array when only getting caller +// reference, and a StackFrameInfo[] array (or derivative) +// otherwise. It should never be null. // // Returns Object returned from AbstractStackWalker::doStackWalk call. // oop StackWalk::walk(Handle stackStream, jlong mode, int skip_frames, int frame_count, int start_index, - objArrayHandle classes_array, objArrayHandle frames_array, TRAPS) { JavaThread* jt = (JavaThread*)THREAD; @@ -296,10 +300,8 @@ oop StackWalk::walk(Handle stackStream, jlong mode, mode, skip_frames, frame_count); } - if (need_method_info(mode)) { - if (frames_array.is_null()) { - THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL); - } + if (frames_array.is_null()) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL); } Klass* stackWalker_klass = SystemDictionary::StackWalker_klass(); @@ -313,48 +315,17 @@ oop StackWalk::walk(Handle stackStream, jlong mode, vframeStream& vfst = anchor.vframe_stream(); { - // Skip all methods from AbstractStackWalker and StackWalk (enclosing method) - if (!fill_in_stacktrace(mode)) { - while (!vfst.at_end()) { - InstanceKlass* ik = vfst.method()->method_holder(); - if (ik != stackWalker_klass && - ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { - break; - } - - if (TraceStackWalk) { - tty->print(" skip "); vfst.method()->print_short_name(); tty->print("\n"); - } - vfst.next(); + while (!vfst.at_end()) { + InstanceKlass* ik = vfst.method()->method_holder(); + if (ik != stackWalker_klass && + ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { + break; } - } - // For exceptions, skip Throwable::fillInStackTrace and methods - // of the exception class and superclasses - if (fill_in_stacktrace(mode)) { - bool skip_to_fillInStackTrace = false; - bool skip_throwableInit_check = false; - while (!vfst.at_end() && !skip_throwableInit_check) { - InstanceKlass* ik = vfst.method()->method_holder(); - Method* method = vfst.method(); - if (!skip_to_fillInStackTrace) { - if (ik == SystemDictionary::Throwable_klass() && - method->name() == vmSymbols::fillInStackTrace_name()) { - // this frame will be skipped - skip_to_fillInStackTrace = true; - } - } else if (!(ik->is_subclass_of(SystemDictionary::Throwable_klass()) && - method->name() == vmSymbols::object_initializer_name())) { - // there are none or we've seen them all - either way stop checking - skip_throwableInit_check = true; - break; - } - - if (TraceStackWalk) { - tty->print("stack walk: skip "); vfst.method()->print_short_name(); tty->print("\n"); - } - vfst.next(); + if (TraceStackWalk) { + tty->print(" skip "); vfst.method()->print_short_name(); tty->print("\n"); } + vfst.next(); } // stack frame has been traversed individually and resume stack walk @@ -372,7 +343,7 @@ oop StackWalk::walk(Handle stackStream, jlong mode, int end_index = start_index; int numFrames = 0; if (!vfst.at_end()) { - numFrames = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, + numFrames = fill_in_frames(mode, vfst, frame_count, start_index, frames_array, end_index, CHECK_NULL); if (numFrames < 1) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL); @@ -392,12 +363,12 @@ oop StackWalk::walk(Handle stackStream, jlong mode, args.push_int(end_index); // Link the thread and vframe stream into the callee-visible object - anchor.setup_magic_on_entry(classes_array); + anchor.setup_magic_on_entry(frames_array); JavaCalls::call(&result, m_doStackWalk, &args, THREAD); // Do this before anything else happens, to disable any lingering stream objects - bool ok = anchor.cleanup_magic_on_exit(classes_array); + bool ok = anchor.cleanup_magic_on_exit(frames_array); // Throw pending exception if we must (void) (CHECK_NULL); @@ -419,31 +390,28 @@ oop StackWalk::walk(Handle stackStream, jlong mode, // magic Must be valid value to continue the stack walk // frame_count Number of frames to be decoded. // start_index Start index to the user-supplied buffers. -// classes_array Buffer to store classes in, starting at start_index. // frames_array Buffer to store StackFrame in, starting at start_index. -// NULL if not used. // // Returns the end index of frame filled in the buffer. // jint StackWalk::moreFrames(Handle stackStream, jlong mode, jlong magic, int frame_count, int start_index, - objArrayHandle classes_array, objArrayHandle frames_array, TRAPS) { JavaThread* jt = (JavaThread*)THREAD; - StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, classes_array); + StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, frames_array); if (existing_anchor == NULL) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L); } - if ((need_method_info(mode) || live_frame_info(mode)) && frames_array.is_null()) { + if (frames_array.is_null()) { THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L); } if (TraceStackWalk) { tty->print_cr("StackWalk::moreFrames frame_count %d existing_anchor " PTR_FORMAT " start %d frames %d", - frame_count, p2i(existing_anchor), start_index, classes_array->length()); + frame_count, p2i(existing_anchor), start_index, frames_array->length()); } int end_index = start_index; if (frame_count <= 0) { @@ -451,14 +419,14 @@ jint StackWalk::moreFrames(Handle stackStream, jlong mode, jlong magic, } int count = frame_count + start_index; - assert (classes_array->length() >= count, "not enough space in buffers"); + assert (frames_array->length() >= count, "not enough space in buffers"); StackWalkAnchor& anchor = (*existing_anchor); vframeStream& vfst = anchor.vframe_stream(); if (!vfst.at_end()) { vfst.next(); // this was the last frame decoded in the previous batch if (!vfst.at_end()) { - int n = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, + int n = fill_in_frames(mode, vfst, frame_count, start_index, frames_array, end_index, CHECK_0); if (n < 1) { THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); diff --git a/hotspot/src/share/vm/prims/stackwalk.hpp b/hotspot/src/share/vm/prims/stackwalk.hpp index 1fa906815be..2eb41aeb711 100644 --- a/hotspot/src/share/vm/prims/stackwalk.hpp +++ b/hotspot/src/share/vm/prims/stackwalk.hpp @@ -45,12 +45,12 @@ public: vframeStream& vframe_stream() { return _vfst; } JavaThread* thread() { return _thread; } - void setup_magic_on_entry(objArrayHandle classes_array); - bool check_magic(objArrayHandle classes_array); - bool cleanup_magic_on_exit(objArrayHandle classes_array); + void setup_magic_on_entry(objArrayHandle frames_array); + bool check_magic(objArrayHandle frames_array); + bool cleanup_magic_on_exit(objArrayHandle frames_array); - bool is_valid_in(Thread* thread, objArrayHandle classes_array) { - return (_thread == thread && check_magic(classes_array)); + bool is_valid_in(Thread* thread, objArrayHandle frames_array) { + return (_thread == thread && check_magic(frames_array)); } jlong address_value() { @@ -64,7 +64,6 @@ class StackWalk : public AllStatic { private: static int fill_in_frames(jlong mode, vframeStream& vfst, int max_nframes, int start_index, - objArrayHandle classes_array, objArrayHandle frames_array, int& end_index, TRAPS); @@ -82,20 +81,18 @@ private: static inline bool live_frame_info(int mode) { return (mode & JVM_STACKWALK_FILL_LIVE_STACK_FRAMES) != 0; } - static inline bool fill_in_stacktrace(int mode) { - return (mode & JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE) != 0; - } public: + static inline bool use_frames_array(int mode) { + return (mode & JVM_STACKWALK_FILL_CLASS_REFS_ONLY) == 0; + } static oop walk(Handle stackStream, jlong mode, int skip_frames, int frame_count, int start_index, - objArrayHandle classes_array, objArrayHandle frames_array, TRAPS); static jint moreFrames(Handle stackStream, jlong mode, jlong magic, int frame_count, int start_index, - objArrayHandle classes_array, objArrayHandle frames_array, TRAPS); }; diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 49e24ed385a..044e26e3ccf 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2958,9 +2958,6 @@ public: develop(bool, TraceStackWalk, false, \ "Trace stack walking") \ \ - product(bool, MemberNameInStackFrame, true, \ - "Use MemberName in StackFrame") \ - \ /* notice: the max range value here is max_jint, not max_intx */ \ /* because of overflow issue */ \ NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000, \ From 28edd79d641a53032589868b3a6ee9441a7b8966 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Thu, 7 Apr 2016 22:03:04 -0700 Subject: [PATCH 21/24] 8145221: Use trampolines for i2i and i2c entries in Methods that are stored in CDS archive This optimization reduces the size of the RW region of the CDS archive. It also reduces the amount of pages in the RW region that are actually written into during runtime. Co-authored-by: Ioi Lam Co-authored-by: Goetz Lindenmaier Reviewed-by: dlong, iklam, jiangli --- .../cpu/aarch64/vm/sharedRuntime_aarch64.cpp | 10 +++ hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 12 +++ .../cpu/sparc/vm/metaspaceShared_sparc.cpp | 2 - .../src/cpu/sparc/vm/sharedRuntime_sparc.cpp | 10 +++ .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 8 ++ .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 8 ++ .../src/cpu/zero/vm/sharedRuntime_zero.cpp | 9 ++ .../src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp | 9 ++ .../linux_aarch64/vm/thread_linux_aarch64.cpp | 9 ++ .../linux_sparc/vm/thread_linux_sparc.cpp | 9 ++ .../os_cpu/linux_x86/vm/thread_linux_x86.cpp | 9 ++ .../solaris_sparc/vm/thread_solaris_sparc.cpp | 9 ++ .../solaris_x86/vm/thread_solaris_x86.cpp | 9 ++ .../windows_x86/vm/thread_windows_x86.cpp | 9 ++ .../vm/interpreter/abstractInterpreter.cpp | 33 ++++++- .../vm/interpreter/abstractInterpreter.hpp | 12 +++ .../templateInterpreterGenerator.cpp | 1 + hotspot/src/share/vm/memory/filemap.cpp | 10 +++ hotspot/src/share/vm/memory/filemap.hpp | 16 ++++ .../src/share/vm/memory/metaspaceShared.cpp | 30 ++++++- .../src/share/vm/memory/metaspaceShared.hpp | 25 ++++-- hotspot/src/share/vm/oops/constMethod.hpp | 30 +++++++ hotspot/src/share/vm/oops/method.cpp | 85 +++++++++++++------ hotspot/src/share/vm/oops/method.hpp | 29 +++++-- .../src/share/vm/runtime/sharedRuntime.cpp | 45 +++++++++- .../src/share/vm/runtime/sharedRuntime.hpp | 16 ++++ hotspot/src/share/vm/runtime/vmStructs.cpp | 1 - 27 files changed, 408 insertions(+), 47 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index 0aeba4cb33c..760256da378 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -198,6 +198,16 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm) { bool SharedRuntime::is_wide_vector(int size) { return size > 8; } + +size_t SharedRuntime::trampoline_size() { + return 16; +} + +void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { + __ mov(rscratch1, destination); + __ br(rscratch1); +} + // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions // (like the placement of the register window) the slots must be biased by diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index 49df282945d..ee8685f4f0a 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -483,6 +483,18 @@ bool SharedRuntime::is_wide_vector(int size) { assert(size <= 8, "%d bytes vectors are not supported", size); return size > 8; } + +size_t SharedRuntime::trampoline_size() { + return Assembler::load_const_size + 8; +} + +void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { + Register Rtemp = R12; + __ load_const(Rtemp, destination); + __ mtctr(Rtemp); + __ bctr(); +} + #ifdef COMPILER2 static int reg2slot(VMReg r) { return r->reg2stack() + SharedRuntime::out_preserve_stack_slots(); diff --git a/hotspot/src/cpu/sparc/vm/metaspaceShared_sparc.cpp b/hotspot/src/cpu/sparc/vm/metaspaceShared_sparc.cpp index 28f606be3b0..cc0141c283e 100644 --- a/hotspot/src/cpu/sparc/vm/metaspaceShared_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/metaspaceShared_sparc.cpp @@ -65,8 +65,6 @@ void MetaspaceShared::generate_vtable_methods(void** vtbl_list, *vtable = dummy_vtable; *md_top += vtable_bytes; - guarantee(*md_top <= md_end, "Insufficient space for vtables."); - // Get ready to generate dummy methods. CodeBuffer cb((unsigned char*)*mc_top, mc_end - *mc_top); diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index ab9fed0d5d1..6727c14d63b 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -324,6 +324,16 @@ bool SharedRuntime::is_wide_vector(int size) { return size > 8; } +size_t SharedRuntime::trampoline_size() { + return 40; +} + +void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { + __ set((intptr_t)destination, G3_scratch); + __ JMP(G3_scratch, 0); + __ delayed()->nop(); +} + // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions // (like the placement of the register window) the slots must be biased by diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index abe9a369eaa..3763b058b8b 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -355,6 +355,14 @@ bool SharedRuntime::is_wide_vector(int size) { return size > 16; } +size_t SharedRuntime::trampoline_size() { + return 16; +} + +void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { + __ jump(RuntimeAddress(destination)); +} + // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions // (like the placement of the register window) the slots must be biased by diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index a5c8f82e6ef..8fca552dd34 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -391,6 +391,14 @@ bool SharedRuntime::is_wide_vector(int size) { return size > 16; } +size_t SharedRuntime::trampoline_size() { + return 16; +} + +void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { + __ jump(RuntimeAddress(destination)); +} + // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions // (like the placement of the register window) the slots must be biased by diff --git a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp index 3fbe12e94f9..0fb36b01b75 100644 --- a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp +++ b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp @@ -132,6 +132,15 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return generate_empty_runtime_stub("resolve_blob"); } +size_t SharedRuntime::trampoline_size() { + ShouldNotCallThis(); + return 0; +} + +void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { + ShouldNotCallThis(); + return; +} int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, diff --git a/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp index c4f991aa650..df36e6edbe1 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -64,6 +65,14 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { #if defined(COMPILER2) || INCLUDE_JVMCI diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.cpp index cd6f71efe2c..07206d873d7 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.cpp @@ -24,6 +24,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -66,6 +67,14 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { #ifdef COMPILER2 diff --git a/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp index dac85519a0c..c571507e675 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -64,6 +65,14 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + // we were running Java code when SIGPROF came in if (isInJava) { // If we have a last_Java_sp, then the SIGPROF signal caught us diff --git a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp index 55e5bbac4e2..3075dd19dd3 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -65,6 +66,14 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { #if defined(COMPILER2) || INCLUDE_JVMCI diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp index 9964114a787..ddbaa702063 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -77,6 +78,14 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + frame ret_frame(ret_sp, frame::unpatchable, addr.pc()); // we were running Java code when SIGPROF came in diff --git a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp index d41f3e7167f..48af49f7497 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -70,6 +71,14 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + // If sp and fp are nonsense just leave them out if (!jt->on_local_stack((address)ret_sp)) { diff --git a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp index 08afec24834..ba5be5736cf 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/metaspaceShared.hpp" #include "runtime/frame.inline.hpp" #include "runtime/thread.inline.hpp" @@ -72,6 +73,14 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) return false; } +#if INCLUDE_CDS + if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { + // In the middle of a trampoline call. Bail out for safety. + // This happens rarely so shouldn't affect profiling. + return false; + } +#endif + frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { #if defined(COMPILER2) || INCLUDE_JVMCI diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp index 96fb64403cd..3717ae061d9 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "compiler/disassembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeInterpreter.hpp" #include "interpreter/interpreter.hpp" @@ -32,6 +33,7 @@ #include "interpreter/interp_masm.hpp" #include "interpreter/templateTable.hpp" #include "memory/allocation.inline.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "oops/arrayOop.hpp" #include "oops/methodData.hpp" @@ -93,6 +95,7 @@ address AbstractInterpreter::_native_entry_begin = NU address AbstractInterpreter::_native_entry_end = NULL; address AbstractInterpreter::_slow_signature_handler; address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries]; +address AbstractInterpreter::_cds_entry_table [AbstractInterpreter::number_of_method_entries]; address AbstractInterpreter::_native_abi_to_tosca [AbstractInterpreter::number_of_result_handlers]; //------------------------------------------------------------------------------------------------------------------------ @@ -204,14 +207,41 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m) return zerolocals; } +#if INCLUDE_CDS + +address AbstractInterpreter::get_trampoline_code_buffer(AbstractInterpreter::MethodKind kind) { + const size_t trampoline_size = SharedRuntime::trampoline_size(); + address addr = MetaspaceShared::cds_i2i_entry_code_buffers((size_t)(AbstractInterpreter::number_of_method_entries) * trampoline_size); + addr += (size_t)(kind) * trampoline_size; + + return addr; +} + +void AbstractInterpreter::update_cds_entry_table(AbstractInterpreter::MethodKind kind) { + if (DumpSharedSpaces || UseSharedSpaces) { + address trampoline = get_trampoline_code_buffer(kind); + _cds_entry_table[kind] = trampoline; + + CodeBuffer buffer(trampoline, (int)(SharedRuntime::trampoline_size())); + MacroAssembler _masm(&buffer); + SharedRuntime::generate_trampoline(&_masm, _entry_table[kind]); + + if (PrintInterpreter) { + Disassembler::decode(buffer.insts_begin(), buffer.insts_end()); + } + } +} + +#endif void AbstractInterpreter::set_entry_for_kind(AbstractInterpreter::MethodKind kind, address entry) { assert(kind >= method_handle_invoke_FIRST && kind <= method_handle_invoke_LAST, "late initialization only for MH entry points"); assert(_entry_table[kind] == _entry_table[abstract], "previous value must be AME entry"); _entry_table[kind] = entry; -} + update_cds_entry_table(kind); +} // Return true if the interpreter can prove that the given bytecode has // not yet been executed (in Java semantics, not in actual operation). @@ -416,5 +446,6 @@ void AbstractInterpreter::initialize_method_handle_entries() { for (int i = method_handle_invoke_FIRST; i <= method_handle_invoke_LAST; i++) { MethodKind kind = (MethodKind) i; _entry_table[kind] = _entry_table[Interpreter::abstract]; + Interpreter::update_cds_entry_table(kind); } } diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index 8be852bae60..db31ac83400 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -113,6 +113,7 @@ class AbstractInterpreter: AllStatic { // method entry points static address _entry_table[number_of_method_entries]; // entry points for a given method + static address _cds_entry_table[number_of_method_entries]; // entry points for methods in the CDS archive static address _native_abi_to_tosca[number_of_result_handlers]; // for native method result handlers static address _slow_signature_handler; // the native method generic (slow) signature handler @@ -132,6 +133,17 @@ class AbstractInterpreter: AllStatic { static address entry_for_kind(MethodKind k) { assert(0 <= k && k < number_of_method_entries, "illegal kind"); return _entry_table[k]; } static address entry_for_method(methodHandle m) { return entry_for_kind(method_kind(m)); } + static address entry_for_cds_method(methodHandle m) { + MethodKind k = method_kind(m); + assert(0 <= k && k < number_of_method_entries, "illegal kind"); + return _cds_entry_table[k]; + } + + // used by class data sharing + static void update_cds_entry_table(MethodKind kind) NOT_CDS_RETURN; + + static address get_trampoline_code_buffer(AbstractInterpreter::MethodKind kind) NOT_CDS_RETURN_(0); + // used for bootstrapping method handles: static void set_entry_for_kind(MethodKind k, address e); diff --git a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp index 0fbe6f8ddac..a10981c48af 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp @@ -212,6 +212,7 @@ void TemplateInterpreterGenerator::generate_all() { #define method_entry(kind) \ { CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \ Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \ + Interpreter::update_cds_entry_table(Interpreter::kind); \ } // all non-native method kinds diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 606b7bd6960..ec3b9462959 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -959,6 +959,16 @@ bool FileMapInfo::is_in_shared_space(const void* p) { return false; } +// Check if a given address is within one of the shared regions (ro, rw, md, mc) +bool FileMapInfo::is_in_shared_region(const void* p, int idx) { + assert((idx >= MetaspaceShared::ro) && (idx <= MetaspaceShared::mc), "invalid region index"); + char* base = _header->region_addr(idx); + if (p >= base && p < base + _header->_space[idx]._used) { + return true; + } + return false; +} + void FileMapInfo::print_shared_spaces() { tty->print_cr("Shared Spaces:"); for (int i = 0; i < MetaspaceShared::n_regions; i++) { diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 7cb179434b9..2c02b427f0b 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -107,6 +107,8 @@ public: int _narrow_klass_shift; // save narrow klass base and shift address _narrow_klass_base; char* _misc_data_patching_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; struct space_info { int _crc; // crc checksum of the current space @@ -195,6 +197,19 @@ public: char* misc_data_patching_start() { return _header->_misc_data_patching_start; } void set_misc_data_patching_start(char* p) { _header->_misc_data_patching_start = p; } + address cds_i2i_entry_code_buffers() { + return _header->_cds_i2i_entry_code_buffers; + } + void set_cds_i2i_entry_code_buffers(address addr) { + _header->_cds_i2i_entry_code_buffers = addr; + } + size_t cds_i2i_entry_code_buffers_size() { + return _header->_cds_i2i_entry_code_buffers_size; + } + void set_cds_i2i_entry_code_buffers_size(size_t s) { + _header->_cds_i2i_entry_code_buffers_size = s; + } + static FileMapInfo* current_info() { CDS_ONLY(return _current_info;) NOT_CDS(return NULL;) @@ -234,6 +249,7 @@ public: // Return true if given address is in the mapped shared space. bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); + bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false); void print_shared_spaces() NOT_CDS_RETURN; static size_t shared_spaces_size() { diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 36efacfc4ab..fa4d31a54be 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -59,6 +59,8 @@ bool MetaspaceShared::_link_classes_made_progress; bool MetaspaceShared::_check_classes_made_progress; bool MetaspaceShared::_has_error_classes; bool MetaspaceShared::_archive_loading_failed = false; +address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL; +size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0; SharedMiscRegion MetaspaceShared::_mc; SharedMiscRegion MetaspaceShared::_md; @@ -129,6 +131,21 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { soc->do_tag(666); } +address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) { + if (DumpSharedSpaces) { + if (_cds_i2i_entry_code_buffers == NULL) { + _cds_i2i_entry_code_buffers = (address)misc_data_space_alloc(total_size); + _cds_i2i_entry_code_buffers_size = total_size; + } + } else if (UseSharedSpaces) { + assert(_cds_i2i_entry_code_buffers != NULL, "must already been initialized"); + } else { + return NULL; + } + + assert(_cds_i2i_entry_code_buffers_size == total_size, "must not change"); + return _cds_i2i_entry_code_buffers; +} // CDS code for dumping shared archive. @@ -576,6 +593,8 @@ void VM_PopulateDumpSharedSpace::doit() { &md_top, md_end, &mc_top, mc_end); + guarantee(md_top <= md_end, "Insufficient space for vtables."); + // Reorder the system dictionary. (Moving the symbols affects // how the hash table indices are calculated.) // Not doing this either. @@ -668,6 +687,8 @@ void VM_PopulateDumpSharedSpace::doit() { FileMapInfo* mapinfo = new FileMapInfo(); mapinfo->populate_header(MetaspaceShared::max_alignment()); mapinfo->set_misc_data_patching_start((char*)vtbl_list); + mapinfo->set_cds_i2i_entry_code_buffers(MetaspaceShared::cds_i2i_entry_code_buffers()); + mapinfo->set_cds_i2i_entry_code_buffers_size(MetaspaceShared::cds_i2i_entry_code_buffers_size()); for (int pass=1; pass<=2; pass++) { if (pass == 1) { @@ -686,7 +707,7 @@ void VM_PopulateDumpSharedSpace::doit() { mapinfo->write_region(MetaspaceShared::md, _md_vs.low(), pointer_delta(md_top, _md_vs.low(), sizeof(char)), SharedMiscDataSize, - false, false); + false, true); mapinfo->write_region(MetaspaceShared::mc, _mc_vs.low(), pointer_delta(mc_top, _mc_vs.low(), sizeof(char)), SharedMiscCodeSize, @@ -980,6 +1001,11 @@ bool MetaspaceShared::is_in_shared_space(const void* p) { return UseSharedSpaces && FileMapInfo::current_info()->is_in_shared_space(p); } +// Return true if given address is in the misc data region +bool MetaspaceShared::is_in_shared_region(const void* p, int idx) { + return UseSharedSpaces && FileMapInfo::current_info()->is_in_shared_region(p, idx); +} + bool MetaspaceShared::is_string_region(int idx) { return (idx >= MetaspaceShared::first_string && idx < MetaspaceShared::first_string + MetaspaceShared::max_strings); @@ -1053,6 +1079,8 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) { void MetaspaceShared::initialize_shared_spaces() { FileMapInfo *mapinfo = FileMapInfo::current_info(); + _cds_i2i_entry_code_buffers = mapinfo->cds_i2i_entry_code_buffers(); + _cds_i2i_entry_code_buffers_size = mapinfo->cds_i2i_entry_code_buffers_size(); char* buffer = mapinfo->misc_data_patching_start(); // Skip over (reserve space for) a list of addresses of C++ vtables diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index c78f78122cf..e759464591d 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -50,17 +50,14 @@ #define MIN_SHARED_READ_ONLY_SIZE (NOT_LP64(8*M) LP64_ONLY(9*M)) // the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on -// MetaspaceShared::generate_vtable_methods(). -// The minimum size only accounts for the vtable methods. Any size less than the -// minimum required size would cause vm crash when allocating the vtable methods. -#define SHARED_MISC_SIZE_FOR(size) (DEFAULT_VTBL_VIRTUALS_COUNT*DEFAULT_VTBL_LIST_SIZE*size) +// the sizes required for dumping the archive using the default classlist. The sizes +// are multiplied by 1.5 for a safety margin. #define DEFAULT_SHARED_MISC_DATA_SIZE (NOT_LP64(2*M) LP64_ONLY(4*M)) -#define MIN_SHARED_MISC_DATA_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*))) +#define MIN_SHARED_MISC_DATA_SIZE (NOT_LP64(1*M) LP64_ONLY(1200*K)) #define DEFAULT_SHARED_MISC_CODE_SIZE (120*K) -#define MIN_SHARED_MISC_CODE_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*))+SHARED_MISC_SIZE_FOR(DEFAULT_VTBL_METHOD_SIZE)+DEFAULT_VTBL_COMMON_CODE_SIZE) - +#define MIN_SHARED_MISC_CODE_SIZE (NOT_LP64(63*K) LP64_ONLY(69*K)) #define DEFAULT_COMBINED_SIZE (DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE) // the max size is the MAX size (ie. 0x7FFFFFFF) - the total size of @@ -128,6 +125,8 @@ class MetaspaceShared : AllStatic { static bool _check_classes_made_progress; static bool _has_error_classes; static bool _archive_loading_failed; + static address _cds_i2i_entry_code_buffers; + static size_t _cds_i2i_entry_code_buffers_size; // Used only during dumping. static SharedMiscRegion _md; @@ -185,6 +184,9 @@ class MetaspaceShared : AllStatic { // Return true if given address is in the mapped shared space. static bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); + // Return true if given address is in the shared region corresponding to the idx + static bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false); + static bool is_string_region(int idx) NOT_CDS_RETURN_(false); static void generate_vtable_methods(void** vtbl_list, @@ -218,6 +220,15 @@ class MetaspaceShared : AllStatic { static char* misc_code_space_alloc(size_t num_bytes) { return _mc.alloc(num_bytes); } static char* misc_data_space_alloc(size_t num_bytes) { return _md.alloc(num_bytes); } + static address cds_i2i_entry_code_buffers(size_t total_size); + + static address cds_i2i_entry_code_buffers() { + return _cds_i2i_entry_code_buffers; + } + static size_t cds_i2i_entry_code_buffers_size() { + return _cds_i2i_entry_code_buffers_size; + } + static SharedMiscRegion* misc_code_region() { assert(DumpSharedSpaces, "used during dumping only"); return &_mc; diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 7d959fb516b..01df3b1a3d8 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -121,6 +121,7 @@ class MethodParametersElement VALUE_OBJ_CLASS_SPEC { }; class KlassSizeStats; +class AdapterHandlerEntry; // Class to collect the sizes of ConstMethod inline tables #define INLINE_TABLES_DO(do_element) \ @@ -201,6 +202,12 @@ private: // Raw stackmap data for the method Array* _stackmap_data; + // Adapter blob (i2c/c2i) for this Method*. Set once when method is linked. + union { + AdapterHandlerEntry* _adapter; + AdapterHandlerEntry** _adapter_trampoline; + }; + int _constMethod_size; u2 _flags; @@ -276,6 +283,29 @@ public: void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS); bool has_stackmap_table() const { return _stackmap_data != NULL; } + // adapter + void set_adapter_entry(AdapterHandlerEntry* adapter) { + assert(!is_shared(), "shared methods have fixed adapter_trampoline"); + _adapter = adapter; + } + void set_adapter_trampoline(AdapterHandlerEntry** trampoline) { + assert(DumpSharedSpaces, "must be"); + assert(*trampoline == NULL, "must be NULL during dump time, to be initialized at run time"); + _adapter_trampoline = trampoline; + } + void update_adapter_trampoline(AdapterHandlerEntry* adapter) { + assert(is_shared(), "must be"); + *_adapter_trampoline = adapter; + assert(this->adapter() == adapter, "must be"); + } + AdapterHandlerEntry* adapter() { + if (is_shared()) { + return *_adapter_trampoline; + } else { + return _adapter; + } + } + void init_fingerprint() { const uint64_t initval = UCONST64(0x8000000000000000); _fingerprint = initval; diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index efaaaa5009a..b3f2b868b64 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -38,6 +38,7 @@ #include "interpreter/oopMapCache.hpp" #include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/constMethod.hpp" @@ -123,18 +124,18 @@ void Method::deallocate_contents(ClassLoaderData* loader_data) { } address Method::get_i2c_entry() { - assert(_adapter != NULL, "must have"); - return _adapter->get_i2c_entry(); + assert(adapter() != NULL, "must have"); + return adapter()->get_i2c_entry(); } address Method::get_c2i_entry() { - assert(_adapter != NULL, "must have"); - return _adapter->get_c2i_entry(); + assert(adapter() != NULL, "must have"); + return adapter()->get_c2i_entry(); } address Method::get_c2i_unverified_entry() { - assert(_adapter != NULL, "must have"); - return _adapter->get_c2i_unverified_entry(); + assert(adapter() != NULL, "must have"); + return adapter()->get_c2i_unverified_entry(); } char* Method::name_and_sig_as_C_string() const { @@ -892,10 +893,10 @@ void Method::clear_code() { // this may be NULL if c2i adapters have not been made yet // Only should happen at allocate time. - if (_adapter == NULL) { + if (adapter() == NULL) { _from_compiled_entry = NULL; } else { - _from_compiled_entry = _adapter->get_c2i_entry(); + _from_compiled_entry = adapter()->get_c2i_entry(); } OrderAccess::storestore(); _from_interpreted_entry = _i2i_entry; @@ -903,47 +904,68 @@ void Method::clear_code() { _code = NULL; } +#if INCLUDE_CDS // Called by class data sharing to remove any entry points (which are not shared) void Method::unlink_method() { _code = NULL; - _i2i_entry = NULL; - _from_interpreted_entry = NULL; + + assert(DumpSharedSpaces, "dump time only"); + // Set the values to what they should be at run time. Note that + // this Method can no longer be executed during dump time. + _i2i_entry = Interpreter::entry_for_cds_method(this); + _from_interpreted_entry = _i2i_entry; + if (is_native()) { *native_function_addr() = NULL; set_signature_handler(NULL); } NOT_PRODUCT(set_compiled_invocation_count(0);) - _adapter = NULL; - _from_compiled_entry = NULL; + + CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter(); + constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline()); + _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline(); + assert(*((int*)_from_compiled_entry) == 0, "must be NULL during dump time, to be initialized at run time"); + // In case of DumpSharedSpaces, _method_data should always be NULL. - // - // During runtime (!DumpSharedSpaces), when we are cleaning a - // shared class that failed to load, this->link_method() may - // have already been called (before an exception happened), so - // this->_method_data may not be NULL. - assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); + assert(_method_data == NULL, "unexpected method data?"); set_method_data(NULL); clear_method_counters(); } +#endif // Called when the method_holder is getting linked. Setup entrypoints so the method // is ready to be called from interpreter, compiler, and vtables. void Method::link_method(const methodHandle& h_method, TRAPS) { // If the code cache is full, we may reenter this function for the // leftover methods that weren't linked. - if (_i2i_entry != NULL) return; + if (is_shared()) { + if (adapter() != NULL) return; + } else { + if (_i2i_entry != NULL) return; - assert(_adapter == NULL, "init'd to NULL" ); + assert(adapter() == NULL, "init'd to NULL" ); + } assert( _code == NULL, "nothing compiled yet" ); // Setup interpreter entrypoint assert(this == h_method(), "wrong h_method()" ); - address entry = Interpreter::entry_for_method(h_method); + address entry; + + if (this->is_shared()) { + entry = Interpreter::entry_for_cds_method(h_method); + } else { + entry = Interpreter::entry_for_method(h_method); + } assert(entry != NULL, "interpreter entry must be non-null"); - // Sets both _i2i_entry and _from_interpreted_entry - set_interpreter_entry(entry); + if (is_shared()) { + assert(entry == _i2i_entry && entry == _from_interpreted_entry, + "should be correctly set during dump time"); + } else { + // Sets both _i2i_entry and _from_interpreted_entry + set_interpreter_entry(entry); + } // Don't overwrite already registered native entries. if (is_native() && !has_native_function()) { @@ -975,8 +997,13 @@ address Method::make_adapters(methodHandle mh, TRAPS) { THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "Out of space in CodeCache for adapters"); } - mh->set_adapter_entry(adapter); - mh->_from_compiled_entry = adapter->get_c2i_entry(); + if (mh->is_shared()) { + assert(mh->adapter() == adapter, "must be"); + assert(mh->_from_compiled_entry != NULL, "must be"); // FIXME, the instructions also not NULL + } else { + mh->set_adapter_entry(adapter); + mh->_from_compiled_entry = adapter->get_c2i_entry(); + } return adapter->get_c2i_entry(); } @@ -992,6 +1019,14 @@ void Method::restore_unshareable_info(TRAPS) { } } +volatile address Method::from_compiled_entry_no_trampoline() const { + nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code); + if (code) { + return code->verified_entry_point(); + } else { + return adapter()->get_c2i_entry(); + } +} // The verified_code_entry() must be called when a invoke is resolved // on this method. diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 8fc7b133a16..d7a705fd84f 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -93,8 +93,6 @@ class Method : public Metadata { #endif // Entry point for calling both from and to the interpreter. address _i2i_entry; // All-args-on-stack calling convention - // Adapter blob (i2c/c2i) for this Method*. Set once when method is linked. - AdapterHandlerEntry* _adapter; // Entry point for calling from compiled code, to compiled code if it exists // or else the interpreter. volatile address _from_compiled_entry; // Cache of: _code ? _code->entry_point() : _adapter->c2i_entry() @@ -137,6 +135,7 @@ class Method : public Metadata { static address make_adapters(methodHandle mh, TRAPS); volatile address from_compiled_entry() const { return (address)OrderAccess::load_ptr_acquire(&_from_compiled_entry); } + volatile address from_compiled_entry_no_trampoline() const; volatile address from_interpreted_entry() const{ return (address)OrderAccess::load_ptr_acquire(&_from_interpreted_entry); } // access flag @@ -431,15 +430,23 @@ class Method : public Metadata { nmethod* volatile code() const { assert( check_code(), "" ); return (nmethod *)OrderAccess::load_ptr_acquire(&_code); } void clear_code(); // Clear out any compiled code static void set_code(methodHandle mh, nmethod* code); - void set_adapter_entry(AdapterHandlerEntry* adapter) { _adapter = adapter; } + void set_adapter_entry(AdapterHandlerEntry* adapter) { + constMethod()->set_adapter_entry(adapter); + } + void update_adapter_trampoline(AdapterHandlerEntry* adapter) { + constMethod()->update_adapter_trampoline(adapter); + } + address get_i2c_entry(); address get_c2i_entry(); address get_c2i_unverified_entry(); - AdapterHandlerEntry* adapter() { return _adapter; } + AdapterHandlerEntry* adapter() const { + return constMethod()->adapter(); + } // setup entry points void link_method(const methodHandle& method, TRAPS); - // clear entry points. Used by sharing code - void unlink_method(); + // clear entry points. Used by sharing code during dump time + void unlink_method() NOT_CDS_RETURN; // vtable index enum VtableIndexFlag { @@ -465,7 +472,15 @@ class Method : public Metadata { // interpreter entry address interpreter_entry() const { return _i2i_entry; } // Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry - void set_interpreter_entry(address entry) { _i2i_entry = entry; _from_interpreted_entry = entry; } + void set_interpreter_entry(address entry) { + assert(!is_shared(), "shared method's interpreter entry should not be changed at run time"); + if (_i2i_entry != entry) { + _i2i_entry = entry; + } + if (_from_interpreted_entry != entry) { + _from_interpreted_entry = entry; + } + } // native function (used for native methods only) enum { diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 89d0f2c66d3..d38d493f198 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -38,6 +38,7 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" +#include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/klass.hpp" @@ -1788,7 +1789,7 @@ void SharedRuntime::check_member_name_argument_is_last_argument(const methodHand IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address caller_pc)) Method* moop(method); - address entry_point = moop->from_compiled_entry(); + address entry_point = moop->from_compiled_entry_no_trampoline(); // It's possible that deoptimization can occur at a call site which hasn't // been resolved yet, in which case this function will be called from @@ -2351,12 +2352,15 @@ class AdapterHandlerTable : public BasicHashtable { public: AdapterHandlerTable() - : BasicHashtable(293, sizeof(AdapterHandlerEntry)) { } + : BasicHashtable(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { } // Create a new entry suitable for insertion in the table AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) { AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable::new_entry(fingerprint->compute_hash()); entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); + if (DumpSharedSpaces) { + ((CDSAdapterHandlerEntry*)entry)->init(); + } return entry; } @@ -2519,6 +2523,28 @@ AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* finger } AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { + AdapterHandlerEntry* entry = get_adapter0(method); + if (method->is_shared()) { + MutexLocker mu(AdapterHandlerLibrary_lock); + if (method->adapter() == NULL) { + method->update_adapter_trampoline(entry); + } + address trampoline = method->from_compiled_entry(); + if (*(int*)trampoline == 0) { + CodeBuffer buffer(trampoline, (int)SharedRuntime::trampoline_size()); + MacroAssembler _masm(&buffer); + SharedRuntime::generate_trampoline(&_masm, entry->get_c2i_entry()); + + if (PrintInterpreter) { + Disassembler::decode(buffer.insts_begin(), buffer.insts_end()); + } + } + } + + return entry; +} + +AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter0(const methodHandle& method) { // Use customized signature handler. Need to lock around updates to // the AdapterHandlerTable (it is not safe for concurrent readers // and a single writer: this could be fixed if it becomes a @@ -2535,7 +2561,9 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth // make sure data structure is initialized initialize(); - if (CodeCacheExtensions::skip_compiler_support()) { + // during dump time, always generate adapters, even if the + // compiler has been turned off. + if (!DumpSharedSpaces && CodeCacheExtensions::skip_compiler_support()) { // adapters are useless and should not be used, including the // abstract_method_handler. However, some callers check that // an adapter was installed. @@ -3017,6 +3045,17 @@ void AdapterHandlerEntry::print_adapter_on(outputStream* st) const { } +#if INCLUDE_CDS + +void CDSAdapterHandlerEntry::init() { + assert(DumpSharedSpaces, "used during dump time only"); + _c2i_entry_trampoline = (address)MetaspaceShared::misc_data_space_alloc(SharedRuntime::trampoline_size()); + _adapter_trampoline = (AdapterHandlerEntry**)MetaspaceShared::misc_data_space_alloc(sizeof(AdapterHandlerEntry*)); +}; + +#endif // INCLUDE_CDS + + #ifndef PRODUCT void AdapterHandlerLibrary::print_statistics() { diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index b3f87cdc7c6..68baebc4686 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -398,6 +398,10 @@ class SharedRuntime: AllStatic { static void convert_ints_to_longints(int i2l_argcnt, int& in_args_count, BasicType*& in_sig_bt, VMRegPair*& in_regs); + static size_t trampoline_size(); + + static void generate_trampoline(MacroAssembler *masm, address destination); + // Generate I2C and C2I adapters. These adapters are simple argument marshalling // blobs. Unlike adapters in the tiger and earlier releases the code in these // blobs does not create a new frame and are therefore virtually invisible @@ -680,6 +684,17 @@ class AdapterHandlerEntry : public BasicHashtableEntry { void print_adapter_on(outputStream* st) const; }; +class CDSAdapterHandlerEntry: public AdapterHandlerEntry { + address _c2i_entry_trampoline; // allocated from shared spaces "MC" region + AdapterHandlerEntry** _adapter_trampoline; // allocated from shared spaces "MD" region + +public: + address get_c2i_entry_trampoline() const { return _c2i_entry_trampoline; } + AdapterHandlerEntry** get_adapter_trampoline() const { return _adapter_trampoline; } + void init() NOT_CDS_RETURN; +}; + + class AdapterHandlerLibrary: public AllStatic { private: static BufferBlob* _buffer; // the temporary code buffer in CodeCache @@ -687,6 +702,7 @@ class AdapterHandlerLibrary: public AllStatic { static AdapterHandlerEntry* _abstract_method_handler; static BufferBlob* buffer_blob(); static void initialize(); + static AdapterHandlerEntry* get_adapter0(const methodHandle& method); public: diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index d7e1f5cb07c..943bf9c83ea 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -400,7 +400,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ - nonstatic_field(Method, _adapter, AdapterHandlerEntry*) \ volatile_nonstatic_field(Method, _from_compiled_entry, address) \ volatile_nonstatic_field(Method, _from_interpreted_entry, address) \ volatile_nonstatic_field(ConstMethod, _fingerprint, uint64_t) \ From e9a1251fb36b9d08bf7ae7a2c4ceea730d0eddf2 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 8 Apr 2016 19:39:32 -0400 Subject: [PATCH 22/24] 8033735: make Throwable.backtrace visible to Class.getDeclaredField again Removed old hack to workaround an old crash. Reviewed-by: hseigel, twisti, mchung --- hotspot/src/share/vm/prims/jvm.cpp | 14 ---- .../ThrowableIntrospectionSegfault.java | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 hotspot/test/runtime/Throwable/ThrowableIntrospectionSegfault.java diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 7665065c9df..7fc617e819f 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1818,9 +1818,6 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, // Ensure class is linked k->link_class(CHECK_NULL); - // 4496456 We need to filter out java.lang.Throwable.backtrace - bool skip_backtrace = false; - // Allocate result int num_fields; @@ -1831,11 +1828,6 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, } } else { num_fields = k->java_fields_count(); - - if (k() == SystemDictionary::Throwable_klass()) { - num_fields--; - skip_backtrace = true; - } } objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Field_klass(), num_fields, CHECK_NULL); @@ -1844,12 +1836,6 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, int out_idx = 0; fieldDescriptor fd; for (JavaFieldStream fs(k); !fs.done(); fs.next()) { - if (skip_backtrace) { - // 4496456 skip java.lang.Throwable.backtrace - int offset = fs.offset(); - if (offset == java_lang_Throwable::get_backtrace_offset()) continue; - } - if (!publicOnly || fs.access_flags().is_public()) { fd.reinitialize(k(), fs.index()); oop field = Reflection::new_field(&fd, CHECK_NULL); diff --git a/hotspot/test/runtime/Throwable/ThrowableIntrospectionSegfault.java b/hotspot/test/runtime/Throwable/ThrowableIntrospectionSegfault.java new file mode 100644 index 00000000000..fd4be6c88e1 --- /dev/null +++ b/hotspot/test/runtime/Throwable/ThrowableIntrospectionSegfault.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8033735 + * @summary check backtrace field introspection + * @library /testlibrary + * @run main ThrowableIntrospectionSegfault + */ + +import java.lang.reflect.*; + +public class ThrowableIntrospectionSegfault { + public static void main(java.lang.String[] unused) { + // Construct a throwable object. + Throwable throwable = new Throwable(); + throwable.fillInStackTrace(); + + // Retrieve a reflection handle to the private backtrace field. + Class class1 = throwable.getClass(); + Field field; + try { + field = class1.getDeclaredField("backtrace"); + } + catch (NoSuchFieldException e) { + System.err.println("Can't retrieve field handle Throwable.backtrace: " + e.toString()); + return; + } + field.setAccessible(true); + + // Retrieve the value of the backtrace field. + Object backtrace; + try { + backtrace = field.get(throwable); + } + catch (IllegalAccessException e) { + System.err.println( "Can't retrieve field value for Throwable.backtrace: " + e.toString()); + return; + } + + try { + + // Retrieve the class of throwable.backtrace[0][0]. + Class class2 = ((Object[]) ((Object[]) backtrace)[2])[0].getClass(); + + // Segfault occurs while executing this line, to retrieve the name of + // this class. + String class2Name = class2.getName(); + + System.err.println("class2Name=" + class2Name); + return; // pass! Passes if it doesn't crash. + } catch (ClassCastException e) { + // Passes if it doesn't crash. Also if the backtrace changes this test might get + // ClassCastException and that's ok too. + System.out.println("Catch exception " + e); + return; // pass! Passes if it doesn't crash. + } + } +} From 78a7d2c16985a2f8273b0902ad83aa134795770b Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Sat, 9 Apr 2016 12:15:13 +0300 Subject: [PATCH 23/24] 8152679: DeadlockDetectionTest.java fails due to expected output missing Detect OS X and bailout Reviewed-by: sspitsyn, tbell --- hotspot/test/serviceability/sa/DeadlockDetectionTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hotspot/test/serviceability/sa/DeadlockDetectionTest.java b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java index aff1aaf156a..23ce96f6399 100644 --- a/hotspot/test/serviceability/sa/DeadlockDetectionTest.java +++ b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java @@ -80,6 +80,12 @@ public class DeadlockDetectionTest { return; } + if (Platform.isOSX()) { + // Coredump stackwalking is not implemented for Darwin + System.out.println("This test is not expected to work on OS X. Skipping"); + return; + } + if (!LingeredApp.isLastModifiedWorking()) { // Exact behaviour of the test depends on operating system and the test nature, From 7b27547030710dbd8b6cf1e5002201e61be7f937 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 10 Apr 2016 21:34:47 -0400 Subject: [PATCH 24/24] 8151322: Implement os::set_native_thread_name() on Solaris Reviewed-by: sla, kbarrett, gziemski --- hotspot/src/os/solaris/vm/os_solaris.cpp | 19 +++++++++++++++++-- hotspot/src/os/solaris/vm/os_solaris.hpp | 5 ++++- .../share/vm/utilities/globalDefinitions.hpp | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 68f4a58c30a..6a10ba59434 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -161,6 +161,7 @@ address os::Solaris::handler_end; // end pc of thr_sighndlrinfo address os::Solaris::_main_stack_base = NULL; // 4352906 workaround +os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL; // "default" initializers for missing libc APIs extern "C" { @@ -441,8 +442,15 @@ static bool assign_distribution(processorid_t* id_array, } void os::set_native_thread_name(const char *name) { - // Not yet implemented. - return; + if (Solaris::_pthread_setname_np != NULL) { + // Only the first 31 bytes of 'name' are processed by pthread_setname_np + // but we explicitly copy into a size-limited buffer to avoid any + // possible overflow. + char buf[32]; + snprintf(buf, sizeof(buf), "%s", name); + buf[sizeof(buf) - 1] = '\0'; + Solaris::_pthread_setname_np(pthread_self(), buf); + } } bool os::distribute_processes(uint length, uint* distribution) { @@ -4410,6 +4418,13 @@ void os::init(void) { // the minimum of what the OS supports (thr_min_stack()), and // enough to allow the thread to get to user bytecode execution. Solaris::min_stack_allowed = MAX2(thr_min_stack(), Solaris::min_stack_allowed); + + // retrieve entry point for pthread_setname_np + void * handle = dlopen("libc.so.1", RTLD_LAZY); + if (handle != NULL) { + Solaris::_pthread_setname_np = + (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np"); + } } // To install functions for atexit system call diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 777e63c8f75..12f72247168 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -122,6 +122,9 @@ class Solaris { static int _SIGasync; // user-overridable ASYNC_SIGNAL static void set_SIGasync(int newsig) { _SIGasync = newsig; } + typedef int (*pthread_setname_np_func_t)(pthread_t, const char*); + static pthread_setname_np_func_t _pthread_setname_np; + public: // Large Page Support--ISM. static bool largepage_range(char* addr, size_t size); diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 3fa2c942f13..5a080626ada 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -328,7 +328,7 @@ inline size_t pointer_delta(const MetaWord* left, const MetaWord* right) { // so far from the middle of the road that it is likely to be problematic in // many C++ compilers. // -#define CAST_TO_FN_PTR(func_type, value) ((func_type)(castable_address(value))) +#define CAST_TO_FN_PTR(func_type, value) (reinterpret_cast(value)) #define CAST_FROM_FN_PTR(new_type, func_ptr) ((new_type)((address_word)(func_ptr))) // Unsigned byte types for os and stream.hpp