From ea35991cab359e88a89cc658735d5387061bf133 Mon Sep 17 00:00:00 2001 From: Bill Pittore Date: Wed, 8 Jan 2014 20:23:16 -0500 Subject: [PATCH 001/170] 8027914: Client JVM silently exit with fail exit code when running in compact(1,2) with options -Dcom.sun.management and -XX:+ManagementServer Check for sun.management.Agent class and print message and exit VM if not found at startup. Reviewed-by: dholmes, mchung --- hotspot/src/share/vm/services/management.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index 9585960daa2..cf0d805c2c3 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -152,11 +152,14 @@ void Management::initialize(TRAPS) { // Load and initialize the sun.management.Agent class // invoke startAgent method to start the management server Handle loader = Handle(THREAD, SystemDictionary::java_system_loader()); - Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), + Klass* k = SystemDictionary::resolve_or_null(vmSymbols::sun_management_Agent(), loader, Handle(), - true, - CHECK); + THREAD); + if (k == NULL) { + vm_exit_during_initialization("Management agent initialization failure: " + "class sun.management.Agent not found."); + } instanceKlassHandle ik (THREAD, k); JavaValue result(T_VOID); From e72dd1b433b1e3f660da86d718955fa0004b9ea6 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Wed, 12 Mar 2014 15:22:45 +0100 Subject: [PATCH 002/170] 8038404: Move object_iterate_mem from Space to CMS since it is only ever used by CMS Reviewed-by: brutisso, tschatzl, stefank --- .../compactibleFreeListSpace.cpp | 53 ++++++++++- .../compactibleFreeListSpace.hpp | 6 ++ .../concurrentMarkSweepGeneration.hpp | 13 +++ hotspot/src/share/vm/memory/iterator.hpp | 13 --- hotspot/src/share/vm/memory/space.cpp | 93 ------------------- hotspot/src/share/vm/memory/space.hpp | 8 -- 6 files changed, 71 insertions(+), 115 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index c8a3f2297dd..6600126dba7 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -851,7 +851,58 @@ void CompactibleFreeListSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { assert_locked(freelistLock()); NOT_PRODUCT(verify_objects_initialized()); - Space::object_iterate_mem(mr, cl); + assert(!mr.is_empty(), "Should be non-empty"); + // We use MemRegion(bottom(), end()) rather than used_region() below + // because the two are not necessarily equal for some kinds of + // spaces, in particular, certain kinds of free list spaces. + // We could use the more complicated but more precise: + // MemRegion(used_region().start(), round_to(used_region().end(), CardSize)) + // but the slight imprecision seems acceptable in the assertion check. + assert(MemRegion(bottom(), end()).contains(mr), + "Should be within used space"); + HeapWord* prev = cl->previous(); // max address from last time + if (prev >= mr.end()) { // nothing to do + return; + } + // This assert will not work when we go from cms space to perm + // space, and use same closure. Easy fix deferred for later. XXX YSR + // assert(prev == NULL || contains(prev), "Should be within space"); + + bool last_was_obj_array = false; + HeapWord *blk_start_addr, *region_start_addr; + if (prev > mr.start()) { + region_start_addr = prev; + blk_start_addr = prev; + // The previous invocation may have pushed "prev" beyond the + // last allocated block yet there may be still be blocks + // in this region due to a particular coalescing policy. + // Relax the assertion so that the case where the unallocated + // block is maintained and "prev" is beyond the unallocated + // block does not cause the assertion to fire. + assert((BlockOffsetArrayUseUnallocatedBlock && + (!is_in(prev))) || + (blk_start_addr == block_start(region_start_addr)), "invariant"); + } else { + region_start_addr = mr.start(); + blk_start_addr = block_start(region_start_addr); + } + HeapWord* region_end_addr = mr.end(); + MemRegion derived_mr(region_start_addr, region_end_addr); + while (blk_start_addr < region_end_addr) { + const size_t size = block_size(blk_start_addr); + if (block_is_obj(blk_start_addr)) { + last_was_obj_array = cl->do_object_bm(oop(blk_start_addr), derived_mr); + } else { + last_was_obj_array = false; + } + blk_start_addr += size; + } + if (!last_was_obj_array) { + assert((bottom() <= blk_start_addr) && (blk_start_addr <= end()), + "Should be within (closed) used space"); + assert(blk_start_addr > prev, "Invariant"); + cl->set_previous(blk_start_addr); // min address for next time + } } // Callers of this iterator beware: The closure application should diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 5cda2c7c4af..5bf3829e48b 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -363,6 +363,12 @@ class CompactibleFreeListSpace: public CompactibleSpace { // obj_is_alive() to determine whether it is safe to iterate of // an object. void safe_object_iterate(ObjectClosure* blk); + + // Iterate over all objects that intersect with mr, calling "cl->do_object" + // on each. There is an exception to this: if this closure has already + // been invoked on an object, it may skip such objects in some cases. This is + // Most likely to happen in an "upwards" (ascending address) iteration of + // MemRegions. void object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl); // Requires that "mr" be entirely within the space. diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index aeb1c9418cc..6cf2f4270b6 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -1498,6 +1498,19 @@ class FalseBitMapClosure: public BitMapClosure { } }; +// A version of ObjectClosure with "memory" (see _previous_address below) +class UpwardsObjectClosure: public BoolObjectClosure { + HeapWord* _previous_address; + public: + UpwardsObjectClosure() : _previous_address(NULL) { } + void set_previous(HeapWord* addr) { _previous_address = addr; } + HeapWord* previous() { return _previous_address; } + // A return value of "true" can be used by the caller to decide + // if this object's end should *NOT* be recorded in + // _previous_address above. + virtual bool do_object_bm(oop obj, MemRegion mr) = 0; +}; + // This closure is used during the second checkpointing phase // to rescan the marked objects on the dirty cards in the mod // union table and the card table proper. It's invoked via diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp index 33d10d69ef6..1e1b17b1405 100644 --- a/hotspot/src/share/vm/memory/iterator.hpp +++ b/hotspot/src/share/vm/memory/iterator.hpp @@ -177,19 +177,6 @@ public: ObjectToOopClosure(ExtendedOopClosure* cl) : _cl(cl) {} }; -// A version of ObjectClosure with "memory" (see _previous_address below) -class UpwardsObjectClosure: public BoolObjectClosure { - HeapWord* _previous_address; - public: - UpwardsObjectClosure() : _previous_address(NULL) { } - void set_previous(HeapWord* addr) { _previous_address = addr; } - HeapWord* previous() { return _previous_address; } - // A return value of "true" can be used by the caller to decide - // if this object's end should *NOT* be recorded in - // _previous_address above. - virtual bool do_object_bm(oop obj, MemRegion mr) = 0; -}; - // A version of ObjectClosure that is expected to be robust // in the face of possibly uninitialized objects. class ObjectClosureCareful : public ObjectClosure { diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 4ea51d8a4fa..c848819004f 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -558,104 +558,11 @@ HeapWord* Space::object_iterate_careful_m(MemRegion mr, return bottom(); } - -void Space::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { - assert(!mr.is_empty(), "Should be non-empty"); - // We use MemRegion(bottom(), end()) rather than used_region() below - // because the two are not necessarily equal for some kinds of - // spaces, in particular, certain kinds of free list spaces. - // We could use the more complicated but more precise: - // MemRegion(used_region().start(), round_to(used_region().end(), CardSize)) - // but the slight imprecision seems acceptable in the assertion check. - assert(MemRegion(bottom(), end()).contains(mr), - "Should be within used space"); - HeapWord* prev = cl->previous(); // max address from last time - if (prev >= mr.end()) { // nothing to do - return; - } - // This assert will not work when we go from cms space to perm - // space, and use same closure. Easy fix deferred for later. XXX YSR - // assert(prev == NULL || contains(prev), "Should be within space"); - - bool last_was_obj_array = false; - HeapWord *blk_start_addr, *region_start_addr; - if (prev > mr.start()) { - region_start_addr = prev; - blk_start_addr = prev; - // The previous invocation may have pushed "prev" beyond the - // last allocated block yet there may be still be blocks - // in this region due to a particular coalescing policy. - // Relax the assertion so that the case where the unallocated - // block is maintained and "prev" is beyond the unallocated - // block does not cause the assertion to fire. - assert((BlockOffsetArrayUseUnallocatedBlock && - (!is_in(prev))) || - (blk_start_addr == block_start(region_start_addr)), "invariant"); - } else { - region_start_addr = mr.start(); - blk_start_addr = block_start(region_start_addr); - } - HeapWord* region_end_addr = mr.end(); - MemRegion derived_mr(region_start_addr, region_end_addr); - while (blk_start_addr < region_end_addr) { - const size_t size = block_size(blk_start_addr); - if (block_is_obj(blk_start_addr)) { - last_was_obj_array = cl->do_object_bm(oop(blk_start_addr), derived_mr); - } else { - last_was_obj_array = false; - } - blk_start_addr += size; - } - if (!last_was_obj_array) { - assert((bottom() <= blk_start_addr) && (blk_start_addr <= end()), - "Should be within (closed) used space"); - assert(blk_start_addr > prev, "Invariant"); - cl->set_previous(blk_start_addr); // min address for next time - } -} - bool Space::obj_is_alive(const HeapWord* p) const { assert (block_is_obj(p), "The address should point to an object"); return true; } -void ContiguousSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) { - assert(!mr.is_empty(), "Should be non-empty"); - assert(used_region().contains(mr), "Should be within used space"); - HeapWord* prev = cl->previous(); // max address from last time - if (prev >= mr.end()) { // nothing to do - return; - } - // See comment above (in more general method above) in case you - // happen to use this method. - assert(prev == NULL || is_in_reserved(prev), "Should be within space"); - - bool last_was_obj_array = false; - HeapWord *obj_start_addr, *region_start_addr; - if (prev > mr.start()) { - region_start_addr = prev; - obj_start_addr = prev; - assert(obj_start_addr == block_start(region_start_addr), "invariant"); - } else { - region_start_addr = mr.start(); - obj_start_addr = block_start(region_start_addr); - } - HeapWord* region_end_addr = mr.end(); - MemRegion derived_mr(region_start_addr, region_end_addr); - while (obj_start_addr < region_end_addr) { - oop obj = oop(obj_start_addr); - const size_t size = obj->size(); - last_was_obj_array = cl->do_object_bm(obj, derived_mr); - obj_start_addr += size; - } - if (!last_was_obj_array) { - assert((bottom() <= obj_start_addr) && (obj_start_addr <= end()), - "Should be within (closed) used space"); - assert(obj_start_addr > prev, "Invariant"); - cl->set_previous(obj_start_addr); // min address for next time - } -} - #if INCLUDE_ALL_GCS #define ContigSpace_PAR_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ \ diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index d83b98048b3..a2438781a56 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -204,13 +204,6 @@ class Space: public CHeapObj { // objects whose internal references point to objects in the space. virtual void safe_object_iterate(ObjectClosure* blk) = 0; - // Iterate over all objects that intersect with mr, calling "cl->do_object" - // on each. There is an exception to this: if this closure has already - // been invoked on an object, it may skip such objects in some cases. This is - // Most likely to happen in an "upwards" (ascending address) iteration of - // MemRegions. - virtual void object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl); - // Iterate over as many initialized objects in the space as possible, // calling "cl.do_object_careful" on each. Return NULL if all objects // in the space (at the start of the iteration) were iterated over. @@ -840,7 +833,6 @@ class ContiguousSpace: public CompactibleSpace { // For contiguous spaces this method will iterate safely over objects // in the space (i.e., between bottom and top) when at a safepoint. void safe_object_iterate(ObjectClosure* blk); - void object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl); // iterates on objects up to the safe limit HeapWord* object_iterate_careful(ObjectClosureCareful* cl); HeapWord* concurrent_iteration_safe_limit() { From c62c16f94a9472b9781969eb3c18e89ad03bb020 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Wed, 12 Mar 2014 17:13:48 +0100 Subject: [PATCH 003/170] 8038412: Move object_iterate_careful down from Space to ContigousSpace and CFLSpace Only declare the functions where they are actually needed. Reviewed-by: tschatzl, stefank --- .../compactibleFreeListSpace.cpp | 33 ------------------- .../compactibleFreeListSpace.hpp | 7 ++-- hotspot/src/share/vm/memory/space.cpp | 11 ------- hotspot/src/share/vm/memory/space.hpp | 20 +++++------ 4 files changed, 10 insertions(+), 61 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 6600126dba7..00157d7eccd 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -905,39 +905,6 @@ void CompactibleFreeListSpace::object_iterate_mem(MemRegion mr, } } -// Callers of this iterator beware: The closure application should -// be robust in the face of uninitialized objects and should (always) -// return a correct size so that the next addr + size below gives us a -// valid block boundary. [See for instance, -// ScanMarkedObjectsAgainCarefullyClosure::do_object_careful() -// in ConcurrentMarkSweepGeneration.cpp.] -HeapWord* -CompactibleFreeListSpace::object_iterate_careful(ObjectClosureCareful* cl) { - assert_lock_strong(freelistLock()); - HeapWord *addr, *last; - size_t size; - for (addr = bottom(), last = end(); - addr < last; addr += size) { - FreeChunk* fc = (FreeChunk*)addr; - if (fc->is_free()) { - // Since we hold the free list lock, which protects direct - // allocation in this generation by mutators, a free object - // will remain free throughout this iteration code. - size = fc->size(); - } else { - // Note that the object need not necessarily be initialized, - // because (for instance) the free list lock does NOT protect - // object initialization. The closure application below must - // therefore be correct in the face of uninitialized objects. - size = cl->do_object_careful(oop(addr)); - if (size == 0) { - // An unparsable object found. Signal early termination. - return addr; - } - } - } - return NULL; -} // Callers of this iterator beware: The closure application should // be robust in the face of uninitialized objects and should (always) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 5bf3829e48b..d2b20c3727f 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -377,11 +377,8 @@ class CompactibleFreeListSpace: public CompactibleSpace { // terminate the iteration and return the address of the start of the // subregion that isn't done. Return of "NULL" indicates that the // iteration completed. - virtual HeapWord* - object_iterate_careful_m(MemRegion mr, - ObjectClosureCareful* cl); - virtual HeapWord* - object_iterate_careful(ObjectClosureCareful* cl); + HeapWord* object_iterate_careful_m(MemRegion mr, + ObjectClosureCareful* cl); // Override: provides a DCTO_CL specific to this kind of space. DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl, diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index c848819004f..7a550c0bfdc 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -547,17 +547,6 @@ void Space::oop_iterate(ExtendedOopClosure* blk) { object_iterate(&blk2); } -HeapWord* Space::object_iterate_careful(ObjectClosureCareful* cl) { - guarantee(false, "NYI"); - return bottom(); -} - -HeapWord* Space::object_iterate_careful_m(MemRegion mr, - ObjectClosureCareful* cl) { - guarantee(false, "NYI"); - return bottom(); -} - bool Space::obj_is_alive(const HeapWord* p) const { assert (block_is_obj(p), "The address should point to an object"); return true; diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index a2438781a56..c412398e040 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -204,17 +204,6 @@ class Space: public CHeapObj { // objects whose internal references point to objects in the space. virtual void safe_object_iterate(ObjectClosure* blk) = 0; - // Iterate over as many initialized objects in the space as possible, - // calling "cl.do_object_careful" on each. Return NULL if all objects - // in the space (at the start of the iteration) were iterated over. - // Return an address indicating the extent of the iteration in the - // event that the iteration had to return because of finding an - // uninitialized object in the space, or if the closure "cl" - // signaled early termination. - virtual HeapWord* object_iterate_careful(ObjectClosureCareful* cl); - virtual HeapWord* object_iterate_careful_m(MemRegion mr, - ObjectClosureCareful* cl); - // Create and return a new dirty card to oop closure. Can be // overridden to return the appropriate type of closure // depending on the type of space in which the closure will @@ -833,7 +822,14 @@ class ContiguousSpace: public CompactibleSpace { // For contiguous spaces this method will iterate safely over objects // in the space (i.e., between bottom and top) when at a safepoint. void safe_object_iterate(ObjectClosure* blk); - // iterates on objects up to the safe limit + + // Iterate over as many initialized objects in the space as possible, + // calling "cl.do_object_careful" on each. Return NULL if all objects + // in the space (at the start of the iteration) were iterated over. + // Return an address indicating the extent of the iteration in the + // event that the iteration had to return because of finding an + // uninitialized object in the space, or if the closure "cl" + // signaled early termination. HeapWord* object_iterate_careful(ObjectClosureCareful* cl); HeapWord* concurrent_iteration_safe_limit() { assert(_concurrent_iteration_safe_limit <= top(), From 1fdc7cd78ffbfc1d3f16b49dbe0b3666e5d75a6f Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Wed, 12 Mar 2014 15:25:35 +0100 Subject: [PATCH 004/170] 8038405: Clean up some virtual fucntions in Space class hierarchy Get rid of some duplicated implementations and change nonsense implementations to pure virtuals Reviewed-by: stefank, jmasa --- .../compactibleFreeListSpace.hpp | 4 -- hotspot/src/share/vm/memory/space.cpp | 4 -- hotspot/src/share/vm/memory/space.hpp | 38 ++++++++----------- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index d2b20c3727f..9f01fcd54a4 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -338,10 +338,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { unallocated_block() : end()); } - bool is_in(const void* p) const { - return used_region().contains(p); - } - virtual bool is_free_block(const HeapWord* p) const; // Resizing support diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 7a550c0bfdc..b7b9c00adc1 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -302,10 +302,6 @@ void ContiguousSpace::clear(bool mangle_space) { CompactibleSpace::clear(mangle_space); } -bool ContiguousSpace::is_in(const void* p) const { - return _bottom <= p && p < _top; -} - bool ContiguousSpace::is_free_block(const HeapWord* p) const { return p >= _top; } diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index c412398e040..2e0ebcb09b4 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -120,6 +120,12 @@ class Space: public CHeapObj { void set_saved_mark_word(HeapWord* p) { _saved_mark_word = p; } + // Returns true if this object has been allocated since a + // generation's "save_marks" call. + virtual bool obj_allocated_since_save_marks(const oop obj) const { + return (HeapWord*)obj >= saved_mark_word(); + } + MemRegionClosure* preconsumptionDirtyCardClosure() const { return _preconsumptionDirtyCardClosure; } @@ -127,9 +133,9 @@ class Space: public CHeapObj { _preconsumptionDirtyCardClosure = cl; } - // Returns a subregion of the space containing all the objects in + // Returns a subregion of the space containing only the allocated objects in // the space. - virtual MemRegion used_region() const { return MemRegion(bottom(), end()); } + virtual MemRegion used_region() const = 0; // Returns a region that is guaranteed to contain (at least) all objects // allocated at the time of the last call to "save_marks". If the space @@ -139,7 +145,7 @@ class Space: public CHeapObj { // saved mark. Otherwise, the "obj_allocated_since_save_marks" method of // the space must distinguish between objects in the region allocated before // and after the call to save marks. - virtual MemRegion used_region_at_save_marks() const { + MemRegion used_region_at_save_marks() const { return MemRegion(bottom(), saved_mark_word()); } @@ -172,7 +178,9 @@ class Space: public CHeapObj { // expensive operation. To prevent performance problems // on account of its inadvertent use in product jvm's, // we restrict its use to assertion checks only. - virtual bool is_in(const void* p) const = 0; + bool is_in(const void* p) const { + return used_region().contains(p); + } // Returns true iff the given reserved memory of the space contains the // given address. @@ -244,10 +252,6 @@ class Space: public CHeapObj { // Allocation (return NULL if full). Enforces mutual exclusion internally. virtual HeapWord* par_allocate(size_t word_size) = 0; - // Returns true if this object has been allocated since a - // generation's "save_marks" call. - virtual bool obj_allocated_since_save_marks(const oop obj) const = 0; - // Mark-sweep-compact support: all spaces can update pointers to objects // moving as a part of compaction. virtual void adjust_pointers(); @@ -379,7 +383,7 @@ public: // Perform operations on the space needed after a compaction // has been performed. - virtual void reset_after_compaction() {} + virtual void reset_after_compaction() = 0; // Returns the next space (in the current generation) to be compacted in // the global compaction order. Also is used to select the next @@ -444,7 +448,7 @@ protected: HeapWord* _end_of_live; // Minimum size of a free block. - virtual size_t minimum_free_block_size() const = 0; + virtual size_t minimum_free_block_size() const { return 0; } // This the function is invoked when an allocation of an object covering // "start" to "end occurs crosses the threshold; returns the next @@ -760,7 +764,7 @@ class ContiguousSpace: public CompactibleSpace { HeapWord* top() const { return _top; } void set_top(HeapWord* value) { _top = value; } - virtual void set_saved_mark() { _saved_mark_word = top(); } + void set_saved_mark() { _saved_mark_word = top(); } void reset_saved_mark() { _saved_mark_word = bottom(); } WaterMark bottom_mark() { return WaterMark(this, bottom()); } @@ -795,27 +799,16 @@ class ContiguousSpace: public CompactibleSpace { size_t used() const { return byte_size(bottom(), top()); } size_t free() const { return byte_size(top(), end()); } - // Override from space. - bool is_in(const void* p) const; - virtual bool is_free_block(const HeapWord* p) const; // In a contiguous space we have a more obvious bound on what parts // contain objects. MemRegion used_region() const { return MemRegion(bottom(), top()); } - MemRegion used_region_at_save_marks() const { - return MemRegion(bottom(), saved_mark_word()); - } - // Allocation (return NULL if full) virtual HeapWord* allocate(size_t word_size); virtual HeapWord* par_allocate(size_t word_size); - virtual bool obj_allocated_since_save_marks(const oop obj) const { - return (HeapWord*)obj >= saved_mark_word(); - } - // Iteration void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* blk); @@ -860,7 +853,6 @@ class ContiguousSpace: public CompactibleSpace { // set new iteration safe limit set_concurrent_iteration_safe_limit(compaction_top()); } - virtual size_t minimum_free_block_size() const { return 0; } // Override. DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl, From f2de069dc2c19698bfbb9d5d92c17bc1cd2b49c3 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 28 Mar 2014 14:03:11 +0100 Subject: [PATCH 005/170] 8038628: Remove unused Closure::abort() Reviewed-by: coleenp, jmasa --- .../vm/gc_implementation/g1/heapRegion.cpp | 3 --- hotspot/src/share/vm/memory/iterator.hpp | 17 ++--------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index d018c9aabc3..a82a9435d0b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -472,9 +472,6 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr, } else if (!g1h->is_obj_dead(obj)) { cl->do_object(obj); } - if (cl->abort()) return cur; - // The check above must occur before the operation below, since an - // abort might invalidate the "size" operation. cur += obj->size(); } return NULL; diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp index 1e1b17b1405..6f1767e4a88 100644 --- a/hotspot/src/share/vm/memory/iterator.hpp +++ b/hotspot/src/share/vm/memory/iterator.hpp @@ -30,8 +30,6 @@ #include "runtime/prefetch.hpp" #include "utilities/top.hpp" -// The following classes are C++ `closures` for iterating over objects, roots and spaces - class CodeBlob; class nmethod; class ReferenceProcessor; @@ -39,22 +37,11 @@ class DataLayout; class KlassClosure; class ClassLoaderData; -// Closure provides abortability. +// The following classes are C++ `closures` for iterating over objects, roots and spaces -class Closure : public StackObj { - protected: - bool _abort; - void set_abort() { _abort = true; } - public: - Closure() : _abort(false) {} - // A subtype can use this mechanism to indicate to some iterator mapping - // functions that the iteration should cease. - bool abort() { return _abort; } - void clear_abort() { _abort = false; } -}; +class Closure : public StackObj { }; // OopClosure is used for iterating through references to Java objects. - class OopClosure : public Closure { public: virtual void do_oop(oop* o) = 0; From a8f01c3f99495803f1e16c40ec7e1bcffa54361d Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 28 Mar 2014 14:15:03 +0100 Subject: [PATCH 006/170] 8038630: Remove ExtendedOopClosure::prefetch_style() Reviewed-by: coleenp, jmasa --- .../concurrentMarkSweep/cmsOopClosures.hpp | 26 ------------------- .../src/share/vm/memory/genOopClosures.hpp | 6 ----- hotspot/src/share/vm/memory/iterator.hpp | 6 ----- 3 files changed, 38 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp index 6c911328a77..1c9f4cba5f2 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp @@ -116,10 +116,6 @@ class MarkRefsIntoClosure: public CMSOopsInGenClosure { MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; class Par_MarkRefsIntoClosure: public CMSOopsInGenClosure { @@ -132,10 +128,6 @@ class Par_MarkRefsIntoClosure: public CMSOopsInGenClosure { Par_MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // A variant of the above used in certain kinds of CMS @@ -152,10 +144,6 @@ class MarkRefsIntoVerifyClosure: public CMSOopsInGenClosure { CMSBitMap* cms_bm); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // The non-parallel version (the parallel version appears further below). @@ -181,10 +169,6 @@ class PushAndMarkClosure: public CMSOopClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { PushAndMarkClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { PushAndMarkClosure::do_oop_work(p); } - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // In the parallel case, the bit map and the @@ -211,10 +195,6 @@ class Par_PushAndMarkClosure: public CMSOopClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { Par_PushAndMarkClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { Par_PushAndMarkClosure::do_oop_work(p); } - - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } }; // The non-parallel version (the parallel version appears further below). @@ -245,9 +225,6 @@ class MarkRefsIntoAndScanClosure: public CMSOopsInGenClosure { inline void do_oop_nv(oop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); } - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } void set_freelistLock(Mutex* m) { _freelistLock = m; } @@ -282,9 +259,6 @@ class Par_MarkRefsIntoAndScanClosure: public CMSOopsInGenClosure { inline void do_oop_nv(oop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); } - Prefetch::style prefetch_style() { - return Prefetch::do_read; - } void trim_queue(uint size); }; diff --git a/hotspot/src/share/vm/memory/genOopClosures.hpp b/hotspot/src/share/vm/memory/genOopClosures.hpp index aa9f4366f85..1f24b2b3cab 100644 --- a/hotspot/src/share/vm/memory/genOopClosures.hpp +++ b/hotspot/src/share/vm/memory/genOopClosures.hpp @@ -115,9 +115,6 @@ class ScanClosure: public OopsInKlassOrGenClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p); inline void do_oop_nv(narrowOop* p); - Prefetch::style prefetch_style() { - return Prefetch::do_write; - } }; // Closure for scanning DefNewGeneration. @@ -137,9 +134,6 @@ class FastScanClosure: public OopsInKlassOrGenClosure { virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p); inline void do_oop_nv(narrowOop* p); - Prefetch::style prefetch_style() { - return Prefetch::do_write; - } }; class KlassScanClosure: public KlassClosure { diff --git a/hotspot/src/share/vm/memory/iterator.hpp b/hotspot/src/share/vm/memory/iterator.hpp index 6f1767e4a88..81a845e5056 100644 --- a/hotspot/src/share/vm/memory/iterator.hpp +++ b/hotspot/src/share/vm/memory/iterator.hpp @@ -27,7 +27,6 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" -#include "runtime/prefetch.hpp" #include "utilities/top.hpp" class CodeBlob; @@ -84,11 +83,6 @@ class ExtendedOopClosure : public OopClosure { virtual void do_class_loader_data(ClassLoaderData* cld) { ShouldNotReachHere(); } - // Controls how prefetching is done for invocations of this closure. - Prefetch::style prefetch_style() { // Note that this is non-virtual. - return Prefetch::do_none; - } - // True iff this closure may be safely applied more than once to an oop // location without an intervening "major reset" (like the end of a GC). virtual bool idempotent() { return false; } From b1cfdfafe229d199e6ad7c739791ce020ca7251e Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Thu, 13 Feb 2014 10:05:03 +0100 Subject: [PATCH 007/170] 8028498: runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java asserts in RT_Baseline Preventing GCs to occur before VM is completely initialized. This was previously partly done by one part of the GC locker which not was removed. Reviewed-by: coleenp, pliden --- .../shared/vmGCOperations.cpp | 9 ++++++ hotspot/src/share/vm/memory/gcLocker.cpp | 32 +++++++------------ hotspot/src/share/vm/memory/gcLocker.hpp | 14 +------- .../src/share/vm/memory/gcLocker.inline.hpp | 16 ---------- .../src/share/vm/memory/metaspaceShared.cpp | 3 -- hotspot/src/share/vm/memory/universe.cpp | 3 -- hotspot/src/share/vm/runtime/thread.cpp | 1 - hotspot/src/share/vm/runtime/thread.hpp | 4 --- .../src/share/vm/runtime/unhandledOops.cpp | 4 +-- 9 files changed, 23 insertions(+), 63 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index 9027b89c375..bdbbae7f412 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp @@ -89,6 +89,15 @@ bool VM_GC_Operation::doit_prologue() { assert(((_gc_cause != GCCause::_no_gc) && (_gc_cause != GCCause::_no_cause_specified)), "Illegal GCCause"); + // To be able to handle a GC the VM initialization needs to be completed. + if (!is_init_completed()) { + vm_exit_during_initialization( + err_msg("GC triggered before VM initialization completed. Try increasing " + "NewSize, current value " UINTX_FORMAT "%s.", + byte_size_in_proper_unit(NewSize), + proper_unit_for_byte_size(NewSize))); + } + acquire_pending_list_lock(); // If the GC count has changed someone beat us to the collection // Get the Heap_lock after the pending_list_lock. diff --git a/hotspot/src/share/vm/memory/gcLocker.cpp b/hotspot/src/share/vm/memory/gcLocker.cpp index 09fb73bb035..3b208dfff8e 100644 --- a/hotspot/src/share/vm/memory/gcLocker.cpp +++ b/hotspot/src/share/vm/memory/gcLocker.cpp @@ -28,7 +28,6 @@ #include "memory/sharedHeap.hpp" volatile jint GC_locker::_jni_lock_count = 0; -volatile jint GC_locker::_lock_count = 0; volatile bool GC_locker::_needs_gc = false; volatile bool GC_locker::_doing_gc = false; @@ -102,7 +101,7 @@ void GC_locker::jni_lock(JavaThread* thread) { // We check that at least one thread is in a critical region before // blocking because blocked threads are woken up by a thread exiting // a JNI critical region. - while ((needs_gc() && is_jni_active()) || _doing_gc) { + while (is_active_and_needs_gc() || _doing_gc) { JNICritical_lock->wait(); } thread->enter_critical(); @@ -116,27 +115,20 @@ void GC_locker::jni_unlock(JavaThread* thread) { _jni_lock_count--; decrement_debug_jni_lock_count(); thread->exit_critical(); - if (needs_gc() && !is_jni_active()) { + if (needs_gc() && !is_active_internal()) { // We're the last thread out. Cause a GC to occur. - // GC will also check is_active, so this check is not - // strictly needed. It's added here to make it clear that - // the GC will NOT be performed if any other caller - // of GC_locker::lock() still needs GC locked. - if (!is_active_internal()) { - _doing_gc = true; - { - // Must give up the lock while at a safepoint - MutexUnlocker munlock(JNICritical_lock); - if (PrintJNIGCStalls && PrintGCDetails) { - ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 - gclog_or_tty->print_cr("%.3f: Thread \"%s\" is performing GC after exiting critical section, %d locked", - gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); - } - Universe::heap()->collect(GCCause::_gc_locker); + _doing_gc = true; + { + // Must give up the lock while at a safepoint + MutexUnlocker munlock(JNICritical_lock); + if (PrintJNIGCStalls && PrintGCDetails) { + ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 + gclog_or_tty->print_cr("%.3f: Thread \"%s\" is performing GC after exiting critical section, %d locked", + gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); } - _doing_gc = false; + Universe::heap()->collect(GCCause::_gc_locker); } - + _doing_gc = false; _needs_gc = false; JNICritical_lock->notify_all(); } diff --git a/hotspot/src/share/vm/memory/gcLocker.hpp b/hotspot/src/share/vm/memory/gcLocker.hpp index 60bebdf0fa4..f12aa675552 100644 --- a/hotspot/src/share/vm/memory/gcLocker.hpp +++ b/hotspot/src/share/vm/memory/gcLocker.hpp @@ -54,8 +54,6 @@ class GC_locker: public AllStatic { // safepointing and decremented during the slow path of GC_locker // unlocking. static volatile jint _jni_lock_count; // number of jni active instances. - - static volatile jint _lock_count; // number of other active instances static volatile bool _needs_gc; // heap is filling, we need a GC // note: bool is typedef'd as jint static volatile bool _doing_gc; // unlock_critical() is doing a GC @@ -66,12 +64,6 @@ class GC_locker: public AllStatic { static volatile jint _debug_jni_lock_count; #endif - // Accessors - static bool is_jni_active() { - assert(_needs_gc, "only valid when _needs_gc is set"); - return _jni_lock_count > 0; - } - // At a safepoint, visit all threads and count the number of active // critical sections. This is used to ensure that all active // critical sections are exited before a new one is started. @@ -82,7 +74,7 @@ class GC_locker: public AllStatic { static bool is_active_internal() { verify_critical_count(); - return _lock_count > 0 || _jni_lock_count > 0; + return _jni_lock_count > 0; } public: @@ -132,10 +124,6 @@ class GC_locker: public AllStatic { // not a stable predicate. static void stall_until_clear(); - // Non-structured GC locking: currently needed for JNI. Use with care! - static void lock(); - static void unlock(); - // The following two methods are used for JNI critical regions. // If we find that we failed to perform a GC because the GC_locker // was active, arrange for one as soon as possible by allowing diff --git a/hotspot/src/share/vm/memory/gcLocker.inline.hpp b/hotspot/src/share/vm/memory/gcLocker.inline.hpp index 37b4231bbe3..e77d5436b1b 100644 --- a/hotspot/src/share/vm/memory/gcLocker.inline.hpp +++ b/hotspot/src/share/vm/memory/gcLocker.inline.hpp @@ -27,22 +27,6 @@ #include "memory/gcLocker.hpp" -inline void GC_locker::lock() { - // cast away volatile - Atomic::inc(&_lock_count); - CHECK_UNHANDLED_OOPS_ONLY( - if (CheckUnhandledOops) { Thread::current()->_gc_locked_out_count++; }) - assert(Universe::heap() == NULL || - !Universe::heap()->is_gc_active(), "locking failed"); -} - -inline void GC_locker::unlock() { - // cast away volatile - Atomic::dec(&_lock_count); - CHECK_UNHANDLED_OOPS_ONLY( - if (CheckUnhandledOops) { Thread::current()->_gc_locked_out_count--; }) -} - inline void GC_locker::lock_critical(JavaThread* thread) { if (!thread->in_critical()) { if (needs_gc()) { diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 8421b12d7f1..ef4572824f7 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -645,9 +645,6 @@ void MetaspaceShared::preload_and_dump(TRAPS) { TraceTime timer("Dump Shared Spaces", TraceStartupTime); ResourceMark rm; - // Lock out GC - is it necessary? I don't think we care. - No_GC_Verifier no_gc; - // Preload classes to be shared. // Should use some os:: method rather than fopen() here. aB. // Construct the path to the class list (in jre/lib) diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index dc4efcd1c8a..63c7c005d44 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -632,7 +632,6 @@ jint universe_init() { guarantee(sizeof(oop) % sizeof(HeapWord) == 0, "oop size is not not a multiple of HeapWord size"); TraceTime timer("Genesis", TraceStartupTime); - GC_locker::lock(); // do not allow gc during bootstrapping JavaClasses::compute_hard_coded_offsets(); jint status = Universe::initialize_heap(); @@ -1164,8 +1163,6 @@ bool universe_post_init() { MemoryService::add_metaspace_memory_pools(); - GC_locker::unlock(); // allow gc after bootstrapping - MemoryService::set_universe_heap(Universe::_collectedHeap); return true; } diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index bd794da4524..6dd4a40dadf 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -211,7 +211,6 @@ Thread::Thread() { debug_only(_allow_allocation_count = 0;) NOT_PRODUCT(_allow_safepoint_count = 0;) NOT_PRODUCT(_skip_gcalot = false;) - CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) _jvmti_env_iteration_count = 0; set_allocated_bytes(0); _vm_operation_started_count = 0; diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index a925646ab04..f97f7952e01 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -249,9 +249,6 @@ class Thread: public ThreadShadow { // Used by SkipGCALot class. NOT_PRODUCT(bool _skip_gcalot;) // Should we elide gc-a-lot? - // Record when GC is locked out via the GC_locker mechanism - CHECK_UNHANDLED_OOPS_ONLY(int _gc_locked_out_count;) - friend class No_Alloc_Verifier; friend class No_Safepoint_Verifier; friend class Pause_No_Safepoint_Verifier; @@ -397,7 +394,6 @@ class Thread: public ThreadShadow { void clear_unhandled_oops() { if (CheckUnhandledOops) unhandled_oops()->clear_unhandled_oops(); } - bool is_gc_locked_out() { return _gc_locked_out_count > 0; } #endif // CHECK_UNHANDLED_OOPS #ifndef PRODUCT diff --git a/hotspot/src/share/vm/runtime/unhandledOops.cpp b/hotspot/src/share/vm/runtime/unhandledOops.cpp index 4cc584e8bc3..cc0002d42c9 100644 --- a/hotspot/src/share/vm/runtime/unhandledOops.cpp +++ b/hotspot/src/share/vm/runtime/unhandledOops.cpp @@ -113,9 +113,7 @@ void UnhandledOops::unregister_unhandled_oop(oop* op) { void UnhandledOops::clear_unhandled_oops() { assert (CheckUnhandledOops, "should only be called with checking option"); - if (_thread->is_gc_locked_out()) { - return; - } + for (int k = 0; k < _oop_list->length(); k++) { UnhandledOopEntry entry = _oop_list->at(k); // If an entry is on the unhandled oop list but isn't on the stack From c88e3def4d776c055ec266d43d932f9e3d87e268 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Fri, 14 Mar 2014 10:15:46 +0100 Subject: [PATCH 008/170] 8034079: G1: Refactor the HeapRegionSet hierarchy Reviewed-by: tschatzl, pliden --- .../gc_implementation/g1/G1CollectedHeap.java | 4 +- .../g1/HeapRegionSetBase.java | 24 +- .../g1/HeapRegionSetCount.java | 73 ++++ .../sun/jvm/hotspot/tools/HeapSummary.java | 3 +- .../gc_implementation/g1/concurrentMark.cpp | 51 +-- .../gc_implementation/g1/concurrentMark.hpp | 2 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 168 ++++----- .../gc_implementation/g1/g1CollectedHeap.hpp | 82 ++--- .../g1/g1CollectedHeap.inline.hpp | 1 + .../vm/gc_implementation/g1/g1MarkSweep.cpp | 19 +- .../vm/gc_implementation/g1/heapRegionSeq.cpp | 2 +- .../vm/gc_implementation/g1/heapRegionSet.cpp | 328 ++++-------------- .../vm/gc_implementation/g1/heapRegionSet.hpp | 274 ++++++--------- .../g1/heapRegionSet.inline.hpp | 101 ++---- .../gc_implementation/g1/heapRegionSets.cpp | 119 ++----- .../gc_implementation/g1/heapRegionSets.hpp | 111 ------ .../vm/gc_implementation/g1/vmStructs_g1.hpp | 8 +- 17 files changed, 447 insertions(+), 923 deletions(-) create mode 100644 hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java delete mode 100644 hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java index b75669ed026..eea5e4b7271 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/G1CollectedHeap.java @@ -51,9 +51,9 @@ public class G1CollectedHeap extends SharedHeap { static private CIntegerField summaryBytesUsedField; // G1MonitoringSupport* _g1mm; static private AddressField g1mmField; - // MasterOldRegionSet _old_set; + // HeapRegionSet _old_set; static private long oldSetFieldOffset; - // MasterHumongousRegionSet _humongous_set; + // HeapRegionSet _humongous_set; static private long humongousSetFieldOffset; static { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java index 4ac8f72c25f..94c3e239990 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetBase.java @@ -40,12 +40,8 @@ import sun.jvm.hotspot.types.TypeDataBase; // Mirror class for HeapRegionSetBase. Represents a group of regions. public class HeapRegionSetBase extends VMObject { - // uint _length; - static private CIntegerField lengthField; - // uint _region_num; - static private CIntegerField regionNumField; - // size_t _total_used_bytes; - static private CIntegerField totalUsedBytesField; + + static private long countField; static { VM.registerVMInitializedObserver(new Observer() { @@ -58,21 +54,13 @@ public class HeapRegionSetBase extends VMObject { static private synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("HeapRegionSetBase"); - lengthField = type.getCIntegerField("_length"); - regionNumField = type.getCIntegerField("_region_num"); - totalUsedBytesField = type.getCIntegerField("_total_used_bytes"); + countField = type.getField("_count").getOffset(); } - public long length() { - return lengthField.getValue(addr); - } - public long regionNum() { - return regionNumField.getValue(addr); - } - - public long totalUsedBytes() { - return totalUsedBytesField.getValue(addr); + public HeapRegionSetCount count() { + Address countFieldAddr = addr.addOffsetTo(countField); + return (HeapRegionSetCount) VMObjectFactory.newObject(HeapRegionSetCount.class, countFieldAddr); } public HeapRegionSetBase(Address addr) { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java new file mode 100644 index 00000000000..2a4483a54c8 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_implementation/g1/HeapRegionSetCount.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 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.gc_implementation.g1; + +import java.util.Iterator; +import java.util.Observable; +import java.util.Observer; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObject; +import sun.jvm.hotspot.runtime.VMObjectFactory; +import sun.jvm.hotspot.types.AddressField; +import sun.jvm.hotspot.types.CIntegerField; +import sun.jvm.hotspot.types.Type; +import sun.jvm.hotspot.types.TypeDataBase; + +// Mirror class for HeapRegionSetCount. Represents a group of regions. + +public class HeapRegionSetCount extends VMObject { + + static private CIntegerField lengthField; + static private CIntegerField capacityField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + static private synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("HeapRegionSetCount"); + + lengthField = type.getCIntegerField("_length"); + capacityField = type.getCIntegerField("_capacity"); + } + + public long length() { + return lengthField.getValue(addr); + } + + public long capacity() { + return capacityField.getValue(addr); + } + + public HeapRegionSetCount(Address addr) { + super(addr); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index 32c1358cbe2..afe4d2a50b5 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -114,7 +114,8 @@ public class HeapSummary extends Tool { long survivorRegionNum = g1mm.survivorRegionNum(); HeapRegionSetBase oldSet = g1h.oldSet(); HeapRegionSetBase humongousSet = g1h.humongousSet(); - long oldRegionNum = oldSet.regionNum() + humongousSet.regionNum(); + long oldRegionNum = oldSet.count().length() + + humongousSet.count().capacity() / HeapRegion.grainBytes(); printG1Space("G1 Heap:", g1h.n_regions(), g1h.used(), g1h.capacity()); System.out.println("G1 Young Generation:"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index c874f56d3c2..cb1187fbd89 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1809,8 +1809,8 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure { uint _regions_claimed; size_t _freed_bytes; FreeRegionList* _local_cleanup_list; - OldRegionSet* _old_proxy_set; - HumongousRegionSet* _humongous_proxy_set; + HeapRegionSetCount _old_regions_removed; + HeapRegionSetCount _humongous_regions_removed; HRRSCleanupTask* _hrrs_cleanup_task; double _claimed_region_time; double _max_region_time; @@ -1819,19 +1819,19 @@ public: G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1, int worker_num, FreeRegionList* local_cleanup_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, HRRSCleanupTask* hrrs_cleanup_task) : _g1(g1), _worker_num(worker_num), _max_live_bytes(0), _regions_claimed(0), _freed_bytes(0), _claimed_region_time(0.0), _max_region_time(0.0), _local_cleanup_list(local_cleanup_list), - _old_proxy_set(old_proxy_set), - _humongous_proxy_set(humongous_proxy_set), + _old_regions_removed(), + _humongous_regions_removed(), _hrrs_cleanup_task(hrrs_cleanup_task) { } size_t freed_bytes() { return _freed_bytes; } + const HeapRegionSetCount& old_regions_removed() { return _old_regions_removed; } + const HeapRegionSetCount& humongous_regions_removed() { return _humongous_regions_removed; } bool doHeapRegion(HeapRegion *hr) { if (hr->continuesHumongous()) { @@ -1844,13 +1844,22 @@ public: _regions_claimed++; hr->note_end_of_marking(); _max_live_bytes += hr->max_live_bytes(); - _g1->free_region_if_empty(hr, - &_freed_bytes, - _local_cleanup_list, - _old_proxy_set, - _humongous_proxy_set, - _hrrs_cleanup_task, - true /* par */); + + if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) { + _freed_bytes += hr->used(); + hr->set_containing_set(NULL); + if (hr->isHumongous()) { + assert(hr->startsHumongous(), "we should only see starts humongous"); + _humongous_regions_removed.increment(1u, hr->capacity()); + _g1->free_humongous_region(hr, _local_cleanup_list, true); + } else { + _old_regions_removed.increment(1u, hr->capacity()); + _g1->free_region(hr, _local_cleanup_list, true); + } + } else { + hr->rem_set()->do_cleanup_work(_hrrs_cleanup_task); + } + double region_time = (os::elapsedTime() - start); _claimed_region_time += region_time; if (region_time > _max_region_time) { @@ -1883,12 +1892,8 @@ public: void work(uint worker_id) { double start = os::elapsedTime(); FreeRegionList local_cleanup_list("Local Cleanup List"); - OldRegionSet old_proxy_set("Local Cleanup Old Proxy Set"); - HumongousRegionSet humongous_proxy_set("Local Cleanup Humongous Proxy Set"); HRRSCleanupTask hrrs_cleanup_task; G1NoteEndOfConcMarkClosure g1_note_end(_g1h, worker_id, &local_cleanup_list, - &old_proxy_set, - &humongous_proxy_set, &hrrs_cleanup_task); if (G1CollectedHeap::use_parallel_gc_threads()) { _g1h->heap_region_par_iterate_chunked(&g1_note_end, worker_id, @@ -1900,13 +1905,10 @@ public: assert(g1_note_end.complete(), "Shouldn't have yielded!"); // Now update the lists - _g1h->update_sets_after_freeing_regions(g1_note_end.freed_bytes(), - NULL /* free_list */, - &old_proxy_set, - &humongous_proxy_set, - true /* par */); + _g1h->remove_from_old_sets(g1_note_end.old_regions_removed(), g1_note_end.humongous_regions_removed()); { MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); + _g1h->decrement_summary_bytes(g1_note_end.freed_bytes()); _max_live_bytes += g1_note_end.max_live_bytes(); _freed_bytes += g1_note_end.freed_bytes(); @@ -1920,7 +1922,7 @@ public: G1HRPrinter* hr_printer = _g1h->hr_printer(); if (hr_printer->is_active()) { - HeapRegionLinkedListIterator iter(&local_cleanup_list); + FreeRegionListIterator iter(&local_cleanup_list); while (iter.more_available()) { HeapRegion* hr = iter.get_next(); hr_printer->cleanup(hr); @@ -1971,7 +1973,6 @@ void ConcurrentMark::cleanup() { return; } - HRSPhaseSetter x(HRSPhaseCleanup); g1h->verify_region_sets_optional(); if (VerifyDuringGC) { @@ -2144,7 +2145,7 @@ void ConcurrentMark::completeCleanup() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - _cleanup_list.verify_optional(); + _cleanup_list.verify_list(); FreeRegionList tmp_free_list("Tmp Free List"); if (G1ConcRegionFreeingVerbose) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 383bb4a6be2..355bddfa2e0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" #include "utilities/taskqueue.hpp" class G1CollectedHeap; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index aacb4969da3..95310267ac6 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1298,7 +1298,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes(); - HRSPhaseSetter x(HRSPhaseFullGC); verify_region_sets_optional(); const bool do_clear_all_soft_refs = clear_all_soft_refs || @@ -1928,10 +1927,10 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _g1mm(NULL), _refine_cte_cl(NULL), _full_collection(false), - _free_list("Master Free List"), - _secondary_free_list("Secondary Free List"), - _old_set("Old Set"), - _humongous_set("Master Humongous Set"), + _free_list("Master Free List", new MasterFreeRegionListMtSafeChecker()), + _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()), + _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()), + _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()), _free_regions_coming(false), _young_list(new YoungList(this)), _gc_time_stamp(0), @@ -2079,7 +2078,7 @@ jint G1CollectedHeap::initialize() { guarantee(HeapRegion::CardsPerRegion < max_cards_per_region, "too many cards per region"); - HeapRegionSet::set_unrealistically_long_length(max_regions() + 1); + FreeRegionList::set_unrealistically_long_length(max_regions() + 1); _bot_shared = new G1BlockOffsetSharedArray(_reserved, heap_word_size(init_byte_size)); @@ -3887,7 +3886,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { print_heap_before_gc(); trace_heap_before_gc(_gc_tracer_stw); - HRSPhaseSetter x(HRSPhaseEvacuation); verify_region_sets_optional(); verify_dirty_young_regions(); @@ -5937,28 +5935,7 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } -void G1CollectedHeap::free_region_if_empty(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - HRRSCleanupTask* hrrs_cleanup_task, - bool par) { - if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) { - if (hr->isHumongous()) { - assert(hr->startsHumongous(), "we should only see starts humongous"); - free_humongous_region(hr, pre_used, free_list, humongous_proxy_set, par); - } else { - _old_set.remove_with_proxy(hr, old_proxy_set); - free_region(hr, pre_used, free_list, par); - } - } else { - hr->rem_set()->do_cleanup_work(hrrs_cleanup_task); - } -} - void G1CollectedHeap::free_region(HeapRegion* hr, - size_t* pre_used, FreeRegionList* free_list, bool par) { assert(!hr->isHumongous(), "this is only for non-humongous regions"); @@ -5971,72 +5948,58 @@ void G1CollectedHeap::free_region(HeapRegion* hr, if (!hr->is_young()) { _cg1r->hot_card_cache()->reset_card_counts(hr); } - *pre_used += hr->used(); hr->hr_clear(par, true /* clear_space */); free_list->add_as_head(hr); } void G1CollectedHeap::free_humongous_region(HeapRegion* hr, - size_t* pre_used, FreeRegionList* free_list, - HumongousRegionSet* humongous_proxy_set, bool par) { assert(hr->startsHumongous(), "this is only for starts humongous regions"); assert(free_list != NULL, "pre-condition"); - assert(humongous_proxy_set != NULL, "pre-condition"); - size_t hr_used = hr->used(); size_t hr_capacity = hr->capacity(); - size_t hr_pre_used = 0; - _humongous_set.remove_with_proxy(hr, humongous_proxy_set); // We need to read this before we make the region non-humongous, // otherwise the information will be gone. uint last_index = hr->last_hc_index(); hr->set_notHumongous(); - free_region(hr, &hr_pre_used, free_list, par); + free_region(hr, free_list, par); uint i = hr->hrs_index() + 1; while (i < last_index) { HeapRegion* curr_hr = region_at(i); assert(curr_hr->continuesHumongous(), "invariant"); curr_hr->set_notHumongous(); - free_region(curr_hr, &hr_pre_used, free_list, par); + free_region(curr_hr, free_list, par); i += 1; } - assert(hr_pre_used == hr_used, - err_msg("hr_pre_used: "SIZE_FORMAT" and hr_used: "SIZE_FORMAT" " - "should be the same", hr_pre_used, hr_used)); - *pre_used += hr_pre_used; } -void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - bool par) { - if (pre_used > 0) { - Mutex* lock = (par) ? ParGCRareEvent_lock : NULL; - MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag); - assert(_summary_bytes_used >= pre_used, - err_msg("invariant: _summary_bytes_used: "SIZE_FORMAT" " - "should be >= pre_used: "SIZE_FORMAT, - _summary_bytes_used, pre_used)); - _summary_bytes_used -= pre_used; +void G1CollectedHeap::remove_from_old_sets(const HeapRegionSetCount& old_regions_removed, + const HeapRegionSetCount& humongous_regions_removed) { + if (old_regions_removed.length() > 0 || humongous_regions_removed.length() > 0) { + MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); + _old_set.bulk_remove(old_regions_removed); + _humongous_set.bulk_remove(humongous_regions_removed); } - if (free_list != NULL && !free_list->is_empty()) { + +} + +void G1CollectedHeap::prepend_to_freelist(FreeRegionList* list) { + assert(list != NULL, "list can't be null"); + if (!list->is_empty()) { MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); - _free_list.add_as_head(free_list); - } - if (old_proxy_set != NULL && !old_proxy_set->is_empty()) { - MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); - _old_set.update_from_proxy(old_proxy_set); - } - if (humongous_proxy_set != NULL && !humongous_proxy_set->is_empty()) { - MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag); - _humongous_set.update_from_proxy(humongous_proxy_set); + _free_list.add_as_head(list); } } +void G1CollectedHeap::decrement_summary_bytes(size_t bytes) { + assert(_summary_bytes_used >= bytes, + err_msg("invariant: _summary_bytes_used: "SIZE_FORMAT" should be >= bytes: "SIZE_FORMAT, + _summary_bytes_used, bytes)); + _summary_bytes_used -= bytes; +} + class G1ParCleanupCTTask : public AbstractGangTask { G1SATBCardTableModRefBS* _ct_bs; G1CollectedHeap* _g1h; @@ -6227,7 +6190,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e // And the region is empty. assert(!used_mr.is_empty(), "Should not have empty regions in a CS."); - free_region(cur, &pre_used, &local_free_list, false /* par */); + pre_used += cur->used(); + free_region(cur, &local_free_list, false /* par */); } else { cur->uninstall_surv_rate_group(); if (cur->is_young()) { @@ -6255,10 +6219,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e young_time_ms += elapsed_ms; } - update_sets_after_freeing_regions(pre_used, &local_free_list, - NULL /* old_proxy_set */, - NULL /* humongous_proxy_set */, - false /* par */); + prepend_to_freelist(&local_free_list); + decrement_summary_bytes(pre_used); policy->phase_times()->record_young_free_cset_time_ms(young_time_ms); policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms); } @@ -6370,10 +6332,10 @@ bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample) class TearDownRegionSetsClosure : public HeapRegionClosure { private: - OldRegionSet *_old_set; + HeapRegionSet *_old_set; public: - TearDownRegionSetsClosure(OldRegionSet* old_set) : _old_set(old_set) { } + TearDownRegionSetsClosure(HeapRegionSet* old_set) : _old_set(old_set) { } bool doHeapRegion(HeapRegion* r) { if (r->is_empty()) { @@ -6412,13 +6374,13 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) { class RebuildRegionSetsClosure : public HeapRegionClosure { private: bool _free_list_only; - OldRegionSet* _old_set; + HeapRegionSet* _old_set; FreeRegionList* _free_list; size_t _total_used; public: RebuildRegionSetsClosure(bool free_list_only, - OldRegionSet* old_set, FreeRegionList* free_list) : + HeapRegionSet* old_set, FreeRegionList* free_list) : _free_list_only(free_list_only), _old_set(old_set), _free_list(free_list), _total_used(0) { assert(_free_list->is_empty(), "pre-condition"); @@ -6615,23 +6577,22 @@ void OldGCAllocRegion::retire_region(HeapRegion* alloc_region, class VerifyRegionListsClosure : public HeapRegionClosure { private: - FreeRegionList* _free_list; - OldRegionSet* _old_set; - HumongousRegionSet* _humongous_set; - uint _region_count; + HeapRegionSet* _old_set; + HeapRegionSet* _humongous_set; + FreeRegionList* _free_list; public: - VerifyRegionListsClosure(OldRegionSet* old_set, - HumongousRegionSet* humongous_set, - FreeRegionList* free_list) : - _old_set(old_set), _humongous_set(humongous_set), - _free_list(free_list), _region_count(0) { } + HeapRegionSetCount _old_count; + HeapRegionSetCount _humongous_count; + HeapRegionSetCount _free_count; - uint region_count() { return _region_count; } + VerifyRegionListsClosure(HeapRegionSet* old_set, + HeapRegionSet* humongous_set, + FreeRegionList* free_list) : + _old_set(old_set), _humongous_set(humongous_set), _free_list(free_list), + _old_count(), _humongous_count(), _free_count(){ } bool doHeapRegion(HeapRegion* hr) { - _region_count += 1; - if (hr->continuesHumongous()) { return false; } @@ -6639,14 +6600,31 @@ public: if (hr->is_young()) { // TODO } else if (hr->startsHumongous()) { - _humongous_set->verify_next_region(hr); + assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->region_num())); + _humongous_count.increment(1u, hr->capacity()); } else if (hr->is_empty()) { - _free_list->verify_next_region(hr); + assert(hr->containing_set() == _free_list, err_msg("Heap region %u is empty but not on the free list.", hr->region_num())); + _free_count.increment(1u, hr->capacity()); } else { - _old_set->verify_next_region(hr); + assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->region_num())); + _old_count.increment(1u, hr->capacity()); } return false; } + + void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, FreeRegionList* free_list) { + guarantee(old_set->length() == _old_count.length(), err_msg("Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length())); + guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), err_msg("Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + old_set->total_capacity_bytes(), _old_count.capacity())); + + guarantee(humongous_set->length() == _humongous_count.length(), err_msg("Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length())); + guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), err_msg("Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + humongous_set->total_capacity_bytes(), _humongous_count.capacity())); + + guarantee(free_list->length() == _free_count.length(), err_msg("Free list count mismatch. Expected %u, actual %u.", free_list->length(), _free_count.length())); + guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), err_msg("Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + free_list->total_capacity_bytes(), _free_count.capacity())); + } }; HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, @@ -6662,16 +6640,14 @@ void G1CollectedHeap::verify_region_sets() { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); // First, check the explicit lists. - _free_list.verify(); + _free_list.verify_list(); { // Given that a concurrent operation might be adding regions to // the secondary free list we have to take the lock before // verifying it. MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); - _secondary_free_list.verify(); + _secondary_free_list.verify_list(); } - _old_set.verify(); - _humongous_set.verify(); // If a concurrent region freeing operation is in progress it will // be difficult to correctly attributed any free regions we come @@ -6694,16 +6670,10 @@ void G1CollectedHeap::verify_region_sets() { // Finally, make sure that the region accounting in the lists is // consistent with what we see in the heap. - _old_set.verify_start(); - _humongous_set.verify_start(); - _free_list.verify_start(); VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_free_list); heap_region_iterate(&cl); - - _old_set.verify_end(); - _humongous_set.verify_end(); - _free_list.verify_end(); + cl.verify_counts(&_old_set, &_humongous_set, &_free_list); } // Optimized nmethod scanning diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index c1601e1c8a6..801bc2d2052 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -34,7 +34,7 @@ #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegionSeq.hpp" -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/shared/hSpaceCounters.hpp" #include "gc_implementation/shared/parGCAllocBuffer.hpp" #include "memory/barrierSet.hpp" @@ -243,18 +243,18 @@ private: MemRegion _g1_committed; // The master free list. It will satisfy all new region allocations. - MasterFreeRegionList _free_list; + FreeRegionList _free_list; // The secondary free list which contains regions that have been // freed up during the cleanup process. This will be appended to the // master free list when appropriate. - SecondaryFreeRegionList _secondary_free_list; + FreeRegionList _secondary_free_list; // It keeps track of the old regions. - MasterOldRegionSet _old_set; + HeapRegionSet _old_set; // It keeps track of the humongous regions. - MasterHumongousRegionSet _humongous_set; + HeapRegionSet _humongous_set; // The number of regions we could create by expansion. uint _expansion_regions; @@ -757,6 +757,26 @@ public: G1HRPrinter* hr_printer() { return &_hr_printer; } + // Frees a non-humongous region by initializing its contents and + // adding it to the free list that's passed as a parameter (this is + // usually a local list which will be appended to the master free + // list later). The used bytes of freed regions are accumulated in + // pre_used. If par is true, the region's RSet will not be freed + // up. The assumption is that this will be done later. + void free_region(HeapRegion* hr, + FreeRegionList* free_list, + bool par); + + // Frees a humongous region by collapsing it into individual regions + // and calling free_region() for each of them. The freed regions + // will be added to the free list that's passed as a parameter (this + // is usually a local list which will be appended to the master free + // list later). The used bytes of freed regions are accumulated in + // pre_used. If par is true, the region's RSet will not be freed + // up. The assumption is that this will be done later. + void free_humongous_region(HeapRegion* hr, + FreeRegionList* free_list, + bool par); protected: // Shrink the garbage-first heap by at most the given size (in bytes!). @@ -835,30 +855,6 @@ protected: G1KlassScanClosure* scan_klasses, int worker_i); - // Frees a non-humongous region by initializing its contents and - // adding it to the free list that's passed as a parameter (this is - // usually a local list which will be appended to the master free - // list later). The used bytes of freed regions are accumulated in - // pre_used. If par is true, the region's RSet will not be freed - // up. The assumption is that this will be done later. - void free_region(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - bool par); - - // Frees a humongous region by collapsing it into individual regions - // and calling free_region() for each of them. The freed regions - // will be added to the free list that's passed as a parameter (this - // is usually a local list which will be appended to the master free - // list later). The used bytes of freed regions are accumulated in - // pre_used. If par is true, the region's RSet will not be freed - // up. The assumption is that this will be done later. - void free_humongous_region(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - HumongousRegionSet* humongous_proxy_set, - bool par); - // Notifies all the necessary spaces that the committed space has // been updated (either expanded or shrunk). It should be called // after _g1_storage is updated. @@ -1228,10 +1224,6 @@ public: bool is_on_master_free_list(HeapRegion* hr) { return hr->containing_set() == &_free_list; } - - bool is_in_humongous_set(HeapRegion* hr) { - return hr->containing_set() == &_humongous_set; - } #endif // ASSERT // Wrapper for the region list operations that can be called from @@ -1284,27 +1276,9 @@ public: // True iff an evacuation has failed in the most-recent collection. bool evacuation_failed() { return _evacuation_failed; } - // It will free a region if it has allocated objects in it that are - // all dead. It calls either free_region() or - // free_humongous_region() depending on the type of the region that - // is passed to it. - void free_region_if_empty(HeapRegion* hr, - size_t* pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - HRRSCleanupTask* hrrs_cleanup_task, - bool par); - - // It appends the free list to the master free list and updates the - // master humongous list according to the contents of the proxy - // list. It also adjusts the total used bytes according to pre_used - // (if par is true, it will do so by taking the ParGCRareEvent_lock). - void update_sets_after_freeing_regions(size_t pre_used, - FreeRegionList* free_list, - OldRegionSet* old_proxy_set, - HumongousRegionSet* humongous_proxy_set, - bool par); + void remove_from_old_sets(const HeapRegionSetCount& old_regions_removed, const HeapRegionSetCount& humongous_regions_removed); + void prepend_to_freelist(FreeRegionList* list); + void decrement_summary_bytes(size_t bytes); // Returns "TRUE" iff "p" points into the committed areas of the heap. virtual bool is_in(const void* p) const; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index 498e65f9b8d..91289d649c3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -30,6 +30,7 @@ #include "gc_implementation/g1/g1AllocRegion.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/g1/heapRegionSet.inline.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "utilities/taskqueue.hpp" diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index dee7ce0b72e..83fbd0835b8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp @@ -194,17 +194,19 @@ class G1PrepareCompactClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; ModRefBarrierSet* _mrbs; CompactPoint _cp; - HumongousRegionSet _humongous_proxy_set; + HeapRegionSetCount _humongous_regions_removed; void free_humongous_region(HeapRegion* hr) { HeapWord* end = hr->end(); - size_t dummy_pre_used; FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); assert(hr->startsHumongous(), "Only the start of a humongous region should be freed."); - _g1h->free_humongous_region(hr, &dummy_pre_used, &dummy_free_list, - &_humongous_proxy_set, false /* par */); + + hr->set_containing_set(NULL); + _humongous_regions_removed.increment(1u, hr->capacity()); + + _g1h->free_humongous_region(hr, &dummy_free_list, false /* par */); hr->prepare_for_compaction(&_cp); // Also clear the part of the card table that will be unused after // compaction. @@ -217,16 +219,13 @@ public: : _g1h(G1CollectedHeap::heap()), _mrbs(_g1h->g1_barrier_set()), _cp(NULL, cs, cs->initialize_threshold()), - _humongous_proxy_set("G1MarkSweep Humongous Proxy Set") { } + _humongous_regions_removed() { } void update_sets() { // We'll recalculate total used bytes and recreate the free list // at the end of the GC, so no point in updating those values here. - _g1h->update_sets_after_freeing_regions(0, /* pre_used */ - NULL, /* free_list */ - NULL, /* old_proxy_set */ - &_humongous_proxy_set, - false /* par */); + HeapRegionSetCount empty_set; + _g1h->remove_from_old_sets(empty_set, _humongous_regions_removed); } bool doHeapRegion(HeapRegion* hr) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index c7b42b5cdc4..c047dccab0d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "memory/allocation.hpp" diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp index c0533c6bf55..fba64b3cdef 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -23,171 +23,60 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSet.inline.hpp" -uint HeapRegionSetBase::_unrealistically_long_length = 0; -HRSPhase HeapRegionSetBase::_phase = HRSPhaseNone; - -//////////////////// HeapRegionSetBase //////////////////// - -void HeapRegionSetBase::set_unrealistically_long_length(uint len) { - guarantee(_unrealistically_long_length == 0, "should only be set once"); - _unrealistically_long_length = len; -} +uint FreeRegionList::_unrealistically_long_length = 0; void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) { - msg->append("[%s] %s ln: %u rn: %u cy: "SIZE_FORMAT" ud: "SIZE_FORMAT, - name(), message, length(), region_num(), - total_capacity_bytes(), total_used_bytes()); + msg->append("[%s] %s ln: %u cy: "SIZE_FORMAT, + name(), message, length(), total_capacity_bytes()); fill_in_ext_msg_extra(msg); } -bool HeapRegionSetBase::verify_region(HeapRegion* hr, - HeapRegionSetBase* expected_containing_set) { - const char* error_message = NULL; - - if (!regions_humongous()) { - if (hr->isHumongous()) { - error_message = "the region should not be humongous"; - } - } else { - if (!hr->isHumongous() || !hr->startsHumongous()) { - error_message = "the region should be 'starts humongous'"; - } - } - - if (!regions_empty()) { - if (hr->is_empty()) { - error_message = "the region should not be empty"; - } - } else { - if (!hr->is_empty()) { - error_message = "the region should be empty"; - } - } - -#ifdef ASSERT - // The _containing_set field is only available when ASSERT is defined. - if (hr->containing_set() != expected_containing_set) { - error_message = "inconsistent containing set found"; - } -#endif // ASSERT - - const char* extra_error_message = verify_region_extra(hr); - if (extra_error_message != NULL) { - error_message = extra_error_message; - } - - if (error_message != NULL) { - outputStream* out = tty; - out->cr(); - out->print_cr("## [%s] %s", name(), error_message); - out->print_cr("## Offending Region: "PTR_FORMAT, hr); - out->print_cr(" "HR_FORMAT, HR_FORMAT_PARAMS(hr)); -#ifdef ASSERT - out->print_cr(" containing set: "PTR_FORMAT, hr->containing_set()); -#endif // ASSERT - out->print_cr("## Offending Region Set: "PTR_FORMAT, this); - print_on(out); - return false; - } else { - return true; - } +#ifndef PRODUCT +void HeapRegionSetBase::verify_region(HeapRegion* hr) { + assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrs_index())); + assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrs_index())); // currently we don't use these sets for young regions + assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrs_index(), name())); + assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrs_index(), name())); + assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrs_index())); } +#endif void HeapRegionSetBase::verify() { // It's important that we also observe the MT safety protocol even // for the verification calls. If we do verification without the // appropriate locks and the set changes underneath our feet // verification might fail and send us on a wild goose chase. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); - guarantee(( is_empty() && length() == 0 && region_num() == 0 && - total_used_bytes() == 0 && total_capacity_bytes() == 0) || - (!is_empty() && length() >= 0 && region_num() >= 0 && - total_used_bytes() >= 0 && total_capacity_bytes() >= 0), - hrs_ext_msg(this, "invariant")); - - guarantee((!regions_humongous() && region_num() == length()) || - ( regions_humongous() && region_num() >= length()), - hrs_ext_msg(this, "invariant")); - - guarantee(!regions_empty() || total_used_bytes() == 0, - hrs_ext_msg(this, "invariant")); - - guarantee(total_used_bytes() <= total_capacity_bytes(), + guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) || + (!is_empty() && length() >= 0 && total_capacity_bytes() >= 0), hrs_ext_msg(this, "invariant")); } void HeapRegionSetBase::verify_start() { // See comment in verify() about MT safety and verification. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); assert(!_verify_in_progress, hrs_ext_msg(this, "verification should not be in progress")); // Do the basic verification first before we do the checks over the regions. HeapRegionSetBase::verify(); - _calc_length = 0; - _calc_region_num = 0; - _calc_total_capacity_bytes = 0; - _calc_total_used_bytes = 0; _verify_in_progress = true; } -void HeapRegionSetBase::verify_next_region(HeapRegion* hr) { - // See comment in verify() about MT safety and verification. - hrs_assert_mt_safety_ok(this); - assert(_verify_in_progress, - hrs_ext_msg(this, "verification should be in progress")); - - guarantee(verify_region(hr, this), hrs_ext_msg(this, "region verification")); - - _calc_length += 1; - _calc_region_num += hr->region_num(); - _calc_total_capacity_bytes += hr->capacity(); - _calc_total_used_bytes += hr->used(); -} - void HeapRegionSetBase::verify_end() { // See comment in verify() about MT safety and verification. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); assert(_verify_in_progress, hrs_ext_msg(this, "verification should be in progress")); - guarantee(length() == _calc_length, - hrs_err_msg("[%s] length: %u should be == calc length: %u", - name(), length(), _calc_length)); - - guarantee(region_num() == _calc_region_num, - hrs_err_msg("[%s] region num: %u should be == calc region num: %u", - name(), region_num(), _calc_region_num)); - - guarantee(total_capacity_bytes() == _calc_total_capacity_bytes, - hrs_err_msg("[%s] capacity bytes: "SIZE_FORMAT" should be == " - "calc capacity bytes: "SIZE_FORMAT, - name(), - total_capacity_bytes(), _calc_total_capacity_bytes)); - - guarantee(total_used_bytes() == _calc_total_used_bytes, - hrs_err_msg("[%s] used bytes: "SIZE_FORMAT" should be == " - "calc used bytes: "SIZE_FORMAT, - name(), total_used_bytes(), _calc_total_used_bytes)); - _verify_in_progress = false; } -void HeapRegionSetBase::clear_phase() { - assert(_phase != HRSPhaseNone, "pre-condition"); - _phase = HRSPhaseNone; -} - -void HeapRegionSetBase::set_phase(HRSPhase phase) { - assert(_phase == HRSPhaseNone, "pre-condition"); - assert(phase != HRSPhaseNone, "pre-condition"); - _phase = phase; -} - void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->cr(); out->print_cr("Set: %s ("PTR_FORMAT")", name(), this); @@ -196,76 +85,38 @@ void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) { out->print_cr(" empty : %s", BOOL_TO_STR(regions_empty())); out->print_cr(" Attributes"); out->print_cr(" length : %14u", length()); - out->print_cr(" region num : %14u", region_num()); out->print_cr(" total capacity : "SIZE_FORMAT_W(14)" bytes", total_capacity_bytes()); - out->print_cr(" total used : "SIZE_FORMAT_W(14)" bytes", - total_used_bytes()); } -void HeapRegionSetBase::clear() { - _length = 0; - _region_num = 0; - _total_used_bytes = 0; -} - -HeapRegionSetBase::HeapRegionSetBase(const char* name) +HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker) : _name(name), _verify_in_progress(false), - _calc_length(0), _calc_region_num(0), - _calc_total_capacity_bytes(0), _calc_total_used_bytes(0) { } + _is_humongous(humongous), _is_empty(empty), _mt_safety_checker(mt_safety_checker), + _count() +{ } -//////////////////// HeapRegionSet //////////////////// - -void HeapRegionSet::update_from_proxy(HeapRegionSet* proxy_set) { - hrs_assert_mt_safety_ok(this); - hrs_assert_mt_safety_ok(proxy_set); - hrs_assert_sets_match(this, proxy_set); - - verify_optional(); - proxy_set->verify_optional(); - - if (proxy_set->is_empty()) return; - - assert(proxy_set->length() <= _length, - hrs_err_msg("[%s] proxy set length: %u should be <= length: %u", - name(), proxy_set->length(), _length)); - _length -= proxy_set->length(); - - assert(proxy_set->region_num() <= _region_num, - hrs_err_msg("[%s] proxy set region num: %u should be <= region num: %u", - name(), proxy_set->region_num(), _region_num)); - _region_num -= proxy_set->region_num(); - - assert(proxy_set->total_used_bytes() <= _total_used_bytes, - hrs_err_msg("[%s] proxy set used bytes: "SIZE_FORMAT" " - "should be <= used bytes: "SIZE_FORMAT, - name(), proxy_set->total_used_bytes(), - _total_used_bytes)); - _total_used_bytes -= proxy_set->total_used_bytes(); - - proxy_set->clear(); - - verify_optional(); - proxy_set->verify_optional(); +void FreeRegionList::set_unrealistically_long_length(uint len) { + guarantee(_unrealistically_long_length == 0, "should only be set once"); + _unrealistically_long_length = len; } -//////////////////// HeapRegionLinkedList //////////////////// - -void HeapRegionLinkedList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { +void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { msg->append(" hd: "PTR_FORMAT" tl: "PTR_FORMAT, head(), tail()); } -void HeapRegionLinkedList::add_as_head(HeapRegionLinkedList* from_list) { - hrs_assert_mt_safety_ok(this); - hrs_assert_mt_safety_ok(from_list); +void FreeRegionList::add_as_head_or_tail(FreeRegionList* from_list, bool as_head) { + check_mt_safety(); + from_list->check_mt_safety(); verify_optional(); from_list->verify_optional(); - if (from_list->is_empty()) return; + if (from_list->is_empty()) { + return; + } #ifdef ASSERT - HeapRegionLinkedListIterator iter(from_list); + FreeRegionListIterator iter(from_list); while (iter.more_available()) { HeapRegion* hr = iter.get_next(); // In set_containing_set() we check that we either set the value @@ -276,70 +127,43 @@ void HeapRegionLinkedList::add_as_head(HeapRegionLinkedList* from_list) { } #endif // ASSERT - if (_head != NULL) { - assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant")); - from_list->_tail->set_next(_head); - } else { + if (_head == NULL) { assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant")); - _tail = from_list->_tail; - } - _head = from_list->_head; - - _length += from_list->length(); - _region_num += from_list->region_num(); - _total_used_bytes += from_list->total_used_bytes(); - from_list->clear(); - - verify_optional(); - from_list->verify_optional(); -} - -void HeapRegionLinkedList::add_as_tail(HeapRegionLinkedList* from_list) { - hrs_assert_mt_safety_ok(this); - hrs_assert_mt_safety_ok(from_list); - - verify_optional(); - from_list->verify_optional(); - - if (from_list->is_empty()) return; - -#ifdef ASSERT - HeapRegionLinkedListIterator iter(from_list); - while (iter.more_available()) { - HeapRegion* hr = iter.get_next(); - // In set_containing_set() we check that we either set the value - // from NULL to non-NULL or vice versa to catch bugs. So, we have - // to NULL it first before setting it to the value. - hr->set_containing_set(NULL); - hr->set_containing_set(this); - } -#endif // ASSERT - - if (_tail != NULL) { - assert(length() > 0 && _head != NULL, hrs_ext_msg(this, "invariant")); - _tail->set_next(from_list->_head); - } else { - assert(length() == 0 && _head == NULL, hrs_ext_msg(this, "invariant")); _head = from_list->_head; + _tail = from_list->_tail; + } else { + assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant")); + if (as_head) { + from_list->_tail->set_next(_head); + _head = from_list->_head; + } else { + _tail->set_next(from_list->_head); + _tail = from_list->_tail; + } } - _tail = from_list->_tail; - _length += from_list->length(); - _region_num += from_list->region_num(); - _total_used_bytes += from_list->total_used_bytes(); + _count.increment(from_list->length(), from_list->total_capacity_bytes()); from_list->clear(); verify_optional(); from_list->verify_optional(); } -void HeapRegionLinkedList::remove_all() { - hrs_assert_mt_safety_ok(this); +void FreeRegionList::add_as_head(FreeRegionList* from_list) { + add_as_head_or_tail(from_list, true /* as_head */); +} + +void FreeRegionList::add_as_tail(FreeRegionList* from_list) { + add_as_head_or_tail(from_list, false /* as_head */); +} + +void FreeRegionList::remove_all() { + check_mt_safety(); verify_optional(); HeapRegion* curr = _head; while (curr != NULL) { - hrs_assert_region_ok(this, curr, this); + verify_region(curr); HeapRegion* next = curr->next(); curr->set_next(NULL); @@ -351,8 +175,8 @@ void HeapRegionLinkedList::remove_all() { verify_optional(); } -void HeapRegionLinkedList::remove_all_pending(uint target_count) { - hrs_assert_mt_safety_ok(this); +void FreeRegionList::remove_all_pending(uint target_count) { + check_mt_safety(); assert(target_count > 1, hrs_ext_msg(this, "pre-condition")); assert(!is_empty(), hrs_ext_msg(this, "pre-condition")); @@ -363,7 +187,7 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { HeapRegion* prev = NULL; uint count = 0; while (curr != NULL) { - hrs_assert_region_ok(this, curr, this); + verify_region(curr); HeapRegion* next = curr->next(); if (curr->pending_removal()) { @@ -387,7 +211,7 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { } curr->set_next(NULL); - remove_internal(curr); + remove(curr); curr->set_pending_removal(false); count += 1; @@ -414,46 +238,26 @@ void HeapRegionLinkedList::remove_all_pending(uint target_count) { verify_optional(); } -void HeapRegionLinkedList::verify() { +void FreeRegionList::verify() { // See comment in HeapRegionSetBase::verify() about MT safety and // verification. - hrs_assert_mt_safety_ok(this); + check_mt_safety(); // This will also do the basic verification too. verify_start(); - HeapRegion* curr = _head; - HeapRegion* prev1 = NULL; - HeapRegion* prev0 = NULL; - uint count = 0; - while (curr != NULL) { - verify_next_region(curr); - - count += 1; - guarantee(count < _unrealistically_long_length, - hrs_err_msg("[%s] the calculated length: %u " - "seems very long, is there maybe a cycle? " - "curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " - "prev1: "PTR_FORMAT" length: %u", - name(), count, curr, prev0, prev1, length())); - - prev1 = prev0; - prev0 = curr; - curr = curr->next(); - } - - guarantee(_tail == prev0, hrs_ext_msg(this, "post-condition")); + verify_list(); verify_end(); } -void HeapRegionLinkedList::clear() { - HeapRegionSetBase::clear(); +void FreeRegionList::clear() { + _count = HeapRegionSetCount(); _head = NULL; _tail = NULL; } -void HeapRegionLinkedList::print_on(outputStream* out, bool print_contents) { +void FreeRegionList::print_on(outputStream* out, bool print_contents) { HeapRegionSetBase::print_on(out, print_contents); out->print_cr(" Linking"); out->print_cr(" head : "PTR_FORMAT, _head); @@ -461,7 +265,7 @@ void HeapRegionLinkedList::print_on(outputStream* out, bool print_contents) { if (print_contents) { out->print_cr(" Contents"); - HeapRegionLinkedListIterator iter(this); + FreeRegionListIterator iter(this); while (iter.more_available()) { HeapRegion* hr = iter.get_next(); hr->print_on(out); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp index f2f10d81548..09a94b52258 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp @@ -38,135 +38,108 @@ typedef FormatBuffer hrs_err_msg; #define HEAP_REGION_SET_FORCE_VERIFY defined(ASSERT) #endif // HEAP_REGION_SET_FORCE_VERIFY -//////////////////// HeapRegionSetBase //////////////////// +class hrs_ext_msg; + +class HRSMtSafeChecker : public CHeapObj { +public: + virtual void check() = 0; +}; + +class MasterFreeRegionListMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; +class SecondaryFreeRegionListMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; +class HumongousRegionSetMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; +class OldRegionSetMtSafeChecker : public HRSMtSafeChecker { public: void check(); }; + +class HeapRegionSetCount VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + uint _length; + size_t _capacity; + +public: + HeapRegionSetCount() : _length(0), _capacity(0) { } + + const uint length() const { return _length; } + const size_t capacity() const { return _capacity; } + + void increment(uint length_to_add, size_t capacity_to_add) { + _length += length_to_add; + _capacity += capacity_to_add; + } + + void decrement(const uint length_to_remove, const size_t capacity_to_remove) { + _length -= length_to_remove; + _capacity -= capacity_to_remove; + } +}; // Base class for all the classes that represent heap region sets. It // contains the basic attributes that each set needs to maintain // (e.g., length, region num, used bytes sum) plus any shared // functionality (e.g., verification). -class hrs_ext_msg; - -typedef enum { - HRSPhaseNone, - HRSPhaseEvacuation, - HRSPhaseCleanup, - HRSPhaseFullGC -} HRSPhase; - -class HRSPhaseSetter; - class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC { - friend class hrs_ext_msg; - friend class HRSPhaseSetter; friend class VMStructs; +private: + bool _is_humongous; + bool _is_empty; + HRSMtSafeChecker* _mt_safety_checker; protected: - static uint _unrealistically_long_length; - // The number of regions added to the set. If the set contains // only humongous regions, this reflects only 'starts humongous' // regions and does not include 'continues humongous' ones. - uint _length; - - // The total number of regions represented by the set. If the set - // does not contain humongous regions, this should be the same as - // _length. If the set contains only humongous regions, this will - // include the 'continues humongous' regions. - uint _region_num; - - // We don't keep track of the total capacity explicitly, we instead - // recalculate it based on _region_num and the heap region size. - - // The sum of used bytes in the all the regions in the set. - size_t _total_used_bytes; + HeapRegionSetCount _count; const char* _name; - bool _verify_in_progress; - uint _calc_length; - uint _calc_region_num; - size_t _calc_total_capacity_bytes; - size_t _calc_total_used_bytes; - - // This is here so that it can be used in the subclasses to assert - // something different depending on which phase the GC is in. This - // can be particularly helpful in the check_mt_safety() methods. - static HRSPhase _phase; - - // Only used by HRSPhaseSetter. - static void clear_phase(); - static void set_phase(HRSPhase phase); + bool _verify_in_progress; // verify_region() is used to ensure that the contents of a region - // added to / removed from a set are consistent. Different sets - // make different assumptions about the regions added to them. So - // each set can override verify_region_extra(), which is called - // from verify_region(), and do any extra verification it needs to - // perform in that. - virtual const char* verify_region_extra(HeapRegion* hr) { return NULL; } - bool verify_region(HeapRegion* hr, - HeapRegionSetBase* expected_containing_set); + // added to / removed from a set are consistent. + void verify_region(HeapRegion* hr) PRODUCT_RETURN; // Indicates whether all regions in the set should be humongous or // not. Only used during verification. - virtual bool regions_humongous() = 0; + bool regions_humongous() { return _is_humongous; } // Indicates whether all regions in the set should be empty or // not. Only used during verification. - virtual bool regions_empty() = 0; + bool regions_empty() { return _is_empty; } - // Subclasses can optionally override this to do MT safety protocol - // checks. It is called in an assert from all methods that perform - // updates on the set (and subclasses should also call it too). - virtual bool check_mt_safety() { return true; } + void check_mt_safety() { + if (_mt_safety_checker != NULL) { + _mt_safety_checker->check(); + } + } + + virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { } + + HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker); + +public: + const char* name() { return _name; } + + uint length() { return _count.length(); } + + bool is_empty() { return _count.length() == 0; } + + size_t total_capacity_bytes() { + return _count.capacity(); + } + + // It updates the fields of the set to reflect hr being added to + // the set and tags the region appropriately. + inline void add(HeapRegion* hr); + + // It updates the fields of the set to reflect hr being removed + // from the set and tags the region appropriately. + inline void remove(HeapRegion* hr); // fill_in_ext_msg() writes the the values of the set's attributes // in the custom err_msg (hrs_ext_msg). fill_in_ext_msg_extra() // allows subclasses to append further information. - virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { } void fill_in_ext_msg(hrs_ext_msg* msg, const char* message); - // It updates the fields of the set to reflect hr being added to - // the set. - inline void update_for_addition(HeapRegion* hr); - - // It updates the fields of the set to reflect hr being added to - // the set and tags the region appropriately. - inline void add_internal(HeapRegion* hr); - - // It updates the fields of the set to reflect hr being removed - // from the set. - inline void update_for_removal(HeapRegion* hr); - - // It updates the fields of the set to reflect hr being removed - // from the set and tags the region appropriately. - inline void remove_internal(HeapRegion* hr); - - // It clears all the fields of the sets. Note: it will not iterate - // over the set and remove regions from it. It assumes that the - // caller has already done so. It will literally just clear the fields. - virtual void clear(); - - HeapRegionSetBase(const char* name); - -public: - static void set_unrealistically_long_length(uint len); - - const char* name() { return _name; } - - uint length() { return _length; } - - bool is_empty() { return _length == 0; } - - uint region_num() { return _region_num; } - - size_t total_capacity_bytes() { - return (size_t) region_num() << HeapRegion::LogOfHRGrainBytes; - } - - size_t total_used_bytes() { return _total_used_bytes; } - virtual void verify(); void verify_start(); void verify_next_region(HeapRegion* hr); @@ -187,7 +160,6 @@ public: // assert/guarantee-specific message it also prints out the values of // the fields of the associated set. This can be very helpful in // diagnosing failures. - class hrs_ext_msg : public hrs_err_msg { public: hrs_ext_msg(HeapRegionSetBase* set, const char* message) : hrs_err_msg("") { @@ -195,32 +167,6 @@ public: } }; -class HRSPhaseSetter { -public: - HRSPhaseSetter(HRSPhase phase) { - HeapRegionSetBase::set_phase(phase); - } - ~HRSPhaseSetter() { - HeapRegionSetBase::clear_phase(); - } -}; - -// These two macros are provided for convenience, to keep the uses of -// these two asserts a bit more concise. - -#define hrs_assert_mt_safety_ok(_set_) \ - do { \ - assert((_set_)->check_mt_safety(), hrs_ext_msg((_set_), "MT safety")); \ - } while (0) - -#define hrs_assert_region_ok(_set_, _hr_, _expected_) \ - do { \ - assert((_set_)->verify_region((_hr_), (_expected_)), \ - hrs_ext_msg((_set_), "region verification")); \ - } while (0) - -//////////////////// HeapRegionSet //////////////////// - #define hrs_assert_sets_match(_set1_, _set2_) \ do { \ assert(((_set1_)->regions_humongous() == \ @@ -236,63 +182,33 @@ public: // the same interface (namely, the HeapRegionSetBase API). class HeapRegionSet : public HeapRegionSetBase { -protected: - virtual const char* verify_region_extra(HeapRegion* hr) { - if (hr->next() != NULL) { - return "next() should always be NULL as we do not link the regions"; - } - - return HeapRegionSetBase::verify_region_extra(hr); - } - - HeapRegionSet(const char* name) : HeapRegionSetBase(name) { - clear(); - } - public: - // It adds hr to the set. The region should not be a member of - // another set. - inline void add(HeapRegion* hr); + HeapRegionSet(const char* name, bool humongous, HRSMtSafeChecker* mt_safety_checker): + HeapRegionSetBase(name, humongous, false /* empty */, mt_safety_checker) { } - // It removes hr from the set. The region should be a member of - // this set. - inline void remove(HeapRegion* hr); - - // It removes a region from the set. Instead of updating the fields - // of the set to reflect this removal, it accumulates the updates - // in proxy_set. The idea is that proxy_set is thread-local to - // avoid multiple threads updating the fields of the set - // concurrently and having to synchronize. The method - // update_from_proxy() will update the fields of the set from the - // proxy_set. - inline void remove_with_proxy(HeapRegion* hr, HeapRegionSet* proxy_set); - - // After multiple calls to remove_with_proxy() the updates to the - // fields of the set are accumulated in proxy_set. This call - // updates the fields of the set from proxy_set. - void update_from_proxy(HeapRegionSet* proxy_set); + void bulk_remove(const HeapRegionSetCount& removed) { + _count.decrement(removed.length(), removed.capacity()); + } }; -//////////////////// HeapRegionLinkedList //////////////////// - // A set that links all the regions added to it in a singly-linked // list. We should try to avoid doing operations that iterate over // such lists in performance critical paths. Typically we should // add / remove one region at a time or concatenate two lists. All // those operations are done in constant time. -class HeapRegionLinkedListIterator; +class FreeRegionListIterator; -class HeapRegionLinkedList : public HeapRegionSetBase { - friend class HeapRegionLinkedListIterator; +class FreeRegionList : public HeapRegionSetBase { + friend class FreeRegionListIterator; private: HeapRegion* _head; HeapRegion* _tail; - // These are provided for use by the friend classes. - HeapRegion* head() { return _head; } - HeapRegion* tail() { return _tail; } + static uint _unrealistically_long_length; + + void add_as_head_or_tail(FreeRegionList* from_list, bool as_head); protected: virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg); @@ -300,11 +216,19 @@ protected: // See the comment for HeapRegionSetBase::clear() virtual void clear(); - HeapRegionLinkedList(const char* name) : HeapRegionSetBase(name) { +public: + FreeRegionList(const char* name, HRSMtSafeChecker* mt_safety_checker = NULL): + HeapRegionSetBase(name, false /* humongous */, true /* empty */, mt_safety_checker) { clear(); } -public: + void verify_list(); + + HeapRegion* head() { return _head; } + HeapRegion* tail() { return _tail; } + + static void set_unrealistically_long_length(uint len); + // It adds hr to the list as the new head. The region should not be // a member of another set. inline void add_as_head(HeapRegion* hr); @@ -323,12 +247,12 @@ public: // It moves the regions from from_list to this list and empties // from_list. The new regions will appear in the same order as they // were in from_list and be linked in the beginning of this list. - void add_as_head(HeapRegionLinkedList* from_list); + void add_as_head(FreeRegionList* from_list); // It moves the regions from from_list to this list and empties // from_list. The new regions will appear in the same order as they // were in from_list and be linked in the end of this list. - void add_as_tail(HeapRegionLinkedList* from_list); + void add_as_tail(FreeRegionList* from_list); // It empties the list by removing all regions from it. void remove_all(); @@ -346,14 +270,12 @@ public: virtual void print_on(outputStream* out, bool print_contents = false); }; -//////////////////// HeapRegionLinkedListIterator //////////////////// - // Iterator class that provides a convenient way to iterate over the // regions of a HeapRegionLinkedList instance. -class HeapRegionLinkedListIterator : public StackObj { +class FreeRegionListIterator : public StackObj { private: - HeapRegionLinkedList* _list; + FreeRegionList* _list; HeapRegion* _curr; public: @@ -369,12 +291,12 @@ public: // do the "cycle" check. HeapRegion* hr = _curr; - assert(_list->verify_region(hr, _list), "region verification"); + _list->verify_region(hr); _curr = hr->next(); return hr; } - HeapRegionLinkedListIterator(HeapRegionLinkedList* list) + FreeRegionListIterator(FreeRegionList* list) : _curr(NULL), _list(list) { _curr = list->head(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp index 18c754bdc51..2a948ec70c8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp @@ -27,87 +27,32 @@ #include "gc_implementation/g1/heapRegionSet.hpp" -//////////////////// HeapRegionSetBase //////////////////// - -inline void HeapRegionSetBase::update_for_addition(HeapRegion* hr) { - // Assumes the caller has already verified the region. - - _length += 1; - _region_num += hr->region_num(); - _total_used_bytes += hr->used(); -} - -inline void HeapRegionSetBase::add_internal(HeapRegion* hr) { - hrs_assert_region_ok(this, hr, NULL); +inline void HeapRegionSetBase::add(HeapRegion* hr) { + check_mt_safety(); + assert(hr->containing_set() == NULL, hrs_ext_msg(this, "should not already have a containing set %u")); assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked")); - update_for_addition(hr); + _count.increment(1u, hr->capacity()); hr->set_containing_set(this); + verify_region(hr); } -inline void HeapRegionSetBase::update_for_removal(HeapRegion* hr) { - // Assumes the caller has already verified the region. - assert(_length > 0, hrs_ext_msg(this, "pre-condition")); - _length -= 1; - - uint region_num_diff = hr->region_num(); - assert(region_num_diff <= _region_num, - hrs_err_msg("[%s] region's region num: %u " - "should be <= region num: %u", - name(), region_num_diff, _region_num)); - _region_num -= region_num_diff; - - size_t used_bytes = hr->used(); - assert(used_bytes <= _total_used_bytes, - hrs_err_msg("[%s] region's used bytes: "SIZE_FORMAT" " - "should be <= used bytes: "SIZE_FORMAT, - name(), used_bytes, _total_used_bytes)); - _total_used_bytes -= used_bytes; -} - -inline void HeapRegionSetBase::remove_internal(HeapRegion* hr) { - hrs_assert_region_ok(this, hr, this); +inline void HeapRegionSetBase::remove(HeapRegion* hr) { + check_mt_safety(); + verify_region(hr); assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked")); hr->set_containing_set(NULL); - update_for_removal(hr); + assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition")); + _count.decrement(1u, hr->capacity()); } -//////////////////// HeapRegionSet //////////////////// - -inline void HeapRegionSet::add(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); - // add_internal() will verify the region. - add_internal(hr); -} - -inline void HeapRegionSet::remove(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); - // remove_internal() will verify the region. - remove_internal(hr); -} - -inline void HeapRegionSet::remove_with_proxy(HeapRegion* hr, - HeapRegionSet* proxy_set) { - // No need to fo the MT safety check here given that this method - // does not update the contents of the set but instead accumulates - // the changes in proxy_set which is assumed to be thread-local. - hrs_assert_sets_match(this, proxy_set); - hrs_assert_region_ok(this, hr, this); - - hr->set_containing_set(NULL); - proxy_set->update_for_addition(hr); -} - -//////////////////// HeapRegionLinkedList //////////////////// - -inline void HeapRegionLinkedList::add_as_head(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); +inline void FreeRegionList::add_as_head(HeapRegion* hr) { assert((length() == 0 && _head == NULL && _tail == NULL) || (length() > 0 && _head != NULL && _tail != NULL), hrs_ext_msg(this, "invariant")); - // add_internal() will verify the region. - add_internal(hr); + // add() will verify the region and check mt safety. + add(hr); // Now link the region. if (_head != NULL) { @@ -118,13 +63,13 @@ inline void HeapRegionLinkedList::add_as_head(HeapRegion* hr) { _head = hr; } -inline void HeapRegionLinkedList::add_as_tail(HeapRegion* hr) { - hrs_assert_mt_safety_ok(this); +inline void FreeRegionList::add_as_tail(HeapRegion* hr) { + check_mt_safety(); assert((length() == 0 && _head == NULL && _tail == NULL) || (length() > 0 && _head != NULL && _tail != NULL), hrs_ext_msg(this, "invariant")); - // add_internal() will verify the region. - add_internal(hr); + // add() will verify the region and check mt safety + add(hr); // Now link the region. if (_tail != NULL) { @@ -135,8 +80,7 @@ inline void HeapRegionLinkedList::add_as_tail(HeapRegion* hr) { _tail = hr; } -inline HeapRegion* HeapRegionLinkedList::remove_head() { - hrs_assert_mt_safety_ok(this); +inline HeapRegion* FreeRegionList::remove_head() { assert(!is_empty(), hrs_ext_msg(this, "the list should not be empty")); assert(length() > 0 && _head != NULL && _tail != NULL, hrs_ext_msg(this, "invariant")); @@ -149,14 +93,13 @@ inline HeapRegion* HeapRegionLinkedList::remove_head() { } hr->set_next(NULL); - // remove_internal() will verify the region. - remove_internal(hr); + // remove() will verify the region and check mt safety + remove(hr); return hr; } -inline HeapRegion* HeapRegionLinkedList::remove_head_or_null() { - hrs_assert_mt_safety_ok(this); - +inline HeapRegion* FreeRegionList::remove_head_or_null() { + check_mt_safety(); if (!is_empty()) { return remove_head(); } else { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp index d2a9665c953..167a440445e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" -#include "gc_implementation/g1/heapRegionSets.hpp" +#include "gc_implementation/g1/heapRegionSet.hpp" // Note on the check_mt_safety() methods below: // @@ -37,30 +37,34 @@ // for the "master" heap region sets / lists, the check_mt_safety() // method should include the VM thread / STW case. -//////////////////// FreeRegionList //////////////////// +void FreeRegionList::verify_list() { + HeapRegion* curr = head(); + HeapRegion* prev1 = NULL; + HeapRegion* prev0 = NULL; + uint count = 0; + size_t capacity = 0; + while (curr != NULL) { + verify_region(curr); -const char* FreeRegionList::verify_region_extra(HeapRegion* hr) { - if (hr->is_young()) { - return "the region should not be young"; + count++; + guarantee(count < _unrealistically_long_length, + hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length())); + + capacity += curr->capacity(); + + prev1 = prev0; + prev0 = curr; + curr = curr->next(); } - // The superclass will check that the region is empty and - // not humongous. - return HeapRegionLinkedList::verify_region_extra(hr); + + guarantee(tail() == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), tail()->hrs_index(), prev0->hrs_index())); + + guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); + guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + name(), total_capacity_bytes(), capacity)); } -//////////////////// MasterFreeRegionList //////////////////// - -const char* MasterFreeRegionList::verify_region_extra(HeapRegion* hr) { - // We should reset the RSet for parallel iteration before we add it - // to the master free list so that it is ready when the region is - // re-allocated. - if (!hr->rem_set()->verify_ready_for_par_iteration()) { - return "the region's RSet should be ready for parallel iteration"; - } - return FreeRegionList::verify_region_extra(hr); -} - -bool MasterFreeRegionList::check_mt_safety() { +void MasterFreeRegionListMtSafeChecker::check() { // Master Free List MT safety protocol: // (a) If we're at a safepoint, operations on the master free list // should be invoked by either the VM thread (which will serialize @@ -71,45 +75,21 @@ bool MasterFreeRegionList::check_mt_safety() { if (SafepointSynchronize::is_at_safepoint()) { guarantee(Thread::current()->is_VM_thread() || - FreeList_lock->owned_by_self(), - hrs_ext_msg(this, "master free list MT safety protocol " - "at a safepoint")); + FreeList_lock->owned_by_self(), "master free list MT safety protocol at a safepoint"); } else { - guarantee(Heap_lock->owned_by_self(), - hrs_ext_msg(this, "master free list MT safety protocol " - "outside a safepoint")); + guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint"); } - - return FreeRegionList::check_mt_safety(); } -//////////////////// SecondaryFreeRegionList //////////////////// - -bool SecondaryFreeRegionList::check_mt_safety() { +void SecondaryFreeRegionListMtSafeChecker::check() { // Secondary Free List MT safety protocol: // Operations on the secondary free list should always be invoked // while holding the SecondaryFreeList_lock. - guarantee(SecondaryFreeList_lock->owned_by_self(), - hrs_ext_msg(this, "secondary free list MT safety protocol")); - - return FreeRegionList::check_mt_safety(); + guarantee(SecondaryFreeList_lock->owned_by_self(), "secondary free list MT safety protocol"); } -//////////////////// OldRegionSet //////////////////// - -const char* OldRegionSet::verify_region_extra(HeapRegion* hr) { - if (hr->is_young()) { - return "the region should not be young"; - } - // The superclass will check that the region is not empty and not - // humongous. - return HeapRegionSet::verify_region_extra(hr); -} - -//////////////////// MasterOldRegionSet //////////////////// - -bool MasterOldRegionSet::check_mt_safety() { +void OldRegionSetMtSafeChecker::check() { // Master Old Set MT safety protocol: // (a) If we're at a safepoint, operations on the master old set // should be invoked: @@ -124,35 +104,16 @@ bool MasterOldRegionSet::check_mt_safety() { // should be invoked while holding the Heap_lock. if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() || - _phase == HRSPhaseEvacuation && FreeList_lock->owned_by_self() || - _phase == HRSPhaseCleanup && OldSets_lock->owned_by_self(), - hrs_ext_msg(this, "master old set MT safety protocol " - "at a safepoint")); + guarantee(Thread::current()->is_VM_thread() + || FreeList_lock->owned_by_self() || OldSets_lock->owned_by_self(), + "master old set MT safety protocol at a safepoint"); } else { - guarantee(Heap_lock->owned_by_self(), - hrs_ext_msg(this, "master old set MT safety protocol " - "outside a safepoint")); + guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint"); } - - return OldRegionSet::check_mt_safety(); } -//////////////////// HumongousRegionSet //////////////////// - -const char* HumongousRegionSet::verify_region_extra(HeapRegion* hr) { - if (hr->is_young()) { - return "the region should not be young"; - } - // The superclass will check that the region is not empty and - // humongous. - return HeapRegionSet::verify_region_extra(hr); -} - -//////////////////// MasterHumongousRegionSet //////////////////// - -bool MasterHumongousRegionSet::check_mt_safety() { - // Master Humongous Set MT safety protocol: +void HumongousRegionSetMtSafeChecker::check() { + // Humongous Set MT safety protocol: // (a) If we're at a safepoint, operations on the master humongous // set should be invoked by either the VM thread (which will // serialize them) or by the GC workers while holding the @@ -163,13 +124,9 @@ bool MasterHumongousRegionSet::check_mt_safety() { if (SafepointSynchronize::is_at_safepoint()) { guarantee(Thread::current()->is_VM_thread() || OldSets_lock->owned_by_self(), - hrs_ext_msg(this, "master humongous set MT safety protocol " - "at a safepoint")); + "master humongous set MT safety protocol at a safepoint"); } else { guarantee(Heap_lock->owned_by_self(), - hrs_ext_msg(this, "master humongous set MT safety protocol " - "outside a safepoint")); + "master humongous set MT safety protocol outside a safepoint"); } - - return HumongousRegionSet::check_mt_safety(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp deleted file mode 100644 index 66423266ef3..00000000000 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.hpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2011, 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_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP -#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP - -#include "gc_implementation/g1/heapRegionSet.inline.hpp" - -//////////////////// FreeRegionList //////////////////// - -class FreeRegionList : public HeapRegionLinkedList { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - - virtual bool regions_humongous() { return false; } - virtual bool regions_empty() { return true; } - -public: - FreeRegionList(const char* name) : HeapRegionLinkedList(name) { } -}; - -//////////////////// MasterFreeRegionList //////////////////// - -class MasterFreeRegionList : public FreeRegionList { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - virtual bool check_mt_safety(); - -public: - MasterFreeRegionList(const char* name) : FreeRegionList(name) { } -}; - -//////////////////// SecondaryFreeRegionList //////////////////// - -class SecondaryFreeRegionList : public FreeRegionList { -protected: - virtual bool check_mt_safety(); - -public: - SecondaryFreeRegionList(const char* name) : FreeRegionList(name) { } -}; - -//////////////////// OldRegionSet //////////////////// - -class OldRegionSet : public HeapRegionSet { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - - virtual bool regions_humongous() { return false; } - virtual bool regions_empty() { return false; } - -public: - OldRegionSet(const char* name) : HeapRegionSet(name) { } -}; - -//////////////////// MasterOldRegionSet //////////////////// - -class MasterOldRegionSet : public OldRegionSet { -private: -protected: - virtual bool check_mt_safety(); - -public: - MasterOldRegionSet(const char* name) : OldRegionSet(name) { } -}; - -//////////////////// HumongousRegionSet //////////////////// - -class HumongousRegionSet : public HeapRegionSet { -protected: - virtual const char* verify_region_extra(HeapRegion* hr); - - virtual bool regions_humongous() { return true; } - virtual bool regions_empty() { return false; } - -public: - HumongousRegionSet(const char* name) : HeapRegionSet(name) { } -}; - -//////////////////// MasterHumongousRegionSet //////////////////// - -class MasterHumongousRegionSet : public HumongousRegionSet { -protected: - virtual bool check_mt_safety(); - -public: - MasterHumongousRegionSet(const char* name) : HumongousRegionSet(name) { } -}; - -#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSETS_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp index 2e4ed2dfb4a..d7820f89abe 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vmStructs_g1.hpp @@ -57,9 +57,10 @@ nonstatic_field(G1MonitoringSupport, _old_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _old_used, size_t) \ \ - nonstatic_field(HeapRegionSetBase, _length, uint) \ - nonstatic_field(HeapRegionSetBase, _region_num, uint) \ - nonstatic_field(HeapRegionSetBase, _total_used_bytes, size_t) \ + nonstatic_field(HeapRegionSetBase, _count, HeapRegionSetCount) \ + \ + nonstatic_field(HeapRegionSetCount, _length, uint) \ + nonstatic_field(HeapRegionSetCount, _capacity, size_t) \ #define VM_TYPES_G1(declare_type, declare_toplevel_type) \ @@ -71,6 +72,7 @@ declare_type(HeapRegion, ContiguousSpace) \ declare_toplevel_type(HeapRegionSeq) \ declare_toplevel_type(HeapRegionSetBase) \ + declare_toplevel_type(HeapRegionSetCount) \ declare_toplevel_type(G1MonitoringSupport) \ \ declare_toplevel_type(G1CollectedHeap*) \ From 329e55e7b091e8af80b8607c884062cdab6f2d1c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:12:21 +0100 Subject: [PATCH 009/170] 8035406: Improve data structure for Code Cache remembered sets Change the code cache remembered sets data structure from a GrowableArray to a chunked list of nmethods. This makes the data structure more amenable to parallelization, and decreases freeing time. Reviewed-by: mgerdin, brutisso --- hotspot/make/excludeSrc.make | 4 +- .../g1/g1CodeCacheRemSet.cpp | 317 ++++++++++++++++++ .../g1/g1CodeCacheRemSet.hpp | 188 +++++++++++ .../gc_implementation/g1/g1CollectedHeap.cpp | 11 +- .../gc_implementation/g1/g1CollectedHeap.hpp | 5 +- .../gc_implementation/g1/g1GCPhaseTimes.cpp | 6 +- .../gc_implementation/g1/g1GCPhaseTimes.hpp | 7 +- .../vm/gc_implementation/g1/g1_globals.hpp | 6 +- .../vm/gc_implementation/g1/heapRegion.cpp | 6 +- .../gc_implementation/g1/heapRegionRemSet.cpp | 66 ++-- .../gc_implementation/g1/heapRegionRemSet.hpp | 42 ++- hotspot/src/share/vm/memory/freeList.cpp | 4 +- hotspot/src/share/vm/prims/jni.cpp | 2 + hotspot/test/gc/g1/TestGCLogMessages.java | 61 ++++ 14 files changed, 656 insertions(+), 69 deletions(-) create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp create mode 100644 hotspot/test/gc/g1/TestGCLogMessages.java diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index 24f1fa20ec3..e76c05fa0fa 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -89,7 +89,7 @@ ifeq ($(INCLUDE_ALL_GCS), false) g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \ g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \ - ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \ + ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp g1CodeCacheRemSet.cpp \ adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \ cardTableExtension.cpp gcTaskManager.cpp gcTaskThread.cpp objectStartArray.cpp \ parallelScavengeHeap.cpp parMarkBitMap.cpp pcTasks.cpp psAdaptiveSizePolicy.cpp \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp new file mode 100644 index 00000000000..7b23022777f --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2014, 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 "code/nmethod.hpp" +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" +#include "memory/iterator.hpp" + +G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL) { + _top = bottom(); +} + +void G1CodeRootChunk::reset() { + _next = _prev = NULL; + _top = bottom(); +} + +void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) { + nmethod** cur = bottom(); + while (cur != _top) { + cl->do_code_blob(*cur); + cur++; + } +} + +FreeList G1CodeRootSet::_free_list; +size_t G1CodeRootSet::_num_chunks_handed_out = 0; + +G1CodeRootChunk* G1CodeRootSet::new_chunk() { + G1CodeRootChunk* result = _free_list.get_chunk_at_head(); + if (result == NULL) { + result = new G1CodeRootChunk(); + } + G1CodeRootSet::_num_chunks_handed_out++; + result->reset(); + return result; +} + +void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) { + _free_list.return_chunk_at_head(chunk); + G1CodeRootSet::_num_chunks_handed_out--; +} + +void G1CodeRootSet::free_all_chunks(FreeList* list) { + G1CodeRootSet::_num_chunks_handed_out -= list->count(); + _free_list.prepend(list); +} + +void G1CodeRootSet::purge_chunks(size_t keep_ratio) { + size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100; + + if (keep >= (size_t)_free_list.count()) { + return; + } + + FreeList temp; + temp.initialize(); + temp.set_size(G1CodeRootChunk::word_size()); + + _free_list.getFirstNChunksFromList((size_t)_free_list.count() - keep, &temp); + + G1CodeRootChunk* cur = temp.get_chunk_at_head(); + while (cur != NULL) { + delete cur; + cur = temp.get_chunk_at_head(); + } +} + +size_t G1CodeRootSet::static_mem_size() { + return sizeof(_free_list) + sizeof(_num_chunks_handed_out); +} + +size_t G1CodeRootSet::fl_mem_size() { + return _free_list.count() * _free_list.size(); +} + +void G1CodeRootSet::initialize() { + _free_list.initialize(); + _free_list.set_size(G1CodeRootChunk::word_size()); +} + +G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) { + _list.initialize(); + _list.set_size(G1CodeRootChunk::word_size()); +} + +G1CodeRootSet::~G1CodeRootSet() { + clear(); +} + +void G1CodeRootSet::add(nmethod* method) { + if (!contains(method)) { + // Try to add the nmethod. If there is not enough space, get a new chunk. + if (_list.head() == NULL || _list.head()->is_full()) { + G1CodeRootChunk* cur = new_chunk(); + _list.return_chunk_at_head(cur); + } + bool result = _list.head()->add(method); + guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method)); + _length++; + } +} + +void G1CodeRootSet::remove(nmethod* method) { + G1CodeRootChunk* found = find(method); + if (found != NULL) { + bool result = found->remove(method); + guarantee(result, err_msg("could not find nmethod "PTR_FORMAT" during removal although we previously found it", method)); + // eventually free completely emptied chunk + if (found->is_empty()) { + _list.remove_chunk(found); + free(found); + } + _length--; + } + assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method)); +} + +nmethod* G1CodeRootSet::pop() { + do { + G1CodeRootChunk* cur = _list.head(); + if (cur == NULL) { + assert(_length == 0, "when there are no chunks, there should be no elements"); + return NULL; + } + nmethod* result = cur->pop(); + if (result != NULL) { + _length--; + return result; + } else { + free(_list.get_chunk_at_head()); + } + } while (true); +} + +G1CodeRootChunk* G1CodeRootSet::find(nmethod* method) { + G1CodeRootChunk* cur = _list.head(); + while (cur != NULL) { + if (cur->contains(method)) { + return cur; + } + cur = (G1CodeRootChunk*)cur->next(); + } + return NULL; +} + +void G1CodeRootSet::free(G1CodeRootChunk* chunk) { + free_chunk(chunk); +} + +bool G1CodeRootSet::contains(nmethod* method) { + return find(method) != NULL; +} + +void G1CodeRootSet::clear() { + free_all_chunks(&_list); + _length = 0; +} + +void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const { + G1CodeRootChunk* cur = _list.head(); + while (cur != NULL) { + cur->nmethods_do(blk); + cur = (G1CodeRootChunk*)cur->next(); + } +} + +size_t G1CodeRootSet::mem_size() { + return sizeof(this) + _list.count() * _list.size(); +} + +#ifndef PRODUCT + +void G1CodeRootSet::test() { + initialize(); + + assert(_free_list.count() == 0, "Free List must be empty"); + assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); + + // The number of chunks that we allocate for purge testing. + size_t const num_chunks = 10; + { + G1CodeRootSet set1; + assert(set1.is_empty(), "Code root set must be initially empty but is not."); + + set1.add((nmethod*)1); + assert(_num_chunks_handed_out == 1, + err_msg("Must have allocated and handed out one chunk, but handed out " + SIZE_FORMAT" chunks", _num_chunks_handed_out)); + assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " + SIZE_FORMAT" elements", set1.length())); + + // G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which + // we cannot access. + for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) { + set1.add((nmethod*)1); + } + assert(_num_chunks_handed_out == 1, + err_msg("Duplicate detection must have prevented allocation of further " + "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out)); + assert(set1.length() == 1, + err_msg("Duplicate detection should not have increased the set size but " + "is "SIZE_FORMAT, set1.length())); + + size_t num_total_after_add = G1CodeRootChunk::word_size() + 1; + for (size_t i = 0; i < num_total_after_add - 1; i++) { + set1.add((nmethod*)(2 + i)); + } + assert(_num_chunks_handed_out > 1, + "After adding more code roots, more than one chunks should have been handed out"); + assert(set1.length() == num_total_after_add, + err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they " + "need to be in the set, but there are only "SIZE_FORMAT, + num_total_after_add, set1.length())); + + size_t num_popped = 0; + while (set1.pop() != NULL) { + num_popped++; + } + assert(num_popped == num_total_after_add, + err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" " + "were added", num_popped, num_total_after_add)); + assert(_num_chunks_handed_out == 0, + err_msg("After popping all elements, all chunks must have been returned " + "but are still "SIZE_FORMAT, _num_chunks_handed_out)); + + purge_chunks(0); + assert(_free_list.count() == 0, + err_msg("After purging everything, the free list must be empty but still " + "contains "SIZE_FORMAT" chunks", _free_list.count())); + + // Add some more handed out chunks. + size_t i = 0; + while (_num_chunks_handed_out < num_chunks) { + set1.add((nmethod*)i); + i++; + } + + { + // Generate chunks on the free list. + G1CodeRootSet set2; + size_t i = 0; + while (_num_chunks_handed_out < num_chunks * 2) { + set2.add((nmethod*)i); + i++; + } + // Exit of the scope of the set2 object will call the destructor that generates + // num_chunks elements on the free list. + } + + assert(_num_chunks_handed_out == num_chunks, + err_msg("Deletion of the second set must have resulted in giving back " + "those, but there is still "SIZE_FORMAT" handed out, expecting " + SIZE_FORMAT, _num_chunks_handed_out, num_chunks)); + assert((size_t)_free_list.count() == num_chunks, + err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " + "but there are only "SIZE_FORMAT, num_chunks, _free_list.count())); + + size_t const test_percentage = 50; + purge_chunks(test_percentage); + assert(_num_chunks_handed_out == num_chunks, + err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT, + _num_chunks_handed_out)); + assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100), + err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks" + "but there are "SSIZE_FORMAT, test_percentage, num_chunks, + _free_list.count())); + // Purge the remainder of the chunks on the free list. + purge_chunks(0); + assert(_free_list.count() == 0, "Free List must be empty"); + assert(_num_chunks_handed_out == num_chunks, + err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set " + "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out)); + + // Exit of the scope of the set1 object will call the destructor that generates + // num_chunks additional elements on the free list. + } + + assert(_num_chunks_handed_out == 0, + err_msg("Deletion of the only set must have resulted in no chunks handed " + "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out)); + assert((size_t)_free_list.count() == num_chunks, + err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list " + "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count())); + + // Restore initial state. + purge_chunks(0); + assert(_free_list.count() == 0, "Free List must be empty"); + assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet"); +} + +void TestCodeCacheRemSet_test() { + G1CodeRootSet::test(); +} +#endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp new file mode 100644 index 00000000000..ad8025c4b03 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, 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_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP + +#include "memory/allocation.hpp" +#include "memory/freeList.hpp" +#include "runtime/globals.hpp" + +class CodeBlobClosure; + +class G1CodeRootChunk : public CHeapObj { + private: + static const int NUM_ENTRIES = 32; + public: + G1CodeRootChunk* _next; + G1CodeRootChunk* _prev; + + nmethod** _top; + + nmethod* _data[NUM_ENTRIES]; + + nmethod** bottom() const { + return (nmethod**) &(_data[0]); + } + + nmethod** end() const { + return (nmethod**) &(_data[NUM_ENTRIES]); + } + + public: + G1CodeRootChunk(); + ~G1CodeRootChunk() {} + + static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); } + + // FreeList "interface" methods + + G1CodeRootChunk* next() const { return _next; } + G1CodeRootChunk* prev() const { return _prev; } + void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");} + void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");} + void clear_next() { set_next(NULL); } + void clear_prev() { set_prev(NULL); } + + size_t size() const { return word_size(); } + + void link_next(G1CodeRootChunk* ptr) { set_next(ptr); } + void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); } + void link_after(G1CodeRootChunk* ptr) { + link_next(ptr); + if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this); + } + + bool is_free() { return true; } + + // New G1CodeRootChunk routines + + void reset(); + + bool is_empty() const { + return _top == bottom(); + } + + bool is_full() const { + return _top == (nmethod**)end(); + } + + bool contains(nmethod* method) { + nmethod** cur = bottom(); + while (cur != _top) { + if (*cur == method) return true; + cur++; + } + return false; + } + + bool add(nmethod* method) { + if (is_full()) return false; + *_top = method; + _top++; + return true; + } + + bool remove(nmethod* method) { + nmethod** cur = bottom(); + while (cur != _top) { + if (*cur == method) { + memmove(cur, cur + 1, (_top - (cur + 1)) * sizeof(nmethod**)); + _top--; + return true; + } + cur++; + } + return false; + } + + void nmethods_do(CodeBlobClosure* blk); + + nmethod* pop() { + if (is_empty()) { + return NULL; + } + _top--; + return *_top; + } +}; + +// Implements storage for a set of code roots. +// All methods that modify the set are not thread-safe except if otherwise noted. +class G1CodeRootSet VALUE_OBJ_CLASS_SPEC { + private: + // Global free chunk list management + static FreeList _free_list; + // Total number of chunks handed out + static size_t _num_chunks_handed_out; + + static G1CodeRootChunk* new_chunk(); + static void free_chunk(G1CodeRootChunk* chunk); + // Free all elements of the given list. + static void free_all_chunks(FreeList* list); + + // Return the chunk that contains the given nmethod, NULL otherwise. + // Scans the list of chunks backwards, as this method is used to add new + // entries, which are typically added in bulk for a single nmethod. + G1CodeRootChunk* find(nmethod* method); + void free(G1CodeRootChunk* chunk); + + size_t _length; + FreeList _list; + + public: + G1CodeRootSet(); + ~G1CodeRootSet(); + + static void initialize(); + static void purge_chunks(size_t keep_ratio); + + static size_t static_mem_size(); + static size_t fl_mem_size(); + + // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this + // method is likely to be repeatedly called with the same nmethod. + void add(nmethod* method); + + void remove(nmethod* method); + nmethod* pop(); + + bool contains(nmethod* method); + + void clear(); + + void nmethods_do(CodeBlobClosure* blk) const; + + bool is_empty() { return length() == 0; } + + // Length in elements + size_t length() const { return _length; } + + // Memory size in bytes taken by this set. + size_t mem_size(); + + static void test() PRODUCT_RETURN; +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 95310267ac6..1bf8decf931 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -5898,6 +5898,8 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { // strong code roots for a particular heap region. migrate_strong_code_roots(); + purge_code_root_memory(); + if (g1_policy()->during_initial_mark_pause()) { // Reset the claim values set during marking the strong code roots reset_heap_region_claim_values(); @@ -6774,6 +6776,13 @@ void G1CollectedHeap::migrate_strong_code_roots() { g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms); } +void G1CollectedHeap::purge_code_root_memory() { + double purge_start = os::elapsedTime(); + G1CodeRootSet::purge_chunks(G1CodeRootsChunkCacheKeepPercent); + double purge_time_ms = (os::elapsedTime() - purge_start) * 1000.0; + g1_policy()->phase_times()->record_strong_code_root_purge_time(purge_time_ms); +} + // Mark all the code roots that point into regions *not* in the // collection set. // @@ -6844,7 +6853,7 @@ public: // Code roots should never be attached to a continuation of a humongous region assert(hrrs->strong_code_roots_list_length() == 0, err_msg("code roots should never be attached to continuations of humongous region "HR_FORMAT - " starting at "HR_FORMAT", but has "INT32_FORMAT, + " starting at "HR_FORMAT", but has "SIZE_FORMAT, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()), hrrs->strong_code_roots_list_length())); return false; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 801bc2d2052..2338e8dc89c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -1633,6 +1633,9 @@ public: // that were not successfully evacuated are not migrated. void migrate_strong_code_roots(); + // Free up superfluous code root memory. + void purge_code_root_memory(); + // During an initial mark pause, mark all the code roots that // point into regions *not* in the collection set. void mark_strong_code_roots(uint worker_id); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 0eda4b35d71..45a4e526eca 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014 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 @@ -250,6 +250,9 @@ double G1GCPhaseTimes::accounted_time_ms() { // Strong code root migration time misc_time_ms += _cur_strong_code_root_migration_time_ms; + // Strong code root purge time + misc_time_ms += _cur_strong_code_root_purge_time_ms; + // Subtract the time taken to clean the card table from the // current value of "other time" misc_time_ms += _cur_clear_ct_time_ms; @@ -299,6 +302,7 @@ void G1GCPhaseTimes::print(double pause_time_sec) { } print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms); + print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); print_stats(1, "Clear CT", _cur_clear_ct_time_ms); double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); print_stats(1, "Other", misc_time_ms); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index b2de97dc4b6..46ac0da8a1b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014 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 @@ -131,6 +131,7 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_collection_par_time_ms; double _cur_collection_code_root_fixup_time_ms; double _cur_strong_code_root_migration_time_ms; + double _cur_strong_code_root_purge_time_ms; double _cur_clear_ct_time_ms; double _cur_ref_proc_time_ms; @@ -223,6 +224,10 @@ class G1GCPhaseTimes : public CHeapObj { _cur_strong_code_root_migration_time_ms = ms; } + void record_strong_code_root_purge_time(double ms) { + _cur_strong_code_root_purge_time_ms = ms; + } + void record_ref_proc_time(double ms) { _cur_ref_proc_time_ms = ms; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index 74158edb7c3..8c8a30bae38 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -285,6 +285,10 @@ product(uintx, G1MixedGCCountTarget, 8, \ "The target number of mixed GCs after a marking cycle.") \ \ + experimental(uintx, G1CodeRootsChunkCacheKeepPercent, 10, \ + "The amount of code root chunks that should be kept at most " \ + "as percentage of already allocated.") \ + \ experimental(uintx, G1OldCSetRegionThresholdPercent, 10, \ "An upper bound for the number of old CSet regions expressed " \ "as a percentage of the heap size.") \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 587ad1e1812..f70fe6c6d1b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -710,14 +710,14 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const } HeapRegionRemSet* hrrs = rem_set(); - int strong_code_roots_length = hrrs->strong_code_roots_list_length(); + size_t strong_code_roots_length = hrrs->strong_code_roots_list_length(); // if this region is empty then there should be no entries // on its strong code root list if (is_empty()) { if (strong_code_roots_length > 0) { gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty " - "but has "INT32_FORMAT" code root entries", + "but has "SIZE_FORMAT" code root entries", bottom(), end(), strong_code_roots_length); *failures = true; } @@ -727,7 +727,7 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const if (continuesHumongous()) { if (strong_code_roots_length > 0) { gclog_or_tty->print_cr("region "HR_FORMAT" is a continuation of a humongous " - "region but has "INT32_FORMAT" code root entries", + "region but has "SIZE_FORMAT" code root entries", HR_FORMAT_PARAMS(this), strong_code_roots_length); *failures = true; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 4308fc01873..51a699a9663 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -259,10 +259,9 @@ size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0; size_t OtherRegionsTable::_fine_eviction_stride = 0; size_t OtherRegionsTable::_fine_eviction_sample_size = 0; -OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) : +OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) : _g1h(G1CollectedHeap::heap()), - _m(Mutex::leaf, "An OtherRegionsTable lock", true), - _hr(hr), + _hr(hr), _m(m), _coarse_map(G1CollectedHeap::heap()->max_regions(), false /* in-resource-area */), _fine_grain_regions(NULL), @@ -442,7 +441,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { size_t ind = from_hrs_ind & _mod_max_fine_entries_mask; PerRegionTable* prt = find_region_table(ind, from_hr); if (prt == NULL) { - MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); // Confirm that it's really not there... prt = find_region_table(ind, from_hr); if (prt == NULL) { @@ -544,7 +543,7 @@ OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const { jint OtherRegionsTable::_n_coarsenings = 0; PerRegionTable* OtherRegionsTable::delete_region_table() { - assert(_m.owned_by_self(), "Precondition"); + assert(_m->owned_by_self(), "Precondition"); assert(_n_fine_entries == _max_fine_entries, "Precondition"); PerRegionTable* max = NULL; jint max_occ = 0; @@ -676,8 +675,6 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, size_t OtherRegionsTable::occupied() const { - // Cast away const in this case. - MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); size_t sum = occ_fine(); sum += occ_sparse(); sum += occ_coarse(); @@ -707,8 +704,6 @@ size_t OtherRegionsTable::occ_sparse() const { } size_t OtherRegionsTable::mem_size() const { - // Cast away const in this case. - MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); size_t sum = 0; // all PRTs are of the same size so it is sufficient to query only one of them. if (_first_all_fine_prts != NULL) { @@ -739,7 +734,6 @@ void OtherRegionsTable::clear_fcc() { } void OtherRegionsTable::clear() { - MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); // if there are no entries, skip this step if (_first_all_fine_prts != NULL) { guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking"); @@ -759,7 +753,7 @@ void OtherRegionsTable::clear() { } void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { - MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag); size_t hrs_ind = (size_t) from_hr->hrs_index(); size_t ind = hrs_ind & _mod_max_fine_entries_mask; if (del_single_region_table(ind, from_hr)) { @@ -805,7 +799,7 @@ bool OtherRegionsTable::del_single_region_table(size_t ind, bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const { // Cast away const in this case. - MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); + MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag); return contains_reference_locked(from); } @@ -850,7 +844,9 @@ int HeapRegionRemSet::num_par_rem_sets() { HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr) - : _bosa(bosa), _strong_code_roots_list(NULL), _other_regions(hr) { + : _bosa(bosa), + _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #"UINT32_FORMAT, hr->hrs_index()), true), + _code_roots(), _other_regions(hr, &_m) { reset_for_par_iteration(); } @@ -883,7 +879,7 @@ bool HeapRegionRemSet::iter_is_complete() { } #ifndef PRODUCT -void HeapRegionRemSet::print() const { +void HeapRegionRemSet::print() { HeapRegionRemSetIterator iter(this); size_t card_index; while (iter.has_next(card_index)) { @@ -909,14 +905,14 @@ void HeapRegionRemSet::cleanup() { } void HeapRegionRemSet::clear() { - if (_strong_code_roots_list != NULL) { - delete _strong_code_roots_list; - } - _strong_code_roots_list = new (ResourceObj::C_HEAP, mtGC) - GrowableArray(10, 0, NULL, true); + MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + clear_locked(); +} +void HeapRegionRemSet::clear_locked() { + _code_roots.clear(); _other_regions.clear(); - assert(occupied() == 0, "Should be clear."); + assert(occupied_locked() == 0, "Should be clear."); reset_for_par_iteration(); } @@ -937,22 +933,14 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); - // Search for the code blob from the RHS to avoid - // duplicate entries as much as possible - if (_strong_code_roots_list->find_from_end(nm) < 0) { - // Code blob isn't already in the list - _strong_code_roots_list->push(nm); - } + _code_roots.add(nm); } void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { assert(nm != NULL, "sanity"); - int idx = _strong_code_roots_list->find(nm); - if (idx >= 0) { - _strong_code_roots_list->remove_at(idx); - } + _code_roots.remove(nm); // Check that there were no duplicates - guarantee(_strong_code_roots_list->find(nm) < 0, "duplicate entry found"); + guarantee(!_code_roots.contains(nm), "duplicate entry found"); } class NMethodMigrationOopClosure : public OopClosure { @@ -1014,8 +1002,8 @@ void HeapRegionRemSet::migrate_strong_code_roots() { GrowableArray to_be_retained(10); G1CollectedHeap* g1h = G1CollectedHeap::heap(); - while (_strong_code_roots_list->is_nonempty()) { - nmethod *nm = _strong_code_roots_list->pop(); + while (!_code_roots.is_empty()) { + nmethod *nm = _code_roots.pop(); if (nm != NULL) { NMethodMigrationOopClosure oop_cl(g1h, hr(), nm); nm->oops_do(&oop_cl); @@ -1038,20 +1026,16 @@ void HeapRegionRemSet::migrate_strong_code_roots() { } void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const { - for (int i = 0; i < _strong_code_roots_list->length(); i += 1) { - nmethod* nm = _strong_code_roots_list->at(i); - blk->do_code_blob(nm); - } + _code_roots.nmethods_do(blk); } size_t HeapRegionRemSet::strong_code_roots_mem_size() { - return sizeof(GrowableArray) + - _strong_code_roots_list->max_length() * sizeof(nmethod*); + return _code_roots.mem_size(); } //-------------------- Iteration -------------------- -HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) : +HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) : _hrrs(hrrs), _g1h(G1CollectedHeap::heap()), _coarse_map(&hrrs->_other_regions._coarse_map), diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 068f64f412e..f0b315d494d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" #include "gc_implementation/g1/sparsePRT.hpp" // Remembered set for a heap region. Represent a set of "cards" that @@ -72,7 +73,7 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC { friend class HeapRegionRemSetIterator; G1CollectedHeap* _g1h; - Mutex _m; + Mutex* _m; HeapRegion* _hr; // These are protected by "_m". @@ -129,7 +130,7 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC { void unlink_from_all(PerRegionTable * prt); public: - OtherRegionsTable(HeapRegion* hr); + OtherRegionsTable(HeapRegion* hr, Mutex* m); HeapRegion* hr() const { return _hr; } @@ -141,7 +142,6 @@ public: // objects. void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); - // Not const because it takes a lock. size_t occupied() const; size_t occ_fine() const; size_t occ_coarse() const; @@ -192,9 +192,11 @@ private: G1BlockOffsetSharedArray* _bosa; G1BlockOffsetSharedArray* bosa() const { return _bosa; } - // A list of code blobs (nmethods) whose code contains pointers into + // A set of code blobs (nmethods) whose code contains pointers into // the region that owns this RSet. - GrowableArray* _strong_code_roots_list; + G1CodeRootSet _code_roots; + + Mutex _m; OtherRegionsTable _other_regions; @@ -218,8 +220,7 @@ private: static void print_event(outputStream* str, Event evnt); public: - HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, - HeapRegion* hr); + HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr); static int num_par_rem_sets(); static void setup_remset_size(); @@ -228,7 +229,11 @@ public: return _other_regions.hr(); } - size_t occupied() const { + size_t occupied() { + MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); + return occupied_locked(); + } + size_t occupied_locked() { return _other_regions.occupied(); } size_t occ_fine() const { @@ -260,6 +265,7 @@ public: // The region is being reclaimed; clear its remset, and any mention of // entries for this region in other remsets. void clear(); + void clear_locked(); // Attempt to claim the region. Returns true iff this call caused an // atomic transition from Unclaimed to Claimed. @@ -289,6 +295,7 @@ public: // The actual # of bytes this hr_remset takes up. // Note also includes the strong code root set. size_t mem_size() { + MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); return _other_regions.mem_size() // This correction is necessary because the above includes the second // part. @@ -299,13 +306,13 @@ public: // Returns the memory occupancy of all static data structures associated // with remembered sets. static size_t static_mem_size() { - return OtherRegionsTable::static_mem_size(); + return OtherRegionsTable::static_mem_size() + G1CodeRootSet::static_mem_size(); } // Returns the memory occupancy of all free_list data structures associated // with remembered sets. static size_t fl_mem_size() { - return OtherRegionsTable::fl_mem_size(); + return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::fl_mem_size(); } bool contains_reference(OopOrNarrowOopStar from) const { @@ -328,21 +335,21 @@ public: void strong_code_roots_do(CodeBlobClosure* blk) const; // Returns the number of elements in the strong code roots list - int strong_code_roots_list_length() { - return _strong_code_roots_list->length(); + size_t strong_code_roots_list_length() { + return _code_roots.length(); } // Returns true if the strong code roots contains the given // nmethod. bool strong_code_roots_list_contains(nmethod* nm) { - return _strong_code_roots_list->contains(nm); + return _code_roots.contains(nm); } // Returns the amount of memory, in bytes, currently // consumed by the strong code roots. size_t strong_code_roots_mem_size(); - void print() const; + void print() PRODUCT_RETURN; // Called during a stop-world phase to perform any deferred cleanups. static void cleanup(); @@ -350,6 +357,7 @@ public: // Declare the heap size (in # of regions) to the HeapRegionRemSet(s). // (Uses it to initialize from_card_cache). static void init_heap(uint max_regions) { + G1CodeRootSet::initialize(); OtherRegionsTable::init_from_card_cache((size_t) max_regions); } @@ -384,7 +392,7 @@ public: class HeapRegionRemSetIterator : public StackObj { // The region RSet over which we're iterating. - const HeapRegionRemSet* _hrrs; + HeapRegionRemSet* _hrrs; // Local caching of HRRS fields. const BitMap* _coarse_map; @@ -441,7 +449,7 @@ class HeapRegionRemSetIterator : public StackObj { public: // We require an iterator to be initialized before use, so the // constructor does little. - HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs); + HeapRegionRemSetIterator(HeapRegionRemSet* hrrs); // If there remains one or more cards to be yielded, returns true and // sets "card_index" to one of those cards (which is then considered diff --git a/hotspot/src/share/vm/memory/freeList.cpp b/hotspot/src/share/vm/memory/freeList.cpp index 1d521885925..f1d4859a040 100644 --- a/hotspot/src/share/vm/memory/freeList.cpp +++ b/hotspot/src/share/vm/memory/freeList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -34,6 +34,7 @@ #if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#include "gc_implementation/g1/g1CodeCacheRemSet.hpp" #endif // INCLUDE_ALL_GCS // Free list. A FreeList is used to access a linked list of chunks @@ -332,4 +333,5 @@ template class FreeList; template class FreeList; #if INCLUDE_ALL_GCS template class FreeList; +template class FreeList; #endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index b778f606998..3f06633e612 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3882,6 +3882,7 @@ void TestKlass_test(); void TestOldFreeSpaceCalculation_test(); void TestG1BiasedArray_test(); void TestBufferingOopClosure_test(); +void TestCodeCacheRemSet_test(); #endif void execute_internal_vm_tests() { @@ -3910,6 +3911,7 @@ void execute_internal_vm_tests() { run_unit_test(TestG1BiasedArray_test()); run_unit_test(HeapRegionRemSet::test_prt()); run_unit_test(TestBufferingOopClosure_test()); + run_unit_test(TestCodeCacheRemSet_test()); #endif tty->print_cr("All internal VM tests passed"); } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java new file mode 100644 index 00000000000..535399795f9 --- /dev/null +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014, 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 TestPrintGCDetails + * @bug 8035406 + * @summary Ensure that the PrintGCDetails output for a minor GC with G1 + * includes the expected necessary messages. + * @key gc + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestGCLogMessages { + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-XX:+PrintGCDetails", + GCTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldContain("[Code Root Purge"); + output.shouldHaveExitValue(0); + } + + static class GCTest { + private static byte[] garbage; + public static void main(String [] args) { + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } + } +} From cde8aa670b01d790a04d7954183aacbd3b3c2ac8 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:12:47 +0100 Subject: [PATCH 010/170] 8035815: Cache-align and pad the from card cache The from card cache is a very frequently accessed data structure. It is essentially a 2d array of per-region values, one row of values for every GC thread. Pad and align the data structure to avoid false sharing. Reviewed-by: stefank --- .../gc_implementation/g1/heapRegionRemSet.cpp | 43 ++++++++++--------- .../gc_implementation/g1/heapRegionRemSet.hpp | 12 +++--- hotspot/src/share/vm/memory/padded.hpp | 13 +++++- hotspot/src/share/vm/memory/padded.inline.hpp | 31 ++++++++++++- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 51a699a9663..ef2ed91ff57 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -29,6 +29,7 @@ #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "memory/allocation.hpp" +#include "memory/padded.inline.hpp" #include "memory/space.inline.hpp" #include "oops/oop.inline.hpp" #include "utilities/bitMap.inline.hpp" @@ -358,27 +359,29 @@ void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) { } int** OtherRegionsTable::_from_card_cache = NULL; -size_t OtherRegionsTable::_from_card_cache_max_regions = 0; +uint OtherRegionsTable::_from_card_cache_max_regions = 0; size_t OtherRegionsTable::_from_card_cache_mem_size = 0; -void OtherRegionsTable::init_from_card_cache(size_t max_regions) { - _from_card_cache_max_regions = max_regions; +void OtherRegionsTable::init_from_card_cache(uint max_regions) { + guarantee(_from_card_cache == NULL, "Should not call this multiple times"); + uint n_par_rs = HeapRegionRemSet::num_par_rem_sets(); - int n_par_rs = HeapRegionRemSet::num_par_rem_sets(); - _from_card_cache = NEW_C_HEAP_ARRAY(int*, n_par_rs, mtGC); - for (int i = 0; i < n_par_rs; i++) { - _from_card_cache[i] = NEW_C_HEAP_ARRAY(int, max_regions, mtGC); - for (size_t j = 0; j < max_regions; j++) { + _from_card_cache_max_regions = max_regions; + _from_card_cache = Padded2DArray::create_unfreeable(n_par_rs, + _from_card_cache_max_regions, + &_from_card_cache_mem_size); + + for (uint i = 0; i < n_par_rs; i++) { + for (uint j = 0; j < _from_card_cache_max_regions; j++) { _from_card_cache[i][j] = -1; // An invalid value. } } - _from_card_cache_mem_size = n_par_rs * max_regions * sizeof(int); } -void OtherRegionsTable::shrink_from_card_cache(size_t new_n_regs) { - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { +void OtherRegionsTable::shrink_from_card_cache(uint new_n_regs) { + for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { assert(new_n_regs <= _from_card_cache_max_regions, "Must be within max."); - for (size_t j = new_n_regs; j < _from_card_cache_max_regions; j++) { + for (uint j = new_n_regs; j < _from_card_cache_max_regions; j++) { _from_card_cache[i][j] = -1; // An invalid value. } } @@ -386,8 +389,8 @@ void OtherRegionsTable::shrink_from_card_cache(size_t new_n_regs) { #ifndef PRODUCT void OtherRegionsTable::print_from_card_cache() { - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - for (size_t j = 0; j < _from_card_cache_max_regions; j++) { + for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { + for (uint j = 0; j < _from_card_cache_max_regions; j++) { gclog_or_tty->print_cr("_from_card_cache[%d][%d] = %d.", i, j, _from_card_cache[i][j]); } @@ -727,8 +730,8 @@ size_t OtherRegionsTable::fl_mem_size() { } void OtherRegionsTable::clear_fcc() { - size_t hrs_idx = hr()->hrs_index(); - for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { + uint hrs_idx = hr()->hrs_index(); + for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { _from_card_cache[i][hrs_idx] = -1; } } @@ -762,8 +765,8 @@ void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { _coarse_map.par_at_put(hrs_ind, 0); } // Check to see if any of the fcc entries come from here. - size_t hr_ind = (size_t) hr()->hrs_index(); - for (int tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) { + uint hr_ind = hr()->hrs_index(); + for (uint tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) { int fcc_ent = _from_card_cache[tid][hr_ind]; if (fcc_ent != -1) { HeapWord* card_addr = (HeapWord*) @@ -838,8 +841,8 @@ OtherRegionsTable::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) { // Determines how many threads can add records to an rset in parallel. // This can be done by either mutator threads together with the // concurrent refinement threads or GC threads. -int HeapRegionRemSet::num_par_rem_sets() { - return (int)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); +uint HeapRegionRemSet::num_par_rem_sets() { + return (uint)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); } HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index f0b315d494d..e8385508970 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -121,7 +121,7 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC { // Indexed by thread X heap region, to minimize thread contention. static int** _from_card_cache; - static size_t _from_card_cache_max_regions; + static uint _from_card_cache_max_regions; static size_t _from_card_cache_mem_size; // link/add the given fine grain remembered set into the "all" list @@ -170,11 +170,11 @@ public: // Declare the heap size (in # of regions) to the OtherRegionsTable. // (Uses it to initialize from_card_cache). - static void init_from_card_cache(size_t max_regions); + static void init_from_card_cache(uint max_regions); // Declares that only regions i s.t. 0 <= i < new_n_regs are in use. // Make sure any entries for higher regions are invalid. - static void shrink_from_card_cache(size_t new_n_regs); + static void shrink_from_card_cache(uint new_n_regs); static void print_from_card_cache(); }; @@ -222,7 +222,7 @@ private: public: HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr); - static int num_par_rem_sets(); + static uint num_par_rem_sets(); static void setup_remset_size(); HeapRegion* hr() const { @@ -358,12 +358,12 @@ public: // (Uses it to initialize from_card_cache). static void init_heap(uint max_regions) { G1CodeRootSet::initialize(); - OtherRegionsTable::init_from_card_cache((size_t) max_regions); + OtherRegionsTable::init_from_card_cache(max_regions); } // Declares that only regions i s.t. 0 <= i < new_n_regs are in use. static void shrink_heap(uint new_n_regs) { - OtherRegionsTable::shrink_from_card_cache((size_t) new_n_regs); + OtherRegionsTable::shrink_from_card_cache(new_n_regs); } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/memory/padded.hpp b/hotspot/src/share/vm/memory/padded.hpp index 4c50b39963e..a03c2ba56c7 100644 --- a/hotspot/src/share/vm/memory/padded.hpp +++ b/hotspot/src/share/vm/memory/padded.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -90,4 +90,15 @@ class PaddedArray { static PaddedEnd* create_unfreeable(uint length); }; +// Helper class to create an array of references to arrays of primitive types +// Both the array of references and the data arrays are aligned to the given +// alignment. The allocated memory is zero-filled. +template +class Padded2DArray { + public: + // Creates an aligned padded 2D array. + // The memory cannot be deleted since the raw memory chunk is not returned. + static T** create_unfreeable(uint rows, uint columns, size_t* allocation_size = NULL); +}; + #endif // SHARE_VM_MEMORY_PADDED_HPP diff --git a/hotspot/src/share/vm/memory/padded.inline.hpp b/hotspot/src/share/vm/memory/padded.inline.hpp index 1e9994ab647..e773c4075f8 100644 --- a/hotspot/src/share/vm/memory/padded.inline.hpp +++ b/hotspot/src/share/vm/memory/padded.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -47,3 +47,32 @@ PaddedEnd* PaddedArray::create_unfreeable(uint length) { return aligned_padded_array; } + +template +T** Padded2DArray::create_unfreeable(uint rows, uint columns, size_t* allocation_size) { + // Calculate and align the size of the first dimension's table. + size_t table_size = align_size_up_(rows * sizeof(T*), alignment); + // The size of the separate rows. + size_t row_size = align_size_up_(columns * sizeof(T), alignment); + // Total size consists of the indirection table plus the rows. + size_t total_size = table_size + rows * row_size + alignment; + + // Allocate a chunk of memory large enough to allow alignment of the chunk. + void* chunk = AllocateHeap(total_size, flags); + // Clear the allocated memory. + memset(chunk, 0, total_size); + // Align the chunk of memory. + T** result = (T**)align_pointer_up(chunk, alignment); + void* data_start = (void*)((uintptr_t)result + table_size); + + // Fill in the row table. + for (size_t i = 0; i < rows; i++) { + result[i] = (T*)((uintptr_t)data_start + i * row_size); + } + + if (allocation_size != NULL) { + *allocation_size = total_size; + } + + return result; +} From d3e28ca6824ce38fd233b7eb53cb858bd1acff12 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:13:18 +0100 Subject: [PATCH 011/170] 8027295: Free CSet takes ~50% of young pause time Improve fast card cache iteration and avoid taking locks when freeing the collection set. Reviewed-by: brutisso --- .../gc_implementation/g1/g1CollectedHeap.cpp | 9 ++--- .../gc_implementation/g1/g1CollectedHeap.hpp | 5 ++- .../gc_implementation/g1/g1GCPhaseTimes.cpp | 4 +++ .../vm/gc_implementation/g1/heapRegion.cpp | 10 ++++-- .../vm/gc_implementation/g1/heapRegion.hpp | 2 +- .../gc_implementation/g1/heapRegionRemSet.cpp | 3 +- hotspot/test/gc/g1/TestGCLogMessages.java | 34 +++++++++++++++++-- 7 files changed, 54 insertions(+), 13 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 1bf8decf931..a0d6d283a0a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -5939,7 +5939,8 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { void G1CollectedHeap::free_region(HeapRegion* hr, FreeRegionList* free_list, - bool par) { + bool par, + bool locked) { assert(!hr->isHumongous(), "this is only for non-humongous regions"); assert(!hr->is_empty(), "the region should not be empty"); assert(free_list != NULL, "pre-condition"); @@ -5950,7 +5951,7 @@ void G1CollectedHeap::free_region(HeapRegion* hr, if (!hr->is_young()) { _cg1r->hot_card_cache()->reset_card_counts(hr); } - hr->hr_clear(par, true /* clear_space */); + hr->hr_clear(par, true /* clear_space */, locked /* locked */); free_list->add_as_head(hr); } @@ -6159,7 +6160,7 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e } } - rs_lengths += cur->rem_set()->occupied(); + rs_lengths += cur->rem_set()->occupied_locked(); HeapRegion* next = cur->next_in_collection_set(); assert(cur->in_collection_set(), "bad CS"); @@ -6193,7 +6194,7 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e // And the region is empty. assert(!used_mr.is_empty(), "Should not have empty regions in a CS."); pre_used += cur->used(); - free_region(cur, &local_free_list, false /* par */); + free_region(cur, &local_free_list, false /* par */, true /* locked */); } else { cur->uninstall_surv_rate_group(); if (cur->is_young()) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 2338e8dc89c..e69ccc6aaa2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -763,9 +763,12 @@ public: // list later). The used bytes of freed regions are accumulated in // pre_used. If par is true, the region's RSet will not be freed // up. The assumption is that this will be done later. + // The locked parameter indicates if the caller has already taken + // care of proper synchronization. This may allow some optimizations. void free_region(HeapRegion* hr, FreeRegionList* free_list, - bool par); + bool par, + bool locked = false); // Frees a humongous region by collapsing it into individual regions // and calling free_region() for each of them. The freed regions diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 45a4e526eca..d38854db335 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -317,6 +317,10 @@ void G1GCPhaseTimes::print(double pause_time_sec) { print_stats(2, "Free CSet", (_recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms)); + if (G1Log::finest()) { + print_stats(3, "Young Free CSet", _recorded_young_free_cset_time_ms); + print_stats(3, "Non-Young Free CSet", _recorded_non_young_free_cset_time_ms); + } if (_cur_verify_after_time_ms > 0.0) { print_stats(2, "Verify After", _cur_verify_after_time_ms); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index f70fe6c6d1b..86546a90140 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -205,7 +205,7 @@ void HeapRegion::reset_after_compaction() { init_top_at_mark_start(); } -void HeapRegion::hr_clear(bool par, bool clear_space) { +void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) { assert(_humongous_type == NotHumongous, "we should have already filtered out humongous regions"); assert(_humongous_start_region == NULL, @@ -223,7 +223,11 @@ void HeapRegion::hr_clear(bool par, bool clear_space) { if (!par) { // If this is parallel, this will be done later. HeapRegionRemSet* hrrs = rem_set(); - hrrs->clear(); + if (locked) { + hrrs->clear_locked(); + } else { + hrrs->clear(); + } _claimed = InitialClaimValue; } zero_marked_bytes(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index ad2b0649795..28c92b854cc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -596,7 +596,7 @@ class HeapRegion: public G1OffsetTableContigSpace { void save_marks(); // Reset HR stuff to default values. - void hr_clear(bool par, bool clear_space); + void hr_clear(bool par, bool clear_space, bool locked = false); void par_clear(); // Get the start of the unmarked area in this region. diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index ef2ed91ff57..7f81c890eaa 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -731,7 +731,8 @@ size_t OtherRegionsTable::fl_mem_size() { void OtherRegionsTable::clear_fcc() { uint hrs_idx = hr()->hrs_index(); - for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { + uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets(); + for (uint i = 0; i < num_par_remsets; i++) { _from_card_cache[i][hrs_idx] = -1; } } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 535399795f9..2e7bfaba062 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -23,7 +23,7 @@ /* * @test TestPrintGCDetails - * @bug 8035406 + * @bug 8035406 8027295 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -38,13 +38,41 @@ public class TestGCLogMessages { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-Xmx10M", - "-XX:+PrintGCDetails", GCTest.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("[Code Root Purge"); + output.shouldNotContain("[Code Root Purge"); + output.shouldNotContain("[Young Free CSet"); + output.shouldNotContain("[Non-Young Free CSet"); output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-XX:+PrintGCDetails", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + + output.shouldContain("[Code Root Purge"); + output.shouldNotContain("[Young Free CSet"); + output.shouldNotContain("[Non-Young Free CSet"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + + output.shouldContain("[Code Root Purge"); + output.shouldContain("[Young Free CSet"); + output.shouldContain("[Non-Young Free CSet"); + output.shouldHaveExitValue(0); + } static class GCTest { From 80188ce0b27e9ca2c40d0f16fe7a9d2a5de55fc9 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:13:27 +0100 Subject: [PATCH 012/170] 8035398: Add card redirty time in "Other" time in G1 Show the time taken by card redirtying during GC in a new "Redirty Cards" line. Reviewed-by: jwilhelm, brutisso --- .../gc_implementation/g1/g1CollectedHeap.cpp | 39 ++++++++++++------- .../gc_implementation/g1/g1CollectedHeap.hpp | 2 + .../gc_implementation/g1/g1GCPhaseTimes.cpp | 3 ++ .../gc_implementation/g1/g1GCPhaseTimes.hpp | 6 +++ hotspot/test/gc/g1/TestGCLogMessages.java | 5 ++- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index a0d6d283a0a..b67ceaf1a19 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -169,14 +169,6 @@ public: int calls() { return _calls; } }; -class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { -public: - bool do_card_ptr(jbyte* card_ptr, int worker_i) { - *card_ptr = CardTableModRefBS::dirty_card_val(); - return true; - } -}; - YoungList::YoungList(G1CollectedHeap* g1h) : _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { @@ -5270,6 +5262,29 @@ void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive } } +class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { +public: + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + return true; + } +}; + +void G1CollectedHeap::redirty_logged_cards() { + guarantee(G1DeferredRSUpdate, "Must only be called when using deferred RS updates."); + double redirty_logged_cards_start = os::elapsedTime(); + + RedirtyLoggedCardTableEntryFastClosure redirty; + dirty_card_queue_set().set_closure(&redirty); + dirty_card_queue_set().apply_closure_to_all_completed_buffers(); + + DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); + dcq.merge_bufferlists(&dirty_card_queue_set()); + assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); + + g1_policy()->phase_times()->record_redirty_logged_cards_time_ms((os::elapsedTime() - redirty_logged_cards_start) * 1000.0); +} + // Weak Reference Processing support // An always "is_alive" closure that is used to preserve referents. @@ -5926,13 +5941,7 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { enqueue_discovered_references(n_workers); if (G1DeferredRSUpdate) { - RedirtyLoggedCardTableEntryFastClosure redirty; - dirty_card_queue_set().set_closure(&redirty); - dirty_card_queue_set().apply_closure_to_all_completed_buffers(); - - DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); - dcq.merge_bufferlists(&dirty_card_queue_set()); - assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); + redirty_logged_cards(); } COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index e69ccc6aaa2..0b46cb3499b 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1651,6 +1651,8 @@ public: // in symbol table, possibly in parallel. void unlink_string_and_symbol_table(BoolObjectClosure* is_alive, bool unlink_strings = true, bool unlink_symbols = true); + // Redirty logged cards in the refinement queue. + void redirty_logged_cards(); // Verification // The following is just to alert the verification code diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index d38854db335..6b6a2cf7f9f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -314,6 +314,9 @@ void G1GCPhaseTimes::print(double pause_time_sec) { _recorded_non_young_cset_choice_time_ms)); print_stats(2, "Ref Proc", _cur_ref_proc_time_ms); print_stats(2, "Ref Enq", _cur_ref_enq_time_ms); + if (G1DeferredRSUpdate) { + print_stats(2, "Redirty Cards", _recorded_redirty_logged_cards_time_ms); + } print_stats(2, "Free CSet", (_recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms)); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index 46ac0da8a1b..7868a89727e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -143,6 +143,8 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_young_cset_choice_time_ms; double _recorded_non_young_cset_choice_time_ms; + double _recorded_redirty_logged_cards_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -256,6 +258,10 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_non_young_cset_choice_time_ms = time_ms; } + void record_redirty_logged_cards_time_ms(double time_ms) { + _recorded_redirty_logged_cards_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 2e7bfaba062..bf45db41297 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -23,7 +23,7 @@ /* * @test TestPrintGCDetails - * @bug 8035406 8027295 + * @bug 8035406 8027295 8035398 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -42,6 +42,7 @@ public class TestGCLogMessages { OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("[Redirty Cards"); output.shouldNotContain("[Code Root Purge"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); @@ -54,6 +55,7 @@ public class TestGCLogMessages { output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Redirty Cards"); output.shouldContain("[Code Root Purge"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); @@ -68,6 +70,7 @@ public class TestGCLogMessages { output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Redirty Cards"); output.shouldContain("[Code Root Purge"); output.shouldContain("[Young Free CSet"); output.shouldContain("[Non-Young Free CSet"); From 2a8616c9d679bcb258d2a7cadad4fdc0bdb50b5c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:13:42 +0100 Subject: [PATCH 013/170] 8035654: Add times for evacuation failure handling in "Other" time Detailed breakdown of time spent in the evacuation failure handling phases to make the "Other" time roughly correspond to the sum of its parts. Reviewed-by: jwilhelm, jmasa --- .../gc_implementation/g1/g1CollectedHeap.cpp | 8 +++ .../gc_implementation/g1/g1GCPhaseTimes.cpp | 10 ++++ .../gc_implementation/g1/g1GCPhaseTimes.hpp | 16 ++++++ .../vm/gc_implementation/g1/g1RemSet.cpp | 5 +- hotspot/test/gc/g1/TestGCLogMessages.java | 55 +++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index b67ceaf1a19..63429dbc85f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2360,8 +2360,12 @@ public: }; size_t G1CollectedHeap::recalculate_used() const { + double recalculate_used_start = os::elapsedTime(); + SumUsedClosure blk; heap_region_iterate(&blk); + + g1_policy()->phase_times()->record_evac_fail_recalc_used_time((os::elapsedTime() - recalculate_used_start) * 1000.0); return blk.result(); } @@ -4376,6 +4380,8 @@ void G1CollectedHeap::finalize_for_evac_failure() { void G1CollectedHeap::remove_self_forwarding_pointers() { assert(check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); + double remove_self_forwards_start = os::elapsedTime(); + G1ParRemoveSelfForwardPtrsTask rsfp_task(this); if (G1CollectedHeap::use_parallel_gc_threads()) { @@ -4403,6 +4409,8 @@ void G1CollectedHeap::remove_self_forwarding_pointers() { } _objs_with_preserved_marks.clear(true); _preserved_marks_of_objs.clear(true); + + g1_policy()->phase_times()->record_evac_fail_remove_self_forwards((os::elapsedTime() - remove_self_forwards_start) * 1000.0); } void G1CollectedHeap::push_on_evac_failure_scan_stack(oop obj) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 6b6a2cf7f9f..0c784a7dddb 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -309,6 +309,16 @@ void G1GCPhaseTimes::print(double pause_time_sec) { if (_cur_verify_before_time_ms > 0.0) { print_stats(2, "Verify Before", _cur_verify_before_time_ms); } + if (G1CollectedHeap::heap()->evacuation_failed()) { + double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + + _cur_evac_fail_restore_remsets; + print_stats(2, "Evacuation Failure", evac_fail_handling); + if (G1Log::finest()) { + print_stats(3, "Recalculate Used", _cur_evac_fail_recalc_used); + print_stats(3, "Remove Self Forwards", _cur_evac_fail_remove_self_forwards); + print_stats(3, "Restore RemSet", _cur_evac_fail_restore_remsets); + } + } print_stats(2, "Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index 7868a89727e..e574777d3bc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -133,6 +133,10 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_strong_code_root_migration_time_ms; double _cur_strong_code_root_purge_time_ms; + double _cur_evac_fail_recalc_used; + double _cur_evac_fail_restore_remsets; + double _cur_evac_fail_remove_self_forwards; + double _cur_clear_ct_time_ms; double _cur_ref_proc_time_ms; double _cur_ref_enq_time_ms; @@ -230,6 +234,18 @@ class G1GCPhaseTimes : public CHeapObj { _cur_strong_code_root_purge_time_ms = ms; } + void record_evac_fail_recalc_used_time(double ms) { + _cur_evac_fail_recalc_used = ms; + } + + void record_evac_fail_restore_remsets(double ms) { + _cur_evac_fail_restore_remsets = ms; + } + + void record_evac_fail_remove_self_forwards(double ms) { + _cur_evac_fail_remove_self_forwards = ms; + } + void record_ref_proc_time(double ms) { _cur_ref_proc_time_ms = ms; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 48e70a1c984..0267e4ea61f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -462,8 +462,9 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); if (_g1->evacuation_failed()) { - // Restore remembered sets for the regions pointing into the collection set. + double restore_remembered_set_start = os::elapsedTime(); + // Restore remembered sets for the regions pointing into the collection set. if (G1DeferredRSUpdate) { // If deferred RS updates are enabled then we just need to transfer // the completed buffers from (a) the DirtyCardQueueSet used to hold @@ -482,6 +483,8 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { } assert(n_completed_buffers == into_cset_n_buffers, "missed some buffers"); } + + _g1->g1_policy()->phase_times()->record_evac_fail_restore_remsets((os::elapsedTime() - restore_remembered_set_start) * 1000.0); } // Free any completed buffers in the DirtyCardQueueSet used to hold cards diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index bf45db41297..4515066417d 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -35,6 +35,11 @@ import com.oracle.java.testlibrary.OutputAnalyzer; public class TestGCLogMessages { public static void main(String[] args) throws Exception { + testNormalLogs(); + testWithToSpaceExhaustionLogs(); + } + + private static void testNormalLogs() throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-Xmx10M", @@ -74,8 +79,43 @@ public class TestGCLogMessages { output.shouldContain("[Code Root Purge"); output.shouldContain("[Young Free CSet"); output.shouldContain("[Non-Young Free CSet"); + + // also check evacuation failure messages once + output.shouldNotContain("[Evacuation Failure"); + output.shouldNotContain("[Recalculate Used"); + output.shouldNotContain("[Remove Self Forwards"); + output.shouldNotContain("[Restore RemSet"); + output.shouldHaveExitValue(0); + } + + private static void testWithToSpaceExhaustionLogs() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-Xmn5M", + "-XX:+PrintGCDetails", + GCTestWithToSpaceExhaustion.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Evacuation Failure"); + output.shouldNotContain("[Recalculate Used"); + output.shouldNotContain("[Remove Self Forwards"); + output.shouldNotContain("[Restore RemSet"); output.shouldHaveExitValue(0); + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-Xmx10M", + "-Xmn5M", + "-XX:+PrintGCDetails", + "-XX:+UnlockExperimentalVMOptions", + "-XX:G1LogLevel=finest", + GCTestWithToSpaceExhaustion.class.getName()); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Evacuation Failure"); + output.shouldContain("[Recalculate Used"); + output.shouldContain("[Remove Self Forwards"); + output.shouldContain("[Restore RemSet"); + output.shouldHaveExitValue(0); } static class GCTest { @@ -89,4 +129,19 @@ public class TestGCLogMessages { System.out.println("Done"); } } + + static class GCTestWithToSpaceExhaustion { + private static byte[] garbage; + private static byte[] largeObject; + public static void main(String [] args) { + largeObject = new byte[5*1024*1024]; + System.out.println("Creating garbage"); + // create 128MB of garbage. This should result in at least one GC, + // some of them with to-space exhaustion. + for (int i = 0; i < 1024; i++) { + garbage = new byte[128 * 1024]; + } + System.out.println("Done"); + } + } } From 375e6df9eecc9c6d883fbcdff2c690c819b19d5a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:13:55 +0100 Subject: [PATCH 014/170] 8034868: Extract G1 From Card Cache into separate class Refactor the From Card Cache into a separate class. Reviewed-by: jmasa --- .../gc_implementation/g1/g1CollectedHeap.cpp | 2 +- .../gc_implementation/g1/heapRegionRemSet.cpp | 85 ++++++++++--------- .../gc_implementation/g1/heapRegionRemSet.hpp | 55 ++++++++++-- 3 files changed, 97 insertions(+), 45 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 63429dbc85f..c69c0aba70a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -1954,7 +1954,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : int n_queues = MAX2((int)ParallelGCThreads, 1); _task_queues = new RefToScanQueueSet(n_queues); - int n_rem_sets = HeapRegionRemSet::num_par_rem_sets(); + uint n_rem_sets = HeapRegionRemSet::num_par_rem_sets(); assert(n_rem_sets > 0, "Invariant."); _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 7f81c890eaa..56d151d0eff 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -358,48 +358,66 @@ void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) { "just checking"); } -int** OtherRegionsTable::_from_card_cache = NULL; -uint OtherRegionsTable::_from_card_cache_max_regions = 0; -size_t OtherRegionsTable::_from_card_cache_mem_size = 0; +int** FromCardCache::_cache = NULL; +uint FromCardCache::_max_regions = 0; +size_t FromCardCache::_static_mem_size = 0; -void OtherRegionsTable::init_from_card_cache(uint max_regions) { - guarantee(_from_card_cache == NULL, "Should not call this multiple times"); - uint n_par_rs = HeapRegionRemSet::num_par_rem_sets(); +void FromCardCache::initialize(uint n_par_rs, uint max_num_regions) { + guarantee(_cache == NULL, "Should not call this multiple times"); - _from_card_cache_max_regions = max_regions; - _from_card_cache = Padded2DArray::create_unfreeable(n_par_rs, - _from_card_cache_max_regions, - &_from_card_cache_mem_size); + _max_regions = max_num_regions; + _cache = Padded2DArray::create_unfreeable(n_par_rs, + _max_regions, + &_static_mem_size); for (uint i = 0; i < n_par_rs; i++) { - for (uint j = 0; j < _from_card_cache_max_regions; j++) { - _from_card_cache[i][j] = -1; // An invalid value. + for (uint j = 0; j < _max_regions; j++) { + set(i, j, InvalidCard); } } } -void OtherRegionsTable::shrink_from_card_cache(uint new_n_regs) { +void FromCardCache::shrink(uint new_num_regions) { for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - assert(new_n_regs <= _from_card_cache_max_regions, "Must be within max."); - for (uint j = new_n_regs; j < _from_card_cache_max_regions; j++) { - _from_card_cache[i][j] = -1; // An invalid value. + assert(new_num_regions <= _max_regions, "Must be within max."); + for (uint j = new_num_regions; j < _max_regions; j++) { + set(i, j, InvalidCard); } } } #ifndef PRODUCT -void OtherRegionsTable::print_from_card_cache() { +void FromCardCache::print(outputStream* out) { for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { - for (uint j = 0; j < _from_card_cache_max_regions; j++) { - gclog_or_tty->print_cr("_from_card_cache[%d][%d] = %d.", - i, j, _from_card_cache[i][j]); + for (uint j = 0; j < _max_regions; j++) { + out->print_cr("_from_card_cache["UINT32_FORMAT"]["UINT32_FORMAT"] = "INT32_FORMAT".", + i, j, at(i, j)); } } } #endif +void FromCardCache::clear(uint region_idx) { + uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets(); + for (uint i = 0; i < num_par_remsets; i++) { + set(i, region_idx, InvalidCard); + } +} + +void OtherRegionsTable::init_from_card_cache(uint max_regions) { + FromCardCache::initialize(HeapRegionRemSet::num_par_rem_sets(), max_regions); +} + +void OtherRegionsTable::shrink_from_card_cache(uint new_num_regions) { + FromCardCache::shrink(new_num_regions); +} + +void OtherRegionsTable::print_from_card_cache() { + FromCardCache::print(); +} + void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { - size_t cur_hrs_ind = (size_t) hr()->hrs_index(); + uint cur_hrs_ind = hr()->hrs_index(); if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").", @@ -412,19 +430,17 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) { int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift); if (G1TraceHeapRegionRememberedSet) { - gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)", + gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = "INT32_FORMAT")", hr()->bottom(), from_card, - _from_card_cache[tid][cur_hrs_ind]); + FromCardCache::at((uint)tid, cur_hrs_ind)); } - if (from_card == _from_card_cache[tid][cur_hrs_ind]) { + if (FromCardCache::contains_or_replace((uint)tid, cur_hrs_ind, from_card)) { if (G1TraceHeapRegionRememberedSet) { gclog_or_tty->print_cr(" from-card cache hit."); } assert(contains_reference(from), "We just added it!"); return; - } else { - _from_card_cache[tid][cur_hrs_ind] = from_card; } // Note that this may be a continued H region. @@ -722,7 +738,7 @@ size_t OtherRegionsTable::mem_size() const { } size_t OtherRegionsTable::static_mem_size() { - return _from_card_cache_mem_size; + return FromCardCache::static_mem_size(); } size_t OtherRegionsTable::fl_mem_size() { @@ -730,11 +746,7 @@ size_t OtherRegionsTable::fl_mem_size() { } void OtherRegionsTable::clear_fcc() { - uint hrs_idx = hr()->hrs_index(); - uint num_par_remsets = HeapRegionRemSet::num_par_rem_sets(); - for (uint i = 0; i < num_par_remsets; i++) { - _from_card_cache[i][hrs_idx] = -1; - } + FromCardCache::clear(hr()->hrs_index()); } void OtherRegionsTable::clear() { @@ -768,13 +780,13 @@ void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { // Check to see if any of the fcc entries come from here. uint hr_ind = hr()->hrs_index(); for (uint tid = 0; tid < HeapRegionRemSet::num_par_rem_sets(); tid++) { - int fcc_ent = _from_card_cache[tid][hr_ind]; - if (fcc_ent != -1) { + int fcc_ent = FromCardCache::at(tid, hr_ind); + if (fcc_ent != FromCardCache::InvalidCard) { HeapWord* card_addr = (HeapWord*) (uintptr_t(fcc_ent) << CardTableModRefBS::card_shift); if (hr()->is_in_reserved(card_addr)) { // Clear the from card cache. - _from_card_cache[tid][hr_ind] = -1; + FromCardCache::set(tid, hr_ind, FromCardCache::InvalidCard); } } } @@ -830,8 +842,6 @@ bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const "Must be in range."); return _sparse_table.contains_card(hr_ind, card_index); } - - } void @@ -932,7 +942,6 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, _other_regions.scrub(ctbs, region_bm, card_bm); } - // Code roots support void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index e8385508970..46b174548a9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -45,6 +45,54 @@ class nmethod; class HRRSCleanupTask : public SparsePRTCleanupTask { }; +// The FromCardCache remembers the most recently processed card on the heap on +// a per-region and per-thread basis. +class FromCardCache : public AllStatic { + private: + // Array of card indices. Indexed by thread X and heap region to minimize + // thread contention. + static int** _cache; + static uint _max_regions; + static size_t _static_mem_size; + + public: + enum { + InvalidCard = -1 // Card value of an invalid card, i.e. a card index not otherwise used. + }; + + static void clear(uint region_idx); + + // Returns true if the given card is in the cache at the given location, or + // replaces the card at that location and returns false. + static bool contains_or_replace(uint worker_id, uint region_idx, int card) { + int card_in_cache = at(worker_id, region_idx); + if (card_in_cache == card) { + return true; + } else { + set(worker_id, region_idx, card); + return false; + } + } + + static int at(uint worker_id, uint region_idx) { + return _cache[worker_id][region_idx]; + } + + static void set(uint worker_id, uint region_idx, int val) { + _cache[worker_id][region_idx] = val; + } + + static void initialize(uint n_par_rs, uint max_num_regions); + + static void shrink(uint new_num_regions); + + static void print(outputStream* out = gclog_or_tty) PRODUCT_RETURN; + + static size_t static_mem_size() { + return _static_mem_size; + } +}; + // The "_coarse_map" is a bitmap with one bit for each region, where set // bits indicate that the corresponding region may contain some pointer // into the owning region. @@ -119,11 +167,6 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC { // false. bool del_single_region_table(size_t ind, HeapRegion* hr); - // Indexed by thread X heap region, to minimize thread contention. - static int** _from_card_cache; - static uint _from_card_cache_max_regions; - static size_t _from_card_cache_mem_size; - // link/add the given fine grain remembered set into the "all" list void link_to_all(PerRegionTable * prt); // unlink/remove the given fine grain remembered set into the "all" list @@ -174,7 +217,7 @@ public: // Declares that only regions i s.t. 0 <= i < new_n_regs are in use. // Make sure any entries for higher regions are invalid. - static void shrink_from_card_cache(uint new_n_regs); + static void shrink_from_card_cache(uint new_num_regions); static void print_from_card_cache(); }; From 483ea400a5abaff0c9dc5ca339ffb114d64fcca6 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 10:07:51 +0100 Subject: [PATCH 015/170] 8035330: Remove G1ParScanPartialArrayClosure and G1ParScanHeapEvacClosure Mentioned closures are actually wrapped methods. This adds confusion to readers, and in this case also increases code size as G1ParScanHeapEvacClosure is part of the oop_oop_iterate() methods. Move them into G1ParScanThreadState as methods. Reviewed-by: stefank --- .../gc_implementation/g1/g1CollectedHeap.cpp | 68 ---------- .../gc_implementation/g1/g1CollectedHeap.hpp | 122 +++++++++++++++--- .../vm/gc_implementation/g1/g1OopClosures.hpp | 54 -------- .../g1/g1_specialized_oop_closures.hpp | 3 - 4 files changed, 107 insertions(+), 140 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index c69c0aba70a..7c856bc8fb7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -4632,9 +4632,7 @@ bool G1ParScanThreadState::verify_task(StarTask ref) const { #endif // ASSERT void G1ParScanThreadState::trim_queue() { - assert(_evac_cl != NULL, "not set"); assert(_evac_failure_cl != NULL, "not set"); - assert(_partial_scan_cl != NULL, "not set"); StarTask ref; do { @@ -4830,55 +4828,6 @@ void G1ParCopyClosure::do_oop_work(T* p) { template void G1ParCopyClosure::do_oop_work(oop* p); template void G1ParCopyClosure::do_oop_work(narrowOop* p); -template void G1ParScanPartialArrayClosure::do_oop_nv(T* p) { - assert(has_partial_array_mask(p), "invariant"); - oop from_obj = clear_partial_array_mask(p); - - assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); - assert(from_obj->is_objArray(), "must be obj array"); - objArrayOop from_obj_array = objArrayOop(from_obj); - // The from-space object contains the real length. - int length = from_obj_array->length(); - - assert(from_obj->is_forwarded(), "must be forwarded"); - oop to_obj = from_obj->forwardee(); - assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); - objArrayOop to_obj_array = objArrayOop(to_obj); - // We keep track of the next start index in the length field of the - // to-space object. - int next_index = to_obj_array->length(); - assert(0 <= next_index && next_index < length, - err_msg("invariant, next index: %d, length: %d", next_index, length)); - - int start = next_index; - int end = length; - int remainder = end - start; - // We'll try not to push a range that's smaller than ParGCArrayScanChunk. - if (remainder > 2 * ParGCArrayScanChunk) { - end = start + ParGCArrayScanChunk; - to_obj_array->set_length(end); - // Push the remainder before we process the range in case another - // worker has run out of things to do and can steal it. - oop* from_obj_p = set_partial_array_mask(from_obj); - _par_scan_state->push_on_queue(from_obj_p); - } else { - assert(length == end, "sanity"); - // We'll process the final range for this object. Restore the length - // so that the heap remains parsable in case of evacuation failure. - to_obj_array->set_length(end); - } - _scanner.set_region(_g1->heap_region_containing_raw(to_obj)); - // Process indexes [start,end). It will also process the header - // along with the first chunk (i.e., the chunk with start == 0). - // Note that at this point the length field of to_obj_array is not - // correct given that we are using it to keep track of the next - // start index. oop_iterate_range() (thankfully!) ignores the length - // field and only relies on the start / end parameters. It does - // however return the size of the object which will be incorrect. So - // we have to ignore it even if we wanted to use it. - to_obj_array->oop_iterate_range(&_scanner, start, end); -} - class G1ParEvacuateFollowersClosure : public VoidClosure { protected: G1CollectedHeap* _g1h; @@ -5020,13 +4969,9 @@ public: ReferenceProcessor* rp = _g1h->ref_processor_stw(); G1ParScanThreadState pss(_g1h, worker_id, rp); - G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, rp); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp); - G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, rp); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss, rp); G1ParScanMetadataClosure only_scan_metadata_cl(_g1h, &pss, rp); @@ -5474,14 +5419,9 @@ public: G1STWIsAliveClosure is_alive(_g1h); G1ParScanThreadState pss(_g1h, worker_id, NULL); - - G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); - G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, NULL); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL); G1ParScanMetadataClosure only_copy_metadata_cl(_g1h, &pss, NULL); @@ -5586,13 +5526,9 @@ public: HandleMark hm; G1ParScanThreadState pss(_g1h, worker_id, NULL); - G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); - G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, NULL); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); assert(pss.refs()->is_empty(), "both queue and overflow should be empty"); @@ -5716,13 +5652,9 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) { // We do not embed a reference processor in the copying/scanning // closures while we're actually processing the discovered // reference objects. - G1ParScanHeapEvacClosure scan_evac_cl(this, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(this, &pss, NULL); - G1ParScanPartialArrayClosure partial_scan_cl(this, &pss, NULL); - pss.set_evac_closure(&scan_evac_cl); pss.set_evac_failure_closure(&evac_failure_cl); - pss.set_partial_scan_closure(&partial_scan_cl); assert(pss.refs()->is_empty(), "pre-condition"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 0b46cb3499b..5a47b8bf91a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1779,8 +1779,6 @@ protected: size_t _undo_waste; OopsInHeapRegionClosure* _evac_failure_cl; - G1ParScanHeapEvacClosure* _evac_cl; - G1ParScanPartialArrayClosure* _partial_scan_cl; int _hash_seed; uint _queue_num; @@ -1908,14 +1906,6 @@ public: return _evac_failure_cl; } - void set_evac_closure(G1ParScanHeapEvacClosure* evac_cl) { - _evac_cl = evac_cl; - } - - void set_partial_scan_closure(G1ParScanPartialArrayClosure* partial_scan_cl) { - _partial_scan_cl = partial_scan_cl; - } - int* hash_seed() { return &_hash_seed; } uint queue_num() { return _queue_num; } @@ -1963,19 +1953,121 @@ public: false /* retain */); } } +private: + #define G1_PARTIAL_ARRAY_MASK 0x2 + + inline bool has_partial_array_mask(oop* ref) const { + return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; + } + + // We never encode partial array oops as narrowOop*, so return false immediately. + // This allows the compiler to create optimized code when popping references from + // the work queue. + inline bool has_partial_array_mask(narrowOop* ref) const { + assert(((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) != G1_PARTIAL_ARRAY_MASK, "Partial array oop reference encoded as narrowOop*"); + return false; + } + + // Only implement set_partial_array_mask() for regular oops, not for narrowOops. + // We always encode partial arrays as regular oop, to allow the + // specialization for has_partial_array_mask() for narrowOops above. + // This means that unintentional use of this method with narrowOops are caught + // by the compiler. + inline oop* set_partial_array_mask(oop obj) const { + assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); + return (oop*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); + } + + inline oop clear_partial_array_mask(oop* ref) const { + return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); + } + + void do_oop_partial_array(oop* p) { + assert(has_partial_array_mask(p), "invariant"); + oop from_obj = clear_partial_array_mask(p); + + assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); + assert(from_obj->is_objArray(), "must be obj array"); + objArrayOop from_obj_array = objArrayOop(from_obj); + // The from-space object contains the real length. + int length = from_obj_array->length(); + + assert(from_obj->is_forwarded(), "must be forwarded"); + oop to_obj = from_obj->forwardee(); + assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); + objArrayOop to_obj_array = objArrayOop(to_obj); + // We keep track of the next start index in the length field of the + // to-space object. + int next_index = to_obj_array->length(); + assert(0 <= next_index && next_index < length, + err_msg("invariant, next index: %d, length: %d", next_index, length)); + + int start = next_index; + int end = length; + int remainder = end - start; + // We'll try not to push a range that's smaller than ParGCArrayScanChunk. + if (remainder > 2 * ParGCArrayScanChunk) { + end = start + ParGCArrayScanChunk; + to_obj_array->set_length(end); + // Push the remainder before we process the range in case another + // worker has run out of things to do and can steal it. + oop* from_obj_p = set_partial_array_mask(from_obj); + push_on_queue(from_obj_p); + } else { + assert(length == end, "sanity"); + // We'll process the final range for this object. Restore the length + // so that the heap remains parsable in case of evacuation failure. + to_obj_array->set_length(end); + } + _scanner.set_region(_g1h->heap_region_containing_raw(to_obj)); + // Process indexes [start,end). It will also process the header + // along with the first chunk (i.e., the chunk with start == 0). + // Note that at this point the length field of to_obj_array is not + // correct given that we are using it to keep track of the next + // start index. oop_iterate_range() (thankfully!) ignores the length + // field and only relies on the start / end parameters. It does + // however return the size of the object which will be incorrect. So + // we have to ignore it even if we wanted to use it. + to_obj_array->oop_iterate_range(&_scanner, start, end); + } + + // This method is applied to the fields of the objects that have just been copied. + template void do_oop_evac(T* p, HeapRegion* from) { + assert(!oopDesc::is_null(oopDesc::load_decode_heap_oop(p)), + "Reference should not be NULL here as such are never pushed to the task queue."); + oop obj = oopDesc::load_decode_heap_oop_not_null(p); + + // Although we never intentionally push references outside of the collection + // set, due to (benign) races in the claim mechanism during RSet scanning more + // than one thread might claim the same card. So the same card may be + // processed multiple times. So redo this check. + if (_g1h->in_cset_fast_test(obj)) { + oop forwardee; + if (obj->is_forwarded()) { + forwardee = obj->forwardee(); + } else { + forwardee = copy_to_survivor_space(obj); + } + assert(forwardee != NULL, "forwardee should not be NULL"); + oopDesc::encode_store_heap_oop(p, forwardee); + } + + assert(obj != NULL, "Must be"); + update_rs(from, p, queue_num()); + } +public: oop copy_to_survivor_space(oop const obj); template void deal_with_reference(T* ref_to_scan) { - if (has_partial_array_mask(ref_to_scan)) { - _partial_scan_cl->do_oop_nv(ref_to_scan); - } else { + if (!has_partial_array_mask(ref_to_scan)) { // Note: we can use "raw" versions of "region_containing" because // "obj_to_scan" is definitely in the heap, and is not in a // humongous region. HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan); - _evac_cl->set_region(r); - _evac_cl->do_oop_nv(ref_to_scan); + do_oop_evac(ref_to_scan, r); + } else { + do_oop_partial_array((oop*)ref_to_scan); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp index 5eb5691c98b..fbcbd9b533e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1OopClosures.hpp @@ -80,53 +80,6 @@ public: virtual void do_oop(narrowOop* p) { do_oop_nv(p); } }; -#define G1_PARTIAL_ARRAY_MASK 0x2 - -inline bool has_partial_array_mask(oop* ref) { - return ((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) == G1_PARTIAL_ARRAY_MASK; -} - -// We never encode partial array oops as narrowOop*, so return false immediately. -// This allows the compiler to create optimized code when popping references from -// the work queue. -inline bool has_partial_array_mask(narrowOop* ref) { - assert(((uintptr_t)ref & G1_PARTIAL_ARRAY_MASK) != G1_PARTIAL_ARRAY_MASK, "Partial array oop reference encoded as narrowOop*"); - return false; -} - -// Only implement set_partial_array_mask() for regular oops, not for narrowOops. -// We always encode partial arrays as regular oop, to allow the -// specialization for has_partial_array_mask() for narrowOops above. -// This means that unintentional use of this method with narrowOops are caught -// by the compiler. -inline oop* set_partial_array_mask(oop obj) { - assert(((uintptr_t)(void *)obj & G1_PARTIAL_ARRAY_MASK) == 0, "Information loss!"); - return (oop*) ((uintptr_t)(void *)obj | G1_PARTIAL_ARRAY_MASK); -} - -template inline oop clear_partial_array_mask(T* ref) { - return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); -} - -class G1ParScanPartialArrayClosure : public G1ParClosureSuper { - G1ParScanClosure _scanner; - -public: - G1ParScanPartialArrayClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state, ReferenceProcessor* rp) : - G1ParClosureSuper(g1, par_scan_state), _scanner(g1, par_scan_state, rp) - { - assert(_ref_processor == NULL, "sanity"); - } - - G1ParScanClosure* scanner() { - return &_scanner; - } - - 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); } -}; - // Add back base class for metadata class G1ParCopyHelper : public G1ParClosureSuper { protected: @@ -173,15 +126,8 @@ typedef G1ParCopyClosure G1ParScanMetadataClosure; typedef G1ParCopyClosure G1ParScanAndMarkExtRootClosure; typedef G1ParCopyClosure G1ParScanAndMarkMetadataClosure; -// The following closure type is defined in g1_specialized_oop_closures.hpp: -// -// typedef G1ParCopyClosure G1ParScanHeapEvacClosure; - // We use a separate closure to handle references during evacuation // failure processing. -// We could have used another instance of G1ParScanHeapEvacClosure -// (since that closure no longer assumes that the references it -// handles point into the collection set). typedef G1ParCopyClosure G1ParScanHeapEvacFailureClosure; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp index e10a658a543..538ca4452b9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_specialized_oop_closures.hpp @@ -43,8 +43,6 @@ class G1ParCopyClosure; class G1ParScanClosure; class G1ParPushHeapRSClosure; -typedef G1ParCopyClosure G1ParScanHeapEvacClosure; - class FilterIntoCSClosure; class FilterOutOfRegionClosure; class G1CMOopClosure; @@ -61,7 +59,6 @@ class G1UpdateRSOrPushRefOopClosure; #endif #define FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES(f) \ - f(G1ParScanHeapEvacClosure,_nv) \ f(G1ParScanClosure,_nv) \ f(G1ParPushHeapRSClosure,_nv) \ f(FilterIntoCSClosure,_nv) \ From a07b2194f75b80594e10c52192ae61eae61df139 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 17 Mar 2014 13:07:55 +0100 Subject: [PATCH 016/170] 8036860: Pad and cache-align the BiasedMappedArray Pad and cache-align BiasedMappedArray instances by default to avoid performance variability problems due to false sharing, as instances of this data structures are typically used for performance sensitive code. Reviewed-by: brutisso, stefank --- .../share/vm/gc_implementation/g1/g1BiasedArray.cpp | 8 ++++++++ .../share/vm/gc_implementation/g1/g1BiasedArray.hpp | 8 ++------ hotspot/src/share/vm/memory/padded.hpp | 8 ++++++++ hotspot/src/share/vm/memory/padded.inline.hpp | 10 ++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp index 7f5023b422b..d5851a6d467 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.cpp @@ -24,6 +24,14 @@ #include "precompiled.hpp" #include "gc_implementation/g1/g1BiasedArray.hpp" +#include "memory/padded.inline.hpp" + +// Allocate a new array, generic version. +address G1BiasedMappedArrayBase::create_new_base_array(size_t length, size_t elem_size) { + assert(length > 0, "just checking"); + assert(elem_size > 0, "just checking"); + return PaddedPrimitiveArray::create_unfreeable(length * elem_size); +} #ifndef PRODUCT void G1BiasedMappedArrayBase::verify_index(idx_t index) const { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp index 6b19f708556..b0b7a76e1fe 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BiasedArray.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1BIASEDARRAY_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_G1BIASEDARRAY_HPP +#include "memory/allocation.hpp" #include "utilities/debug.hpp" -#include "memory/allocation.inline.hpp" // Implements the common base functionality for arrays that contain provisions // for accessing its elements using a biased index. @@ -48,11 +48,7 @@ protected: _bias(0), _shift_by(0) { } // Allocate a new array, generic version. - static address create_new_base_array(size_t length, size_t elem_size) { - assert(length > 0, "just checking"); - assert(elem_size > 0, "just checking"); - return NEW_C_HEAP_ARRAY(u_char, length * elem_size, mtGC); - } + static address create_new_base_array(size_t length, size_t elem_size); // Initialize the members of this class. The biased start address of this array // is the bias (in elements) multiplied by the element size. diff --git a/hotspot/src/share/vm/memory/padded.hpp b/hotspot/src/share/vm/memory/padded.hpp index a03c2ba56c7..9ddd14f8576 100644 --- a/hotspot/src/share/vm/memory/padded.hpp +++ b/hotspot/src/share/vm/memory/padded.hpp @@ -101,4 +101,12 @@ class Padded2DArray { static T** create_unfreeable(uint rows, uint columns, size_t* allocation_size = NULL); }; +// Helper class to create an array of T objects. The array as a whole will +// start at a multiple of alignment and its size will be aligned to alignment. +template +class PaddedPrimitiveArray { + public: + static T* create_unfreeable(size_t length); +}; + #endif // SHARE_VM_MEMORY_PADDED_HPP diff --git a/hotspot/src/share/vm/memory/padded.inline.hpp b/hotspot/src/share/vm/memory/padded.inline.hpp index e773c4075f8..1e4f8858460 100644 --- a/hotspot/src/share/vm/memory/padded.inline.hpp +++ b/hotspot/src/share/vm/memory/padded.inline.hpp @@ -76,3 +76,13 @@ T** Padded2DArray::create_unfreeable(uint rows, uint column return result; } + +template +T* PaddedPrimitiveArray::create_unfreeable(size_t length) { + // Allocate a chunk of memory large enough to allow for some alignment. + void* chunk = AllocateHeap(length * sizeof(T) + alignment, flags); + + memset(chunk, 0, length * sizeof(T) + alignment); + + return (T*)align_pointer_up(chunk, alignment); +} From 13792b1aa7bdaf221849ed85277388e2dd386bea Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Mon, 17 Mar 2014 13:42:16 +0100 Subject: [PATCH 017/170] 8037407: G1: Remove heapRegionSets.cpp Reviewed-by: tschatzl, pliden --- .../vm/gc_implementation/g1/heapRegionSet.cpp | 105 ++++++++++++++ .../gc_implementation/g1/heapRegionSets.cpp | 132 ------------------ 2 files changed, 105 insertions(+), 132 deletions(-) delete mode 100644 hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp index fba64b3cdef..873fdb6c3f2 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -272,3 +272,108 @@ void FreeRegionList::print_on(outputStream* out, bool print_contents) { } } } + +void FreeRegionList::verify_list() { + HeapRegion* curr = head(); + HeapRegion* prev1 = NULL; + HeapRegion* prev0 = NULL; + uint count = 0; + size_t capacity = 0; + while (curr != NULL) { + verify_region(curr); + + count++; + guarantee(count < _unrealistically_long_length, + hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length())); + + capacity += curr->capacity(); + + prev1 = prev0; + prev0 = curr; + curr = curr->next(); + } + + guarantee(tail() == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), tail()->hrs_index(), prev0->hrs_index())); + + guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); + guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + name(), total_capacity_bytes(), capacity)); +} + +// Note on the check_mt_safety() methods below: +// +// Verification of the "master" heap region sets / lists that are +// maintained by G1CollectedHeap is always done during a STW pause and +// by the VM thread at the start / end of the pause. The standard +// verification methods all assert check_mt_safety(). This is +// important as it ensures that verification is done without +// concurrent updates taking place at the same time. It follows, that, +// for the "master" heap region sets / lists, the check_mt_safety() +// method should include the VM thread / STW case. + +void MasterFreeRegionListMtSafeChecker::check() { + // Master Free List MT safety protocol: + // (a) If we're at a safepoint, operations on the master free list + // should be invoked by either the VM thread (which will serialize + // them) or by the GC workers while holding the + // FreeList_lock. + // (b) If we're not at a safepoint, operations on the master free + // list should be invoked while holding the Heap_lock. + + if (SafepointSynchronize::is_at_safepoint()) { + guarantee(Thread::current()->is_VM_thread() || + FreeList_lock->owned_by_self(), "master free list MT safety protocol at a safepoint"); + } else { + guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint"); + } +} + +void SecondaryFreeRegionListMtSafeChecker::check() { + // Secondary Free List MT safety protocol: + // Operations on the secondary free list should always be invoked + // while holding the SecondaryFreeList_lock. + + guarantee(SecondaryFreeList_lock->owned_by_self(), "secondary free list MT safety protocol"); +} + +void OldRegionSetMtSafeChecker::check() { + // Master Old Set MT safety protocol: + // (a) If we're at a safepoint, operations on the master old set + // should be invoked: + // - by the VM thread (which will serialize them), or + // - by the GC workers while holding the FreeList_lock, if we're + // at a safepoint for an evacuation pause (this lock is taken + // anyway when an GC alloc region is retired so that a new one + // is allocated from the free list), or + // - by the GC workers while holding the OldSets_lock, if we're at a + // safepoint for a cleanup pause. + // (b) If we're not at a safepoint, operations on the master old set + // should be invoked while holding the Heap_lock. + + if (SafepointSynchronize::is_at_safepoint()) { + guarantee(Thread::current()->is_VM_thread() + || FreeList_lock->owned_by_self() || OldSets_lock->owned_by_self(), + "master old set MT safety protocol at a safepoint"); + } else { + guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint"); + } +} + +void HumongousRegionSetMtSafeChecker::check() { + // Humongous Set MT safety protocol: + // (a) If we're at a safepoint, operations on the master humongous + // set should be invoked by either the VM thread (which will + // serialize them) or by the GC workers while holding the + // OldSets_lock. + // (b) If we're not at a safepoint, operations on the master + // humongous set should be invoked while holding the Heap_lock. + + if (SafepointSynchronize::is_at_safepoint()) { + guarantee(Thread::current()->is_VM_thread() || + OldSets_lock->owned_by_self(), + "master humongous set MT safety protocol at a safepoint"); + } else { + guarantee(Heap_lock->owned_by_self(), + "master humongous set MT safety protocol outside a safepoint"); + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp deleted file mode 100644 index 167a440445e..00000000000 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSets.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2011, 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_implementation/g1/heapRegionRemSet.hpp" -#include "gc_implementation/g1/heapRegionSet.hpp" - -// Note on the check_mt_safety() methods below: -// -// Verification of the "master" heap region sets / lists that are -// maintained by G1CollectedHeap is always done during a STW pause and -// by the VM thread at the start / end of the pause. The standard -// verification methods all assert check_mt_safety(). This is -// important as it ensures that verification is done without -// concurrent updates taking place at the same time. It follows, that, -// for the "master" heap region sets / lists, the check_mt_safety() -// method should include the VM thread / STW case. - -void FreeRegionList::verify_list() { - HeapRegion* curr = head(); - HeapRegion* prev1 = NULL; - HeapRegion* prev0 = NULL; - uint count = 0; - size_t capacity = 0; - while (curr != NULL) { - verify_region(curr); - - count++; - guarantee(count < _unrealistically_long_length, - hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length())); - - capacity += curr->capacity(); - - prev1 = prev0; - prev0 = curr; - curr = curr->next(); - } - - guarantee(tail() == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), tail()->hrs_index(), prev0->hrs_index())); - - guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); - guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - name(), total_capacity_bytes(), capacity)); -} - -void MasterFreeRegionListMtSafeChecker::check() { - // Master Free List MT safety protocol: - // (a) If we're at a safepoint, operations on the master free list - // should be invoked by either the VM thread (which will serialize - // them) or by the GC workers while holding the - // FreeList_lock. - // (b) If we're not at a safepoint, operations on the master free - // list should be invoked while holding the Heap_lock. - - if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() || - FreeList_lock->owned_by_self(), "master free list MT safety protocol at a safepoint"); - } else { - guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint"); - } -} - -void SecondaryFreeRegionListMtSafeChecker::check() { - // Secondary Free List MT safety protocol: - // Operations on the secondary free list should always be invoked - // while holding the SecondaryFreeList_lock. - - guarantee(SecondaryFreeList_lock->owned_by_self(), "secondary free list MT safety protocol"); -} - -void OldRegionSetMtSafeChecker::check() { - // Master Old Set MT safety protocol: - // (a) If we're at a safepoint, operations on the master old set - // should be invoked: - // - by the VM thread (which will serialize them), or - // - by the GC workers while holding the FreeList_lock, if we're - // at a safepoint for an evacuation pause (this lock is taken - // anyway when an GC alloc region is retired so that a new one - // is allocated from the free list), or - // - by the GC workers while holding the OldSets_lock, if we're at a - // safepoint for a cleanup pause. - // (b) If we're not at a safepoint, operations on the master old set - // should be invoked while holding the Heap_lock. - - if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() - || FreeList_lock->owned_by_self() || OldSets_lock->owned_by_self(), - "master old set MT safety protocol at a safepoint"); - } else { - guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint"); - } -} - -void HumongousRegionSetMtSafeChecker::check() { - // Humongous Set MT safety protocol: - // (a) If we're at a safepoint, operations on the master humongous - // set should be invoked by either the VM thread (which will - // serialize them) or by the GC workers while holding the - // OldSets_lock. - // (b) If we're not at a safepoint, operations on the master - // humongous set should be invoked while holding the Heap_lock. - - if (SafepointSynchronize::is_at_safepoint()) { - guarantee(Thread::current()->is_VM_thread() || - OldSets_lock->owned_by_self(), - "master humongous set MT safety protocol at a safepoint"); - } else { - guarantee(Heap_lock->owned_by_self(), - "master humongous set MT safety protocol outside a safepoint"); - } -} From d75f47a49d6f90991e001b8f41877438226f1e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Mon, 17 Mar 2014 15:18:38 +0100 Subject: [PATCH 018/170] 8036672: G1: alloc_purpose in copy_to_survivor_space() used incorrectly Reviewed-by: brutisso, tschatzl --- .../src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 7c856bc8fb7..38a6e62b44f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -4723,6 +4723,12 @@ oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { oop forward_ptr = old->forward_to_atomic(obj); if (forward_ptr == NULL) { Copy::aligned_disjoint_words((HeapWord*) old, obj_ptr, word_sz); + + // alloc_purpose is just a hint to allocate() above, recheck the type of region + // we actually allocated from and update alloc_purpose accordingly + HeapRegion* to_region = _g1h->heap_region_containing_raw(obj_ptr); + alloc_purpose = to_region->is_young() ? GCAllocForSurvived : GCAllocForTenured; + if (g1p->track_object_age(alloc_purpose)) { // We could simply do obj->incr_age(). However, this causes a // performance issue. obj->incr_age() will first check whether From 731ef44b87ee4c3870af09799d77932e19bc8f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Mon, 17 Mar 2014 15:18:45 +0100 Subject: [PATCH 019/170] 8036673: G1: Abort weak reference processing if mark stack overflows Reviewed-by: brutisso, tschatzl --- hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index cb1187fbd89..b74984554b1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -2529,6 +2529,11 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { assert(!rp->discovery_enabled(), "Post condition"); } + if (has_overflown()) { + // We can not trust g1_is_alive if the marking stack overflowed + return; + } + g1h->unlink_string_and_symbol_table(&g1_is_alive, /* process_strings */ false, // currently strings are always roots /* process_symbols */ true); From 1fb06836647ea62fce23b6fe83d208cf584d580a Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 17 Mar 2014 17:31:46 +0100 Subject: [PATCH 020/170] 8036696: Add metaspace gc threshold to metaspace summary trace event Reviewed-by: jmasa, stefank, mgerdin --- .../share/vm/gc_implementation/shared/gcHeapSummary.hpp | 8 +++++--- .../src/share/vm/gc_implementation/shared/gcTraceSend.cpp | 1 + hotspot/src/share/vm/gc_interface/collectedHeap.cpp | 2 +- hotspot/src/share/vm/trace/trace.xml | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp index 4e79b8f93d5..c5d59eb865e 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp @@ -125,15 +125,17 @@ class PSHeapSummary : public GCHeapSummary { }; class MetaspaceSummary : public StackObj { + size_t _capacity_until_GC; MetaspaceSizes _meta_space; MetaspaceSizes _data_space; MetaspaceSizes _class_space; public: - MetaspaceSummary() : _meta_space(), _data_space(), _class_space() {} - MetaspaceSummary(const MetaspaceSizes& meta_space, const MetaspaceSizes& data_space, const MetaspaceSizes& class_space) : - _meta_space(meta_space), _data_space(data_space), _class_space(class_space) { } + MetaspaceSummary() : _capacity_until_GC(0), _meta_space(), _data_space(), _class_space() {} + MetaspaceSummary(size_t capacity_until_GC, const MetaspaceSizes& meta_space, const MetaspaceSizes& data_space, const MetaspaceSizes& class_space) : + _capacity_until_GC(capacity_until_GC), _meta_space(meta_space), _data_space(data_space), _class_space(class_space) { } + size_t capacity_until_GC() const { return _capacity_until_GC; } const MetaspaceSizes& meta_space() const { return _meta_space; } const MetaspaceSizes& data_space() const { return _data_space; } const MetaspaceSizes& class_space() const { return _class_space; } diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp index ecf0731255b..8d1459d5ba1 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp @@ -246,6 +246,7 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceS if (e.should_commit()) { e.set_gcId(_shared_gc_info.id()); e.set_when((u1) when); + e.set_gcThreshold(meta_space_summary.capacity_until_GC()); e.set_metaspace(to_trace_struct(meta_space_summary.meta_space())); e.set_dataSpace(to_trace_struct(meta_space_summary.data_space())); e.set_classSpace(to_trace_struct(meta_space_summary.class_space())); diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index 4efb5651b03..a1b28991248 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -97,7 +97,7 @@ MetaspaceSummary CollectedHeap::create_metaspace_summary() { MetaspaceAux::allocated_used_bytes(Metaspace::ClassType), MetaspaceAux::reserved_bytes(Metaspace::ClassType)); - return MetaspaceSummary(meta_space, data_space, class_space); + return MetaspaceSummary(MetaspaceGC::capacity_until_GC(), meta_space, data_space, class_space); } void CollectedHeap::print_heap_before_gc() { diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 75efeea115e..737627a3862 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -193,6 +193,7 @@ Declares a structure type that can be used in other events. + From 51584519f434a576a2b4f160a0613d363ea7719e Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 17 Mar 2014 20:59:19 +0100 Subject: [PATCH 021/170] 8036698: Add trace event for updates to metaspace gc threshold Reviewed-by: stefank, mgerdin --- hotspot/src/share/vm/memory/metaspace.cpp | 41 ++++++++++----- hotspot/src/share/vm/memory/metaspace.hpp | 5 ++ .../vm/memory/metaspaceGCThresholdUpdater.hpp | 52 +++++++++++++++++++ .../src/share/vm/memory/metaspaceTracer.cpp | 40 ++++++++++++++ .../src/share/vm/memory/metaspaceTracer.hpp | 38 ++++++++++++++ hotspot/src/share/vm/trace/trace.xml | 6 +++ hotspot/src/share/vm/trace/tracetypes.xml | 9 ++++ 7 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp create mode 100644 hotspot/src/share/vm/memory/metaspaceTracer.cpp create mode 100644 hotspot/src/share/vm/memory/metaspaceTracer.hpp diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 9c3b48dc8f8..61fe1580acd 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -32,7 +32,9 @@ #include "memory/gcLocker.hpp" #include "memory/metachunk.hpp" #include "memory/metaspace.hpp" +#include "memory/metaspaceGCThresholdUpdater.hpp" #include "memory/metaspaceShared.hpp" +#include "memory/metaspaceTracer.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "runtime/atomic.inline.hpp" @@ -57,6 +59,7 @@ size_t const allocation_from_dictionary_limit = 4 * K; MetaWord* last_allocated = 0; size_t Metaspace::_compressed_class_space_size; +const MetaspaceTracer* Metaspace::_tracer = NULL; // Used in declarations in SpaceManager and ChunkManager enum ChunkIndex { @@ -1436,19 +1439,21 @@ void MetaspaceGC::compute_new_size() { expand_bytes = align_size_up(expand_bytes, Metaspace::commit_alignment()); // Don't expand unless it's significant if (expand_bytes >= MinMetaspaceExpansion) { - MetaspaceGC::inc_capacity_until_GC(expand_bytes); - } - if (PrintGCDetails && Verbose) { - size_t new_capacity_until_GC = capacity_until_GC; - gclog_or_tty->print_cr(" expanding:" - " minimum_desired_capacity: %6.1fKB" - " expand_bytes: %6.1fKB" - " MinMetaspaceExpansion: %6.1fKB" - " new metaspace HWM: %6.1fKB", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - MinMetaspaceExpansion / (double) K, - new_capacity_until_GC / (double) K); + size_t new_capacity_until_GC = MetaspaceGC::inc_capacity_until_GC(expand_bytes); + Metaspace::tracer()->report_gc_threshold(capacity_until_GC, + new_capacity_until_GC, + MetaspaceGCThresholdUpdater::ComputeNewSize); + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr(" expanding:" + " minimum_desired_capacity: %6.1fKB" + " expand_bytes: %6.1fKB" + " MinMetaspaceExpansion: %6.1fKB" + " new metaspace HWM: %6.1fKB", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + MinMetaspaceExpansion / (double) K, + new_capacity_until_GC / (double) K); + } } return; } @@ -1528,7 +1533,10 @@ void MetaspaceGC::compute_new_size() { // Don't shrink unless it's significant if (shrink_bytes >= MinMetaspaceExpansion && ((capacity_until_GC - shrink_bytes) >= MetaspaceSize)) { - MetaspaceGC::dec_capacity_until_GC(shrink_bytes); + size_t new_capacity_until_GC = MetaspaceGC::dec_capacity_until_GC(shrink_bytes); + Metaspace::tracer()->report_gc_threshold(capacity_until_GC, + new_capacity_until_GC, + MetaspaceGCThresholdUpdater::ComputeNewSize); } } @@ -3132,6 +3140,7 @@ void Metaspace::global_initialize() { } MetaspaceGC::initialize(); + _tracer = new MetaspaceTracer(); } Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, @@ -3220,8 +3229,12 @@ MetaWord* Metaspace::expand_and_allocate(size_t word_size, MetadataType mdtype) assert(delta_bytes > 0, "Must be"); size_t after_inc = MetaspaceGC::inc_capacity_until_GC(delta_bytes); + + // capacity_until_GC might be updated concurrently, must calculate previous value. size_t before_inc = after_inc - delta_bytes; + tracer()->report_gc_threshold(before_inc, after_inc, + MetaspaceGCThresholdUpdater::ExpandAndAllocate); if (PrintGCDetails && Verbose) { gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT " to " SIZE_FORMAT, before_inc, after_inc); diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index f74cec35546..fa4ee7c167a 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -60,6 +60,7 @@ class ChunkManager; class ClassLoaderData; class Metablock; class Metachunk; +class MetaspaceTracer; class MetaWord; class Mutex; class outputStream; @@ -149,6 +150,8 @@ class Metaspace : public CHeapObj { static ChunkManager* _chunk_manager_metadata; static ChunkManager* _chunk_manager_class; + static const MetaspaceTracer* _tracer; + public: static VirtualSpaceList* space_list() { return _space_list; } static VirtualSpaceList* class_space_list() { return _class_space_list; } @@ -164,6 +167,8 @@ class Metaspace : public CHeapObj { return mdtype == ClassType ? chunk_manager_class() : chunk_manager_metadata(); } + static const MetaspaceTracer* tracer() { return _tracer; } + private: // This is used by DumpSharedSpaces only, where only _vsm is used. So we will // maintain a single list for now. diff --git a/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp new file mode 100644 index 00000000000..cbb221dd33b --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 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_MEMORY_METASPACE_GC_THRESHOLD_UPDATER_HPP +#define SHARE_VM_MEMORY_METASPACE_GC_THRESHOLD_UPDATER_HPP + +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" + +class MetaspaceGCThresholdUpdater : public AllStatic { + public: + enum Type { + ComputeNewSize, + ExpandAndAllocate, + Last + }; + + static const char* to_string(MetaspaceGCThresholdUpdater::Type updater) { + switch (updater) { + case ComputeNewSize: + return "compute_new_size"; + case ExpandAndAllocate: + return "expand_and_allocate"; + default: + assert(false, err_msg("Got bad updater: %d", (int) updater)); + return NULL; + }; + } +}; + +#endif // SHARE_VM_MEMORY_METASPACE_GC_THRESHOLD_UPDATER_HPP diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.cpp b/hotspot/src/share/vm/memory/metaspaceTracer.cpp new file mode 100644 index 00000000000..6cb3f4d397f --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceTracer.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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 "memory/metaspaceTracer.hpp" +#include "trace/tracing.hpp" +#include "trace/traceBackend.hpp" + +void MetaspaceTracer::report_gc_threshold(size_t old_val, + size_t new_val, + MetaspaceGCThresholdUpdater::Type updater) const { + EventMetaspaceGCThreshold event; + if (event.should_commit()) { + event.set_oldValue(old_val); + event.set_newValue(new_val); + event.set_updater((u1)updater); + event.commit(); + } +} diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.hpp b/hotspot/src/share/vm/memory/metaspaceTracer.hpp new file mode 100644 index 00000000000..84d92a985ab --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceTracer.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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_MEMORY_METASPACE_TRACER_HPP +#define SHARE_VM_MEMORY_METASPACE_TRACER_HPP + +#include "memory/allocation.hpp" +#include "memory/metaspaceGCThresholdUpdater.hpp" + +class MetaspaceTracer : public CHeapObj { + public: + void report_gc_threshold(size_t old_val, + size_t new_val, + MetaspaceGCThresholdUpdater::Type updater) const; +}; + +#endif // SHARE_VM_MEMORY_METASPACE_TRACER_HPP diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 737627a3862..71d284ef7dd 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -199,6 +199,12 @@ Declares a structure type that can be used in other events. + + + + + + diff --git a/hotspot/src/share/vm/trace/tracetypes.xml b/hotspot/src/share/vm/trace/tracetypes.xml index 9305d2fa75e..b6195946953 100644 --- a/hotspot/src/share/vm/trace/tracetypes.xml +++ b/hotspot/src/share/vm/trace/tracetypes.xml @@ -130,6 +130,11 @@ Now we can use the content + data type in declaring event fields. + + + + @@ -324,6 +329,10 @@ Now we can use the content + data type in declaring event fields. + + + From 29387ae1a76b1ade4a3badb766fb711794022d01 Mon Sep 17 00:00:00 2001 From: Andrey Zakharov Date: Mon, 17 Mar 2014 16:29:13 +0100 Subject: [PATCH 022/170] 8037510: CMM Testing: Check Min/MaxHeapFreeRatio flags allows to shrink the heap when using ParallelGC Added tests for Min/MaxHeapFreeRatio flags Reviewed-by: jwilhelm, tschatzl --- hotspot/test/TEST.groups | 2 + .../gc/arguments/TestDynMaxHeapFreeRatio.java | 64 +++++++++ .../gc/arguments/TestDynMinHeapFreeRatio.java | 62 +++++++++ .../testlibrary/DynamicVMOptionChecker.java | 121 ++++++++++++++++++ .../java/testlibrary/TestDynamicVMOption.java | 104 +++++++++++++++ 5 files changed, 353 insertions(+) create mode 100644 hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.java create mode 100644 hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index 676d859686d..b0a4f605ad8 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -129,6 +129,8 @@ needs_compact3 = \ gc/g1/TestHumongousAllocInitialMark.java \ gc/arguments/TestG1HeapRegionSize.java \ gc/metaspace/TestMetaspaceMemoryPool.java \ + gc/arguments/TestDynMinHeapFreeRatio.java \ + gc/arguments/TestDynMaxHeapFreeRatio.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ serviceability/threads/TestFalseDeadLock.java \ compiler/tiered/NonTieredLevelsTest.java \ diff --git a/hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.java b/hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.java new file mode 100644 index 00000000000..6d36106c43b --- /dev/null +++ b/hotspot/test/gc/arguments/TestDynMaxHeapFreeRatio.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, 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 TestDynMaxHeapFreeRatio + * @bug 8028391 + * @summary Verify that MaxHeapFreeRatio flag is manageable + * @library /testlibrary + * @run main TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:-UseAdaptiveSizePolicy TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=51 -XX:MaxHeapFreeRatio=52 TestDynMaxHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=75 -XX:MaxHeapFreeRatio=100 TestDynMaxHeapFreeRatio + */ +import com.oracle.java.testlibrary.TestDynamicVMOption; +import com.oracle.java.testlibrary.DynamicVMOptionChecker; + +public class TestDynMaxHeapFreeRatio extends TestDynamicVMOption { + + public static final String MinFreeRatioFlagName = "MinHeapFreeRatio"; + public static final String MaxFreeRatioFlagName = "MaxHeapFreeRatio"; + + public TestDynMaxHeapFreeRatio() { + super(MaxFreeRatioFlagName); + } + + public void test() { + + int minHeapFreeValue = DynamicVMOptionChecker.getIntValue(MinFreeRatioFlagName); + System.out.println(MinFreeRatioFlagName + " = " + minHeapFreeValue); + + testPercentageValues(); + + checkInvalidValue(Integer.toString(minHeapFreeValue - 1)); + checkValidValue(Integer.toString(minHeapFreeValue)); + checkValidValue("100"); + } + + public static void main(String args[]) throws Exception { + new TestDynMaxHeapFreeRatio().test(); + } + +} diff --git a/hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java b/hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java new file mode 100644 index 00000000000..13132f04d38 --- /dev/null +++ b/hotspot/test/gc/arguments/TestDynMinHeapFreeRatio.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 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 TestDynMinHeapFreeRatio + * @bug 8028391 + * @summary Verify that MinHeapFreeRatio flag is manageable + * @library /testlibrary + * @run main TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:-UseAdaptiveSizePolicy TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=51 -XX:MaxHeapFreeRatio=52 TestDynMinHeapFreeRatio + * @run main/othervm -XX:MinHeapFreeRatio=75 -XX:MaxHeapFreeRatio=100 TestDynMinHeapFreeRatio + */ +import com.oracle.java.testlibrary.TestDynamicVMOption; +import com.oracle.java.testlibrary.DynamicVMOptionChecker; + +public class TestDynMinHeapFreeRatio extends TestDynamicVMOption { + + public static final String MinFreeRatioFlagName = "MinHeapFreeRatio"; + public static final String MaxFreeRatioFlagName = "MaxHeapFreeRatio"; + + public TestDynMinHeapFreeRatio() { + super(MinFreeRatioFlagName); + } + + public void test() { + int maxHeapFreeValue = DynamicVMOptionChecker.getIntValue(MaxFreeRatioFlagName); + System.out.println(MaxFreeRatioFlagName + " = " + maxHeapFreeValue); + + testPercentageValues(); + + checkInvalidValue(Integer.toString(maxHeapFreeValue + 1)); + checkValidValue(Integer.toString(maxHeapFreeValue)); + checkValidValue("0"); + } + + public static void main(String args[]) throws Exception { + new TestDynMinHeapFreeRatio().test(); + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java new file mode 100644 index 00000000000..baa717d46aa --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/DynamicVMOptionChecker.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014, 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 com.oracle.java.testlibrary; + +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; +import java.lang.management.ManagementFactory; + +/** + * Simple class to check writeability, invalid and valid values for VMOption + */ +public class DynamicVMOptionChecker { + + /** + * Reads VM option from PlatformMXBean and parse it to integer value + * + * @param name of option + * @return parsed value + */ + public static int getIntValue(String name) { + + VMOption option = ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + getVMOption(name); + + return Integer.parseInt(option.getValue()); + } + + /** + * Sets VM option value + * + * @param name of option + * @param value to set + */ + public static void setIntValue(String name, int value) { + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class).setVMOption(name, Integer.toString(value)); + } + + /** + * Checks that VM option is dynamically writable + * + * @param name + * @throws RuntimeException if option if not writable + * @return always true + */ + public static boolean checkIsWritable(String name) { + VMOption option = ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + getVMOption(name); + + if (!option.isWriteable()) { + throw new RuntimeException(name + " is not writable"); + } + + return true; + } + + /** + * Checks that value cannot be set + * + * @param name of flag + * @param value string representation of value to set + * @throws RuntimeException on error - when expected exception hasn't been thrown + */ + public static void checkInvalidValue(String name, String value) { + // should throw + try { + ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + setVMOption(name, value); + + } catch (IllegalArgumentException e) { + return; + } + + throw new RuntimeException("Expected IllegalArgumentException was not thrown, " + name + "= " + value); + } + + /** + * Checks that value can be set + * + * @param name of flag to set + * @param value string representation of value to set + * @throws RuntimeException on error - when value in VM is not equal to origin + */ + public static void checkValidValue(String name, String value) { + ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + setVMOption(name, value); + + VMOption option = ManagementFactory. + getPlatformMXBean(HotSpotDiagnosticMXBean.class). + getVMOption(name); + + if (!option.getValue().equals(value)) { + throw new RuntimeException("Actual value of " + name + " \"" + option.getValue() + + "\" not equal origin \"" + value + "\""); + } + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java new file mode 100644 index 00000000000..2c164596924 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/TestDynamicVMOption.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014, 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 com.oracle.java.testlibrary; + +/** + * Simple class to check writeability, invalid and valid values for concrete VMOption + */ +public class TestDynamicVMOption { + + private final String name; + private final int value; + + /** + * Constructor + * + * @param name of VM option to test + */ + public TestDynamicVMOption(String name) { + this.name = name; + this.value = DynamicVMOptionChecker.getIntValue(name); + System.out.println(this.name + " = " + this.value); + } + + /** + * Checks that this value can accept valid percentage values and cannot accept invalid percentage values + * + * @throws RuntimeException + */ + public void testPercentageValues() { + checkInvalidValue(Integer.toString(Integer.MIN_VALUE)); + checkInvalidValue(Integer.toString(Integer.MAX_VALUE)); + checkInvalidValue("-10"); + checkInvalidValue("190"); + } + + /** + * Reads VM option from PlatformMXBean and parse it to integer value + * + * @return value + */ + public int getIntValue() { + return DynamicVMOptionChecker.getIntValue(this.name); + } + + /** + * Sets VM option value + * + * @param value to set + */ + public void setIntValue(int value) { + DynamicVMOptionChecker.setIntValue(this.name, value); + } + + /** + * Checks that this VM option is dynamically writable + * + * @throws RuntimeException if option if not writable + * @return true + */ + public boolean checkIsWritable() throws RuntimeException { + return DynamicVMOptionChecker.checkIsWritable(this.name); + } + + /** + * Checks that value for this VM option cannot be set + * + * @param value to check + * @throws RuntimeException on error - when expected exception hasn't been thrown + */ + public void checkInvalidValue(String value) { + DynamicVMOptionChecker.checkInvalidValue(this.name, value); + } + + /** + * Checks that value for this VM option can be set + * + * @param value to check + * @throws RuntimeException on error - when value in VM is not equal to origin + */ + public void checkValidValue(String value) { + DynamicVMOptionChecker.checkValidValue(this.name, value); + } + +} From ddce6492be8ead9399b3753f16e0816a4d4d27d6 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Tue, 18 Mar 2014 06:15:45 +0100 Subject: [PATCH 023/170] 8037495: Remove platform specific specification of SurvivorRatio for BSD Reviewed-by: mgerdin, stefank --- hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp b/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp index 0da430230a8..4bc678e9d59 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp @@ -42,7 +42,6 @@ define_pd_global(intx, VMThreadStackSize, 512); #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); -define_pd_global(uintx, SurvivorRatio, 8); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); From b533eca89d2604e2e77913887d55360e3aad3b0f Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Tue, 18 Mar 2014 07:00:06 +0100 Subject: [PATCH 024/170] 8036699: Add trace event when a metaspace allocation fails Reviewed-by: jmasa, stefank --- hotspot/src/share/vm/memory/metaspace.cpp | 12 +++++++++ hotspot/src/share/vm/memory/metaspace.hpp | 2 ++ .../src/share/vm/memory/metaspaceTracer.cpp | 26 +++++++++++++++++++ .../src/share/vm/memory/metaspaceTracer.hpp | 7 +++++ hotspot/src/share/vm/trace/trace.xml | 8 ++++++ hotspot/src/share/vm/trace/tracetypes.xml | 18 +++++++++++++ 6 files changed, 73 insertions(+) diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 61fe1580acd..90de2f02527 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -3358,6 +3358,8 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype); if (result == NULL) { + tracer()->report_metaspace_allocation_failure(loader_data, word_size, type, mdtype); + // Allocation failed. if (is_init_completed()) { // Only start a GC if the bootstrapping has completed. @@ -3426,6 +3428,16 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s } } +const char* Metaspace::metadata_type_name(Metaspace::MetadataType mdtype) { + switch (mdtype) { + case Metaspace::ClassType: return "Class"; + case Metaspace::NonClassType: return "Metadata"; + default: + assert(false, err_msg("Got bad mdtype: %d", (int) mdtype)); + return NULL; + } +} + void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) { assert(DumpSharedSpaces, "sanity"); diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index fa4ee7c167a..671c6b6e8b1 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -241,6 +241,8 @@ class Metaspace : public CHeapObj { static void report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS); + static const char* metadata_type_name(Metaspace::MetadataType mdtype); + void print_on(outputStream* st) const; // Debugging support void verify(); diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.cpp b/hotspot/src/share/vm/memory/metaspaceTracer.cpp index 6cb3f4d397f..93bfda3a306 100644 --- a/hotspot/src/share/vm/memory/metaspaceTracer.cpp +++ b/hotspot/src/share/vm/memory/metaspaceTracer.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" #include "memory/metaspaceTracer.hpp" #include "trace/tracing.hpp" #include "trace/traceBackend.hpp" @@ -38,3 +39,28 @@ void MetaspaceTracer::report_gc_threshold(size_t old_val, event.commit(); } } + +void MetaspaceTracer::report_metaspace_allocation_failure(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const { + EventMetaspaceAllocationFailure event; + if (event.should_commit()) { + if (cld->is_anonymous()) { + event.set_classLoader(NULL); + event.set_anonymousClassLoader(true); + } else { + if (cld->is_the_null_class_loader_data()) { + event.set_classLoader((Klass*) NULL); + } else { + event.set_classLoader(cld->class_loader()->klass()); + } + event.set_anonymousClassLoader(false); + } + + event.set_size(word_size * BytesPerWord); + event.set_metadataType((u1) mdtype); + event.set_metaspaceObjectType((u1) objtype); + event.commit(); + } +} diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.hpp b/hotspot/src/share/vm/memory/metaspaceTracer.hpp index 84d92a985ab..4e5352b3c5e 100644 --- a/hotspot/src/share/vm/memory/metaspaceTracer.hpp +++ b/hotspot/src/share/vm/memory/metaspaceTracer.hpp @@ -26,13 +26,20 @@ #define SHARE_VM_MEMORY_METASPACE_TRACER_HPP #include "memory/allocation.hpp" +#include "memory/metaspace.hpp" #include "memory/metaspaceGCThresholdUpdater.hpp" +class ClassLoaderData; + class MetaspaceTracer : public CHeapObj { public: void report_gc_threshold(size_t old_val, size_t new_val, MetaspaceGCThresholdUpdater::Type updater) const; + void report_metaspace_allocation_failure(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const; }; #endif // SHARE_VM_MEMORY_METASPACE_TRACER_HPP diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 71d284ef7dd..9f3206e007a 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -205,6 +205,14 @@ Declares a structure type that can be used in other events. + + + + + + + + diff --git a/hotspot/src/share/vm/trace/tracetypes.xml b/hotspot/src/share/vm/trace/tracetypes.xml index b6195946953..eb1c708eadb 100644 --- a/hotspot/src/share/vm/trace/tracetypes.xml +++ b/hotspot/src/share/vm/trace/tracetypes.xml @@ -140,6 +140,16 @@ Now we can use the content + data type in declaring event fields. + + + + + + + + @@ -337,6 +347,14 @@ Now we can use the content + data type in declaring event fields. + + + + + + From 0a79ba66806166189a0e7dde2ad71c3daa3d12e8 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Tue, 18 Mar 2014 08:00:21 +0100 Subject: [PATCH 025/170] 8036701: Add trace event when a metaspace throws out of memory error Reviewed-by: stefank, mgerdin --- hotspot/src/share/vm/memory/metaspace.cpp | 6 ++++-- hotspot/src/share/vm/memory/metaspace.hpp | 2 +- hotspot/src/share/vm/memory/metaspaceTracer.cpp | 17 ++++++++++++++++- hotspot/src/share/vm/memory/metaspaceTracer.hpp | 10 ++++++++++ hotspot/src/share/vm/trace/trace.xml | 8 ++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 90de2f02527..b5e4b0d1513 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -3371,7 +3371,7 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, } if (result == NULL) { - report_metadata_oome(loader_data, word_size, mdtype, CHECK_NULL); + report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL); } // Zero initialize. @@ -3385,7 +3385,9 @@ size_t Metaspace::class_chunk_size(size_t word_size) { return class_vsm()->calc_chunk_size(word_size); } -void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetadataType mdtype, TRAPS) { +void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type, MetadataType mdtype, TRAPS) { + tracer()->report_metadata_oom(loader_data, word_size, type, mdtype); + // If result is still null, we are out of memory. if (Verbose && TraceMetadataChunkAllocation) { gclog_or_tty->print_cr("Metaspace allocation failed for size " diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index 671c6b6e8b1..ce570928939 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -239,7 +239,7 @@ class Metaspace : public CHeapObj { static void purge(); static void report_metadata_oome(ClassLoaderData* loader_data, size_t word_size, - MetadataType mdtype, TRAPS); + MetaspaceObj::Type type, MetadataType mdtype, TRAPS); static const char* metadata_type_name(Metaspace::MetadataType mdtype); diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.cpp b/hotspot/src/share/vm/memory/metaspaceTracer.cpp index 93bfda3a306..bd4960aab3e 100644 --- a/hotspot/src/share/vm/memory/metaspaceTracer.cpp +++ b/hotspot/src/share/vm/memory/metaspaceTracer.cpp @@ -44,7 +44,22 @@ void MetaspaceTracer::report_metaspace_allocation_failure(ClassLoaderData *cld, size_t word_size, MetaspaceObj::Type objtype, Metaspace::MetadataType mdtype) const { - EventMetaspaceAllocationFailure event; + send_allocation_failure_event(cld, word_size, objtype, mdtype); +} + +void MetaspaceTracer::report_metadata_oom(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const { + send_allocation_failure_event(cld, word_size, objtype, mdtype); +} + +template +void MetaspaceTracer::send_allocation_failure_event(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const { + E event; if (event.should_commit()) { if (cld->is_anonymous()) { event.set_classLoader(NULL); diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.hpp b/hotspot/src/share/vm/memory/metaspaceTracer.hpp index 4e5352b3c5e..4ae0138d581 100644 --- a/hotspot/src/share/vm/memory/metaspaceTracer.hpp +++ b/hotspot/src/share/vm/memory/metaspaceTracer.hpp @@ -32,6 +32,11 @@ class ClassLoaderData; class MetaspaceTracer : public CHeapObj { + template + void send_allocation_failure_event(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const; public: void report_gc_threshold(size_t old_val, size_t new_val, @@ -40,6 +45,11 @@ class MetaspaceTracer : public CHeapObj { size_t word_size, MetaspaceObj::Type objtype, Metaspace::MetadataType mdtype) const; + void report_metadata_oom(ClassLoaderData *cld, + size_t word_size, + MetaspaceObj::Type objtype, + Metaspace::MetadataType mdtype) const; + }; #endif // SHARE_VM_MEMORY_METASPACE_TRACER_HPP diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 9f3206e007a..21aa3a35679 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -213,6 +213,14 @@ Declares a structure type that can be used in other events. + + + + + + + + From 853fffb2cb1a0d5b772319eb318570f5ba0dc3fe Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Tue, 18 Mar 2014 09:03:28 +0100 Subject: [PATCH 026/170] 8036703: Add trace event with statistics for the metaspace chunk free lists Reviewed-by: stefank, mgerdin, coleenp, egahlin --- .../concurrentMarkSweepGeneration.cpp | 3 +- .../parallelScavenge/parallelScavengeHeap.cpp | 4 +- .../shared/gcHeapSummary.hpp | 36 +++++- .../vm/gc_implementation/shared/gcTrace.cpp | 14 ++- .../vm/gc_implementation/shared/gcTrace.hpp | 6 +- .../gc_implementation/shared/gcTraceSend.cpp | 24 ++++ .../share/vm/gc_interface/collectedHeap.cpp | 12 +- hotspot/src/share/vm/memory/metaspace.cpp | 55 ++++++++++ hotspot/src/share/vm/memory/metaspace.hpp | 4 + .../memory/metaspaceChunkFreeListSummary.hpp | 103 ++++++++++++++++++ hotspot/src/share/vm/trace/trace.xml | 14 +++ 11 files changed, 265 insertions(+), 10 deletions(-) create mode 100644 hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 5807db38eed..0e1bf9f8d48 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -2496,7 +2496,8 @@ void CMSCollector::save_heap_summary() { } void CMSCollector::report_heap_summary(GCWhen::Type when) { - _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary, _last_metaspace_summary); + _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary); + _gc_tracer_cm->report_metaspace_summary(when, _last_metaspace_summary); } void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) { diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index da0e569e869..9ebdb841dfd 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -665,8 +665,10 @@ void ParallelScavengeHeap::print_heap_change(size_t prev_used) { void ParallelScavengeHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { const PSHeapSummary& heap_summary = create_ps_heap_summary(); + gc_tracer->report_gc_heap_summary(when, heap_summary); + const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); - gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary); + gc_tracer->report_metaspace_summary(when, metaspace_summary); } ParallelScavengeHeap* ParallelScavengeHeap::heap() { diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp index c5d59eb865e..7f6dca0fb1f 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP #include "memory/allocation.hpp" +#include "memory/metaspaceChunkFreeListSummary.hpp" class VirtualSpaceSummary : public StackObj { HeapWord* _start; @@ -129,16 +130,45 @@ class MetaspaceSummary : public StackObj { MetaspaceSizes _meta_space; MetaspaceSizes _data_space; MetaspaceSizes _class_space; + MetaspaceChunkFreeListSummary _metaspace_chunk_free_list_summary; + MetaspaceChunkFreeListSummary _class_chunk_free_list_summary; public: - MetaspaceSummary() : _capacity_until_GC(0), _meta_space(), _data_space(), _class_space() {} - MetaspaceSummary(size_t capacity_until_GC, const MetaspaceSizes& meta_space, const MetaspaceSizes& data_space, const MetaspaceSizes& class_space) : - _capacity_until_GC(capacity_until_GC), _meta_space(meta_space), _data_space(data_space), _class_space(class_space) { } + MetaspaceSummary() : + _capacity_until_GC(0), + _meta_space(), + _data_space(), + _class_space(), + _metaspace_chunk_free_list_summary(), + _class_chunk_free_list_summary() + {} + MetaspaceSummary(size_t capacity_until_GC, + const MetaspaceSizes& meta_space, + const MetaspaceSizes& data_space, + const MetaspaceSizes& class_space, + const MetaspaceChunkFreeListSummary& metaspace_chunk_free_list_summary, + const MetaspaceChunkFreeListSummary& class_chunk_free_list_summary) : + _capacity_until_GC(capacity_until_GC), + _meta_space(meta_space), + _data_space(data_space), + _class_space(class_space), + _metaspace_chunk_free_list_summary(metaspace_chunk_free_list_summary), + _class_chunk_free_list_summary(class_chunk_free_list_summary) + {} size_t capacity_until_GC() const { return _capacity_until_GC; } const MetaspaceSizes& meta_space() const { return _meta_space; } const MetaspaceSizes& data_space() const { return _data_space; } const MetaspaceSizes& class_space() const { return _class_space; } + + const MetaspaceChunkFreeListSummary& metaspace_chunk_free_list_summary() const { + return _metaspace_chunk_free_list_summary; + } + + const MetaspaceChunkFreeListSummary& class_chunk_free_list_summary() const { + return _class_chunk_free_list_summary; + } + }; #endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp index 5e533d341d4..994d468bbc5 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp @@ -139,11 +139,21 @@ void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { } #endif // INCLUDE_SERVICES -void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const { +void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { assert_set_gc_id(); send_gc_heap_summary_event(when, heap_summary); - send_meta_space_summary_event(when, meta_space_summary); +} + +void GCTracer::report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& summary) const { + assert_set_gc_id(); + + send_meta_space_summary_event(when, summary); + + send_metaspace_chunk_free_list_summary(when, Metaspace::NonClassType, summary.metaspace_chunk_free_list_summary()); + if (UseCompressedClassPointers) { + send_metaspace_chunk_free_list_summary(when, Metaspace::ClassType, summary.class_chunk_free_list_summary()); + } } void YoungGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp index fda51e8bf52..3b55211a724 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp @@ -30,6 +30,7 @@ #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/allocation.hpp" +#include "memory/metaspace.hpp" #include "memory/referenceType.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1YCTypes.hpp" @@ -41,6 +42,7 @@ typedef uint GCId; class EvacuationInfo; class GCHeapSummary; +class MetaspaceChunkFreeListSummary; class MetaspaceSummary; class PSHeapSummary; class ReferenceProcessorStats; @@ -124,7 +126,8 @@ class GCTracer : public ResourceObj { public: void report_gc_start(GCCause::Cause cause, const Ticks& timestamp); void report_gc_end(const Ticks& timestamp, TimePartitions* time_partitions); - void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const; + void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const; + void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN; bool has_reported_gc_start() const; @@ -138,6 +141,7 @@ class GCTracer : public ResourceObj { void send_garbage_collection_event() const; void send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const; void send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const; + void send_metaspace_chunk_free_list_summary(GCWhen::Type when, Metaspace::MetadataType mdtype, const MetaspaceChunkFreeListSummary& summary) const; void send_reference_stats_event(ReferenceType type, size_t count) const; void send_phase_events(TimePartitions* time_partitions) const; }; diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp index 8d1459d5ba1..b7d6e8e6b59 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp @@ -64,6 +64,30 @@ void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) cons } } +void GCTracer::send_metaspace_chunk_free_list_summary(GCWhen::Type when, Metaspace::MetadataType mdtype, + const MetaspaceChunkFreeListSummary& summary) const { + EventMetaspaceChunkFreeListSummary e; + if (e.should_commit()) { + e.set_gcId(_shared_gc_info.id()); + e.set_when(when); + e.set_metadataType(mdtype); + + e.set_specializedChunks(summary.num_specialized_chunks()); + e.set_specializedChunksTotalSize(summary.specialized_chunks_size_in_bytes()); + + e.set_smallChunks(summary.num_small_chunks()); + e.set_smallChunksTotalSize(summary.small_chunks_size_in_bytes()); + + e.set_mediumChunks(summary.num_medium_chunks()); + e.set_mediumChunksTotalSize(summary.medium_chunks_size_in_bytes()); + + e.set_humongousChunks(summary.num_humongous_chunks()); + e.set_humongousChunksTotalSize(summary.humongous_chunks_size_in_bytes()); + + e.commit(); + } +} + void ParallelOldTracer::send_parallel_old_event() const { EventGCParallelOld e(UNTIMED); if (e.should_commit()) { diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index a1b28991248..071ca3812d2 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -97,7 +97,13 @@ MetaspaceSummary CollectedHeap::create_metaspace_summary() { MetaspaceAux::allocated_used_bytes(Metaspace::ClassType), MetaspaceAux::reserved_bytes(Metaspace::ClassType)); - return MetaspaceSummary(MetaspaceGC::capacity_until_GC(), meta_space, data_space, class_space); + const MetaspaceChunkFreeListSummary& ms_chunk_free_list_summary = + MetaspaceAux::chunk_free_list_summary(Metaspace::NonClassType); + const MetaspaceChunkFreeListSummary& class_chunk_free_list_summary = + MetaspaceAux::chunk_free_list_summary(Metaspace::ClassType); + + return MetaspaceSummary(MetaspaceGC::capacity_until_GC(), meta_space, data_space, class_space, + ms_chunk_free_list_summary, class_chunk_free_list_summary); } void CollectedHeap::print_heap_before_gc() { @@ -128,8 +134,10 @@ void CollectedHeap::unregister_nmethod(nmethod* nm) { void CollectedHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { const GCHeapSummary& heap_summary = create_heap_summary(); + gc_tracer->report_gc_heap_summary(when, heap_summary); + const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); - gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary); + gc_tracer->report_metaspace_summary(when, metaspace_summary); } void CollectedHeap::trace_heap_before_gc(GCTracer* gc_tracer) { diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index b5e4b0d1513..8280104a7e7 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -185,6 +185,48 @@ class ChunkManager : public CHeapObj { // Remove from a list by size. Selects list based on size of chunk. Metachunk* free_chunks_get(size_t chunk_word_size); +#define index_bounds_check(index) \ + assert(index == SpecializedIndex || \ + index == SmallIndex || \ + index == MediumIndex || \ + index == HumongousIndex, err_msg("Bad index: %d", (int) index)) + + size_t num_free_chunks(ChunkIndex index) const { + index_bounds_check(index); + + if (index == HumongousIndex) { + return _humongous_dictionary.total_free_blocks(); + } + + ssize_t count = _free_chunks[index].count(); + return count == -1 ? 0 : (size_t) count; + } + + size_t size_free_chunks_in_bytes(ChunkIndex index) const { + index_bounds_check(index); + + size_t word_size = 0; + if (index == HumongousIndex) { + word_size = _humongous_dictionary.total_size(); + } else { + const size_t size_per_chunk_in_words = _free_chunks[index].size(); + word_size = size_per_chunk_in_words * num_free_chunks(index); + } + + return word_size * BytesPerWord; + } + + MetaspaceChunkFreeListSummary chunk_free_list_summary() const { + return MetaspaceChunkFreeListSummary(num_free_chunks(SpecializedIndex), + num_free_chunks(SmallIndex), + num_free_chunks(MediumIndex), + num_free_chunks(HumongousIndex), + size_free_chunks_in_bytes(SpecializedIndex), + size_free_chunks_in_bytes(SmallIndex), + size_free_chunks_in_bytes(MediumIndex), + size_free_chunks_in_bytes(HumongousIndex)); + } + // Debug support void verify(); void slow_verify() { @@ -2637,6 +2679,19 @@ size_t MetaspaceAux::free_chunks_total_bytes() { return free_chunks_total_words() * BytesPerWord; } +bool MetaspaceAux::has_chunk_free_list(Metaspace::MetadataType mdtype) { + return Metaspace::get_chunk_manager(mdtype) != NULL; +} + +MetaspaceChunkFreeListSummary MetaspaceAux::chunk_free_list_summary(Metaspace::MetadataType mdtype) { + if (!has_chunk_free_list(mdtype)) { + return MetaspaceChunkFreeListSummary(); + } + + const ChunkManager* cm = Metaspace::get_chunk_manager(mdtype); + return cm->chunk_free_list_summary(); +} + void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) { gclog_or_tty->print(", [Metaspace:"); if (PrintGCDetails && Verbose) { diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index ce570928939..cd02b4a153e 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -26,6 +26,7 @@ #include "memory/allocation.hpp" #include "memory/memRegion.hpp" +#include "memory/metaspaceChunkFreeListSummary.hpp" #include "runtime/virtualspace.hpp" #include "utilities/exceptions.hpp" @@ -355,6 +356,9 @@ class MetaspaceAux : AllStatic { return min_chunk_size_words() * BytesPerWord; } + static bool has_chunk_free_list(Metaspace::MetadataType mdtype); + static MetaspaceChunkFreeListSummary chunk_free_list_summary(Metaspace::MetadataType mdtype); + // Print change in used metadata. static void print_metaspace_change(size_t prev_metadata_used); static void print_on(outputStream * out); diff --git a/hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp b/hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp new file mode 100644 index 00000000000..bc262f6a19d --- /dev/null +++ b/hotspot/src/share/vm/memory/metaspaceChunkFreeListSummary.hpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014, 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_MEMORY_METASPACE_CHUNK_FREE_LIST_SUMMARY_HPP +#define SHARE_VM_MEMORY_METASPACE_CHUNK_FREE_LIST_SUMMARY_HPP + +#include "memory/allocation.hpp" + +class MetaspaceChunkFreeListSummary VALUE_OBJ_CLASS_SPEC { + size_t _num_specialized_chunks; + size_t _num_small_chunks; + size_t _num_medium_chunks; + size_t _num_humongous_chunks; + + size_t _specialized_chunks_size_in_bytes; + size_t _small_chunks_size_in_bytes; + size_t _medium_chunks_size_in_bytes; + size_t _humongous_chunks_size_in_bytes; + + public: + MetaspaceChunkFreeListSummary() : + _num_specialized_chunks(0), + _num_small_chunks(0), + _num_medium_chunks(0), + _num_humongous_chunks(0), + _specialized_chunks_size_in_bytes(0), + _small_chunks_size_in_bytes(0), + _medium_chunks_size_in_bytes(0), + _humongous_chunks_size_in_bytes(0) + {} + + MetaspaceChunkFreeListSummary(size_t num_specialized_chunks, + size_t num_small_chunks, + size_t num_medium_chunks, + size_t num_humongous_chunks, + size_t specialized_chunks_size_in_bytes, + size_t small_chunks_size_in_bytes, + size_t medium_chunks_size_in_bytes, + size_t humongous_chunks_size_in_bytes) : + _num_specialized_chunks(num_specialized_chunks), + _num_small_chunks(num_small_chunks), + _num_medium_chunks(num_medium_chunks), + _num_humongous_chunks(num_humongous_chunks), + _specialized_chunks_size_in_bytes(specialized_chunks_size_in_bytes), + _small_chunks_size_in_bytes(small_chunks_size_in_bytes), + _medium_chunks_size_in_bytes(medium_chunks_size_in_bytes), + _humongous_chunks_size_in_bytes(humongous_chunks_size_in_bytes) + {} + + size_t num_specialized_chunks() const { + return _num_specialized_chunks; + } + + size_t num_small_chunks() const { + return _num_small_chunks; + } + + size_t num_medium_chunks() const { + return _num_medium_chunks; + } + + size_t num_humongous_chunks() const { + return _num_humongous_chunks; + } + + size_t specialized_chunks_size_in_bytes() const { + return _specialized_chunks_size_in_bytes; + } + + size_t small_chunks_size_in_bytes() const { + return _small_chunks_size_in_bytes; + } + + size_t medium_chunks_size_in_bytes() const { + return _medium_chunks_size_in_bytes; + } + + size_t humongous_chunks_size_in_bytes() const { + return _humongous_chunks_size_in_bytes; + } +}; + +#endif // SHARE_VM_MEMORY_METASPACE_CHUNK_FREE_LIST_SUMMARY_HPP diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 21aa3a35679..cd71b64a2d8 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -221,6 +221,20 @@ Declares a structure type that can be used in other events. + + + + + + + + + + + + + + From 1e1ad7f13215119d6b25cfc0836d530601d4be88 Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Fri, 28 Feb 2014 15:27:09 +0100 Subject: [PATCH 027/170] 8036025: Sort the freelist in order to shrink the heap The free list is being maintained in a sorted fashion and old and humongous regions are allocated from the bottom of the heap while young regions are allocated at the top. Co-authored-by: Staffan Friberg Reviewed-by: tschatzl, mgerdin --- .../gc_implementation/g1/concurrentMark.cpp | 8 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 34 +++--- .../gc_implementation/g1/g1CollectedHeap.hpp | 13 ++- .../vm/gc_implementation/g1/heapRegion.cpp | 2 +- .../vm/gc_implementation/g1/heapRegion.hpp | 5 +- .../vm/gc_implementation/g1/heapRegionSet.cpp | 94 +++++++++++++++- .../vm/gc_implementation/g1/heapRegionSet.hpp | 40 +++++-- .../g1/heapRegionSet.inline.hpp | 105 +++++++++++++++++- 8 files changed, 258 insertions(+), 43 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index b74984554b1..55482f1a1d9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -1929,7 +1929,7 @@ public: } } - _cleanup_list->add_as_tail(&local_cleanup_list); + _cleanup_list->add_ordered(&local_cleanup_list); assert(local_cleanup_list.is_empty(), "post-condition"); HeapRegionRemSet::finish_cleanup_task(&hrrs_cleanup_task); @@ -2158,9 +2158,9 @@ void ConcurrentMark::completeCleanup() { // so it's not necessary to take any locks while (!_cleanup_list.is_empty()) { HeapRegion* hr = _cleanup_list.remove_head(); - assert(hr != NULL, "the list was not empty"); + assert(hr != NULL, "Got NULL from a non-empty list"); hr->par_clear(); - tmp_free_list.add_as_tail(hr); + tmp_free_list.add_ordered(hr); // Instead of adding one region at a time to the secondary_free_list, // we accumulate them in the local list and move them a few at a @@ -2180,7 +2180,7 @@ void ConcurrentMark::completeCleanup() { { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); - g1h->secondary_free_list_add_as_tail(&tmp_free_list); + g1h->secondary_free_list_add(&tmp_free_list); SecondaryFreeList_lock->notify_all(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 38a6e62b44f..3a980bec4a4 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -516,7 +516,7 @@ G1CollectedHeap* G1CollectedHeap::_g1h; // Private methods. HeapRegion* -G1CollectedHeap::new_region_try_secondary_free_list() { +G1CollectedHeap::new_region_try_secondary_free_list(bool is_old) { MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag); while (!_secondary_free_list.is_empty() || free_regions_coming()) { if (!_secondary_free_list.is_empty()) { @@ -532,7 +532,7 @@ G1CollectedHeap::new_region_try_secondary_free_list() { assert(!_free_list.is_empty(), "if the secondary_free_list was not " "empty we should have moved at least one entry to the free_list"); - HeapRegion* res = _free_list.remove_head(); + HeapRegion* res = _free_list.remove_region(is_old); if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "allocated "HR_FORMAT" from secondary_free_list", @@ -554,7 +554,7 @@ G1CollectedHeap::new_region_try_secondary_free_list() { return NULL; } -HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { +HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool is_old, bool do_expand) { assert(!isHumongous(word_size) || word_size <= HeapRegion::GrainWords, "the only time we use this to allocate a humongous region is " "when we are allocating a single humongous region"); @@ -566,19 +566,21 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "forced to look at the secondary_free_list"); } - res = new_region_try_secondary_free_list(); + res = new_region_try_secondary_free_list(is_old); if (res != NULL) { return res; } } } - res = _free_list.remove_head_or_null(); + + res = _free_list.remove_region(is_old); + if (res == NULL) { if (G1ConcRegionFreeingVerbose) { gclog_or_tty->print_cr("G1ConcRegionFreeing [region alloc] : " "res == NULL, trying the secondary_free_list"); } - res = new_region_try_secondary_free_list(); + res = new_region_try_secondary_free_list(is_old); } if (res == NULL && do_expand && _expand_heap_after_alloc_failure) { // Currently, only attempts to allocate GC alloc regions set @@ -595,12 +597,9 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, bool do_expand) { if (expand(word_size * HeapWordSize)) { // Given that expand() succeeded in expanding the heap, and we // always expand the heap by an amount aligned to the heap - // region size, the free list should in theory not be empty. So - // it would probably be OK to use remove_head(). But the extra - // check for NULL is unlikely to be a performance issue here (we - // just expanded the heap!) so let's just be conservative and - // use remove_head_or_null(). - res = _free_list.remove_head_or_null(); + // region size, the free list should in theory not be empty. + // In either case remove_region() will check for NULL. + res = _free_list.remove_region(is_old); } else { _expand_heap_after_alloc_failure = false; } @@ -618,7 +617,7 @@ uint G1CollectedHeap::humongous_obj_allocate_find_first(uint num_regions, // Only one region to allocate, no need to go through the slower // path. The caller will attempt the expansion if this fails, so // let's not try to expand here too. - HeapRegion* hr = new_region(word_size, false /* do_expand */); + HeapRegion* hr = new_region(word_size, true /* is_old */, false /* do_expand */); if (hr != NULL) { first = hr->hrs_index(); } else { @@ -5907,7 +5906,7 @@ void G1CollectedHeap::free_region(HeapRegion* hr, _cg1r->hot_card_cache()->reset_card_counts(hr); } hr->hr_clear(par, true /* clear_space */, locked /* locked */); - free_list->add_as_head(hr); + free_list->add_ordered(hr); } void G1CollectedHeap::free_humongous_region(HeapRegion* hr, @@ -5947,7 +5946,7 @@ void G1CollectedHeap::prepend_to_freelist(FreeRegionList* list) { assert(list != NULL, "list can't be null"); if (!list->is_empty()) { MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag); - _free_list.add_as_head(list); + _free_list.add_ordered(list); } } @@ -6413,6 +6412,7 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, bool young_list_full = g1_policy()->is_young_list_full(); if (force || !young_list_full) { HeapRegion* new_alloc_region = new_region(word_size, + false /* is_old */, false /* do_expand */); if (new_alloc_region != NULL) { set_region_short_lived_locked(new_alloc_region); @@ -6471,14 +6471,16 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, assert(FreeList_lock->owned_by_self(), "pre-condition"); if (count < g1_policy()->max_regions(ap)) { + bool survivor = (ap == GCAllocForSurvived); HeapRegion* new_alloc_region = new_region(word_size, + !survivor, true /* do_expand */); if (new_alloc_region != NULL) { // We really only need to do this for old regions given that we // should never scan survivors. But it doesn't hurt to do it // for survivors too. new_alloc_region->set_saved_mark(); - if (ap == GCAllocForSurvived) { + if (survivor) { new_alloc_region->set_survivor(); _hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor); } else { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 5a47b8bf91a..4d0ff5369e4 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -497,13 +497,14 @@ protected: // check whether there's anything available on the // secondary_free_list and/or wait for more regions to appear on // that list, if _free_regions_coming is set. - HeapRegion* new_region_try_secondary_free_list(); + HeapRegion* new_region_try_secondary_free_list(bool is_old); // Try to allocate a single non-humongous HeapRegion sufficient for // an allocation of the given word_size. If do_expand is true, // attempt to expand the heap if necessary to satisfy the allocation - // request. - HeapRegion* new_region(size_t word_size, bool do_expand); + // request. If the region is to be used as an old region or for a + // humongous object, set is_old to true. If not, to false. + HeapRegion* new_region(size_t word_size, bool is_old, bool do_expand); // Attempt to satisfy a humongous allocation request of the given // size by finding a contiguous set of free regions of num_regions @@ -1232,12 +1233,12 @@ public: // Wrapper for the region list operations that can be called from // methods outside this class. - void secondary_free_list_add_as_tail(FreeRegionList* list) { - _secondary_free_list.add_as_tail(list); + void secondary_free_list_add(FreeRegionList* list) { + _secondary_free_list.add_ordered(list); } void append_secondary_free_list() { - _free_list.add_as_head(&_secondary_free_list); + _free_list.add_ordered(&_secondary_free_list); } void append_secondary_free_list_if_not_empty_with_lock() { diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 86546a90140..d018c9aabc3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -356,7 +356,7 @@ HeapRegion::HeapRegion(uint hrs_index, _claimed(InitialClaimValue), _evacuation_failed(false), _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0), _young_type(NotYoung), _next_young_region(NULL), - _next_dirty_cards_region(NULL), _next(NULL), _pending_removal(false), + _next_dirty_cards_region(NULL), _next(NULL), _prev(NULL), _pending_removal(false), #ifdef ASSERT _containing_set(NULL), #endif // ASSERT diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 28c92b854cc..b10f32674cc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -271,6 +271,7 @@ class HeapRegion: public G1OffsetTableContigSpace { // Fields used by the HeapRegionSetBase class and subclasses. HeapRegion* _next; + HeapRegion* _prev; #ifdef ASSERT HeapRegionSetBase* _containing_set; #endif // ASSERT @@ -531,11 +532,13 @@ class HeapRegion: public G1OffsetTableContigSpace { // Methods used by the HeapRegionSetBase class and subclasses. - // Getter and setter for the next field used to link regions into + // Getter and setter for the next and prev fields used to link regions into // linked lists. HeapRegion* next() { return _next; } + HeapRegion* prev() { return _prev; } void set_next(HeapRegion* next) { _next = next; } + void set_prev(HeapRegion* prev) { _prev = prev; } // Every region added to a set is tagged with a reference to that // set. This is used for doing consistency checking to make sure that diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp index 873fdb6c3f2..6ec03d5ceae 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -135,9 +135,11 @@ void FreeRegionList::add_as_head_or_tail(FreeRegionList* from_list, bool as_head assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant")); if (as_head) { from_list->_tail->set_next(_head); + _head->set_prev(from_list->_tail); _head = from_list->_head; } else { _tail->set_next(from_list->_head); + from_list->_head->set_prev(_tail); _tail = from_list->_tail; } } @@ -167,6 +169,7 @@ void FreeRegionList::remove_all() { HeapRegion* next = curr->next(); curr->set_next(NULL); + curr->set_prev(NULL); curr->set_containing_set(NULL); curr = next; } @@ -175,6 +178,74 @@ void FreeRegionList::remove_all() { verify_optional(); } +void FreeRegionList::add_ordered(FreeRegionList* from_list) { + check_mt_safety(); + from_list->check_mt_safety(); + + verify_optional(); + from_list->verify_optional(); + + if (from_list->is_empty()) { + return; + } + + if (is_empty()) { + add_as_head(from_list); + return; + } + + #ifdef ASSERT + FreeRegionListIterator iter(from_list); + while (iter.more_available()) { + HeapRegion* hr = iter.get_next(); + // In set_containing_set() we check that we either set the value + // from NULL to non-NULL or vice versa to catch bugs. So, we have + // to NULL it first before setting it to the value. + hr->set_containing_set(NULL); + hr->set_containing_set(this); + } + #endif // ASSERT + + HeapRegion* curr_to = _head; + HeapRegion* curr_from = from_list->_head; + + while (curr_from != NULL) { + while (curr_to != NULL && curr_to->hrs_index() < curr_from->hrs_index()) { + curr_to = curr_to->next(); + } + + if (curr_to == NULL) { + // The rest of the from list should be added as tail + _tail->set_next(curr_from); + curr_from->set_prev(_tail); + curr_from = NULL; + } else { + HeapRegion* next_from = curr_from->next(); + + curr_from->set_next(curr_to); + curr_from->set_prev(curr_to->prev()); + if (curr_to->prev() == NULL) { + _head = curr_from; + } else { + curr_to->prev()->set_next(curr_from); + } + curr_to->set_prev(curr_from); + + curr_from = next_from; + } + } + + if (_tail->hrs_index() < from_list->_tail->hrs_index()) { + _tail = from_list->_tail; + } + + _count.increment(from_list->length(), from_list->total_capacity_bytes()); + from_list->clear(); + + verify_optional(); + from_list->verify_optional(); +} + void FreeRegionList::remove_all_pending(uint target_count) { check_mt_safety(); assert(target_count > 1, hrs_ext_msg(this, "pre-condition")); @@ -184,11 +255,11 @@ void FreeRegionList::remove_all_pending(uint target_count) { DEBUG_ONLY(uint old_length = length();) HeapRegion* curr = _head; - HeapRegion* prev = NULL; uint count = 0; while (curr != NULL) { verify_region(curr); HeapRegion* next = curr->next(); + HeapRegion* prev = curr->prev(); if (curr->pending_removal()) { assert(count < target_count, @@ -208,9 +279,14 @@ void FreeRegionList::remove_all_pending(uint target_count) { _tail = prev; } else { assert(_tail != curr, hrs_ext_msg(this, "invariant")); + next->set_prev(prev); + } + if (_last = curr) { + _last = NULL; } curr->set_next(NULL); + curr->set_prev(NULL); remove(curr); curr->set_pending_removal(false); @@ -221,8 +297,6 @@ void FreeRegionList::remove_all_pending(uint target_count) { // carry on iterating to make sure there are not more regions // tagged with pending removal. DEBUG_ONLY(if (count == target_count) break;) - } else { - prev = curr; } curr = next; } @@ -255,6 +329,7 @@ void FreeRegionList::clear() { _count = HeapRegionSetCount(); _head = NULL; _tail = NULL; + _last = NULL; } void FreeRegionList::print_on(outputStream* out, bool print_contents) { @@ -279,6 +354,9 @@ void FreeRegionList::verify_list() { HeapRegion* prev0 = NULL; uint count = 0; size_t capacity = 0; + uint last_index = 0; + + guarantee(_head == NULL || _head->prev() == NULL, "_head should not have a prev"); while (curr != NULL) { verify_region(curr); @@ -286,6 +364,12 @@ void FreeRegionList::verify_list() { guarantee(count < _unrealistically_long_length, hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: "PTR_FORMAT" prev0: "PTR_FORMAT" " "prev1: "PTR_FORMAT" length: %u", name(), count, curr, prev0, prev1, length())); + if (curr->next() != NULL) { + guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up"); + } + guarantee(curr->hrs_index() == 0 || curr->hrs_index() > last_index, "List should be sorted"); + last_index = curr->hrs_index(); + capacity += curr->capacity(); prev1 = prev0; @@ -294,7 +378,7 @@ void FreeRegionList::verify_list() { } guarantee(tail() == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), tail()->hrs_index(), prev0->hrs_index())); - + guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next"); guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, name(), total_capacity_bytes(), capacity)); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp index 09a94b52258..c54fc784719 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -191,11 +191,14 @@ public: } }; -// A set that links all the regions added to it in a singly-linked +// A set that links all the regions added to it in a doubly-linked // list. We should try to avoid doing operations that iterate over // such lists in performance critical paths. Typically we should -// add / remove one region at a time or concatenate two lists. All -// those operations are done in constant time. +// add / remove one region at a time or concatenate two lists. There are +// two ways to treat your lists, ordered and un-ordered. All un-ordered +// operations are done in constant time. To keep a list ordered only use +// add_ordered() to add elements to the list. If a list is not ordered +// from start, there is no way to sort it later. class FreeRegionListIterator; @@ -206,6 +209,11 @@ private: HeapRegion* _head; HeapRegion* _tail; + // _last is used to keep track of where we added an element the last + // time in ordered lists. It helps to improve performance when adding + // several ordered items in a row. + HeapRegion* _last; + static uint _unrealistically_long_length; void add_as_head_or_tail(FreeRegionList* from_list, bool as_head); @@ -229,6 +237,11 @@ public: static void set_unrealistically_long_length(uint len); + // Add hr to the list. The region should not be a member of another set. + // Assumes that the list is ordered and will preserve that order. The order + // is determined by hrs_index. + inline void add_ordered(HeapRegion* hr); + // It adds hr to the list as the new head. The region should not be // a member of another set. inline void add_as_head(HeapRegion* hr); @@ -244,6 +257,20 @@ public: // Convenience method. inline HeapRegion* remove_head_or_null(); + // Removes and returns the last element (_tail) of the list. It assumes + // that the list isn't empty so that it can return a non-NULL value. + inline HeapRegion* remove_tail(); + + // Convenience method + inline HeapRegion* remove_tail_or_null(); + + // Removes from head or tail based on the given argument. + inline HeapRegion* remove_region(bool from_head); + + // Merge two ordered lists. The result is also ordered. The order is + // determined by hrs_index. + void add_ordered(FreeRegionList* from_list); + // It moves the regions from from_list to this list and empties // from_list. The new regions will appear in the same order as they // were in from_list and be linked in the beginning of this list. @@ -276,7 +303,7 @@ public: class FreeRegionListIterator : public StackObj { private: FreeRegionList* _list; - HeapRegion* _curr; + HeapRegion* _curr; public: bool more_available() { @@ -296,8 +323,7 @@ public: return hr; } - FreeRegionListIterator(FreeRegionList* list) - : _curr(NULL), _list(list) { + FreeRegionListIterator(FreeRegionList* list) : _curr(NULL), _list(list) { _curr = list->head(); } }; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp index 2a948ec70c8..287f1bd96a7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -47,6 +47,54 @@ inline void HeapRegionSetBase::remove(HeapRegion* hr) { _count.decrement(1u, hr->capacity()); } +inline void FreeRegionList::add_ordered(HeapRegion* hr) { + check_mt_safety(); + assert((length() == 0 && _head == NULL && _tail == NULL) || + (length() > 0 && _head != NULL && _tail != NULL), + hrs_ext_msg(this, "invariant")); + // add() will verify the region and check mt safety. + add(hr); + + // Now link the region + if (_head != NULL) { + HeapRegion* curr; + + if (_last != NULL && _last->hrs_index() < hr->hrs_index()) { + curr = _last; + } else { + curr = _head; + } + + // Find first entry with a Region Index larger than entry to insert. + while (curr != NULL && curr->hrs_index() < hr->hrs_index()) { + curr = curr->next(); + } + + hr->set_next(curr); + + if (curr == NULL) { + // Adding at the end + hr->set_prev(_tail); + _tail->set_next(hr); + _tail = hr; + } else if (curr->prev() == NULL) { + // Adding at the beginning + hr->set_prev(NULL); + _head = hr; + curr->set_prev(hr); + } else { + hr->set_prev(curr->prev()); + hr->prev()->set_next(hr); + curr->set_prev(hr); + } + } else { + // The list was empty + _tail = hr; + _head = hr; + } + _last = hr; +} + inline void FreeRegionList::add_as_head(HeapRegion* hr) { assert((length() == 0 && _head == NULL && _tail == NULL) || (length() > 0 && _head != NULL && _tail != NULL), @@ -57,6 +105,7 @@ inline void FreeRegionList::add_as_head(HeapRegion* hr) { // Now link the region. if (_head != NULL) { hr->set_next(_head); + _head->set_prev(hr); } else { _tail = hr; } @@ -68,12 +117,13 @@ inline void FreeRegionList::add_as_tail(HeapRegion* hr) { assert((length() == 0 && _head == NULL && _tail == NULL) || (length() > 0 && _head != NULL && _tail != NULL), hrs_ext_msg(this, "invariant")); - // add() will verify the region and check mt safety + // add() will verify the region and check mt safety. add(hr); // Now link the region. if (_tail != NULL) { _tail->set_next(hr); + hr->set_prev(_tail); } else { _head = hr; } @@ -90,10 +140,16 @@ inline HeapRegion* FreeRegionList::remove_head() { _head = hr->next(); if (_head == NULL) { _tail = NULL; + } else { + _head->set_prev(NULL); } hr->set_next(NULL); - // remove() will verify the region and check mt safety + if (_last == hr) { + _last = NULL; + } + + // remove() will verify the region and check mt safety. remove(hr); return hr; } @@ -107,4 +163,47 @@ inline HeapRegion* FreeRegionList::remove_head_or_null() { } } +inline HeapRegion* FreeRegionList::remove_tail() { + assert(!is_empty(), hrs_ext_msg(this, "The list should not be empty")); + assert(length() > 0 && _head != NULL && _tail != NULL, + hrs_ext_msg(this, "invariant")); + + // We need to unlink it first + HeapRegion* hr = _tail; + + _tail = hr->prev(); + if (_tail == NULL) { + _head = NULL; + } else { + _tail->set_next(NULL); + } + hr->set_prev(NULL); + + if (_last == hr) { + _last = NULL; + } + + // remove() will verify the region and check mt safety. + remove(hr); + return hr; +} + +inline HeapRegion* FreeRegionList::remove_tail_or_null() { + check_mt_safety(); + + if (!is_empty()) { + return remove_tail(); + } else { + return NULL; + } +} + +inline HeapRegion* FreeRegionList::remove_region(bool from_head) { + if (from_head) { + return remove_head_or_null(); + } else { + return remove_tail_or_null(); + } +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONSET_INLINE_HPP From 8159b86e35b7e4620afe9f9d10224dba781519ef Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Thu, 20 Mar 2014 15:03:18 +0100 Subject: [PATCH 028/170] 8037952: Remove code duplication in Metaspace::deallocate Reviewed-by: tschatzl, pliden, coleenp --- hotspot/src/share/vm/memory/metaspace.cpp | 41 +++++++---------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index 8280104a7e7..31318cb51d0 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -3343,37 +3343,22 @@ size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const { } void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { - if (SafepointSynchronize::is_at_safepoint()) { - assert(Thread::current()->is_VM_thread(), "should be the VM thread"); - // Don't take Heap_lock - MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); - if (word_size < TreeChunk >::min_size()) { - // Dark matter. Too small for dictionary. -#ifdef ASSERT - Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5); -#endif - return; - } - if (is_class && using_class_space()) { - class_vsm()->deallocate(ptr, word_size); - } else { - vsm()->deallocate(ptr, word_size); - } - } else { - MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); + assert(!SafepointSynchronize::is_at_safepoint() + || Thread::current()->is_VM_thread(), "should be the VM thread"); - if (word_size < TreeChunk >::min_size()) { - // Dark matter. Too small for dictionary. + MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag); + + if (word_size < TreeChunk >::min_size()) { + // Dark matter. Too small for dictionary. #ifdef ASSERT - Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5); + Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5); #endif - return; - } - if (is_class && using_class_space()) { - class_vsm()->deallocate(ptr, word_size); - } else { - vsm()->deallocate(ptr, word_size); - } + return; + } + if (is_class && using_class_space()) { + class_vsm()->deallocate(ptr, word_size); + } else { + vsm()->deallocate(ptr, word_size); } } From 547e8e4b756dd1e508b876742f21924c62bf0efc Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Wed, 26 Mar 2014 10:54:52 +0100 Subject: [PATCH 029/170] 8037958: ConcurrentMark::cleanup leaks BitMaps if VerifyDuringGC is enabled Allocate temporary BitMaps in the VMThread's resource area Reviewed-by: stefank, sjohanss --- hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 55482f1a1d9..727be275ab4 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -2018,8 +2018,8 @@ void ConcurrentMark::cleanup() { // that calculated by walking the marking bitmap. // Bitmaps to hold expected values - BitMap expected_region_bm(_region_bm.size(), false); - BitMap expected_card_bm(_card_bm.size(), false); + BitMap expected_region_bm(_region_bm.size(), true); + BitMap expected_card_bm(_card_bm.size(), true); G1ParVerifyFinalCountTask g1_par_verify_task(g1h, &_region_bm, From 7a39c2c7d5d757bd97fd9e5cf294394e6b2384a2 Mon Sep 17 00:00:00 2001 From: Tao Mao Date: Wed, 26 Mar 2014 12:49:34 +0100 Subject: [PATCH 030/170] 6521376: MaxTenuringThreshold and AlwayTenure/NeverTenure consistency Adapt InitialTenuringThreshold and MaxTenuringThreshold according to AlwaysTenure/NeverTenure flag setting. Reviewed-by: jmasa, tschatzl --- .../parallelScavenge/psScavenge.cpp | 11 +- .../vm/gc_implementation/shared/ageTable.cpp | 37 +-- hotspot/src/share/vm/runtime/arguments.cpp | 34 ++- hotspot/test/gc/arguments/FlagsValue.java | 43 ++++ .../TestInitialTenuringThreshold.java | 8 +- .../gc/arguments/TestObjectTenuringFlags.java | 215 ++++++++++++++++++ 6 files changed, 313 insertions(+), 35 deletions(-) create mode 100644 hotspot/test/gc/arguments/FlagsValue.java create mode 100644 hotspot/test/gc/arguments/TestObjectTenuringFlags.java diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp index a708d8ebb72..a5d008ee11c 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp @@ -550,7 +550,8 @@ bool PSScavenge::invoke_no_policy() { if (PrintTenuringDistribution) { gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)", + gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold " + UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", size_policy->calculated_survivor_size_in_bytes(), _tenuring_threshold, MaxTenuringThreshold); } @@ -829,10 +830,10 @@ GCTaskManager* const PSScavenge::gc_task_manager() { void PSScavenge::initialize() { // Arguments must have been parsed - if (AlwaysTenure) { - _tenuring_threshold = 0; - } else if (NeverTenure) { - _tenuring_threshold = markOopDesc::max_age + 1; + if (AlwaysTenure || NeverTenure) { + assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, + err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is ", MaxTenuringThreshold)); + _tenuring_threshold = MaxTenuringThreshold; } else { // We want to smooth out our startup times for the AdaptiveSizePolicy _tenuring_threshold = (UseAdaptiveSizePolicy) ? InitialTenuringThreshold : diff --git a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp index 311fd7771dd..2fe4de9c30e 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/ageTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -80,28 +80,37 @@ void ageTable::merge_par(ageTable* subTable) { uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) { size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); - size_t total = 0; - uint age = 1; - assert(sizes[0] == 0, "no objects with age zero should be recorded"); - while (age < table_size) { - total += sizes[age]; - // check if including objects of age 'age' made us pass the desired - // size, if so 'age' is the new threshold - if (total > desired_survivor_size) break; - age++; + uint result; + + if (AlwaysTenure || NeverTenure) { + assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, + err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is ", MaxTenuringThreshold)); + result = MaxTenuringThreshold; + } else { + size_t total = 0; + uint age = 1; + assert(sizes[0] == 0, "no objects with age zero should be recorded"); + while (age < table_size) { + total += sizes[age]; + // check if including objects of age 'age' made us pass the desired + // size, if so 'age' is the new threshold + if (total > desired_survivor_size) break; + age++; + } + result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; } - uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold; if (PrintTenuringDistribution || UsePerfData) { if (PrintTenuringDistribution) { gclog_or_tty->cr(); - gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold %u (max %u)", + gclog_or_tty->print_cr("Desired survivor size " SIZE_FORMAT " bytes, new threshold " + UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", desired_survivor_size*oopSize, result, MaxTenuringThreshold); } - total = 0; - age = 1; + size_t total = 0; + uint age = 1; while (age < table_size) { total += sizes[age]; if (sizes[age] > 0) { diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 2bb12bc16f2..1e7435fbcd4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1186,11 +1186,6 @@ void Arguments::set_parnew_gc_flags() { FLAG_SET_DEFAULT(OldPLABSize, (intx)1024); } - // AlwaysTenure flag should make ParNew promote all at first collection. - // See CR 6362902. - if (AlwaysTenure) { - FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0); - } // When using compressed oops, we use local overflow stacks, // rather than using a global overflow list chained through // the klass word of the object's pre-image. @@ -2343,10 +2338,8 @@ bool Arguments::check_vm_args_consistency() { status = status && verify_percentage(YoungGenerationSizeSupplement, "YoungGenerationSizeSupplement"); status = status && verify_percentage(TenuredGenerationSizeSupplement, "TenuredGenerationSizeSupplement"); - // the "age" field in the oop header is 4 bits; do not want to pull in markOop.hpp - // just for that, so hardcode here. - status = status && verify_interval(MaxTenuringThreshold, 0, 15, "MaxTenuringThreshold"); - status = status && verify_interval(InitialTenuringThreshold, 0, MaxTenuringThreshold, "MaxTenuringThreshold"); + status = status && verify_interval(MaxTenuringThreshold, 0, markOopDesc::max_age + 1, "MaxTenuringThreshold"); + status = status && verify_interval(InitialTenuringThreshold, 0, MaxTenuringThreshold, "InitialTenuringThreshold"); status = status && verify_percentage(TargetSurvivorRatio, "TargetSurvivorRatio"); status = status && verify_percentage(MarkSweepDeadRatio, "MarkSweepDeadRatio"); @@ -3072,14 +3065,31 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // but disallow DR and offlining (5008695). FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true); + // Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure; + // and the last option wins. } else if (match_option(option, "-XX:+NeverTenure", &tail)) { - // The last option must always win. - FLAG_SET_CMDLINE(bool, AlwaysTenure, false); FLAG_SET_CMDLINE(bool, NeverTenure, true); + FLAG_SET_CMDLINE(bool, AlwaysTenure, false); + FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1); } else if (match_option(option, "-XX:+AlwaysTenure", &tail)) { - // The last option must always win. FLAG_SET_CMDLINE(bool, NeverTenure, false); FLAG_SET_CMDLINE(bool, AlwaysTenure, true); + FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0); + } else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) { + uintx max_tenuring_thresh = 0; + if(!parse_uintx(tail, &max_tenuring_thresh, 0)) { + jio_fprintf(defaultStream::error_stream(), + "Invalid MaxTenuringThreshold: %s\n", option->optionString); + } + FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh); + + if (MaxTenuringThreshold == 0) { + FLAG_SET_CMDLINE(bool, NeverTenure, false); + FLAG_SET_CMDLINE(bool, AlwaysTenure, true); + } else { + FLAG_SET_CMDLINE(bool, NeverTenure, false); + FLAG_SET_CMDLINE(bool, AlwaysTenure, false); + } } else if (match_option(option, "-XX:+CMSPermGenSweepingEnabled", &tail) || match_option(option, "-XX:-CMSPermGenSweepingEnabled", &tail)) { jio_fprintf(defaultStream::error_stream(), diff --git a/hotspot/test/gc/arguments/FlagsValue.java b/hotspot/test/gc/arguments/FlagsValue.java new file mode 100644 index 00000000000..1dbd4a3cbbf --- /dev/null +++ b/hotspot/test/gc/arguments/FlagsValue.java @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2014, 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. +*/ + +import java.util.regex.*; + +public class FlagsValue { + public static boolean getFlagBoolValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + return m.group(1).equals("true"); + } + + public static long getFlagLongValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return Long.parseLong(match.substring(match.lastIndexOf(" ") + 1, match.length())); + } +} \ No newline at end of file diff --git a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java index 2c97ccd8fff..130ff744d08 100644 --- a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java +++ b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2013, 2014, 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 @@ -63,13 +63,13 @@ public class TestInitialTenuringThreshold { // successful tests runWithThresholds(0, 10, false); runWithThresholds(5, 5, false); + runWithThresholds(8, 16, false); // failing tests runWithThresholds(10, 0, true); runWithThresholds(9, 8, true); runWithThresholds(-1, 8, true); runWithThresholds(8, -1, true); - runWithThresholds(8, 16, true); runWithThresholds(16, 8, true); + runWithThresholds(8, 17, true); } -} - +} \ No newline at end of file diff --git a/hotspot/test/gc/arguments/TestObjectTenuringFlags.java b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java new file mode 100644 index 00000000000..64ddeb46744 --- /dev/null +++ b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java @@ -0,0 +1,215 @@ +/* +* Copyright (c) 2014, 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 TestObjectTenuringFlags + * @key gc + * @bug 6521376 + * @summary Tests argument processing for NeverTenure, AlwaysTenure, + * and MaxTenuringThreshold + * @library /testlibrary + * @build TestObjectTenuringFlags FlagsValue + * @run main/othervm TestObjectTenuringFlags + */ + +import com.oracle.java.testlibrary.*; + +import java.util.*; + +public class TestObjectTenuringFlags { + public static void main(String args[]) throws Exception { + // default case + runTenuringFlagsConsistencyTest( + new String[]{}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 15)); + + // valid cases + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+NeverTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, true /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+AlwaysTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=0"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=5"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 5, 5)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=10"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 10)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=15"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=16"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=0"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 0, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=5"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 5, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=10"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 10, 15)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=15"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 15, 15)); + + // "Last option wins" cases + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+AlwaysTenure", "-XX:+NeverTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, true /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+NeverTenure", "-XX:+AlwaysTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=16", "-XX:+AlwaysTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+AlwaysTenure", "-XX:MaxTenuringThreshold=16"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, false /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=0", "-XX:+NeverTenure"}, + false /* shouldFail */, + new ExpectedTenuringFlags(false /* alwaysTenure */, true /* neverTenure */, 7, 16)); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:+NeverTenure", "-XX:MaxTenuringThreshold=0"}, + false /* shouldFail */, + new ExpectedTenuringFlags(true /* alwaysTenure */, false /* neverTenure */, 0, 0)); + + // Illegal cases + runTenuringFlagsConsistencyTest( + new String[]{"-XX:MaxTenuringThreshold=17"}, + true /* shouldFail */, + new ExpectedTenuringFlags()); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=16"}, + true /* shouldFail */, + new ExpectedTenuringFlags()); + + runTenuringFlagsConsistencyTest( + new String[]{"-XX:InitialTenuringThreshold=17"}, + true /* shouldFail */, + new ExpectedTenuringFlags()); + } + + private static void runTenuringFlagsConsistencyTest(String[] tenuringFlags, + boolean shouldFail, + ExpectedTenuringFlags expectedFlags) throws Exception { + List vmOpts = new ArrayList<>(); + if (tenuringFlags.length > 0) { + Collections.addAll(vmOpts, tenuringFlags); + } + Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + if (shouldFail) { + output.shouldHaveExitValue(1); + } else { + output.shouldHaveExitValue(0); + String stdout = output.getStdout(); + checkTenuringFlagsConsistency(stdout, expectedFlags); + } + } + + private static void checkTenuringFlagsConsistency(String output, ExpectedTenuringFlags expectedFlags) { + if (expectedFlags.alwaysTenure != FlagsValue.getFlagBoolValue("AlwaysTenure", output)) { + throw new RuntimeException( + "Actual flag AlwaysTenure " + FlagsValue.getFlagBoolValue("AlwaysTenure", output) + + " is not equal to expected flag AlwaysTenure " + expectedFlags.alwaysTenure); + } + + if (expectedFlags.neverTenure != FlagsValue.getFlagBoolValue("NeverTenure", output)) { + throw new RuntimeException( + "Actual flag NeverTenure " + FlagsValue.getFlagBoolValue("NeverTenure", output) + + " is not equal to expected flag NeverTenure " + expectedFlags.neverTenure); + } + + if (expectedFlags.initialTenuringThreshold != FlagsValue.getFlagLongValue("InitialTenuringThreshold", output)) { + throw new RuntimeException( + "Actual flag InitialTenuringThreshold " + FlagsValue.getFlagLongValue("InitialTenuringThreshold", output) + + " is not equal to expected flag InitialTenuringThreshold " + expectedFlags.initialTenuringThreshold); + } + + if (expectedFlags.maxTenuringThreshold != FlagsValue.getFlagLongValue("MaxTenuringThreshold", output)) { + throw new RuntimeException( + "Actual flag MaxTenuringThreshold " + FlagsValue.getFlagLongValue("MaxTenuringThreshold", output) + + " is not equal to expected flag MaxTenuringThreshold " + expectedFlags.maxTenuringThreshold); + } + } +} + +class ExpectedTenuringFlags { + public boolean alwaysTenure; + public boolean neverTenure; + public long initialTenuringThreshold; + public long maxTenuringThreshold; + + public ExpectedTenuringFlags(boolean alwaysTenure, + boolean neverTenure, + long initialTenuringThreshold, + long maxTenuringThreshold) { + this.alwaysTenure = alwaysTenure; + this.neverTenure = neverTenure; + this.initialTenuringThreshold = initialTenuringThreshold; + this.maxTenuringThreshold = maxTenuringThreshold; + } + public ExpectedTenuringFlags() {} +} From 102943d1f2778752848030136acecd55e5d63583 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Wed, 19 Mar 2014 14:35:38 +0100 Subject: [PATCH 031/170] 8033580: Old debug information in IMPORT_JDK is not removed Reviewed-by: dcubed, erikj --- hotspot/make/Makefile | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index 75893a6a1f9..bde309fc467 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -287,8 +287,43 @@ else @$(ECHO) "Error: trying to build a minimal target but JVM_VARIANT_MINIMAL1 is not true." endif +remove_old_debuginfo: +ifeq ($(JVM_VARIANT_CLIENT), true) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + ifeq ($(OSNAME), windows) + $(RM) -f $(EXPORT_CLIENT_DIR)/jvm.map $(EXPORT_CLIENT_DIR)/jvm.pdb + else + $(RM) -f $(EXPORT_CLIENT_DIR)/libjvm.debuginfo + endif + else + $(RM) -f $(EXPORT_CLIENT_DIR)/libjvm.diz + endif +endif +ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + ifeq ($(OSNAME), windows) + $(RM) -f $(EXPORT_SERVER_DIR)/jvm.map $(EXPORT_SERVER_DIR)/jvm.pdb + else + ifeq ($(OS_VENDOR), Darwin) + $(RM) -rf $(EXPORT_SERVER_DIR)/libjvm.dylib.dSYM + else + $(RM) -f $(EXPORT_SERVER_DIR)/libjvm.debuginfo + endif + endif + else + $(RM) -f $(EXPORT_SERVER_DIR)/libjvm.diz + endif +endif +ifeq ($(JVM_VARIANT_MINIMAL1),true) + ifeq ($(ZIP_DEBUGINFO_FILES),1) + $(RM) -f $(EXPORT_MINIMAL_DIR)/libjvm.debuginfo + else + $(RM) -f $(EXPORT_MINIMAL_DIR)/libjvm.diz + endif +endif + # Export file rule -generic_export: $(EXPORT_LIST) +generic_export: $(EXPORT_LIST) remove_old_debuginfo export_product: $(MAKE) BUILD_FLAVOR=$(@:export_%=%) generic_export @@ -841,4 +876,4 @@ include $(GAMMADIR)/make/jprt.gmk export_jdk_product export_jdk_fastdebug export_jdk_debug \ create_jdk copy_jdk update_jdk test_jdk \ copy_product_jdk copy_fastdebug_jdk copy_debug_jdk \ - $(HS_ALT_MAKE)/Makefile.make + $(HS_ALT_MAKE)/Makefile.make remove_old_debuginfo From 74235d9630bf5337186840d130b70b0475de4e0f Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Thu, 6 Mar 2014 09:08:18 +0100 Subject: [PATCH 032/170] 8038399: Remove dead oop_iterate MemRegion variants from SharedHeap, Generation and Space classes Reviewed-by: tschatzl, stefank --- .../compactibleFreeListSpace.cpp | 47 ------------------- .../compactibleFreeListSpace.hpp | 1 - .../concurrentMarkSweepGeneration.cpp | 10 ---- .../concurrentMarkSweepGeneration.hpp | 1 - .../src/share/vm/memory/genCollectedHeap.cpp | 6 --- .../src/share/vm/memory/genCollectedHeap.hpp | 1 - hotspot/src/share/vm/memory/generation.cpp | 16 ++----- hotspot/src/share/vm/memory/generation.hpp | 4 -- hotspot/src/share/vm/memory/sharedHeap.hpp | 3 -- hotspot/src/share/vm/memory/space.cpp | 40 ---------------- hotspot/src/share/vm/memory/space.hpp | 31 ------------ 11 files changed, 5 insertions(+), 155 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index cd3e7ddc21c..c8a3f2297dd 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -793,53 +793,6 @@ void CompactibleFreeListSpace::oop_iterate(ExtendedOopClosure* cl) { } } -// Apply the given closure to each oop in the space \intersect memory region. -void CompactibleFreeListSpace::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - assert_lock_strong(freelistLock()); - if (is_empty()) { - return; - } - MemRegion cur = MemRegion(bottom(), end()); - mr = mr.intersection(cur); - if (mr.is_empty()) { - return; - } - if (mr.equals(cur)) { - oop_iterate(cl); - return; - } - assert(mr.end() <= end(), "just took an intersection above"); - HeapWord* obj_addr = block_start(mr.start()); - HeapWord* t = mr.end(); - - SpaceMemRegionOopsIterClosure smr_blk(cl, mr); - if (block_is_obj(obj_addr)) { - // Handle first object specially. - oop obj = oop(obj_addr); - obj_addr += adjustObjectSize(obj->oop_iterate(&smr_blk)); - } else { - FreeChunk* fc = (FreeChunk*)obj_addr; - obj_addr += fc->size(); - } - while (obj_addr < t) { - HeapWord* obj = obj_addr; - obj_addr += block_size(obj_addr); - // If "obj_addr" is not greater than top, then the - // entire object "obj" is within the region. - if (obj_addr <= t) { - if (block_is_obj(obj)) { - oop(obj)->oop_iterate(cl); - } - } else { - // "obj" extends beyond end of region - if (block_is_obj(obj)) { - oop(obj)->oop_iterate(&smr_blk); - } - break; - } - } -} - // NOTE: In the following methods, in order to safely be able to // apply the closure to an object, we need to be sure that the // object has been initialized. We are guaranteed that an object diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 59ea6c30fb8..5cda2c7c4af 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -351,7 +351,6 @@ class CompactibleFreeListSpace: public CompactibleSpace { Mutex* freelistLock() const { return &_freelistLock; } // Iteration support - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); void oop_iterate(ExtendedOopClosure* cl); void object_iterate(ObjectClosure* blk); diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 0e1bf9f8d48..d71e82799d2 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -3163,16 +3163,6 @@ ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure* cl) { cl->reset_generation(); } -void -ConcurrentMarkSweepGeneration::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - if (freelistLock()->owned_by_self()) { - Generation::oop_iterate(mr, cl); - } else { - MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag); - Generation::oop_iterate(mr, cl); - } -} - void ConcurrentMarkSweepGeneration::oop_iterate(ExtendedOopClosure* cl) { if (freelistLock()->owned_by_self()) { diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index 3c771ef3946..aeb1c9418cc 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -1285,7 +1285,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { void save_sweep_limit(); // More iteration support - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); virtual void oop_iterate(ExtendedOopClosure* cl); virtual void safe_object_iterate(ObjectClosure* cl); virtual void object_iterate(ObjectClosure* cl); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index be4ad6945dd..75faabc648e 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -837,12 +837,6 @@ void GenCollectedHeap::oop_iterate(ExtendedOopClosure* cl) { } } -void GenCollectedHeap::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - for (int i = 0; i < _n_gens; i++) { - _gens[i]->oop_iterate(mr, cl); - } -} - void GenCollectedHeap::object_iterate(ObjectClosure* cl) { for (int i = 0; i < _n_gens; i++) { _gens[i]->object_iterate(cl); diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index f687a1c97e6..4a62aa4b411 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -212,7 +212,6 @@ public: // Iteration functions. void oop_iterate(ExtendedOopClosure* cl); - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); void object_iterate(ObjectClosure* cl); void safe_object_iterate(ObjectClosure* cl); Space* space_containing(const void* addr) const; diff --git a/hotspot/src/share/vm/memory/generation.cpp b/hotspot/src/share/vm/memory/generation.cpp index 5ea44867d6d..11ba05fed8d 100644 --- a/hotspot/src/share/vm/memory/generation.cpp +++ b/hotspot/src/share/vm/memory/generation.cpp @@ -295,22 +295,16 @@ bool Generation::block_is_obj(const HeapWord* p) const { class GenerationOopIterateClosure : public SpaceClosure { public: - ExtendedOopClosure* cl; - MemRegion mr; + ExtendedOopClosure* _cl; virtual void do_space(Space* s) { - s->oop_iterate(mr, cl); + s->oop_iterate(_cl); } - GenerationOopIterateClosure(ExtendedOopClosure* _cl, MemRegion _mr) : - cl(_cl), mr(_mr) {} + GenerationOopIterateClosure(ExtendedOopClosure* cl) : + _cl(cl) {} }; void Generation::oop_iterate(ExtendedOopClosure* cl) { - GenerationOopIterateClosure blk(cl, _reserved); - space_iterate(&blk); -} - -void Generation::oop_iterate(MemRegion mr, ExtendedOopClosure* cl) { - GenerationOopIterateClosure blk(cl, mr); + GenerationOopIterateClosure blk(cl); space_iterate(&blk); } diff --git a/hotspot/src/share/vm/memory/generation.hpp b/hotspot/src/share/vm/memory/generation.hpp index e7cbd2c1226..f44f0245c36 100644 --- a/hotspot/src/share/vm/memory/generation.hpp +++ b/hotspot/src/share/vm/memory/generation.hpp @@ -543,10 +543,6 @@ class Generation: public CHeapObj { // generation, calling "cl.do_oop" on each. virtual void oop_iterate(ExtendedOopClosure* cl); - // Same as above, restricted to the intersection of a memory region and - // the generation. - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); - // Iterate over all objects in the generation, calling "cl.do_object" on // each. virtual void object_iterate(ObjectClosure* cl); diff --git a/hotspot/src/share/vm/memory/sharedHeap.hpp b/hotspot/src/share/vm/memory/sharedHeap.hpp index 21d6755d9d3..fef0a3da068 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.hpp +++ b/hotspot/src/share/vm/memory/sharedHeap.hpp @@ -163,9 +163,6 @@ public: // Iteration functions. void oop_iterate(ExtendedOopClosure* cl) = 0; - // Same as above, restricted to a memory region. - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl) = 0; - // Iterate over all spaces in use in the heap, in an undefined order. virtual void space_iterate(SpaceClosure* cl) = 0; diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index 7858a668293..4ea51d8a4fa 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -42,9 +42,6 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -void SpaceMemRegionOopsIterClosure::do_oop(oop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } -void SpaceMemRegionOopsIterClosure::do_oop(narrowOop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } - HeapWord* DirtyCardToOopClosure::get_actual_top(HeapWord* top, HeapWord* top_obj) { if (top_obj != NULL) { @@ -686,43 +683,6 @@ void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) { } } -void ContiguousSpace::oop_iterate(MemRegion mr, ExtendedOopClosure* blk) { - if (is_empty()) { - return; - } - MemRegion cur = MemRegion(bottom(), top()); - mr = mr.intersection(cur); - if (mr.is_empty()) { - return; - } - if (mr.equals(cur)) { - oop_iterate(blk); - return; - } - assert(mr.end() <= top(), "just took an intersection above"); - HeapWord* obj_addr = block_start(mr.start()); - HeapWord* t = mr.end(); - - // Handle first object specially. - oop obj = oop(obj_addr); - SpaceMemRegionOopsIterClosure smr_blk(blk, mr); - obj_addr += obj->oop_iterate(&smr_blk); - while (obj_addr < t) { - oop obj = oop(obj_addr); - assert(obj->is_oop(), "expected an oop"); - obj_addr += obj->size(); - // If "obj_addr" is not greater than top, then the - // entire object "obj" is within the region. - if (obj_addr <= t) { - obj->oop_iterate(blk); - } else { - // "obj" extends beyond end of region - obj->oop_iterate(&smr_blk); - break; - } - }; -} - void ContiguousSpace::object_iterate(ObjectClosure* blk) { if (is_empty()) return; WaterMark bm = bottom_mark(); diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index 245439f8e3a..d83b98048b3 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -81,31 +81,6 @@ class GenRemSet; class CardTableRS; class DirtyCardToOopClosure; -// An oop closure that is circumscribed by a filtering memory region. -class SpaceMemRegionOopsIterClosure: public ExtendedOopClosure { - private: - ExtendedOopClosure* _cl; - MemRegion _mr; - protected: - template void do_oop_work(T* p) { - if (_mr.contains(p)) { - _cl->do_oop(p); - } - } - public: - SpaceMemRegionOopsIterClosure(ExtendedOopClosure* cl, MemRegion mr): - _cl(cl), _mr(mr) {} - virtual void do_oop(oop* p); - virtual void do_oop(narrowOop* p); - virtual bool do_metadata() { - // _cl is of type ExtendedOopClosure instead of OopClosure, so that we can check this. - assert(!_cl->do_metadata(), "I've checked all call paths, this shouldn't happen."); - return false; - } - virtual void do_klass(Klass* k) { ShouldNotReachHere(); } - virtual void do_class_loader_data(ClassLoaderData* cld) { ShouldNotReachHere(); } -}; - // A Space describes a heap area. Class Space is an abstract // base class. // @@ -221,11 +196,6 @@ class Space: public CHeapObj { // applications of the closure are not included in the iteration. virtual void oop_iterate(ExtendedOopClosure* cl); - // Same as above, restricted to the intersection of a memory region and - // the space. Fields in objects allocated by applications of the closure - // are not included in the iteration. - virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl) = 0; - // Iterate over all objects in the space, calling "cl.do_object" on // each. Objects allocated by applications of the closure are not // included in the iteration. @@ -866,7 +836,6 @@ class ContiguousSpace: public CompactibleSpace { // Iteration void oop_iterate(ExtendedOopClosure* cl); - void oop_iterate(MemRegion mr, ExtendedOopClosure* cl); void object_iterate(ObjectClosure* blk); // For contiguous spaces this method will iterate safely over objects // in the space (i.e., between bottom and top) when at a safepoint. From 5b046a555f65aa731be2c2b127d909ffca482b68 Mon Sep 17 00:00:00 2001 From: Mattias Tobiasson Date: Fri, 4 Apr 2014 13:01:26 +0200 Subject: [PATCH 033/170] 8038822: java/lang/management/MemoryMXBean/LowMemoryTest2.sh still fails with OutOfMemoryError: Metaspace Force a GC when usage above threshold. Add more logging. Reviewed-by: dfuchs --- .../MemoryMXBean/LowMemoryTest2.java | 72 +++++++++++++------ .../management/MemoryMXBean/MemoryUtil.java | 2 + 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java index 638b053f086..01a8a3b47c4 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java +++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java @@ -64,6 +64,11 @@ public class LowMemoryTest2 { // low memory notification static class BoundlessLoaderThread extends ClassLoader implements Runnable { + private final List pools; + + public BoundlessLoaderThread(List pools) { + this.pools = pools; + } static int count = 100000; @@ -139,26 +144,29 @@ public class LowMemoryTest2 { * Then wait for the memory threshold notification to be received. */ public void run() { - List pools = ManagementFactory.getMemoryPoolMXBeans(); - boolean thresholdExceeded = false; - // Load classes until MemoryPoolMXBean.getUsageThresholdCount() > 0 - while (!thresholdExceeded) { - // the classes are small so we load 10 at a time - for (int i=0; i<10; i++) { - loadNext(); - } - - // check if the threshold has been exceeded - for (MemoryPoolMXBean p : pools) { - if (p.getType() == MemoryType.NON_HEAP && - p.isUsageThresholdSupported() && - p.getUsageThresholdCount() > 0) - { - thresholdExceeded = true; - break; + boolean isThresholdCountSet = false; + try { + while (!isThresholdCountSet) { + // the classes are small so we load 10 at a time + for (int i=0; i<10; i++) { + loadNext(); } + + if (isAnyUsageAboveThreshold(pools)) { + // UsageThresholdCount is only updated during GC. + // Force GC to update counters. + // If we don't force a GC we may get an + // OutOfMemoryException before the counters are updated. + System.out.println("Force GC"); + System.gc(); + } + isThresholdCountSet = isAnyThresholdCountSet(pools); } + } catch (OutOfMemoryError e) { + e.printStackTrace(); + MemoryUtil.printMemoryPools(pools); + throw e; } System.out.println("thresholdExceeded. Waiting for notification"); @@ -168,16 +176,39 @@ public class LowMemoryTest2 { } catch (InterruptedException x) {} } } + + private boolean isAnyUsageAboveThreshold(List pools) { + for (MemoryPoolMXBean p : pools) { + if (p.isUsageThresholdExceeded()) { + System.out.println("isAnyUsageAboveThreshold is true for " + p.getName()); + MemoryUtil.printMemoryPool(p); + return true; + } + } + return false; + } + + private boolean isAnyThresholdCountSet(List pools) { + for (MemoryPoolMXBean p : pools) { + if (p.getUsageThresholdCount() > 0) { + System.out.println("isAnyThresholdCountSet is true for " + p.getName()); + MemoryUtil.printMemoryPool(p); + return true; + } + } + return false; + } } public static void main(String args[]) { - List pools = ManagementFactory.getMemoryPoolMXBeans(); + // The pools list will only contain the pools that we are interested in. + List pools = new ArrayList(); // Set threshold of 80% of all NON_HEAP memory pools // In the Hotspot implementation this means we should get a notification // if the CodeCache or metaspace fills up. - for (MemoryPoolMXBean p : pools) { + for (MemoryPoolMXBean p : ManagementFactory.getMemoryPoolMXBeans()) { if (p.getType() == MemoryType.NON_HEAP && p.isUsageThresholdSupported()) { // set threshold @@ -190,6 +221,7 @@ public class LowMemoryTest2 { long threshold = (max * 80) / 100; p.setUsageThreshold(threshold); + pools.add(p); System.out.println("Selected memory pool for low memory " + "detection."); @@ -209,7 +241,7 @@ public class LowMemoryTest2 { // Start the thread loading classes - Thread thr = new Thread(new BoundlessLoaderThread()); + Thread thr = new Thread(new BoundlessLoaderThread(pools)); thr.start(); // Wait for the thread to terminate diff --git a/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java b/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java index f6b88ab59e1..55605c6c1c4 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java +++ b/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java @@ -54,6 +54,8 @@ public class MemoryUtil { pool.getUsage()); System.out.println(INDENT + "Threshold: " + (pool.isUsageThresholdSupported() ? pool.getUsageThreshold() : -1)); + System.out.println(INDENT + "ThresholdCount: " + + (pool.isUsageThresholdSupported() ? pool.getUsageThresholdCount() : -1)); System.out.print(INDENT + "Manager = ["); String[] mgrs = pool.getMemoryManagerNames(); for (int i = 0; i < mgrs.length; i++) { From efc809c16a3f7f918078b72c29a605a184558622 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Thu, 6 Mar 2014 17:31:07 +0000 Subject: [PATCH 034/170] 8036818: DateTimeFormatter withResolverFields() fails to accept null Reviewed-by: chegar, rriggs --- .../java/time/format/DateTimeFormatter.java | 12 +++++++----- .../tck/java/time/format/TCKDateTimeFormatter.java | 14 ++++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java index e92f3e9a122..3e1a2bdd2c9 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java @@ -1644,12 +1644,13 @@ public final class DateTimeFormatter { * @return a formatter based on this formatter with the requested resolver style, not null */ public DateTimeFormatter withResolverFields(TemporalField... resolverFields) { - Objects.requireNonNull(resolverFields, "resolverFields"); - Set fields = new HashSet<>(Arrays.asList(resolverFields)); + Set fields = null; + if (resolverFields != null) { + fields = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(resolverFields))); + } if (Objects.equals(this.resolverFields, fields)) { return this; } - fields = Collections.unmodifiableSet(fields); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone); } @@ -1693,11 +1694,12 @@ public final class DateTimeFormatter { * @return a formatter based on this formatter with the requested resolver style, not null */ public DateTimeFormatter withResolverFields(Set resolverFields) { - Objects.requireNonNull(resolverFields, "resolverFields"); if (Objects.equals(this.resolverFields, resolverFields)) { return this; } - resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields)); + if (resolverFields != null) { + resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields)); + } return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java index 8e2091e9888..9c0a783ec53 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java @@ -254,14 +254,20 @@ public class TCKDateTimeFormatter { assertEquals(parsed.isSupported(YEAR), false); // not in the list of resolverFields } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_resolverFields_Array_null() throws Exception { - DateTimeFormatter.ISO_DATE.withResolverFields((TemporalField[]) null); + DateTimeFormatter f = DateTimeFormatter.ISO_DATE.withResolverFields(MONTH_OF_YEAR); + assertEquals(f.getResolverFields().size(), 1); + f = f.withResolverFields((TemporalField[]) null); + assertEquals(f.getResolverFields(), null); } - @Test(expectedExceptions = NullPointerException.class) + @Test public void test_resolverFields_Set_null() throws Exception { - DateTimeFormatter.ISO_DATE.withResolverFields((Set) null); + DateTimeFormatter f = DateTimeFormatter.ISO_DATE.withResolverFields(MONTH_OF_YEAR); + assertEquals(f.getResolverFields().size(), 1); + f = f.withResolverFields((Set) null); + assertEquals(f.getResolverFields(), null); } //----------------------------------------------------------------------- From ce25911489a882ac6713353adeb57dc335051192 Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Mon, 10 Mar 2014 14:50:20 -0400 Subject: [PATCH 035/170] 8026154: [TESTBUG] runtime/CDSCompressedKPtrs/XShareAuto.java failed due to exception Added statements in the tests to handle failures in sharing Reviewed-by: zgu, ctornqvi --- .../CDSCompressedKPtrs/XShareAuto.java | 19 ++++++------------- .../CdsDifferentObjectAlignment.java | 9 ++++++--- .../DefaultUseWithClient.java | 10 ++++++++-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java index 480905f5dca..73f0c804312 100644 --- a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java +++ b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -22,7 +22,6 @@ */ /* - * @ignore 8026154 * @test * @bug 8005933 * @summary Test that -Xshare:auto uses CDS when explicitly specified with -server. @@ -50,21 +49,15 @@ public class XShareAuto { pb = ProcessTools.createJavaProcessBuilder( "-server", "-Xshare:auto", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-version"); + "-XX:SharedArchiveFile=./sample.jsa", "-XX:+PrintSharedSpaces", "-version"); output = new OutputAnalyzer(pb.start()); try { output.shouldContain("sharing"); - output.shouldHaveExitValue(0); } catch (RuntimeException e) { - // If this failed then check that it would also be unable - // to share even if -Xshare:on is specified. If so, then - // return a success status. - pb = ProcessTools.createJavaProcessBuilder( - "-server", "-Xshare:on", "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./sample.jsa", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Unable to use shared archive"); - output.shouldHaveExitValue(1); + // if sharing failed due to ASLR or similar reasons, + // check whether sharing was attempted at all (UseSharedSpaces) + output.shouldContain("UseSharedSpaces:"); } + output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java b/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java index 55eb104b050..9ecb1dae390 100644 --- a/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java +++ b/hotspot/test/runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -22,7 +22,6 @@ */ /* - * @ignore 8025642 * @test CdsDifferentObjectAlignment * @summary Testing CDS (class data sharing) using varying object alignment. * Using different object alignment for each dump/load pair. @@ -84,7 +83,11 @@ public class CdsDifferentObjectAlignment { createAlignment, loadAlignment); - output.shouldContain(expectedErrorMsg); + try { + output.shouldContain(expectedErrorMsg); + } catch (RuntimeException e) { + output.shouldContain("Unable to use shared archive"); + } output.shouldHaveExitValue(1); } } diff --git a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java index 5883fab7ecc..52cae81cc4f 100644 --- a/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java +++ b/hotspot/test/runtime/SharedArchiveFile/DefaultUseWithClient.java @@ -22,7 +22,6 @@ */ /* - * @ignore 8032224 * @test DefaultUseWithClient * @summary Test default behavior of sharing with -client * @library /testlibrary @@ -57,10 +56,17 @@ public class DefaultUseWithClient { "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./" + fileName, "-client", + "-XX:+PrintSharedSpaces", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("sharing"); + try { + output.shouldContain("sharing"); + } catch (RuntimeException e) { + // if sharing failed due to ASLR or similar reasons, + // check whether sharing was attempted at all (UseSharedSpaces) + output.shouldContain("UseSharedSpaces:"); + } output.shouldHaveExitValue(0); } } From 3c58faecfeb67b1e7ee665a2fd291fe0d5233089 Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Tue, 25 Mar 2014 09:26:18 -0400 Subject: [PATCH 036/170] 8032222: [TESTBUG] runtime/SharedArchiveFile/CdsWriteError.java fails on Mac OS with java.lang.RuntimeException Excluded the test from running on Mac OS Reviewed-by: coleenp, ctornqvi --- hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java b/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java index 05e469452ec..162f3ad4722 100644 --- a/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java +++ b/hotspot/test/runtime/SharedArchiveFile/CdsWriteError.java @@ -22,7 +22,6 @@ */ /* - * @ignore 8032222 * @test CdsWriteError * @summary Test how VM handles situation when it is impossible to write the * CDS archive. VM is expected to exit gracefully and display the @@ -46,6 +45,12 @@ public class CdsWriteError { return; } + // This test has been unstable for Mac OSx (see JDK-8032222) + if (Platform.isOSX()) { + System.out.println("This test is skipped on Mac"); + return; + } + String folderName = "tmp"; String fileName = folderName + File.separator + "empty.jsa"; From 472622d900ef957947d4db47e184648722342d02 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 26 Mar 2014 21:47:45 -0400 Subject: [PATCH 037/170] 8031820: NPG: Fix remaining references to metadata as oops in comments 8012125: Comments for ConstantPoolCache should reflect the addition of resolved_references in ConstantPool Updated comments in metadata header files, and renamed this_oop variables to this_cp or this_k when referring to constant pool or classes. Reviewed-by: stefank, jmasa --- hotspot/src/share/vm/memory/filemap.hpp | 6 +- hotspot/src/share/vm/oops/constMethod.hpp | 113 +++++------ hotspot/src/share/vm/oops/constantPool.cpp | 186 ++++++++--------- hotspot/src/share/vm/oops/constantPool.hpp | 35 ++-- hotspot/src/share/vm/oops/cpCache.cpp | 4 +- hotspot/src/share/vm/oops/cpCache.hpp | 7 +- hotspot/src/share/vm/oops/instanceKlass.cpp | 209 ++++++++++---------- hotspot/src/share/vm/oops/instanceKlass.hpp | 48 +---- hotspot/src/share/vm/oops/klass.cpp | 18 +- hotspot/src/share/vm/oops/klass.hpp | 34 +--- hotspot/src/share/vm/oops/method.cpp | 8 +- hotspot/src/share/vm/oops/method.hpp | 53 +---- hotspot/src/share/vm/utilities/debug.hpp | 3 +- 13 files changed, 308 insertions(+), 416 deletions(-) diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 0c93c87992b..166486fa3f0 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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,8 +32,8 @@ // header: dump of archive instance plus versioning info, datestamp, etc. // [magic # = 0xF00BABA2] // ... padding to align on page-boundary -// read-write space from CompactingPermGenGen -// read-only space from CompactingPermGenGen +// read-write space +// read-only space // misc data (block offset table, string table, symbols, dictionary, etc.) // tag(666) diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 21df75bdec0..8a8de131420 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -27,68 +27,61 @@ #include "oops/oop.hpp" -// An ConstMethod* represents portions of a Java method which -// do not vary. +// An ConstMethod represents portions of a Java method which are not written to after +// the classfile is parsed(*see below). This part of the method can be shared across +// processes in a read-only section with Class Data Sharing (CDS). It's important +// that this class doesn't have virtual functions because the vptr cannot be shared +// with CDS. +// (*)RewriteByteCodes and RewriteFrequentPairs is an exception but turned off in CDS // -// Memory layout (each line represents a word). Note that most -// applications load thousands of methods, so keeping the size of this +// Note that most applications load thousands of methods, so keeping the size of this // structure small has a big impact on footprint. + +// The actual bytecodes are inlined after the end of the ConstMethod struct. // -// |------------------------------------------------------| -// | header | -// | klass | -// |------------------------------------------------------| -// | fingerprint 1 | -// | fingerprint 2 | -// | constants (oop) | -// | stackmap_data (oop) | -// | constMethod_size | -// | interp_kind | flags | code_size | -// | name index | signature index | -// | method_idnum | max_stack | -// | max_locals | size_of_parameters | -// |------------------------------------------------------| -// | | -// | byte codes | -// | | -// |------------------------------------------------------| -// | compressed linenumber table | -// | (see class CompressedLineNumberReadStream) | -// | (note that length is unknown until decompressed) | -// | (access flags bit tells whether table is present) | -// | (indexed from start of ConstMethod*) | -// | (elements not necessarily sorted!) | -// |------------------------------------------------------| -// | localvariable table elements + length (length last) | -// | (length is u2, elements are 6-tuples of u2) | -// | (see class LocalVariableTableElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | exception table + length (length last) | -// | (length is u2, elements are 4-tuples of u2) | -// | (see class ExceptionTableElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | checked exceptions elements + length (length last) | -// | (length is u2, elements are u2) | -// | (see class CheckedExceptionElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | method parameters elements + length (length last) | -// | (length is u2, elements are u2, u4 structures) | -// | (see class MethodParametersElement) | -// | (access flags bit tells whether table is present) | -// | (indexed from end of ConstMethod*) | -// |------------------------------------------------------| -// | generic signature index (u2) | -// | (indexed from start of constMethodOop) | -// |------------------------------------------------------| -// | annotations arrays - method, parameter, type, default| -// | pointer to Array if annotation is present | -// |------------------------------------------------------| +// The line number table is compressed and inlined following the byte codes. It is +// found as the first byte following the byte codes. Note that accessing the line +// number and local variable tables is not performance critical at all. +// +// The checked exceptions table and the local variable table are inlined after the +// line number table, and indexed from the end of the method. We do not compress the +// checked exceptions table since the average length is less than 2, and it is used +// by reflection so access should be fast. We do not bother to compress the local +// variable table either since it is mostly absent. +// +// +// ConstMethod embedded field layout (after declared fields): +// [EMBEDDED byte codes] +// [EMBEDDED compressed linenumber table] +// (see class CompressedLineNumberReadStream) +// (note that length is unknown until decompressed) +// (access flags bit tells whether table is present) +// (indexed from start of ConstMethod) +// (elements not necessarily sorted!) +// [EMBEDDED localvariable table elements + length (length last)] +// (length is u2, elements are 6-tuples of u2) +// (see class LocalVariableTableElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED exception table + length (length last)] +// (length is u2, elements are 4-tuples of u2) +// (see class ExceptionTableElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED checked exceptions elements + length (length last)] +// (length is u2, elements are u2) +// (see class CheckedExceptionElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED method parameters elements + length (length last)] +// (length is u2, elements are u2, u4 structures) +// (see class MethodParametersElement) +// (access flags bit tells whether table is present) +// (indexed from end of ConstMethod*) +// [EMBEDDED generic signature index (u2)] +// (indexed from end of constMethodOop) +// [EMBEDDED annotations arrays - method, parameter, type, default] +// pointer to Array if annotation is present // // IMPORTANT: If anything gets added here, there need to be changes to // ensure that ServicabilityAgent doesn't get broken as a result! diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 9ed7628985d..f59a6d1d60b 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -180,12 +180,12 @@ int ConstantPool::cp_to_object_index(int cp_index) { return (i < 0) ? _no_index_sentinel : i; } -Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) { +Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS) { // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. // It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and // tag is not updated atomicly. - CPSlot entry = this_oop->slot_at(which); + CPSlot entry = this_cp->slot_at(which); if (entry.is_resolved()) { assert(entry.get_klass()->is_klass(), "must be"); // Already resolved - return entry. @@ -204,15 +204,15 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS Symbol* name = NULL; Handle loader; - { MonitorLockerEx ml(this_oop->lock()); + { MonitorLockerEx ml(this_cp->lock()); - if (this_oop->tag_at(which).is_unresolved_klass()) { - if (this_oop->tag_at(which).is_unresolved_klass_in_error()) { + if (this_cp->tag_at(which).is_unresolved_klass()) { + if (this_cp->tag_at(which).is_unresolved_klass_in_error()) { in_error = true; } else { do_resolve = true; - name = this_oop->unresolved_klass_at(which); - loader = Handle(THREAD, this_oop->pool_holder()->class_loader()); + name = this_cp->unresolved_klass_at(which); + loader = Handle(THREAD, this_cp->pool_holder()->class_loader()); } } } // unlocking constantPool @@ -221,26 +221,26 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS // The original attempt to resolve this constant pool entry failed so find the // original error and throw it again (JVMS 5.4.3). if (in_error) { - Symbol* error = SystemDictionary::find_resolution_error(this_oop, which); + Symbol* error = SystemDictionary::find_resolution_error(this_cp, which); guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table"); ResourceMark rm; // exception text will be the class name - const char* className = this_oop->unresolved_klass_at(which)->as_C_string(); + const char* className = this_cp->unresolved_klass_at(which)->as_C_string(); THROW_MSG_0(error, className); } if (do_resolve) { - // this_oop must be unlocked during resolve_or_fail - oop protection_domain = this_oop->pool_holder()->protection_domain(); + // this_cp must be unlocked during resolve_or_fail + oop protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (THREAD, protection_domain); - Klass* k_oop = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD); + Klass* kk = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD); KlassHandle k; if (!HAS_PENDING_EXCEPTION) { - k = KlassHandle(THREAD, k_oop); + k = KlassHandle(THREAD, kk); // preserve the resolved klass. - mirror_handle = Handle(THREAD, k_oop->java_mirror()); + mirror_handle = Handle(THREAD, kk->java_mirror()); // Do access check for klasses - verify_constant_pool_resolve(this_oop, k, THREAD); + verify_constant_pool_resolve(this_cp, k, THREAD); } // Failed to resolve class. We must record the errors so that subsequent attempts @@ -251,12 +251,12 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS bool throw_orig_error = false; { - MonitorLockerEx ml(this_oop->lock()); + MonitorLockerEx ml(this_cp->lock()); // some other thread has beaten us and has resolved the class. - if (this_oop->tag_at(which).is_klass()) { + if (this_cp->tag_at(which).is_klass()) { CLEAR_PENDING_EXCEPTION; - entry = this_oop->resolved_klass_at(which); + entry = this_cp->resolved_klass_at(which); return entry.get_klass(); } @@ -267,12 +267,12 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS // and OutOfMemoryError, etc, or if the thread was hit by stop() // Needs clarification to section 5.4.3 of the VM spec (see 6308271) } - else if (!this_oop->tag_at(which).is_unresolved_klass_in_error()) { - SystemDictionary::add_resolution_error(this_oop, which, error); - this_oop->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError); + else if (!this_cp->tag_at(which).is_unresolved_klass_in_error()) { + SystemDictionary::add_resolution_error(this_cp, which, error); + this_cp->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError); } else { // some other thread has put the class in error state. - error = SystemDictionary::find_resolution_error(this_oop, which); + error = SystemDictionary::find_resolution_error(this_cp, which); assert(error != NULL, "checking"); throw_orig_error = true; } @@ -281,7 +281,7 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS if (throw_orig_error) { CLEAR_PENDING_EXCEPTION; ResourceMark rm; - const char* className = this_oop->unresolved_klass_at(which)->as_C_string(); + const char* className = this_cp->unresolved_klass_at(which)->as_C_string(); THROW_MSG_0(error, className); } @@ -305,32 +305,32 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS } } } - if (k() != this_oop->pool_holder()) { + if (k() != this_cp->pool_holder()) { // only print something if the classes are different if (source_file != NULL) { tty->print("RESOLVE %s %s %s:%d\n", - this_oop->pool_holder()->external_name(), + this_cp->pool_holder()->external_name(), InstanceKlass::cast(k())->external_name(), source_file, line_number); } else { tty->print("RESOLVE %s %s\n", - this_oop->pool_holder()->external_name(), + this_cp->pool_holder()->external_name(), InstanceKlass::cast(k())->external_name()); } } return k(); } else { - MonitorLockerEx ml(this_oop->lock()); + MonitorLockerEx ml(this_cp->lock()); // Only updated constant pool - if it is resolved. - do_resolve = this_oop->tag_at(which).is_unresolved_klass(); + do_resolve = this_cp->tag_at(which).is_unresolved_klass(); if (do_resolve) { - ClassLoaderData* this_key = this_oop->pool_holder()->class_loader_data(); + ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data(); this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM - this_oop->klass_at_put(which, k()); + this_cp->klass_at_put(which, k()); } } } - entry = this_oop->resolved_klass_at(which); + entry = this_cp->resolved_klass_at(which); assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point"); return entry.get_klass(); } @@ -340,8 +340,8 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS // by compiler and exception handling. Also used to avoid classloads for // instanceof operations. Returns NULL if the class has not been loaded or // if the verification of constant pool failed -Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) { - CPSlot entry = this_oop->slot_at(which); +Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_cp, int which) { + CPSlot entry = this_cp->slot_at(which); if (entry.is_resolved()) { assert(entry.get_klass()->is_klass(), "must be"); return entry.get_klass(); @@ -349,8 +349,8 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) assert(entry.is_unresolved(), "must be either symbol or klass"); Thread *thread = Thread::current(); Symbol* name = entry.get_symbol(); - oop loader = this_oop->pool_holder()->class_loader(); - oop protection_domain = this_oop->pool_holder()->protection_domain(); + oop loader = this_cp->pool_holder()->class_loader(); + oop protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (thread, protection_domain); Handle h_loader (thread, loader); Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread); @@ -360,7 +360,7 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) EXCEPTION_MARK; KlassHandle klass(THREAD, k); // return NULL if verification fails - verify_constant_pool_resolve(this_oop, klass, THREAD); + verify_constant_pool_resolve(this_cp, klass, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return NULL; @@ -373,8 +373,8 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) } -Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_oop, int which) { - return klass_at_if_loaded(this_oop, this_oop->klass_ref_index_at(which)); +Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_cp, int which) { + return klass_at_if_loaded(this_cp, this_cp->klass_ref_index_at(which)); } @@ -486,11 +486,11 @@ int ConstantPool::remap_instruction_operand_from_cache(int operand) { } -void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle k, TRAPS) { +void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_cp, KlassHandle k, TRAPS) { if (k->oop_is_instance() || k->oop_is_objArray()) { - instanceKlassHandle holder (THREAD, this_oop->pool_holder()); - Klass* elem_oop = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass(); - KlassHandle element (THREAD, elem_oop); + instanceKlassHandle holder (THREAD, this_cp->pool_holder()); + Klass* elem = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass(); + KlassHandle element (THREAD, elem); // The element type could be a typeArray - we only need the access check if it is // an reference to another class @@ -559,10 +559,10 @@ BasicType ConstantPool::basic_type_for_signature_at(int which) { } -void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS) { - for (int index = 1; index < this_oop->length(); index++) { // Index 0 is unused - if (this_oop->tag_at(index).is_string()) { - this_oop->string_at(index, CHECK); +void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS) { + for (int index = 1; index < this_cp->length(); index++) { // Index 0 is unused + if (this_cp->tag_at(index).is_string()) { + this_cp->string_at(index, CHECK); } } } @@ -585,11 +585,11 @@ bool ConstantPool::resolve_class_constants(TRAPS) { // If resolution for MethodHandle or MethodType fails, save the exception // in the resolution error table, so that the same exception is thrown again. -void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int which, +void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int which, int tag, TRAPS) { ResourceMark rm; Symbol* error = PENDING_EXCEPTION->klass()->name(); - MonitorLockerEx ml(this_oop->lock()); // lock cpool to change tag. + MonitorLockerEx ml(this_cp->lock()); // lock cpool to change tag. int error_tag = (tag == JVM_CONSTANT_MethodHandle) ? JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError; @@ -601,12 +601,12 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int whi // and OutOfMemoryError, etc, or if the thread was hit by stop() // Needs clarification to section 5.4.3 of the VM spec (see 6308271) - } else if (this_oop->tag_at(which).value() != error_tag) { - SystemDictionary::add_resolution_error(this_oop, which, error); - this_oop->tag_at_put(which, error_tag); + } else if (this_cp->tag_at(which).value() != error_tag) { + SystemDictionary::add_resolution_error(this_cp, which, error); + this_cp->tag_at_put(which, error_tag); } else { // some other thread has put the class in error state. - error = SystemDictionary::find_resolution_error(this_oop, which); + error = SystemDictionary::find_resolution_error(this_cp, which); assert(error != NULL, "checking"); CLEAR_PENDING_EXCEPTION; THROW_MSG(error, ""); @@ -617,7 +617,7 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int whi // Called to resolve constants in the constant pool and return an oop. // Some constant pool entries cache their resolved oop. This is also // called to create oops from constants to use in arguments for invokedynamic -oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) { +oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS) { oop result_oop = NULL; Handle throw_exception; @@ -625,23 +625,23 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde // It is possible that this constant is one which is cached in the objects. // We'll do a linear search. This should be OK because this usage is rare. assert(index > 0, "valid index"); - cache_index = this_oop->cp_to_object_index(index); + cache_index = this_cp->cp_to_object_index(index); } assert(cache_index == _no_index_sentinel || cache_index >= 0, ""); assert(index == _no_index_sentinel || index >= 0, ""); if (cache_index >= 0) { - result_oop = this_oop->resolved_references()->obj_at(cache_index); + result_oop = this_cp->resolved_references()->obj_at(cache_index); if (result_oop != NULL) { return result_oop; // That was easy... } - index = this_oop->object_to_cp_index(cache_index); + index = this_cp->object_to_cp_index(cache_index); } jvalue prim_value; // temp used only in a few cases below - int tag_value = this_oop->tag_at(index).value(); + int tag_value = this_cp->tag_at(index).value(); switch (tag_value) { @@ -650,7 +650,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde case JVM_CONSTANT_Class: { assert(cache_index == _no_index_sentinel, "should not have been set"); - Klass* resolved = klass_at_impl(this_oop, index, CHECK_NULL); + Klass* resolved = klass_at_impl(this_cp, index, CHECK_NULL); // ldc wants the java mirror. result_oop = resolved->java_mirror(); break; @@ -658,17 +658,17 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde case JVM_CONSTANT_String: assert(cache_index != _no_index_sentinel, "should have been set"); - if (this_oop->is_pseudo_string_at(index)) { - result_oop = this_oop->pseudo_string_at(index, cache_index); + if (this_cp->is_pseudo_string_at(index)) { + result_oop = this_cp->pseudo_string_at(index, cache_index); break; } - result_oop = string_at_impl(this_oop, index, cache_index, CHECK_NULL); + result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL); break; case JVM_CONSTANT_MethodHandleInError: case JVM_CONSTANT_MethodTypeInError: { - Symbol* error = SystemDictionary::find_resolution_error(this_oop, index); + Symbol* error = SystemDictionary::find_resolution_error(this_cp, index); guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table"); ResourceMark rm; THROW_MSG_0(error, ""); @@ -677,72 +677,72 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde case JVM_CONSTANT_MethodHandle: { - int ref_kind = this_oop->method_handle_ref_kind_at(index); - int callee_index = this_oop->method_handle_klass_index_at(index); - Symbol* name = this_oop->method_handle_name_ref_at(index); - Symbol* signature = this_oop->method_handle_signature_ref_at(index); + int ref_kind = this_cp->method_handle_ref_kind_at(index); + int callee_index = this_cp->method_handle_klass_index_at(index); + Symbol* name = this_cp->method_handle_name_ref_at(index); + Symbol* signature = this_cp->method_handle_signature_ref_at(index); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", - ref_kind, index, this_oop->method_handle_index_at(index), + ref_kind, index, this_cp->method_handle_index_at(index), callee_index, name->as_C_string(), signature->as_C_string()); KlassHandle callee; - { Klass* k = klass_at_impl(this_oop, callee_index, CHECK_NULL); + { Klass* k = klass_at_impl(this_cp, callee_index, CHECK_NULL); callee = KlassHandle(THREAD, k); } - KlassHandle klass(THREAD, this_oop->pool_holder()); + KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, THREAD); result_oop = value(); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL); + save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL); } break; } case JVM_CONSTANT_MethodType: { - Symbol* signature = this_oop->method_type_signature_at(index); + Symbol* signature = this_cp->method_type_signature_at(index); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s", - index, this_oop->method_type_index_at(index), + index, this_cp->method_type_index_at(index), signature->as_C_string()); - KlassHandle klass(THREAD, this_oop->pool_holder()); + KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD); result_oop = value(); if (HAS_PENDING_EXCEPTION) { - save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL); + save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL); } break; } case JVM_CONSTANT_Integer: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.i = this_oop->int_at(index); + prim_value.i = this_cp->int_at(index); result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Float: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.f = this_oop->float_at(index); + prim_value.f = this_cp->float_at(index); result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Long: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.j = this_oop->long_at(index); + prim_value.j = this_cp->long_at(index); result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL); break; case JVM_CONSTANT_Double: assert(cache_index == _no_index_sentinel, "should not have been set"); - prim_value.d = this_oop->double_at(index); + prim_value.d = this_cp->double_at(index); result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL); break; default: DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", - this_oop(), index, cache_index, tag_value) ); + this_cp(), index, cache_index, tag_value) ); assert(false, "unexpected constant tag"); break; } @@ -750,15 +750,15 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde if (cache_index >= 0) { // Cache the oop here also. Handle result_handle(THREAD, result_oop); - MonitorLockerEx ml(this_oop->lock()); // don't know if we really need this - oop result = this_oop->resolved_references()->obj_at(cache_index); + MonitorLockerEx ml(this_cp->lock()); // don't know if we really need this + oop result = this_cp->resolved_references()->obj_at(cache_index); // Benign race condition: resolved_references may already be filled in while we were trying to lock. // The important thing here is that all threads pick up the same result. // It doesn't matter which racing thread wins, as long as only one // result is used by all threads, and all future queries. // That result may be either a resolved constant or a failure exception. if (result == NULL) { - this_oop->resolved_references()->obj_at_put(cache_index, result_handle()); + this_cp->resolved_references()->obj_at_put(cache_index, result_handle()); return result_handle(); } else { // Return the winning thread's result. This can be different than @@ -778,8 +778,8 @@ oop ConstantPool::uncached_string_at(int which, TRAPS) { } -oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS) { - assert(this_oop->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool"); +oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS) { + assert(this_cp->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool"); Handle bsm; int argc; @@ -787,14 +787,14 @@ oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oo // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry. // It is accompanied by the optional arguments. - int bsm_index = this_oop->invoke_dynamic_bootstrap_method_ref_index_at(index); - oop bsm_oop = this_oop->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL); + int bsm_index = this_cp->invoke_dynamic_bootstrap_method_ref_index_at(index); + oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL); if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) { THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle"); } // Extract the optional static arguments. - argc = this_oop->invoke_dynamic_argument_count_at(index); + argc = this_cp->invoke_dynamic_argument_count_at(index); if (argc == 0) return bsm_oop; bsm = Handle(THREAD, bsm_oop); @@ -808,21 +808,21 @@ oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oo info->obj_at_put(0, bsm()); for (int i = 0; i < argc; i++) { - int arg_index = this_oop->invoke_dynamic_argument_index_at(index, i); - oop arg_oop = this_oop->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL); + int arg_index = this_cp->invoke_dynamic_argument_index_at(index, i); + oop arg_oop = this_cp->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL); info->obj_at_put(1+i, arg_oop); } return info(); } -oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS) { +oop ConstantPool::string_at_impl(constantPoolHandle this_cp, int which, int obj_index, TRAPS) { // If the string has already been interned, this entry will be non-null - oop str = this_oop->resolved_references()->obj_at(obj_index); + oop str = this_cp->resolved_references()->obj_at(obj_index); if (str != NULL) return str; - Symbol* sym = this_oop->unresolved_string_at(which); + Symbol* sym = this_cp->unresolved_string_at(which); str = StringTable::intern(sym, CHECK_(NULL)); - this_oop->string_at_put(which, obj_index, str); + this_cp->string_at_put(which, obj_index, str); assert(java_lang_String::is_instance(str), "must be string"); return str; } diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 497df53d778..169d97f4266 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -48,7 +48,7 @@ # include "bytes_ppc.hpp" #endif -// A constantPool is an array containing class constants as described in the +// A ConstantPool is an array containing class constants as described in the // class file. // // Most of the constant pool entries are written during class parsing, which @@ -81,9 +81,10 @@ class CPSlot VALUE_OBJ_CLASS_SPEC { }; class KlassSizeStats; + class ConstantPool : public Metadata { friend class VMStructs; - friend class BytecodeInterpreter; // Directly extracts an oop in the pool for fast instanceof/checkcast + friend class BytecodeInterpreter; // Directly extracts a klass in the pool for fast instanceof/checkcast friend class Universe; // For null constructor private: Array* _tags; // the tag array describing the constant pool's contents @@ -747,13 +748,13 @@ class ConstantPool : public Metadata { friend class SystemDictionary; // Used by compiler to prevent classloading. - static Method* method_at_if_loaded (constantPoolHandle this_oop, int which); - static bool has_appendix_at_if_loaded (constantPoolHandle this_oop, int which); - static oop appendix_at_if_loaded (constantPoolHandle this_oop, int which); - static bool has_method_type_at_if_loaded (constantPoolHandle this_oop, int which); - static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which); - static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which); - static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which); + static Method* method_at_if_loaded (constantPoolHandle this_cp, int which); + static bool has_appendix_at_if_loaded (constantPoolHandle this_cp, int which); + static oop appendix_at_if_loaded (constantPoolHandle this_cp, int which); + static bool has_method_type_at_if_loaded (constantPoolHandle this_cp, int which); + static oop method_type_at_if_loaded (constantPoolHandle this_cp, int which); + static Klass* klass_at_if_loaded (constantPoolHandle this_cp, int which); + static Klass* klass_ref_at_if_loaded (constantPoolHandle this_cp, int which); // Routines currently used for annotations (only called by jvm.cpp) but which might be used in the // future by other Java code. These take constant pool indices rather than @@ -811,19 +812,19 @@ class ConstantPool : public Metadata { } // Performs the LinkResolver checks - static void verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle klass, TRAPS); + static void verify_constant_pool_resolve(constantPoolHandle this_cp, KlassHandle klass, TRAPS); // Implementation of methods that needs an exposed 'this' pointer, in order to // handle GC while executing the method - static Klass* klass_at_impl(constantPoolHandle this_oop, int which, TRAPS); - static oop string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS); + static Klass* klass_at_impl(constantPoolHandle this_cp, int which, TRAPS); + static oop string_at_impl(constantPoolHandle this_cp, int which, int obj_index, TRAPS); // Resolve string constants (to prevent allocation during compilation) - static void resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS); + static void resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS); - static oop resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS); - static void save_and_throw_exception(constantPoolHandle this_oop, int which, int tag_value, TRAPS); - static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS); + static oop resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS); + static void save_and_throw_exception(constantPoolHandle this_cp, int which, int tag_value, TRAPS); + static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS); public: // Merging ConstantPool* support: diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 5e93cd6c803..5e75ad8917e 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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 @@ -328,7 +328,7 @@ void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool, // the f1 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;', // not '(Ljava/lang/String;)Ljava/util/List;'. // The fact that String and List are involved is encoded in the MethodType in refs[f2]. - // This allows us to create fewer method oops, while keeping type safety. + // This allows us to create fewer Methods, while keeping type safety. // objArrayHandle resolved_references = cpool->resolved_references(); diff --git a/hotspot/src/share/vm/oops/cpCache.hpp b/hotspot/src/share/vm/oops/cpCache.hpp index 49559be5e2e..1bc7a417938 100644 --- a/hotspot/src/share/vm/oops/cpCache.hpp +++ b/hotspot/src/share/vm/oops/cpCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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 @@ -102,8 +102,9 @@ class PSPromotionManager; // _f1 = Method* for non-virtual calls, unused by virtual calls. // for interface calls, which are essentially virtual but need a klass, // contains Klass* for the corresponding interface. -// for invokedynamic, f1 contains a site-specific CallSite object (as an appendix) -// for invokehandle, f1 contains a site-specific MethodType object (as an appendix) +// for invokedynamic and invokehandle, f1 contains the adapter method which +// manages the actual call. The appendix is stored in the ConstantPool +// resolved_references array. // (upcoming metadata changes will move the appendix to a separate array) // _f2 = vtable/itable index (or final Method*) for virtual calls only, // unused by non-virtual. The is_vfinal flag indicates this is a diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 976386978ce..9e6080a8266 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -432,8 +432,8 @@ void InstanceKlass::eager_initialize(Thread *thread) { if (!InstanceKlass::cast(super)->is_initialized()) return; // call body to expose the this pointer - instanceKlassHandle this_oop(thread, this); - eager_initialize_impl(this_oop); + instanceKlassHandle this_k(thread, this); + eager_initialize_impl(this_k); } } @@ -470,16 +470,16 @@ void InstanceKlass::fence_and_clear_init_lock() { assert(!is_not_initialized(), "class must be initialized now"); } -void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { +void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_k) { EXCEPTION_MARK; - oop init_lock = this_oop->init_lock(); + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // abort if someone beat us to the initialization - if (!this_oop->is_not_initialized()) return; // note: not equivalent to is_initialized() + if (!this_k->is_not_initialized()) return; // note: not equivalent to is_initialized() - ClassState old_state = this_oop->init_state(); - link_class_impl(this_oop, true, THREAD); + ClassState old_state = this_k->init_state(); + link_class_impl(this_k, true, THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; // Abort if linking the class throws an exception. @@ -487,16 +487,16 @@ void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { // Use a test to avoid redundantly resetting the state if there's // no change. Set_init_state() asserts that state changes make // progress, whereas here we might just be spinning in place. - if( old_state != this_oop->_init_state ) - this_oop->set_init_state (old_state); + if( old_state != this_k->_init_state ) + this_k->set_init_state (old_state); } else { // linking successfull, mark class as initialized - this_oop->set_init_state (fully_initialized); - this_oop->fence_and_clear_init_lock(); + this_k->set_init_state (fully_initialized); + this_k->fence_and_clear_init_lock(); // trace if (TraceClassInitialization) { ResourceMark rm(THREAD); - tty->print_cr("[Initialized %s without side effects]", this_oop->external_name()); + tty->print_cr("[Initialized %s without side effects]", this_k->external_name()); } } } @@ -508,8 +508,8 @@ void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) { void InstanceKlass::initialize(TRAPS) { if (this->should_be_initialized()) { HandleMark hm(THREAD); - instanceKlassHandle this_oop(THREAD, this); - initialize_impl(this_oop, CHECK); + instanceKlassHandle this_k(THREAD, this); + initialize_impl(this_k, CHECK); // Note: at this point the class may be initialized // OR it may be in the state of being initialized // in case of recursive initialization! @@ -520,11 +520,11 @@ void InstanceKlass::initialize(TRAPS) { bool InstanceKlass::verify_code( - instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { + instanceKlassHandle this_k, bool throw_verifyerror, TRAPS) { // 1) Verify the bytecodes Verifier::Mode mode = throw_verifyerror ? Verifier::ThrowException : Verifier::NoException; - return Verifier::verify(this_oop, mode, this_oop->should_verify_class(), CHECK_false); + return Verifier::verify(this_k, mode, this_k->should_verify_class(), CHECK_false); } @@ -540,8 +540,8 @@ void InstanceKlass::link_class(TRAPS) { assert(is_loaded(), "must be loaded"); if (!is_linked()) { HandleMark hm(THREAD); - instanceKlassHandle this_oop(THREAD, this); - link_class_impl(this_oop, true, CHECK); + instanceKlassHandle this_k(THREAD, this); + link_class_impl(this_k, true, CHECK); } } @@ -551,22 +551,22 @@ bool InstanceKlass::link_class_or_fail(TRAPS) { assert(is_loaded(), "must be loaded"); if (!is_linked()) { HandleMark hm(THREAD); - instanceKlassHandle this_oop(THREAD, this); - link_class_impl(this_oop, false, CHECK_false); + instanceKlassHandle this_k(THREAD, this); + link_class_impl(this_k, false, CHECK_false); } return is_linked(); } bool InstanceKlass::link_class_impl( - instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { + instanceKlassHandle this_k, bool throw_verifyerror, TRAPS) { // check for error state - if (this_oop->is_in_error_state()) { + if (this_k->is_in_error_state()) { ResourceMark rm(THREAD); THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(), - this_oop->external_name(), false); + this_k->external_name(), false); } // return if already verified - if (this_oop->is_linked()) { + if (this_k->is_linked()) { return true; } @@ -576,7 +576,7 @@ bool InstanceKlass::link_class_impl( JavaThread* jt = (JavaThread*)THREAD; // link super class before linking this class - instanceKlassHandle super(THREAD, this_oop->super()); + instanceKlassHandle super(THREAD, this_k->super()); if (super.not_null()) { if (super->is_interface()) { // check if super class is an interface ResourceMark rm(THREAD); @@ -584,7 +584,7 @@ bool InstanceKlass::link_class_impl( THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), "class %s has interface %s as super class", - this_oop->external_name(), + this_k->external_name(), super->external_name() ); return false; @@ -594,7 +594,7 @@ bool InstanceKlass::link_class_impl( } // link all interfaces implemented by this class before linking this class - Array* interfaces = this_oop->local_interfaces(); + Array* interfaces = this_k->local_interfaces(); int num_interfaces = interfaces->length(); for (int index = 0; index < num_interfaces; index++) { HandleMark hm(THREAD); @@ -603,7 +603,7 @@ bool InstanceKlass::link_class_impl( } // in case the class is linked in the process of linking its superclasses - if (this_oop->is_linked()) { + if (this_k->is_linked()) { return true; } @@ -618,14 +618,14 @@ bool InstanceKlass::link_class_impl( // verification & rewriting { - oop init_lock = this_oop->init_lock(); + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); // rewritten will have been set if loader constraint error found // on an earlier link attempt // don't verify or rewrite if already rewritten - if (!this_oop->is_linked()) { - if (!this_oop->is_rewritten()) { + if (!this_k->is_linked()) { + if (!this_k->is_rewritten()) { { // Timer includes any side effects of class verification (resolution, // etc), but not recursive entry into verify_code(). @@ -635,7 +635,7 @@ bool InstanceKlass::link_class_impl( jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_VERIFY); - bool verify_ok = verify_code(this_oop, throw_verifyerror, THREAD); + bool verify_ok = verify_code(this_k, throw_verifyerror, THREAD); if (!verify_ok) { return false; } @@ -644,39 +644,39 @@ bool InstanceKlass::link_class_impl( // Just in case a side-effect of verify linked this class already // (which can sometimes happen since the verifier loads classes // using custom class loaders, which are free to initialize things) - if (this_oop->is_linked()) { + if (this_k->is_linked()) { return true; } // also sets rewritten - this_oop->rewrite_class(CHECK_false); + this_k->rewrite_class(CHECK_false); } // relocate jsrs and link methods after they are all rewritten - this_oop->link_methods(CHECK_false); + this_k->link_methods(CHECK_false); // Initialize the vtable and interface table after // methods have been rewritten since rewrite may // fabricate new Method*s. // also does loader constraint checking - if (!this_oop()->is_shared()) { + if (!this_k()->is_shared()) { ResourceMark rm(THREAD); - this_oop->vtable()->initialize_vtable(true, CHECK_false); - this_oop->itable()->initialize_itable(true, CHECK_false); + this_k->vtable()->initialize_vtable(true, CHECK_false); + this_k->itable()->initialize_itable(true, CHECK_false); } #ifdef ASSERT else { ResourceMark rm(THREAD); - this_oop->vtable()->verify(tty, true); + this_k->vtable()->verify(tty, true); // In case itable verification is ever added. - // this_oop->itable()->verify(tty, true); + // this_k->itable()->verify(tty, true); } #endif - this_oop->set_init_state(linked); + this_k->set_init_state(linked); if (JvmtiExport::should_post_class_prepare()) { Thread *thread = THREAD; assert(thread->is_Java_thread(), "thread->is_Java_thread()"); - JvmtiExport::post_class_prepare((JavaThread *) thread, this_oop()); + JvmtiExport::post_class_prepare((JavaThread *) thread, this_k()); } } } @@ -689,13 +689,13 @@ bool InstanceKlass::link_class_impl( // verification but before the first method of the class is executed. void InstanceKlass::rewrite_class(TRAPS) { assert(is_loaded(), "must be loaded"); - instanceKlassHandle this_oop(THREAD, this); - if (this_oop->is_rewritten()) { - assert(this_oop()->is_shared(), "rewriting an unshared class?"); + instanceKlassHandle this_k(THREAD, this); + if (this_k->is_rewritten()) { + assert(this_k()->is_shared(), "rewriting an unshared class?"); return; } - Rewriter::rewrite(this_oop, CHECK); - this_oop->set_rewritten(); + Rewriter::rewrite(this_k, CHECK); + this_k->set_rewritten(); } // Now relocate and link method entry points after class is rewritten. @@ -729,19 +729,19 @@ void InstanceKlass::link_methods(TRAPS) { } -void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { +void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) { // Make sure klass is linked (verified) before initialization // A class could already be verified, since it has been reflected upon. - this_oop->link_class(CHECK); + this_k->link_class(CHECK); - DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_oop()), -1); + DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_k()), -1); bool wait = false; // refer to the JVM book page 47 for description of steps // Step 1 { - oop init_lock = this_oop->init_lock(); + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); Thread *self = THREAD; // it's passed the current thread @@ -750,29 +750,29 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { // If we were to use wait() instead of waitInterruptibly() then // we might end up throwing IE from link/symbol resolution sites // that aren't expected to throw. This would wreak havoc. See 6320309. - while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) { + while(this_k->is_being_initialized() && !this_k->is_reentrant_initialization(self)) { wait = true; ol.waitUninterruptibly(CHECK); } // Step 3 - if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) { - DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_oop()), -1,wait); + if (this_k->is_being_initialized() && this_k->is_reentrant_initialization(self)) { + DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_k()), -1,wait); return; } // Step 4 - if (this_oop->is_initialized()) { - DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_oop()), -1,wait); + if (this_k->is_initialized()) { + DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_k()), -1,wait); return; } // Step 5 - if (this_oop->is_in_error_state()) { - DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_oop()), -1,wait); + if (this_k->is_in_error_state()) { + DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_k()), -1,wait); ResourceMark rm(THREAD); const char* desc = "Could not initialize class "; - const char* className = this_oop->external_name(); + const char* className = this_k->external_name(); size_t msglen = strlen(desc) + strlen(className) + 1; char* message = NEW_RESOURCE_ARRAY(char, msglen); if (NULL == message) { @@ -785,13 +785,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { } // Step 6 - this_oop->set_init_state(being_initialized); - this_oop->set_init_thread(self); + this_k->set_init_state(being_initialized); + this_k->set_init_thread(self); } // Step 7 - Klass* super_klass = this_oop->super(); - if (super_klass != NULL && !this_oop->is_interface() && super_klass->should_be_initialized()) { + Klass* super_klass = this_k->super(); + if (super_klass != NULL && !this_k->is_interface() && super_klass->should_be_initialized()) { super_klass->initialize(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -799,18 +799,18 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { CLEAR_PENDING_EXCEPTION; { EXCEPTION_MARK; - this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads + this_k->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below } - DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_k()), -1,wait); THROW_OOP(e()); } } - if (this_oop->has_default_methods()) { + if (this_k->has_default_methods()) { // Step 7.5: initialize any interfaces which have default methods - for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) { - Klass* iface = this_oop->local_interfaces()->at(i); + for (int i = 0; i < this_k->local_interfaces()->length(); ++i) { + Klass* iface = this_k->local_interfaces()->at(i); InstanceKlass* ik = InstanceKlass::cast(iface); if (ik->has_default_methods() && ik->should_be_initialized()) { ik->initialize(THREAD); @@ -821,7 +821,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { { EXCEPTION_MARK; // Locks object, set state, and notify all waiting threads - this_oop->set_initialization_state_and_notify( + this_k->set_initialization_state_and_notify( initialization_error, THREAD); // ignore any exception thrown, superclass initialization error is @@ -829,7 +829,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { CLEAR_PENDING_EXCEPTION; } DTRACE_CLASSINIT_PROBE_WAIT( - super__failed, InstanceKlass::cast(this_oop()), -1, wait); + super__failed, InstanceKlass::cast(this_k()), -1, wait); THROW_OOP(e()); } } @@ -840,7 +840,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { { assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl"); JavaThread* jt = (JavaThread*)THREAD; - DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_k()), -1,wait); // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). PerfClassTraceTime timer(ClassLoader::perf_class_init_time(), @@ -849,14 +849,14 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { jt->get_thread_stat()->perf_recursion_counts_addr(), jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_CLINIT); - this_oop->call_class_initializer(THREAD); + this_k->call_class_initializer(THREAD); } // Step 9 if (!HAS_PENDING_EXCEPTION) { - this_oop->set_initialization_state_and_notify(fully_initialized, CHECK); + this_k->set_initialization_state_and_notify(fully_initialized, CHECK); { ResourceMark rm(THREAD); - debug_only(this_oop->vtable()->verify(tty, true);) + debug_only(this_k->vtable()->verify(tty, true);) } } else { @@ -868,13 +868,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { JvmtiExport::clear_detected_exception((JavaThread*)THREAD); { EXCEPTION_MARK; - this_oop->set_initialization_state_and_notify(initialization_error, THREAD); + this_k->set_initialization_state_and_notify(initialization_error, THREAD); CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below // JVMTI has already reported the pending exception // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError JvmtiExport::clear_detected_exception((JavaThread*)THREAD); } - DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_k()), -1,wait); if (e->is_a(SystemDictionary::Error_klass())) { THROW_OOP(e()); } else { @@ -884,7 +884,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { &args); } } - DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_oop()), -1,wait); + DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_k()), -1,wait); } @@ -894,11 +894,11 @@ void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS) set_initialization_state_and_notify_impl(kh, state, CHECK); } -void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) { - oop init_lock = this_oop->init_lock(); +void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_k, ClassState state, TRAPS) { + oop init_lock = this_k->init_lock(); ObjectLocker ol(init_lock, THREAD, init_lock != NULL); - this_oop->set_init_state(state); - this_oop->fence_and_clear_init_lock(); + this_k->set_init_state(state); + this_k->fence_and_clear_init_lock(); ol.notify_all(CHECK); } @@ -952,12 +952,11 @@ void InstanceKlass::init_implementor() { void InstanceKlass::process_interfaces(Thread *thread) { // link this class into the implementors list of every interface it implements - Klass* this_as_klass_oop = this; for (int i = local_interfaces()->length() - 1; i >= 0; i--) { assert(local_interfaces()->at(i)->is_klass(), "must be a klass"); InstanceKlass* interf = InstanceKlass::cast(local_interfaces()->at(i)); assert(interf->is_interface(), "expected interface"); - interf->add_implementor(this_as_klass_oop); + interf->add_implementor(this); } } @@ -1083,12 +1082,12 @@ void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) { } Klass* InstanceKlass::array_klass_impl(bool or_null, int n, TRAPS) { - instanceKlassHandle this_oop(THREAD, this); - return array_klass_impl(this_oop, or_null, n, THREAD); + instanceKlassHandle this_k(THREAD, this); + return array_klass_impl(this_k, or_null, n, THREAD); } -Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_oop, bool or_null, int n, TRAPS) { - if (this_oop->array_klasses() == NULL) { +Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_k, bool or_null, int n, TRAPS) { + if (this_k->array_klasses() == NULL) { if (or_null) return NULL; ResourceMark rm; @@ -1099,14 +1098,14 @@ Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_oop, bool or_nul MutexLocker ma(MultiArray_lock, THREAD); // Check if update has already taken place - if (this_oop->array_klasses() == NULL) { - Klass* k = ObjArrayKlass::allocate_objArray_klass(this_oop->class_loader_data(), 1, this_oop, CHECK_NULL); - this_oop->set_array_klasses(k); + if (this_k->array_klasses() == NULL) { + Klass* k = ObjArrayKlass::allocate_objArray_klass(this_k->class_loader_data(), 1, this_k, CHECK_NULL); + this_k->set_array_klasses(k); } } } // _this will always be set at this point - ObjArrayKlass* oak = (ObjArrayKlass*)this_oop->array_klasses(); + ObjArrayKlass* oak = (ObjArrayKlass*)this_k->array_klasses(); if (or_null) { return oak->array_klass_or_null(n); } @@ -1133,20 +1132,20 @@ Method* InstanceKlass::class_initializer() { return NULL; } -void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) { +void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_k, TRAPS) { if (ReplayCompiles && (ReplaySuppressInitializers == 1 || - ReplaySuppressInitializers >= 2 && this_oop->class_loader() != NULL)) { + ReplaySuppressInitializers >= 2 && this_k->class_loader() != NULL)) { // Hide the existence of the initializer for the purpose of replaying the compile return; } - methodHandle h_method(THREAD, this_oop->class_initializer()); - assert(!this_oop->is_initialized(), "we cannot initialize twice"); + methodHandle h_method(THREAD, this_k->class_initializer()); + assert(!this_k->is_initialized(), "we cannot initialize twice"); if (TraceClassInitialization) { tty->print("%d Initializing ", call_class_initializer_impl_counter++); - this_oop->name()->print_value(); - tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_oop()); + this_k->name()->print_value(); + tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_k()); } if (h_method() != NULL) { JavaCallArguments args; // No arguments @@ -1296,8 +1295,8 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAP } -void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) { - for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) { +void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_k, void f(fieldDescriptor* fd, TRAPS), TRAPS) { + for (JavaFieldStream fs(this_k()); !fs.done(); fs.next()) { if (fs.access_flags().is_static()) { fieldDescriptor& fd = fs.field_descriptor(); f(&fd, CHECK); @@ -1515,14 +1514,14 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, } /* jni_id_for_impl for jfieldIds only */ -JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_oop, int offset) { +JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_k, int offset) { MutexLocker ml(JfieldIdCreation_lock); // Retry lookup after we got the lock - JNIid* probe = this_oop->jni_ids() == NULL ? NULL : this_oop->jni_ids()->find(offset); + JNIid* probe = this_k->jni_ids() == NULL ? NULL : this_k->jni_ids()->find(offset); if (probe == NULL) { // Slow case, allocate new static field identifier - probe = new JNIid(this_oop(), offset, this_oop->jni_ids()); - this_oop->set_jni_ids(probe); + probe = new JNIid(this_k(), offset, this_k->jni_ids()); + this_k->set_jni_ids(probe); } return probe; } @@ -3161,8 +3160,8 @@ void InstanceKlass::verify_on(outputStream* st) { } // Verify first subklass - if (subklass_oop() != NULL) { - guarantee(subklass_oop()->is_klass(), "should be klass"); + if (subklass() != NULL) { + guarantee(subklass()->is_klass(), "should be klass"); } // Verify siblings diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index b25c75afc3b..6525c538af9 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -43,35 +43,7 @@ // An InstanceKlass is the VM level representation of a Java class. // It contains all information needed for at class at execution runtime. -// InstanceKlass layout: -// [C++ vtbl pointer ] Klass -// [subtype cache ] Klass -// [instance size ] Klass -// [java mirror ] Klass -// [super ] Klass -// [access_flags ] Klass -// [name ] Klass -// [first subklass ] Klass -// [next sibling ] Klass -// [array klasses ] -// [methods ] -// [local interfaces ] -// [transitive interfaces ] -// [fields ] -// [constants ] -// [class loader ] -// [source file name ] -// [inner classes ] -// [static field size ] -// [nonstatic field size ] -// [static oop fields size ] -// [nonstatic oop maps size ] -// [has finalize method ] -// [deoptimization mark bit ] -// [initialization state ] -// [initializing thread ] -// [Java vtable length ] -// [oop map cache (stack maps) ] +// InstanceKlass embedded field layout (after declared fields): // [EMBEDDED Java vtable ] size in words = vtable_len // [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size // The embedded nonstatic oop-map blocks are short pairs (offset, length) @@ -1031,16 +1003,16 @@ private: // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs - static bool link_class_impl (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS); - static bool verify_code (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS); - static void initialize_impl (instanceKlassHandle this_oop, TRAPS); - static void eager_initialize_impl (instanceKlassHandle this_oop); - static void set_initialization_state_and_notify_impl (instanceKlassHandle this_oop, ClassState state, TRAPS); - static void call_class_initializer_impl (instanceKlassHandle this_oop, TRAPS); - static Klass* array_klass_impl (instanceKlassHandle this_oop, bool or_null, int n, TRAPS); - static void do_local_static_fields_impl (instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS); + static bool link_class_impl (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS); + static bool verify_code (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS); + static void initialize_impl (instanceKlassHandle this_k, TRAPS); + static void eager_initialize_impl (instanceKlassHandle this_k); + static void set_initialization_state_and_notify_impl (instanceKlassHandle this_k, ClassState state, TRAPS); + static void call_class_initializer_impl (instanceKlassHandle this_k, TRAPS); + static Klass* array_klass_impl (instanceKlassHandle this_k, bool or_null, int n, TRAPS); + static void do_local_static_fields_impl (instanceKlassHandle this_k, void f(fieldDescriptor* fd, TRAPS), TRAPS); /* jni_id_for_impl for jfieldID only */ - static JNIid* jni_id_for_impl (instanceKlassHandle this_oop, int offset); + static JNIid* jni_id_for_impl (instanceKlassHandle this_k, int offset); // Returns the array class for the n'th dimension Klass* array_klass_impl(bool or_null, int n, TRAPS); diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 0717079e002..ca8a788d477 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -334,19 +334,11 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots) { } -Klass* Klass::subklass() const { - return _subklass == NULL ? NULL : _subklass; -} - InstanceKlass* Klass::superklass() const { assert(super() == NULL || super()->oop_is_instance(), "must be instance klass"); return _super == NULL ? NULL : InstanceKlass::cast(_super); } -Klass* Klass::next_sibling() const { - return _next_sibling == NULL ? NULL : _next_sibling; -} - void Klass::set_subklass(Klass* s) { assert(s != this, "sanity check"); _subklass = s; @@ -365,7 +357,7 @@ void Klass::append_to_sibling_list() { assert((!super->is_interface() // interfaces cannot be supers && (super->superklass() == NULL || !is_interface())), "an interface can only be a subklass of Object"); - Klass* prev_first_subklass = super->subklass_oop(); + Klass* prev_first_subklass = super->subklass(); if (prev_first_subklass != NULL) { // set our sibling to be the superklass' previous first subklass set_next_sibling(prev_first_subklass); @@ -405,7 +397,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) { assert(current->is_loader_alive(is_alive), "just checking, this should be live"); // Find and set the first alive subklass - Klass* sub = current->subklass_oop(); + Klass* sub = current->subklass(); while (sub != NULL && !sub->is_loader_alive(is_alive)) { #ifndef PRODUCT if (TraceClassUnloading && WizardMode) { @@ -413,7 +405,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) { tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name()); } #endif - sub = sub->next_sibling_oop(); + sub = sub->next_sibling(); } current->set_subklass(sub); if (sub != NULL) { @@ -421,13 +413,13 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) { } // Find and set the first alive sibling - Klass* sibling = current->next_sibling_oop(); + Klass* sibling = current->next_sibling(); while (sibling != NULL && !sibling->is_loader_alive(is_alive)) { if (TraceClassUnloading && WizardMode) { ResourceMark rm; tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name()); } - sibling = sibling->next_sibling_oop(); + sibling = sibling->next_sibling(); } current->set_next_sibling(sibling); if (sibling != NULL) { diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index fd4701c6e4f..e1a1f817a92 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -56,34 +56,6 @@ // actual type. (See oop.inline.hpp for some of the forwarding code.) // ALL FUNCTIONS IMPLEMENTING THIS DISPATCH ARE PREFIXED WITH "oop_"! -// Klass layout: -// [C++ vtbl ptr ] (contained in Metadata) -// [layout_helper ] -// [super_check_offset ] for fast subtype checks -// [name ] -// [secondary_super_cache] for fast subtype checks -// [secondary_supers ] array of 2ndary supertypes -// [primary_supers 0] -// [primary_supers 1] -// [primary_supers 2] -// ... -// [primary_supers 7] -// [java_mirror ] -// [super ] -// [subklass ] first subclass -// [next_sibling ] link to chain additional subklasses -// [next_link ] -// [class_loader_data] -// [modifier_flags] -// [access_flags ] -// [last_biased_lock_bulk_revocation_time] (64 bits) -// [prototype_header] -// [biased_lock_revocation_count] -// [_modified_oops] -// [_accumulated_modified_oops] -// [trace_id] - - // Forward declarations. template class Array; template class GrowableArray; @@ -257,9 +229,9 @@ class Klass : public Metadata { // Use InstanceKlass::contains_field_offset to classify field offsets. // sub/superklass links + Klass* subklass() const { return _subklass; } + Klass* next_sibling() const { return _next_sibling; } InstanceKlass* superklass() const; - Klass* subklass() const; - Klass* next_sibling() const; void append_to_sibling_list(); // add newly created receiver to superklass' subklass list void set_next_link(Klass* k) { _next_link = k; } @@ -281,8 +253,6 @@ class Klass : public Metadata { bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; } protected: // internal accessors - Klass* subklass_oop() const { return _subklass; } - Klass* next_sibling_oop() const { return _next_sibling; } void set_subklass(Klass* s); void set_next_sibling(Klass* s); diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 7c292c3ffe5..06b634fd19d 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -577,12 +577,12 @@ bool Method::is_static_initializer() const { } -objArrayHandle Method::resolved_checked_exceptions_impl(Method* this_oop, TRAPS) { - int length = this_oop->checked_exceptions_length(); +objArrayHandle Method::resolved_checked_exceptions_impl(Method* method, TRAPS) { + int length = method->checked_exceptions_length(); if (length == 0) { // common case return objArrayHandle(THREAD, Universe::the_empty_class_klass_array()); } else { - methodHandle h_this(THREAD, this_oop); + methodHandle h_this(THREAD, method); objArrayOop m_oop = oopFactory::new_objArray(SystemDictionary::Class_klass(), length, CHECK_(objArrayHandle())); objArrayHandle mirrors (THREAD, m_oop); for (int i = 0; i < length; i++) { diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 98598dbeeff..5ff0fc81cd2 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -40,50 +40,15 @@ // A Method represents a Java method. // -// Memory layout (each line represents a word). Note that most applications load thousands of methods, -// so keeping the size of this structure small has a big impact on footprint. +// Note that most applications load thousands of methods, so keeping the size of this +// class small has a big impact on footprint. // -// The actual bytecodes are inlined after the end of the Method struct. +// Note that native_function and signature_handler have to be at fixed offsets +// (required by the interpreter) // -// There are bits in the access_flags telling whether inlined tables are present. -// Note that accessing the line number and local variable tables is not performance critical at all. -// Accessing the checked exceptions table is used by reflection, so we put that last to make access -// to it fast. -// -// The line number table is compressed and inlined following the byte codes. It is found as the first -// byte following the byte codes. The checked exceptions table and the local variable table are inlined -// after the line number table, and indexed from the end of the method. We do not compress the checked -// exceptions table since the average length is less than 2, and do not bother to compress the local -// variable table either since it is mostly absent. -// -// Note that native_function and signature_handler has to be at fixed offsets (required by the interpreter) -// -// |------------------------------------------------------| -// | header | -// | klass | -// |------------------------------------------------------| -// | ConstMethod* (metadata) | -// |------------------------------------------------------| -// | MethodData* (metadata) | -// | MethodCounters | -// |------------------------------------------------------| -// | access_flags | -// | vtable_index | -// |------------------------------------------------------| -// | result_index (C++ interpreter only) | -// |------------------------------------------------------| -// | method_size | intrinsic_id | flags | -// |------------------------------------------------------| -// | code (pointer) | -// | i2i (pointer) | -// | adapter (pointer) | -// | from_compiled_entry (pointer) | -// | from_interpreted_entry (pointer) | -// |------------------------------------------------------| -// | native_function (present only if native) | -// | signature_handler (present only if native) | -// |------------------------------------------------------| - +// Method embedded field layout (after declared fields): +// [EMBEDDED native_function (present only if native) ] +// [EMBEDDED signature_handler (present only if native) ] class CheckedExceptionElement; class LocalVariableTableElement; @@ -661,7 +626,7 @@ class Method : public Metadata { // Static methods that are used to implement member methods where an exposed this pointer // is needed due to possible GCs - static objArrayHandle resolved_checked_exceptions_impl(Method* this_oop, TRAPS); + static objArrayHandle resolved_checked_exceptions_impl(Method* method, TRAPS); // Returns the byte code index from the byte code pointer int bci_from(address bcp) const; diff --git a/hotspot/src/share/vm/utilities/debug.hpp b/hotspot/src/share/vm/utilities/debug.hpp index ccadc077219..310080dbb0e 100644 --- a/hotspot/src/share/vm/utilities/debug.hpp +++ b/hotspot/src/share/vm/utilities/debug.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -243,7 +243,6 @@ template <> struct StaticAssert {}; // out of shared space reporting enum SharedSpaceType { - SharedPermGen, SharedReadOnly, SharedReadWrite, SharedMiscData From 0b0fdb97ce99f43bb908fe4b07ca2b6157a4be14 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Thu, 27 Mar 2014 22:36:08 +0100 Subject: [PATCH 038/170] 8007890: [TESTBUG] JcmdWithNMTDisabled.java fails when invoked with NMT explicitly turned on Wrapped the test in another layer process creation to avoid NMT being turned on. Reviewed-by: coleenp, dcubed --- .../test/runtime/NMT/JcmdWithNMTDisabled.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java b/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java index 7b58a841315..9ef37434937 100644 --- a/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java +++ b/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java @@ -26,10 +26,7 @@ * @key nmt jcmd * @summary Verify that jcmd correctly reports that NMT is not enabled * @library /testlibrary - * First run without enabling NMT - * @run main/othervm JcmdWithNMTDisabled - * Then run with explicitly disabling NMT, should not be any difference - * @run main/othervm -XX:NativeMemoryTracking=off JcmdWithNMTDisabled + * @run main JcmdWithNMTDisabled 1 */ import com.oracle.java.testlibrary.*; @@ -39,6 +36,27 @@ public class JcmdWithNMTDisabled { static String pid; public static void main(String args[]) throws Exception { + + // This test explicitly needs to be run with the exact command lines below, not passing on + // arguments from the parent VM is a conscious choice to avoid NMT being turned on. + if (args.length > 0) { + ProcessBuilder pb; + OutputAnalyzer output; + String testjdkPath = System.getProperty("test.jdk"); + + // First run without enabling NMT + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + // Then run with explicitly disabling NMT, should not be any difference + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "JcmdWithNMTDisabled"); + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + return; + } + // Grab my own PID pid = Integer.toString(ProcessTools.getProcessId()); From 57d7e49ab19682bdbc626787b309c22b7bcab65f Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Fri, 28 Mar 2014 21:04:37 -0700 Subject: [PATCH 039/170] 7090324: gclog rotation via external tool GC log rotation can be set via java command line, but customer sometime need to sync with OS level rotation setting. Reviewed-by: sla, minqi, ehelin --- hotspot/src/share/vm/runtime/arguments.cpp | 18 ++--- hotspot/src/share/vm/runtime/globals.hpp | 6 +- hotspot/src/share/vm/runtime/safepoint.cpp | 2 +- .../src/share/vm/runtime/vm_operations.hpp | 12 +++ .../share/vm/services/diagnosticCommand.cpp | 11 +++ .../share/vm/services/diagnosticCommand.hpp | 17 ++++ hotspot/src/share/vm/utilities/ostream.cpp | 28 +++++-- hotspot/src/share/vm/utilities/ostream.hpp | 10 ++- hotspot/test/gc/TestGCLogRotationViaJcmd.java | 77 +++++++++++++++++++ 9 files changed, 159 insertions(+), 22 deletions(-) create mode 100644 hotspot/test/gc/TestGCLogRotationViaJcmd.java diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 2bb12bc16f2..16cd65676e4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1907,24 +1907,22 @@ static bool verify_serial_gc_flags() { // check if do gclog rotation // +UseGCLogFileRotation is a must, // no gc log rotation when log file not supplied or -// NumberOfGCLogFiles is 0, or GCLogFileSize is 0 +// NumberOfGCLogFiles is 0 void check_gclog_consistency() { if (UseGCLogFileRotation) { - if ((Arguments::gc_log_filename() == NULL) || - (NumberOfGCLogFiles == 0) || - (GCLogFileSize == 0)) { + if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) { jio_fprintf(defaultStream::output_stream(), - "To enable GC log rotation, use -Xloggc: -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles= -XX:GCLogFileSize=[k|K|m|M|g|G]\n" - "where num_of_file > 0 and num_of_size > 0\n" + "To enable GC log rotation, use -Xloggc: -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=\n" + "where num_of_file > 0\n" "GC log rotation is turned off\n"); UseGCLogFileRotation = false; } } - if (UseGCLogFileRotation && GCLogFileSize < 8*K) { - FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K); - jio_fprintf(defaultStream::output_stream(), - "GCLogFileSize changed to minimum 8K\n"); + if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) { + FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K); + jio_fprintf(defaultStream::output_stream(), + "GCLogFileSize changed to minimum 8K\n"); } } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index d2de68b1103..523a4883346 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2423,9 +2423,9 @@ class CommandLineFlags { "Number of gclog files in rotation " \ "(default: 0, no rotation)") \ \ - product(uintx, GCLogFileSize, 0, \ - "GC log file size (default: 0 bytes, no rotation). " \ - "It requires UseGCLogFileRotation") \ + product(uintx, GCLogFileSize, 8*K, \ + "GC log file size, requires UseGCLogFileRotation. " \ + "Set to 0 to only trigger rotation via jcmd") \ \ /* JVMTI heap profiling */ \ \ diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index 5e04b0ba73d..967b1bd3d75 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -535,7 +535,7 @@ void SafepointSynchronize::do_cleanup_tasks() { // rotate log files? if (UseGCLogFileRotation) { - gclog_or_tty->rotate_log(); + gclog_or_tty->rotate_log(false); } if (MemTracker::is_on()) { diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index a3a58e4d4c3..d0014ef97f5 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -96,6 +96,7 @@ template(JFRCheckpoint) \ template(Exit) \ template(LinuxDllLoad) \ + template(RotateGCLog) \ class VM_Operation: public CHeapObj { public: @@ -399,4 +400,15 @@ class VM_Exit: public VM_Operation { void doit(); }; + +class VM_RotateGCLog: public VM_Operation { + private: + outputStream* _out; + + public: + VM_RotateGCLog(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_RotateGCLog; } + void doit() { gclog_or_tty->rotate_log(true, _out); } +}; + #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index daa09f36ff4..74444d6168d 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -55,6 +55,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); #endif // INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); // Enhanced JMX Agent Support // These commands won't be exported via the DiagnosticCommandMBean until an @@ -659,3 +660,13 @@ void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { os::print_dll_info(output()); output()->cr(); } + +void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) { + if (UseGCLogFileRotation) { + VM_RotateGCLog rotateop(output()); + VMThread::execute(&rotateop); + } else { + output()->print_cr("Target VM does not support GC log file rotation."); + } +} + diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index a23af05aa09..7a6d3402809 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -383,4 +383,21 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class RotateGCLogDCmd : public DCmd { +public: + RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { return "GC.rotate_log"; } + static const char* description() { + return "Force the GC log file to be rotated."; + } + static const char* impact() { return "Low"; } + virtual void execute(DCmdSource source, TRAPS); + static int num_arguments() { return 0; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "control", NULL}; + return p; + } +}; + #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 90b3559e48c..e09dfccf123 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -662,13 +662,13 @@ void gcLogFileStream::write(const char* s, size_t len) { // write to gc log file at safepoint. If in future, changes made for mutator threads or // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log // must be synchronized. -void gcLogFileStream::rotate_log() { +void gcLogFileStream::rotate_log(bool force, outputStream* out) { char time_msg[FILENAMEBUFLEN]; char time_str[EXTRACHARLEN]; char current_file_name[FILENAMEBUFLEN]; char renamed_file_name[FILENAMEBUFLEN]; - if (_bytes_written < (jlong)GCLogFileSize) { + if (!should_rotate(force)) { return; } @@ -685,6 +685,11 @@ void gcLogFileStream::rotate_log() { jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n", _file_name, os::local_time_string((char *)time_str, sizeof(time_str))); write(time_msg, strlen(time_msg)); + + if (out != NULL) { + out->print(time_msg); + } + dump_loggc_header(); return; } @@ -706,12 +711,18 @@ void gcLogFileStream::rotate_log() { _file_name, _cur_file_num); jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); - jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the" - " maximum size. Saved as %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), - renamed_file_name); + + const char* msg = force ? "GC log rotation request has been received." + : "GC log file has reached the maximum size."; + jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n", + os::local_time_string((char *)time_str, sizeof(time_str)), + msg, renamed_file_name); write(time_msg, strlen(time_msg)); + if (out != NULL) { + out->print(time_msg); + } + fclose(_file); _file = NULL; @@ -752,6 +763,11 @@ void gcLogFileStream::rotate_log() { os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name); write(time_msg, strlen(time_msg)); + + if (out != NULL) { + out->print(time_msg); + } + dump_loggc_header(); // remove the existing file if (access(current_file_name, F_OK) == 0) { diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp index 20e6f30bf37..92440ee0a64 100644 --- a/hotspot/src/share/vm/utilities/ostream.hpp +++ b/hotspot/src/share/vm/utilities/ostream.hpp @@ -115,7 +115,7 @@ class outputStream : public ResourceObj { // flushing virtual void flush() {} virtual void write(const char* str, size_t len) = 0; - virtual void rotate_log() {} // GC log rotation + virtual void rotate_log(bool force, outputStream* out = NULL) {} // GC log rotation virtual ~outputStream() {} // close properly on deletion void dec_cr() { dec(); cr(); } @@ -240,8 +240,14 @@ class gcLogFileStream : public fileStream { gcLogFileStream(const char* file_name); ~gcLogFileStream(); virtual void write(const char* c, size_t len); - virtual void rotate_log(); + virtual void rotate_log(bool force, outputStream* out = NULL); void dump_loggc_header(); + + /* If "force" sets true, force log file rotation from outside JVM */ + bool should_rotate(bool force) { + return force || + ((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize)); + } }; #ifndef PRODUCT diff --git a/hotspot/test/gc/TestGCLogRotationViaJcmd.java b/hotspot/test/gc/TestGCLogRotationViaJcmd.java new file mode 100644 index 00000000000..fd71d368b88 --- /dev/null +++ b/hotspot/test/gc/TestGCLogRotationViaJcmd.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 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 TestGCLogRotationViaJcmd.java + * @bug 7090324 + * @summary test for gc log rotation via jcmd + * @library /testlibrary + * @run main/othervm -Xloggc:test.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 TestGCLogRotationViaJcmd + * + */ +import com.oracle.java.testlibrary.*; +import java.io.File; +import java.io.FilenameFilter; + +public class TestGCLogRotationViaJcmd { + + static final File currentDirectory = new File("."); + static final String LOG_FILE_NAME = "test.log"; + static final int NUM_LOGS = 3; + + static FilenameFilter logFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith(LOG_FILE_NAME); + } + }; + + public static void main(String[] args) throws Exception { + // Grab the pid from the current java process + String pid = Integer.toString(ProcessTools.getProcessId()); + + // Create a JDKToolLauncher + JDKToolLauncher jcmd = JDKToolLauncher.create("jcmd") + .addToolArg(pid) + .addToolArg("GC.rotate_log"); + + for (int times = 1; times < NUM_LOGS; times++) { + // Run jcmd GC.rotate_log + ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand()); + + // Make sure we didn't crash + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } + + // GC log check + File[] logs = currentDirectory.listFiles(logFilter); + if (logs.length != NUM_LOGS) { + throw new Error("There are only " + logs.length + + " logs instead " + NUM_LOGS); + } + + } + +} + From 6035ac234bb7ab7495a8f166eba31aedc0ec286e Mon Sep 17 00:00:00 2001 From: Axel Siebenborn Date: Tue, 11 Mar 2014 15:22:44 +0100 Subject: [PATCH 040/170] 8036666: VMTI GetObjectMonitorUsage does not return correct recursion count Fix object lock recursion count and add test Reviewed-by: sspitsyn, dsamersoff --- hotspot/src/share/vm/prims/jvmtiEnvBase.cpp | 21 +- .../jvmti/8036666/GetObjectLockCount.java | 284 ++++++++++++++++++ .../jvmti/8036666/RecursiveObjectLock.java | 63 ++++ 3 files changed, 354 insertions(+), 14 deletions(-) create mode 100644 hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java create mode 100644 hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp index 597d7a164dc..4e39e767833 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -1020,19 +1020,12 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec } if (owning_thread != NULL) { // monitor is owned - if ((address)owning_thread == owner) { - // the owner field is the JavaThread * - assert(mon != NULL, - "must have heavyweight monitor with JavaThread * owner"); - ret.entry_count = mon->recursions() + 1; - } else { - // The owner field is the Lock word on the JavaThread's stack - // so the recursions field is not valid. We have to count the - // number of recursive monitor entries the hard way. We pass - // a handle to survive any GCs along the way. - ResourceMark rm; - ret.entry_count = count_locked_objects(owning_thread, hobj); - } + // The recursions field of a monitor does not reflect recursions + // as lightweight locks before inflating the monitor are not included. + // We have to count the number of recursive monitor entries the hard way. + // We pass a handle to survive any GCs along the way. + ResourceMark rm; + ret.entry_count = count_locked_objects(owning_thread, hobj); } // implied else: entry_count == 0 } diff --git a/hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java b/hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java new file mode 100644 index 00000000000..47e4104bd3d --- /dev/null +++ b/hotspot/test/serviceability/jvmti/8036666/GetObjectLockCount.java @@ -0,0 +1,284 @@ +/* + * Copyright 2014 SAP AG. 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. + */ + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Bootstrap; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.Location; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.Connector.Argument; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.VMStartException; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.VMDeathEvent; +import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.event.VMStartEvent; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.EventRequestManager; + + +/* + * @test GetObjectLockCount.java + * @bug 8036666 + * @key regression + * @summary verify jvm returns correct lock recursion count + * @run compile -g RecursiveObjectLock.java + * @run main/othervm GetObjectLockCount + * @author axel.siebenborn@sap.com + */ + +public class GetObjectLockCount { + + public static final String CLASS_NAME = "RecursiveObjectLock"; + public static final String METHOD_NAME = "breakpoint1"; + public static final String ARGUMENTS = ""; + + + /** + * Find a com.sun.jdi.CommandLineLaunch connector + */ + static LaunchingConnector findLaunchingConnector() { + List connectors = Bootstrap.virtualMachineManager().allConnectors(); + Iterator iter = connectors.iterator(); + while (iter.hasNext()) { + Connector connector = iter.next(); + if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { + return (LaunchingConnector)connector; + } + } + throw new Error("No launching connector"); + } + + static VirtualMachine launchTarget(String mainArgs) { + LaunchingConnector connector = findLaunchingConnector(); + Map arguments = connectorArguments(connector, mainArgs); + try { + return (VirtualMachine) connector.launch(arguments); + } catch (IOException exc) { + throw new Error("Unable to launch target VM: " + exc); + } catch (IllegalConnectorArgumentsException exc) { + throw new Error("Internal error: " + exc); + } catch (VMStartException exc) { + throw new Error("Target VM failed to initialize: " + + exc.getMessage()); + } + } + /** + * Return the launching connector's arguments. + */ + static Map connectorArguments(LaunchingConnector connector, String mainArgs) { + Map arguments = connector.defaultArguments(); + + Connector.Argument mainArg = (Connector.Argument)arguments.get("main"); + if (mainArg == null) { + throw new Error("Bad launching connector"); + } + mainArg.setValue(mainArgs); + + Connector.Argument optionsArg = (Connector.Argument)arguments.get("options"); + if (optionsArg == null) { + throw new Error("Bad launching connector"); + } + optionsArg.setValue(ARGUMENTS); + return arguments; + } + + private static void addClassWatch(VirtualMachine vm) { + EventRequestManager erm = vm.eventRequestManager(); + ClassPrepareRequest classPrepareRequest = erm + .createClassPrepareRequest(); + classPrepareRequest.addClassFilter(CLASS_NAME); + classPrepareRequest.setEnabled(true); + } + + private static void addBreakpoint(VirtualMachine vm, ReferenceType refType) { + Location breakpointLocation = null; + List locs; + try { + locs = refType.allLineLocations(); + for (Location loc: locs) { + if (loc.method().name().equals(METHOD_NAME)) { + breakpointLocation = loc; + break; + } + } + } catch (AbsentInformationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (breakpointLocation != null) { + EventRequestManager evtReqMgr = vm.eventRequestManager(); + BreakpointRequest bReq = evtReqMgr.createBreakpointRequest(breakpointLocation); + bReq.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); + bReq.enable(); + } + } + + /** + * @param args + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + + VirtualMachine vm = launchTarget(CLASS_NAME); + + // process events + EventQueue eventQueue = vm.eventQueue(); + // resume the vm + boolean launched = false; + + while (!launched) { + EventSet eventSet = eventQueue.remove(); + for (Event event : eventSet) { + if (event instanceof VMStartEvent) { + System.out.println("Vm launched"); + // set watch field on already loaded classes + List referenceTypes = vm.classesByName(CLASS_NAME); + for (ReferenceType refType : referenceTypes) { + System.out.println("Found Class"); + addBreakpoint(vm, refType); + } + + // watch for loaded classes + addClassWatch(vm); + vm.resume(); + launched = true; + } + } + } + + Process process = vm.process(); + + // Copy target's output and error to our output and error. + Thread outThread = new StreamRedirectThread("out reader", process.getInputStream()); + Thread errThread = new StreamRedirectThread("error reader", process.getErrorStream()); + + int recursionCount = -1; + + errThread.start(); + outThread.start(); + boolean connected = true; + while (connected) { + EventSet eventSet = eventQueue.remove(); + for (Event event : eventSet) { + if (event instanceof VMDeathEvent || event instanceof VMDisconnectEvent) { + // exit + connected = false; + } + else if (event instanceof ClassPrepareEvent) { + // watch field on loaded class + System.out.println("ClassPrepareEvent"); + ClassPrepareEvent classPrepEvent = (ClassPrepareEvent) event; + ReferenceType refType = classPrepEvent.referenceType(); + addBreakpoint(vm, refType); + } else if (event instanceof BreakpointEvent) { + recursionCount = getLockRecursions(vm); + System.out.println("resume..."); + } + } + eventSet.resume(); + } + // Shutdown begins when event thread terminates + try { + errThread.join(); // Make sure output is forwarded + outThread.join(); + } catch (InterruptedException e) { + // we don't interrupt + e.printStackTrace(); + } + if (recursionCount != 3) { + throw new AssertionError("recursions: expected 3, but was " + recursionCount); + } + } + + public static int getLockRecursions(VirtualMachine vm) { + List threads = vm.allThreads(); + for (ThreadReference thread : threads) { + if (thread.name().equals("main")) { + + System.out.println("Found main thread."); + try{ + StackFrame frame = thread.frame(3); + return frame.thisObject().entryCount(); + } catch (Exception e) { + e.printStackTrace(); + } + } + System.out.println("Main thread not found!"); + } + return -1; + } +} + +class StreamRedirectThread extends Thread { + + private final BufferedReader in; + + private static final int BUFFER_SIZE = 2048; + + /** + * Set up for copy. + * @param name Name of the thread + * @param in Stream to copy from + */ + StreamRedirectThread(String name, InputStream in) { + super(name); + this.in = new BufferedReader(new InputStreamReader(in)); + } + + /** + * Copy. + */ + public void run() { + try { + String line; + while ((line = in.readLine ()) != null) { + System.out.println("testvm: " + line); + } + System.out.flush(); + } catch(IOException exc) { + System.err.println("Child I/O Transfer - " + exc); + exc.printStackTrace(); + } + } +} diff --git a/hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java b/hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java new file mode 100644 index 00000000000..d1a35edd6c3 --- /dev/null +++ b/hotspot/test/serviceability/jvmti/8036666/RecursiveObjectLock.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 SAP AG. 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. + */ + +public class RecursiveObjectLock { + + public void testMethod() { + synchronized (this) { + nestedLock1(); + } + } + + public void nestedLock1() { + synchronized (this) { + nestedLock2(); + } + } + + public void nestedLock2() { + synchronized (this) { + callWait(); + } + } + + public void callWait(){ + try { + this.wait(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + breakpoint1(); + } + + public static void breakpoint1() { + // purpose: hold a breakpoint + } + + public static void main(String[] args) { + RecursiveObjectLock ro = new RecursiveObjectLock(); + ro.testMethod(); + System.out.println("ready"); + } + +} From af7a190f2163d18e81ad6c0702e13f05a99aecec Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 13 Mar 2014 14:55:10 -0700 Subject: [PATCH 041/170] 8037149: C1: getThreadTemp should return a T_LONG register on 64bit Fix the type of the register returned by getThreadTemp() to depend on bitness Reviewed-by: kvn, twisti --- hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp | 4 ++-- hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 488a53d9b6e..b9105e92e9b 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -3320,7 +3320,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, // if tmp is invalid, then the function being called doesn't destroy the thread if (tmp->is_valid()) { - __ save_thread(tmp->as_register()); + __ save_thread(tmp->as_pointer_register()); } __ call(dest, relocInfo::runtime_call_type); __ delayed()->nop(); @@ -3328,7 +3328,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, add_call_info_here(info); } if (tmp->is_valid()) { - __ restore_thread(tmp->as_register()); + __ restore_thread(tmp->as_pointer_register()); } #ifdef ASSERT diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index dc3bc8691ac..6f6d4c30e13 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -69,7 +69,7 @@ void LIRItem::load_nonconstant() { LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::Oexception_opr; } LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::Oissuing_pc_opr; } LIR_Opr LIRGenerator::syncTempOpr() { return new_register(T_OBJECT); } -LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(T_INT); } +LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(NOT_LP64(T_INT) LP64_ONLY(T_LONG)); } LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { LIR_Opr opr; From a415d9069180ebf919e0a3babb17a64974c7ddbb Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 13 Mar 2014 14:55:34 -0700 Subject: [PATCH 042/170] 8037140: C1: Incorrect argument type used for SharedRuntime::OSR_migration_end in LIRGenerator::do_Goto Fix the type of osrBuffer parameter to depend on bitness Reviewed-by: kvn, twisti --- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index ca8383b2542..6d7ed620be3 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2526,7 +2526,7 @@ void LIRGenerator::do_Goto(Goto* x) { // need to free up storage used for OSR entry point LIR_Opr osrBuffer = block()->next()->operand(); BasicTypeList signature; - signature.append(T_INT); + signature.append(NOT_LP64(T_INT) LP64_ONLY(T_LONG)); // pass a pointer to osrBuffer CallingConvention* cc = frame_map()->c_calling_convention(&signature); __ move(osrBuffer, cc->args()->at(0)); __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_end), From 26553754383835df0b1f9b23bc54fb17b7709788 Mon Sep 17 00:00:00 2001 From: Frederic Parain Date: Fri, 14 Mar 2014 12:02:54 +0000 Subject: [PATCH 043/170] 8036128: Remove deprecated VM flag UseVMInterruptibleIO Reviewed-by: acorn, dholmes, dcubed, coleenp --- .../src/os/solaris/vm/osThread_solaris.cpp | 3 +- .../src/os/solaris/vm/osThread_solaris.hpp | 16 +- hotspot/src/os/solaris/vm/os_solaris.cpp | 154 +++++++----------- hotspot/src/os/solaris/vm/os_solaris.hpp | 20 +-- .../src/os/solaris/vm/os_solaris.inline.hpp | 99 +---------- hotspot/src/share/vm/runtime/arguments.cpp | 6 +- hotspot/src/share/vm/runtime/globals.hpp | 5 - .../src/share/vm/services/runtimeService.cpp | 43 +---- .../src/share/vm/services/runtimeService.hpp | 9 +- 9 files changed, 70 insertions(+), 285 deletions(-) diff --git a/hotspot/src/os/solaris/vm/osThread_solaris.cpp b/hotspot/src/os/solaris/vm/osThread_solaris.cpp index 9cbd632e578..76f4bd88f4a 100644 --- a/hotspot/src/os/solaris/vm/osThread_solaris.cpp +++ b/hotspot/src/os/solaris/vm/osThread_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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 @@ -41,7 +41,6 @@ void OSThread::pd_initialize() { _thread_id = 0; sigemptyset(&_caller_sigmask); - _saved_interrupt_thread_state = _thread_new; _vm_created_thread = false; } diff --git a/hotspot/src/os/solaris/vm/osThread_solaris.hpp b/hotspot/src/os/solaris/vm/osThread_solaris.hpp index c3f96699421..06b5fc2ca85 100644 --- a/hotspot/src/os/solaris/vm/osThread_solaris.hpp +++ b/hotspot/src/os/solaris/vm/osThread_solaris.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -82,20 +82,6 @@ void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; } static void SR_handler(Thread* thread, ucontext_t* uc); - // *************************************************************** - // java.lang.Thread.interrupt state. - // *************************************************************** - - private: - - JavaThreadState _saved_interrupt_thread_state; // the thread state before a system call -- restored afterward - - public: - - - JavaThreadState saved_interrupt_thread_state() { return _saved_interrupt_thread_state; } - void set_saved_interrupt_thread_state(JavaThreadState state) { _saved_interrupt_thread_state = state; } - static void handle_spinlock_contention(int tries); // Used for thread local eden locking // *************************************************************** diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index d6f1341d1b5..3f9d1d810bb 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -311,33 +311,6 @@ struct tm* os::localtime_pd(const time_t* clock, struct tm* res) { return localtime_r(clock, res); } -// interruptible infrastructure - -// setup_interruptible saves the thread state before going into an -// interruptible system call. -// The saved state is used to restore the thread to -// its former state whether or not an interrupt is received. -// Used by classloader os::read -// os::restartable_read calls skip this layer and stay in _thread_in_native - -void os::Solaris::setup_interruptible(JavaThread* thread) { - - JavaThreadState thread_state = thread->thread_state(); - - assert(thread_state != _thread_blocked, "Coming from the wrong thread"); - assert(thread_state != _thread_in_native, "Native threads skip setup_interruptible"); - OSThread* osthread = thread->osthread(); - osthread->set_saved_interrupt_thread_state(thread_state); - thread->frame_anchor()->make_walkable(thread); - ThreadStateTransition::transition(thread, thread_state, _thread_blocked); -} - -JavaThread* os::Solaris::setup_interruptible() { - JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread(); - setup_interruptible(thread); - return thread; -} - void os::Solaris::try_enable_extended_io() { typedef int (*enable_extended_FILE_stdio_t)(int, int); @@ -353,41 +326,6 @@ void os::Solaris::try_enable_extended_io() { } } - -#ifdef ASSERT - -JavaThread* os::Solaris::setup_interruptible_native() { - JavaThread* thread = (JavaThread*)ThreadLocalStorage::thread(); - JavaThreadState thread_state = thread->thread_state(); - assert(thread_state == _thread_in_native, "Assumed thread_in_native"); - return thread; -} - -void os::Solaris::cleanup_interruptible_native(JavaThread* thread) { - JavaThreadState thread_state = thread->thread_state(); - assert(thread_state == _thread_in_native, "Assumed thread_in_native"); -} -#endif - -// cleanup_interruptible reverses the effects of setup_interruptible -// setup_interruptible_already_blocked() does not need any cleanup. - -void os::Solaris::cleanup_interruptible(JavaThread* thread) { - OSThread* osthread = thread->osthread(); - - ThreadStateTransition::transition(thread, _thread_blocked, osthread->saved_interrupt_thread_state()); -} - -// I/O interruption related counters called in _INTERRUPTIBLE - -void os::Solaris::bump_interrupted_before_count() { - RuntimeService::record_interrupted_before_count(); -} - -void os::Solaris::bump_interrupted_during_count() { - RuntimeService::record_interrupted_during_count(); -} - static int _processors_online = 0; jint os::Solaris::_os_thread_limit = 0; @@ -3366,11 +3304,20 @@ bool os::can_execute_large_page_memory() { // Read calls from inside the vm need to perform state transitions size_t os::read(int fd, void *buf, unsigned int nBytes) { - INTERRUPTIBLE_RETURN_INT_VM(::read(fd, buf, nBytes), os::Solaris::clear_interrupted); + size_t res; + JavaThread* thread = (JavaThread*)Thread::current(); + assert(thread->thread_state() == _thread_in_vm, "Assumed _thread_in_vm"); + ThreadBlockInVM tbiv(thread); + RESTARTABLE(::read(fd, buf, (size_t) nBytes), res); + return res; } size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) { - INTERRUPTIBLE_RETURN_INT(::read(fd, buf, nBytes), os::Solaris::clear_interrupted); + size_t res; + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE(::read(fd, buf, (size_t) nBytes), res); + return res; } void os::naked_short_sleep(jlong ms) { @@ -5305,6 +5252,8 @@ int os::fsync(int fd) { } int os::available(int fd, jlong *bytes) { + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); jlong cur, end; int mode; struct stat64 buf64; @@ -5312,14 +5261,9 @@ int os::available(int fd, jlong *bytes) { if (::fstat64(fd, &buf64) >= 0) { mode = buf64.st_mode; if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { - /* - * XXX: is the following call interruptible? If so, this might - * need to go through the INTERRUPT_IO() wrapper as for other - * blocking, interruptible calls in this file. - */ int n,ioctl_return; - INTERRUPTIBLE(::ioctl(fd, FIONREAD, &n),ioctl_return,os::Solaris::clear_interrupted); + RESTARTABLE(::ioctl(fd, FIONREAD, &n), ioctl_return); if (ioctl_return>= 0) { *bytes = n; return 1; @@ -6250,7 +6194,11 @@ bool os::is_headless_jre() { } size_t os::write(int fd, const void *buf, unsigned int nBytes) { - INTERRUPTIBLE_RETURN_INT(::write(fd, buf, nBytes), os::Solaris::clear_interrupted); + size_t res; + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res); + return res; } int os::close(int fd) { @@ -6262,11 +6210,15 @@ int os::socket_close(int fd) { } int os::recv(int fd, char* buf, size_t nBytes, uint flags) { - INTERRUPTIBLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags)); } int os::send(int fd, char* buf, size_t nBytes, uint flags) { - INTERRUPTIBLE_RETURN_INT((int)::send(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags)); } int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { @@ -6287,11 +6239,14 @@ int os::timeout(int fd, long timeout) { pfd.fd = fd; pfd.events = POLLIN; + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + gettimeofday(&t, &aNull); prevtime = ((julong)t.tv_sec * 1000) + t.tv_usec / 1000; for(;;) { - INTERRUPTIBLE_NORESTART(::poll(&pfd, 1, timeout), res, os::Solaris::clear_interrupted); + res = ::poll(&pfd, 1, timeout); if(res == OS_ERR && errno == EINTR) { if(timeout != -1) { gettimeofday(&t, &aNull); @@ -6307,17 +6262,30 @@ int os::timeout(int fd, long timeout) { int os::connect(int fd, struct sockaddr *him, socklen_t len) { int _result; - INTERRUPTIBLE_NORESTART(::connect(fd, him, len), _result,\ - os::Solaris::clear_interrupted); + _result = ::connect(fd, him, len); - // Depending on when thread interruption is reset, _result could be - // one of two values when errno == EINTR - - if (((_result == OS_INTRPT) || (_result == OS_ERR)) - && (errno == EINTR)) { + // On Solaris, when a connect() call is interrupted, the connection + // can be established asynchronously (see 6343810). Subsequent calls + // to connect() must check the errno value which has the semantic + // described below (copied from the connect() man page). Handling + // of asynchronously established connections is required for both + // blocking and non-blocking sockets. + // EINTR The connection attempt was interrupted + // before any data arrived by the delivery of + // a signal. The connection, however, will be + // established asynchronously. + // + // EINPROGRESS The socket is non-blocking, and the connec- + // tion cannot be completed immediately. + // + // EALREADY The socket is non-blocking, and a previous + // connection attempt has not yet been com- + // pleted. + // + // EISCONN The socket is already connected. + if (_result == OS_ERR && errno == EINTR) { /* restarting a connect() changes its errno semantics */ - INTERRUPTIBLE(::connect(fd, him, len), _result,\ - os::Solaris::clear_interrupted); + RESTARTABLE(::connect(fd, him, len), _result); /* undo these changes */ if (_result == OS_ERR) { if (errno == EALREADY) { @@ -6335,20 +6303,23 @@ int os::accept(int fd, struct sockaddr* him, socklen_t* len) { if (fd < 0) { return OS_ERR; } - INTERRUPTIBLE_RETURN_INT((int)::accept(fd, him, len),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::accept(fd, him, len)); } int os::recvfrom(int fd, char* buf, size_t nBytes, uint flags, sockaddr* from, socklen_t* fromlen) { - INTERRUPTIBLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen)); } int os::sendto(int fd, char* buf, size_t len, uint flags, struct sockaddr* to, socklen_t tolen) { - INTERRUPTIBLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + RESTARTABLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen)); } int os::socket_available(int fd, jint *pbytes) { @@ -6363,8 +6334,9 @@ int os::socket_available(int fd, jint *pbytes) { } int os::bind(int fd, struct sockaddr* him, socklen_t len) { - INTERRUPTIBLE_RETURN_INT_NORESTART(::bind(fd, him, len),\ - os::Solaris::clear_interrupted); + assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, + "Assumed _thread_in_native"); + return ::bind(fd, him, len); } // Get the default path to the core file diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 0485346914a..99a0da0f279 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, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -311,24 +311,6 @@ class Solaris { outdata, validity) : -1; } - enum { - clear_interrupted = true - }; - static void setup_interruptible(JavaThread* thread); - static void setup_interruptible_already_blocked(JavaThread* thread); - static JavaThread* setup_interruptible(); - static void cleanup_interruptible(JavaThread* thread); - - // perf counter incrementers used by _INTERRUPTIBLE - - static void bump_interrupted_before_count(); - static void bump_interrupted_during_count(); - -#ifdef ASSERT - static JavaThread* setup_interruptible_native(); - static void cleanup_interruptible_native(JavaThread* thread); -#endif - static sigset_t* unblocked_signals(); static sigset_t* vm_signals(); static sigset_t* allowdebug_blocked_signals(); diff --git a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp index d7d53f223fc..72a9b0b7059 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp @@ -111,104 +111,7 @@ inline int os::closedir(DIR *dirp) { ////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -// macros for interruptible io and system calls and system call restarting - -#define _INTERRUPTIBLE(_setup, _cmd, _result, _thread, _clear, _before, _after, _int_enable) \ -do { \ - _setup; \ - _before; \ - OSThread* _osthread = _thread->osthread(); \ - if (_int_enable && _thread->has_last_Java_frame()) { \ - /* this is java interruptible io stuff */ \ - if (os::is_interrupted(_thread, _clear)) { \ - os::Solaris::bump_interrupted_before_count(); \ - _result = OS_INTRPT; \ - } else { \ - /* _cmd always expands to an assignment to _result */ \ - if ((_cmd) < 0 && errno == EINTR \ - && os::is_interrupted(_thread, _clear)) { \ - os::Solaris::bump_interrupted_during_count(); \ - _result = OS_INTRPT; \ - } \ - } \ - } else { \ - /* this is normal blocking io stuff */ \ - _cmd; \ - } \ - _after; \ -} while(false) - -// Interruptible io support + restarting of interrupted system calls - -#ifndef ASSERT - -#define INTERRUPTIBLE(_cmd, _result, _clear) do { \ - _INTERRUPTIBLE( JavaThread* _thread = (JavaThread*)ThreadLocalStorage::thread(),_result = _cmd, _result, _thread, _clear, , , UseVMInterruptibleIO); \ -} while((_result == OS_ERR) && (errno == EINTR)) - -#else - -// This adds an assertion that it is only called from thread_in_native -// The call overhead is skipped for performance in product mode -#define INTERRUPTIBLE(_cmd, _result, _clear) do { \ - _INTERRUPTIBLE(JavaThread* _thread = os::Solaris::setup_interruptible_native(), _result = _cmd, _result, _thread, _clear, , os::Solaris::cleanup_interruptible_native(_thread), UseVMInterruptibleIO ); \ -} while((_result == OS_ERR) && (errno == EINTR)) - -#endif - -// Used for calls from _thread_in_vm, not from _thread_in_native -#define INTERRUPTIBLE_VM(_cmd, _result, _clear) do { \ - _INTERRUPTIBLE(JavaThread* _thread = os::Solaris::setup_interruptible(), _result = _cmd, _result, _thread, _clear, , os::Solaris::cleanup_interruptible(_thread), UseVMInterruptibleIO ); \ -} while((_result == OS_ERR) && (errno == EINTR)) - -/* Use NORESTART when the system call cannot return EINTR, when something other - than a system call is being invoked, or when the caller must do EINTR - handling. */ - -#ifndef ASSERT - -#define INTERRUPTIBLE_NORESTART(_cmd, _result, _clear) \ - _INTERRUPTIBLE( JavaThread* _thread = (JavaThread*)ThreadLocalStorage::thread(),_result = _cmd, _result, _thread, _clear, , , UseVMInterruptibleIO) - -#else - -// This adds an assertion that it is only called from thread_in_native -// The call overhead is skipped for performance in product mode -#define INTERRUPTIBLE_NORESTART(_cmd, _result, _clear) \ - _INTERRUPTIBLE(JavaThread* _thread = os::Solaris::setup_interruptible_native(), _result = _cmd, _result, _thread, _clear, , os::Solaris::cleanup_interruptible_native(_thread), UseVMInterruptibleIO ) - -#endif - -// Don't attend to UseVMInterruptibleIO. Always allow interruption. -// Also assumes that it is called from the _thread_blocked state. -// Used by os_sleep(). - -#define INTERRUPTIBLE_NORESTART_VM_ALWAYS(_cmd, _result, _thread, _clear) \ - _INTERRUPTIBLE(os::Solaris::setup_interruptible_already_blocked(_thread), _result = _cmd, _result, _thread, _clear, , , true ) - -#define INTERRUPTIBLE_RETURN_INT(_cmd, _clear) do { \ - int _result; \ - do { \ - INTERRUPTIBLE(_cmd, _result, _clear); \ - } while((_result == OS_ERR) && (errno == EINTR)); \ - return _result; \ -} while(false) - -#define INTERRUPTIBLE_RETURN_INT_VM(_cmd, _clear) do { \ - int _result; \ - do { \ - INTERRUPTIBLE_VM(_cmd, _result, _clear); \ - } while((_result == OS_ERR) && (errno == EINTR)); \ - return _result; \ -} while(false) - -#define INTERRUPTIBLE_RETURN_INT_NORESTART(_cmd, _clear) do { \ - int _result; \ - INTERRUPTIBLE_NORESTART(_cmd, _result, _clear); \ - return _result; \ -} while(false) - -/* Use the RESTARTABLE macros when interruptible io is not needed */ +// macros for restartable system calls #define RESTARTABLE(_cmd, _result) do { \ do { \ diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index c6549f88665..ae60e4c50a7 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -305,6 +305,7 @@ static ObsoleteFlag obsolete_jvm_flags[] = { { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, #endif // PRODUCT + { "UseVMInterruptibleIO", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -3224,11 +3225,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, return JNI_EINVAL; } FLAG_SET_CMDLINE(uintx, MaxDirectMemorySize, max_direct_memory_size); - } else if (match_option(option, "-XX:+UseVMInterruptibleIO", &tail)) { - // NOTE! In JDK 9, the UseVMInterruptibleIO flag will completely go - // away and will cause VM initialization failures! - warning("-XX:+UseVMInterruptibleIO is obsolete and will be removed in a future release."); - FLAG_SET_CMDLINE(bool, UseVMInterruptibleIO, true); #if !INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:+ManagementServer", &tail)) { jio_fprintf(defaultStream::error_stream(), diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index b971907b980..bb7eed6e76b 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3842,11 +3842,6 @@ class CommandLineFlags { develop(bool, VerifyGenericSignatures, false, \ "Abort VM on erroneous or inconsistent generic signatures") \ \ - product(bool, UseVMInterruptibleIO, false, \ - "(Unstable, Solaris-specific) Thread interrupt before or with " \ - "EINTR for I/O operations results in OS_INTRPT. The default " \ - "value of this flag is true for JDK 6 and earlier") \ - \ diagnostic(bool, WhiteBoxAPI, false, \ "Enable internal testing APIs") \ \ diff --git a/hotspot/src/share/vm/services/runtimeService.cpp b/hotspot/src/share/vm/services/runtimeService.cpp index 5fdb9705a4d..e2b829c41f5 100644 --- a/hotspot/src/share/vm/services/runtimeService.cpp +++ b/hotspot/src/share/vm/services/runtimeService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -38,9 +38,6 @@ PerfCounter* RuntimeService::_sync_time_ticks = NULL; PerfCounter* RuntimeService::_total_safepoints = NULL; PerfCounter* RuntimeService::_safepoint_time_ticks = NULL; PerfCounter* RuntimeService::_application_time_ticks = NULL; -PerfCounter* RuntimeService::_thread_interrupt_signaled_count = NULL; -PerfCounter* RuntimeService::_interrupted_before_count = NULL; -PerfCounter* RuntimeService::_interrupted_during_count = NULL; void RuntimeService::init() { // Make sure the VM version is initialized @@ -70,26 +67,6 @@ void RuntimeService::init() { PerfDataManager::create_constant(SUN_RT, "jvmVersion", PerfData::U_None, (jlong) Abstract_VM_Version::jvm_version(), CHECK); - // I/O interruption related counters - - // thread signaling via os::interrupt() - - _thread_interrupt_signaled_count = - PerfDataManager::create_counter(SUN_RT, - "threadInterruptSignaled", PerfData::U_Events, CHECK); - - // OS_INTRPT via "check before" in _INTERRUPTIBLE - - _interrupted_before_count = - PerfDataManager::create_counter(SUN_RT, "interruptedBeforeIO", - PerfData::U_Events, CHECK); - - // OS_INTRPT via "check during" in _INTERRUPTIBLE - - _interrupted_during_count = - PerfDataManager::create_counter(SUN_RT, "interruptedDuringIO", - PerfData::U_Events, CHECK); - // The capabilities counter is a binary representation of the VM capabilities in string. // This string respresentation simplifies the implementation of the client side // to parse the value. @@ -181,22 +158,4 @@ jlong RuntimeService::application_time_ms() { Management::ticks_to_ms(_application_time_ticks->get_value()) : -1; } -void RuntimeService::record_interrupted_before_count() { - if (UsePerfData) { - _interrupted_before_count->inc(); - } -} - -void RuntimeService::record_interrupted_during_count() { - if (UsePerfData) { - _interrupted_during_count->inc(); - } -} - -void RuntimeService::record_thread_interrupt_signaled_count() { - if (UsePerfData) { - _thread_interrupt_signaled_count->inc(); - } -} - #endif // INCLUDE_MANAGEMENT diff --git a/hotspot/src/share/vm/services/runtimeService.hpp b/hotspot/src/share/vm/services/runtimeService.hpp index 8de0ebf6ffc..90981ee2ebe 100644 --- a/hotspot/src/share/vm/services/runtimeService.hpp +++ b/hotspot/src/share/vm/services/runtimeService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -34,9 +34,6 @@ private: static PerfCounter* _total_safepoints; static PerfCounter* _safepoint_time_ticks; // Accumulated time at safepoints static PerfCounter* _application_time_ticks; // Accumulated time not at safepoints - static PerfCounter* _thread_interrupt_signaled_count;// os:interrupt thr_kill - static PerfCounter* _interrupted_before_count; // _INTERRUPTIBLE OS_INTRPT - static PerfCounter* _interrupted_during_count; // _INTERRUPTIBLE OS_INTRPT static TimeStamp _safepoint_timer; static TimeStamp _app_timer; @@ -58,10 +55,6 @@ public: static void record_safepoint_end() NOT_MANAGEMENT_RETURN; static void record_application_start() NOT_MANAGEMENT_RETURN; - // interruption events - static void record_interrupted_before_count() NOT_MANAGEMENT_RETURN; - static void record_interrupted_during_count() NOT_MANAGEMENT_RETURN; - static void record_thread_interrupt_signaled_count() NOT_MANAGEMENT_RETURN; }; #endif // SHARE_VM_SERVICES_RUNTIMESERVICE_HPP From f2fbd2207de0305aaa82312ea57bbfb2dcd86bbb Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Fri, 14 Mar 2014 14:17:11 -0700 Subject: [PATCH 044/170] 6536943: Bogus -Xcheck:jni warning for SIG_INT action for SIGINT in JVM started from non-interactive shell Under non-interactive shell, with -Xcheck:jni, check_signal_handler will print out Warning for SHURDOWN2_SIGNAL (SIGINT) which is replaced by non-interactive shell. Fix by supply more information of the replacement to user. Reviewed-by: acorn, dsamersoff --- hotspot/src/os/aix/vm/os_aix.cpp | 5 +++++ hotspot/src/os/bsd/vm/os_bsd.cpp | 5 +++++ hotspot/src/os/linux/vm/os_linux.cpp | 5 +++++ hotspot/src/os/solaris/vm/os_solaris.cpp | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index ba6b8d494c6..b0ffd77cfb3 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -3741,6 +3741,11 @@ void os::Aix::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if (os::Aix::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Aix::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Aix::get_our_sigflags(sig)); diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 830ceb3a812..79ea15941aa 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -3374,6 +3374,11 @@ void os::Bsd::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Bsd::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Bsd::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Bsd::get_our_sigflags(sig)); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 20ef1e10fb4..dc46fdd8888 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -4560,6 +4560,11 @@ void os::Linux::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Linux::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Linux::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Linux::get_our_sigflags(sig)); diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 3f9d1d810bb..54b78261856 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -4418,6 +4418,11 @@ void os::Solaris::check_signal_handler(int sig) { tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); // No need to check this sig any longer sigaddset(&check_signal_done, sig); + // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN + if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { + tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", + exception_name(sig, buf, O_BUFLEN)); + } } else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) { tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); tty->print("expected:" PTR32_FORMAT, os::Solaris::get_our_sigflags(sig)); From d3f1dc78ef5116cc175707df23d9cfdd12f26460 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 14 Mar 2014 17:28:58 -0700 Subject: [PATCH 045/170] 8037226: compiler/7196199/Test7196199.java fails on 32-bit linux with MaxVectorSize > 16 Verify YMM registers after signal processing and set limit on vector's size. Reviewed-by: iveresov, twisti --- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 85 ++++++++++++++++--- hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 34 ++++++++ hotspot/src/os/windows/vm/os_windows.cpp | 6 ++ hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp | 5 ++ .../src/os_cpu/linux_x86/vm/os_linux_x86.cpp | 5 ++ .../os_cpu/solaris_x86/vm/os_solaris_x86.cpp | 5 ++ 6 files changed, 126 insertions(+), 14 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index b949e4e2998..f449cc446e5 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -50,8 +50,13 @@ int VM_Version::_cpuFeatures; const char* VM_Version::_features_str = ""; VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, }; +// Address of instruction which causes SEGV +address VM_Version::_cpuinfo_segv_addr = 0; +// Address of instruction after the one which causes SEGV +address VM_Version::_cpuinfo_cont_addr = 0; + static BufferBlob* stub_blob; -static const int stub_size = 550; +static const int stub_size = 600; extern "C" { typedef void (*getPsrInfo_stub_t)(void*); @@ -234,9 +239,9 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // Check if OS has enabled XGETBV instruction to access XCR0 // (OSXSAVE feature flag) and CPU supports AVX // - __ andl(rcx, 0x18000000); + __ andl(rcx, 0x18000000); // cpuid1 bits osxsave | avx __ cmpl(rcx, 0x18000000); - __ jccb(Assembler::notEqual, sef_cpuid); + __ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported // // XCR0, XFEATURE_ENABLED_MASK register @@ -247,6 +252,47 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movl(Address(rsi, 0), rax); __ movl(Address(rsi, 4), rdx); + __ andl(rax, 0x6); // xcr0 bits sse | ymm + __ cmpl(rax, 0x6); + __ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported + + // + // Some OSs have a bug when upper 128bits of YMM + // registers are not restored after a signal processing. + // Generate SEGV here (reference through NULL) + // and check upper YMM bits after it. + // + VM_Version::set_avx_cpuFeatures(); // Enable temporary to pass asserts + + // load value into all 32 bytes of ymm7 register + __ movl(rcx, VM_Version::ymm_test_value()); + + __ movdl(xmm0, rcx); + __ pshufd(xmm0, xmm0, 0x00); + __ vinsertf128h(xmm0, xmm0, xmm0); + __ vmovdqu(xmm7, xmm0); +#ifdef _LP64 + __ vmovdqu(xmm8, xmm0); + __ vmovdqu(xmm15, xmm0); +#endif + + __ xorl(rsi, rsi); + VM_Version::set_cpuinfo_segv_addr( __ pc() ); + // Generate SEGV + __ movl(rax, Address(rsi, 0)); + + VM_Version::set_cpuinfo_cont_addr( __ pc() ); + // Returns here after signal. Save xmm0 to check it later. + __ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset()))); + __ vmovdqu(Address(rsi, 0), xmm0); + __ vmovdqu(Address(rsi, 32), xmm7); +#ifdef _LP64 + __ vmovdqu(Address(rsi, 64), xmm8); + __ vmovdqu(Address(rsi, 96), xmm15); +#endif + + VM_Version::clean_cpuFeatures(); + // // cpuid(0x7) Structured Extended Features // @@ -540,14 +586,28 @@ void VM_Version::get_processor_features() { if (MaxVectorSize > 32) { FLAG_SET_DEFAULT(MaxVectorSize, 32); } - if (MaxVectorSize > 16 && UseAVX == 0) { - // Only supported with AVX+ + if (MaxVectorSize > 16 && (UseAVX == 0 || !os_supports_avx_vectors())) { + // 32 bytes vectors (in YMM) are only supported with AVX+ FLAG_SET_DEFAULT(MaxVectorSize, 16); } if (UseSSE < 2) { - // Only supported with SSE2+ + // Vectors (in XMM) are only supported with SSE2+ FLAG_SET_DEFAULT(MaxVectorSize, 0); } +#ifdef ASSERT + if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { + tty->print_cr("State of YMM registers after signal handle:"); + int nreg = 2 LP64_ONLY(+2); + const char* ymm_name[4] = {"0", "7", "8", "15"}; + for (int i = 0; i < nreg; i++) { + tty->print("YMM%s:", ymm_name[i]); + for (int j = 7; j >=0; j--) { + tty->print(" %x", _cpuid_info.ymm_save[i*8 + j]); + } + tty->cr(); + } + } +#endif } #endif @@ -678,14 +738,6 @@ void VM_Version::get_processor_features() { } } } -#if defined(COMPILER2) && defined(_ALLBSD_SOURCE) - if (MaxVectorSize > 16) { - // Limit vectors size to 16 bytes on BSD until it fixes - // restoring upper 128bit of YMM registers on return - // from signal handler. - FLAG_SET_DEFAULT(MaxVectorSize, 16); - } -#endif // COMPILER2 // Use count leading zeros count instruction if available. if (supports_lzcnt()) { @@ -814,6 +866,11 @@ void VM_Version::get_processor_features() { if (UseAES) { tty->print(" UseAES=1"); } +#ifdef COMPILER2 + if (MaxVectorSize > 0) { + tty->print(" MaxVectorSize=%d", MaxVectorSize); + } +#endif tty->cr(); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) { diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 07d64451870..dbc4a9a085a 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -229,6 +229,9 @@ protected: // 0 if this instruction is not available static const char* _features_str; + static address _cpuinfo_segv_addr; // address of instruction which causes SEGV + static address _cpuinfo_cont_addr; // address of instruction after the one which causes SEGV + enum { CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX) CPU_CMOV = (1 << 1), @@ -361,6 +364,9 @@ protected: // extended control register XCR0 (the XFEATURE_ENABLED_MASK register) XemXcr0Eax xem_xcr0_eax; uint32_t xem_xcr0_edx; // reserved + + // Space to save ymm registers after signal handle + int ymm_save[8*4]; // Save ymm0, ymm7, ymm8, ymm15 }; // The actual cpuid info block @@ -460,6 +466,21 @@ protected: return result; } + static bool os_supports_avx_vectors() { + if (!supports_avx()) { + return false; + } + // Verify that OS save/restore all bits of AVX registers + // during signal processing. + int nreg = 2 LP64_ONLY(+2); + for (int i = 0; i < 8 * nreg; i++) { // 32 bytes per ymm register + if (_cpuid_info.ymm_save[i] != ymm_test_value()) { + return false; + } + } + return true; + } + static void get_processor_features(); public: @@ -476,6 +497,19 @@ public: static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); } static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); } static ByteSize xem_xcr0_offset() { return byte_offset_of(CpuidInfo, xem_xcr0_eax); } + static ByteSize ymm_save_offset() { return byte_offset_of(CpuidInfo, ymm_save); } + + // The value used to check ymm register after signal handle + static int ymm_test_value() { return 0xCAFEBABE; } + + static void set_cpuinfo_segv_addr(address pc) { _cpuinfo_segv_addr = pc; } + static bool is_cpuinfo_segv_addr(address pc) { return _cpuinfo_segv_addr == pc; } + static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; } + static address cpuinfo_cont_addr() { return _cpuinfo_cont_addr; } + + static void clean_cpuFeatures() { _cpuFeatures = 0; } + static void set_avx_cpuFeatures() { _cpuFeatures = (CPU_SSE | CPU_SSE2 | CPU_AVX); } + // Initialization static void initialize(); diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 69fb8bc0600..1f4e12c132c 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2425,6 +2425,12 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } } + if ((exception_code == EXCEPTION_ACCESS_VIOLATION) && + VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + return Handle_Exception(exceptionInfo, VM_Version::cpuinfo_cont_addr()); + } + if (t != NULL && t->is_Java_thread()) { JavaThread* thread = (JavaThread*) t; bool in_java = thread->thread_state() == _thread_in_Java; 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 df24bcdc594..5718a791959 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 @@ -492,6 +492,11 @@ JVM_handle_bsd_signal(int sig, } } + if ((sig == SIGSEGV || sig == SIGBUS) && VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + stub = VM_Version::cpuinfo_cont_addr(); + } + // We test if stub is already set (by the stack overflow code // above) so it is not overwritten by the code that follows. This // check is not required on other platforms, because on other 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 a7fa497c871..d269d38ac59 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 @@ -338,6 +338,11 @@ JVM_handle_linux_signal(int sig, } } + if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + stub = VM_Version::cpuinfo_cont_addr(); + } + if (thread->thread_state() == _thread_in_Java) { // Java thread running in Java code => find exception handler if any // a fault inside compiled code, the interpreter, or a stub 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 054a8132b3b..36bf8058a9f 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 @@ -459,6 +459,11 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, } } + if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { + // Verify that OS save/restore AVX registers. + stub = VM_Version::cpuinfo_cont_addr(); + } + if (thread->thread_state() == _thread_in_vm) { if (sig == SIGBUS && info->si_code == BUS_OBJERR && thread->doing_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); From 52f97b0ee1daad9baf608ceb2c88bfe8352d43c6 Mon Sep 17 00:00:00 2001 From: Bharadwaj Yadavalli Date: Mon, 17 Mar 2014 11:33:21 -0400 Subject: [PATCH 046/170] 8036576: jtreg failed on Test6792161 timed out Increase time out value of test since debug VM executes additional code Reviewed-by: kvn --- hotspot/test/compiler/6792161/Test6792161.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/compiler/6792161/Test6792161.java b/hotspot/test/compiler/6792161/Test6792161.java index ac3843c1b72..309c5bbf3be 100644 --- a/hotspot/test/compiler/6792161/Test6792161.java +++ b/hotspot/test/compiler/6792161/Test6792161.java @@ -27,7 +27,7 @@ * @bug 6792161 * @summary assert("No dead instructions after post-alloc") * - * @run main/othervm/timeout=300 -Xcomp -XX:MaxInlineSize=120 Test6792161 + * @run main/othervm/timeout=600 -Xcomp -XX:MaxInlineSize=120 Test6792161 */ import java.lang.reflect.Constructor; From da4aab3c1db4c11d66c8d104adff6155860208fd Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 17 Mar 2014 13:39:17 -0400 Subject: [PATCH 047/170] 8025550: valgrind: Conditional jump depends on uninitialised value in Arena::set_size_in_bytes() Fixed initialized variable that could miscount arena memory Reviewed-by: coleenp, ccheung --- hotspot/src/share/vm/memory/allocation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index 8e382ba85d1..9fece9b4ef4 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -446,6 +446,7 @@ Arena::Arena(size_t init_size) { _first = _chunk = new (AllocFailStrategy::EXIT_OOM, init_size) Chunk(init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); + _size_in_bytes = 0; set_size_in_bytes(init_size); NOT_PRODUCT(Atomic::inc(&_instance_count);) } @@ -454,6 +455,7 @@ Arena::Arena() { _first = _chunk = new (AllocFailStrategy::EXIT_OOM, Chunk::init_size) Chunk(Chunk::init_size); _hwm = _chunk->bottom(); // Save the cached hwm, max _max = _chunk->top(); + _size_in_bytes = 0; set_size_in_bytes(Chunk::init_size); NOT_PRODUCT(Atomic::inc(&_instance_count);) } From 6c36e9d3fd1026d16b651d5c0ca4f25abcdd7531 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Mon, 17 Mar 2014 19:29:29 -0700 Subject: [PATCH 048/170] 6976636: JVM/TI test ex03t001 fails assertion Relax assert in the post_class_unload for the CMS case Reviewed-by: dcubed, dsamersoff --- hotspot/src/share/vm/prims/jvmtiExport.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index 8aacad27e83..8ef2f6ba63b 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -993,7 +993,9 @@ void JvmtiExport::post_class_unload(Klass* klass) { // Before we call the JVMTI agent, we have to set the state in the // thread for which we are proxying. JavaThreadState prev_state = real_thread->thread_state(); - assert(prev_state == _thread_blocked, "JavaThread should be at safepoint"); + assert(((Thread *)real_thread)->is_ConcurrentGC_thread() || + (real_thread->is_Java_thread() && prev_state == _thread_blocked), + "should be ConcurrentGCThread or JavaThread at safepoint"); real_thread->set_thread_state(_thread_in_native); jvmtiExtensionEvent callback = env->ext_callbacks()->ClassUnload; From 4880019b3efaafe1707514c0016539e860bf1c05 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 18 Mar 2014 13:45:27 -0400 Subject: [PATCH 049/170] 8036630: Null ProtectionDomain in JVM can cause NPE because principals field is not initialized to an empty array Call ProtectionDomain constructor instead of making all fields null. Reviewed-by: fparain, zgu --- hotspot/src/share/vm/classfile/vmSymbols.hpp | 3 ++- hotspot/src/share/vm/prims/jvm.cpp | 16 ++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index ed3c0dbcb0c..655792688d3 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -497,6 +497,7 @@ template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \ template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \ template(int_String_signature, "(I)Ljava/lang/String;") \ + template(codesource_permissioncollection_signature, "(Ljava/security/CodeSource;Ljava/security/PermissionCollection;)V") \ /* signature symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ \ diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 1c95046c77b..fec483f3011 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1160,18 +1160,22 @@ static bool is_authorized(Handle context, instanceKlassHandle klass, TRAPS) { // and null permissions - which gives no permissions. oop create_dummy_access_control_context(TRAPS) { InstanceKlass* pd_klass = InstanceKlass::cast(SystemDictionary::ProtectionDomain_klass()); - // new ProtectionDomain(null,null); - oop null_protection_domain = pd_klass->allocate_instance(CHECK_NULL); - Handle null_pd(THREAD, null_protection_domain); + Handle obj = pd_klass->allocate_instance_handle(CHECK_NULL); + // Call constructor ProtectionDomain(null, null); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, obj, KlassHandle(THREAD, pd_klass), + vmSymbols::object_initializer_name(), + vmSymbols::codesource_permissioncollection_signature(), + Handle(), Handle(), CHECK_NULL); // new ProtectionDomain[] {pd}; objArrayOop context = oopFactory::new_objArray(pd_klass, 1, CHECK_NULL); - context->obj_at_put(0, null_pd()); + context->obj_at_put(0, obj()); // new AccessControlContext(new ProtectionDomain[] {pd}) objArrayHandle h_context(THREAD, context); - oop result = java_security_AccessControlContext::create(h_context, false, Handle(), CHECK_NULL); - return result; + oop acc = java_security_AccessControlContext::create(h_context, false, Handle(), CHECK_NULL); + return acc; } JVM_ENTRY(jobject, JVM_DoPrivileged(JNIEnv *env, jclass cls, jobject action, jobject context, jboolean wrapException)) From 4a4c0fce93fb919383c793983bcf1cc4bfb7b7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Lid=C3=A9n?= Date: Tue, 18 Mar 2014 19:07:22 +0100 Subject: [PATCH 050/170] 8029075: String deduplication in G1 Implementation of JEP 192, http://openjdk.java.net/jeps/192 Reviewed-by: brutisso, tschatzl, coleenp --- hotspot/make/excludeSrc.make | 3 +- .../src/share/vm/classfile/javaClasses.hpp | 20 +- .../src/share/vm/classfile/symbolTable.cpp | 14 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 48 +- .../gc_implementation/g1/g1GCPhaseTimes.cpp | 25 +- .../gc_implementation/g1/g1GCPhaseTimes.hpp | 19 + .../vm/gc_implementation/g1/g1MarkSweep.cpp | 7 +- .../vm/gc_implementation/g1/g1StringDedup.cpp | 208 +++++++ .../vm/gc_implementation/g1/g1StringDedup.hpp | 202 +++++++ .../g1/g1StringDedupQueue.cpp | 162 +++++ .../g1/g1StringDedupQueue.hpp | 97 +++ .../g1/g1StringDedupStat.cpp | 162 +++++ .../g1/g1StringDedupStat.hpp | 142 +++++ .../g1/g1StringDedupTable.cpp | 569 ++++++++++++++++++ .../g1/g1StringDedupTable.hpp | 230 +++++++ .../g1/g1StringDedupThread.cpp | 124 ++++ .../g1/g1StringDedupThread.hpp | 56 ++ .../shared/markSweep.inline.hpp | 10 +- hotspot/src/share/vm/runtime/arguments.cpp | 2 + hotspot/src/share/vm/runtime/globals.hpp | 16 + hotspot/src/share/vm/runtime/mutexLocker.cpp | 7 +- hotspot/src/share/vm/runtime/mutexLocker.hpp | 4 +- hotspot/test/gc/g1/TestGCLogMessages.java | 5 + .../TestStringDeduplicationAgeThreshold.java | 36 ++ .../gc/g1/TestStringDeduplicationFullGC.java | 36 ++ .../g1/TestStringDeduplicationInterned.java | 36 ++ .../TestStringDeduplicationMemoryUsage.java | 36 ++ .../TestStringDeduplicationPrintOptions.java | 36 ++ .../TestStringDeduplicationTableRehash.java | 36 ++ .../TestStringDeduplicationTableResize.java | 36 ++ .../gc/g1/TestStringDeduplicationTools.java | 512 ++++++++++++++++ .../gc/g1/TestStringDeduplicationYoungGC.java | 36 ++ 32 files changed, 2915 insertions(+), 17 deletions(-) create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp create mode 100644 hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationFullGC.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationInterned.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationTableResize.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationTools.java create mode 100644 hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index e76c05fa0fa..dcaa3a11a0c 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -87,7 +87,8 @@ ifeq ($(INCLUDE_ALL_GCS), false) g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \ g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \ g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \ - g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \ + g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1StringDedup.cpp g1StringDedupStat.cpp \ + g1StringDedupTable.cpp g1StringDedupThread.cpp g1StringDedupQueue.cpp g1_globals.cpp heapRegion.cpp \ g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \ ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp g1CodeCacheRemSet.cpp \ adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \ diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 7cbaac925e7..c7a162960d9 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -61,10 +61,6 @@ class java_lang_String : AllStatic { static Handle basic_create(int length, TRAPS); - static void set_value( oop string, typeArrayOop buffer) { - assert(initialized, "Must be initialized"); - string->obj_field_put(value_offset, (oop)buffer); - } static void set_offset(oop string, int offset) { assert(initialized, "Must be initialized"); if (offset_offset > 0) { @@ -122,12 +118,26 @@ class java_lang_String : AllStatic { return hash_offset; } + static void set_value(oop string, typeArrayOop buffer) { + assert(initialized && (value_offset > 0), "Must be initialized"); + string->obj_field_put(value_offset, (oop)buffer); + } + static void set_hash(oop string, unsigned int hash) { + assert(initialized && (hash_offset > 0), "Must be initialized"); + string->int_field_put(hash_offset, hash); + } + // Accessors static typeArrayOop value(oop java_string) { assert(initialized && (value_offset > 0), "Must be initialized"); assert(is_instance(java_string), "must be java_string"); return (typeArrayOop) java_string->obj_field(value_offset); } + static unsigned int hash(oop java_string) { + assert(initialized && (hash_offset > 0), "Must be initialized"); + assert(is_instance(java_string), "must be java_string"); + return java_string->int_field(hash_offset); + } static int offset(oop java_string) { assert(initialized, "Must be initialized"); assert(is_instance(java_string), "must be java_string"); diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index d20673b1a19..e7c1a73e067 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -35,6 +35,9 @@ #include "oops/oop.inline2.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/hashtable.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1StringDedup.hpp" +#endif // -------------------------------------------------------------------------- @@ -728,6 +731,15 @@ oop StringTable::intern(Handle string_or_null, jchar* name, string = java_lang_String::create_from_unicode(name, len, CHECK_NULL); } +#if INCLUDE_ALL_GCS + if (G1StringDedup::is_enabled()) { + // Deduplicate the string before it is interned. Note that we should never + // deduplicate a string after it has been interned. Doing so will counteract + // compiler optimizations done on e.g. interned string literals. + G1StringDedup::deduplicate(string()); + } +#endif + // Grab the StringTable_lock before getting the_table() because it could // change at safepoint. MutexLocker ml(StringTable_lock, THREAD); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 3a980bec4a4..bc2e624ac25 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -39,6 +39,7 @@ #include "gc_implementation/g1/g1MarkSweep.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/g1/g1YCTypes.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" @@ -2172,6 +2173,8 @@ jint G1CollectedHeap::initialize() { // values in the heap have been properly initialized. _g1mm = new G1MonitoringSupport(this); + G1StringDedup::initialize(); + return JNI_OK; } @@ -3456,6 +3459,11 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) { if (!silent) gclog_or_tty->print("RemSet "); rem_set()->verify(); + if (G1StringDedup::is_enabled()) { + if (!silent) gclog_or_tty->print("StrDedup "); + G1StringDedup::verify(); + } + if (failures) { gclog_or_tty->print_cr("Heap:"); // It helps to have the per-region information in the output to @@ -3473,8 +3481,13 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) { } guarantee(!failures, "there should not have been any failures"); } else { - if (!silent) - gclog_or_tty->print("(SKIPPING roots, heapRegionSets, heapRegions, remset) "); + if (!silent) { + gclog_or_tty->print("(SKIPPING Roots, HeapRegionSets, HeapRegions, RemSet"); + if (G1StringDedup::is_enabled()) { + gclog_or_tty->print(", StrDedup"); + } + gclog_or_tty->print(") "); + } } } @@ -3567,6 +3580,9 @@ void G1CollectedHeap::print_gc_threads_on(outputStream* st) const { st->cr(); _cm->print_worker_threads_on(st); _cg1r->print_worker_threads_on(st); + if (G1StringDedup::is_enabled()) { + G1StringDedup::print_worker_threads_on(st); + } } void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { @@ -3575,6 +3591,9 @@ void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const { } tc->do_thread(_cmThread); _cg1r->threads_do(tc); + if (G1StringDedup::is_enabled()) { + G1StringDedup::threads_do(tc); + } } void G1CollectedHeap::print_tracing_info() const { @@ -4755,6 +4774,13 @@ oop G1ParScanThreadState::copy_to_survivor_space(oop const old) { obj->set_mark(m); } + if (G1StringDedup::is_enabled()) { + G1StringDedup::enqueue_from_evacuation(from_region->is_young(), + to_region->is_young(), + queue_num(), + obj); + } + size_t* surv_young_words = surviving_young_words(); surv_young_words[young_index] += word_sz; @@ -5218,6 +5244,10 @@ void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive g1_unlink_task.strings_processed(), g1_unlink_task.strings_removed(), g1_unlink_task.symbols_processed(), g1_unlink_task.symbols_removed()); } + + if (G1StringDedup::is_enabled()) { + G1StringDedup::unlink(is_alive); + } } class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure { @@ -5841,6 +5871,9 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { G1STWIsAliveClosure is_alive(this); G1KeepAliveClosure keep_alive(this); JNIHandles::weak_oops_do(&is_alive, &keep_alive); + if (G1StringDedup::is_enabled()) { + G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive); + } } release_gc_alloc_regions(n_workers, evacuation_info); @@ -6321,9 +6354,10 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) { TearDownRegionSetsClosure cl(&_old_set); heap_region_iterate(&cl); - // Need to do this after the heap iteration to be able to - // recognize the young regions and ignore them during the iteration. - _young_list->empty_list(); + // Note that emptying the _young_list is postponed and instead done as + // the first step when rebuilding the regions sets again. The reason for + // this is that during a full GC string deduplication needs to know if + // a collected region was young or old when the full GC was initiated. } _free_list.remove_all(); } @@ -6377,6 +6411,10 @@ public: void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { assert_at_safepoint(true /* should_be_vm_thread */); + if (!free_list_only) { + _young_list->empty_list(); + } + RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list); heap_region_iterate(&cl); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index 0c784a7dddb..0f1a5e345ad 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -27,6 +27,7 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1GCPhaseTimes.hpp" #include "gc_implementation/g1/g1Log.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" // Helper class for avoiding interleaved logging class LineBuffer: public StackObj { @@ -168,7 +169,9 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _last_termination_attempts(_max_gc_threads, SIZE_FORMAT), _last_gc_worker_end_times_ms(_max_gc_threads, "%.1lf", false), _last_gc_worker_times_ms(_max_gc_threads, "%.1lf"), - _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf") + _last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf"), + _cur_string_dedup_queue_fixup_worker_times_ms(_max_gc_threads, "%.1lf"), + _cur_string_dedup_table_fixup_worker_times_ms(_max_gc_threads, "%.1lf") { assert(max_gc_threads > 0, "Must have some GC threads"); } @@ -229,6 +232,16 @@ void G1GCPhaseTimes::note_gc_end() { _last_gc_worker_other_times_ms.verify(); } +void G1GCPhaseTimes::note_string_dedup_fixup_start() { + _cur_string_dedup_queue_fixup_worker_times_ms.reset(); + _cur_string_dedup_table_fixup_worker_times_ms.reset(); +} + +void G1GCPhaseTimes::note_string_dedup_fixup_end() { + _cur_string_dedup_queue_fixup_worker_times_ms.verify(); + _cur_string_dedup_table_fixup_worker_times_ms.verify(); +} + void G1GCPhaseTimes::print_stats(int level, const char* str, double value) { LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value); } @@ -253,6 +266,11 @@ double G1GCPhaseTimes::accounted_time_ms() { // Strong code root purge time misc_time_ms += _cur_strong_code_root_purge_time_ms; + if (G1StringDedup::is_enabled()) { + // String dedup fixup time + misc_time_ms += _cur_string_dedup_fixup_time_ms; + } + // Subtract the time taken to clean the card table from the // current value of "other time" misc_time_ms += _cur_clear_ct_time_ms; @@ -303,6 +321,11 @@ void G1GCPhaseTimes::print(double pause_time_sec) { print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms); print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms); + if (G1StringDedup::is_enabled()) { + print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads); + _cur_string_dedup_queue_fixup_worker_times_ms.print(2, "Queue Fixup (ms)"); + _cur_string_dedup_table_fixup_worker_times_ms.print(2, "Table Fixup (ms)"); + } print_stats(1, "Clear CT", _cur_clear_ct_time_ms); double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); print_stats(1, "Other", misc_time_ms); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index e574777d3bc..d8517b9b46c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -137,6 +137,10 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_evac_fail_restore_remsets; double _cur_evac_fail_remove_self_forwards; + double _cur_string_dedup_fixup_time_ms; + WorkerDataArray _cur_string_dedup_queue_fixup_worker_times_ms; + WorkerDataArray _cur_string_dedup_table_fixup_worker_times_ms; + double _cur_clear_ct_time_ms; double _cur_ref_proc_time_ms; double _cur_ref_enq_time_ms; @@ -246,6 +250,21 @@ class G1GCPhaseTimes : public CHeapObj { _cur_evac_fail_remove_self_forwards = ms; } + void note_string_dedup_fixup_start(); + void note_string_dedup_fixup_end(); + + void record_string_dedup_fixup_time(double ms) { + _cur_string_dedup_fixup_time_ms = ms; + } + + void record_string_dedup_queue_fixup_worker_time(uint worker_id, double ms) { + _cur_string_dedup_queue_fixup_worker_times_ms.set(worker_id, ms); + } + + void record_string_dedup_table_fixup_worker_time(uint worker_id, double ms) { + _cur_string_dedup_table_fixup_worker_times_ms.set(worker_id, ms); + } + void record_ref_proc_time(double ms) { _cur_ref_proc_time_ms = ms; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp index 83fbd0835b8..d8bda059bb8 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -31,6 +31,7 @@ #include "code/icBuffer.hpp" #include "gc_implementation/g1/g1Log.hpp" #include "gc_implementation/g1/g1MarkSweep.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shared/gcTrace.hpp" @@ -316,6 +317,10 @@ void G1MarkSweep::mark_sweep_phase3() { // have been cleared if they pointed to non-surviving objects.) sh->process_weak_roots(&GenMarkSweep::adjust_pointer_closure); + if (G1StringDedup::is_enabled()) { + G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); + } + GenMarkSweep::adjust_marks(); G1AdjustPointersClosure blk; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp new file mode 100644 index 00000000000..b1f8e01524e --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2014, 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 "classfile/javaClasses.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1GCPhaseTimes.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" +#include "gc_implementation/g1/g1StringDedupQueue.hpp" +#include "gc_implementation/g1/g1StringDedupStat.hpp" +#include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "gc_implementation/g1/g1StringDedupThread.hpp" + +bool G1StringDedup::_enabled = false; + +void G1StringDedup::initialize() { + assert(UseG1GC, "String deduplication only available with G1"); + if (UseStringDeduplication) { + _enabled = true; + G1StringDedupQueue::create(); + G1StringDedupTable::create(); + G1StringDedupThread::create(); + } +} + +bool G1StringDedup::is_candidate_from_mark(oop obj) { + if (java_lang_String::is_instance(obj)) { + bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young(); + if (from_young && obj->age() < StringDeduplicationAgeThreshold) { + // Candidate found. String is being evacuated from young to old but has not + // reached the deduplication age threshold, i.e. has not previously been a + // candidate during its life in the young generation. + return true; + } + } + + // Not a candidate + return false; +} + +void G1StringDedup::enqueue_from_mark(oop java_string) { + assert(is_enabled(), "String deduplication not enabled"); + if (is_candidate_from_mark(java_string)) { + G1StringDedupQueue::push(0 /* worker_id */, java_string); + } +} + +bool G1StringDedup::is_candidate_from_evacuation(bool from_young, bool to_young, oop obj) { + if (from_young && java_lang_String::is_instance(obj)) { + if (to_young && obj->age() == StringDeduplicationAgeThreshold) { + // Candidate found. String is being evacuated from young to young and just + // reached the deduplication age threshold. + return true; + } + if (!to_young && obj->age() < StringDeduplicationAgeThreshold) { + // Candidate found. String is being evacuated from young to old but has not + // reached the deduplication age threshold, i.e. has not previously been a + // candidate during its life in the young generation. + return true; + } + } + + // Not a candidate + return false; +} + +void G1StringDedup::enqueue_from_evacuation(bool from_young, bool to_young, uint worker_id, oop java_string) { + assert(is_enabled(), "String deduplication not enabled"); + if (is_candidate_from_evacuation(from_young, to_young, java_string)) { + G1StringDedupQueue::push(worker_id, java_string); + } +} + +void G1StringDedup::deduplicate(oop java_string) { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupStat dummy; // Statistics from this path is never used + G1StringDedupTable::deduplicate(java_string, dummy); +} + +void G1StringDedup::oops_do(OopClosure* keep_alive) { + assert(is_enabled(), "String deduplication not enabled"); + unlink_or_oops_do(NULL, keep_alive); +} + +void G1StringDedup::unlink(BoolObjectClosure* is_alive) { + assert(is_enabled(), "String deduplication not enabled"); + // Don't allow a potential resize or rehash during unlink, as the unlink + // operation itself might remove enough entries to invalidate such a decision. + unlink_or_oops_do(is_alive, NULL, false /* allow_resize_and_rehash */); +} + +// +// Task for parallel unlink_or_oops_do() operation on the deduplication queue +// and table. +// +class G1StringDedupUnlinkOrOopsDoTask : public AbstractGangTask { +private: + G1StringDedupUnlinkOrOopsDoClosure _cl; + +public: + G1StringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash) : + AbstractGangTask("G1StringDedupUnlinkOrOopsDoTask"), + _cl(is_alive, keep_alive, allow_resize_and_rehash) { + } + + virtual void work(uint worker_id) { + double queue_fixup_start = os::elapsedTime(); + G1StringDedupQueue::unlink_or_oops_do(&_cl); + + double table_fixup_start = os::elapsedTime(); + G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id); + + double queue_fixup_time_ms = (table_fixup_start - queue_fixup_start) * 1000.0; + double table_fixup_time_ms = (os::elapsedTime() - table_fixup_start) * 1000.0; + G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); + g1p->phase_times()->record_string_dedup_queue_fixup_worker_time(worker_id, queue_fixup_time_ms); + g1p->phase_times()->record_string_dedup_table_fixup_worker_time(worker_id, table_fixup_time_ms); + } +}; + +void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool allow_resize_and_rehash) { + assert(is_enabled(), "String deduplication not enabled"); + G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy(); + g1p->phase_times()->note_string_dedup_fixup_start(); + double fixup_start = os::elapsedTime(); + + G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash); + if (G1CollectedHeap::use_parallel_gc_threads()) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + g1h->set_par_threads(); + g1h->workers()->run_task(&task); + g1h->set_par_threads(0); + } else { + task.work(0); + } + + double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0; + g1p->phase_times()->record_string_dedup_fixup_time(fixup_time_ms); + g1p->phase_times()->note_string_dedup_fixup_end(); +} + +void G1StringDedup::threads_do(ThreadClosure* tc) { + assert(is_enabled(), "String deduplication not enabled"); + tc->do_thread(G1StringDedupThread::thread()); +} + +void G1StringDedup::print_worker_threads_on(outputStream* st) { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupThread::thread()->print_on(st); + st->cr(); +} + +void G1StringDedup::verify() { + assert(is_enabled(), "String deduplication not enabled"); + G1StringDedupQueue::verify(); + G1StringDedupTable::verify(); +} + +G1StringDedupUnlinkOrOopsDoClosure::G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash) : + _is_alive(is_alive), + _keep_alive(keep_alive), + _resized_table(NULL), + _rehashed_table(NULL), + _next_queue(0), + _next_bucket(0) { + if (allow_resize_and_rehash) { + // If both resize and rehash is needed, only do resize. Rehash of + // the table will eventually happen if the situation persists. + _resized_table = G1StringDedupTable::prepare_resize(); + if (!is_resizing()) { + _rehashed_table = G1StringDedupTable::prepare_rehash(); + } + } +} + +G1StringDedupUnlinkOrOopsDoClosure::~G1StringDedupUnlinkOrOopsDoClosure() { + assert(!is_resizing() || !is_rehashing(), "Can not both resize and rehash"); + if (is_resizing()) { + G1StringDedupTable::finish_resize(_resized_table); + } else if (is_rehashing()) { + G1StringDedupTable::finish_rehash(_rehashed_table); + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp new file mode 100644 index 00000000000..80af6b661d2 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedup.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2014, 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_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP + +// +// String Deduplication +// +// String deduplication aims to reduce the heap live-set by deduplicating identical +// instances of String so that they share the same backing character array. +// +// The deduplication process is divided in two main parts, 1) finding the objects to +// deduplicate, and 2) deduplicating those objects. The first part is done as part of +// a normal GC cycle when objects are marked or evacuated. At this time a check is +// applied on each object to check if it is a candidate for deduplication. If so, the +// object is placed on the deduplication queue for later processing. The second part, +// processing the objects on the deduplication queue, is a concurrent phase which +// starts right after the stop-the-wold marking/evacuation phase. This phase is +// executed by the deduplication thread, which pulls deduplication candidates of the +// deduplication queue and tries to deduplicate them. +// +// A deduplication hashtable is used to keep track of all unique character arrays +// used by String objects. When deduplicating, a lookup is made in this table to see +// if there is already an identical character array somewhere on the heap. If so, the +// String object is adjusted to point to that character array, releasing the reference +// to the original array allowing it to eventually be garbage collected. If the lookup +// fails the character array is instead inserted into the hashtable so that this array +// can be shared at some point in the future. +// +// Candidate selection +// +// An object is considered a deduplication candidate if all of the following +// statements are true: +// +// - The object is an instance of java.lang.String +// +// - The object is being evacuated from a young heap region +// +// - The object is being evacuated to a young/survivor heap region and the +// object's age is equal to the deduplication age threshold +// +// or +// +// The object is being evacuated to an old heap region and the object's age is +// less than the deduplication age threshold +// +// Once an string object has been promoted to an old region, or its age is higher +// than the deduplication age threshold, is will never become a candidate again. +// This approach avoids making the same object a candidate more than once. +// +// Interned strings are a bit special. They are explicitly deduplicated just before +// being inserted into the StringTable (to avoid counteracting C2 optimizations done +// on string literals), then they also become deduplication candidates if they reach +// the deduplication age threshold or are evacuated to an old heap region. The second +// attempt to deduplicate such strings will be in vain, but we have no fast way of +// filtering them out. This has not shown to be a problem, as the number of interned +// strings is usually dwarfed by the number of normal (non-interned) strings. +// +// For additional information on string deduplication, please see JEP 192, +// http://openjdk.java.net/jeps/192 +// + +#include "memory/allocation.hpp" +#include "oops/oop.hpp" + +class OopClosure; +class BoolObjectClosure; +class ThreadClosure; +class outputStream; +class G1StringDedupTable; + +// +// Main interface for interacting with string deduplication. +// +class G1StringDedup : public AllStatic { +private: + // Single state for checking if both G1 and string deduplication is enabled. + static bool _enabled; + + // Candidate selection policies, returns true if the given object is + // candidate for string deduplication. + static bool is_candidate_from_mark(oop obj); + static bool is_candidate_from_evacuation(bool from_young, bool to_young, oop obj); + +public: + // Returns true if both G1 and string deduplication is enabled. + static bool is_enabled() { + return _enabled; + } + + static void initialize(); + + // Immediately deduplicates the given String object, bypassing the + // the deduplication queue. + static void deduplicate(oop java_string); + + // Enqueues a deduplication candidate for later processing by the deduplication + // thread. Before enqueuing, these functions apply the appropriate candidate + // selection policy to filters out non-candidates. + static void enqueue_from_mark(oop java_string); + static void enqueue_from_evacuation(bool from_young, bool to_young, + unsigned int queue, oop java_string); + + static void oops_do(OopClosure* keep_alive); + static void unlink(BoolObjectClosure* is_alive); + static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, + bool allow_resize_and_rehash = true); + + static void threads_do(ThreadClosure* tc); + static void print_worker_threads_on(outputStream* st); + static void verify(); +}; + +// +// This closure encapsulates the state and the closures needed when scanning +// the deduplication queue and table during the unlink_or_oops_do() operation. +// A single instance of this closure is created and then shared by all worker +// threads participating in the scan. The _next_queue and _next_bucket fields +// provide a simple mechanism for GC workers to claim exclusive access to a +// queue or a table partition. +// +class G1StringDedupUnlinkOrOopsDoClosure : public StackObj { +private: + BoolObjectClosure* _is_alive; + OopClosure* _keep_alive; + G1StringDedupTable* _resized_table; + G1StringDedupTable* _rehashed_table; + size_t _next_queue; + size_t _next_bucket; + +public: + G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive, + OopClosure* keep_alive, + bool allow_resize_and_rehash); + ~G1StringDedupUnlinkOrOopsDoClosure(); + + bool is_resizing() { + return _resized_table != NULL; + } + + G1StringDedupTable* resized_table() { + return _resized_table; + } + + bool is_rehashing() { + return _rehashed_table != NULL; + } + + // Atomically claims the next available queue for exclusive access by + // the current thread. Returns the queue number of the claimed queue. + size_t claim_queue() { + return (size_t)Atomic::add_ptr(1, &_next_queue) - 1; + } + + // Atomically claims the next available table partition for exclusive + // access by the current thread. Returns the table bucket number where + // the claimed partition starts. + size_t claim_table_partition(size_t partition_size) { + return (size_t)Atomic::add_ptr(partition_size, &_next_bucket) - partition_size; + } + + // Applies and returns the result from the is_alive closure, or + // returns true if no such closure was provided. + bool is_alive(oop o) { + if (_is_alive != NULL) { + return _is_alive->do_object_b(o); + } + return true; + } + + // Applies the keep_alive closure, or does nothing if no such + // closure was provided. + void keep_alive(oop* p) { + if (_keep_alive != NULL) { + _keep_alive->do_oop(p); + } + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp new file mode 100644 index 00000000000..330b5a434c2 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014, 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 "classfile/javaClasses.hpp" +#include "gc_implementation/g1/g1StringDedupQueue.hpp" +#include "memory/gcLocker.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/stack.inline.hpp" + +G1StringDedupQueue* G1StringDedupQueue::_queue = NULL; +const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue +const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue + +G1StringDedupQueue::G1StringDedupQueue() : + _cursor(0), + _empty(true), + _dropped(0) { + _nqueues = MAX2(ParallelGCThreads, (size_t)1); + _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC); + for (size_t i = 0; i < _nqueues; i++) { + new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size); + } +} + +G1StringDedupQueue::~G1StringDedupQueue() { + ShouldNotReachHere(); +} + +void G1StringDedupQueue::create() { + assert(_queue == NULL, "One string deduplication queue allowed"); + _queue = new G1StringDedupQueue(); +} + +void G1StringDedupQueue::wait() { + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); + while (_queue->_empty) { + ml.wait(Mutex::_no_safepoint_check_flag); + } +} + +void G1StringDedupQueue::push(uint worker_id, oop java_string) { + assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); + assert(worker_id < _queue->_nqueues, "Invalid queue"); + + // Push and notify waiter + G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id]; + if (!worker_queue.is_full()) { + worker_queue.push(java_string); + if (_queue->_empty) { + MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); + if (_queue->_empty) { + // Mark non-empty and notify waiter + _queue->_empty = false; + ml.notify(); + } + } + } else { + // Queue is full, drop the string and update the statistics + Atomic::inc_ptr(&_queue->_dropped); + } +} + +oop G1StringDedupQueue::pop() { + assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint"); + No_Safepoint_Verifier nsv; + + // Try all queues before giving up + for (size_t tries = 0; tries < _queue->_nqueues; tries++) { + // The cursor indicates where we left of last time + G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor]; + while (!queue->is_empty()) { + oop obj = queue->pop(); + // The oop we pop can be NULL if it was marked + // dead. Just ignore those and pop the next oop. + if (obj != NULL) { + return obj; + } + } + + // Try next queue + _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues; + } + + // Mark empty + _queue->_empty = true; + + return NULL; +} + +void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) { + // A worker thread first claims a queue, which ensures exclusive + // access to that queue, then continues to process it. + for (;;) { + // Grab next queue to scan + size_t queue = cl->claim_queue(); + if (queue >= _queue->_nqueues) { + // End of queues + break; + } + + // Scan the queue + unlink_or_oops_do(cl, queue); + } +} + +void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) { + assert(queue < _queue->_nqueues, "Invalid queue"); + StackIterator iter(_queue->_queues[queue]); + while (!iter.is_empty()) { + oop* p = iter.next_addr(); + if (*p != NULL) { + if (cl->is_alive(*p)) { + cl->keep_alive(p); + } else { + // Clear dead reference + *p = NULL; + } + } + } +} + +void G1StringDedupQueue::print_statistics(outputStream* st) { + st->print_cr( + " [Queue]\n" + " [Dropped: "UINTX_FORMAT"]", _queue->_dropped); +} + +void G1StringDedupQueue::verify() { + for (size_t i = 0; i < _queue->_nqueues; i++) { + StackIterator iter(_queue->_queues[i]); + while (!iter.is_empty()) { + oop obj = iter.next(); + if (obj != NULL) { + guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); + guarantee(!obj->is_forwarded(), "Object must not be forwarded"); + guarantee(java_lang_String::is_instance(obj), "Object must be a String"); + } + } + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp new file mode 100644 index 00000000000..1690247b769 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupQueue.hpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, 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_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP + +#include "memory/allocation.hpp" +#include "oops/oop.hpp" +#include "utilities/stack.hpp" + +class G1StringDedupUnlinkOrOopsDoClosure; + +// +// The deduplication queue acts as the communication channel between the stop-the-world +// mark/evacuation phase and the concurrent deduplication phase. Deduplication candidates +// found during mark/evacuation are placed on this queue for later processing in the +// deduplication thread. A queue entry is an oop pointing to a String object (as opposed +// to entries in the deduplication hashtable which points to character arrays). +// +// While users of the queue treat it as a single queue, it is implemented as a set of +// queues, one queue per GC worker thread, to allow lock-free and cache-friendly enqueue +// operations by the GC workers. +// +// The oops in the queue are treated as weak pointers, meaning the objects they point to +// can become unreachable and pruned (cleared) before being popped by the deduplication +// thread. +// +// Pushing to the queue is thread safe (this relies on each thread using a unique worker +// id), but only allowed during a safepoint. Popping from the queue is NOT thread safe +// and can only be done by the deduplication thread outside a safepoint. +// +// The StringDedupQueue_lock is only used for blocking and waking up the deduplication +// thread in case the queue is empty or becomes non-empty, respectively. This lock does +// not otherwise protect the queue content. +// +class G1StringDedupQueue : public CHeapObj { +private: + typedef Stack G1StringDedupWorkerQueue; + + static G1StringDedupQueue* _queue; + static const size_t _max_size; + static const size_t _max_cache_size; + + G1StringDedupWorkerQueue* _queues; + size_t _nqueues; + size_t _cursor; + volatile bool _empty; + + // Statistics counter, only used for logging. + uintx _dropped; + + G1StringDedupQueue(); + ~G1StringDedupQueue(); + + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue); + +public: + static void create(); + + // Blocks and waits for the queue to become non-empty. + static void wait(); + + // Pushes a deduplication candidate onto a specific GC worker queue. + static void push(uint worker_id, oop java_string); + + // Pops a deduplication candidate from any queue, returns NULL if + // all queues are empty. + static oop pop(); + + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl); + + static void print_statistics(outputStream* st); + static void verify(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp new file mode 100644 index 00000000000..2d5523cce9e --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014, 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_implementation/g1/g1StringDedupStat.hpp" + +G1StringDedupStat::G1StringDedupStat() : + _inspected(0), + _skipped(0), + _hashed(0), + _known(0), + _new(0), + _new_bytes(0), + _deduped(0), + _deduped_bytes(0), + _deduped_young(0), + _deduped_young_bytes(0), + _deduped_old(0), + _deduped_old_bytes(0), + _idle(0), + _exec(0), + _block(0), + _start(0.0), + _idle_elapsed(0.0), + _exec_elapsed(0.0), + _block_elapsed(0.0) { +} + +void G1StringDedupStat::add(const G1StringDedupStat& stat) { + _inspected += stat._inspected; + _skipped += stat._skipped; + _hashed += stat._hashed; + _known += stat._known; + _new += stat._new; + _new_bytes += stat._new_bytes; + _deduped += stat._deduped; + _deduped_bytes += stat._deduped_bytes; + _deduped_young += stat._deduped_young; + _deduped_young_bytes += stat._deduped_young_bytes; + _deduped_old += stat._deduped_old; + _deduped_old_bytes += stat._deduped_old_bytes; + _idle += stat._idle; + _exec += stat._exec; + _block += stat._block; + _idle_elapsed += stat._idle_elapsed; + _exec_elapsed += stat._exec_elapsed; + _block_elapsed += stat._block_elapsed; +} + +void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { + double total_deduped_bytes_percent = 0.0; + + if (total_stat._new_bytes > 0) { + // Avoid division by zero + total_deduped_bytes_percent = (double)total_stat._deduped_bytes / (double)total_stat._new_bytes * 100.0; + } + + st->date_stamp(PrintGCDateStamps); + st->stamp(PrintGCTimeStamps); + st->print_cr( + "[GC concurrent-string-deduplication, " + G1_STRDEDUP_BYTES_FORMAT_NS"->"G1_STRDEDUP_BYTES_FORMAT_NS"("G1_STRDEDUP_BYTES_FORMAT_NS"), avg " + G1_STRDEDUP_PERCENT_FORMAT_NS", "G1_STRDEDUP_TIME_FORMAT"]", + G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes), + G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes), + G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes), + total_deduped_bytes_percent, + last_stat._exec_elapsed); +} + +void G1StringDedupStat::print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total) { + double young_percent = 0.0; + double old_percent = 0.0; + double skipped_percent = 0.0; + double hashed_percent = 0.0; + double known_percent = 0.0; + double new_percent = 0.0; + double deduped_percent = 0.0; + double deduped_bytes_percent = 0.0; + double deduped_young_percent = 0.0; + double deduped_young_bytes_percent = 0.0; + double deduped_old_percent = 0.0; + double deduped_old_bytes_percent = 0.0; + + if (stat._inspected > 0) { + // Avoid division by zero + skipped_percent = (double)stat._skipped / (double)stat._inspected * 100.0; + hashed_percent = (double)stat._hashed / (double)stat._inspected * 100.0; + known_percent = (double)stat._known / (double)stat._inspected * 100.0; + new_percent = (double)stat._new / (double)stat._inspected * 100.0; + } + + if (stat._new > 0) { + // Avoid division by zero + deduped_percent = (double)stat._deduped / (double)stat._new * 100.0; + } + + if (stat._deduped > 0) { + // Avoid division by zero + deduped_young_percent = (double)stat._deduped_young / (double)stat._deduped * 100.0; + deduped_old_percent = (double)stat._deduped_old / (double)stat._deduped * 100.0; + } + + if (stat._new_bytes > 0) { + // Avoid division by zero + deduped_bytes_percent = (double)stat._deduped_bytes / (double)stat._new_bytes * 100.0; + } + + if (stat._deduped_bytes > 0) { + // Avoid division by zero + deduped_young_bytes_percent = (double)stat._deduped_young_bytes / (double)stat._deduped_bytes * 100.0; + deduped_old_bytes_percent = (double)stat._deduped_old_bytes / (double)stat._deduped_bytes * 100.0; + } + + if (total) { + st->print_cr( + " [Total Exec: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Idle: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]", + stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed); + } else { + st->print_cr( + " [Last Exec: "G1_STRDEDUP_TIME_FORMAT", Idle: "G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]", + stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed); + } + st->print_cr( + " [Inspected: "G1_STRDEDUP_OBJECTS_FORMAT"]\n" + " [Skipped: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Hashed: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Known: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [New: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"]\n" + " [Deduplicated: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Young: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n" + " [Old: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]", + stat._inspected, + stat._skipped, skipped_percent, + stat._hashed, hashed_percent, + stat._known, known_percent, + stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes), + stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent, + stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent, + stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp new file mode 100644 index 00000000000..bfb55caa720 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupStat.hpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, 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_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP + +#include "memory/allocation.hpp" +#include "runtime/os.hpp" + +// Macros for GC log output formating +#define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12) +#define G1_STRDEDUP_TIME_FORMAT "%1.7lf secs" +#define G1_STRDEDUP_PERCENT_FORMAT "%5.1lf%%" +#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1lf%%" +#define G1_STRDEDUP_BYTES_FORMAT "%8.1lf%s" +#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1lf%s" +#define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes)) + +// +// Statistics gathered by the deduplication thread. +// +class G1StringDedupStat : public StackObj { +private: + // Counters + uintx _inspected; + uintx _skipped; + uintx _hashed; + uintx _known; + uintx _new; + uintx _new_bytes; + uintx _deduped; + uintx _deduped_bytes; + uintx _deduped_young; + uintx _deduped_young_bytes; + uintx _deduped_old; + uintx _deduped_old_bytes; + uintx _idle; + uintx _exec; + uintx _block; + + // Time spent by the deduplication thread in different phases + double _start; + double _idle_elapsed; + double _exec_elapsed; + double _block_elapsed; + +public: + G1StringDedupStat(); + + void inc_inspected() { + _inspected++; + } + + void inc_skipped() { + _skipped++; + } + + void inc_hashed() { + _hashed++; + } + + void inc_known() { + _known++; + } + + void inc_new(uintx bytes) { + _new++; + _new_bytes += bytes; + } + + void inc_deduped_young(uintx bytes) { + _deduped++; + _deduped_bytes += bytes; + _deduped_young++; + _deduped_young_bytes += bytes; + } + + void inc_deduped_old(uintx bytes) { + _deduped++; + _deduped_bytes += bytes; + _deduped_old++; + _deduped_old_bytes += bytes; + } + + void mark_idle() { + _start = os::elapsedTime(); + _idle++; + } + + void mark_exec() { + double now = os::elapsedTime(); + _idle_elapsed = now - _start; + _start = now; + _exec++; + } + + void mark_block() { + double now = os::elapsedTime(); + _exec_elapsed += now - _start; + _start = now; + _block++; + } + + void mark_unblock() { + double now = os::elapsedTime(); + _block_elapsed += now - _start; + _start = now; + } + + void mark_done() { + double now = os::elapsedTime(); + _exec_elapsed += now - _start; + } + + void add(const G1StringDedupStat& stat); + + static void print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + static void print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp new file mode 100644 index 00000000000..2b41688a3e5 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2014, 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 "classfile/altHashing.hpp" +#include "classfile/javaClasses.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "memory/gcLocker.hpp" +#include "memory/padded.inline.hpp" +#include "oops/typeArrayOop.hpp" +#include "runtime/mutexLocker.hpp" + +// +// Freelist in the deduplication table entry cache. Links table +// entries together using their _next fields. +// +class G1StringDedupEntryFreeList : public CHeapObj { +private: + G1StringDedupEntry* _list; + size_t _length; + +public: + G1StringDedupEntryFreeList() : + _list(NULL), + _length(0) { + } + + void add(G1StringDedupEntry* entry) { + entry->set_next(_list); + _list = entry; + _length++; + } + + G1StringDedupEntry* remove() { + G1StringDedupEntry* entry = _list; + if (entry != NULL) { + _list = entry->next(); + _length--; + } + return entry; + } + + size_t length() { + return _length; + } +}; + +// +// Cache of deduplication table entries. This cache provides fast allocation and +// reuse of table entries to lower the pressure on the underlying allocator. +// But more importantly, it provides fast/deferred freeing of table entries. This +// is important because freeing of table entries is done during stop-the-world +// phases and it is not uncommon for large number of entries to be freed at once. +// Tables entries that are freed during these phases are placed onto a freelist in +// the cache. The deduplication thread, which executes in a concurrent phase, will +// later reuse or free the underlying memory for these entries. +// +// The cache allows for single-threaded allocations and multi-threaded frees. +// Allocations are synchronized by StringDedupTable_lock as part of a table +// modification. +// +class G1StringDedupEntryCache : public CHeapObj { +private: + // One freelist per GC worker to allow lock less freeing of + // entries while doing a parallel scan of the table. Using + // PaddedEnd to avoid false sharing. + PaddedEnd* _lists; + size_t _nlists; + +public: + G1StringDedupEntryCache(); + ~G1StringDedupEntryCache(); + + // Get a table entry from the cache freelist, or allocate a new + // entry if the cache is empty. + G1StringDedupEntry* alloc(); + + // Insert a table entry into the cache freelist. + void free(G1StringDedupEntry* entry, uint worker_id); + + // Returns current number of entries in the cache. + size_t size(); + + // If the cache has grown above the given max size, trim it down + // and deallocate the memory occupied by trimmed of entries. + void trim(size_t max_size); +}; + +G1StringDedupEntryCache::G1StringDedupEntryCache() { + _nlists = MAX2(ParallelGCThreads, (size_t)1); + _lists = PaddedArray::create_unfreeable((uint)_nlists); +} + +G1StringDedupEntryCache::~G1StringDedupEntryCache() { + ShouldNotReachHere(); +} + +G1StringDedupEntry* G1StringDedupEntryCache::alloc() { + for (size_t i = 0; i < _nlists; i++) { + G1StringDedupEntry* entry = _lists[i].remove(); + if (entry != NULL) { + return entry; + } + } + return new G1StringDedupEntry(); +} + +void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { + assert(entry->obj() != NULL, "Double free"); + assert(worker_id < _nlists, "Invalid worker id"); + entry->set_obj(NULL); + entry->set_hash(0); + _lists[worker_id].add(entry); +} + +size_t G1StringDedupEntryCache::size() { + size_t size = 0; + for (size_t i = 0; i < _nlists; i++) { + size += _lists[i].length(); + } + return size; +} + +void G1StringDedupEntryCache::trim(size_t max_size) { + size_t cache_size = 0; + for (size_t i = 0; i < _nlists; i++) { + G1StringDedupEntryFreeList* list = &_lists[i]; + cache_size += list->length(); + while (cache_size > max_size) { + G1StringDedupEntry* entry = list->remove(); + assert(entry != NULL, "Should not be null"); + cache_size--; + delete entry; + } + } +} + +G1StringDedupTable* G1StringDedupTable::_table = NULL; +G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL; + +const size_t G1StringDedupTable::_min_size = (1 << 10); // 1024 +const size_t G1StringDedupTable::_max_size = (1 << 24); // 16777216 +const double G1StringDedupTable::_grow_load_factor = 2.0; // Grow table at 200% load +const double G1StringDedupTable::_shrink_load_factor = _grow_load_factor / 3.0; // Shrink table at 67% load +const double G1StringDedupTable::_max_cache_factor = 0.1; // Cache a maximum of 10% of the table size +const uintx G1StringDedupTable::_rehash_multiple = 60; // Hash bucket has 60 times more collisions than expected +const uintx G1StringDedupTable::_rehash_threshold = (uintx)(_rehash_multiple * _grow_load_factor); + +uintx G1StringDedupTable::_entries_added = 0; +uintx G1StringDedupTable::_entries_removed = 0; +uintx G1StringDedupTable::_resize_count = 0; +uintx G1StringDedupTable::_rehash_count = 0; + +G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) : + _size(size), + _entries(0), + _grow_threshold((uintx)(size * _grow_load_factor)), + _shrink_threshold((uintx)(size * _shrink_load_factor)), + _rehash_needed(false), + _hash_seed(hash_seed) { + assert(is_power_of_2(size), "Table size must be a power of 2"); + _buckets = NEW_C_HEAP_ARRAY(G1StringDedupEntry*, _size, mtGC); + memset(_buckets, 0, _size * sizeof(G1StringDedupEntry*)); +} + +G1StringDedupTable::~G1StringDedupTable() { + FREE_C_HEAP_ARRAY(G1StringDedupEntry*, _buckets, mtGC); +} + +void G1StringDedupTable::create() { + assert(_table == NULL, "One string deduplication table allowed"); + _entry_cache = new G1StringDedupEntryCache(); + _table = new G1StringDedupTable(_min_size); +} + +void G1StringDedupTable::add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list) { + G1StringDedupEntry* entry = _entry_cache->alloc(); + entry->set_obj(value); + entry->set_hash(hash); + entry->set_next(*list); + *list = entry; + _entries++; +} + +void G1StringDedupTable::remove(G1StringDedupEntry** pentry, uint worker_id) { + G1StringDedupEntry* entry = *pentry; + *pentry = entry->next(); + _entry_cache->free(entry, worker_id); +} + +void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) { + G1StringDedupEntry* entry = *pentry; + *pentry = entry->next(); + unsigned int hash = entry->hash(); + size_t index = dest->hash_to_index(hash); + G1StringDedupEntry** list = dest->bucket(index); + entry->set_next(*list); + *list = entry; +} + +bool G1StringDedupTable::equals(typeArrayOop value1, typeArrayOop value2) { + return (value1 == value2 || + (value1->length() == value2->length() && + (!memcmp(value1->base(T_CHAR), + value2->base(T_CHAR), + value1->length() * sizeof(jchar))))); +} + +typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, unsigned int hash, + G1StringDedupEntry** list, uintx &count) { + for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) { + if (entry->hash() == hash) { + typeArrayOop existing_value = entry->obj(); + if (equals(value, existing_value)) { + // Match found + return existing_value; + } + } + count++; + } + + // Not found + return NULL; +} + +typeArrayOop G1StringDedupTable::lookup_or_add_inner(typeArrayOop value, unsigned int hash) { + size_t index = hash_to_index(hash); + G1StringDedupEntry** list = bucket(index); + uintx count = 0; + + // Lookup in list + typeArrayOop existing_value = lookup(value, hash, list, count); + + // Check if rehash is needed + if (count > _rehash_threshold) { + _rehash_needed = true; + } + + if (existing_value == NULL) { + // Not found, add new entry + add(value, hash, list); + + // Update statistics + _entries_added++; + } + + return existing_value; +} + +unsigned int G1StringDedupTable::hash_code(typeArrayOop value) { + unsigned int hash; + int length = value->length(); + const jchar* data = (jchar*)value->base(T_CHAR); + + if (use_java_hash()) { + hash = java_lang_String::hash_code(data, length); + } else { + hash = AltHashing::murmur3_32(_table->_hash_seed, data, length); + } + + return hash; +} + +void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) { + assert(java_lang_String::is_instance(java_string), "Must be a string"); + No_Safepoint_Verifier nsv; + + stat.inc_inspected(); + + typeArrayOop value = java_lang_String::value(java_string); + if (value == NULL) { + // String has no value + stat.inc_skipped(); + return; + } + + unsigned int hash = 0; + + if (use_java_hash()) { + // Get hash code from cache + hash = java_lang_String::hash(java_string); + } + + if (hash == 0) { + // Compute hash + hash = hash_code(value); + stat.inc_hashed(); + } + + if (use_java_hash() && hash != 0) { + // Store hash code in cache + java_lang_String::set_hash(java_string, hash); + } + + typeArrayOop existing_value = lookup_or_add(value, hash); + if (existing_value == value) { + // Same value, already known + stat.inc_known(); + return; + } + + // Get size of value array + uintx size_in_bytes = value->size() * HeapWordSize; + stat.inc_new(size_in_bytes); + + if (existing_value != NULL) { + // Enqueue the reference to make sure it is kept alive. Concurrent mark might + // otherwise declare it dead if there are no other strong references to this object. + G1SATBCardTableModRefBS::enqueue(existing_value); + + // Existing value found, deduplicate string + java_lang_String::set_value(java_string, existing_value); + + if (G1CollectedHeap::heap()->is_in_young(value)) { + stat.inc_deduped_young(size_in_bytes); + } else { + stat.inc_deduped_old(size_in_bytes); + } + } +} + +G1StringDedupTable* G1StringDedupTable::prepare_resize() { + size_t size = _table->_size; + + // Check if the hashtable needs to be resized + if (_table->_entries > _table->_grow_threshold) { + // Grow table, double the size + size *= 2; + if (size > _max_size) { + // Too big, don't resize + return NULL; + } + } else if (_table->_entries < _table->_shrink_threshold) { + // Shrink table, half the size + size /= 2; + if (size < _min_size) { + // Too small, don't resize + return NULL; + } + } else if (StringDeduplicationResizeALot) { + // Force grow + size *= 2; + if (size > _max_size) { + // Too big, force shrink instead + size /= 4; + } + } else { + // Resize not needed + return NULL; + } + + // Update statistics + _resize_count++; + + // Allocate the new table. The new table will be populated by workers + // calling unlink_or_oops_do() and finally installed by finish_resize(). + return new G1StringDedupTable(size, _table->_hash_seed); +} + +void G1StringDedupTable::finish_resize(G1StringDedupTable* resized_table) { + assert(resized_table != NULL, "Invalid table"); + + resized_table->_entries = _table->_entries; + + // Free old table + delete _table; + + // Install new table + _table = resized_table; +} + +void G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id) { + // The table is divided into partitions to allow lock-less parallel processing by + // multiple worker threads. A worker thread first claims a partition, which ensures + // exclusive access to that part of the table, then continues to process it. To allow + // shrinking of the table in parallel we also need to make sure that the same worker + // thread processes all partitions where entries will hash to the same destination + // partition. Since the table size is always a power of two and we always shrink by + // dividing the table in half, we know that for a given partition there is only one + // other partition whoes entries will hash to the same destination partition. That + // other partition is always the sibling partition in the second half of the table. + // For example, if the table is divided into 8 partitions, the sibling of partition 0 + // is partition 4, the sibling of partition 1 is partition 5, etc. + size_t table_half = _table->_size / 2; + + // Let each partition be one page worth of buckets + size_t partition_size = MIN2(table_half, os::vm_page_size() / sizeof(G1StringDedupEntry*)); + assert(table_half % partition_size == 0, "Invalid partition size"); + + // Number of entries removed during the scan + uintx removed = 0; + + for (;;) { + // Grab next partition to scan + size_t partition_begin = cl->claim_table_partition(partition_size); + size_t partition_end = partition_begin + partition_size; + if (partition_begin >= table_half) { + // End of table + break; + } + + // Scan the partition followed by the sibling partition in the second half of the table + removed += unlink_or_oops_do(cl, partition_begin, partition_end, worker_id); + removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id); + } + + // Delayed update avoid contention on the table lock + if (removed > 0) { + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); + _table->_entries -= removed; + _entries_removed += removed; + } +} + +uintx G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, + size_t partition_begin, + size_t partition_end, + uint worker_id) { + uintx removed = 0; + for (size_t bucket = partition_begin; bucket < partition_end; bucket++) { + G1StringDedupEntry** entry = _table->bucket(bucket); + while (*entry != NULL) { + oop* p = (oop*)(*entry)->obj_addr(); + if (cl->is_alive(*p)) { + cl->keep_alive(p); + if (cl->is_resizing()) { + // We are resizing the table, transfer entry to the new table + _table->transfer(entry, cl->resized_table()); + } else { + if (cl->is_rehashing()) { + // We are rehashing the table, rehash the entry but keep it + // in the table. We can't transfer entries into the new table + // at this point since we don't have exclusive access to all + // destination partitions. finish_rehash() will do a single + // threaded transfer of all entries. + typeArrayOop value = (typeArrayOop)*p; + unsigned int hash = hash_code(value); + (*entry)->set_hash(hash); + } + + // Move to next entry + entry = (*entry)->next_addr(); + } + } else { + // Not alive, remove entry from table + _table->remove(entry, worker_id); + removed++; + } + } + } + + return removed; +} + +G1StringDedupTable* G1StringDedupTable::prepare_rehash() { + if (!_table->_rehash_needed && !StringDeduplicationRehashALot) { + // Rehash not needed + return NULL; + } + + // Update statistics + _rehash_count++; + + // Compute new hash seed + _table->_hash_seed = AltHashing::compute_seed(); + + // Allocate the new table, same size and hash seed + return new G1StringDedupTable(_table->_size, _table->_hash_seed); +} + +void G1StringDedupTable::finish_rehash(G1StringDedupTable* rehashed_table) { + assert(rehashed_table != NULL, "Invalid table"); + + // Move all newly rehashed entries into the correct buckets in the new table + for (size_t bucket = 0; bucket < _table->_size; bucket++) { + G1StringDedupEntry** entry = _table->bucket(bucket); + while (*entry != NULL) { + _table->transfer(entry, rehashed_table); + } + } + + rehashed_table->_entries = _table->_entries; + + // Free old table + delete _table; + + // Install new table + _table = rehashed_table; +} + +void G1StringDedupTable::verify() { + for (size_t bucket = 0; bucket < _table->_size; bucket++) { + // Verify entries + G1StringDedupEntry** entry = _table->bucket(bucket); + while (*entry != NULL) { + typeArrayOop value = (*entry)->obj(); + guarantee(value != NULL, "Object must not be NULL"); + guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); + guarantee(!value->is_forwarded(), "Object must not be forwarded"); + guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); + unsigned int hash = hash_code(value); + guarantee((*entry)->hash() == hash, "Table entry has inorrect hash"); + guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index"); + entry = (*entry)->next_addr(); + } + + // Verify that we do not have entries with identical oops or identical arrays. + // We only need to compare entries in the same bucket. If the same oop or an + // identical array has been inserted more than once into different/incorrect + // buckets the verification step above will catch that. + G1StringDedupEntry** entry1 = _table->bucket(bucket); + while (*entry1 != NULL) { + typeArrayOop value1 = (*entry1)->obj(); + G1StringDedupEntry** entry2 = (*entry1)->next_addr(); + while (*entry2 != NULL) { + typeArrayOop value2 = (*entry2)->obj(); + guarantee(!equals(value1, value2), "Table entries must not have identical arrays"); + entry2 = (*entry2)->next_addr(); + } + entry1 = (*entry1)->next_addr(); + } + } +} + +void G1StringDedupTable::trim_entry_cache() { + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); + size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor); + _entry_cache->trim(max_cache_size); +} + +void G1StringDedupTable::print_statistics(outputStream* st) { + st->print_cr( + " [Table]\n" + " [Memory Usage: "G1_STRDEDUP_BYTES_FORMAT_NS"]\n" + " [Size: "SIZE_FORMAT", Min: "SIZE_FORMAT", Max: "SIZE_FORMAT"]\n" + " [Entries: "UINTX_FORMAT", Load: "G1_STRDEDUP_PERCENT_FORMAT_NS", Cached: " UINTX_FORMAT ", Added: "UINTX_FORMAT", Removed: "UINTX_FORMAT"]\n" + " [Resize Count: "UINTX_FORMAT", Shrink Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS"), Grow Threshold: "UINTX_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT_NS")]\n" + " [Rehash Count: "UINTX_FORMAT", Rehash Threshold: "UINTX_FORMAT", Hash Seed: 0x%x]\n" + " [Age Threshold: "UINTX_FORMAT"]", + G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), + _table->_size, _min_size, _max_size, + _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed, + _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0, + _rehash_count, _rehash_threshold, _table->_hash_seed, + StringDeduplicationAgeThreshold); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp new file mode 100644 index 00000000000..f357523c513 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2014, 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_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP + +#include "gc_implementation/g1/g1StringDedupStat.hpp" +#include "runtime/mutexLocker.hpp" + +class G1StringDedupEntryCache; + +// +// Table entry in the deduplication hashtable. Points weakly to the +// character array. Can be chained in a linked list in case of hash +// collisions or when placed in a freelist in the entry cache. +// +class G1StringDedupEntry : public CHeapObj { +private: + G1StringDedupEntry* _next; + unsigned int _hash; + typeArrayOop _obj; + +public: + G1StringDedupEntry() : + _next(NULL), + _hash(0), + _obj(NULL) { + } + + G1StringDedupEntry* next() { + return _next; + } + + G1StringDedupEntry** next_addr() { + return &_next; + } + + void set_next(G1StringDedupEntry* next) { + _next = next; + } + + unsigned int hash() { + return _hash; + } + + void set_hash(unsigned int hash) { + _hash = hash; + } + + typeArrayOop obj() { + return _obj; + } + + typeArrayOop* obj_addr() { + return &_obj; + } + + void set_obj(typeArrayOop obj) { + _obj = obj; + } +}; + +// +// The deduplication hashtable keeps track of all unique character arrays used +// by String objects. Each table entry weakly points to an character array, allowing +// otherwise unreachable character arrays to be declared dead and pruned from the +// table. +// +// The table is dynamically resized to accommodate the current number of table entries. +// The table has hash buckets with chains for hash collision. If the average chain +// length goes above or below given thresholds the table grows or shrinks accordingly. +// +// The table is also dynamically rehashed (using a new hash seed) if it becomes severely +// unbalanced, i.e., a hash chain is significantly longer than average. +// +// All access to the table is protected by the StringDedupTable_lock, except under +// safepoints in which case GC workers are allowed to access a table partitions they +// have claimed without first acquiring the lock. Note however, that this applies only +// the table partition (i.e. a range of elements in _buckets), not other parts of the +// table such as the _entries field, statistics counters, etc. +// +class G1StringDedupTable : public CHeapObj { +private: + // The currently active hashtable instance. Only modified when + // the table is resizes or rehashed. + static G1StringDedupTable* _table; + + // Cache for reuse and fast alloc/free of table entries. + static G1StringDedupEntryCache* _entry_cache; + + G1StringDedupEntry** _buckets; + size_t _size; + uintx _entries; + uintx _shrink_threshold; + uintx _grow_threshold; + bool _rehash_needed; + + // The hash seed also dictates which hash function to use. A + // zero hash seed means we will use the Java compatible hash + // function (which doesn't use a seed), and a non-zero hash + // seed means we use the murmur3 hash function. + jint _hash_seed; + + // Constants governing table resize/rehash/cache. + static const size_t _min_size; + static const size_t _max_size; + static const double _grow_load_factor; + static const double _shrink_load_factor; + static const uintx _rehash_multiple; + static const uintx _rehash_threshold; + static const double _max_cache_factor; + + // Table statistics, only used for logging. + static uintx _entries_added; + static uintx _entries_removed; + static uintx _resize_count; + static uintx _rehash_count; + + G1StringDedupTable(size_t size, jint hash_seed = 0); + ~G1StringDedupTable(); + + // Returns the hash bucket at the given index. + G1StringDedupEntry** bucket(size_t index) { + return _buckets + index; + } + + // Returns the hash bucket index for the given hash code. + size_t hash_to_index(unsigned int hash) { + return (size_t)hash & (_size - 1); + } + + // Adds a new table entry to the given hash bucket. + void add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list); + + // Removes the given table entry from the table. + void remove(G1StringDedupEntry** pentry, uint worker_id); + + // Transfers a table entry from the current table to the destination table. + void transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest); + + // Returns an existing character array in the given hash bucket, or NULL + // if no matching character array exists. + typeArrayOop lookup(typeArrayOop value, unsigned int hash, + G1StringDedupEntry** list, uintx &count); + + // Returns an existing character array in the table, or inserts a new + // table entry if no matching character array exists. + typeArrayOop lookup_or_add_inner(typeArrayOop value, unsigned int hash); + + // Thread safe lookup or add of table entry + static typeArrayOop lookup_or_add(typeArrayOop value, unsigned int hash) { + // Protect the table from concurrent access. Also note that this lock + // acts as a fence for _table, which could have been replaced by a new + // instance if the table was resized or rehashed. + MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); + return _table->lookup_or_add_inner(value, hash); + } + + // Returns true if the hashtable is currently using a Java compatible + // hash function. + static bool use_java_hash() { + return _table->_hash_seed == 0; + } + + static bool equals(typeArrayOop value1, typeArrayOop value2); + + // Computes the hash code for the given character array, using the + // currently active hash function and hash seed. + static unsigned int hash_code(typeArrayOop value); + + static uintx unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, + size_t partition_begin, + size_t partition_end, + uint worker_id); + +public: + static void create(); + + // Deduplicates the given String object, or adds its backing + // character array to the deduplication hashtable. + static void deduplicate(oop java_string, G1StringDedupStat& stat); + + // If a table resize is needed, returns a newly allocated empty + // hashtable of the proper size. + static G1StringDedupTable* prepare_resize(); + + // Installs a newly resized table as the currently active table + // and deletes the previously active table. + static void finish_resize(G1StringDedupTable* resized_table); + + // If a table rehash is needed, returns a newly allocated empty + // hashtable and updates the hash seed. + static G1StringDedupTable* prepare_rehash(); + + // Transfers rehashed entries from the currently active table into + // the new table. Installs the new table as the currently active table + // and deletes the previously active table. + static void finish_rehash(G1StringDedupTable* rehashed_table); + + // If the table entry cache has grown too large, trim it down according to policy + static void trim_entry_cache(); + + static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id); + + static void print_statistics(outputStream* st); + static void verify(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp new file mode 100644 index 00000000000..7263220a391 --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014, 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_implementation/g1/g1Log.hpp" +#include "gc_implementation/g1/g1StringDedup.hpp" +#include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "gc_implementation/g1/g1StringDedupThread.hpp" +#include "gc_implementation/g1/g1StringDedupQueue.hpp" + +G1StringDedupThread* G1StringDedupThread::_thread = NULL; + +G1StringDedupThread::G1StringDedupThread() : + ConcurrentGCThread() { + set_name("String Deduplication Thread"); + create_and_start(); +} + +G1StringDedupThread::~G1StringDedupThread() { + ShouldNotReachHere(); +} + +void G1StringDedupThread::create() { + assert(G1StringDedup::is_enabled(), "String deduplication not enabled"); + assert(_thread == NULL, "One string deduplication thread allowed"); + _thread = new G1StringDedupThread(); +} + +G1StringDedupThread* G1StringDedupThread::thread() { + assert(G1StringDedup::is_enabled(), "String deduplication not enabled"); + assert(_thread != NULL, "String deduplication thread not created"); + return _thread; +} + +void G1StringDedupThread::print_on(outputStream* st) const { + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} + +void G1StringDedupThread::run() { + G1StringDedupStat total_stat; + + initialize_in_thread(); + wait_for_universe_init(); + + // Main loop + for (;;) { + G1StringDedupStat stat; + + stat.mark_idle(); + + // Wait for the queue to become non-empty + G1StringDedupQueue::wait(); + + // Include this thread in safepoints + stsJoin(); + + stat.mark_exec(); + + // Process the queue + for (;;) { + oop java_string = G1StringDedupQueue::pop(); + if (java_string == NULL) { + break; + } + + G1StringDedupTable::deduplicate(java_string, stat); + + // Safepoint this thread if needed + if (stsShouldYield()) { + stat.mark_block(); + stsYield(NULL); + stat.mark_unblock(); + } + } + + G1StringDedupTable::trim_entry_cache(); + + stat.mark_done(); + + // Print statistics + total_stat.add(stat); + print(gclog_or_tty, stat, total_stat); + + // Exclude this thread from safepoints + stsLeave(); + } + + ShouldNotReachHere(); +} + +void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { + if (G1Log::fine() || PrintStringDeduplicationStatistics) { + G1StringDedupStat::print_summary(st, last_stat, total_stat); + if (PrintStringDeduplicationStatistics) { + G1StringDedupStat::print_statistics(st, last_stat, false); + G1StringDedupStat::print_statistics(st, total_stat, true); + G1StringDedupTable::print_statistics(st); + G1StringDedupQueue::print_statistics(st); + } + } +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp new file mode 100644 index 00000000000..8a93058fd1e --- /dev/null +++ b/hotspot/src/share/vm/gc_implementation/g1/g1StringDedupThread.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, 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_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP + +#include "gc_implementation/g1/g1StringDedupStat.hpp" +#include "gc_implementation/shared/concurrentGCThread.hpp" + +// +// The deduplication thread is where the actual deduplication occurs. It waits for +// deduplication candidates to appear on the deduplication queue, removes them from +// the queue and tries to deduplicate them. It uses the deduplication hashtable to +// find identical, already existing, character arrays on the heap. The thread runs +// concurrently with the Java application but participates in safepoints to allow +// the GC to adjust and unlink oops from the deduplication queue and table. +// +class G1StringDedupThread: public ConcurrentGCThread { +private: + static G1StringDedupThread* _thread; + + G1StringDedupThread(); + ~G1StringDedupThread(); + + void print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); + +public: + static void create(); + static G1StringDedupThread* thread(); + + virtual void run(); + virtual void print_on(outputStream* st) const; +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP diff --git a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp index 270d9de71bf..c08e7a6379b 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -30,10 +30,18 @@ #include "utilities/stack.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1StringDedup.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #endif // INCLUDE_ALL_GCS inline void MarkSweep::mark_object(oop obj) { +#if INCLUDE_ALL_GCS + if (G1StringDedup::is_enabled()) { + // We must enqueue the object before it is marked + // as we otherwise can't read the object's age. + G1StringDedup::enqueue_from_mark(obj); + } +#endif // some marks may contain information we need to preserve so we store them away // and overwrite the mark. We'll restore it at the end of markSweep. markOop mark = obj->mark(); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 3099df2e8ef..934a832edae 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2246,6 +2246,8 @@ bool Arguments::check_vm_args_consistency() { "G1ConcRSHotCardLimit"); status = status && verify_interval(G1ConcRSLogCacheSize, 0, 31, "G1ConcRSLogCacheSize"); + status = status && verify_interval(StringDeduplicationAgeThreshold, 1, markOopDesc::max_age, + "StringDeduplicationAgeThreshold"); } if (UseConcMarkSweepGC) { status = status && verify_min_value(CMSOldPLABNumRefills, 1, "CMSOldPLABNumRefills"); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 945e8ea667e..9973ee4d577 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3840,6 +3840,22 @@ class CommandLineFlags { experimental(uintx, SymbolTableSize, defaultSymbolTableSize, \ "Number of buckets in the JVM internal Symbol table") \ \ + product(bool, UseStringDeduplication, false, \ + "Use string deduplication") \ + \ + product(bool, PrintStringDeduplicationStatistics, false, \ + "Print string deduplication statistics") \ + \ + product(uintx, StringDeduplicationAgeThreshold, 3, \ + "A string must reach this age (or be promoted to an old region) " \ + "to be considered for deduplication") \ + \ + diagnostic(bool, StringDeduplicationResizeALot, false, \ + "Force table resize every time the table is scanned") \ + \ + diagnostic(bool, StringDeduplicationRehashALot, false, \ + "Force table rehash every time the table is scanned") \ + \ develop(bool, TraceDefaultMethods, false, \ "Trace the default method processing steps") \ \ diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 19f98cc2e4f..a798bd8d5b4 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -58,6 +58,8 @@ Mutex* SignatureHandlerLibrary_lock = NULL; Mutex* VtableStubs_lock = NULL; Mutex* SymbolTable_lock = NULL; Mutex* StringTable_lock = NULL; +Monitor* StringDedupQueue_lock = NULL; +Mutex* StringDedupTable_lock = NULL; Mutex* CodeCache_lock = NULL; Mutex* MethodData_lock = NULL; Mutex* RetData_lock = NULL; @@ -196,6 +198,9 @@ void mutex_init() { def(MMUTracker_lock , Mutex , leaf , true ); def(HotCardCache_lock , Mutex , special , true ); def(EvacFailureStack_lock , Mutex , nonleaf , true ); + + def(StringDedupQueue_lock , Monitor, leaf, true ); + def(StringDedupTable_lock , Mutex , leaf, true ); } def(ParGCRareEvent_lock , Mutex , leaf , true ); def(DerivedPointerTableGC_lock , Mutex, leaf, true ); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index d5084aeb476..9ee61bff653 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,6 +66,8 @@ extern Mutex* SignatureHandlerLibrary_lock; // a lock on the SignatureHandl extern Mutex* VtableStubs_lock; // a lock on the VtableStubs extern Mutex* SymbolTable_lock; // a lock on the symbol table extern Mutex* StringTable_lock; // a lock on the interned string table +extern Monitor* StringDedupQueue_lock; // a lock on the string deduplication queue +extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table extern Mutex* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx extern Mutex* MethodData_lock; // a lock on installation of method data extern Mutex* RetData_lock; // a lock on installation of RetData inside method data diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 4515066417d..06ce2ca6d2d 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -49,11 +49,13 @@ public class TestGCLogMessages { output.shouldNotContain("[Redirty Cards"); output.shouldNotContain("[Code Root Purge"); + output.shouldNotContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UseStringDeduplication", "-Xmx10M", "-XX:+PrintGCDetails", GCTest.class.getName()); @@ -62,11 +64,13 @@ public class TestGCLogMessages { output.shouldContain("[Redirty Cards"); output.shouldContain("[Code Root Purge"); + output.shouldContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:+UseStringDeduplication", "-Xmx10M", "-XX:+PrintGCDetails", "-XX:+UnlockExperimentalVMOptions", @@ -77,6 +81,7 @@ public class TestGCLogMessages { output.shouldContain("[Redirty Cards"); output.shouldContain("[Code Root Purge"); + output.shouldContain("[String Dedup Fixup"); output.shouldContain("[Young Free CSet"); output.shouldContain("[Non-Young Free CSet"); diff --git a/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java b/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java new file mode 100644 index 00000000000..8bdac8d07f6 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationAgeThreshold.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationAgeThreshold + * @summary Test string deduplication age threshold + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationAgeThreshold { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testAgeThreshold(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java b/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java new file mode 100644 index 00000000000..0e47db75c4c --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationFullGC.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationFullGC + * @summary Test string deduplication during full GC + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationFullGC { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testFullGC(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationInterned.java b/hotspot/test/gc/g1/TestStringDeduplicationInterned.java new file mode 100644 index 00000000000..680fa860ea8 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationInterned.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationInterned + * @summary Test string deduplication of interned strings + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationInterned { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testInterned(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java b/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java new file mode 100644 index 00000000000..ba3428986e2 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationMemoryUsage.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationMemoryUsage + * @summary Test string deduplication memory usage + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationMemoryUsage { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testMemoryUsage(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java b/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java new file mode 100644 index 00000000000..58279644490 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationPrintOptions.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationPrintOptions + * @summary Test string deduplication print options + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationPrintOptions { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testPrintOptions(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java b/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java new file mode 100644 index 00000000000..9b5d09215dd --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationTableRehash.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationTableRehash + * @summary Test string deduplication table rehash + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationTableRehash { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testTableRehash(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java b/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java new file mode 100644 index 00000000000..803c63bbb20 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationTableResize.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationTableResize + * @summary Test string deduplication table resize + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationTableResize { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testTableResize(); + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationTools.java b/hotspot/test/gc/g1/TestStringDeduplicationTools.java new file mode 100644 index 00000000000..1c1f480189a --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * Common code for string deduplication tests + */ + +import java.lang.management.*; +import java.lang.reflect.*; +import java.security.*; +import java.util.*; +import com.oracle.java.testlibrary.*; +import sun.misc.*; + +class TestStringDeduplicationTools { + private static final String YoungGC = "YoungGC"; + private static final String FullGC = "FullGC"; + + private static final int Xmn = 50; // MB + private static final int Xms = 100; // MB + private static final int Xmx = 100; // MB + private static final int MB = 1024 * 1024; + private static final int StringLength = 50; + + private static Field valueField; + private static Unsafe unsafe; + private static byte[] dummy; + + static { + try { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = (Unsafe)field.get(null); + + valueField = String.class.getDeclaredField("value"); + valueField.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Object getValue(String string) { + try { + return valueField.get(string); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void doFullGc(int numberOfTimes) { + for (int i = 0; i < numberOfTimes; i++) { + System.out.println("Begin: Full GC " + (i + 1) + "/" + numberOfTimes); + System.gc(); + System.out.println("End: Full GC " + (i + 1) + "/" + numberOfTimes); + } + } + + private static void doYoungGc(int numberOfTimes) { + // Provoke at least numberOfTimes young GCs + final int objectSize = 128; + final int maxObjectInYoung = (Xmn * MB) / objectSize; + for (int i = 0; i < numberOfTimes; i++) { + System.out.println("Begin: Young GC " + (i + 1) + "/" + numberOfTimes); + for (int j = 0; j < maxObjectInYoung + 1; j++) { + dummy = new byte[objectSize]; + } + System.out.println("End: Young GC " + (i + 1) + "/" + numberOfTimes); + } + } + + private static void forceDeduplication(int ageThreshold, String gcType) { + // Force deduplication to happen by either causing a FullGC or a YoungGC. + // We do several collections to also provoke a situation where the the + // deduplication thread needs to yield while processing the queue. This + // also tests that the references in the deduplication queue are adjusted + // accordingly. + if (gcType.equals(FullGC)) { + doFullGc(3); + } else { + doYoungGc(ageThreshold + 3); + } + } + + private static String generateString(int id) { + StringBuilder builder = new StringBuilder(StringLength); + + builder.append("DeduplicationTestString:" + id + ":"); + + while (builder.length() < StringLength) { + builder.append('X'); + } + + return builder.toString(); + } + + private static ArrayList createStrings(int total, int unique) { + System.out.println("Creating strings: total=" + total + ", unique=" + unique); + if (total % unique != 0) { + throw new RuntimeException("Total must be divisible by unique"); + } + + ArrayList list = new ArrayList(total); + for (int j = 0; j < total / unique; j++) { + for (int i = 0; i < unique; i++) { + list.add(generateString(i)); + } + } + + return list; + } + + private static void verifyStrings(ArrayList list, int uniqueExpected) { + for (;;) { + // Check number of deduplicated strings + ArrayList unique = new ArrayList(uniqueExpected); + for (String string: list) { + Object value = getValue(string); + boolean uniqueValue = true; + for (Object obj: unique) { + if (obj == value) { + uniqueValue = false; + break; + } + } + + if (uniqueValue) { + unique.add(value); + } + } + + System.out.println("Verifying strings: total=" + list.size() + + ", uniqueFound=" + unique.size() + + ", uniqueExpected=" + uniqueExpected); + + if (unique.size() == uniqueExpected) { + System.out.println("Deduplication completed"); + break; + } else { + System.out.println("Deduplication not completed, waiting..."); + + // Give the deduplication thread time to complete + try { + Thread.sleep(1000); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + + private static OutputAnalyzer runTest(String... extraArgs) throws Exception { + String[] defaultArgs = new String[] { + "-Xmn" + Xmn + "m", + "-Xms" + Xms + "m", + "-Xmx" + Xmx + "m", + "-XX:+UseG1GC", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyAfterGC" // Always verify after GC + }; + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(defaultArgs)); + args.addAll(Arrays.asList(extraArgs)); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + System.err.println(output.getStderr()); + System.out.println(output.getStdout()); + return output; + } + + private static class DeduplicationTest { + public static void main(String[] args) { + System.out.println("Begin: DeduplicationTest"); + + final int numberOfStrings = Integer.parseUnsignedInt(args[0]); + final int numberOfUniqueStrings = Integer.parseUnsignedInt(args[1]); + final int ageThreshold = Integer.parseUnsignedInt(args[2]); + final String gcType = args[3]; + + ArrayList list = createStrings(numberOfStrings, numberOfUniqueStrings); + forceDeduplication(ageThreshold, gcType); + verifyStrings(list, numberOfUniqueStrings); + + System.out.println("End: DeduplicationTest"); + } + + public static OutputAnalyzer run(int numberOfStrings, int ageThreshold, String gcType, String... extraArgs) throws Exception { + String[] defaultArgs = new String[] { + "-XX:+UseStringDeduplication", + "-XX:StringDeduplicationAgeThreshold=" + ageThreshold, + DeduplicationTest.class.getName(), + "" + numberOfStrings, + "" + numberOfStrings / 2, + "" + ageThreshold, + gcType + }; + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(extraArgs)); + args.addAll(Arrays.asList(defaultArgs)); + + return runTest(args.toArray(new String[args.size()])); + } + } + + private static class InternedTest { + public static void main(String[] args) { + // This test verifies that interned strings are always + // deduplicated when being interned, and never after + // being interned. + + System.out.println("Begin: InternedTest"); + + final int ageThreshold = Integer.parseUnsignedInt(args[0]); + final String baseString = "DeduplicationTestString:" + InternedTest.class.getName(); + + // Create duplicate of baseString + StringBuilder sb1 = new StringBuilder(baseString); + String dupString1 = sb1.toString(); + if (getValue(dupString1) == getValue(baseString)) { + throw new RuntimeException("Values should not match"); + } + + // Force baseString to be inspected for deduplication + // and be inserted into the deduplication hashtable. + forceDeduplication(ageThreshold, FullGC); + + // Wait for deduplication to occur + while (getValue(dupString1) != getValue(baseString)) { + System.out.println("Waiting..."); + try { + Thread.sleep(100); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // Create a new duplicate of baseString + StringBuilder sb2 = new StringBuilder(baseString); + String dupString2 = sb2.toString(); + if (getValue(dupString2) == getValue(baseString)) { + throw new RuntimeException("Values should not match"); + } + + // Intern the new duplicate + Object beforeInternedValue = getValue(dupString2); + String internedString = dupString2.intern(); + if (internedString != dupString2) { + throw new RuntimeException("String should match"); + } + if (getValue(internedString) != getValue(baseString)) { + throw new RuntimeException("Values should match"); + } + + // Check original value of interned string, to make sure + // deduplication happened on the interned string and not + // on the base string + if (beforeInternedValue == getValue(baseString)) { + throw new RuntimeException("Values should not match"); + } + + System.out.println("End: InternedTest"); + } + + public static OutputAnalyzer run() throws Exception { + return runTest("-XX:+PrintGC", + "-XX:+PrintGCDetails", + "-XX:+UseStringDeduplication", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold, + InternedTest.class.getName(), + "" + DefaultAgeThreshold); + } + } + + private static class MemoryUsageTest { + public static void main(String[] args) { + System.out.println("Begin: MemoryUsageTest"); + + final boolean useStringDeduplication = Boolean.parseBoolean(args[0]); + final int numberOfStrings = LargeNumberOfStrings; + final int numberOfUniqueStrings = 1; + + ArrayList list = createStrings(numberOfStrings, numberOfUniqueStrings); + forceDeduplication(DefaultAgeThreshold, FullGC); + + if (useStringDeduplication) { + verifyStrings(list, numberOfUniqueStrings); + } + + System.gc(); + System.out.println("Heap Memory Usage: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()); + + System.out.println("End: MemoryUsageTest"); + } + + public static OutputAnalyzer run(boolean useStringDeduplication) throws Exception { + String[] extraArgs = new String[0]; + + if (useStringDeduplication) { + extraArgs = new String[] { + "-XX:+UseStringDeduplication", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold + }; + } + + String[] defaultArgs = new String[] { + "-XX:+PrintGC", + "-XX:+PrintGCDetails", + MemoryUsageTest.class.getName(), + "" + useStringDeduplication + }; + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(extraArgs)); + args.addAll(Arrays.asList(defaultArgs)); + + return runTest(args.toArray(new String[args.size()])); + } + } + + /* + * Tests + */ + + private static final int LargeNumberOfStrings = 10000; + private static final int SmallNumberOfStrings = 10; + + private static final int MaxAgeThreshold = 15; + private static final int DefaultAgeThreshold = 3; + private static final int MinAgeThreshold = 1; + + private static final int TooLowAgeThreshold = MinAgeThreshold - 1; + private static final int TooHighAgeThreshold = MaxAgeThreshold + 1; + + public static void testYoungGC() throws Exception { + // Do young GC to age strings to provoke deduplication + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldNotContain("Full GC"); + output.shouldContain("GC pause (G1 Evacuation Pause) (young)"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + } + + public static void testFullGC() throws Exception { + // Do full GC to age strings to provoke deduplication + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + FullGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldNotContain("GC pause (G1 Evacuation Pause) (young)"); + output.shouldContain("Full GC"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + } + + public static void testTableResize() throws Exception { + // Test with StringDeduplicationResizeALot + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:+StringDeduplicationResizeALot"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldNotContain("Resize Count: 0"); + output.shouldHaveExitValue(0); + } + + public static void testTableRehash() throws Exception { + // Test with StringDeduplicationRehashALot + OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics", + "-XX:+StringDeduplicationRehashALot"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldNotContain("Rehash Count: 0"); + output.shouldNotContain("Hash Seed: 0x0"); + output.shouldHaveExitValue(0); + } + + public static void testAgeThreshold() throws Exception { + OutputAnalyzer output; + + // Test with max age theshold + output = DeduplicationTest.run(SmallNumberOfStrings, + MaxAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + + // Test with min age theshold + output = DeduplicationTest.run(SmallNumberOfStrings, + MinAgeThreshold, + YoungGC, + "-XX:+PrintGC", + "-XX:+PrintStringDeduplicationStatistics"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldContain("Deduplicated:"); + output.shouldHaveExitValue(0); + + // Test with too low age threshold + output = DeduplicationTest.run(SmallNumberOfStrings, + TooLowAgeThreshold, + YoungGC); + output.shouldContain("StringDeduplicationAgeThreshold of " + TooLowAgeThreshold + + " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold); + output.shouldHaveExitValue(1); + + // Test with too high age threshold + output = DeduplicationTest.run(SmallNumberOfStrings, + TooHighAgeThreshold, + YoungGC); + output.shouldContain("StringDeduplicationAgeThreshold of " + TooHighAgeThreshold + + " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold); + output.shouldHaveExitValue(1); + } + + public static void testPrintOptions() throws Exception { + OutputAnalyzer output; + + // Test without PrintGC and without PrintStringDeduplicationStatistics + output = DeduplicationTest.run(SmallNumberOfStrings, + DefaultAgeThreshold, + YoungGC); + output.shouldNotContain("GC concurrent-string-deduplication"); + output.shouldNotContain("Deduplicated:"); + output.shouldHaveExitValue(0); + + // Test with PrintGC but without PrintStringDeduplicationStatistics + output = DeduplicationTest.run(SmallNumberOfStrings, + DefaultAgeThreshold, + YoungGC, + "-XX:+PrintGC"); + output.shouldContain("GC concurrent-string-deduplication"); + output.shouldNotContain("Deduplicated:"); + output.shouldHaveExitValue(0); + } + + public static void testInterned() throws Exception { + // Test that interned strings are deduplicated before being interned + OutputAnalyzer output = InternedTest.run(); + output.shouldHaveExitValue(0); + } + + public static void testMemoryUsage() throws Exception { + // Test that memory usage is reduced after deduplication + OutputAnalyzer output; + final String usagePattern = "Heap Memory Usage: (\\d+)"; + + // Run without deduplication + output = MemoryUsageTest.run(false); + output.shouldHaveExitValue(0); + final long memoryUsageWithoutDedup = Long.parseLong(output.firstMatch(usagePattern, 1)); + + // Run with deduplication + output = MemoryUsageTest.run(true); + output.shouldHaveExitValue(0); + final long memoryUsageWithDedup = Long.parseLong(output.firstMatch(usagePattern, 1)); + + // Calculate expected memory usage with deduplication enabled. This calculation does + // not take alignment and padding into account, so it's a conservative estimate. + final long sizeOfChar = 2; // bytes + final long bytesSaved = (LargeNumberOfStrings - 1) * (StringLength * sizeOfChar + unsafe.ARRAY_CHAR_BASE_OFFSET); + final long memoryUsageWithDedupExpected = memoryUsageWithoutDedup - bytesSaved; + + System.out.println("Memory usage summary:"); + System.out.println(" memoryUsageWithoutDedup: " + memoryUsageWithoutDedup); + System.out.println(" memoryUsageWithDedup: " + memoryUsageWithDedup); + System.out.println(" memoryUsageWithDedupExpected: " + memoryUsageWithDedupExpected); + + if (memoryUsageWithDedup > memoryUsageWithDedupExpected) { + throw new Exception("Unexpected memory usage, memoryUsageWithDedup should less or equal to memoryUsageWithDedupExpected"); + } + } +} diff --git a/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java b/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java new file mode 100644 index 00000000000..c856d019205 --- /dev/null +++ b/hotspot/test/gc/g1/TestStringDeduplicationYoungGC.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 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 TestStringDeduplicationYoungGC + * @summary Test string deduplication during young GC + * @bug 8029075 + * @key gc + * @library /testlibrary + */ + +public class TestStringDeduplicationYoungGC { + public static void main(String[] args) throws Exception { + TestStringDeduplicationTools.testYoungGC(); + } +} From 06461f9c1baeb7c17084525cc8af1f64f89be381 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Tue, 18 Mar 2014 14:07:38 -0700 Subject: [PATCH 051/170] 8033926: Update hotspot/make/jprt.properties to use jdk 9 instead of jdk 8 Reviewed-by: sla, dholmes --- hotspot/make/jprt.properties | 66 +++++++++++------------------------- 1 file changed, 19 insertions(+), 47 deletions(-) diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 9109ded6f98..25b13107dcb 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -33,7 +33,7 @@ jprt.need.sibling.build=false # This tells jprt what default release we want to build -jprt.hotspot.default.release=jdk8 +jprt.hotspot.default.release=jdk9 jprt.tools.default.release=${jprt.submit.option.release?${jprt.submit.option.release}:${jprt.hotspot.default.release}} @@ -47,72 +47,50 @@ jprt.sync.push=false # sparc etc. # Define the Solaris platforms we want for the various releases -jprt.my.solaris.sparcv9.jdk8=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7u8=${jprt.my.solaris.sparcv9.jdk7} +jprt.my.solaris.sparcv9.jdk9=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} -jprt.my.solaris.x64.jdk8=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7u8=${jprt.my.solaris.x64.jdk7} +jprt.my.solaris.x64.jdk9=solaris_x64_5.10 jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} -jprt.my.linux.i586.jdk8=linux_i586_2.6 -jprt.my.linux.i586.jdk7=linux_i586_2.6 -jprt.my.linux.i586.jdk7u8=${jprt.my.linux.i586.jdk7} +jprt.my.linux.i586.jdk9=linux_i586_2.6 jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} -jprt.my.linux.x64.jdk8=linux_x64_2.6 -jprt.my.linux.x64.jdk7=linux_x64_2.6 -jprt.my.linux.x64.jdk7u8=${jprt.my.linux.x64.jdk7} +jprt.my.linux.x64.jdk9=linux_x64_2.6 jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} -jprt.my.linux.ppc.jdk8=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7u8=${jprt.my.linux.ppc.jdk7} +jprt.my.linux.ppc.jdk9=linux_ppc_2.6 jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}} -jprt.my.linux.ppcv2.jdk8=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7u8=${jprt.my.linux.ppcv2.jdk7} +jprt.my.linux.ppcv2.jdk9=linux_ppcv2_2.6 jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}} -jprt.my.linux.ppcsflt.jdk8=linux_ppcsflt_2.6 -jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6 -jprt.my.linux.ppcsflt.jdk7u8=${jprt.my.linux.ppcsflt.jdk7} +jprt.my.linux.ppcsflt.jdk9=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}} -jprt.my.linux.armvfpsflt.jdk8=linux_armvfpsflt_2.6 +jprt.my.linux.armvfpsflt.jdk9=linux_armvfpsflt_2.6 jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}} -jprt.my.linux.armvfphflt.jdk8=linux_armvfphflt_2.6 +jprt.my.linux.armvfphflt.jdk9=linux_armvfphflt_2.6 jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}} # The ARM GP vfp-sflt build is not currently supported -#jprt.my.linux.armvs.jdk8=linux_armvs_2.6 +#jprt.my.linux.armvs.jdk9=linux_armvs_2.6 #jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}} -jprt.my.linux.armvh.jdk8=linux_armvh_2.6 +jprt.my.linux.armvh.jdk9=linux_armvh_2.6 jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}} -jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7u8=${jprt.my.linux.armsflt.jdk7} +jprt.my.linux.armsflt.jdk9=linux_armsflt_2.6 jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}} -jprt.my.macosx.x64.jdk8=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7u8=${jprt.my.macosx.x64.jdk7} +jprt.my.macosx.x64.jdk9=macosx_x64_10.7 jprt.my.macosx.x64=${jprt.my.macosx.x64.${jprt.tools.default.release}} -jprt.my.windows.i586.jdk8=windows_i586_6.1 -jprt.my.windows.i586.jdk7=windows_i586_6.1 -jprt.my.windows.i586.jdk7u8=${jprt.my.windows.i586.jdk7} +jprt.my.windows.i586.jdk9=windows_i586_6.1 jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} -jprt.my.windows.x64.jdk8=windows_x64_6.1 -jprt.my.windows.x64.jdk7=windows_x64_6.1 -jprt.my.windows.x64.jdk7u8=${jprt.my.windows.x64.jdk7} +jprt.my.windows.x64.jdk9=windows_x64_6.1 jprt.my.windows.x64=${jprt.my.windows.x64.${jprt.tools.default.release}} # Standard list of jprt build targets for this source tree @@ -143,9 +121,7 @@ jprt.build.targets.embedded= \ jprt.build.targets.all=${jprt.build.targets.standard}, \ ${jprt.build.targets.embedded}, ${jprt.build.targets.open} -jprt.build.targets.jdk8=${jprt.build.targets.all} -jprt.build.targets.jdk7=${jprt.build.targets.all} -jprt.build.targets.jdk7u8=${jprt.build.targets.all} +jprt.build.targets.jdk9=${jprt.build.targets.all} jprt.build.targets=${jprt.build.targets.${jprt.tools.default.release}} # Subset lists of test targets for this source tree @@ -349,9 +325,7 @@ jprt.test.targets.embedded= \ ${jprt.my.windows.i586.test.targets}, \ ${jprt.my.windows.x64.test.targets} -jprt.test.targets.jdk8=${jprt.test.targets.standard} -jprt.test.targets.jdk7=${jprt.test.targets.standard} -jprt.test.targets.jdk7u8=${jprt.test.targets.jdk7} +jprt.test.targets.jdk9=${jprt.test.targets.standard} jprt.test.targets=${jprt.test.targets.${jprt.tools.default.release}} # The default test/Makefile targets that should be run @@ -399,9 +373,7 @@ jprt.make.rule.test.targets.standard = \ jprt.make.rule.test.targets.embedded = \ ${jprt.make.rule.test.targets.standard.client} -jprt.make.rule.test.targets.jdk8=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7u8=${jprt.make.rule.test.targets.jdk7} +jprt.make.rule.test.targets.jdk9=${jprt.make.rule.test.targets.standard} jprt.make.rule.test.targets=${jprt.make.rule.test.targets.${jprt.tools.default.release}} # 7155453: Work-around to prevent popups on OSX from blocking test completion From 71ded92863c3bdab5ee7949d0732ff51c00455c9 Mon Sep 17 00:00:00 2001 From: Matherey Nunez Date: Wed, 19 Mar 2014 16:01:19 +0100 Subject: [PATCH 052/170] 8037779: NoPersistenceCachingTest fails with ant test Reviewed-by: sundar, hannesw --- .../runtime/NoPersistenceCachingTest.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java index aefa828b470..7b84f5a7af3 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/NoPersistenceCachingTest.java @@ -37,6 +37,8 @@ import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.SimpleScriptContext; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; /** * @test @@ -50,8 +52,8 @@ public class NoPersistenceCachingTest { private ScriptContext context1, context2, context3; private ByteArrayOutputStream stderr; private PrintStream prevStderr; - private final String script = "print('Hello')"; + @BeforeTest public void setupTest() { stderr = new ByteArrayOutputStream(); prevStderr = System.err; @@ -69,33 +71,33 @@ public class NoPersistenceCachingTest { } String[] options = new String[]{"--log=compiler:finest"}; engine = nashornFactory.getScriptEngine(options); + context1 = engine.getContext(); + context2 = new SimpleScriptContext(); + context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); + context3 = new SimpleScriptContext(); + context3.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); } + @AfterTest public void setErrTest() { System.setErr(prevStderr); } public void runTest(int numberOfContext, String expectedOutputPattern, int expectedPatternOccurrence) { - setupTest(); + try { switch (numberOfContext) { case 2: - context1 = engine.getContext(); - context2 = new SimpleScriptContext(); - context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - engine.eval(script, context1); - engine.eval(script, context2); + String scriptTwoContexts = "print('HelloTwoContexts')"; + engine.eval(scriptTwoContexts, context1); + engine.eval(scriptTwoContexts, context2); break; case 3: - context1 = engine.getContext(); - context2 = new SimpleScriptContext(); - context2.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - context3 = new SimpleScriptContext(); - context3.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); - engine.eval(script, context1); - engine.eval(script, context2); - engine.eval(script, context3); + String scriptThreeContexts = "print('HelloThreeContexts')"; + engine.eval(scriptThreeContexts, context1); + engine.eval(scriptThreeContexts, context2); + engine.eval(scriptThreeContexts, context3); break; } } catch (final Exception se) { @@ -113,7 +115,7 @@ public class NoPersistenceCachingTest { + expectedPatternOccurrence + " and found: " + matches + "\n" + stderr); } - setErrTest(); + stderr.reset(); } private static String getCodeCachePattern() { From e0bc15202b69b4997ef477c9451a66a071260fee Mon Sep 17 00:00:00 2001 From: Paul Govereau Date: Wed, 19 Mar 2014 11:34:27 -0400 Subject: [PATCH 053/170] 6898851: Compiling against this corrupt class file causes a stacktrace from javac Added check for index out-of-bounds erros in ClassReader Reviewed-by: jjg --- .../com/sun/tools/javac/jvm/ClassReader.java | 2 + .../tools/javac/resources/compiler.properties | 4 + .../tools/javac/classreader/BadClass.java | 76 +++++++++++++++++++ .../tools/javac/diags/examples.not-yet.txt | 1 + 4 files changed, 83 insertions(+) create mode 100644 langtools/test/tools/javac/classreader/BadClass.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java index ba6fc9e4cf1..c1fdd998dec 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2501,6 +2501,8 @@ public class ClassReader { return; } catch (IOException ex) { throw badClassFile("unable.to.access.file", ex.getMessage()); + } catch (ArrayIndexOutOfBoundsException ex) { + throw badClassFile("bad.class.file", c.flatname); } finally { currentClassFile = previousClassFile; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 8ed68e04151..43b3c638527 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1709,6 +1709,10 @@ compiler.err.cant.access=\ cannot access {0}\n\ {1} +# 0: class name +compiler.misc.bad.class.file=\ + class file is invalid for class {0} + # 0: file name, 1: message segment compiler.misc.bad.class.file.header=\ bad class file: {0}\n\ diff --git a/langtools/test/tools/javac/classreader/BadClass.java b/langtools/test/tools/javac/classreader/BadClass.java new file mode 100644 index 00000000000..929b4d689ba --- /dev/null +++ b/langtools/test/tools/javac/classreader/BadClass.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 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 6898851 + * @summary Compiling against this corrupt class file causes a stacktrace from javac + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.StringWriter; +import java.io.PrintWriter; +import java.io.IOException; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ClassWriter; +import com.sun.tools.javac.Main; + +public class BadClass { + // Create and compile file containing body; return compiler output + static String makeClass(String dir, String filename, String body) throws IOException { + File file = new File(dir, filename); + try (FileWriter fw = new FileWriter(file)) { + fw.write(body); + } + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + String args[] = { "-cp", dir, "-d", dir, "-XDrawDiagnostics", file.getPath() }; + Main.compile(args, pw); + pw.close(); + return sw.toString(); + } + + public static void main(String... args) throws Exception { + new File("d1").mkdir(); + new File("d2").mkdir(); + + // Step 1. build an empty class with an interface + makeClass("d1", "Empty.java", "abstract class Empty implements Readable {}"); + + // Step 2. Modify classfile to have invalid constant pool index + ClassFile cf = ClassFile.read(new File("d1","Empty.class")); + cf.interfaces[0] = cf.constant_pool.size() + 10; + ClassWriter cw = new ClassWriter(); + cw.write(cf, new File("d2","Empty.class")); + + // Step 3. Compile use of invalid class + String result = makeClass("d2", "EmptyUse.java", "class EmptyUse { Empty e; }"); + if (!result.contains("compiler.misc.bad.class.file")) { + System.out.println(result); + throw new Exception("test failed"); + } + } +} diff --git a/langtools/test/tools/javac/diags/examples.not-yet.txt b/langtools/test/tools/javac/diags/examples.not-yet.txt index 9f227708f46..0db17ba5d23 100644 --- a/langtools/test/tools/javac/diags/examples.not-yet.txt +++ b/langtools/test/tools/javac/diags/examples.not-yet.txt @@ -111,3 +111,4 @@ compiler.warn.unknown.enum.constant # in bad class file compiler.warn.unknown.enum.constant.reason # in bad class file compiler.warn.override.equals.but.not.hashcode # when a class overrides equals but not hashCode method from Object compiler.warn.file.from.future # warning for future modification times on files +compiler.misc.bad.class.file # class file is malformed From 315e4838e91e1f19d92292e61f4e3f3b0da2d887 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Wed, 19 Mar 2014 11:37:58 -0700 Subject: [PATCH 054/170] 8031203: remove SafepointPollOffset Reviewed-by: kvn, roland --- hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp | 2 -- hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp | 6 ++---- hotspot/src/cpu/x86/vm/c1_globals_x86.hpp | 2 -- hotspot/src/share/vm/c1/c1_globals.hpp | 3 --- hotspot/src/share/vm/runtime/arguments.cpp | 1 + 5 files changed, 3 insertions(+), 11 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp index 57f871247b0..111f22730d3 100644 --- a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp @@ -66,6 +66,4 @@ define_pd_global(bool, OptimizeSinglePrecision, false); define_pd_global(bool, CSEArrayLength, true ); define_pd_global(bool, TwoOperandLIRForm, false); -define_pd_global(intx, SafepointPollOffset, 0 ); - #endif // CPU_SPARC_VM_C1_GLOBALS_SPARC_HPP diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index bf9c9347380..39c130fdf06 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -604,8 +604,7 @@ void LIR_Assembler::return_op(LIR_Opr result) { // Note: we do not need to round double result; float result has the right precision // the poll sets the condition code, but no data registers - AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), - relocInfo::poll_return_type); + AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_return_type); if (Assembler::is_polling_page_far()) { __ lea(rscratch1, polling_page); @@ -619,8 +618,7 @@ void LIR_Assembler::return_op(LIR_Opr result) { int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { - AddressLiteral polling_page(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()), - relocInfo::poll_type); + AddressLiteral polling_page(os::get_polling_page(), relocInfo::poll_type); guarantee(info != NULL, "Shouldn't be NULL"); int offset = __ offset(); if (Assembler::is_polling_page_far()) { diff --git a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp index 2e99c41949f..742a5d8601d 100644 --- a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp @@ -65,6 +65,4 @@ define_pd_global(bool, OptimizeSinglePrecision, true ); define_pd_global(bool, CSEArrayLength, false); define_pd_global(bool, TwoOperandLIRForm, true ); -define_pd_global(intx, SafepointPollOffset, 256 ); - #endif // CPU_X86_VM_C1_GLOBALS_X86_HPP diff --git a/hotspot/src/share/vm/c1/c1_globals.hpp b/hotspot/src/share/vm/c1/c1_globals.hpp index 272d2bd2620..048a94a59d6 100644 --- a/hotspot/src/share/vm/c1/c1_globals.hpp +++ b/hotspot/src/share/vm/c1/c1_globals.hpp @@ -308,9 +308,6 @@ develop(intx, InstructionCountCutoff, 37000, \ "If GraphBuilder adds this many instructions, bails out") \ \ - product_pd(intx, SafepointPollOffset, \ - "Offset added to polling address (Intel only)") \ - \ develop(bool, ComputeExactFPURegisterUsage, true, \ "Compute additional live set for fpu registers to simplify fpu stack merge (Intel only)") \ \ diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 3099df2e8ef..d568a33334d 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -301,6 +301,7 @@ static ObsoleteFlag obsolete_jvm_flags[] = { { "UseMPSS", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseStringCache", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseOldInlining", JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "SafepointPollOffset", JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, From 019025c61f615d9ff7dbf8d011be831dcd8fe8b2 Mon Sep 17 00:00:00 2001 From: Paul Govereau Date: Wed, 19 Mar 2014 17:39:28 -0400 Subject: [PATCH 055/170] 8025505: Constant folding deficiency Provide constant folding of equality tests involving constant and null. Reviewed-by: jjg --- .../com/sun/tools/javac/comp/Lower.java | 66 ++++++++++++-- langtools/test/tools/javac/ConstFoldTest.java | 86 +++++++++++++++++++ 2 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 langtools/test/tools/javac/ConstFoldTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index d7046596483..31f5095e93b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -2919,15 +2919,65 @@ public class Lower extends TreeTranslator { // constant propagation would require that we take care to // preserve possible side-effects in the condition expression. + // One common case is equality expressions involving a constant and null. + // Since null is not a constant expression (because null cannot be + // represented in the constant pool), equality checks involving null are + // not captured by Flow.isTrue/isFalse. + // Equality checks involving a constant and null, e.g. + // "" == null + // are safe to simplify as no side-effects can occur. + + private boolean isTrue(JCTree exp) { + if (exp.type.isTrue()) + return true; + Boolean b = expValue(exp); + return b == null ? false : b; + } + private boolean isFalse(JCTree exp) { + if (exp.type.isFalse()) + return true; + Boolean b = expValue(exp); + return b == null ? false : !b; + } + /* look for (in)equality relations involving null. + * return true - if expression is always true + * false - if expression is always false + * null - if expression cannot be eliminated + */ + private Boolean expValue(JCTree exp) { + while (exp.hasTag(PARENS)) + exp = ((JCParens)exp).expr; + + boolean eq; + switch (exp.getTag()) { + case EQ: eq = true; break; + case NE: eq = false; break; + default: + return null; + } + + // we have a JCBinary(EQ|NE) + // check if we have two literals (constants or null) + JCBinary b = (JCBinary)exp; + if (b.lhs.type.hasTag(BOT)) return expValueIsNull(eq, b.rhs); + if (b.rhs.type.hasTag(BOT)) return expValueIsNull(eq, b.lhs); + return null; + } + private Boolean expValueIsNull(boolean eq, JCTree t) { + if (t.type.hasTag(BOT)) return Boolean.valueOf(eq); + if (t.hasTag(LITERAL)) return Boolean.valueOf(!eq); + return null; + } + /** Visitor method for conditional expressions. */ @Override public void visitConditional(JCConditional tree) { JCTree cond = tree.cond = translate(tree.cond, syms.booleanType); - if (cond.type.isTrue()) { + if (isTrue(cond)) { result = convert(translate(tree.truepart, tree.type), tree.type); addPrunedInfo(cond); - } else if (cond.type.isFalse()) { + } else if (isFalse(cond)) { result = convert(translate(tree.falsepart, tree.type), tree.type); addPrunedInfo(cond); } else { @@ -2951,10 +3001,10 @@ public class Lower extends TreeTranslator { */ public void visitIf(JCIf tree) { JCTree cond = tree.cond = translate(tree.cond, syms.booleanType); - if (cond.type.isTrue()) { + if (isTrue(cond)) { result = translate(tree.thenpart); addPrunedInfo(cond); - } else if (cond.type.isFalse()) { + } else if (isFalse(cond)) { if (tree.elsepart != null) { result = translate(tree.elsepart); } else { @@ -3333,21 +3383,21 @@ public class Lower extends TreeTranslator { JCTree lhs = tree.lhs = translate(tree.lhs, formals.head); switch (tree.getTag()) { case OR: - if (lhs.type.isTrue()) { + if (isTrue(lhs)) { result = lhs; return; } - if (lhs.type.isFalse()) { + if (isFalse(lhs)) { result = translate(tree.rhs, formals.tail.head); return; } break; case AND: - if (lhs.type.isFalse()) { + if (isFalse(lhs)) { result = lhs; return; } - if (lhs.type.isTrue()) { + if (isTrue(lhs)) { result = translate(tree.rhs, formals.tail.head); return; } diff --git a/langtools/test/tools/javac/ConstFoldTest.java b/langtools/test/tools/javac/ConstFoldTest.java new file mode 100644 index 00000000000..c9865f3a476 --- /dev/null +++ b/langtools/test/tools/javac/ConstFoldTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, 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 8025505 + * @summary Constant folding deficiency + * @library /tools/javac/lib + * @build ToolBox + * @run main ConstFoldTest + */ + +import java.net.URL; +import java.util.List; + +public class ConstFoldTest { + public static void main(String... args) throws Exception { + new ConstFoldTest().run(); + } + + // This is the test case. This class should end up + // as straight-line code with no conditionals + class CFTest { + void m() { + int x; + if (1 != 2) x=1; else x=0; + if (1 == 2) x=1; else x=0; + if ("" != null) x=1; else x=0; + if ("" == null) x=1; else x=0; + if (null == null) x=1; else x=0; + if (null != null) x=1; else x=0; + + x = 1 != 2 ? 1 : 0; + x = 1 == 2 ? 1 : 0; + x = "" != null ? 1 : 0; + x = "" == null ? 1 : 0; + x = null == null ? 1 : 0; + x = null != null ? 1 : 0; + + boolean b; + b = 1 != 2 && true; + b = 1 == 2 || true; + b = ("" != null) && true; + b = ("" == null) || true; + b = (null == null) && true; + b = (null != null) || true; + } + } + + // All of the conditionals above should be eliminated. + // these if* bytecodes should not be seen + final String regex = "\\sif(?:null|nonnull|eq|ne){1}\\s"; + + void run() throws Exception { + URL url = ConstFoldTest.class.getResource("ConstFoldTest$CFTest.class"); + String result = ToolBox.javap(new ToolBox.JavaToolArgs().setAllArgs("-c", url.getFile())); + System.out.println(result); + + List bad_codes = ToolBox.grep(regex, result, "\n"); + if (!bad_codes.isEmpty()) { + for (String code : bad_codes) + System.out.println("Bad OpCode Found: " + code); + throw new Exception("constant folding failed"); + } + } +} From 97a51c5c2a63a94d7f0551c32767a8000f9dd636 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 20 Mar 2014 17:49:27 -0700 Subject: [PATCH 056/170] 8031320: Use Intel RTM instructions for locks Use RTM for inflated locks and stack locks. Reviewed-by: iveresov, twisti, roland, dcubed --- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 39 ++ hotspot/src/cpu/x86/vm/assembler_x86.hpp | 10 + hotspot/src/cpu/x86/vm/globals_x86.hpp | 36 ++ hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 490 ++++++++++++++++-- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 57 +- hotspot/src/cpu/x86/vm/rtmLocking.cpp | 59 +++ .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 21 + .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 19 + hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 77 ++- hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 13 +- hotspot/src/cpu/x86/vm/x86_32.ad | 22 +- hotspot/src/cpu/x86/vm/x86_64.ad | 22 +- hotspot/src/share/vm/adlc/output_c.cpp | 4 + hotspot/src/share/vm/ci/ciEnv.cpp | 16 +- hotspot/src/share/vm/ci/ciEnv.hpp | 3 +- hotspot/src/share/vm/ci/ciMethodData.hpp | 12 + hotspot/src/share/vm/code/nmethod.cpp | 4 +- hotspot/src/share/vm/code/nmethod.hpp | 12 + hotspot/src/share/vm/oops/method.cpp | 2 +- hotspot/src/share/vm/oops/methodData.cpp | 16 + hotspot/src/share/vm/oops/methodData.hpp | 24 +- hotspot/src/share/vm/opto/c2_globals.hpp | 3 + hotspot/src/share/vm/opto/classes.hpp | 1 + hotspot/src/share/vm/opto/compile.cpp | 25 +- hotspot/src/share/vm/opto/compile.hpp | 6 +- hotspot/src/share/vm/opto/connode.hpp | 13 + hotspot/src/share/vm/opto/graphKit.cpp | 6 +- hotspot/src/share/vm/opto/locknode.cpp | 18 + hotspot/src/share/vm/opto/locknode.hpp | 12 +- hotspot/src/share/vm/opto/loopTransform.cpp | 18 + hotspot/src/share/vm/opto/machnode.hpp | 6 +- hotspot/src/share/vm/opto/macro.cpp | 29 +- hotspot/src/share/vm/opto/macro.hpp | 4 +- hotspot/src/share/vm/opto/parse.hpp | 2 + hotspot/src/share/vm/opto/parse1.cpp | 40 ++ hotspot/src/share/vm/opto/runtime.cpp | 11 + hotspot/src/share/vm/opto/runtime.hpp | 18 +- hotspot/src/share/vm/opto/type.cpp | 2 +- hotspot/src/share/vm/runtime/arguments.cpp | 8 +- .../src/share/vm/runtime/deoptimization.cpp | 17 +- .../src/share/vm/runtime/deoptimization.hpp | 1 + hotspot/src/share/vm/runtime/java.cpp | 4 +- hotspot/src/share/vm/runtime/rtmLocking.hpp | 113 ++++ hotspot/src/share/vm/runtime/task.cpp | 1 - hotspot/src/share/vm/runtime/thread.cpp | 7 + .../share/vm/utilities/globalDefinitions.hpp | 15 + 46 files changed, 1251 insertions(+), 87 deletions(-) create mode 100644 hotspot/src/cpu/x86/vm/rtmLocking.cpp create mode 100644 hotspot/src/share/vm/runtime/rtmLocking.hpp diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index d305ac18537..4de27ac6770 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -2343,6 +2343,11 @@ void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector25 emit_int8(imm8); } +void Assembler::pause() { + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)0x90); +} + void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); InstructionMark im(this); @@ -2667,6 +2672,11 @@ void Assembler::rcll(Register dst, int imm8) { } } +void Assembler::rdtsc() { + emit_int8((unsigned char)0x0F); + emit_int8((unsigned char)0x31); +} + // copies data from [esi] to [edi] using rcx pointer sized words // generic void Assembler::rep_mov() { @@ -2976,6 +2986,11 @@ void Assembler::ucomiss(XMMRegister dst, XMMRegister src) { emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_NONE); } +void Assembler::xabort(int8_t imm8) { + emit_int8((unsigned char)0xC6); + emit_int8((unsigned char)0xF8); + emit_int8((unsigned char)(imm8 & 0xFF)); +} void Assembler::xaddl(Address dst, Register src) { InstructionMark im(this); @@ -2985,6 +3000,24 @@ void Assembler::xaddl(Address dst, Register src) { emit_operand(src, dst); } +void Assembler::xbegin(Label& abort, relocInfo::relocType rtype) { + InstructionMark im(this); + relocate(rtype); + if (abort.is_bound()) { + address entry = target(abort); + assert(entry != NULL, "abort entry NULL"); + intptr_t offset = entry - pc(); + emit_int8((unsigned char)0xC7); + emit_int8((unsigned char)0xF8); + emit_int32(offset - 6); // 2 opcode + 4 address + } else { + abort.add_patch_at(code(), locator()); + emit_int8((unsigned char)0xC7); + emit_int8((unsigned char)0xF8); + emit_int32(0); + } +} + void Assembler::xchgl(Register dst, Address src) { // xchg InstructionMark im(this); prefix(src, dst); @@ -2998,6 +3031,12 @@ void Assembler::xchgl(Register dst, Register src) { emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::xend() { + emit_int8((unsigned char)0x0F); + emit_int8((unsigned char)0x01); + emit_int8((unsigned char)0xD5); +} + void Assembler::xgetbv() { emit_int8(0x0F); emit_int8(0x01); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 95ca231cef4..12bc14e7195 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1451,6 +1451,8 @@ private: // Pemutation of 64bit words void vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256); + void pause(); + // SSE4.2 string instructions void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); void pcmpestri(XMMRegister xmm1, Address src, int imm8); @@ -1535,6 +1537,8 @@ private: void rclq(Register dst, int imm8); + void rdtsc(); + void ret(int imm16); void sahf(); @@ -1632,16 +1636,22 @@ private: void ucomiss(XMMRegister dst, Address src); void ucomiss(XMMRegister dst, XMMRegister src); + void xabort(int8_t imm8); + void xaddl(Address dst, Register src); void xaddq(Address dst, Register src); + void xbegin(Label& abort, relocInfo::relocType rtype = relocInfo::none); + void xchgl(Register reg, Address adr); void xchgl(Register dst, Register src); void xchgq(Register reg, Address adr); void xchgq(Register dst, Register src); + void xend(); + // Get Value of Extended Control Register void xgetbv(); diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index f29e5d6e322..fe5db1ce7fe 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -129,6 +129,42 @@ define_pd_global(uintx, TypeProfileLevel, 111); product(bool, UseFastStosb, false, \ "Use fast-string operation for zeroing: rep stosb") \ \ + /* Use Restricted Transactional Memory for lock eliding */ \ + product(bool, UseRTMLocking, false, \ + "Enable RTM lock eliding for inflated locks in compiled code") \ + \ + experimental(bool, UseRTMForStackLocks, false, \ + "Enable RTM lock eliding for stack locks in compiled code") \ + \ + product(bool, UseRTMDeopt, false, \ + "Perform deopt and recompilation based on RTM abort ratio") \ + \ + product(uintx, RTMRetryCount, 5, \ + "Number of RTM retries on lock abort or busy") \ + \ + experimental(intx, RTMSpinLoopCount, 100, \ + "Spin count for lock to become free before RTM retry") \ + \ + experimental(intx, RTMAbortThreshold, 1000, \ + "Calculate abort ratio after this number of aborts") \ + \ + experimental(intx, RTMLockingThreshold, 10000, \ + "Lock count at which to do RTM lock eliding without " \ + "abort ratio calculation") \ + \ + experimental(intx, RTMAbortRatio, 50, \ + "Lock abort ratio at which to stop use RTM lock eliding") \ + \ + experimental(intx, RTMTotalCountIncrRate, 64, \ + "Increment total RTM attempted lock count once every n times") \ + \ + experimental(intx, RTMLockingCalculationDelay, 0, \ + "Number of milliseconds to wait before start calculating aborts " \ + "for RTM locking") \ + \ + experimental(bool, UseRTMXendForLockBusy, false, \ + "Use RTM Xend instead of Xabort when lock busy") \ + \ /* assembler */ \ product(bool, Use486InstrsOnly, false, \ "Use 80486 Compliant instruction subset") \ diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 74fa1b298ac..3426d6d55cf 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -301,7 +301,9 @@ void MacroAssembler::mov_metadata(Address dst, Metadata* obj) { mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate()); } -void MacroAssembler::movptr(Register dst, AddressLiteral src) { +void MacroAssembler::movptr(Register dst, AddressLiteral src, Register scratch) { + // scratch register is not used, + // it is defined to match parameters of 64-bit version of this method. if (src.is_lval()) { mov_literal32(dst, (intptr_t)src.target(), src.rspec()); } else { @@ -613,6 +615,15 @@ void MacroAssembler::decrementq(Address dst, int value) { /* else */ { subq(dst, value) ; return; } } +void MacroAssembler::incrementq(AddressLiteral dst) { + if (reachable(dst)) { + incrementq(as_Address(dst)); + } else { + lea(rscratch1, dst); + incrementq(Address(rscratch1, 0)); + } +} + void MacroAssembler::incrementq(Register reg, int value) { if (value == min_jint) { addq(reg, value); return; } if (value < 0) { decrementq(reg, -value); return; } @@ -681,15 +692,15 @@ void MacroAssembler::mov_metadata(Address dst, Metadata* obj) { movq(dst, rscratch1); } -void MacroAssembler::movptr(Register dst, AddressLiteral src) { +void MacroAssembler::movptr(Register dst, AddressLiteral src, Register scratch) { if (src.is_lval()) { mov_literal64(dst, (intptr_t)src.target(), src.rspec()); } else { if (reachable(src)) { movq(dst, as_Address(src)); } else { - lea(rscratch1, src); - movq(dst, Address(rscratch1,0)); + lea(scratch, src); + movq(dst, Address(scratch, 0)); } } } @@ -988,21 +999,38 @@ void MacroAssembler::andptr(Register dst, int32_t imm32) { LP64_ONLY(andq(dst, imm32)) NOT_LP64(andl(dst, imm32)); } -void MacroAssembler::atomic_incl(AddressLiteral counter_addr) { - pushf(); - if (reachable(counter_addr)) { - if (os::is_MP()) - lock(); - incrementl(as_Address(counter_addr)); - } else { - lea(rscratch1, counter_addr); - if (os::is_MP()) - lock(); - incrementl(Address(rscratch1, 0)); - } - popf(); +void MacroAssembler::atomic_incl(Address counter_addr) { + if (os::is_MP()) + lock(); + incrementl(counter_addr); } +void MacroAssembler::atomic_incl(AddressLiteral counter_addr, Register scr) { + if (reachable(counter_addr)) { + atomic_incl(as_Address(counter_addr)); + } else { + lea(scr, counter_addr); + atomic_incl(Address(scr, 0)); + } +} + +#ifdef _LP64 +void MacroAssembler::atomic_incq(Address counter_addr) { + if (os::is_MP()) + lock(); + incrementq(counter_addr); +} + +void MacroAssembler::atomic_incq(AddressLiteral counter_addr, Register scr) { + if (reachable(counter_addr)) { + atomic_incq(as_Address(counter_addr)); + } else { + lea(scr, counter_addr); + atomic_incq(Address(scr, 0)); + } +} +#endif + // Writes to stack successive pages until offset reached to check for // stack overflow + shadow pages. This clobbers tmp. void MacroAssembler::bang_stack_size(Register size, Register tmp) { @@ -1274,6 +1302,325 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, La } #ifdef COMPILER2 + +#if INCLUDE_RTM_OPT + +// Update rtm_counters based on abort status +// input: abort_status +// rtm_counters (RTMLockingCounters*) +// flags are killed +void MacroAssembler::rtm_counters_update(Register abort_status, Register rtm_counters) { + + atomic_incptr(Address(rtm_counters, RTMLockingCounters::abort_count_offset())); + if (PrintPreciseRTMLockingStatistics) { + for (int i = 0; i < RTMLockingCounters::ABORT_STATUS_LIMIT; i++) { + Label check_abort; + testl(abort_status, (1< 0) { + // Delay calculation + movptr(tmpReg, ExternalAddress((address) RTMLockingCounters::rtm_calculation_flag_addr()), tmpReg); + testptr(tmpReg, tmpReg); + jccb(Assembler::equal, L_done); + } + // Abort ratio calculation only if abort_count > RTMAbortThreshold + // Aborted transactions = abort_count * 100 + // All transactions = total_count * RTMTotalCountIncrRate + // Set no_rtm bit if (Aborted transactions >= All transactions * RTMAbortRatio) + + movptr(tmpReg, Address(rtm_counters_Reg, RTMLockingCounters::abort_count_offset())); + cmpptr(tmpReg, RTMAbortThreshold); + jccb(Assembler::below, L_check_always_rtm2); + imulptr(tmpReg, tmpReg, 100); + + Register scrReg = rtm_counters_Reg; + movptr(scrReg, Address(rtm_counters_Reg, RTMLockingCounters::total_count_offset())); + imulptr(scrReg, scrReg, RTMTotalCountIncrRate); + imulptr(scrReg, scrReg, RTMAbortRatio); + cmpptr(tmpReg, scrReg); + jccb(Assembler::below, L_check_always_rtm1); + if (method_data != NULL) { + // set rtm_state to "no rtm" in MDO + mov_metadata(tmpReg, method_data); + if (os::is_MP()) { + lock(); + } + orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), NoRTM); + } + jmpb(L_done); + bind(L_check_always_rtm1); + // Reload RTMLockingCounters* address + lea(rtm_counters_Reg, ExternalAddress((address)rtm_counters)); + bind(L_check_always_rtm2); + movptr(tmpReg, Address(rtm_counters_Reg, RTMLockingCounters::total_count_offset())); + cmpptr(tmpReg, RTMLockingThreshold / RTMTotalCountIncrRate); + jccb(Assembler::below, L_done); + if (method_data != NULL) { + // set rtm_state to "always rtm" in MDO + mov_metadata(tmpReg, method_data); + if (os::is_MP()) { + lock(); + } + orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), UseRTM); + } + bind(L_done); +} + +// Update counters and perform abort ratio calculation +// input: abort_status_Reg +// rtm_counters_Reg, flags are killed +void MacroAssembler::rtm_profiling(Register abort_status_Reg, + Register rtm_counters_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data, + bool profile_rtm) { + + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + // update rtm counters based on rax value at abort + // reads abort_status_Reg, updates flags + lea(rtm_counters_Reg, ExternalAddress((address)rtm_counters)); + rtm_counters_update(abort_status_Reg, rtm_counters_Reg); + if (profile_rtm) { + // Save abort status because abort_status_Reg is used by following code. + if (RTMRetryCount > 0) { + push(abort_status_Reg); + } + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + rtm_abort_ratio_calculation(abort_status_Reg, rtm_counters_Reg, rtm_counters, method_data); + // restore abort status + if (RTMRetryCount > 0) { + pop(abort_status_Reg); + } + } +} + +// Retry on abort if abort's status is 0x6: can retry (0x2) | memory conflict (0x4) +// inputs: retry_count_Reg +// : abort_status_Reg +// output: retry_count_Reg decremented by 1 +// flags are killed +void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register abort_status_Reg, Label& retryLabel) { + Label doneRetry; + assert(abort_status_Reg == rax, ""); + // The abort reason bits are in eax (see all states in rtmLocking.hpp) + // 0x6 = conflict on which we can retry (0x2) | memory conflict (0x4) + // if reason is in 0x6 and retry count != 0 then retry + andptr(abort_status_Reg, 0x6); + jccb(Assembler::zero, doneRetry); + testl(retry_count_Reg, retry_count_Reg); + jccb(Assembler::zero, doneRetry); + pause(); + decrementl(retry_count_Reg); + jmp(retryLabel); + bind(doneRetry); +} + +// Spin and retry if lock is busy, +// inputs: box_Reg (monitor address) +// : retry_count_Reg +// output: retry_count_Reg decremented by 1 +// : clear z flag if retry count exceeded +// tmp_Reg, scr_Reg, flags are killed +void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register box_Reg, + Register tmp_Reg, Register scr_Reg, Label& retryLabel) { + Label SpinLoop, SpinExit, doneRetry; + // Clean monitor_value bit to get valid pointer + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + + testl(retry_count_Reg, retry_count_Reg); + jccb(Assembler::zero, doneRetry); + decrementl(retry_count_Reg); + movptr(scr_Reg, RTMSpinLoopCount); + + bind(SpinLoop); + pause(); + decrementl(scr_Reg); + jccb(Assembler::lessEqual, SpinExit); + movptr(tmp_Reg, Address(box_Reg, owner_offset)); + testptr(tmp_Reg, tmp_Reg); + jccb(Assembler::notZero, SpinLoop); + + bind(SpinExit); + jmp(retryLabel); + bind(doneRetry); + incrementl(retry_count_Reg); // clear z flag +} + +// Use RTM for normal stack locks +// Input: objReg (object to lock) +void MacroAssembler::rtm_stack_locking(Register objReg, Register tmpReg, Register scrReg, + Register retry_on_abort_count_Reg, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL, Label& IsInflated) { + assert(UseRTMForStackLocks, "why call this otherwise?"); + assert(!UseBiasedLocking, "Biased locking is not supported with RTM locking"); + assert(tmpReg == rax, ""); + assert(scrReg == rdx, ""); + Label L_rtm_retry, L_decrement_retry, L_on_abort; + + if (RTMRetryCount > 0) { + movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort + bind(L_rtm_retry); + } + if (!UseRTMXendForLockBusy) { + movptr(tmpReg, Address(objReg, 0)); + testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + jcc(Assembler::notZero, IsInflated); + } + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + Label L_noincrement; + if (RTMTotalCountIncrRate > 1) { + // tmpReg, scrReg and flags are killed + branch_on_random_using_rdtsc(tmpReg, scrReg, (int)RTMTotalCountIncrRate, L_noincrement); + } + assert(stack_rtm_counters != NULL, "should not be NULL when profiling RTM"); + atomic_incptr(ExternalAddress((address)stack_rtm_counters->total_count_addr()), scrReg); + bind(L_noincrement); + } + xbegin(L_on_abort); + movptr(tmpReg, Address(objReg, 0)); // fetch markword + andptr(tmpReg, markOopDesc::biased_lock_mask_in_place); // look at 3 lock bits + cmpptr(tmpReg, markOopDesc::unlocked_value); // bits = 001 unlocked + jcc(Assembler::equal, DONE_LABEL); // all done if unlocked + + Register abort_status_Reg = tmpReg; // status of abort is stored in RAX + if (UseRTMXendForLockBusy) { + xend(); + movptr(tmpReg, Address(objReg, 0)); + testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + jcc(Assembler::notZero, IsInflated); + movptr(abort_status_Reg, 0x1); // Set the abort status to 1 (as xabort does) + jmp(L_decrement_retry); + } + else { + xabort(0); + } + bind(L_on_abort); + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + rtm_profiling(abort_status_Reg, scrReg, stack_rtm_counters, method_data, profile_rtm); + } + bind(L_decrement_retry); + if (RTMRetryCount > 0) { + // retry on lock abort if abort status is 'can retry' (0x2) or 'memory conflict' (0x4) + rtm_retry_lock_on_abort(retry_on_abort_count_Reg, abort_status_Reg, L_rtm_retry); + } +} + +// Use RTM for inflating locks +// inputs: objReg (object to lock) +// boxReg (on-stack box address (displaced header location) - KILLED) +// tmpReg (ObjectMonitor address + 2(monitor_value)) +void MacroAssembler::rtm_inflated_locking(Register objReg, Register boxReg, Register tmpReg, + Register scrReg, Register retry_on_busy_count_Reg, + Register retry_on_abort_count_Reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL) { + assert(UseRTMLocking, "why call this otherwise?"); + assert(tmpReg == rax, ""); + assert(scrReg == rdx, ""); + Label L_rtm_retry, L_decrement_retry, L_on_abort; + // Clean monitor_value bit to get valid pointer + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + + // Without cast to int32_t a movptr will destroy r10 which is typically obj + movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); + movptr(boxReg, tmpReg); // Save ObjectMonitor address + + if (RTMRetryCount > 0) { + movl(retry_on_busy_count_Reg, RTMRetryCount); // Retry on lock busy + movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort + bind(L_rtm_retry); + } + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + Label L_noincrement; + if (RTMTotalCountIncrRate > 1) { + // tmpReg, scrReg and flags are killed + branch_on_random_using_rdtsc(tmpReg, scrReg, (int)RTMTotalCountIncrRate, L_noincrement); + } + assert(rtm_counters != NULL, "should not be NULL when profiling RTM"); + atomic_incptr(ExternalAddress((address)rtm_counters->total_count_addr()), scrReg); + bind(L_noincrement); + } + xbegin(L_on_abort); + movptr(tmpReg, Address(objReg, 0)); + movptr(tmpReg, Address(tmpReg, owner_offset)); + testptr(tmpReg, tmpReg); + jcc(Assembler::zero, DONE_LABEL); + if (UseRTMXendForLockBusy) { + xend(); + jmp(L_decrement_retry); + } + else { + xabort(0); + } + bind(L_on_abort); + Register abort_status_Reg = tmpReg; // status of abort is stored in RAX + if (PrintPreciseRTMLockingStatistics || profile_rtm) { + rtm_profiling(abort_status_Reg, scrReg, rtm_counters, method_data, profile_rtm); + } + if (RTMRetryCount > 0) { + // retry on lock abort if abort status is 'can retry' (0x2) or 'memory conflict' (0x4) + rtm_retry_lock_on_abort(retry_on_abort_count_Reg, abort_status_Reg, L_rtm_retry); + } + + movptr(tmpReg, Address(boxReg, owner_offset)) ; + testptr(tmpReg, tmpReg) ; + jccb(Assembler::notZero, L_decrement_retry) ; + + // Appears unlocked - try to swing _owner from null to non-null. + // Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand. +#ifdef _LP64 + Register threadReg = r15_thread; +#else + get_thread(scrReg); + Register threadReg = scrReg; +#endif + if (os::is_MP()) { + lock(); + } + cmpxchgptr(threadReg, Address(boxReg, owner_offset)); // Updates tmpReg + + if (RTMRetryCount > 0) { + // success done else retry + jccb(Assembler::equal, DONE_LABEL) ; + bind(L_decrement_retry); + // Spin and retry if lock is busy. + rtm_retry_lock_on_busy(retry_on_busy_count_Reg, boxReg, tmpReg, scrReg, L_rtm_retry); + } + else { + bind(L_decrement_retry); + } +} + +#endif // INCLUDE_RTM_OPT + // Fast_Lock and Fast_Unlock used by C2 // Because the transitions from emitted code to the runtime @@ -1350,17 +1697,26 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, La // box: on-stack box address (displaced header location) - KILLED // rax,: tmp -- KILLED // scr: tmp -- KILLED -void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, Register scrReg, BiasedLockingCounters* counters) { +void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg, + Register scrReg, Register cx1Reg, Register cx2Reg, + BiasedLockingCounters* counters, + RTMLockingCounters* rtm_counters, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, + bool use_rtm, bool profile_rtm) { // Ensure the register assignents are disjoint - guarantee (objReg != boxReg, ""); - guarantee (objReg != tmpReg, ""); - guarantee (objReg != scrReg, ""); - guarantee (boxReg != tmpReg, ""); - guarantee (boxReg != scrReg, ""); - guarantee (tmpReg == rax, ""); + assert(tmpReg == rax, ""); + + if (use_rtm) { + assert_different_registers(objReg, boxReg, tmpReg, scrReg, cx1Reg, cx2Reg); + } else { + assert(cx1Reg == noreg, ""); + assert(cx2Reg == noreg, ""); + assert_different_registers(objReg, boxReg, tmpReg, scrReg); + } if (counters != NULL) { - atomic_incl(ExternalAddress((address)counters->total_entry_count_addr())); + atomic_incl(ExternalAddress((address)counters->total_entry_count_addr()), scrReg); } if (EmitSync & 1) { // set box->dhw = unused_mark (3) @@ -1419,12 +1775,20 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, counters); } +#if INCLUDE_RTM_OPT + if (UseRTMForStackLocks && use_rtm) { + rtm_stack_locking(objReg, tmpReg, scrReg, cx2Reg, + stack_rtm_counters, method_data, profile_rtm, + DONE_LABEL, IsInflated); + } +#endif // INCLUDE_RTM_OPT + movptr(tmpReg, Address(objReg, 0)); // [FETCH] - testl (tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased - jccb (Assembler::notZero, IsInflated); + testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased + jccb(Assembler::notZero, IsInflated); // Attempt stack-locking ... - orptr (tmpReg, 0x1); + orptr (tmpReg, markOopDesc::unlocked_value); movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS if (os::is_MP()) { lock(); @@ -1434,19 +1798,32 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg cond_inc32(Assembler::equal, ExternalAddress((address)counters->fast_path_entry_count_addr())); } - jccb(Assembler::equal, DONE_LABEL); + jcc(Assembler::equal, DONE_LABEL); // Success - // Recursive locking + // Recursive locking. + // The object is stack-locked: markword contains stack pointer to BasicLock. + // Locked by current thread if difference with current SP is less than one page. subptr(tmpReg, rsp); + // Next instruction set ZFlag == 1 (Success) if difference is less then one page. andptr(tmpReg, (int32_t) (NOT_LP64(0xFFFFF003) LP64_ONLY(7 - os::vm_page_size())) ); movptr(Address(boxReg, 0), tmpReg); if (counters != NULL) { cond_inc32(Assembler::equal, ExternalAddress((address)counters->fast_path_entry_count_addr())); } - jmpb(DONE_LABEL); + jmp(DONE_LABEL); bind(IsInflated); + // The object is inflated. tmpReg contains pointer to ObjectMonitor* + 2(monitor_value) + +#if INCLUDE_RTM_OPT + // Use the same RTM locking code in 32- and 64-bit VM. + if (use_rtm) { + rtm_inflated_locking(objReg, boxReg, tmpReg, scrReg, cx1Reg, cx2Reg, + rtm_counters, method_data, profile_rtm, DONE_LABEL); + } else { +#endif // INCLUDE_RTM_OPT + #ifndef _LP64 // The object is inflated. // @@ -1576,7 +1953,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg // Without cast to int32_t a movptr will destroy r10 which is typically obj movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); - mov (boxReg, tmpReg); + movptr (boxReg, tmpReg); movptr (tmpReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); testptr(tmpReg, tmpReg); jccb (Assembler::notZero, DONE_LABEL); @@ -1587,9 +1964,11 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg } cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); // Intentional fall-through into DONE_LABEL ... +#endif // _LP64 +#if INCLUDE_RTM_OPT + } // use_rtm() #endif - // DONE_LABEL is a hot target - we'd really like to place it at the // start of cache line by padding with NOPs. // See the AMD and Intel software optimization manuals for the @@ -1631,11 +2010,9 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg // should not be unlocked by "normal" java-level locking and vice-versa. The specification // doesn't specify what will occur if a program engages in such mixed-mode locking, however. -void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg) { - guarantee (objReg != boxReg, ""); - guarantee (objReg != tmpReg, ""); - guarantee (boxReg != tmpReg, ""); - guarantee (boxReg == rax, ""); +void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpReg, bool use_rtm) { + assert(boxReg == rax, ""); + assert_different_registers(objReg, boxReg, tmpReg); if (EmitSync & 4) { // Disable - inhibit all inlining. Force control through the slow-path @@ -1667,14 +2044,41 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR biased_locking_exit(objReg, tmpReg, DONE_LABEL); } - cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD); // Examine the displaced header - movptr(tmpReg, Address(objReg, 0)); // Examine the object's markword - jccb (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock +#if INCLUDE_RTM_OPT + if (UseRTMForStackLocks && use_rtm) { + assert(!UseBiasedLocking, "Biased locking is not supported with RTM locking"); + Label L_regular_unlock; + movptr(tmpReg, Address(objReg, 0)); // fetch markword + andptr(tmpReg, markOopDesc::biased_lock_mask_in_place); // look at 3 lock bits + cmpptr(tmpReg, markOopDesc::unlocked_value); // bits = 001 unlocked + jccb(Assembler::notEqual, L_regular_unlock); // if !HLE RegularLock + xend(); // otherwise end... + jmp(DONE_LABEL); // ... and we're done + bind(L_regular_unlock); + } +#endif - testptr(tmpReg, 0x02); // Inflated? + cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD); // Examine the displaced header + jcc (Assembler::zero, DONE_LABEL); // 0 indicates recursive stack-lock + movptr(tmpReg, Address(objReg, 0)); // Examine the object's markword + testptr(tmpReg, markOopDesc::monitor_value); // Inflated? jccb (Assembler::zero, Stacked); // It's inflated. +#if INCLUDE_RTM_OPT + if (use_rtm) { + Label L_regular_inflated_unlock; + // Clean monitor_value bit to get valid pointer + int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + movptr(boxReg, Address(tmpReg, owner_offset)); + testptr(boxReg, boxReg); + jccb(Assembler::notZero, L_regular_inflated_unlock); + xend(); + jmpb(DONE_LABEL); + bind(L_regular_inflated_unlock); + } +#endif + // Despite our balanced locking property we still check that m->_owner == Self // as java routines or native JNI code called by this thread might // have released the lock. @@ -2448,7 +2852,9 @@ void MacroAssembler::cond_inc32(Condition cond, AddressLiteral counter_addr) { Condition negated_cond = negate_condition(cond); Label L; jcc(negated_cond, L); + pushf(); // Preserve flags atomic_incl(counter_addr); + popf(); bind(L); } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 6ac95774ba9..e154ae838c4 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -27,6 +27,7 @@ #include "asm/assembler.hpp" #include "utilities/macros.hpp" +#include "runtime/rtmLocking.hpp" // MacroAssembler extends Assembler by frequently used macros. @@ -111,7 +112,8 @@ class MacroAssembler: public Assembler { op == 0xE9 /* jmp */ || op == 0xEB /* short jmp */ || (op & 0xF0) == 0x70 /* short jcc */ || - op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */, + op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */ || + op == 0xC7 && branch[1] == 0xF8 /* xbegin */, "Invalid opcode at patch point"); if (op == 0xEB || (op & 0xF0) == 0x70) { @@ -121,7 +123,7 @@ class MacroAssembler: public Assembler { guarantee(this->is8bit(imm8), "Short forward jump exceeds 8-bit offset"); *disp = imm8; } else { - int* disp = (int*) &branch[(op == 0x0F)? 2: 1]; + int* disp = (int*) &branch[(op == 0x0F || op == 0xC7)? 2: 1]; int imm32 = target - (address) &disp[1]; *disp = imm32; } @@ -161,7 +163,6 @@ class MacroAssembler: public Assembler { void incrementq(Register reg, int value = 1); void incrementq(Address dst, int value = 1); - // Support optimal SSE move instructions. void movflt(XMMRegister dst, XMMRegister src) { if (UseXmmRegToRegMoveAll) { movaps(dst, src); return; } @@ -187,6 +188,8 @@ class MacroAssembler: public Assembler { void incrementl(AddressLiteral dst); void incrementl(ArrayAddress dst); + void incrementq(AddressLiteral dst); + // Alignment void align(int modulus); @@ -654,8 +657,36 @@ class MacroAssembler: public Assembler { #ifdef COMPILER2 // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. // See full desription in macroAssembler_x86.cpp. - void fast_lock(Register obj, Register box, Register tmp, Register scr, BiasedLockingCounters* counters); - void fast_unlock(Register obj, Register box, Register tmp); + void fast_lock(Register obj, Register box, Register tmp, + Register scr, Register cx1, Register cx2, + BiasedLockingCounters* counters, + RTMLockingCounters* rtm_counters, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, + bool use_rtm, bool profile_rtm); + void fast_unlock(Register obj, Register box, Register tmp, bool use_rtm); +#if INCLUDE_RTM_OPT + void rtm_counters_update(Register abort_status, Register rtm_counters); + void branch_on_random_using_rdtsc(Register tmp, Register scr, int count, Label& brLabel); + void rtm_abort_ratio_calculation(Register tmp, Register rtm_counters_reg, + RTMLockingCounters* rtm_counters, + Metadata* method_data); + void rtm_profiling(Register abort_status_Reg, Register rtm_counters_Reg, + RTMLockingCounters* rtm_counters, Metadata* method_data, bool profile_rtm); + void rtm_retry_lock_on_abort(Register retry_count, Register abort_status, Label& retryLabel); + void rtm_retry_lock_on_busy(Register retry_count, Register box, Register tmp, Register scr, Label& retryLabel); + void rtm_stack_locking(Register obj, Register tmp, Register scr, + Register retry_on_abort_count, + RTMLockingCounters* stack_rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL, Label& IsInflated); + void rtm_inflated_locking(Register obj, Register box, Register tmp, + Register scr, Register retry_on_busy_count, + Register retry_on_abort_count, + RTMLockingCounters* rtm_counters, + Metadata* method_data, bool profile_rtm, + Label& DONE_LABEL); +#endif #endif Condition negate_condition(Condition cond); @@ -721,6 +752,7 @@ class MacroAssembler: public Assembler { void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); } + void imulptr(Register dst, Register src, int imm32) { LP64_ONLY(imulq(dst, src, imm32)) NOT_LP64(imull(dst, src, imm32)); } void negptr(Register dst) { LP64_ONLY(negq(dst)) NOT_LP64(negl(dst)); } @@ -762,7 +794,14 @@ class MacroAssembler: public Assembler { // Conditionally (atomically, on MPs) increments passed counter address, preserving condition codes. void cond_inc32(Condition cond, AddressLiteral counter_addr); // Unconditional atomic increment. - void atomic_incl(AddressLiteral counter_addr); + void atomic_incl(Address counter_addr); + void atomic_incl(AddressLiteral counter_addr, Register scr = rscratch1); +#ifdef _LP64 + void atomic_incq(Address counter_addr); + void atomic_incq(AddressLiteral counter_addr, Register scr = rscratch1); +#endif + void atomic_incptr(AddressLiteral counter_addr, Register scr = rscratch1) { LP64_ONLY(atomic_incq(counter_addr, scr)) NOT_LP64(atomic_incl(counter_addr, scr)) ; } + void atomic_incptr(Address counter_addr) { LP64_ONLY(atomic_incq(counter_addr)) NOT_LP64(atomic_incl(counter_addr)) ; } void lea(Register dst, AddressLiteral adr); void lea(Address dst, AddressLiteral adr); @@ -1074,7 +1113,11 @@ public: void movptr(Register dst, Address src); - void movptr(Register dst, AddressLiteral src); +#ifdef _LP64 + void movptr(Register dst, AddressLiteral src, Register scratch=rscratch1); +#else + void movptr(Register dst, AddressLiteral src, Register scratch=noreg); // Scratch reg is ignored in 32-bit +#endif void movptr(Register dst, intptr_t src); void movptr(Register dst, Register src); diff --git a/hotspot/src/cpu/x86/vm/rtmLocking.cpp b/hotspot/src/cpu/x86/vm/rtmLocking.cpp new file mode 100644 index 00000000000..8ea21d896ea --- /dev/null +++ b/hotspot/src/cpu/x86/vm/rtmLocking.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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 "runtime/task.hpp" +#include "runtime/rtmLocking.hpp" + +// One-shot PeriodicTask subclass for enabling RTM locking +uintx RTMLockingCounters::_calculation_flag = 0; + +class RTMLockingCalculationTask : public PeriodicTask { + public: + RTMLockingCalculationTask(size_t interval_time) : PeriodicTask(interval_time){ } + + virtual void task() { + RTMLockingCounters::_calculation_flag = 1; + // Reclaim our storage and disenroll ourself + delete this; + } +}; + +void RTMLockingCounters::init() { + if (UseRTMLocking && RTMLockingCalculationDelay > 0) { + RTMLockingCalculationTask* task = new RTMLockingCalculationTask(RTMLockingCalculationDelay); + task->enroll(); + } else { + _calculation_flag = 1; + } +} + +//------------------------------print_on------------------------------- +void RTMLockingCounters::print_on(outputStream* st) { + tty->print_cr("# rtm locks total (estimated): " UINTX_FORMAT, _total_count * RTMTotalCountIncrRate); + tty->print_cr("# rtm lock aborts : " UINTX_FORMAT, _abort_count); + for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { + tty->print_cr("# rtm lock aborts %d: " UINTX_FORMAT, i, _abortX_count[i]); + } +} diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 146d34c40a4..2f9ffd7feb7 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1817,6 +1817,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Frame is now completed as far as size and linkage. int frame_complete = ((intptr_t)__ pc()) - start; + if (UseRTMLocking) { + // Abort RTM transaction before calling JNI + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + // Calculate the difference between rsp and rbp,. We need to know it // after the native call because on windows Java Natives will pop // the arguments and it is painful to do rsp relative addressing @@ -3170,6 +3177,12 @@ void SharedRuntime::generate_uncommon_trap_blob() { }; address start = __ pc(); + + if (UseRTMLocking) { + // Abort RTM transaction before possible nmethod deoptimization. + __ xabort(0); + } + // Push self-frame. __ subptr(rsp, return_off*wordSize); // Epilog! @@ -3355,6 +3368,14 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t address call_pc = NULL; bool cause_return = (poll_type == POLL_AT_RETURN); bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + + if (UseRTMLocking) { + // Abort RTM transaction before calling runtime + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + // If cause_return is true we are at a poll_return and there is // the return address on the stack to the caller on the nmethod // that is safepoint. We can leave this return on the stack and diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 37cf1d5c2cf..bdb77a66351 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -2012,6 +2012,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Frame is now completed as far as size and linkage. int frame_complete = ((intptr_t)__ pc()) - start; + if (UseRTMLocking) { + // Abort RTM transaction before calling JNI + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + #ifdef ASSERT { Label L; @@ -3612,6 +3619,11 @@ void SharedRuntime::generate_uncommon_trap_blob() { address start = __ pc(); + if (UseRTMLocking) { + // Abort RTM transaction before possible nmethod deoptimization. + __ xabort(0); + } + // Push self-frame. We get here with a return address on the // stack, so rsp is 8-byte aligned until we allocate our frame. __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog! @@ -3792,6 +3804,13 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t bool cause_return = (poll_type == POLL_AT_RETURN); bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); + if (UseRTMLocking) { + // Abort RTM transaction before calling runtime + // because critical section will be large and will be + // aborted anyway. Also nmethod could be deoptimized. + __ xabort(0); + } + // Make room for return address (or push it again) if (!cause_return) { __ push(rbx); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index f449cc446e5..28b79b784f2 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -475,7 +475,7 @@ void VM_Version::get_processor_features() { } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -492,8 +492,9 @@ void VM_Version::get_processor_features() { (supports_avx() ? ", avx" : ""), (supports_avx2() ? ", avx2" : ""), (supports_aes() ? ", aes" : ""), - (supports_clmul() ? ", clmul" : ""), + (supports_clmul() ? ", clmul" : ""), (supports_erms() ? ", erms" : ""), + (supports_rtm() ? ", rtm" : ""), (supports_mmx_ext() ? ", mmxext" : ""), (supports_3dnow_prefetch() ? ", 3dnowpref" : ""), (supports_lzcnt() ? ", lzcnt": ""), @@ -534,7 +535,7 @@ void VM_Version::get_processor_features() { } } else if (UseAES) { if (!FLAG_IS_DEFAULT(UseAES)) - warning("AES instructions not available on this CPU"); + warning("AES instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseAES, false); } @@ -567,10 +568,57 @@ void VM_Version::get_processor_features() { } } else if (UseAESIntrinsics) { if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) - warning("AES intrinsics not available on this CPU"); + warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } + // Adjust RTM (Restricted Transactional Memory) flags + if (!supports_rtm() && UseRTMLocking) { + // Can't continue because UseRTMLocking affects UseBiasedLocking flag + // setting during arguments processing. See use_biased_locking(). + // VM_Version_init() is executed after UseBiasedLocking is used + // in Thread::allocate(). + vm_exit_during_initialization("RTM instructions are not available on this CPU"); + } + +#if INCLUDE_RTM_OPT + if (UseRTMLocking) { + if (!FLAG_IS_CMDLINE(UseRTMLocking)) { + // RTM locking should be used only for applications with + // high lock contention. For now we do not use it by default. + vm_exit_during_initialization("UseRTMLocking flag should be only set on command line"); + } + if (!is_power_of_2(RTMTotalCountIncrRate)) { + warning("RTMTotalCountIncrRate must be a power of 2, resetting it to 64"); + FLAG_SET_DEFAULT(RTMTotalCountIncrRate, 64); + } + if (RTMAbortRatio < 0 || RTMAbortRatio > 100) { + warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50"); + FLAG_SET_DEFAULT(RTMAbortRatio, 50); + } + } else { // !UseRTMLocking + if (UseRTMForStackLocks) { + if (!FLAG_IS_DEFAULT(UseRTMForStackLocks)) { + warning("UseRTMForStackLocks flag should be off when UseRTMLocking flag is off"); + } + FLAG_SET_DEFAULT(UseRTMForStackLocks, false); + } + if (UseRTMDeopt) { + FLAG_SET_DEFAULT(UseRTMDeopt, false); + } + if (PrintPreciseRTMLockingStatistics) { + FLAG_SET_DEFAULT(PrintPreciseRTMLockingStatistics, false); + } + } +#else + if (UseRTMLocking) { + // Only C2 does RTM locking optimization. + // Can't continue because UseRTMLocking affects UseBiasedLocking flag + // setting during arguments processing. See use_biased_locking(). + vm_exit_during_initialization("RTM locking optimization is not supported in this VM"); + } +#endif + #ifdef COMPILER2 if (UseFPUForSpilling) { if (UseSSE < 2) { @@ -913,6 +961,27 @@ void VM_Version::get_processor_features() { #endif // !PRODUCT } +bool VM_Version::use_biased_locking() { +#if INCLUDE_RTM_OPT + // RTM locking is most useful when there is high lock contention and + // low data contention. With high lock contention the lock is usually + // inflated and biased locking is not suitable for that case. + // RTM locking code requires that biased locking is off. + // Note: we can't switch off UseBiasedLocking in get_processor_features() + // because it is used by Thread::allocate() which is called before + // VM_Version::initialize(). + if (UseRTMLocking && UseBiasedLocking) { + if (FLAG_IS_DEFAULT(UseBiasedLocking)) { + FLAG_SET_DEFAULT(UseBiasedLocking, false); + } else { + warning("Biased locking is not supported with RTM locking; ignoring UseBiasedLocking flag." ); + UseBiasedLocking = false; + } + } +#endif + return UseBiasedLocking; +} + void VM_Version::initialize() { ResourceMark rm; // Making this stub must be FIRST use of assembler diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index dbc4a9a085a..a3be0995ae1 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -207,7 +207,9 @@ public: : 2, bmi2 : 1, erms : 1, - : 22; + : 1, + rtm : 1, + : 20; } bits; }; @@ -257,7 +259,8 @@ protected: CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions CPU_CLMUL = (1 << 21), // carryless multiply for CRC CPU_BMI1 = (1 << 22), - CPU_BMI2 = (1 << 23) + CPU_BMI2 = (1 << 23), + CPU_RTM = (1 << 24) // Restricted Transactional Memory instructions } cpuFeatureFlags; enum { @@ -444,6 +447,8 @@ protected: result |= CPU_ERMS; if (_cpuid_info.std_cpuid1_ecx.bits.clmul != 0) result |= CPU_CLMUL; + if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0) + result |= CPU_RTM; // AMD features. if (is_amd()) { @@ -514,6 +519,9 @@ public: // Initialization static void initialize(); + // Override Abstract_VM_Version implementation + static bool use_biased_locking(); + // Asserts static void assert_is_initialized() { assert(_cpuid_info.std_cpuid1_eax.bits.family != 0, "VM_Version not initialized"); @@ -606,6 +614,7 @@ public: static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; } static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; } static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; } + static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } // Intel features diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index c4820db3b07..6a377b89401 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -12925,13 +12925,31 @@ instruct RethrowException() // inlined locking and unlocking +instruct cmpFastLockRTM(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eDXRegI scr, rRegI cx1, rRegI cx2) %{ + predicate(Compile::current()->use_rtm()); + match(Set cr (FastLock object box)); + effect(TEMP tmp, TEMP scr, TEMP cx1, TEMP cx2, USE_KILL box); + ins_cost(300); + format %{ "FASTLOCK $object,$box\t! kills $box,$tmp,$scr,$cx1,$cx2" %} + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, $cx1$$Register, $cx2$$Register, + _counters, _rtm_counters, _stack_rtm_counters, + ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), + true, ra_->C->profile_rtm()); + %} + ins_pipe(pipe_slow); +%} + instruct cmpFastLock(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eRegP scr) %{ + predicate(!Compile::current()->use_rtm()); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP scr, USE_KILL box); ins_cost(300); format %{ "FASTLOCK $object,$box\t! kills $box,$tmp,$scr" %} ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $scr$$Register, _counters); + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, noreg, noreg, _counters, NULL, NULL, NULL, false, false); %} ins_pipe(pipe_slow); %} @@ -12942,7 +12960,7 @@ instruct cmpFastUnlock(eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{ ins_cost(300); format %{ "FASTUNLOCK $object,$box\t! kills $box,$tmp" %} ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register); + __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, ra_->C->use_rtm()); %} ins_pipe(pipe_slow); %} diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index cebc37cc25c..cd898026b06 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -11387,13 +11387,31 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ // ============================================================================ // inlined locking and unlocking +instruct cmpFastLockRTM(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rdx_RegI scr, rRegI cx1, rRegI cx2) %{ + predicate(Compile::current()->use_rtm()); + match(Set cr (FastLock object box)); + effect(TEMP tmp, TEMP scr, TEMP cx1, TEMP cx2, USE_KILL box); + ins_cost(300); + format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr,$cx1,$cx2" %} + ins_encode %{ + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, $cx1$$Register, $cx2$$Register, + _counters, _rtm_counters, _stack_rtm_counters, + ((Method*)(ra_->C->method()->constant_encoding()))->method_data(), + true, ra_->C->profile_rtm()); + %} + ins_pipe(pipe_slow); +%} + instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr) %{ + predicate(!Compile::current()->use_rtm()); match(Set cr (FastLock object box)); effect(TEMP tmp, TEMP scr, USE_KILL box); ins_cost(300); format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr" %} ins_encode %{ - __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $scr$$Register, _counters); + __ fast_lock($object$$Register, $box$$Register, $tmp$$Register, + $scr$$Register, noreg, noreg, _counters, NULL, NULL, NULL, false, false); %} ins_pipe(pipe_slow); %} @@ -11404,7 +11422,7 @@ instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{ ins_cost(300); format %{ "fastunlock $object,$box\t! kills $box,$tmp" %} ins_encode %{ - __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register); + __ fast_unlock($object$$Register, $box$$Register, $tmp$$Register, ra_->C->use_rtm()); %} ins_pipe(pipe_slow); %} diff --git a/hotspot/src/share/vm/adlc/output_c.cpp b/hotspot/src/share/vm/adlc/output_c.cpp index c351ed323d2..bd2393c578c 100644 --- a/hotspot/src/share/vm/adlc/output_c.cpp +++ b/hotspot/src/share/vm/adlc/output_c.cpp @@ -1582,6 +1582,8 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) { if( node->is_ideal_fastlock() && new_inst->is_ideal_fastlock() ) { fprintf(fp, " ((MachFastLockNode*)n%d)->_counters = _counters;\n",cnt); + fprintf(fp, " ((MachFastLockNode*)n%d)->_rtm_counters = _rtm_counters;\n",cnt); + fprintf(fp, " ((MachFastLockNode*)n%d)->_stack_rtm_counters = _stack_rtm_counters;\n",cnt); } // Fill in the bottom_type where requested @@ -3963,6 +3965,8 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden } if( inst->is_ideal_fastlock() ) { fprintf(fp_cpp, "%s node->_counters = _leaf->as_FastLock()->counters();\n", indent); + fprintf(fp_cpp, "%s node->_rtm_counters = _leaf->as_FastLock()->rtm_counters();\n", indent); + fprintf(fp_cpp, "%s node->_stack_rtm_counters = _leaf->as_FastLock()->stack_rtm_counters();\n", indent); } } diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 17764f12ad1..36a46f271a3 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -961,7 +961,8 @@ void ciEnv::register_method(ciMethod* target, AbstractCompiler* compiler, int comp_level, bool has_unsafe_access, - bool has_wide_vectors) { + bool has_wide_vectors, + RTMState rtm_state) { VM_ENTRY_MARK; nmethod* nm = NULL; { @@ -1002,6 +1003,15 @@ void ciEnv::register_method(ciMethod* target, methodHandle method(THREAD, target->get_Method()); +#if INCLUDE_RTM_OPT + if (!failing() && (rtm_state != NoRTM) && + (method()->method_data() != NULL) && + (method()->method_data()->rtm_state() != rtm_state)) { + // Preemptive decompile if rtm state was changed. + record_failure("RTM state change invalidated rtm code"); + } +#endif + if (failing()) { // While not a true deoptimization, it is a preemptive decompile. MethodData* mdo = method()->method_data(); @@ -1028,7 +1038,9 @@ void ciEnv::register_method(ciMethod* target, frame_words, oop_map_set, handler_table, inc_table, compiler, comp_level); - +#if INCLUDE_RTM_OPT + nm->set_rtm_state(rtm_state); +#endif // Free codeBlobs code_buffer->free_blob(); diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index 2b847f0af3c..65e4bb39434 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -365,7 +365,8 @@ public: AbstractCompiler* compiler, int comp_level, bool has_unsafe_access, - bool has_wide_vectors); + bool has_wide_vectors, + RTMState rtm_state = NoRTM); // Access to certain well known ciObjects. diff --git a/hotspot/src/share/vm/ci/ciMethodData.hpp b/hotspot/src/share/vm/ci/ciMethodData.hpp index e5b380fe70f..b1809a19d10 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.hpp +++ b/hotspot/src/share/vm/ci/ciMethodData.hpp @@ -478,6 +478,18 @@ public: int invocation_count() { return _invocation_counter; } int backedge_count() { return _backedge_counter; } + +#if INCLUDE_RTM_OPT + // return cached value + int rtm_state() { + if (is_empty()) { + return NoRTM; + } else { + return get_MethodData()->rtm_state(); + } + } +#endif + // Transfer information about the method to MethodData*. // would_profile means we would like to profile this method, // meaning it's not trivial. diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index a002ee76ea4..16b4cce17ed 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -460,7 +460,9 @@ void nmethod::init_defaults() { _scavenge_root_link = NULL; _scavenge_root_state = 0; _compiler = NULL; - +#if INCLUDE_RTM_OPT + _rtm_state = NoRTM; +#endif #ifdef HAVE_DTRACE_H _trap_offset = 0; #endif // def HAVE_DTRACE_H diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 294160cdd3b..2c36de2c9dd 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -193,6 +193,12 @@ class nmethod : public CodeBlob { jbyte _scavenge_root_state; +#if INCLUDE_RTM_OPT + // RTM state at compile time. Used during deoptimization to decide + // whether to restart collecting RTM locking abort statistic again. + RTMState _rtm_state; +#endif + // Nmethod Flushing lock. If non-zero, then the nmethod is not removed // and is not made into a zombie. However, once the nmethod is made into // a zombie, it will be locked one final time if CompiledMethodUnload @@ -414,6 +420,12 @@ class nmethod : public CodeBlob { bool is_zombie() const { return _state == zombie; } bool is_unloaded() const { return _state == unloaded; } +#if INCLUDE_RTM_OPT + // rtm state accessing and manipulating + RTMState rtm_state() const { return _rtm_state; } + void set_rtm_state(RTMState state) { _rtm_state = state; } +#endif + // Make the nmethod non entrant. The nmethod will continue to be // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 7c292c3ffe5..d97a626ebf4 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -273,7 +273,7 @@ int Method::validate_bci_from_bcx(intptr_t bcx) const { } address Method::bcp_from(int bci) const { - assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), "illegal bci"); + assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), err_msg("illegal bci: %d", bci)); address bcp = code_base() + bci; assert(is_native() && bcp == code_base() || contains(bcp), "bcp doesn't belong to this method"); return bcp; diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 0e6e0ec0130..20b36e9514d 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/systemDictionary.hpp" +#include "compiler/compilerOracle.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/linkResolver.hpp" @@ -1153,6 +1154,21 @@ void MethodData::init() { _highest_osr_comp_level = 0; _would_profile = true; +#if INCLUDE_RTM_OPT + _rtm_state = NoRTM; // No RTM lock eliding by default + if (UseRTMLocking && + !CompilerOracle::has_option_string(_method, "NoRTMLockEliding")) { + if (CompilerOracle::has_option_string(_method, "UseRTMLockEliding") || !UseRTMDeopt) { + // Generate RTM lock eliding code without abort ratio calculation code. + _rtm_state = UseRTM; + } else if (UseRTMDeopt) { + // Generate RTM lock eliding code and include abort ratio calculation + // code if UseRTMDeopt is on. + _rtm_state = ProfileRTM; + } + } +#endif + // Initialize flags and trap history. _nof_decompiles = 0; _nof_overflow_recompiles = 0; diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index e0218f9fd47..c763779c351 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -2052,7 +2052,7 @@ public: // Whole-method sticky bits and flags enum { - _trap_hist_limit = 18, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 19, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -2083,6 +2083,12 @@ private: // Counter values at the time profiling started. int _invocation_counter_start; int _backedge_counter_start; + +#if INCLUDE_RTM_OPT + // State of RTM code generation during compilation of the method + int _rtm_state; +#endif + // Number of loops and blocks is computed when compiling the first // time with C1. It is used to determine if method is trivial. short _num_loops; @@ -2246,6 +2252,22 @@ public: InvocationCounter* invocation_counter() { return &_invocation_counter; } InvocationCounter* backedge_counter() { return &_backedge_counter; } +#if INCLUDE_RTM_OPT + int rtm_state() const { + return _rtm_state; + } + void set_rtm_state(RTMState rstate) { + _rtm_state = (int)rstate; + } + void atomic_set_rtm_state(RTMState rstate) { + Atomic::store((int)rstate, &_rtm_state); + } + + static int rtm_state_offset_in_bytes() { + return offset_of(MethodData, _rtm_state); + } +#endif + void set_would_profile(bool p) { _would_profile = p; } bool would_profile() const { return _would_profile; } diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 0db9dab8104..4f45d28666b 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -446,6 +446,9 @@ diagnostic(bool, PrintPreciseBiasedLockingStatistics, false, \ "Print per-lock-site statistics of biased locking in JVM") \ \ + diagnostic(bool, PrintPreciseRTMLockingStatistics, false, \ + "Print per-lock-site statistics of rtm locking in JVM") \ + \ notproduct(bool, PrintEliminateLocks, false, \ "Print out when locks are eliminated") \ \ diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 3cdc2c58525..54a63db1a98 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -198,6 +198,7 @@ macro(NegF) macro(NeverBranch) macro(Opaque1) macro(Opaque2) +macro(Opaque3) macro(OrI) macro(OrL) macro(OverflowAddI) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 47acd4c5b49..9c77dd0cf0b 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -694,9 +694,10 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining)); set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics")); - if (ProfileTraps) { + if (ProfileTraps RTM_OPT_ONLY( || UseRTMLocking )) { // Make sure the method being compiled gets its own MDO, // so we can at least track the decompile_count(). + // Need MDO to record RTM code generation state. method()->ensure_method_data(); } @@ -907,7 +908,8 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr compiler, env()->comp_level(), has_unsafe_access(), - SharedRuntime::is_wide_vector(max_vector_size()) + SharedRuntime::is_wide_vector(max_vector_size()), + rtm_state() ); if (log() != NULL) // Print code cache state into compiler log @@ -1073,7 +1075,23 @@ void Compile::Init(int aliaslevel) { set_do_scheduling(OptoScheduling); set_do_count_invocations(false); set_do_method_data_update(false); - + set_rtm_state(NoRTM); // No RTM lock eliding by default +#if INCLUDE_RTM_OPT + if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) { + int rtm_state = method()->method_data()->rtm_state(); + if (method_has_option("NoRTMLockEliding") || ((rtm_state & NoRTM) != 0)) { + // Don't generate RTM lock eliding code. + set_rtm_state(NoRTM); + } else if (method_has_option("UseRTMLockEliding") || ((rtm_state & UseRTM) != 0) || !UseRTMDeopt) { + // Generate RTM lock eliding code without abort ratio calculation code. + set_rtm_state(UseRTM); + } else if (UseRTMDeopt) { + // Generate RTM lock eliding code and include abort ratio calculation + // code if UseRTMDeopt is on. + set_rtm_state(ProfileRTM); + } + } +#endif if (debug_info()->recording_non_safepoints()) { set_node_note_array(new(comp_arena()) GrowableArray (comp_arena(), 8, 0, NULL)); @@ -2581,6 +2599,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { break; case Op_Opaque1: // Remove Opaque Nodes before matching case Op_Opaque2: // Remove Opaque Nodes before matching + case Op_Opaque3: n->subsume_by(n->in(1), this); break; case Op_CallStaticJava: diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 3fde797fad1..b9f48c494b9 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -319,9 +319,9 @@ class Compile : public Phase { bool _trace_opto_output; bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing #endif - // JSR 292 bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. + RTMState _rtm_state; // State of Restricted Transactional Memory usage // Compilation environment. Arena _comp_arena; // Arena with lifetime equivalent to Compile @@ -591,6 +591,10 @@ class Compile : public Phase { void set_print_inlining(bool z) { _print_inlining = z; } bool print_intrinsics() const { return _print_intrinsics; } void set_print_intrinsics(bool z) { _print_intrinsics = z; } + RTMState rtm_state() const { return _rtm_state; } + void set_rtm_state(RTMState s) { _rtm_state = s; } + bool use_rtm() const { return (_rtm_state & NoRTM) == 0; } + bool profile_rtm() const { return _rtm_state == ProfileRTM; } // check the CompilerOracle for special behaviours for this compile bool method_has_option(const char * option) { return method() != NULL && method()->has_option(option); diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp index 03a096b2331..5f6b5a7c9b1 100644 --- a/hotspot/src/share/vm/opto/connode.hpp +++ b/hotspot/src/share/vm/opto/connode.hpp @@ -642,6 +642,19 @@ public: virtual const Type *bottom_type() const { return TypeInt::INT; } }; +//------------------------------Opaque3Node------------------------------------ +// A node to prevent unwanted optimizations. Will be optimized only during +// macro nodes expansion. +class Opaque3Node : public Opaque2Node { + int _opt; // what optimization it was used for +public: + enum { RTM_OPT }; + Opaque3Node(Compile* C, Node *n, int opt) : Opaque2Node(C, n), _opt(opt) {} + virtual int Opcode() const; + bool rtm_opt() const { return (_opt == RTM_OPT); } +}; + + //----------------------PartialSubtypeCheckNode-------------------------------- // The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass // array for an instance of the superklass. Set a hidden internal cache on a diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index d9fcfb2cb91..803637dd2be 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3151,10 +3151,14 @@ FastLockNode* GraphKit::shared_lock(Node* obj) { Node* mem = reset_memory(); FastLockNode * flock = _gvn.transform(new (C) FastLockNode(0, obj, box) )->as_FastLock(); - if (PrintPreciseBiasedLockingStatistics) { + if (UseBiasedLocking && PrintPreciseBiasedLockingStatistics) { // Create the counters for this fast lock. flock->create_lock_counter(sync_jvms()); // sync_jvms used to get current bci } + + // Create the rtm counters for this fast lock if needed. + flock->create_rtm_lock_counter(sync_jvms()); // sync_jvms used to get current bci + // Add monitor to debug info for the slow path. If we block inside the // slow path and de-opt, we need the monitor hanging around map()->push_monitor( flock ); diff --git a/hotspot/src/share/vm/opto/locknode.cpp b/hotspot/src/share/vm/opto/locknode.cpp index 26c6291686b..426ed9a67d2 100644 --- a/hotspot/src/share/vm/opto/locknode.cpp +++ b/hotspot/src/share/vm/opto/locknode.cpp @@ -136,6 +136,8 @@ bool BoxLockNode::is_simple_lock_region(LockNode** unique_lock, Node* obj) { //-----------------------------hash-------------------------------------------- uint FastLockNode::hash() const { return NO_HASH; } +uint FastLockNode::size_of() const { return sizeof(*this); } + //------------------------------cmp-------------------------------------------- uint FastLockNode::cmp( const Node &n ) const { return (&n == this); // Always fail except on self @@ -159,6 +161,22 @@ void FastLockNode::create_lock_counter(JVMState* state) { _counters = blnc->counters(); } +void FastLockNode::create_rtm_lock_counter(JVMState* state) { +#if INCLUDE_RTM_OPT + Compile* C = Compile::current(); + if (C->profile_rtm() || (PrintPreciseRTMLockingStatistics && C->use_rtm())) { + RTMLockingNamedCounter* rlnc = (RTMLockingNamedCounter*) + OptoRuntime::new_named_counter(state, NamedCounter::RTMLockingCounter); + _rtm_counters = rlnc->counters(); + if (UseRTMForStackLocks) { + rlnc = (RTMLockingNamedCounter*) + OptoRuntime::new_named_counter(state, NamedCounter::RTMLockingCounter); + _stack_rtm_counters = rlnc->counters(); + } + } +#endif +} + //============================================================================= //------------------------------do_monitor_enter------------------------------- void Parse::do_monitor_enter() { diff --git a/hotspot/src/share/vm/opto/locknode.hpp b/hotspot/src/share/vm/opto/locknode.hpp index d8c400c1e61..8bd6f35afd8 100644 --- a/hotspot/src/share/vm/opto/locknode.hpp +++ b/hotspot/src/share/vm/opto/locknode.hpp @@ -92,13 +92,17 @@ public: //------------------------------FastLockNode----------------------------------- class FastLockNode: public CmpNode { private: - BiasedLockingCounters* _counters; + BiasedLockingCounters* _counters; + RTMLockingCounters* _rtm_counters; // RTM lock counters for inflated locks + RTMLockingCounters* _stack_rtm_counters; // RTM lock counters for stack locks public: FastLockNode(Node *ctrl, Node *oop, Node *box) : CmpNode(oop,box) { init_req(0,ctrl); init_class_id(Class_FastLock); _counters = NULL; + _rtm_counters = NULL; + _stack_rtm_counters = NULL; } Node* obj_node() const { return in(1); } Node* box_node() const { return in(2); } @@ -107,13 +111,17 @@ public: // FastLock and FastUnlockNode do not hash, we need one for each correspoding // LockNode/UnLockNode to avoid creating Phi's. virtual uint hash() const ; // { return NO_HASH; } + virtual uint size_of() const; virtual uint cmp( const Node &n ) const ; // Always fail, except on self virtual int Opcode() const; virtual const Type *Value( PhaseTransform *phase ) const { return TypeInt::CC; } const Type *sub(const Type *t1, const Type *t2) const { return TypeInt::CC;} void create_lock_counter(JVMState* s); - BiasedLockingCounters* counters() const { return _counters; } + void create_rtm_lock_counter(JVMState* state); + BiasedLockingCounters* counters() const { return _counters; } + RTMLockingCounters* rtm_counters() const { return _rtm_counters; } + RTMLockingCounters* stack_rtm_counters() const { return _stack_rtm_counters; } }; diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 7fa685b03eb..fcf623ca7ac 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -617,6 +617,15 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const { case Op_AryEq: { return false; } +#if INCLUDE_RTM_OPT + case Op_FastLock: + case Op_FastUnlock: { + // Don't unroll RTM locking code because it is large. + if (UseRTMLocking) { + return false; + } + } +#endif } // switch } @@ -722,6 +731,15 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const { // String intrinsics are large and have loops. return false; } +#if INCLUDE_RTM_OPT + case Op_FastLock: + case Op_FastUnlock: { + // Don't unroll RTM locking code because it is large. + if (UseRTMLocking) { + return false; + } + } +#endif } // switch } diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index 55d7e515882..def4a0df6a8 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -53,6 +53,7 @@ class MachSpillCopyNode; class Matcher; class PhaseRegAlloc; class RegMask; +class RTMLockingCounters; class State; //---------------------------MachOper------------------------------------------ @@ -714,8 +715,9 @@ public: class MachFastLockNode : public MachNode { virtual uint size_of() const { return sizeof(*this); } // Size is bigger public: - BiasedLockingCounters* _counters; - + BiasedLockingCounters* _counters; + RTMLockingCounters* _rtm_counters; // RTM lock counters for inflated locks + RTMLockingCounters* _stack_rtm_counters; // RTM lock counters for stack locks MachFastLockNode() : MachNode() {} }; diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 912709fdbee..6e18c773e36 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -2439,6 +2439,7 @@ void PhaseMacroExpand::eliminate_macro_nodes() { } } // Next, attempt to eliminate allocations + _has_locks = false; progress = true; while (progress) { progress = false; @@ -2457,11 +2458,13 @@ void PhaseMacroExpand::eliminate_macro_nodes() { case Node::Class_Lock: case Node::Class_Unlock: assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); + _has_locks = true; break; default: assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_Opaque1 || - n->Opcode() == Op_Opaque2, "unknown node type in macro list"); + n->Opcode() == Op_Opaque2 || + n->Opcode() == Op_Opaque3, "unknown node type in macro list"); } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success; @@ -2502,6 +2505,30 @@ bool PhaseMacroExpand::expand_macro_nodes() { } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { _igvn.replace_node(n, n->in(1)); success = true; +#if INCLUDE_RTM_OPT + } else if ((n->Opcode() == Op_Opaque3) && ((Opaque3Node*)n)->rtm_opt()) { + assert(C->profile_rtm(), "should be used only in rtm deoptimization code"); + assert((n->outcnt() == 1) && n->unique_out()->is_Cmp(), ""); + Node* cmp = n->unique_out(); +#ifdef ASSERT + // Validate graph. + assert((cmp->outcnt() == 1) && cmp->unique_out()->is_Bool(), ""); + BoolNode* bol = cmp->unique_out()->as_Bool(); + assert((bol->outcnt() == 1) && bol->unique_out()->is_If() && + (bol->_test._test == BoolTest::ne), ""); + IfNode* ifn = bol->unique_out()->as_If(); + assert((ifn->outcnt() == 2) && + ifn->proj_out(1)->is_uncommon_trap_proj(Deoptimization::Reason_rtm_state_change), ""); +#endif + Node* repl = n->in(1); + if (!_has_locks) { + // Remove RTM state check if there are no locks in the code. + // Replace input to compare the same value. + repl = (cmp->in(1) == n) ? cmp->in(2) : cmp->in(1); + } + _igvn.replace_node(n, repl); + success = true; +#endif } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success; diff --git a/hotspot/src/share/vm/opto/macro.hpp b/hotspot/src/share/vm/opto/macro.hpp index 5e2e97c7e3c..0efe988ab17 100644 --- a/hotspot/src/share/vm/opto/macro.hpp +++ b/hotspot/src/share/vm/opto/macro.hpp @@ -76,6 +76,8 @@ private: ProjNode *_memproj_catchall; ProjNode *_resproj; + // Additional data collected during macro expansion + bool _has_locks; void expand_allocate(AllocateNode *alloc); void expand_allocate_array(AllocateArrayNode *alloc); @@ -118,7 +120,7 @@ private: Node* length); public: - PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) { + PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) { _igvn.set_delay_transform(true); } void eliminate_macro_nodes(); diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index 092e40a7f64..aae634a9563 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -486,6 +486,8 @@ class Parse : public GraphKit { // Helper function to compute array addressing Node* array_addressing(BasicType type, int vals, const Type* *result2=NULL); + void rtm_deopt(); + // Pass current map to exits void return_current(Node* value); diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index db50f98492b..cae980512b1 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -567,6 +567,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Pars set_map(entry_map); do_method_entry(); } + if (depth() == 1) { + // Add check to deoptimize the nmethod if RTM state was changed + rtm_deopt(); + } // Check for bailouts during method entry. if (failing()) { @@ -2006,6 +2010,42 @@ void Parse::call_register_finalizer() { set_control( _gvn.transform(result_rgn) ); } +// Add check to deoptimize if RTM state is not ProfileRTM +void Parse::rtm_deopt() { +#if INCLUDE_RTM_OPT + if (C->profile_rtm()) { + assert(C->method() != NULL, "only for normal compilations"); + assert(!C->method()->method_data()->is_empty(), "MDO is needed to record RTM state"); + assert(depth() == 1, "generate check only for main compiled method"); + + // Set starting bci for uncommon trap. + set_parse_bci(is_osr_parse() ? osr_bci() : 0); + + // Load the rtm_state from the MethodData. + const TypePtr* adr_type = TypeMetadataPtr::make(C->method()->method_data()); + Node* mdo = makecon(adr_type); + int offset = MethodData::rtm_state_offset_in_bytes(); + Node* adr_node = basic_plus_adr(mdo, mdo, offset); + Node* rtm_state = make_load(control(), adr_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); + + // Separate Load from Cmp by Opaque. + // In expand_macro_nodes() it will be replaced either + // with this load when there are locks in the code + // or with ProfileRTM (cmp->in(2)) otherwise so that + // the check will fold. + Node* profile_state = makecon(TypeInt::make(ProfileRTM)); + Node* opq = _gvn.transform( new (C) Opaque3Node(C, rtm_state, Opaque3Node::RTM_OPT) ); + Node* chk = _gvn.transform( new (C) CmpINode(opq, profile_state) ); + Node* tst = _gvn.transform( new (C) BoolNode(chk, BoolTest::eq) ); + // Branch to failure if state was changed + { BuildCutout unless(this, tst, PROB_ALWAYS); + uncommon_trap(Deoptimization::Reason_rtm_state_change, + Deoptimization::Action_make_not_entrant); + } + } +#endif +} + //------------------------------return_current--------------------------------- // Append current _map to _exit_return void Parse::return_current(Node* value) { diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 4a18b0a2eae..e1b671ffd29 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -1310,6 +1310,14 @@ void OptoRuntime::print_named_counters() { tty->print_cr("%s", c->name()); blc->print_on(tty); } +#if INCLUDE_RTM_OPT + } else if (c->tag() == NamedCounter::RTMLockingCounter) { + RTMLockingCounters* rlc = ((RTMLockingNamedCounter*)c)->counters(); + if (rlc->nonzero()) { + tty->print_cr("%s", c->name()); + rlc->print_on(tty); + } +#endif } c = c->next(); } @@ -1349,6 +1357,8 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount NamedCounter* c; if (tag == NamedCounter::BiasedLockingCounter) { c = new BiasedLockingNamedCounter(strdup(st.as_string())); + } else if (tag == NamedCounter::RTMLockingCounter) { + c = new RTMLockingNamedCounter(strdup(st.as_string())); } else { c = new NamedCounter(strdup(st.as_string()), tag); } @@ -1357,6 +1367,7 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount // add counters so this is safe. NamedCounter* head; do { + c->set_next(NULL); head = _named_counters; c->set_next(head); } while (Atomic::cmpxchg_ptr(c, &_named_counters, head) != head); diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index aecb97f6572..9f2a26cecb7 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -29,6 +29,7 @@ #include "opto/machnode.hpp" #include "opto/type.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/rtmLocking.hpp" #include "runtime/deoptimization.hpp" #include "runtime/vframe.hpp" @@ -61,7 +62,8 @@ public: NoTag, LockCounter, EliminatedLockCounter, - BiasedLockingCounter + BiasedLockingCounter, + RTMLockingCounter }; private: @@ -85,7 +87,7 @@ private: NamedCounter* next() const { return _next; } void set_next(NamedCounter* next) { - assert(_next == NULL, "already set"); + assert(_next == NULL || next == NULL, "already set"); _next = next; } @@ -102,6 +104,18 @@ class BiasedLockingNamedCounter : public NamedCounter { BiasedLockingCounters* counters() { return &_counters; } }; + +class RTMLockingNamedCounter : public NamedCounter { + private: + RTMLockingCounters _counters; + + public: + RTMLockingNamedCounter(const char *n) : + NamedCounter(n, RTMLockingCounter), _counters() {} + + RTMLockingCounters* counters() { return &_counters; } +}; + typedef const TypeFunc*(*TypeFunc_generator)(); class OptoRuntime : public AllStatic { diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index d2591735770..4a7ad22b2c1 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -4380,7 +4380,7 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const { // else fall through: case TopPTR: case AnyNull: { - return make(ptr, NULL, offset); + return make(ptr, _metadata, offset); } case BotPTR: case NotNull: diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index d568a33334d..dfb8a07a1e1 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3782,9 +3782,6 @@ jint Arguments::apply_ergo() { #endif // CC_INTERP #ifdef COMPILER2 - if (!UseBiasedLocking || EmitSync != 0) { - UseOptoBiasInlining = false; - } if (!EliminateLocks) { EliminateNestedLocks = false; } @@ -3845,6 +3842,11 @@ jint Arguments::apply_ergo() { UseBiasedLocking = false; } } +#ifdef COMPILER2 + if (!UseBiasedLocking || EmitSync != 0) { + UseOptoBiasInlining = false; + } +#endif return JNI_OK; } diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index b1b078f6491..ea4f1f1220f 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1288,7 +1288,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra gather_statistics(reason, action, trap_bc); // Ensure that we can record deopt. history: - bool create_if_missing = ProfileTraps; + // Need MDO to record RTM code generation state. + bool create_if_missing = ProfileTraps RTM_OPT_ONLY( || UseRTMLocking ); MethodData* trap_mdo = get_method_data(thread, trap_method, create_if_missing); @@ -1569,6 +1570,17 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra if (tstate1 != tstate0) pdata->set_trap_state(tstate1); } + +#if INCLUDE_RTM_OPT + // Restart collecting RTM locking abort statistic if the method + // is recompiled for a reason other than RTM state change. + // Assume that in new recompiled code the statistic could be different, + // for example, due to different inlining. + if ((reason != Reason_rtm_state_change) && (trap_mdo != NULL) && + UseRTMDeopt && (nm->rtm_state() != ProfileRTM)) { + trap_mdo->atomic_set_rtm_state(ProfileRTM); + } +#endif } if (inc_recompile_count) { @@ -1826,7 +1838,8 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = { "age", "predicate", "loop_limit_check", - "speculate_class_check" + "speculate_class_check", + "rtm_state_change" }; const char* Deoptimization::_trap_action_name[Action_LIMIT] = { // Note: Keep this in sync. with enum DeoptAction. diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index f2233c9869b..f896a70341a 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -60,6 +60,7 @@ class Deoptimization : AllStatic { Reason_predicate, // compiler generated predicate failed Reason_loop_limit_check, // compiler generated loop limits check failed Reason_speculate_class_check, // saw unexpected object class from type speculation + Reason_rtm_state_change, // rtm state change detected Reason_LIMIT, // Note: Keep this enum in sync. with _trap_reason_name. Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 6c2d90daeaa..b467587c834 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -265,7 +265,7 @@ void print_statistics() { os::print_statistics(); } - if (PrintLockStatistics || PrintPreciseBiasedLockingStatistics) { + if (PrintLockStatistics || PrintPreciseBiasedLockingStatistics || PrintPreciseRTMLockingStatistics) { OptoRuntime::print_named_counters(); } @@ -387,7 +387,7 @@ void print_statistics() { } #ifdef COMPILER2 - if (PrintPreciseBiasedLockingStatistics) { + if (PrintPreciseBiasedLockingStatistics || PrintPreciseRTMLockingStatistics) { OptoRuntime::print_named_counters(); } #endif diff --git a/hotspot/src/share/vm/runtime/rtmLocking.hpp b/hotspot/src/share/vm/runtime/rtmLocking.hpp new file mode 100644 index 00000000000..b308b98bf31 --- /dev/null +++ b/hotspot/src/share/vm/runtime/rtmLocking.hpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014, 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_RUNTIME_RTMLOCKING_HPP +#define SHARE_VM_RUNTIME_RTMLOCKING_HPP + +// Generate RTM (Restricted Transactional Memory) locking code for all inflated +// locks when "UseRTMLocking" option is on with normal locking mechanism as fall back +// handler. +// +// On abort/lock busy the lock will be retried a fixed number of times under RTM +// as specified by "RTMRetryCount" option. The locks which abort too often +// can be auto tuned or manually tuned. +// +// Auto-tuning can be done on an option like UseRTMDeopt and it will need abort +// ratio calculation for each lock. The abort ratio will be calculated after +// "RTMAbortThreshold" number of aborts is reached. The formulas are: +// +// Aborted transactions = abort_count * 100 +// All transactions = total_count * RTMTotalCountIncrRate +// +// Aborted transactions >= All transactions * RTMAbortRatio +// +// If "UseRTMDeopt" is on and the aborts ratio reaches "RTMAbortRatio" +// the method containing the lock will be deoptimized and recompiled with +// all locks as normal locks. If the abort ratio continues to remain low after +// "RTMLockingThreshold" locks are attempted, then the method will be deoptimized +// and recompiled with all locks as RTM locks without abort ratio calculation code. +// The abort ratio calculation can be delayed by specifying flag +// -XX:RTMLockingCalculationDelay in millisecond. +// +// For manual tuning the abort statistics for each lock needs to be provided +// to the user on some JVM option like "PrintPreciseRTMLockingStatistics". +// Based on the abort statistics users can create a .hotspot_compiler file +// or use -XX:CompileCommand=option,class::method,NoRTMLockEliding +// to specify for which methods to disable RTM locking. +// +// When UseRTMForStackLocks option is enabled along with UseRTMLocking option, +// the RTM locking code is generated for stack locks too. +// The retries, auto-tuning support and rtm locking statistics are all +// supported for stack locks just like inflated locks. + +// RTM locking counters +class RTMLockingCounters VALUE_OBJ_CLASS_SPEC { + private: + uintx _total_count; // Total RTM locks count + uintx _abort_count; // Total aborts count + + public: + enum { ABORT_STATUS_LIMIT = 6 }; + // Counters per RTM Abort Status. Incremented with +PrintPreciseRTMLockingStatistics + // RTM uses the EAX register to communicate abort status to software. + // Following an RTM abort the EAX register has the following definition. + // + // EAX register bit position Meaning + // 0 Set if abort caused by XABORT instruction. + // 1 If set, the transaction may succeed on a retry. This bit is always clear if bit 0 is set. + // 2 Set if another logical processor conflicted with a memory address that was part of the transaction that aborted. + // 3 Set if an internal buffer overflowed. + // 4 Set if a debug breakpoint was hit. + // 5 Set if an abort occurred during execution of a nested transaction. + private: + uintx _abortX_count[ABORT_STATUS_LIMIT]; + + public: + static uintx _calculation_flag; + static uintx* rtm_calculation_flag_addr() { return &_calculation_flag; } + + static void init(); + + RTMLockingCounters() : _total_count(0), _abort_count(0) { + for (int i = 0; i < ABORT_STATUS_LIMIT; i++) { + _abortX_count[i] = 0; + } + } + + uintx* total_count_addr() { return &_total_count; } + uintx* abort_count_addr() { return &_abort_count; } + uintx* abortX_count_addr() { return &_abortX_count[0]; } + + static int total_count_offset() { return (int)offset_of(RTMLockingCounters, _total_count); } + static int abort_count_offset() { return (int)offset_of(RTMLockingCounters, _abort_count); } + static int abortX_count_offset() { return (int)offset_of(RTMLockingCounters, _abortX_count[0]); } + + + bool nonzero() { return (_abort_count + _total_count) > 0; } + + void print_on(outputStream* st); + void print() { print_on(tty); } +}; + +#endif // SHARE_VM_RUNTIME_RTMLOCKING_HPP diff --git a/hotspot/src/share/vm/runtime/task.cpp b/hotspot/src/share/vm/runtime/task.cpp index ef57dcd68cc..cc163d38963 100644 --- a/hotspot/src/share/vm/runtime/task.cpp +++ b/hotspot/src/share/vm/runtime/task.cpp @@ -105,7 +105,6 @@ PeriodicTask::PeriodicTask(size_t interval_time) : _counter(0), _interval((int) interval_time) { // Sanity check the interval time assert(_interval >= PeriodicTask::min_interval && - _interval <= PeriodicTask::max_interval && _interval % PeriodicTask::interval_gran == 0, "improper PeriodicTask interval time"); } diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index bd794da4524..2f93db88864 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -107,6 +107,9 @@ #include "opto/c2compiler.hpp" #include "opto/idealGraphPrinter.hpp" #endif +#if INCLUDE_RTM_OPT +#include "runtime/rtmLocking.hpp" +#endif #ifdef DTRACE_ENABLED @@ -3622,6 +3625,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { BiasedLocking::init(); +#if INCLUDE_RTM_OPT + RTMLockingCounters::init(); +#endif + if (JDK_Version::current().post_vm_init_hook_enabled()) { call_postVMInitHook(THREAD); // The Java side of PostVMInitHook.run must deal with all diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index e56d4b0d59e..df2a8a30253 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -373,6 +373,21 @@ const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlass // Machine dependent stuff +#if defined(X86) && defined(COMPILER2) && !defined(JAVASE_EMBEDDED) +// Include Restricted Transactional Memory lock eliding optimization +#define INCLUDE_RTM_OPT 1 +#define RTM_OPT_ONLY(code) code +#else +#define INCLUDE_RTM_OPT 0 +#define RTM_OPT_ONLY(code) +#endif +// States of Restricted Transactional Memory usage. +enum RTMState { + NoRTM = 0x2, // Don't use RTM + UseRTM = 0x1, // Use RTM + ProfileRTM = 0x0 // Use RTM with abort ratio calculation +}; + #ifdef TARGET_ARCH_x86 # include "globalDefinitions_x86.hpp" #endif From fc7f4197f1b391bed8eabbe57c6358ac83fc4806 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Mar 2014 11:03:06 +0100 Subject: [PATCH 057/170] 8037915: PPC64/AIX: Several smaller fixes Reviewed-by: kvn --- hotspot/src/cpu/ppc/vm/assembler_ppc.cpp | 17 ++++++----- .../src/cpu/ppc/vm/assembler_ppc.inline.hpp | 26 +++++++++++------ hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp | 4 +-- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 29 ++++++++++--------- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 4 +-- hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp | 17 ++++++++++- hotspot/src/cpu/ppc/vm/ppc.ad | 4 +-- .../src/cpu/ppc/vm/stubRoutines_ppc_64.cpp | 13 +-------- hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 24 +++++++++------ hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp | 5 +++- hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp | 10 +++---- hotspot/src/os/aix/vm/mutex_aix.inline.hpp | 4 +-- hotspot/src/os/aix/vm/os_aix.cpp | 4 +-- hotspot/src/os/aix/vm/threadCritical_aix.cpp | 4 +-- hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp | 4 +-- .../os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp | 8 ++--- .../src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp | 6 ++-- .../os_cpu/linux_ppc/vm/thread_linux_ppc.cpp | 6 ++-- 18 files changed, 105 insertions(+), 84 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp index 76a1cac53f3..f9e49e1f4a8 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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,7 +24,6 @@ */ #include "precompiled.hpp" -#include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" @@ -37,6 +36,7 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "utilities/macros.hpp" #if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" @@ -384,10 +384,10 @@ int Assembler::load_const_optimized(Register d, long x, Register tmp, bool retur bool load_xa = (xa != 0) || (xb < 0); bool return_xd = false; - if (load_xa) lis(tmp, xa); - if (xc) lis(d, xc); + if (load_xa) { lis(tmp, xa); } + if (xc) { lis(d, xc); } if (load_xa) { - if (xb) ori(tmp, tmp, xb); // No addi, we support tmp == R0. + if (xb) { ori(tmp, tmp, (unsigned short)xb); } // No addi, we support tmp == R0. } else { li(tmp, xb); // non-negative } @@ -409,18 +409,18 @@ int Assembler::load_const_optimized(Register d, long x, Register tmp, bool retur // opt 4: avoid adding 0 if (xa) { // Highest 16-bit needed? lis(d, xa); - if (xb) addi(d, d, xb); + if (xb) { addi(d, d, xb); } } else { li(d, xb); } sldi(d, d, 32); - if (xc) addis(d, d, xc); + if (xc) { addis(d, d, xc); } } // opt 5: Return offset to be inserted into following instruction. if (return_simm16_rest) return xd; - if (xd) addi(d, d, xd); + if (xd) { addi(d, d, xd); } return 0; } @@ -696,4 +696,5 @@ void Assembler::test_asm() { tty->print_cr("\ntest_asm disassembly (0x%lx 0x%lx):", code()->insts_begin(), code()->insts_end()); code()->decode(); } + #endif // !PRODUCT diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index d96d9204dbc..3b7eb5f55e5 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -139,7 +139,8 @@ inline void Assembler::cmpldi(ConditionRegister crx, Register a, int ui16) { A inline void Assembler::cmplw( ConditionRegister crx, Register a, Register b) { Assembler::cmpl( crx, 0, a, b); } inline void Assembler::cmpld( ConditionRegister crx, Register a, Register b) { Assembler::cmpl( crx, 1, a, b); } -inline void Assembler::isel(Register d, Register a, Register b, int c) { emit_int32(ISEL_OPCODE | rt(d) | ra(a) | rb(b) | bc(c)); } +inline void Assembler::isel(Register d, Register a, Register b, int c) { guarantee(VM_Version::has_isel(), "opcode not supported on this hardware"); + emit_int32(ISEL_OPCODE | rt(d) | ra(a) | rb(b) | bc(c)); } // PPC 1, section 3.3.11, Fixed-Point Logical Instructions inline void Assembler::andi_( Register a, Register s, int ui16) { emit_int32(ANDI_OPCODE | rta(a) | rs(s) | uimm(ui16, 16)); } @@ -531,9 +532,12 @@ inline void Assembler::fmr_(FloatRegister d, FloatRegister b) { emit_int32( FMR_ //inline void Assembler::mffgpr( FloatRegister d, Register b) { emit_int32( MFFGPR_OPCODE | frt(d) | rb(b) | rc(0)); } //inline void Assembler::mftgpr( Register d, FloatRegister b) { emit_int32( MFTGPR_OPCODE | rt(d) | frb(b) | rc(0)); } // add cmpb and popcntb to detect ppc power version. -inline void Assembler::cmpb( Register a, Register s, Register b) { emit_int32( CMPB_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } -inline void Assembler::popcntb(Register a, Register s) { emit_int32( POPCNTB_OPCODE | rta(a) | rs(s)); }; -inline void Assembler::popcntw(Register a, Register s) { emit_int32( POPCNTW_OPCODE | rta(a) | rs(s)); }; +inline void Assembler::cmpb( Register a, Register s, Register b) { guarantee(VM_Version::has_cmpb(), "opcode not supported on this hardware"); + emit_int32( CMPB_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } +inline void Assembler::popcntb(Register a, Register s) { guarantee(VM_Version::has_popcntb(), "opcode not supported on this hardware"); + emit_int32( POPCNTB_OPCODE | rta(a) | rs(s)); }; +inline void Assembler::popcntw(Register a, Register s) { guarantee(VM_Version::has_popcntw(), "opcode not supported on this hardware"); + emit_int32( POPCNTW_OPCODE | rta(a) | rs(s)); }; inline void Assembler::popcntd(Register a, Register s) { emit_int32( POPCNTD_OPCODE | rta(a) | rs(s)); }; inline void Assembler::fneg( FloatRegister d, FloatRegister b) { emit_int32( FNEG_OPCODE | frt(d) | frb(b) | rc(0)); } @@ -568,14 +572,17 @@ inline void Assembler::fctidz(FloatRegister d, FloatRegister b) { emit_int32( FC inline void Assembler::fctiw( FloatRegister d, FloatRegister b) { emit_int32( FCTIW_OPCODE | frt(d) | frb(b) | rc(0)); } inline void Assembler::fctiwz(FloatRegister d, FloatRegister b) { emit_int32( FCTIWZ_OPCODE | frt(d) | frb(b) | rc(0)); } inline void Assembler::fcfid( FloatRegister d, FloatRegister b) { emit_int32( FCFID_OPCODE | frt(d) | frb(b) | rc(0)); } -inline void Assembler::fcfids(FloatRegister d, FloatRegister b) { emit_int32( FCFIDS_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fcfids(FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fcfids(), "opcode not supported on this hardware"); + emit_int32( FCFIDS_OPCODE | frt(d) | frb(b) | rc(0)); } // PPC 1, section 4.6.7 Floating-Point Compare Instructions inline void Assembler::fcmpu( ConditionRegister crx, FloatRegister a, FloatRegister b) { emit_int32( FCMPU_OPCODE | bf(crx) | fra(a) | frb(b)); } // PPC 1, section 5.2.1 Floating-Point Arithmetic Instructions -inline void Assembler::fsqrt( FloatRegister d, FloatRegister b) { emit_int32( FSQRT_OPCODE | frt(d) | frb(b) | rc(0)); } -inline void Assembler::fsqrts(FloatRegister d, FloatRegister b) { emit_int32( FSQRTS_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fsqrt( FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fsqrt(), "opcode not supported on this hardware"); + emit_int32( FSQRT_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fsqrts(FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fsqrts(), "opcode not supported on this hardware"); + emit_int32( FSQRTS_OPCODE | frt(d) | frb(b) | rc(0)); } // Vector instructions for >= Power6. inline void Assembler::lvebx( VectorRegister d, Register s1, Register s2) { emit_int32( LVEBX_OPCODE | vrt(d) | ra0mem(s1) | rb(s2)); } @@ -703,7 +710,8 @@ inline void Assembler::vcmpgtsw_(VectorRegister d,VectorRegister a, VectorRegist inline void Assembler::vcmpgtub_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUB_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } inline void Assembler::vcmpgtuh_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUH_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } inline void Assembler::vcmpgtuw_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUW_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } -inline void Assembler::vand( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VAND_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vand( VectorRegister d, VectorRegister a, VectorRegister b) { guarantee(VM_Version::has_vand(), "opcode not supported on this hardware"); + emit_int32( VAND_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vandc( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VANDC_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vnor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VNOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index 03e5a5d0b55..58e4f3887cb 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -87,7 +87,7 @@ define_pd_global(uint64_t,MaxRAM, 4ULL*G); define_pd_global(uintx, CodeCacheMinBlockLength, 4); define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); -define_pd_global(bool, TrapBasedRangeChecks, false); +define_pd_global(bool, TrapBasedRangeChecks, true); // Heap related flags define_pd_global(uintx,MetaspaceSize, ScaleForWordSize(16*M)); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 2d3d9cf9713..8f026ac0d0c 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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,8 +24,6 @@ */ #include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" #include "compiler/disassembler.hpp" #include "gc_interface/collectedHeap.inline.hpp" @@ -1120,7 +1118,7 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd, } return _last_calls_return_pc; } -#endif +#endif // ABI_ELFv2 void MacroAssembler::call_VM_base(Register oop_result, Register last_java_sp, @@ -1794,7 +1792,7 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj cmpwi(cr_reg, temp_reg, markOopDesc::biased_lock_pattern); bne(cr_reg, cas_label); - load_klass_with_trap_null_check(temp_reg, obj_reg); + load_klass(temp_reg, obj_reg); load_const_optimized(temp2_reg, ~((int) markOopDesc::age_mask_in_place)); ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg); @@ -1891,7 +1889,7 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // the bias from one thread to another directly in this situation. andi(temp_reg, mark_reg, markOopDesc::age_mask_in_place); orr(temp_reg, R16_thread, temp_reg); - load_klass_with_trap_null_check(temp2_reg, obj_reg); + load_klass(temp2_reg, obj_reg); ld(temp2_reg, in_bytes(Klass::prototype_header_offset()), temp2_reg); orr(temp_reg, temp_reg, temp2_reg); @@ -1927,7 +1925,7 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // that another thread raced us for the privilege of revoking the // bias of this particular object, so it's okay to continue in the // normal locking code. - load_klass_with_trap_null_check(temp_reg, obj_reg); + load_klass(temp_reg, obj_reg); ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg); andi(temp2_reg, mark_reg, markOopDesc::age_mask_in_place); orr(temp_reg, temp_reg, temp2_reg); @@ -2213,8 +2211,7 @@ void MacroAssembler::card_table_write(jbyte* byte_map_base, Register Rtmp, Regis stbx(R0, Rtmp, Robj); } -#ifndef SERIALGC - +#if INCLUDE_ALL_GCS // General G1 pre-barrier generator. // Goal: record the previous value if it is not null. void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val, @@ -2328,14 +2325,17 @@ void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_v // Get the address of the card. lbzx(/*card value*/ Rtmp3, Rbase, Rcard_addr); + cmpwi(CCR0, Rtmp3, (int)G1SATBCardTableModRefBS::g1_young_card_val()); + beq(CCR0, filtered); - assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code"); - cmpwi(CCR0, Rtmp3 /* card value */, 0); + membar(Assembler::StoreLoad); + lbzx(/*card value*/ Rtmp3, Rbase, Rcard_addr); // Reload after membar. + cmpwi(CCR0, Rtmp3 /* card value */, CardTableModRefBS::dirty_card_val()); beq(CCR0, filtered); // Storing a region crossing, non-NULL oop, card is clean. // Dirty card and log. - li(Rtmp3, 0); // dirty + li(Rtmp3, CardTableModRefBS::dirty_card_val()); //release(); // G1: oops are allowed to get visible after dirty marking. stbx(Rtmp3, Rbase, Rcard_addr); @@ -2362,7 +2362,7 @@ void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_v bind(filtered_int); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Values for last_Java_pc, and last_Java_sp must comply to the rules // in frame_ppc64.hpp. @@ -2453,7 +2453,8 @@ void MacroAssembler::get_vm_result_2(Register metadata_result) { void MacroAssembler::encode_klass_not_null(Register dst, Register src) { Register current = (src != noreg) ? src : dst; // Klass is in dst if no src provided. if (Universe::narrow_klass_base() != 0) { - load_const(R0, Universe::narrow_klass_base(), (dst != current) ? dst : noreg); // Use dst as temp if it is free. + // Use dst as temp if it is free. + load_const(R0, Universe::narrow_klass_base(), (dst != current && dst != R0) ? dst : noreg); sub(dst, current, R0); current = dst; } diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index a6576a4c472..5bbea5ada2a 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -514,14 +514,14 @@ class MacroAssembler: public Assembler { void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp); void card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // General G1 pre-barrier generator. void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val, Register Rtmp1, Register Rtmp2, bool needs_frame = false); // General G1 post-barrier generator void g1_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp1, Register Rtmp2, Register Rtmp3, Label *filtered_ext = NULL); -#endif // SERIALGC +#endif // Support for managing the JavaThread pointer (i.e.; the reference to // thread-local information). diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index 26363754b09..4383d61f7fd 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -119,6 +119,7 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { + Label L_no_such_method; assert(method == R19_method, "interpreter calling convention"); assert_different_registers(method, target, temp); @@ -131,17 +132,31 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ lwz(temp, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); __ cmplwi(CCR0, temp, 0); __ beq(CCR0, run_compiled_code); + // Null method test is replicated below in compiled case, + // it might be able to address across the verify_thread() + __ cmplwi(CCR0, R19_method, 0); + __ beq(CCR0, L_no_such_method); __ ld(target, in_bytes(Method::interpreter_entry_offset()), R19_method); __ mtctr(target); __ bctr(); __ BIND(run_compiled_code); } + // Compiled case, either static or fall-through from runtime conditional + __ cmplwi(CCR0, R19_method, 0); + __ beq(CCR0, L_no_such_method); + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ ld(target, in_bytes(entry_offset), R19_method); __ mtctr(target); __ bctr(); + + __ bind(L_no_such_method); + assert(StubRoutines::throw_AbstractMethodError_entry() != NULL, "not yet generated!"); + __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + __ mtctr(target); + __ bctr(); } diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index c2854e68e16..9c3f40a6303 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -8755,6 +8755,7 @@ instruct sqrtD_reg(regD dst, regD src) %{ // Single-precision sqrt. instruct sqrtF_reg(regF dst, regF src) %{ match(Set dst (ConvD2F (SqrtD (ConvF2D src)))); + predicate(VM_Version::has_fsqrts()); ins_cost(DEFAULT_COST); format %{ "FSQRTS $dst, $src" %} @@ -11550,8 +11551,7 @@ instruct safePoint_poll_conPollAddr(rscratch2RegP poll) %{ // effect no longer needs to be mentioned, since r0 is not contained // in a reg_class. - format %{ "LD R12, addr of polling page\n\t" - "LD R0, #0, R12 \t// Safepoint poll for GC" %} + format %{ "LD R0, #0, R12 \t// Safepoint poll for GC" %} ins_encode( enc_poll(0x0, poll) ); ins_pipe(pipe_class_default); %} diff --git a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp index 47735a8b1ba..0c1b93b6ba3 100644 --- a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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,17 +23,6 @@ * */ -#include "precompiled.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/stubRoutines.hpp" -#ifdef TARGET_OS_FAMILY_aix -# include "thread_aix.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_linux -# include "thread_linux.inline.hpp" -#endif - // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file. diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 567a5d0d3f6..0a6261a21e8 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -402,6 +402,9 @@ void VM_Version::determine_features() { CodeBuffer cb("detect_cpu_features", code_size, 0); MacroAssembler* a = new MacroAssembler(&cb); + // Must be set to true so we can generate the test code. + _features = VM_Version::all_features_m; + // Emit code. void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry(); uint32_t *code = (uint32_t *)a->pc(); @@ -409,14 +412,15 @@ void VM_Version::determine_features() { // Keep R3_ARG1 unmodified, it contains &field (see below). // Keep R4_ARG2 unmodified, it contains offset = 0 (see below). a->fsqrt(F3, F4); // code[0] -> fsqrt_m - a->isel(R7, R5, R6, 0); // code[1] -> isel_m - a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[2] -> lxarx_m - a->cmpb(R7, R5, R6); // code[3] -> bcmp - //a->mftgpr(R7, F3); // code[4] -> mftgpr - a->popcntb(R7, R5); // code[5] -> popcntb - a->popcntw(R7, R5); // code[6] -> popcntw - a->fcfids(F3, F4); // code[7] -> fcfids - a->vand(VR0, VR0, VR0); // code[8] -> vand + a->fsqrts(F3, F4); // code[1] -> fsqrts_m + a->isel(R7, R5, R6, 0); // code[2] -> isel_m + a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[3] -> lxarx_m + a->cmpb(R7, R5, R6); // code[4] -> bcmp + //a->mftgpr(R7, F3); // code[5] -> mftgpr + a->popcntb(R7, R5); // code[6] -> popcntb + a->popcntw(R7, R5); // code[7] -> popcntw + a->fcfids(F3, F4); // code[8] -> fcfids + a->vand(VR0, VR0, VR0); // code[9] -> vand a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -426,6 +430,7 @@ void VM_Version::determine_features() { uint32_t *code_end = (uint32_t *)a->pc(); a->flush(); + _features = VM_Version::unknown_m; // Print the detection code. if (PrintAssembly) { @@ -450,6 +455,7 @@ void VM_Version::determine_features() { // determine which instructions are legal. int feature_cntr = 0; if (code[feature_cntr++]) features |= fsqrt_m; + if (code[feature_cntr++]) features |= fsqrts_m; if (code[feature_cntr++]) features |= isel_m; if (code[feature_cntr++]) features |= lxarxeh_m; if (code[feature_cntr++]) features |= cmpb_m; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 59553a6bb0e..2bbfdddb21f 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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,6 +33,7 @@ class VM_Version: public Abstract_VM_Version { protected: enum Feature_Flag { fsqrt, + fsqrts, isel, lxarxeh, cmpb, @@ -46,6 +47,7 @@ protected: enum Feature_Flag_Set { unknown_m = 0, fsqrt_m = (1 << fsqrt ), + fsqrts_m = (1 << fsqrts ), isel_m = (1 << isel ), lxarxeh_m = (1 << lxarxeh), cmpb_m = (1 << cmpb ), @@ -72,6 +74,7 @@ public: static bool is_determine_features_test_running() { return _is_determine_features_test_running; } // CPU instruction support static bool has_fsqrt() { return (_features & fsqrt_m) != 0; } + static bool has_fsqrts() { return (_features & fsqrts_m) != 0; } static bool has_isel() { return (_features & isel_m) != 0; } static bool has_lxarxeh() { return (_features & lxarxeh_m) !=0; } static bool has_cmpb() { return (_features & cmpb_m) != 0; } diff --git a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp index c9e5f5eccac..5931afd5c32 100644 --- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -79,7 +79,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3); - // Set methodOop (in case of interpreted method), and destination address. + // Set method (in case of interpreted method), and destination address. int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); #ifndef PRODUCT @@ -161,8 +161,6 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); - //__ ld(rcvr_klass, oopDesc::klass_offset_in_bytes(), R3_ARG1); - BLOCK_COMMENT("Load start of itable entries into itable_entry."); __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass); __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size() * wordSize)); @@ -199,7 +197,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { itable_offset_search_inc; __ lwz(vtable_offset, vtable_offset_offset, itable_entry_addr); - // Compute itableMethodEntry and get methodOop and entry point for compiler. + // Compute itableMethodEntry and get method and entry point for compiler. const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes(); @@ -211,7 +209,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { Label ok; __ cmpd(CCR0, R19_method, 0); __ bne(CCR0, ok); - __ stop("methodOop is null", 103); + __ stop("method is null", 103); __ bind(ok); } #endif diff --git a/hotspot/src/os/aix/vm/mutex_aix.inline.hpp b/hotspot/src/os/aix/vm/mutex_aix.inline.hpp index 479032f7297..82ae899e14d 100644 --- a/hotspot/src/os/aix/vm/mutex_aix.inline.hpp +++ b/hotspot/src/os/aix/vm/mutex_aix.inline.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -28,6 +28,6 @@ #include "os_aix.inline.hpp" #include "runtime/interfaceSupport.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.inline.hpp" #endif // OS_AIX_VM_MUTEX_AIX_INLINE_HPP diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 33385e7a09a..81de8d0f56c 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -61,10 +61,10 @@ #include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/threadCritical.hpp" +#include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" #include "services/runtimeService.hpp" -#include "thread_aix.inline.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" diff --git a/hotspot/src/os/aix/vm/threadCritical_aix.cpp b/hotspot/src/os/aix/vm/threadCritical_aix.cpp index a7cc96fce35..f2d651ff7e8 100644 --- a/hotspot/src/os/aix/vm/threadCritical_aix.cpp +++ b/hotspot/src/os/aix/vm/threadCritical_aix.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "runtime/threadCritical.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.inline.hpp" // put OS-includes here # include 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 f2bbfb34b9e..8573cf33e73 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,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -49,8 +49,8 @@ #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/thread.inline.hpp" #include "runtime/timer.hpp" -#include "thread_aix.inline.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" #ifdef COMPILER1 diff --git a/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp index fa7ebf72bc4..69d2f1dd5ca 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/threadLS_aix_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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 @@ -25,14 +25,14 @@ #include "precompiled.hpp" #include "runtime/threadLocalStorage.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/thread.hpp" void ThreadLocalStorage::generate_code_for_get_thread() { - // nothing we can do here for user-level thread + // Nothing we can do here for user-level thread. } void ThreadLocalStorage::pd_init() { - // Nothing to do + // Nothing to do. } void ThreadLocalStorage::pd_set_thread(Thread* thread) { diff --git a/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp index 6e8572490ca..96a09b2787f 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/frame.inline.hpp" -#include "thread_aix.inline.hpp" +#include "runtime/frame.hpp" +#include "runtime/thread.hpp" // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Aix/PPC. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { diff --git a/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp b/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp index 77bfacd390c..92661222b07 100644 --- a/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp +++ b/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright 2012, 2014 SAP AG. 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,8 +24,8 @@ */ #include "precompiled.hpp" -#include "runtime/frame.inline.hpp" -#include "thread_linux.inline.hpp" +#include "runtime/frame.hpp" +#include "runtime/thread.hpp" // Forte Analyzer AsyncGetCallTrace profiling support is not implemented on Linux/PPC. bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava) { From 908ea8bebdf0bf76fb367b49c1c65399808eb54f Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 20 Mar 2014 15:13:26 +0400 Subject: [PATCH 058/170] 7118295: javac does not explicitly close -Xstdout file Reviewed-by: ksrini, jjg --- .../com/sun/tools/javac/main/Main.java | 7 +- .../com/sun/tools/javac/main/Option.java | 1 - .../test/tools/javac/StdoutCloseTest.java | 90 +++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 langtools/test/tools/javac/StdoutCloseTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java index 669c897627b..2c7f2f55939 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, 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 @@ -506,6 +506,11 @@ public class Main { } } + if (options.get(XSTDOUT) != null) { + // Stdout reassigned - ask compiler to close it when it is done + comp.closeables = comp.closeables.prepend(log.getWriter(WriterKind.NOTICE)); + } + fileManager = context.get(JavaFileManager.class); if (!files.isEmpty()) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java index 6ecf168d894..8821970f904 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java @@ -399,7 +399,6 @@ public enum Option { public boolean process(OptionHelper helper, String option, String arg) { try { Log log = helper.getLog(); - // TODO: this file should be closed at the end of compilation log.setWriters(new PrintWriter(new FileWriter(arg), true)); } catch (java.io.IOException e) { helper.error("err.error.writing.file", arg, e); diff --git a/langtools/test/tools/javac/StdoutCloseTest.java b/langtools/test/tools/javac/StdoutCloseTest.java new file mode 100644 index 00000000000..f6cb8b86a4f --- /dev/null +++ b/langtools/test/tools/javac/StdoutCloseTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, 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 7118295 + * @summary javac does not explicitly close -Xstdout file + * @run main StdoutCloseTest + */ + + +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.main.Main; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +public class StdoutCloseTest { + + public static void main(String[] args) throws Exception { + new StdoutCloseTest().test(); + } + + static final String program = "public class Test {\n" + + " public boolean test() {\n" + + " int i;\n" + + " if (i > 0) return true;\n" + + " return false;\n" + + " }\n" + + "}\n"; + + public void test() throws Exception { + final String sourceName = "Test.java"; + final String outName = "Test.out"; + File source = new File(sourceName); + PrintWriter pw = new PrintWriter(source); + pw.write(program); + pw.flush(); + pw.close(); + + PrintWriter log = compileClass(sourceName, outName); + + File outFile = new File(outName); + if (!outFile.exists()) { + throw new Exception("Output file was not created!"); + } + if (!log.checkError()) { // will return true if the stream is still open + log.close(); // Close output PrintWriter manually + throw new Exception("Output file was still open!"); + } + } + + public PrintWriter compileClass(String src, String out) { + List options = new ArrayList<>(); + options.add("-Xstdout"); + options.add(out); + options.add(src); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Main compiler = new Main("javac", pw); + compiler.compile(options.toArray(new String[options.size()])); + pw.flush(); + if (sw.getBuffer().length() > 0) { + System.err.println(sw.toString()); + } + return compiler.log.getWriter(Log.WriterKind.NOTICE); + } +} From 15e6b91ca55c34cccbe07716f8bb4772f548ff2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Thu, 20 Mar 2014 14:28:25 +0100 Subject: [PATCH 059/170] 8037340: Linux semaphores to use CLOCK_REALTIME Reviewed-by: dholmes, sla --- hotspot/src/os/linux/vm/os_linux.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index dc46fdd8888..77dfc54bd7b 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -109,6 +109,8 @@ #define MAX_PATH (2 * K) +#define MAX_SECS 100000000 + // for timer info max values which include all bits #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) @@ -2434,7 +2436,6 @@ class Semaphore : public StackObj { sem_t _semaphore; }; - Semaphore::Semaphore() { sem_init(&_semaphore, 0, 0); } @@ -2456,8 +2457,22 @@ bool Semaphore::trywait() { } bool Semaphore::timedwait(unsigned int sec, int nsec) { + struct timespec ts; - unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec); + // Semaphore's are always associated with CLOCK_REALTIME + os::Linux::clock_gettime(CLOCK_REALTIME, &ts); + // see unpackTime for discussion on overflow checking + if (sec >= MAX_SECS) { + ts.tv_sec += MAX_SECS; + ts.tv_nsec = 0; + } else { + ts.tv_sec += sec; + ts.tv_nsec += nsec; + if (ts.tv_nsec >= NANOSECS_PER_SEC) { + ts.tv_nsec -= NANOSECS_PER_SEC; + ++ts.tv_sec; // note: this must be <= max_secs + } + } while (1) { int result = sem_timedwait(&_semaphore, &ts); @@ -5661,7 +5676,6 @@ void os::PlatformEvent::unpark() { * is no need to track notifications. */ -#define MAX_SECS 100000000 /* * This code is common to linux and solaris and will be moved to a * common place in dolphin. From e3ebae0947a835c0fde6589f4d141ceb894c86d7 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Mar 2014 15:53:17 +0100 Subject: [PATCH 060/170] 8037962: metaspaceTracer.cpp misses a symbol Reviewed-by: tschatzl, mgerdin --- hotspot/src/share/vm/memory/metaspaceTracer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/share/vm/memory/metaspaceTracer.cpp b/hotspot/src/share/vm/memory/metaspaceTracer.cpp index bd4960aab3e..2a5cc2825de 100644 --- a/hotspot/src/share/vm/memory/metaspaceTracer.cpp +++ b/hotspot/src/share/vm/memory/metaspaceTracer.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" #include "memory/metaspaceTracer.hpp" +#include "oops/oop.inline.hpp" #include "trace/tracing.hpp" #include "trace/traceBackend.hpp" From e71ffe9834f0997f2b39e4ff91bc61e3741576ca Mon Sep 17 00:00:00 2001 From: Mark Sheppard Date: Thu, 20 Mar 2014 15:05:58 +0000 Subject: [PATCH 061/170] 8033075: Broken Links In CORBA API docs Fix broken URLs change cgi.omg.org to www.omg.org Reviewed-by: alanb --- .../share/classes/org/omg/CORBA/AnySeqHelper.java | 4 ++-- .../classes/org/omg/CORBA/BooleanSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/CharSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/DoubleSeqHelper.java | 4 ++-- .../classes/org/omg/CORBA/LongLongSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/LongSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/OctetSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/ShortSeqHelper.java | 4 ++-- .../classes/org/omg/CORBA/StringValueHelper.java | 4 ++-- .../classes/org/omg/CORBA/ULongLongSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/ULongSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/UShortSeqHelper.java | 4 ++-- .../share/classes/org/omg/CORBA/WCharSeqHelper.java | 4 ++-- .../classes/org/omg/CORBA/WStringValueHelper.java | 4 ++-- .../classes/org/omg/CORBA/doc-files/compliance.html | 12 ++++++------ .../org/omg/CORBA/doc-files/generatedfiles.html | 2 +- corba/src/share/classes/org/omg/CORBA/package.html | 2 +- .../src/share/classes/org/omg/CosNaming/package.html | 2 +- corba/src/share/classes/org/omg/Dynamic/package.html | 4 ++-- .../omg/DynamicAny/DynAnyFactoryPackage/package.html | 4 ++-- .../org/omg/DynamicAny/DynAnyPackage/package.html | 4 ++-- corba/src/share/classes/org/omg/IOP/package.html | 4 ++-- .../src/share/classes/org/omg/Messaging/package.html | 4 ++-- .../ORBInitInfoPackage/package.html | 4 ++-- 24 files changed, 49 insertions(+), 49 deletions(-) diff --git a/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java b/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java index 03164504ed9..e01c8110ef4 100644 --- a/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/AnySeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java index 2ebf7327b64..661de0a1255 100644 --- a/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/BooleanSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java index b3bd4ae0869..15bdec03432 100644 --- a/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/CharSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java index 7a967349ec5..307f1254b5c 100644 --- a/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/DoubleSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java index f30c37f2d9f..cad08837d5c 100644 --- a/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/LongLongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java index 5f7e678bac2..eae18b59c1a 100644 --- a/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/LongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java index b056758a5d5..a937e471615 100644 --- a/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/OctetSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java index 2055428deec..bc63630caff 100644 --- a/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/ShortSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java b/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java index 1e88c7f1f34..013c16a1290 100644 --- a/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/StringValueHelper.java @@ -44,11 +44,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java index fb945bf817f..4267d13108c 100644 --- a/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/ULongLongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java index 8681802119b..001fd4a3157 100644 --- a/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/ULongSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java index 70b3c793f54..0c09a1fdb73 100644 --- a/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/UShortSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java b/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java index 7a055d08e20..ef26bf66373 100644 --- a/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/WCharSeqHelper.java @@ -38,11 +38,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java b/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java index 94b7e94f412..a535caed09b 100644 --- a/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java +++ b/corba/src/share/classes/org/omg/CORBA/WStringValueHelper.java @@ -48,11 +48,11 @@ package org.omg.CORBA; * OMG specifications : * */ diff --git a/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html b/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html index 5201175d4d7..ff57fbd24be 100644 --- a/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html +++ b/corba/src/share/classes/org/omg/CORBA/doc-files/compliance.html @@ -18,26 +18,26 @@ href="http://www.omg.org/">www.omg.org to search for the correct specificati
  • CORBA 2.3.1 (formal/99-10-07)
  • +href="http://www.omg.org/cgi-bin/doc?formal/99-10-07">formal/99-10-07)
  • IDL to Java language mapping (ptc/00-01-08)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-01-08">ptc/00-01-08)
  • Revised IDL to Java language mapping (ptc/00-11-03)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-11-03">ptc/00-11-03)
  • Java to IDL language mapping (ptc/00-01-06)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-01-06">ptc/00-01-06)
  • Interoperable Naming Service (ptc/00-08-07)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/00-08-07">ptc/00-08-07)
  • Portable Interceptors (ptc/2001-03-04)
  • +href="http://www.omg.org/cgi-bin/doc?ptc/2001-03-04">ptc/2001-03-04)
These are the only specifications referenced by this document. diff --git a/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html b/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html index 53f28a1737f..d63460d0871 100644 --- a/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html +++ b/corba/src/share/classes/org/omg/CORBA/doc-files/generatedfiles.html @@ -8,7 +8,7 @@

IDL-to-Java Generated Files

-

The files that are generated by the IDL-to-Java compiler, in accordance with the IDL-to-Java Language Mapping Specification, which is implemented in JavaTM SE 6 according the compliance document. +

The files that are generated by the IDL-to-Java compiler, in accordance with the IDL-to-Java Language Mapping Specification, which is implemented in JavaTM SE 6 according the compliance document.

In general IDL names and identifiers are mapped to Java names and identifiers with no change. Because of the nature of the Java language, a single IDL construct may be mapped to several (differently named) Java constructs. The additional names are constructed by appending a descriptive suffix. For example, the IDL interface foo is mapped to the Java interfaces foo and fooOperations, and additional Java classes fooHelper, fooHolder, fooPOA, and optionally fooPOATie. diff --git a/corba/src/share/classes/org/omg/CORBA/package.html b/corba/src/share/classes/org/omg/CORBA/package.html index 02c6d0b1876..437b84870a4 100644 --- a/corba/src/share/classes/org/omg/CORBA/package.html +++ b/corba/src/share/classes/org/omg/CORBA/package.html @@ -344,7 +344,7 @@ public final class AccountHolder implements

For more information on Holder classes, see Chapter 1.4, Mapping for -Basic Types in the +Basic Types in the OMG IDL to Java Language Mapping. The Holder classes defined in the package org.omg.CORBA are:

diff --git a/corba/src/share/classes/org/omg/CosNaming/package.html b/corba/src/share/classes/org/omg/CosNaming/package.html
index e64de1740d6..a7fca8f22aa 100644
--- a/corba/src/share/classes/org/omg/CosNaming/package.html
+++ b/corba/src/share/classes/org/omg/CosNaming/package.html
@@ -331,7 +331,7 @@ Context.
 
 
  • Interoperable Naming Service (ptc/00-08-07) +href="http://www.omg.org/cgi-bin/doc?ptc/00-08-07">ptc/00-08-07)

Related Documentation

diff --git a/corba/src/share/classes/org/omg/Dynamic/package.html b/corba/src/share/classes/org/omg/Dynamic/package.html index f7b27322eb3..0a9895fc871 100644 --- a/corba/src/share/classes/org/omg/Dynamic/package.html +++ b/corba/src/share/classes/org/omg/Dynamic/package.html @@ -33,8 +33,8 @@

This package contains the Dynamic module specified in the OMG Portable Interceptor specification, - -http://cgi.omg.org/cgi-bin/doc?ptc/2000-08-06, section 21.9. Please + +ptc/2000-08-06, section 21.9. Please refer to that OMG specification for further details. diff --git a/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html b/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html index 0cf2fe073f9..9f9e72f12ce 100644 --- a/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html +++ b/corba/src/share/classes/org/omg/DynamicAny/DynAnyFactoryPackage/package.html @@ -38,8 +38,8 @@ interface of the DynamicAny module specified in the OMG The Common Object Request Broker: Architecture and Specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07, section 9.2.2. Please + +formal/99-10-07, section 9.2.2. Please refer to that OMG specification for further details.

Package Specification

diff --git a/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html b/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html index d0c2dc30829..480ed552c05 100644 --- a/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html +++ b/corba/src/share/classes/org/omg/DynamicAny/DynAnyPackage/package.html @@ -34,8 +34,8 @@ interface of the DynamicAny module specified in the OMG The Common Object Request Broker: Architecture and Specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07, section 9.2. Please + +formal/99-10-07, section 9.2. Please refer to that OMG specification for further details. diff --git a/corba/src/share/classes/org/omg/IOP/package.html b/corba/src/share/classes/org/omg/IOP/package.html index 34f2aa2060e..f0016bfc271 100644 --- a/corba/src/share/classes/org/omg/IOP/package.html +++ b/corba/src/share/classes/org/omg/IOP/package.html @@ -33,8 +33,8 @@ questions.

This package contains the IOP module specified in the OMG document The Common Object Request Broker: Architecture and Specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07, section 13.6. Please + +formal/99-10-07, section 13.6. Please refer to that OMG specification for further details.

Please note that we do not provide all parts of the IOP module from diff --git a/corba/src/share/classes/org/omg/Messaging/package.html b/corba/src/share/classes/org/omg/Messaging/package.html index f2fa37bdb4a..61e73d5b685 100644 --- a/corba/src/share/classes/org/omg/Messaging/package.html +++ b/corba/src/share/classes/org/omg/Messaging/package.html @@ -32,8 +32,8 @@ questions.

This package contains the Messaging module specified in the OMG CORBA Messaging specification, - -http://cgi.omg.org/cgi-bin/doc?formal/99-10-07. Please refer to that OMG + +formal/99-10-07. Please refer to that OMG specification for further details.

Please note that we do not provide all parts of the Messaging module from diff --git a/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html b/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html index 422069e6b71..d648d5af9e5 100644 --- a/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html +++ b/corba/src/share/classes/org/omg/PortableInterceptor/ORBInitInfoPackage/package.html @@ -33,8 +33,8 @@ questions.

This package contains the exceptions and typedefs from the ORBInitInfo local interface of the PortableInterceptor module specified in the OMG Portable Interceptor specification, - -http://cgi.omg.org/cgi-bin/doc?ptc/2000-08-06, section 21.7.2. Please + +ptc/2000-08-06, section 21.7.2. Please refer to that OMG specification for further details. From f3d19df488aaf96fdc57b93d3c66501aeb544eec Mon Sep 17 00:00:00 2001 From: David Li Date: Thu, 20 Mar 2014 13:38:07 -0700 Subject: [PATCH 062/170] 8035577: Xerces Update: impl/xpath/regex/RangeToken.java Reviewed-by: lancea, alanb, sherman, joehw --- .../internal/impl/xpath/regex/RangeToken.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java b/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java index 3a7ac70385b..192be06a35c 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/xpath/regex/RangeToken.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -351,7 +352,7 @@ final class RangeToken extends Token implements java.io.Serializable { // src2: o----o // src2: o----o // src2: o------------o - if (src2begin <= src2begin && src1end <= src2end) { + if (src2begin <= src1begin && src1end <= src2end) { // src1: o--------o // src2: o------------o // res: o--------o @@ -384,6 +385,7 @@ final class RangeToken extends Token implements java.io.Serializable { result[wp++] = src2begin; result[wp++] = src2end; this.ranges[src1] = src2end+1; + src2 += 2; } } else if (src2end < src1begin) { // Not overlapped @@ -399,10 +401,6 @@ final class RangeToken extends Token implements java.io.Serializable { +"]"); } } - while (src1 < this.ranges.length) { - result[wp++] = this.ranges[src1++]; - result[wp++] = this.ranges[src1++]; - } this.ranges = new int[wp]; System.arraycopy(result, 0, this.ranges, 0, wp); // this.ranges is sorted and compacted. @@ -464,8 +462,8 @@ final class RangeToken extends Token implements java.io.Serializable { if (ch > 0xffff) lowers.addRange(ch, ch); else { - char uch = Character.toUpperCase((char)ch); - lowers.addRange(uch, uch); + char lch = Character.toLowerCase((char)ch); + lowers.addRange(lch, lch); } } } @@ -479,8 +477,10 @@ final class RangeToken extends Token implements java.io.Serializable { void dumpRanges() { System.err.print("RANGE: "); - if (this.ranges == null) + if (this.ranges == null) { System.err.println(" NULL"); + return; + } for (int i = 0; i < this.ranges.length; i += 2) { System.err.print("["+this.ranges[i]+","+this.ranges[i+1]+"] "); } @@ -552,10 +552,10 @@ final class RangeToken extends Token implements java.io.Serializable { else if (this == Token.token_spaces) ret = "\\s"; else { - StringBuffer sb = new StringBuffer(); - sb.append("["); + StringBuilder sb = new StringBuilder(); + sb.append('['); for (int i = 0; i < this.ranges.length; i += 2) { - if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(","); + if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(','); if (this.ranges[i] == this.ranges[i+1]) { sb.append(escapeCharInCharClass(this.ranges[i])); } else { @@ -564,7 +564,7 @@ final class RangeToken extends Token implements java.io.Serializable { sb.append(escapeCharInCharClass(this.ranges[i+1])); } } - sb.append("]"); + sb.append(']'); ret = sb.toString(); } } else { @@ -578,7 +578,7 @@ final class RangeToken extends Token implements java.io.Serializable { StringBuffer sb = new StringBuffer(); sb.append("[^"); for (int i = 0; i < this.ranges.length; i += 2) { - if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(","); + if ((options & RegularExpression.SPECIAL_COMMA) != 0 && i > 0) sb.append(','); if (this.ranges[i] == this.ranges[i+1]) { sb.append(escapeCharInCharClass(this.ranges[i])); } else { @@ -587,7 +587,7 @@ final class RangeToken extends Token implements java.io.Serializable { sb.append(escapeCharInCharClass(this.ranges[i+1])); } } - sb.append("]"); + sb.append(']'); ret = sb.toString(); } } From c78becb61069defeb3d26ccad50d36add5361b9d Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Thu, 20 Mar 2014 14:25:22 -0700 Subject: [PATCH 063/170] 8034034: [parfait] JNI exc. pending in hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m Added JNI exception check in the appropriate places Reviewed-by: sla, zgu --- hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m index 1234645c257..0f0ff4e5da4 100644 --- a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m +++ b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m @@ -95,7 +95,9 @@ static task_t getTask(JNIEnv *env, jobject this_obj) { #define CHECK_EXCEPTION_CLEAR_(value) if ((*env)->ExceptionOccurred(env)) { (*env)->ExceptionClear(env); return value; } static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { - (*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg); + jclass exceptionClass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); + CHECK_EXCEPTION; + (*env)->ThrowNew(env, exceptionClass, errMsg); } static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { @@ -129,6 +131,7 @@ static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); + CHECK_EXCEPTION; taskID = (*env)->GetFieldID(env, cls, "task", "J"); CHECK_EXCEPTION; @@ -236,13 +239,16 @@ JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_loo (JNIEnv *env, jobject this_obj, jlong addr) { uintptr_t offset; const char* sym = NULL; + jstring sym_string; struct ps_prochandle* ph = get_proc_handle(env, this_obj); if (ph != NULL && ph->core != NULL) { sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); if (sym == NULL) return 0; + sym_string = (*env)->NewStringUTF(env, sym); + CHECK_EXCEPTION_(0); return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, - (*env)->NewStringUTF(env, sym), (jlong)offset); + sym_string, (jlong)offset); } return 0; } @@ -749,11 +755,14 @@ static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* const char* name; jobject loadObject; jobject loadObjectList; + jstring nameString; base = get_lib_base(ph, i); name = get_lib_name(ph, i); + nameString = (*env)->NewStringUTF(env, name); + CHECK_EXCEPTION; loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, - (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base); + nameString, (jlong)0, (jlong)base); CHECK_EXCEPTION; loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); CHECK_EXCEPTION; From 89a408692d8648aa6b35788b974e57def1315472 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Fri, 21 Mar 2014 09:35:43 +0100 Subject: [PATCH 064/170] 8037825: Fix warnings and enable "warnings as errors" in serviceability native libraries Reviewed-by: erikj, ihse --- common/autoconf/flags.m4 | 16 ++++++++++++++++ common/autoconf/generated-configure.sh | 21 ++++++++++++++++++++- common/autoconf/spec.gmk.in | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index bcfa1777bcf..1024b9400d6 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -735,4 +735,20 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], [COMPILER_SUPPORTS_TARGET_BITS_FLAG=true], [COMPILER_SUPPORTS_TARGET_BITS_FLAG=false]) AC_SUBST(COMPILER_SUPPORTS_TARGET_BITS_FLAG) + + case "${TOOLCHAIN_TYPE}" in + microsoft) + CFLAGS_WARNINGS_ARE_ERRORS="/WX" + ;; + solstudio) + CFLAGS_WARNINGS_ARE_ERRORS="-errtags -errwarn=%all" + ;; + gcc) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + clang) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + esac + AC_SUBST(CFLAGS_WARNINGS_ARE_ERRORS) ]) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index b3d823b29ed..824fa9d0e3d 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -673,6 +673,7 @@ XMKMF FIXPATH ZIP_DEBUGINFO_FILES ENABLE_DEBUG_SYMBOLS +CFLAGS_WARNINGS_ARE_ERRORS COMPILER_SUPPORTS_TARGET_BITS_FLAG ZERO_ARCHFLAG LDFLAGS_CXX_JDK @@ -4232,7 +4233,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1394794899 +DATE_WHEN_GENERATED=1395236071 ############################################################################### # @@ -41989,6 +41990,24 @@ $as_echo "$supports" >&6; } + case "${TOOLCHAIN_TYPE}" in + microsoft) + CFLAGS_WARNINGS_ARE_ERRORS="/WX" + ;; + solstudio) + CFLAGS_WARNINGS_ARE_ERRORS="-errtags -errwarn=%all" + ;; + gcc) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + clang) + CFLAGS_WARNINGS_ARE_ERRORS="-Werror" + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: warnings are errors: $CFLAGS_WARNINGS_ARE_ERRORS" >&5 +$as_echo "warnings are errors: $CFLAGS_WARNINGS_ARE_ERRORS" >&6; } + # Setup debug symbols (need objcopy from the toolchain for that) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index fe5fb1be8d8..5cd0185fbaa 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -324,6 +324,8 @@ CXX_O_FLAG_NONE:=@CXX_O_FLAG_NONE@ C_FLAG_DEPS:=@C_FLAG_DEPS@ CXX_FLAG_DEPS:=@CXX_FLAG_DEPS@ +CFLAGS_WARNINGS_ARE_ERRORS:=@CFLAGS_WARNINGS_ARE_ERRORS@ + # Tools that potentially need to be cross compilation aware. CC:=@FIXPATH@ @CCACHE@ @CC@ From 4036a466ca041853dca31a63c32ef6427b66559f Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Fri, 21 Mar 2014 20:24:01 +0530 Subject: [PATCH 065/170] 8037562: Nashorn: JSON.parse comes up with nonexistent entries if there are gaps between the keys Reviewed-by: jlaskey, hannesw --- .../nashorn/internal/objects/NativeArray.java | 22 ++++++++++ .../internal/runtime/JSONFunctions.java | 1 - .../internal/runtime/ScriptObject.java | 29 +++++++------ nashorn/test/script/basic/JDK-8037562.js | 41 +++++++++++++++++++ .../test/script/basic/JDK-8037562.js.EXPECTED | 4 ++ 5 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8037562.js create mode 100644 nashorn/test/script/basic/JDK-8037562.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index 168a2f8a9ec..d95caf2c665 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -31,6 +31,7 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator; import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator; +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; import java.lang.invoke.MethodHandle; import java.util.ArrayList; @@ -349,6 +350,27 @@ public final class NativeArray extends ScriptObject { return super.defineOwnProperty(key, desc, reject); } + /** + * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in + * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set + * method in such cases. This is because set method uses inherited setters (if any) + * from any object in proto chain such as Array.prototype, Object.prototype. + * This method directly sets a particular element value in the current object. + * + * @param index key for property + * @param value value to define + */ + @Override + public final void defineOwnProperty(final int index, final Object value) { + assert isValidArrayIndex(index) : "invalid array index"; + final long longIndex = ArrayIndex.toLongIndex(index); + if (longIndex >= getArray().length()) { + // make array big enough to hold.. + setArray(getArray().ensure(longIndex)); + } + setArray(getArray().set(index, value, false)); + } + /** * Return the array contents upcasted as an ObjectArray, regardless of * representation diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java index 64863184759..f12945fee52 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -101,7 +101,6 @@ public final class JSONFunctions { // apply 'reviver' function if available private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) { if (reviver instanceof ScriptFunction) { - assert global instanceof Global; final ScriptObject root = global.newObject(); root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered); return walk(root, "", (ScriptFunction)reviver); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 05e236e3bd6..1519024a70b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -593,23 +593,16 @@ public abstract class ScriptObject implements PropertyAccess { } /** - * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in - * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set - * method in such cases. This is because set method uses inherited setters (if any) - * from any object in proto chain such as Array.prototype, Object.prototype. - * This method directly sets a particular element value in the current object. + * Almost like defineOwnProperty(int,Object) for arrays this one does + * not add 'gap' elements (like the array one does). * * @param index key for property * @param value value to define */ - public final void defineOwnProperty(final int index, final Object value) { + public void defineOwnProperty(final int index, final Object value) { assert isValidArrayIndex(index) : "invalid array index"; final long longIndex = ArrayIndex.toLongIndex(index); - if (longIndex >= getArray().length()) { - // make array big enough to hold.. - setArray(getArray().ensure(longIndex)); - } - setArray(getArray().set(index, value, false)); + setValueAtArrayIndex(longIndex, index, value, false); } private void checkIntegerKey(final String key) { @@ -2747,9 +2740,7 @@ public abstract class ScriptObject implements PropertyAccess { * @param strict are we in strict mode */ private void doesNotHave(final int index, final Object value, final boolean strict) { - final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); - if (getMap().containsArrayKeys()) { final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); @@ -2760,6 +2751,18 @@ public abstract class ScriptObject implements PropertyAccess { } } + setValueAtArrayIndex(longIndex, index, value, strict); + } + + /** + * Handle when an array doesn't have a slot - possibly grow and/or convert array. + * + * @param index key as index + * @param value element value + * @param strict are we in strict mode + */ + private void setValueAtArrayIndex(final long longIndex, final int index, final Object value, final boolean strict) { + final long oldLength = getArray().length(); if (longIndex >= oldLength) { if (!isExtensible()) { if (strict) { diff --git a/nashorn/test/script/basic/JDK-8037562.js b/nashorn/test/script/basic/JDK-8037562.js new file mode 100644 index 00000000000..7534a0dab12 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8037562.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 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. + */ + + +/** + * JDK-8037562: Nashorn: JSON.parse comes up with nonexistent entries if there are gaps between the keys + * + * @test + * @run + */ + +var strs = [ + '{ "0":0, "2":2 }', + '{ "0":"", "2":"" }', + '{ "0":0, "5":"hello" }', + '{ "0":"", "15":3234 }', +] + +for (var i in strs) { + print(JSON.stringify(JSON.parse(strs[i]))); +} diff --git a/nashorn/test/script/basic/JDK-8037562.js.EXPECTED b/nashorn/test/script/basic/JDK-8037562.js.EXPECTED new file mode 100644 index 00000000000..ea671713c4e --- /dev/null +++ b/nashorn/test/script/basic/JDK-8037562.js.EXPECTED @@ -0,0 +1,4 @@ +{"0":0,"2":2} +{"0":"","2":""} +{"0":0,"5":"hello"} +{"0":"","15":3234} From 8167043964729b9eefb74f0c982db482d90abf11 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Sat, 22 Mar 2014 00:26:48 +0400 Subject: [PATCH 066/170] 8035857: Add tests to verify correctness of operations with BMI1 and LZCNT instructions Reviewed-by: iveresov, kvn, iignatyev --- hotspot/src/share/vm/prims/whitebox.cpp | 11 + .../intrinsics/bmi/BMITestRunner.java | 442 ++++++++++++++++++ .../test/compiler/intrinsics/bmi/Expr.java | 178 +++++++ .../compiler/intrinsics/bmi/TestAndnI.java | 91 ++++ .../compiler/intrinsics/bmi/TestAndnL.java | 95 ++++ .../compiler/intrinsics/bmi/TestBlsiI.java | 78 ++++ .../compiler/intrinsics/bmi/TestBlsiL.java | 78 ++++ .../compiler/intrinsics/bmi/TestBlsmskI.java | 78 ++++ .../compiler/intrinsics/bmi/TestBlsmskL.java | 80 ++++ .../compiler/intrinsics/bmi/TestBlsrI.java | 78 ++++ .../compiler/intrinsics/bmi/TestBlsrL.java | 78 ++++ .../compiler/intrinsics/bmi/TestLzcntI.java | 60 +++ .../compiler/intrinsics/bmi/TestLzcntL.java | 60 +++ .../compiler/intrinsics/bmi/TestTzcntI.java | 60 +++ .../compiler/intrinsics/bmi/TestTzcntL.java | 60 +++ .../com/oracle/java/testlibrary/Asserts.java | 58 +++ .../whitebox/sun/hotspot/WhiteBox.java | 3 + .../whitebox/sun/hotspot/cpuinfo/CPUInfo.java | 98 ++++ 18 files changed, 1686 insertions(+) create mode 100644 hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/Expr.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestAndnI.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestAndnL.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java create mode 100644 hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java create mode 100644 hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.java diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index d2d5fadb024..969c6542d06 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -500,6 +500,16 @@ WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o)) c = *p; WB_END +WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o)) + const char* cpu_features = VM_Version::cpu_features(); + ThreadToNativeFromVM ttn(thread); + jstring features_string = env->NewStringUTF(cpu_features); + + CHECK_JNI_EXCEPTION_(env, NULL); + + return features_string; +WB_END + //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { @@ -611,6 +621,7 @@ static JNINativeMethod methods[] = { {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, {CC"fullGC", CC"()V", (void*)&WB_FullGC }, {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory }, + {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, }; #undef CC diff --git a/hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java b/hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java new file mode 100644 index 00000000000..ea7fd821f33 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/BMITestRunner.java @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +import java.util.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.charset.StandardCharsets; + +import com.oracle.java.testlibrary.*; + +/** + * Test runner that invokes all methods implemented by particular Expr + * with random arguments in two different JVM processes and compares output. + * JVMs being started in different modes - one in int and other in comp + * with C2 and disabled tiered compilation. + */ +public class BMITestRunner { + + enum VMMode { + COMP, INT; + }; + + public static int DEFAULT_ITERATIONS_COUNT = 4000; + + /** + * Execute all methods implemented by expr in int and comp modes + * and compare output. + * Test pass only of output obtained with different VM modes is equal. + * To control behaviour of test following options could be passed: + *

    + *
  • -iterations=<N> each operation implemented by + * expr will be executed N times. Default value + * is 4000.
  • + *
  • -seed=<SEED> arguments for expr's methods + * obtained via RNG initiated with seed SEED. By default + * some random seed will be used.
  • + *
+ * + * @param expr operation that should be tested + * @param testOpts options to control test behaviour + * @param additionalVMOpts additional options for VM + * + * @throws Throwable if test failed. + */ + public static void runTests(Class expr, + String testOpts[], + String... additionalVMOpts) + throws Throwable { + + int seed = new Random().nextInt(); + int iterations = DEFAULT_ITERATIONS_COUNT; + + for (String testOption : testOpts) { + if (testOption.startsWith("-iterations=")) { + iterations = Integer.valueOf(testOption. + replace("-iterations=", "")); + } else if (testOption.startsWith("-seed=")) { + seed = Integer.valueOf(testOption.replace("-seed=", "")); + } + } + + System.out.println("Running test with seed: " + seed); + + OutputAnalyzer intOutput = runTest(expr, VMMode.INT, + additionalVMOpts, + seed, iterations); + OutputAnalyzer compOutput = runTest(expr, VMMode.COMP, + additionalVMOpts, + seed, iterations); + + dumpOutput(intOutput, "int"); + dumpOutput(compOutput, "comp"); + + Asserts.assertStringsEqual(intOutput.getStdout(), + compOutput.getStdout(), + "Results obtained in -Xint and " + + "-Xcomp should be the same."); + } + + /** + * Execute tests on methods implemented by expr in new VM + * started in testVMMode mode. + * + * @param expr operation that should be tested + * @param testVMMode VM mode for test + * @param additionalVMOpts additional options for VM + * @param seed for RNG used it tests + * @param iterations that will be used to invoke expr's methods. + * + * @return OutputAnalyzer for executed test. + * @throws Throwable when something goes wrong. + */ + public static OutputAnalyzer runTest(Class expr, + VMMode testVMMode, + String additionalVMOpts[], + int seed, int iterations) + throws Throwable { + + List vmOpts = new LinkedList(); + + Collections.addAll(vmOpts, additionalVMOpts); + + //setup mode-specific options + switch (testVMMode) { + case INT: + Collections.addAll(vmOpts, new String[] { "-Xint" }); + break; + case COMP: + Collections.addAll(vmOpts, new String[] { + "-Xcomp", + "-XX:-TieredCompilation", + String.format("-XX:CompileCommand=compileonly,%s::*", + expr.getName()) + }); + break; + } + + Collections.addAll(vmOpts, new String[] { + "-XX:+DisplayVMOutputToStderr", + Executor.class.getName(), + expr.getName(), + new Integer(seed).toString(), + new Integer(iterations).toString() + }); + + OutputAnalyzer outputAnalyzer = ProcessTools. + executeTestJvm(vmOpts.toArray(new String[vmOpts.size()])); + + outputAnalyzer.shouldHaveExitValue(0); + + return outputAnalyzer; + } + + /** + * Dump stdout and stderr of test process to prefix.test.out + * and prefix.test.err respectively. + * + * @param outputAnalyzer OutputAnalyzer whom output should be dumped + * @param prefix Prefix that will be used in file names. + * @throws IOException if unable to dump output to file. + */ + protected static void dumpOutput(OutputAnalyzer outputAnalyzer, + String prefix) + throws IOException { + Files.write(Paths.get(prefix + ".test.out"), + outputAnalyzer.getStdout().getBytes()); + + Files.write(Paths.get(prefix + ".test.err"), + outputAnalyzer.getStderr().getBytes()); + } + + + /** + * Executor that invoke all methods implemented by particular + * Expr instance. + */ + public static class Executor { + + /** + * Usage: BMITestRunner$Executor + */ + public static void main(String args[]) throws Exception { + @SuppressWarnings("unchecked") + Class exprClass = + (Class)Class.forName(args[0]); + Expr expr = exprClass.getConstructor().newInstance(); + Random rng = new Random(Integer.valueOf(args[1])); + int iterations = Integer.valueOf(args[2]); + runTests(expr, iterations, rng); + } + + + public static int[] getIntBitShifts() { + //SIZE+1 shift is for zero. + int data[] = new int[Integer.SIZE+1]; + for (int s = 0; s < data.length; s++) { + data[s] = 1< 0X%x", + value, expr.intExpr(value)); + } + + for (int i = 0; i < iterations; i++) { + int value = rng.nextInt(); + log("UnaryIntReg(0X%x) -> 0X%x", + value, expr.intExpr(value)); + } + } + + public static void runUnaryIntMemTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isUnaryArgumentSupported() + && expr.isIntExprSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int value : getIntBitShifts()) { + log("UnaryIntMem(0X%x) -> 0X%x", + value, expr.intExpr(new Expr.MemI(value))); + } + + for (int i = 0; i < iterations; i++) { + int value = rng.nextInt(); + log("UnaryIntMem(0X%x) -> 0X%x", + value, expr.intExpr(new Expr.MemI(value))); + } + } + + public static void runUnaryLongRegTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isUnaryArgumentSupported() + && expr.isLongExprSupported())) { + return; + } + + for (long value : getLongBitShifts()) { + log("UnaryLongReg(0X%x) -> 0X%x", + value, expr.longExpr(value)); + } + + for (int i = 0; i < iterations; i++) { + long value = rng.nextLong(); + log("UnaryLongReg(0X%x) -> 0X%x", + value, expr.longExpr(value)); + } + } + + public static void runUnaryLongMemTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isUnaryArgumentSupported() + && expr.isLongExprSupported() + && expr.isMemExprSupported())) { + return; + } + + for (long value : getLongBitShifts()) { + log("UnaryLongMem(0X%x) -> 0X%x", + value, expr.longExpr(new Expr.MemL(value))); + } + + for (int i = 0; i < iterations; i++) { + long value = rng.nextLong(); + log("UnaryLongMem(0X%x) -> 0X%x", + value, expr.longExpr(new Expr.MemL(value))); + } + } + + public static void runBinaryRegRegIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntRegReg(0X%x, 0X%x) -> 0X%x", + aValue, bValue, expr.intExpr(aValue, bValue)); + } + } + + public static void runBinaryRegMemIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.intExpr(aValue, new Expr.MemI(bValue))); + } + } + + public static void runBinaryMemRegIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.intExpr(new Expr.MemI(aValue), bValue)); + } + } + + public static void runBinaryMemMemIntTest(Expr expr, int iterations, + Random rng) { + if (!(expr.isIntExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + int aValue = rng.nextInt(); + int bValue = rng.nextInt(); + log("BinaryIntMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.intExpr(new Expr.MemI(aValue), + new Expr.MemI(bValue))); + } + } + + public static void runBinaryRegRegLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongRegReg(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(aValue, bValue)); + } + } + + public static void runBinaryRegMemLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(aValue, new Expr.MemL(bValue))); + } + } + + public static void runBinaryMemRegLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(new Expr.MemL(aValue), bValue)); + } + } + + public static void runBinaryMemMemLongTest(Expr expr, + int iterations, + Random rng) { + if (!(expr.isLongExprSupported() + && expr.isBinaryArgumentSupported() + && expr.isMemExprSupported())) { + return; + } + + for (int i = 0; i < iterations; i++) { + long aValue = rng.nextLong(); + long bValue = rng.nextLong(); + log("BinaryLongMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue, + expr.longExpr(new Expr.MemL(aValue), + new Expr.MemL(bValue))); + } + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/Expr.java b/hotspot/test/compiler/intrinsics/bmi/Expr.java new file mode 100644 index 00000000000..2d4a84a0193 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/Expr.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +/** + * Expression that should be replaced by particular instrinsic + * or intruction during compilation. + */ + +public abstract class Expr { + + public static class MemI { + public MemI(int i) { + this.value = i; + } + + public int value; + } + + public static class MemL { + public MemL(long l) { + this.value = l; + } + + public long value; + } + + public boolean isUnaryArgumentSupported() { + return false; + } + + public boolean isIntExprSupported() { + return false; + } + + public boolean isBinaryArgumentSupported() { + return false; + } + + public boolean isLongExprSupported() { + return false; + } + + public boolean isMemExprSupported() { + return false; + } + + public int intExpr(int reg) { + throw new UnsupportedOperationException(); + } + + public int intExpr(MemI mem) { + throw new UnsupportedOperationException(); + } + + public int intExpr(int a, int b) { + throw new UnsupportedOperationException(); + } + + public int intExpr(int a, MemI b) { + throw new UnsupportedOperationException(); + } + + public int intExpr(MemI a, int b) { + throw new UnsupportedOperationException(); + } + + public int intExpr(MemI a, MemI b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(long reg) { + throw new UnsupportedOperationException(); + } + + public long longExpr(MemL mem) { + throw new UnsupportedOperationException(); + } + + public long longExpr(long a, long b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(long a, MemL b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(MemL a, long b) { + throw new UnsupportedOperationException(); + } + + public long longExpr(MemL a, MemL b) { + throw new UnsupportedOperationException(); + } + + public static class BMIExpr extends Expr { + + public boolean isMemExprSupported() { + return true; + } + } + + public static class BMIBinaryExpr extends BMIExpr { + + public boolean isBinaryArgumentSupported() { + return true; + } + + } + + public static class BMIUnaryExpr extends BMIExpr { + public boolean isUnaryArgumentSupported() { + return true; + } + } + + public static class BMIBinaryIntExpr extends BMIBinaryExpr { + public boolean isIntExprSupported() { + return true; + } + } + + public static class BMIBinaryLongExpr extends BMIBinaryExpr { + public boolean isLongExprSupported() { + return true; + } + } + + public static class BMIUnaryIntExpr extends BMIUnaryExpr { + public boolean isIntExprSupported() { + return true; + } + } + + public static class BMIUnaryLongExpr extends BMIUnaryExpr { + public boolean isLongExprSupported() { + return true; + } + } + + public static class BitCountingExpr extends Expr { + public boolean isUnaryArgumentSupported() { + return true; + } + } + + public static class BitCountingIntExpr extends BitCountingExpr { + public boolean isIntExprSupported() { + return true; + } + } + + public static class BitCountingLongExpr extends BitCountingExpr { + public boolean isLongExprSupported() { + return true; + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java new file mode 100644 index 00000000000..e8cfaa23f0f --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of ANDN instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestAndnI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestAndnI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestAndnI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. "+ + "Test skipped."); + return; + } + + BMITestRunner.runTests(AndnIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(AndnICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class AndnIExpr extends Expr.BMIBinaryIntExpr { + + public int intExpr(int src1, int src2) { + return ~src1 & src2; + } + + public int intExpr(int src1, Expr.MemI src2) { + return ~src1 & src2.value; + } + + public int intExpr(Expr.MemI src1, int src2) { + return ~src1.value & src2; + } + + public int intExpr(Expr.MemI src1, Expr.MemI src2) { + return ~src1.value & src2.value; + } + } + + public static class AndnICommutativeExpr extends Expr.BMIBinaryIntExpr { + + public int intExpr(int src1, int src2) { + return src1 & ~src2; + } + + public int intExpr(int src1, Expr.MemI src2) { + return src1 & ~src2.value; + } + + public int intExpr(Expr.MemI src1, int src2) { + return src1.value & ~src2; + } + + public int intExpr(Expr.MemI src1, Expr.MemI src2) { + return src1.value & ~src2.value; + } + } +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java new file mode 100644 index 00000000000..0dca7aa399a --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of ANDN instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestAndnL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestAndnL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestAndnL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(AndnLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(AndnLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class AndnLExpr extends Expr.BMIBinaryLongExpr { + + public long longExpr(long src1, long src2) { + return ~src1 & src2; + } + + public long longExpr(long src1, Expr.MemL src2) { + return ~src1 & src2.value; + } + + public long longExpr(Expr.MemL src1, long src2) { + return ~src1.value & src2; + } + + public long longExpr(Expr.MemL src1, Expr.MemL src2) { + return ~src1.value & src2.value; + } + + + } + + public static class AndnLCommutativeExpr extends Expr.BMIBinaryLongExpr { + + public long longExpr(long src1, long src2) { + return src1 & ~src2; + } + + public long longExpr(long src1, Expr.MemL src2) { + return src1 & ~src2.value; + } + + public long longExpr(Expr.MemL src1, long src2) { + return src1.value & ~src2; + } + + public long longExpr(Expr.MemL src1, Expr.MemL src2) { + return src1.value & ~src2.value; + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java new file mode 100644 index 00000000000..9f998bc05d5 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiI.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSI instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsiI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsiI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsiI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsiIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsiICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsiIExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return -src & src; + } + + public int intExpr(Expr.MemI src) { + return -src.value & src.value; + } + + } + + public static class BlsiICommutativeExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return src & -src; + } + + public int intExpr(Expr.MemI src) { + return src.value & -src.value; + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java new file mode 100644 index 00000000000..b7a36c65a26 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsiL.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSI instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsiL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsiL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsiL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsiLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsiLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsiLExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return -src & src; + } + + public long longExpr(Expr.MemL src) { + return -src.value & src.value; + } + + } + + public static class BlsiLCommutativeExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return src & -src; + } + + public long longExpr(Expr.MemL src) { + return src.value & -src.value; + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java new file mode 100644 index 00000000000..a06b429ec03 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskI.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSMSK instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsmskI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsmskI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsmskI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsmskIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsmskICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsmskIExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return (src - 1) ^ src; + } + + public int intExpr(Expr.MemI src) { + return (src.value - 1) ^ src.value; + } + + } + + public static class BlsmskICommutativeExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return src ^ (src - 1); + } + + public int intExpr(Expr.MemI src) { + return src.value ^ (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java new file mode 100644 index 00000000000..794c4c8f9a9 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsmskL.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSMSK instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsmskL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsmskL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsmskL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsmskLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsmskLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsmskLExpr + extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return (src - 1) ^ src; + } + + public long longExpr(Expr.MemL src) { + return (src.value - 1) ^ src.value; + } + + } + + public static class BlsmskLCommutativeExpr + extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return src ^ (src - 1); + } + + public long longExpr(Expr.MemL src) { + return src.value ^ (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java new file mode 100644 index 00000000000..73ea886023f --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrI.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSR instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsrI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsrI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsrI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsrIExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsrICommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsrIExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return (src - 1) & src; + } + + public int intExpr(Expr.MemI src) { + return (src.value - 1) & src.value; + } + + } + + public static class BlsrICommutativeExpr extends Expr.BMIUnaryIntExpr { + + public int intExpr(int src) { + return src & (src - 1); + } + + public int intExpr(Expr.MemI src) { + return src.value & (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java new file mode 100644 index 00000000000..861f160806b --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestBlsrL.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of BLSR instruction + * @library /testlibrary /testlibrary/whitebox + * @build TestBlsrL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestBlsrL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestBlsrL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(BlsrLExpr.class, args, + "-XX:+UseBMI1Instructions"); + BMITestRunner.runTests(BlsrLCommutativeExpr.class, args, + "-XX:+UseBMI1Instructions"); + } + + public static class BlsrLExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return (src - 1) & src; + } + + public long longExpr(Expr.MemL src) { + return (src.value - 1) & src.value; + } + + } + + public static class BlsrLCommutativeExpr extends Expr.BMIUnaryLongExpr { + + public long longExpr(long src) { + return src & (src - 1); + } + + public long longExpr(Expr.MemL src) { + return src.value & (src.value - 1); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java new file mode 100644 index 00000000000..a3720dc51e3 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntI.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestLzcntI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestLzcntI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestLzcntI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("lzcnt")) { + System.out.println("CPU does not support lzcnt feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(LzcntIExpr.class, args, + "-XX:+UseCountLeadingZerosInstruction"); + } + + public static class LzcntIExpr extends Expr.BitCountingIntExpr { + + public int intExpr(int src) { + return Integer.numberOfLeadingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java new file mode 100644 index 00000000000..a3d788725a7 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestLzcntL.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestLzcntL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestLzcntL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestLzcntL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("lzcnt")) { + System.out.println("CPU does not support lzcnt feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(LzcntLExpr.class, args, + "-XX:+UseCountLeadingZerosInstruction"); + } + + public static class LzcntLExpr extends Expr.BitCountingLongExpr { + + public long longExpr(long src) { + return Long.numberOfLeadingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java new file mode 100644 index 00000000000..d74c82a9a9e --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntI.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestTzcntI BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestTzcntI + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestTzcntI { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(TzcntIExpr.class, args, + "-XX:+UseCountTrailingZerosInstruction"); + } + + public static class TzcntIExpr extends Expr.BitCountingIntExpr { + + public int intExpr(int src) { + return Integer.numberOfTrailingZeros(src); + } + + } + +} diff --git a/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java new file mode 100644 index 00000000000..0c1841991d9 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/bmi/TestTzcntL.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify that results of computations are the same w/ + * and w/o usage of intrinsic + * @library /testlibrary /testlibrary/whitebox + * @build TestTzcntL BMITestRunner Expr + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestTzcntL + */ + +import sun.hotspot.cpuinfo.CPUInfo; + +public class TestTzcntL { + + public static void main(String args[]) throws Throwable { + if (!CPUInfo.hasFeature("bmi1")) { + System.out.println("CPU does not support bmi1 feature. " + + "Test skipped."); + return; + } + + BMITestRunner.runTests(TzcntLExpr.class, args, + "-XX:+UseCountTrailingZerosInstruction"); + } + + public static class TzcntLExpr extends Expr.BitCountingLongExpr { + + public long longExpr(long src) { + return Long.numberOfTrailingZeros(src); + } + + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java index e92e26dd4b5..176e883546b 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java @@ -378,6 +378,64 @@ public class Asserts { } } + /** + * Asserts that two strings are equal. + * + * If strings are not equals, then exception message + * will contain {@code msg} followed by list of mismatched lines. + * + * @param str1 First string to compare. + * @param str2 Second string to compare. + * @param msg A description of the assumption. + * @throws RuntimeException if strings are not equal. + */ + public static void assertStringsEqual(String str1, String str2, + String msg) { + String lineSeparator = System.getProperty("line.separator"); + String str1Lines[] = str1.split(lineSeparator); + String str2Lines[] = str2.split(lineSeparator); + + int minLength = Math.min(str1Lines.length, str2Lines.length); + String longestStringLines[] = ((str1Lines.length == minLength) ? + str2Lines : str1Lines); + + boolean stringsAreDifferent = false; + + StringBuilder messageBuilder = new StringBuilder(msg); + + messageBuilder.append("\n"); + + for (int line = 0; line < minLength; line++) { + if (!str1Lines[line].equals(str2Lines[line])) { + messageBuilder.append(String. + format("[line %d] '%s' differs " + + "from '%s'\n", + line, + str1Lines[line], + str2Lines[line])); + stringsAreDifferent = true; + } + } + + if (minLength < longestStringLines.length) { + String stringName = ((longestStringLines == str1Lines) ? + "first" : "second"); + messageBuilder.append(String.format("Only %s string contains " + + "following lines:\n", + stringName)); + stringsAreDifferent = true; + for(int line = minLength; line < longestStringLines.length; line++) { + messageBuilder.append(String. + format("[line %d] '%s'", line, + longestStringLines[line])); + } + } + + if (stringsAreDifferent) { + error(messageBuilder.toString()); + } + } + private static > int compare(T lhs, T rhs, String msg) { assertNotNull(lhs, msg); assertNotNull(rhs, msg); diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java index da1244ce093..f37a6fc1d56 100644 --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -150,4 +150,7 @@ public class WhiteBox { public native void runMemoryUnitTests(); public native void readFromNoaccessArea(); + // CPU features + public native String getCPUFeatures(); + } diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.java new file mode 100644 index 00000000000..8532573a94c --- /dev/null +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/cpuinfo/CPUInfo.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014, 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.hotspot.cpuinfo; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import sun.hotspot.WhiteBox; + +/** + * Information about CPU on test box. + * + * CPUInfo uses WhiteBox to gather information, + * so WhiteBox class should be added to bootclasspath + * and option -XX:+WhiteBoxAPI should expclicetly + * specified on command line. + */ +public class CPUInfo { + + private static final List features; + private static final String additionalCPUInfo; + + static { + WhiteBox wb = WhiteBox.getWhiteBox(); + + Pattern additionalCPUInfoRE = + Pattern.compile("([^(]*\\([^)]*\\)[^,]*),\\s*"); + + String cpuFeaturesString = wb.getCPUFeatures(); + Matcher matcher = additionalCPUInfoRE.matcher(cpuFeaturesString); + if (matcher.find()) { + additionalCPUInfo = matcher.group(1); + } else { + additionalCPUInfo = ""; + } + String splittedFeatures[] = matcher.replaceAll("").split("(, )| "); + + features = Collections.unmodifiableList(Arrays. + asList(splittedFeatures)); + } + + /** + * Get additional information about CPU. + * For example, on X86 in will be family/model/stepping + * and number of cores. + * + * @return additional CPU info + */ + public static String getAdditionalCPUInfo() { + return additionalCPUInfo; + } + + /** + * Get all known features supported by CPU. + * + * @return unmodifiable list with names of all known features + * supported by CPU. + */ + public static List getFeatures() { + return features; + } + + /** + * Check if some feature is supported by CPU. + * + * @param feature Name of feature to be tested. + * @return true if tested feature is supported by CPU. + */ + public static boolean hasFeature(String feature) { + return features.contains(feature.toLowerCase()); + } +} From 93c0cc2aa872414c9f3116a8140d9f13299a2cc3 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 21 Mar 2014 18:03:11 -0700 Subject: [PATCH 067/170] 8038181: Can't build product VM without precompiled header Added missing #include. Reviewed-by: twisti --- hotspot/src/cpu/x86/vm/rtmLocking.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/cpu/x86/vm/rtmLocking.cpp b/hotspot/src/cpu/x86/vm/rtmLocking.cpp index 8ea21d896ea..e1b28654b03 100644 --- a/hotspot/src/cpu/x86/vm/rtmLocking.cpp +++ b/hotspot/src/cpu/x86/vm/rtmLocking.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/allocation.inline.hpp" #include "runtime/task.hpp" #include "runtime/rtmLocking.hpp" From 3c590f1afe7018dff9ea64f2bd29d980292345be Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Mon, 24 Mar 2014 10:15:52 +0100 Subject: [PATCH 068/170] 8037298: Export HotSpots 'optimized' (i.e. not-product) configuration in the top-level configure/makefile Reviewed-by: ihse --- common/autoconf/generated-configure.sh | 33 ++++++++++++++++++++++---- common/autoconf/help.m4 | 1 + common/autoconf/jdk-options.m4 | 26 +++++++++++++++++++- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 824fa9d0e3d..6b7a52bd273 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -1861,8 +1861,8 @@ Optional Packages: --with-jvm-variants JVM variants (separated by commas) to build (server, client, minimal1, kernel, zero, zeroshark, core) [server] - --with-debug-level set the debug level (release, fastdebug, slowdebug) - [release] + --with-debug-level set the debug level (release, fastdebug, slowdebug, + optimized (HotSpot build only)) [release] --with-conf-name use this as the name of the configuration [generated from important configuration options] --with-builddeps-conf use this configuration file for the builddeps @@ -4233,7 +4233,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1395236071 +DATE_WHEN_GENERATED=1395652496 ############################################################################### # @@ -14648,6 +14648,7 @@ $as_echo "$with_jvm_variants" >&6; } # # Set the debug level # release: no debug information, all optimizations, no asserts. + # optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'. # fastdebug: debug information (-g), all optimizations, all asserts # slowdebug: debug information (-g), no optimizations, all asserts # @@ -14680,6 +14681,7 @@ fi $as_echo "$DEBUG_LEVEL" >&6; } if test "x$DEBUG_LEVEL" != xrelease && \ + test "x$DEBUG_LEVEL" != xoptimized && \ test "x$DEBUG_LEVEL" != xfastdebug && \ test "x$DEBUG_LEVEL" != xslowdebug; then as_fn_error $? "Allowed debug levels are: release, fastdebug and slowdebug" "$LINENO" 5 @@ -14716,8 +14718,30 @@ $as_echo "$DEBUG_LEVEL" >&6; } HOTSPOT_DEBUG_LEVEL="jvmg" HOTSPOT_EXPORT="debug" ;; + optimized ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + BUILD_VARIANT_RELEASE="-optimized" + HOTSPOT_DEBUG_LEVEL="optimized" + HOTSPOT_EXPORT="optimized" + ;; esac + # The debug level 'optimized' is a little special because it is currently only + # applicable to the HotSpot build where it means to build a completely + # optimized version of the VM without any debugging code (like for the + # 'release' debug level which is called 'product' in the HotSpot build) but + # with the exception that it can contain additional code which is otherwise + # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to + # test new and/or experimental features which are not intended for customer + # shipment. Because these new features need to be tested and benchmarked in + # real world scenarios, we want to build the containing JDK at the 'release' + # debug level. + if test "x$DEBUG_LEVEL" = xoptimized; then + DEBUG_LEVEL="release" + fi + ##### # Generate the legacy makefile targets for hotspot. # The hotspot api for selecting the build artifacts, really, needs to be improved. @@ -42005,8 +42029,6 @@ $as_echo "$supports" >&6; } ;; esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: warnings are errors: $CFLAGS_WARNINGS_ARE_ERRORS" >&5 -$as_echo "warnings are errors: $CFLAGS_WARNINGS_ARE_ERRORS" >&6; } # Setup debug symbols (need objcopy from the toolchain for that) @@ -50222,6 +50244,7 @@ $CHMOD +x $OUTPUT_ROOT/compare.sh printf "\n" printf "Configuration summary:\n" printf "* Debug level: $DEBUG_LEVEL\n" + printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" printf "* JDK variant: $JDK_VARIANT\n" printf "* JVM variants: $with_jvm_variants\n" printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index 2cad8d6fb39..9ae7874fd6b 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -200,6 +200,7 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], printf "\n" printf "Configuration summary:\n" printf "* Debug level: $DEBUG_LEVEL\n" + printf "* HS debug level: $HOTSPOT_DEBUG_LEVEL\n" printf "* JDK variant: $JDK_VARIANT\n" printf "* JVM variants: $with_jvm_variants\n" printf "* OpenJDK target: OS: $OPENJDK_TARGET_OS, CPU architecture: $OPENJDK_TARGET_CPU_ARCH, address length: $OPENJDK_TARGET_CPU_BITS\n" diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 58d148fe421..b012aa756b4 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -176,6 +176,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], # # Set the debug level # release: no debug information, all optimizations, no asserts. + # optimized: no debug information, all optimizations, no asserts, HotSpot target is 'optimized'. # fastdebug: debug information (-g), all optimizations, all asserts # slowdebug: debug information (-g), no optimizations, all asserts # @@ -189,7 +190,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], ], [ENABLE_DEBUG="no"]) AC_ARG_WITH([debug-level], [AS_HELP_STRING([--with-debug-level], - [set the debug level (release, fastdebug, slowdebug) @<:@release@:>@])], + [set the debug level (release, fastdebug, slowdebug, optimized (HotSpot build only)) @<:@release@:>@])], [ DEBUG_LEVEL="${withval}" if test "x$ENABLE_DEBUG" = xyes; then @@ -199,6 +200,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], AC_MSG_RESULT([$DEBUG_LEVEL]) if test "x$DEBUG_LEVEL" != xrelease && \ + test "x$DEBUG_LEVEL" != xoptimized && \ test "x$DEBUG_LEVEL" != xfastdebug && \ test "x$DEBUG_LEVEL" != xslowdebug; then AC_MSG_ERROR([Allowed debug levels are: release, fastdebug and slowdebug]) @@ -235,8 +237,30 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_LEVEL], HOTSPOT_DEBUG_LEVEL="jvmg" HOTSPOT_EXPORT="debug" ;; + optimized ) + VARIANT="OPT" + FASTDEBUG="false" + DEBUG_CLASSFILES="false" + BUILD_VARIANT_RELEASE="-optimized" + HOTSPOT_DEBUG_LEVEL="optimized" + HOTSPOT_EXPORT="optimized" + ;; esac + # The debug level 'optimized' is a little special because it is currently only + # applicable to the HotSpot build where it means to build a completely + # optimized version of the VM without any debugging code (like for the + # 'release' debug level which is called 'product' in the HotSpot build) but + # with the exception that it can contain additional code which is otherwise + # protected by '#ifndef PRODUCT' macros. These 'optimized' builds are used to + # test new and/or experimental features which are not intended for customer + # shipment. Because these new features need to be tested and benchmarked in + # real world scenarios, we want to build the containing JDK at the 'release' + # debug level. + if test "x$DEBUG_LEVEL" = xoptimized; then + DEBUG_LEVEL="release" + fi + ##### # Generate the legacy makefile targets for hotspot. # The hotspot api for selecting the build artifacts, really, needs to be improved. From 1516f610a1b4259b069a8f18bb946a740f9021d9 Mon Sep 17 00:00:00 2001 From: Poonam Bajaj Date: Mon, 24 Mar 2014 08:43:10 -0700 Subject: [PATCH 069/170] 6653795: C2 intrinsic for Unsafe.getAddress performs pointer sign extension on 32-bit systems Native pointers less than 64 bits wide should be extended as an unsigned number. Reviewed-by: kvn, kevinw --- hotspot/src/share/vm/opto/graphKit.cpp | 11 +++ hotspot/src/share/vm/opto/graphKit.hpp | 1 + hotspot/src/share/vm/opto/library_call.cpp | 2 +- hotspot/src/share/vm/opto/type.hpp | 2 + .../unsafe/UnsafeGetAddressTest.java | 68 +++++++++++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 803637dd2be..a710d6c32c9 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1125,6 +1125,17 @@ Node* GraphKit::ConvI2L(Node* offset) { } return _gvn.transform( new (C) ConvI2LNode(offset)); } + +Node* GraphKit::ConvI2UL(Node* offset) { + juint offset_con = (juint) find_int_con(offset, Type::OffsetBot); + if (offset_con != (juint) Type::OffsetBot) { + return longcon((julong) offset_con); + } + Node* conv = _gvn.transform( new (C) ConvI2LNode(offset)); + Node* mask = _gvn.transform( ConLNode::make(C, (julong) max_juint) ); + return _gvn.transform( new (C) AndLNode(conv, mask) ); +} + Node* GraphKit::ConvL2I(Node* offset) { // short-circuit a common case jlong offset_con = find_long_con(offset, (jlong)Type::OffsetBot); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index fbbf8c9aa86..703b8d8f2a6 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -338,6 +338,7 @@ class GraphKit : public Phase { // Convert between int and long, and size_t. // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.) Node* ConvI2L(Node* offset); + Node* ConvI2UL(Node* offset); Node* ConvL2I(Node* offset); // Find out the klass of an object. Node* load_object_klass(Node* object); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index bd2ef020bb2..065776dd421 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -2600,7 +2600,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas case T_ADDRESS: // Cast to an int type. p = _gvn.transform(new (C) CastP2XNode(NULL, p)); - p = ConvX2L(p); + p = ConvX2UL(p); break; default: fatal(err_msg_res("unexpected type %d: %s", type, type2name(type))); diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index fb58dc2f584..c587e145e33 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -1716,6 +1716,7 @@ inline bool Type::is_ptr_to_boxing_obj() const { #define ConvL2X(x) (x) #define ConvX2I(x) ConvL2I(x) #define ConvX2L(x) (x) +#define ConvX2UL(x) (x) #else @@ -1760,6 +1761,7 @@ inline bool Type::is_ptr_to_boxing_obj() const { #define ConvL2X(x) ConvL2I(x) #define ConvX2I(x) (x) #define ConvX2L(x) ConvI2L(x) +#define ConvX2UL(x) ConvI2UL(x) #endif diff --git a/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java b/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java new file mode 100644 index 00000000000..9e5772a944d --- /dev/null +++ b/hotspot/test/compiler/intrinsics/unsafe/UnsafeGetAddressTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, 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 6653795 + * @summary C2 intrinsic for Unsafe.getAddress performs pointer sign extension on 32-bit systems + * @run main UnsafeGetAddressTest + * + */ + +import sun.misc.Unsafe; +import java.lang.reflect.*; + +public class UnsafeGetAddressTest { + private static Unsafe unsafe; + + public static void main(String[] args) throws Exception { + Class c = UnsafeGetAddressTest.class.getClassLoader().loadClass("sun.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe)f.get(c); + + long address = unsafe.allocateMemory(unsafe.addressSize()); + unsafe.putAddress(address, 0x0000000080000000L); + // from sun.misc.Unsafe.getAddress' documentation: + // "If the native pointer is less than 64 bits wide, it is + // extended as an unsigned number to a Java long." + result = unsafe.getAddress(address); + System.out.printf("1: was 0x%x, expected 0x%x\n", result, + 0x0000000080000000L); + for (int i = 0; i < 1000000; i++) { + result = unsafe.getAddress(address); + } + + // The code has got compiled, check the result now + System.out.printf("2: was 0x%x, expected 0x%x\n", result, + 0x0000000080000000L); + if (result != 0x0000000080000000L) { + System.out.println("Test Failed"); + System.exit(97); + } else { + System.out.println("Test Passed"); + } + } + static volatile long result; +} + From 1c9ebd2bebb33d782ba60e5a32bd5c6d15ccf0e3 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 24 Mar 2014 10:48:44 -0700 Subject: [PATCH 070/170] 8033566: [parfait] warning from b128 for hotspot/src/share/vm/runtime/frame.cpp: JNI primitive type mismatch Added an assert for checking the return value is <= max_jint Reviewed-by: coleenp, minqi --- hotspot/src/share/vm/runtime/frame.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index cdd2cf79ac3..1409bd79651 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -531,13 +531,16 @@ jint frame::interpreter_frame_expression_stack_size() const { // Number of elements on the interpreter expression stack // Callers should span by stackElementWords int element_size = Interpreter::stackElementWords; + size_t stack_size = 0; if (frame::interpreter_frame_expression_stack_direction() < 0) { - return (interpreter_frame_expression_stack() - - interpreter_frame_tos_address() + 1)/element_size; + stack_size = (interpreter_frame_expression_stack() - + interpreter_frame_tos_address() + 1)/element_size; } else { - return (interpreter_frame_tos_address() - - interpreter_frame_expression_stack() + 1)/element_size; + stack_size = (interpreter_frame_tos_address() - + interpreter_frame_expression_stack() + 1)/element_size; } + assert( stack_size <= (size_t)max_jint, "stack size too big"); + return ((jint)stack_size); } From 3273c46daf70e6804b74decf0a6a92e87f276d45 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Mon, 24 Mar 2014 11:51:40 -0700 Subject: [PATCH 071/170] 8038262: Workaround for ccache in vm.make is missing for aix Reviewed-by: simonis, kvn --- hotspot/make/aix/makefiles/vm.make | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/aix/makefiles/vm.make b/hotspot/make/aix/makefiles/vm.make index 21818dcdc1a..ab994a3c2ae 100644 --- a/hotspot/make/aix/makefiles/vm.make +++ b/hotspot/make/aix/makefiles/vm.make @@ -101,7 +101,7 @@ CXXFLAGS = \ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain # a time and date. -vm_version.o: CXXFLAGS += ${JRE_VERSION} +CXXFLAGS/vm_version.o += ${JRE_VERSION} CXXFLAGS/BYFILE = $(CXXFLAGS/$@) From ef9ad46ff8d2078216fcde0e3cc01dbac0d588ad Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Mon, 24 Mar 2014 15:40:29 -0700 Subject: [PATCH 072/170] 8030681: add "serve" command and --quiet and --verbose options to hgforest Reviewed-by: ihse --- common/bin/hgforest.sh | 214 ++++++++++++++++++++++++++++------------- 1 file changed, 145 insertions(+), 69 deletions(-) diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index d8164d60316..17a4e79a4e7 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. @@ -24,12 +24,53 @@ # # Shell script for a fast parallel forest command -command="$1" -pull_extra_base="$2" -if [ "" = "$command" ] ; then - echo No command to hg supplied! - exit 1 +global_opts="" +status_output="/dev/stdout" +qflag="false" +vflag="false" +while [ $# -gt 0 ] +do + case $1 in + -q | --quiet ) + qflag="true" + global_opts="${global_opts} -q" + status_output="/dev/null" + ;; + + -v | --verbose ) + vflag="true" + global_opts="${global_opts} -v" + ;; + + '--' ) # no more options + shift; break + ;; + + -*) # bad option + usage + ;; + + * ) # non option + break + ;; + esac + shift +done + + +command="$1"; shift +repo_base="$@" + +usage() { + echo "usage: $0 [-q|--quiet] [-v|--verbose] [--] [repo_base_path]" > ${status_output} + exit 1 +} + + +if [ "x" = "x$command" ] ; then + echo "ERROR: No command to hg supplied!" + usage fi # Clean out the temporary directory that stores the pid files. @@ -40,17 +81,17 @@ mkdir -p ${tmp} safe_interrupt () { if [ -d ${tmp} ]; then if [ "`ls ${tmp}/*.pid`" != "" ]; then - echo "Waiting for processes ( `cat ${tmp}/*.pid | tr '\n' ' '`) to terminate nicely!" + echo "Waiting for processes ( `cat ${tmp}/*.pid | tr '\n' ' '`) to terminate nicely!" > ${status_output} sleep 1 # Pipe stderr to dev/null to silence kill, that complains when trying to kill # a subprocess that has already exited. kill -TERM `cat ${tmp}/*.pid | tr '\n' ' '` 2> /dev/null wait - echo Interrupt complete! + echo "Interrupt complete!" > ${status_output} fi + rm -f -r ${tmp} fi - rm -f -r ${tmp} - exit 1 + exit 130 } nice_exit () { @@ -58,28 +99,30 @@ nice_exit () { if [ "`ls ${tmp}`" != "" ]; then wait fi + rm -f -r ${tmp} fi - rm -f -r ${tmp} } trap 'safe_interrupt' INT QUIT trap 'nice_exit' EXIT +subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" +subrepos_extra="closed jdk/src/closed jdk/make/closed jdk/test/closed hotspot/make/closed hotspot/src/closed hotspot/test/closed deploy install sponsors pubs" + # Only look in specific locations for possible forests (avoids long searches) pull_default="" repos="" repos_extra="" if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - subrepos="corba jaxp jaxws langtools jdk hotspot nashorn" if [ -f .hg/hgrc ] ; then pull_default=`hg paths default` if [ "${pull_default}" = "" ] ; then - echo "ERROR: Need initial clone with 'hg paths default' defined" + echo "ERROR: Need initial clone with 'hg paths default' defined" > ${status_output} exit 1 fi fi if [ "${pull_default}" = "" ] ; then - echo "ERROR: Need initial repository to use this script" + echo "ERROR: Need initial repository to use this script" > ${status_output} exit 1 fi for i in ${subrepos} ; do @@ -87,10 +130,9 @@ if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then repos="${repos} ${i}" fi done - if [ "${pull_extra_base}" != "" ] ; then - subrepos_extra="closed jdk/src/closed jdk/make/closed jdk/test/closed hotspot/make/closed hotspot/src/closed hotspot/test/closed deploy install sponsors pubs" + if [ "${repo_base}" != "" ] ; then pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'` - pull_extra="${pull_extra_base}/${pull_default_tail}" + pull_extra="${repo_base}/${pull_default_tail}" for i in ${subrepos_extra} ; do if [ ! -f ${i}/.hg/hgrc ] ; then repos_extra="${repos_extra} ${i}" @@ -100,78 +142,111 @@ if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then at_a_time=2 # Any repos to deal with? if [ "${repos}" = "" -a "${repos_extra}" = "" ] ; then + echo "No repositories to process." > ${status_output} exit fi else - hgdirs=`ls -d ./.hg ./*/.hg ./*/*/.hg ./*/*/*/.hg ./*/*/*/*/.hg 2>/dev/null` - # Derive repository names from the .hg directory locations - for i in ${hgdirs} ; do - repos="${repos} `echo ${i} | sed -e 's@/.hg$@@'`" + for i in . ${subrepos} ${subrepos_extra} ; do + if [ -d ${i}/.hg ] ; then + repos="${repos} ${i}" + fi done + + # Any repos to deal with? + if [ "${repos}" = "" ] ; then + echo "No repositories to process." > ${status_output} + exit + fi + + # any of the repos locked? for i in ${repos} ; do if [ -h ${i}/.hg/store/lock -o -f ${i}/.hg/store/lock ] ; then locked="${i} ${locked}" fi done - at_a_time=8 - # Any repos to deal with? - if [ "${repos}" = "" ] ; then - echo "No repositories to process." - exit - fi if [ "${locked}" != "" ] ; then - echo "These repositories are locked: ${locked}" - exit + echo "ERROR: These repositories are locked: ${locked}" > ${status_output} + exit 1 fi + at_a_time=8 fi # Echo out what repositories we do a command on. -echo "# Repositories: ${repos} ${repos_extra}" -echo +echo "# Repositories: ${repos} ${repos_extra}" > ${status_output} -# Run the supplied command on all repos in parallel. -n=0 -for i in ${repos} ${repos_extra} ; do - n=`expr ${n} '+' 1` - repopidfile=`echo ${i} | sed -e 's@./@@' -e 's@/@_@g'` - reponame=`echo ${i} | sed -e :a -e 's/^.\{1,20\}$/ &/;ta'` - pull_base="${pull_default}" - for j in $repos_extra ; do +if [ "${command}" = "serve" ] ; then + # "serve" is run for all the repos. + ( + ( + ( + echo "[web]" + echo "description = $(basename $(pwd))" + echo "allow_push = *" + echo "push_ssl = False" + + echo "[paths]" + for i in ${repos} ${repos_extra} ; do + if [ "${i}" != "." ] ; then + echo "/$(basename $(pwd))/${i} = ${i}" + else + echo "/$(basename $(pwd)) = $(pwd)" + fi + done + ) > ${tmp}/serve.web-conf + + echo "serving root repo $(basename $(pwd))" + + (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 & + ) 2>&1 | sed -e "s@^@serve: @" > ${status_output} + ) & +else + # Run the supplied command on all repos in parallel. + n=0 + for i in ${repos} ${repos_extra} ; do + n=`expr ${n} '+' 1` + repopidfile=`echo ${i} | sed -e 's@./@@' -e 's@/@_@g'` + reponame=`echo ${i} | sed -e :a -e 's/^.\{1,20\}$/ &/;ta'` + pull_base="${pull_default}" + for j in $repos_extra ; do if [ "$i" = "$j" ] ; then pull_base="${pull_extra}" fi - done - ( + done ( - if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - pull_newrepo="`echo ${pull_base}/${i} | sed -e 's@\([^:]/\)//*@\1@g'`" - echo hg clone ${pull_newrepo} ${i} - path="`dirname ${i}`" - if [ "${path}" != "." ] ; then - times=0 - while [ ! -d "${path}" ] ## nested repo, ensure containing dir exists - do - times=`expr ${times} '+' 1` - if [ `expr ${times} '%' 10` -eq 0 ] ; then - echo ${path} still not created, waiting... - fi - sleep 5 - done + ( + if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then + pull_newrepo="`echo ${pull_base}/${i} | sed -e 's@\([^:]/\)//*@\1@g'`" + echo "hg clone ${pull_newrepo} ${i}" > ${status_output} + path="`dirname ${i}`" + if [ "${path}" != "." ] ; then + times=0 + while [ ! -d "${path}" ] ## nested repo, ensure containing dir exists + do + times=`expr ${times} '+' 1` + if [ `expr ${times} '%' 10` -eq 0 ] ; then + echo "${path} still not created, waiting..." > ${status_output} + fi + sleep 5 + done + fi + (PYTHONUNBUFFERED=true hg${global_opts} clone ${pull_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & + else + echo "cd ${i} && hg${global_opts} ${command} ${repo_base}" > ${status_output} + cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} ${command_repo}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & fi - (PYTHONUNBUFFERED=true hg clone ${pull_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc )& - else - echo "cd ${i} && hg $*" - cd ${i} && (PYTHONUNBUFFERED=true hg "$@"; echo "$?" > ${tmp}/${repopidfile}.pid.rc )& - fi - echo $! > ${tmp}/${repopidfile}.pid - ) 2>&1 | sed -e "s@^@${reponame}: @") & - if [ `expr ${n} '%' ${at_a_time}` -eq 0 ] ; then - sleep 2 - echo Waiting 5 secs before spawning next background command. - sleep 3 - fi -done + echo $! > ${tmp}/${repopidfile}.pid + ) 2>&1 | sed -e "s@^@${reponame}: @" > ${status_output} + ) & + + if [ `expr ${n} '%' ${at_a_time}` -eq 0 ] ; then + sleep 2 + echo "Waiting 5 secs before spawning next background command." > ${status_output} + sleep 3 + fi + done +fi + # Wait for all hg commands to complete wait @@ -181,7 +256,8 @@ if [ -d ${tmp} ]; then for rc in ${tmp}/*.pid.rc ; do exit_code=`cat ${rc} | tr -d ' \n\r'` if [ "${exit_code}" != "0" ] ; then - echo "WARNING: ${rc} exited abnormally." + repo="`echo ${rc} | sed -e s@^${tmp}@@ -e 's@/*\([^/]*\)\.pid\.rc$@\1@' -e 's@_@/@g'`" + echo "WARNING: ${repo} exited abnormally." > ${status_output} ec=1 fi done From 04e8f324514a0f4c4ee8d61bcdfd201b2abc5af8 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 24 Mar 2014 17:44:27 -0700 Subject: [PATCH 073/170] 8038286: nm->set_rtm_state() should be called after (nm != NULL) check Move set_rtm_state() call after (nm != NULL) check Reviewed-by: iveresov, twisti --- hotspot/src/share/vm/ci/ciEnv.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 36a46f271a3..9da5f98ded5 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -1038,15 +1038,15 @@ void ciEnv::register_method(ciMethod* target, frame_words, oop_map_set, handler_table, inc_table, compiler, comp_level); -#if INCLUDE_RTM_OPT - nm->set_rtm_state(rtm_state); -#endif // Free codeBlobs code_buffer->free_blob(); if (nm != NULL) { nm->set_has_unsafe_access(has_unsafe_access); nm->set_has_wide_vectors(has_wide_vectors); +#if INCLUDE_RTM_OPT + nm->set_rtm_state(rtm_state); +#endif // Record successful registration. // (Put nm into the task handle *before* publishing to the Java heap.) From ddc2f91ab4f354f9b687723669f0475a6e75be54 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Mon, 24 Mar 2014 23:13:46 -0700 Subject: [PATCH 074/170] 8038222: Assembler::bsrl fails on assert when -UseCountLeadingZerosInstruction is used on CPU with LZCNT support Remove the overly strict assert Reviewed-by: kvn, twisti --- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 4de27ac6770..2fc29eae21e 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -1112,7 +1112,6 @@ void Assembler::bsfl(Register dst, Register src) { } void Assembler::bsrl(Register dst, Register src) { - assert(!VM_Version::supports_lzcnt(), "encoding is treated as LZCNT"); int encode = prefix_and_encode(dst->encoding(), src->encoding()); emit_int8(0x0F); emit_int8((unsigned char)0xBD); @@ -4977,7 +4976,6 @@ void Assembler::bsfq(Register dst, Register src) { } void Assembler::bsrq(Register dst, Register src) { - assert(!VM_Version::supports_lzcnt(), "encoding is treated as LZCNT"); int encode = prefixq_and_encode(dst->encoding(), src->encoding()); emit_int8(0x0F); emit_int8((unsigned char)0xBD); From ac75d4fc2fb3fbe6e71f31f7463657f50d2ebd20 Mon Sep 17 00:00:00 2001 From: Lutz Schmidt Date: Tue, 25 Mar 2014 12:54:21 -0700 Subject: [PATCH 075/170] 8037821: Account for trampoline stubs when estimating code buffer sizes Take into account space needed for "trampoline code" used by calls on PPC64. Reviewed-by: kvn --- hotspot/src/cpu/ppc/vm/ppc.ad | 103 +++++++++++----- hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 7 +- hotspot/src/cpu/sparc/vm/sparc.ad | 64 +++++++--- hotspot/src/cpu/x86/vm/x86.ad | 118 +++++++++++++++++++ hotspot/src/cpu/x86/vm/x86_32.ad | 53 --------- hotspot/src/cpu/x86/vm/x86_64.ad | 59 +--------- hotspot/src/share/vm/opto/output.cpp | 25 ++-- 7 files changed, 255 insertions(+), 174 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 9c3f40a6303..2989ca5167d 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -891,6 +891,13 @@ definitions %{ // This is a block of C++ code which provides values, functions, and // definitions necessary in the rest of the architecture description. source_hpp %{ + // Header information of the source block. + // Method declarations/definitions which are used outside + // the ad-scope can conveniently be defined here. + // + // To keep related declarations/definitions/uses close together, + // we switch between source %{ }% and source_hpp %{ }% freely as needed. + // Returns true if Node n is followed by a MemBar node that // will do an acquire. If so, this node must not do the acquire // operation. @@ -1114,6 +1121,40 @@ static inline void emit_long(CodeBuffer &cbuf, int value) { //============================================================================= +%} // interrupt source + +source_hpp %{ // Header information of the source block. + +//-------------------------------------------------------------- +//---< Used for optimization in Compile::Shorten_branches >--- +//-------------------------------------------------------------- + +const uint trampoline_stub_size = 6 * BytesPerInstWord; + +class CallStubImpl { + + public: + + static void emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset); + + // Size of call trampoline stub. + // This doesn't need to be accurate to the byte, but it + // must be larger than or equal to the real size of the stub. + static uint size_call_trampoline() { + return trampoline_stub_size; + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 5; + } + +}; + +%} // end source_hpp + +source %{ + // Emit a trampoline stub for a call to a target which is too far away. // // code sequences: @@ -1125,9 +1166,7 @@ static inline void emit_long(CodeBuffer &cbuf, int value) { // load the call target from the constant pool // branch via CTR (LR/link still points to the call-site above) -const uint trampoline_stub_size = 6 * BytesPerInstWord; - -void emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { +void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { // Start the stub. address stub = __ start_a_stub(Compile::MAX_stubs_size/2); if (stub == NULL) { @@ -1170,19 +1209,6 @@ void emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int __ end_a_stub(); } -// Size of trampoline stub, this doesn't need to be accurate but it must -// be larger or equal to the real size of the stub. -// Used for optimization in Compile::Shorten_branches. -uint size_call_trampoline() { - return trampoline_stub_size; -} - -// Number of relocation entries needed by trampoline stub. -// Used for optimization in Compile::Shorten_branches. -uint reloc_call_trampoline() { - return 5; -} - //============================================================================= // Emit an inline branch-and-link call and a related trampoline stub. @@ -1221,7 +1247,7 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. - emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset); __ relocate(rtype); } @@ -2023,17 +2049,34 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const { //============================================================================= -uint size_exception_handler() { - // The exception_handler is a b64_patchable. - return MacroAssembler::b64_patchable_size; -} +%} // interrupt source -uint size_deopt_handler() { - // The deopt_handler is a bl64_patchable. - return MacroAssembler::bl64_patchable_size; -} +source_hpp %{ // Header information of the source block. -int emit_exception_handler(CodeBuffer &cbuf) { +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + // The exception_handler is a b64_patchable. + return MacroAssembler::b64_patchable_size; + } + + static uint size_deopt_handler() { + // The deopt_handler is a bl64_patchable. + return MacroAssembler::bl64_patchable_size; + } + +}; + +%} // end source_hpp + +source %{ + +int HandlerImpl::emit_exception_handler(CodeBuffer &cbuf) { MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); @@ -2050,7 +2093,7 @@ int emit_exception_handler(CodeBuffer &cbuf) { // The deopt_handler is like the exception handler, but it calls to // the deoptimization blob instead of jumping to the exception blob. -int emit_deopt_handler(CodeBuffer& cbuf) { +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); @@ -3438,7 +3481,7 @@ encode %{ const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. - emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); __ relocate(_optimized_virtual ? relocInfo::opt_virtual_call_type : relocInfo::static_call_type); } @@ -3481,7 +3524,7 @@ encode %{ const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. - emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); assert(_optimized_virtual, "methodHandle call should be a virtual call"); __ relocate(relocInfo::opt_virtual_call_type); } @@ -3531,7 +3574,7 @@ encode %{ const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method; const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none); const int entry_point_const_toc_offset = __ offset_to_method_toc(entry_point_const); - emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset()); + CallStubImpl::emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset()); if (ra_->C->env()->failing()) return; diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index d556d7009fa..15a5812e881 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -34,6 +34,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" #include "vmreg_ppc.inline.hpp" +#include "adfiles/ad_ppc_64.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif @@ -52,10 +53,6 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -// Used by generate_deopt_blob. Defined in .ad file. -extern uint size_deopt_handler(); - - class RegisterSaver { // Used for saving volatile registers. public: @@ -2782,7 +2779,7 @@ void SharedRuntime::generate_deopt_blob() { // We can't grab a free register here, because all registers may // contain live values, so let the RegisterSaver do the adjustment // of the return pc. - const int return_pc_adjustment_no_exception = -size_deopt_handler(); + const int return_pc_adjustment_no_exception = -HandlerImpl::size_deopt_handler(); // Push the "unpack frame" // Save everything in sight. diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 15b5c7b524f..4a3a33dfd87 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -457,6 +457,13 @@ definitions %{ // This is a block of C++ code which provides values, functions, and // definitions necessary in the rest of the architecture description source_hpp %{ +// Header information of the source block. +// Method declarations/definitions which are used outside +// the ad-scope can conveniently be defined here. +// +// To keep related declarations/definitions/uses close together, +// we switch between source %{ }% and source_hpp %{ }% freely as needed. + // Must be visible to the DFA in dfa_sparc.cpp extern bool can_branch_register( Node *bol, Node *cmp ); @@ -468,6 +475,46 @@ extern bool use_block_zeroing(Node* count); #define LONG_HI_REG(x) (x) #define LONG_LO_REG(x) (x) +class CallStubImpl { + + //-------------------------------------------------------------- + //---< Used for optimization in Compile::Shorten_branches >--- + //-------------------------------------------------------------- + + public: + // Size of call trampoline stub. + static uint size_call_trampoline() { + return 0; // no call trampolines on this platform + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 0; // no call trampolines on this platform + } +}; + +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + if (TraceJumps) { + return (400); // just a guess + } + return ( NativeJump::instruction_size ); // sethi;jmp;nop + } + + static uint size_deopt_handler() { + if (TraceJumps) { + return (400); // just a guess + } + return ( 4+ NativeJump::instruction_size ); // save;sethi;jmp;restore + } +}; + %} source %{ @@ -1710,22 +1757,9 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const { //============================================================================= -uint size_exception_handler() { - if (TraceJumps) { - return (400); // just a guess - } - return ( NativeJump::instruction_size ); // sethi;jmp;nop -} - -uint size_deopt_handler() { - if (TraceJumps) { - return (400); // just a guess - } - return ( 4+ NativeJump::instruction_size ); // save;sethi;jmp;restore -} // Emit exception handler code. -int emit_exception_handler(CodeBuffer& cbuf) { +int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { Register temp_reg = G3; AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point()); MacroAssembler _masm(&cbuf); @@ -1746,7 +1780,7 @@ int emit_exception_handler(CodeBuffer& cbuf) { return offset; } -int emit_deopt_handler(CodeBuffer& cbuf) { +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { // Can't use any of the current frame's registers as we may have deopted // at a poll and everything (including G3) can be live. Register temp_reg = L0; diff --git a/hotspot/src/cpu/x86/vm/x86.ad b/hotspot/src/cpu/x86/vm/x86.ad index b0077a5f58c..b575a98a816 100644 --- a/hotspot/src/cpu/x86/vm/x86.ad +++ b/hotspot/src/cpu/x86/vm/x86.ad @@ -474,7 +474,125 @@ reg_class vectory_reg(XMM0, XMM0b, XMM0c, XMM0d, XMM0e, XMM0f, XMM0g, XMM %} + +//----------SOURCE BLOCK------------------------------------------------------- +// This is a block of C++ code which provides values, functions, and +// definitions necessary in the rest of the architecture description + +source_hpp %{ +// Header information of the source block. +// Method declarations/definitions which are used outside +// the ad-scope can conveniently be defined here. +// +// To keep related declarations/definitions/uses close together, +// we switch between source %{ }% and source_hpp %{ }% freely as needed. + +class CallStubImpl { + + //-------------------------------------------------------------- + //---< Used for optimization in Compile::shorten_branches >--- + //-------------------------------------------------------------- + + public: + // Size of call trampoline stub. + static uint size_call_trampoline() { + return 0; // no call trampolines on this platform + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 0; // no call trampolines on this platform + } +}; + +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + // NativeCall instruction size is the same as NativeJump. + // exception handler starts out as jump and can be patched to + // a call be deoptimization. (4932387) + // Note that this value is also credited (in output.cpp) to + // the size of the code section. + return NativeJump::instruction_size; + } + +#ifdef _LP64 + static uint size_deopt_handler() { + // three 5 byte instructions + return 15; + } +#else + static uint size_deopt_handler() { + // NativeCall instruction size is the same as NativeJump. + // exception handler starts out as jump and can be patched to + // a call be deoptimization. (4932387) + // Note that this value is also credited (in output.cpp) to + // the size of the code section. + return 5 + NativeJump::instruction_size; // pushl(); jmp; + } +#endif +}; + +%} // end source_hpp + source %{ + +// Emit exception handler code. +// Stuff framesize into a register and call a VM stub routine. +int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { + + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a handler. + MacroAssembler _masm(&cbuf); + address base = __ start_a_stub(size_exception_handler()); + if (base == NULL) return 0; // CodeBuffer::expand failed + int offset = __ offset(); + __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); + assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); + __ end_a_stub(); + return offset; +} + +// Emit deopt handler code. +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { + + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a handler. + MacroAssembler _masm(&cbuf); + address base = __ start_a_stub(size_deopt_handler()); + if (base == NULL) return 0; // CodeBuffer::expand failed + int offset = __ offset(); + +#ifdef _LP64 + address the_pc = (address) __ pc(); + Label next; + // push a "the_pc" on the stack without destroying any registers + // as they all may be live. + + // push address of "next" + __ call(next, relocInfo::none); // reloc none is fine since it is a disp32 + __ bind(next); + // adjust it so it matches "the_pc" + __ subptr(Address(rsp, 0), __ offset() - offset); +#else + InternalAddress here(__ pc()); + __ pushptr(here.addr()); +#endif + + __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); + assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); + __ end_a_stub(); + return offset; +} + + +//============================================================================= + // Float masks come from different places depending on platform. #ifdef _LP64 static address float_signmask() { return StubRoutines::x86::float_sign_mask(); } diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 6a377b89401..cd4b7c730ca 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1297,59 +1297,6 @@ uint MachUEPNode::size(PhaseRegAlloc *ra_) const { //============================================================================= -uint size_exception_handler() { - // NativeCall instruction size is the same as NativeJump. - // exception handler starts out as jump and can be patched to - // a call be deoptimization. (4932387) - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return NativeJump::instruction_size; -} - -// Emit exception handler code. Stuff framesize into a register -// and call a VM stub routine. -int emit_exception_handler(CodeBuffer& cbuf) { - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); - assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); - __ end_a_stub(); - return offset; -} - -uint size_deopt_handler() { - // NativeCall instruction size is the same as NativeJump. - // exception handler starts out as jump and can be patched to - // a call be deoptimization. (4932387) - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return 5 + NativeJump::instruction_size; // pushl(); jmp; -} - -// Emit deopt handler code. -int emit_deopt_handler(CodeBuffer& cbuf) { - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - InternalAddress here(__ pc()); - __ pushptr(here.addr()); - - __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); - assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); - __ end_a_stub(); - return offset; -} int Matcher::regnum_to_fpu_offset(int regnum) { return regnum - 32; // The FP registers are in the second chunk diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index cd898026b06..2a0e29900b9 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -1439,66 +1439,9 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const return MachNode::size(ra_); // too many variables; just compute it // the hard way } - + //============================================================================= -uint size_exception_handler() -{ - // NativeCall instruction size is the same as NativeJump. - // Note that this value is also credited (in output.cpp) to - // the size of the code section. - return NativeJump::instruction_size; -} - -// Emit exception handler code. -int emit_exception_handler(CodeBuffer& cbuf) -{ - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); - assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); - __ end_a_stub(); - return offset; -} - -uint size_deopt_handler() -{ - // three 5 byte instructions - return 15; -} - -// Emit deopt handler code. -int emit_deopt_handler(CodeBuffer& cbuf) -{ - - // Note that the code buffer's insts_mark is always relative to insts. - // That's why we must use the macroassembler to generate a handler. - MacroAssembler _masm(&cbuf); - address base = - __ start_a_stub(size_deopt_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed - int offset = __ offset(); - address the_pc = (address) __ pc(); - Label next; - // push a "the_pc" on the stack without destroying any registers - // as they all may be live. - - // push address of "next" - __ call(next, relocInfo::none); // reloc none is fine since it is a disp32 - __ bind(next); - // adjust it so it matches "the_pc" - __ subptr(Address(rsp, 0), __ offset() - offset); - __ jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); - assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); - __ end_a_stub(); - return offset; -} int Matcher::regnum_to_fpu_offset(int regnum) { diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 48117ea14fe..debf13693f2 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -42,18 +42,12 @@ #include "runtime/handles.inline.hpp" #include "utilities/xmlstream.hpp" -extern uint size_exception_handler(); -extern uint size_deopt_handler(); - #ifndef PRODUCT #define DEBUG_ARG(x) , x #else #define DEBUG_ARG(x) #endif -extern int emit_exception_handler(CodeBuffer &cbuf); -extern int emit_deopt_handler(CodeBuffer &cbuf); - // Convert Nodes to instruction bits and pass off to the VM void Compile::Output() { // RootNode goes @@ -394,6 +388,11 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding reloc_size += mach->reloc(); if (mach->is_MachCall()) { + // add size information for trampoline stub + // class CallStubImpl is platform-specific and defined in the *.ad files. + stub_size += CallStubImpl::size_call_trampoline(); + reloc_size += CallStubImpl::reloc_call_trampoline(); + MachCallNode *mcall = mach->as_MachCall(); // This destination address is NOT PC-relative @@ -1133,10 +1132,9 @@ CodeBuffer* Compile::init_buffer(uint* blk_starts) { shorten_branches(blk_starts, code_req, locs_req, stub_req); // nmethod and CodeBuffer count stubs & constants as part of method's code. - int exception_handler_req = size_exception_handler(); - int deopt_handler_req = size_deopt_handler(); - exception_handler_req += MAX_stubs_size; // add marginal slop for handler - deopt_handler_req += MAX_stubs_size; // add marginal slop for handler + // class HandlerImpl is platform-specific and defined in the *.ad files. + int exception_handler_req = HandlerImpl::size_exception_handler() + MAX_stubs_size; // add marginal slop for handler + int deopt_handler_req = HandlerImpl::size_deopt_handler() + MAX_stubs_size; // add marginal slop for handler stub_req += MAX_stubs_size; // ensure per-stub margin code_req += MAX_inst_size; // ensure per-instruction margin @@ -1622,17 +1620,18 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { FillExceptionTables(inct_cnt, call_returns, inct_starts, blk_labels); // Only java methods have exception handlers and deopt handlers + // class HandlerImpl is platform-specific and defined in the *.ad files. if (_method) { // Emit the exception handler code. - _code_offsets.set_value(CodeOffsets::Exceptions, emit_exception_handler(*cb)); + _code_offsets.set_value(CodeOffsets::Exceptions, HandlerImpl::emit_exception_handler(*cb)); // Emit the deopt handler code. - _code_offsets.set_value(CodeOffsets::Deopt, emit_deopt_handler(*cb)); + _code_offsets.set_value(CodeOffsets::Deopt, HandlerImpl::emit_deopt_handler(*cb)); // Emit the MethodHandle deopt handler code (if required). if (has_method_handle_invokes()) { // We can use the same code as for the normal deopt handler, we // just need a different entry point address. - _code_offsets.set_value(CodeOffsets::DeoptMH, emit_deopt_handler(*cb)); + _code_offsets.set_value(CodeOffsets::DeoptMH, HandlerImpl::emit_deopt_handler(*cb)); } } From da71a6dd96126a962f6d9c1038a4c952d4b3de6b Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Tue, 25 Mar 2014 22:07:55 -0700 Subject: [PATCH 076/170] 8031625: javadoc problems referencing inner class constructors Reviewed-by: jjg --- .../formats/html/HtmlDocletWriter.java | 5 +-- .../com/sun/tools/javadoc/SeeTagImpl.java | 5 +-- .../testConstructors/TestConstructors.java | 31 +++++++++++++++++-- .../javadoc/testConstructors/pkg1/Outer.java | 13 +++++++- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java index bccbba16322..ff4da111a8e 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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 @@ -1443,7 +1443,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { } } if (configuration.currentcd != containing) { - refMemName = containing.name() + "." + refMemName; + refMemName = (refMem instanceof ConstructorDoc) ? + refMemName : containing.name() + "." + refMemName; } if (refMem instanceof ExecutableMemberDoc) { if (refMemName.indexOf('(') < 0) { diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java index 03abe7ba117..a5e79118da8 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/SeeTagImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -398,7 +398,8 @@ class SeeTagImpl extends TagImpl implements SeeTag, LayoutCharacters { private MemberDoc findExecutableMember(String memName, String[] paramarr, ClassDoc referencedClass) { - if (memName.equals(referencedClass.name())) { + String className = referencedClass.name(); + if (memName.equals(className.substring(className.lastIndexOf(".") + 1))) { return ((ClassDocImpl)referencedClass).findConstructor(memName, paramarr); } else { // it's a method. diff --git a/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java b/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java index 90524af51af..52cebb631e7 100644 --- a/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java +++ b/langtools/test/com/sun/javadoc/testConstructors/TestConstructors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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,7 +23,7 @@ /* * @test - * @bug 8025524 + * @bug 8025524 8031625 * @summary Test for constructor name which should be a non-qualified name. * @author Bhavesh Patel * @library ../lib/ @@ -37,6 +37,21 @@ public class TestConstructors extends JavadocTester { //Input for string search tests. private static final String[][] TEST = { + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "
See Also:
" + NL + + "
Inner(), " + NL + + "Inner(int), " + NL + + "NestedInner(), " + NL + + "NestedInner(int), " + NL + + "Outer(), " + NL + + "Outer(int)" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Link: Inner(), " + + "Outer(int), " + + "" + + "NestedInner(int)" + }, {BUG_ID + FS + "pkg1" + FS + "Outer.html", "Outer()" }, @@ -87,6 +102,18 @@ public class TestConstructors extends JavadocTester { }, {BUG_ID + FS + "pkg1" + FS + "Outer.Inner.NestedInner.html", "Outer.Inner.NestedInner-int-" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner()" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner(int)" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner.NestedInner()" + }, + {BUG_ID + FS + "pkg1" + FS + "Outer.html", + "Outer.Inner.NestedInner(int)" } }; diff --git a/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java b/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java index 7cf5ef63bb2..9d8f76fefb9 100644 --- a/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java +++ b/langtools/test/com/sun/javadoc/testConstructors/pkg1/Outer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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,17 @@ package pkg1; +/** + * Test link tag. + * Link: {@link pkg1.Outer.Inner#Inner()}, {@link pkg1.Outer#Outer(int)}, {@link pkg1.Outer.Inner.NestedInner#NestedInner(int)} + * + * @see Outer.Inner#Inner() + * @see Outer.Inner#Inner(int) + * @see Outer.Inner.NestedInner#NestedInner() + * @see Outer.Inner.NestedInner#NestedInner(int) + * @see Outer#Outer() + * @see Outer#Outer(int) + */ public class Outer { /** From 24400e17453c53c39f7fbb4ce1a19bdb36ac2317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Borggr=C3=A9n-Franck?= Date: Wed, 26 Mar 2014 12:18:11 +0100 Subject: [PATCH 077/170] 8038080: annotation processors don't visit declaration parameter annotations Co-authored-by: Liam Miller-Cushon Reviewed-by: darcy --- .../JavacProcessingEnvironment.java | 4 +- .../processing/JavacRoundEnvironment.java | 4 +- .../ProcessingEnvAnnoDiscovery.java | 78 +++++++++++++++++++ .../processing/environment/round/Anno.java | 28 +++++++ .../round/ParameterAnnotations.java | 33 ++++++++ .../round/TestElementsAnnotatedWith.java | 4 +- 6 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java create mode 100644 langtools/test/tools/javac/processing/environment/round/Anno.java create mode 100644 langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 1f48ab27287..c53a60d73e7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -761,14 +761,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea public Set visitType(TypeElement e, Set p) { // Type parameters are not considered to be enclosed by a type scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitType(e, p); } @Override public Set visitExecutable(ExecutableElement e, Set p) { // Type parameters are not considered to be enclosed by an executable scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitExecutable(e, p); } void addAnnotations(Element e, Set p) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java index 1b1ec416e6a..d41c6241e30 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java @@ -137,14 +137,14 @@ public class JavacRoundEnvironment implements RoundEnvironment { public Set visitType(TypeElement e, TypeElement p) { // Type parameters are not considered to be enclosed by a type scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitType(e, p); } @Override public Set visitExecutable(ExecutableElement e, TypeElement p) { // Type parameters are not considered to be enclosed by an executable scan(e.getTypeParameters(), p); - return scan(e.getEnclosedElements(), p); + return super.visitExecutable(e, p); } @Override diff --git a/langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java b/langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java new file mode 100644 index 00000000000..ef2721f83f5 --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/ProcessingEnvAnnoDiscovery.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8038080 + * @summary make sure that all declaration annotations are discovered + * by the processing environment + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor ProcessingEnvAnnoDiscovery + * @compile/process -processor ProcessingEnvAnnoDiscovery ProcessingEnvAnnoDiscovery.java + */ + +import java.lang.annotation.*; +import java.util.Set; +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +import com.sun.tools.javac.util.*; + +@ProcessingEnvAnnoDiscovery.Anno1 +public class ProcessingEnvAnnoDiscovery<@ProcessingEnvAnnoDiscovery.Anno4 T> + extends JavacTestingAbstractProcessor { + private int round = 0; + + public boolean process(Set annos, RoundEnvironment rEnv) { + if (round++ == 0) { + System.out.println(annos); + Assert.check(annos.contains(eltUtils.getTypeElement("java.lang.annotation.Target"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno1"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno2"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno3"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno4"))); + Assert.check(annos.contains(eltUtils.getTypeElement("ProcessingEnvAnnoDiscovery.Anno5"))); + Assert.check(annos.size() == 6, "Found extra annotations"); //Anno1-5 + @Target + } + + return true; + } + + @Anno2 + public <@Anno5 K> K m(@Anno3 long foo) { + return null; + } + + @interface Anno1 {} + + @interface Anno2 {} + + @interface Anno3 {} + + @Target(ElementType.TYPE_PARAMETER) + @interface Anno4 {} + + @Target(ElementType.TYPE_PARAMETER) + @interface Anno5 {} + +} diff --git a/langtools/test/tools/javac/processing/environment/round/Anno.java b/langtools/test/tools/javac/processing/environment/round/Anno.java new file mode 100644 index 00000000000..366b489e07b --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/round/Anno.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.lang.annotation.*; +import static java.lang.annotation.RetentionPolicy.*; + +@Retention(RUNTIME) +public @interface Anno {} diff --git a/langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java b/langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java new file mode 100644 index 00000000000..a4433e352e0 --- /dev/null +++ b/langtools/test/tools/javac/processing/environment/round/ParameterAnnotations.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * Class to hold annotations for ElementsAnnotatedWithTest. + */ + +@AnnotatedElementInfo(annotationName="Anno", + expectedSize=1, + names={"annotatedParameter"}) +public class ParameterAnnotations { + private void foo(@Anno Object annotatedParameter) {} +} diff --git a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java index 3a020060d22..398b2f530df 100644 --- a/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java +++ b/langtools/test/tools/javac/processing/environment/round/TestElementsAnnotatedWith.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854 8030049 + * @bug 6397298 6400986 6425592 6449798 6453386 6508401 6498938 6911854 8030049 8038080 * @summary Tests that getElementsAnnotatedWith works properly. * @author Joseph D. Darcy * @library /tools/javac/lib @@ -31,12 +31,14 @@ * @compile TestElementsAnnotatedWith.java * @compile InheritedAnnotation.java * @compile TpAnno.java + * @compile Anno.java * @compile -processor TestElementsAnnotatedWith -proc:only SurfaceAnnotations.java * @compile -processor TestElementsAnnotatedWith -proc:only BuriedAnnotations.java * @compile -processor TestElementsAnnotatedWith -proc:only Part1.java Part2.java * @compile -processor TestElementsAnnotatedWith -proc:only C2.java * @compile -processor TestElementsAnnotatedWith -proc:only Foo.java * @compile -processor TestElementsAnnotatedWith -proc:only TypeParameterAnnotations.java + * @compile -processor TestElementsAnnotatedWith -proc:only ParameterAnnotations.java * @compile/fail/ref=ErroneousAnnotations.out -processor TestElementsAnnotatedWith -proc:only -XDrawDiagnostics ErroneousAnnotations.java * @compile Foo.java * @compile/process -processor TestElementsAnnotatedWith -proc:only Foo From 98d8c513894cb97039ee5344fc0bc2f22e498c6a Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Wed, 26 Mar 2014 16:33:13 +0100 Subject: [PATCH 078/170] 8027924: gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java fails with warning Reviewed-by: jmasa, tschatzl --- .../gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java b/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java index 8152a9eb1ca..489ae411669 100644 --- a/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java +++ b/hotspot/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java @@ -26,7 +26,7 @@ * @bug 8004924 * @summary Checks that jmap -heap contains the flag CompressedClassSpaceSize * @library /testlibrary - * @run main/othervm -XX:CompressedClassSpaceSize=50m CompressedClassSpaceSizeInJmapHeap + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompressedClassSpaceSize=50m CompressedClassSpaceSizeInJmapHeap */ import com.oracle.java.testlibrary.*; @@ -37,6 +37,11 @@ import java.util.List; public class CompressedClassSpaceSizeInJmapHeap { public static void main(String[] args) throws Exception { + if (!Platform.is64bit()) { + // Compressed Class Space is only available on 64-bit JVMs + return; + } + String pid = Integer.toString(ProcessTools.getProcessId()); JDKToolLauncher jmap = JDKToolLauncher.create("jmap") From 3eb793cd06e4335757c739b037fcb8d835e7e670 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 26 Mar 2014 10:47:30 -0700 Subject: [PATCH 079/170] 8035956: javac, incomplete error message Reviewed-by: vromero --- .../classes/com/sun/tools/javac/comp/Check.java | 2 +- .../IncompleteMessageOverride.java | 16 ++++++++++++++++ .../OverrideChecks/IncompleteMessageOverride.out | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java create mode 100644 langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 1bec67e8a0c..0e0f0c59a70 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -1625,7 +1625,7 @@ public class Check { protection(m.flags()) > protection(other.flags())) { log.error(TreeInfo.diagnosticPositionFor(m, tree), "override.weaker.access", cannotOverride(m, other), - other.flags() == 0 ? + (other.flags() & AccessFlags) == 0 ? "package" : asFlagSet(other.flags() & AccessFlags)); m.flags_field |= BAD_OVERRIDE; diff --git a/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java new file mode 100644 index 00000000000..8369c66fb7a --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.java @@ -0,0 +1,16 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8035956 + * @summary javac, incomplete error message + * @author kizune + * + * @run compile/fail/ref=IncompleteMessageOverride.out -XDrawDiagnostics IncompleteMessageOverride.java + */ + +class Super { + static void m() {} +} + +class Sub extends Super { + private static void m() {} +} diff --git a/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out new file mode 100644 index 00000000000..62cab888c9e --- /dev/null +++ b/langtools/test/tools/javac/OverrideChecks/IncompleteMessageOverride.out @@ -0,0 +1,2 @@ +IncompleteMessageOverride.java:15:25: compiler.err.override.weaker.access: (compiler.misc.cant.override: m(), Sub, m(), Super), package +1 error From 60eff958b1884488cb90dd1dd33065b3a1ea7d10 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Wed, 26 Mar 2014 16:56:58 -0700 Subject: [PATCH 080/170] 8038435: Some hgforest.sh commands don't receive parameters Reviewed-by: katleman --- common/bin/hgforest.sh | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index 17a4e79a4e7..aae55ea12a7 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. @@ -60,10 +60,10 @@ done command="$1"; shift -repo_base="$@" +command_args="$@" usage() { - echo "usage: $0 [-q|--quiet] [-v|--verbose] [--] [repo_base_path]" > ${status_output} + echo "usage: $0 [-q|--quiet] [-v|--verbose] [--] [commands...]" > ${status_output} exit 1 } @@ -113,26 +113,30 @@ subrepos_extra="closed jdk/src/closed jdk/make/closed jdk/test/closed hotspot/ma pull_default="" repos="" repos_extra="" -if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then - if [ -f .hg/hgrc ] ; then - pull_default=`hg paths default` - if [ "${pull_default}" = "" ] ; then - echo "ERROR: Need initial clone with 'hg paths default' defined" > ${status_output} - exit 1 - fi - fi - if [ "${pull_default}" = "" ] ; then +if [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone" ] ; then + if [ ! -f .hg/hgrc ] ; then echo "ERROR: Need initial repository to use this script" > ${status_output} exit 1 fi + + pull_default=`hg paths default` + if [ "${pull_default}" = "" ] ; then + echo "ERROR: Need initial clone with 'hg paths default' defined" > ${status_output} + exit 1 + fi + for i in ${subrepos} ; do if [ ! -f ${i}/.hg/hgrc ] ; then repos="${repos} ${i}" fi done - if [ "${repo_base}" != "" ] ; then + if [ "${command_args}" != "" ] ; then pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'` - pull_extra="${repo_base}/${pull_default_tail}" + if [ "x${pull_default}" = "x${pull_default_tail}" ] ; then + echo "ERROR: Need initial clone from non-local source" > ${status_output} + exit 1 + fi + pull_extra="${command_args}/${pull_default_tail}" for i in ${subrepos_extra} ; do if [ ! -f ${i}/.hg/hgrc ] ; then repos_extra="${repos_extra} ${i}" @@ -214,9 +218,8 @@ else done ( ( - if [ "${command}" = "clone" -o "${command}" = "fclone" ] ; then + if [ "${command}" = "clone" -o "${command}" = "fclone" -o "${command}" = "tclone" ] ; then pull_newrepo="`echo ${pull_base}/${i} | sed -e 's@\([^:]/\)//*@\1@g'`" - echo "hg clone ${pull_newrepo} ${i}" > ${status_output} path="`dirname ${i}`" if [ "${path}" != "." ] ; then times=0 @@ -229,10 +232,11 @@ else sleep 5 done fi + echo "hg clone ${pull_newrepo} ${i}" > ${status_output} (PYTHONUNBUFFERED=true hg${global_opts} clone ${pull_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & else - echo "cd ${i} && hg${global_opts} ${command} ${repo_base}" > ${status_output} - cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} ${command_repo}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & + echo "cd ${i} && hg${global_opts} ${command} ${command_args}" > ${status_output} + cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} ${command_args}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 & fi echo $! > ${tmp}/${repopidfile}.pid From 77ad0945a6ee9aa73ad0b47fbe1eca49b511cdff Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 26 Mar 2014 17:50:33 -0700 Subject: [PATCH 081/170] 8035104: reorder class file attributes in javap listing Reviewed-by: ksrini --- .../com/sun/tools/javap/ClassWriter.java | 5 +- langtools/test/tools/javap/T4975569.java | 6 +- langtools/test/tools/javap/T8035104.java | 67 +++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 langtools/test/tools/javap/T8035104.java diff --git a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java index 83b8ba8e9e1..a483775b78b 100644 --- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java @@ -202,7 +202,6 @@ public class ClassWriter extends BasicWriter { if (options.verbose) { println(); indent(+1); - attrWriter.write(cf, cf.attributes, constant_pool); println("minor version: " + cf.minor_version); println("major version: " + cf.major_version); writeList("flags: ", flags.getClassFlags(), "\n"); @@ -218,6 +217,10 @@ public class ClassWriter extends BasicWriter { writeMethods(); indent(-1); println("}"); + + if (options.verbose) { + attrWriter.write(cf, cf.attributes, constant_pool); + } } // where class JavaTypePrinter implements Type.Visitor { diff --git a/langtools/test/tools/javap/T4975569.java b/langtools/test/tools/javap/T4975569.java index b4a55492f31..df35b7ffd50 100644 --- a/langtools/test/tools/javap/T4975569.java +++ b/langtools/test/tools/javap/T4975569.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2014, 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 @@ -40,10 +40,10 @@ public class T4975569 verify("T4975569$Anno", "flags: ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION"); verify("T4975569$E", "flags: ACC_FINAL, ACC_SUPER, ACC_ENUM"); verify("T4975569$S", "flags: ACC_BRIDGE, ACC_SYNTHETIC", - "InnerClasses:\n static"); + "InnerClasses:\n static"); verify("T4975569$V", "void m(java.lang.String...)", "flags: ACC_VARARGS"); - verify("T4975569$Prot", "InnerClasses:\n protected"); + verify("T4975569$Prot", "InnerClasses:\n protected"); //verify("T4975569$Priv", "InnerClasses"); if (errors > 0) throw new Error(errors + " found."); diff --git a/langtools/test/tools/javap/T8035104.java b/langtools/test/tools/javap/T8035104.java new file mode 100644 index 00000000000..37ef8fc015b --- /dev/null +++ b/langtools/test/tools/javap/T8035104.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, 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 8035104 + * @summary reorder class file attributes in javap listing + */ + +import java.io.*; + +public class T8035104 { + public static void main(String[] args) throws Exception { + new T8035104().run(); + } + + public void run() throws Exception { + String[] lines = javap("-v", T8035104.class.getName()).split("[\r\n]+"); + int minor = -1; + int SourceFile = -1; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line.matches(" *minor version: [0-9.]+")) + minor = i; + if (line.matches(" *SourceFile: .+")) + SourceFile = i; + } + if (minor == -1) + throw new Exception("minor version not found"); + if (SourceFile == -1) + throw new Exception("SourceFile not found"); + if (SourceFile < minor) + throw new Exception("unexpected order of output"); + + System.out.println("output OK"); + } + + String javap(String... args) { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + int rc = com.sun.tools.javap.Main.run(args, out); + out.close(); + System.out.println(sw.toString()); + System.out.println("javap exited, rc=" + rc); + return sw.toString(); + } +} From d9187e9799c65e973027ba47221f2e073a19ad99 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Thu, 27 Mar 2014 11:17:26 +0400 Subject: [PATCH 082/170] 8038240: new WB API to get nmethod Reviewed-by: morris, kvn --- hotspot/src/share/vm/prims/whitebox.cpp | 42 ++++++++++- hotspot/src/share/vm/prims/whitebox.hpp | 4 +- .../whitebox/CompilerWhiteBoxTest.java | 4 +- .../compiler/whitebox/GetNMethodTest.java | 71 +++++++++++++++++++ .../whitebox/sun/hotspot/WhiteBox.java | 3 +- .../whitebox/sun/hotspot/code/NMethod.java | 51 +++++++++++++ 6 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 hotspot/test/compiler/whitebox/GetNMethodTest.java create mode 100644 hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 969c6542d06..df8a0d2dc2f 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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 @@ -510,6 +510,44 @@ WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o)) return features_string; WB_END + +WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) + ResourceMark rm(THREAD); + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, NULL); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + jobjectArray result = NULL; + if (code == NULL) { + return result; + } + int insts_size = code->insts_size(); + + ThreadToNativeFromVM ttn(thread); + jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + result = env->NewObjectArray(2, clazz, NULL); + if (result == NULL) { + return result; + } + + clazz = env->FindClass(vmSymbols::java_lang_Integer()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + jmethodID constructor = env->GetMethodID(clazz, vmSymbols::object_initializer_name()->as_C_string(), vmSymbols::int_void_signature()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + jobject obj = env->NewObject(clazz, constructor, code->comp_level()); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 0, obj); + + jbyteArray insts = env->NewByteArray(insts_size); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin()); + env->SetObjectArrayElement(result, 1, insts); + + return result; +WB_END + + //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { @@ -622,6 +660,8 @@ static JNINativeMethod methods[] = { {CC"fullGC", CC"()V", (void*)&WB_FullGC }, {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, + {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", + (void*)&WB_GetNMethod }, }; #undef CC diff --git a/hotspot/src/share/vm/prims/whitebox.hpp b/hotspot/src/share/vm/prims/whitebox.hpp index a6e27b49055..a9854f3ffea 100644 --- a/hotspot/src/share/vm/prims/whitebox.hpp +++ b/hotspot/src/share/vm/prims/whitebox.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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 @@ -40,7 +40,6 @@ do { \ JavaThread* THREAD = JavaThread::thread_from_jni_environment(env); \ if (HAS_PENDING_EXCEPTION) { \ - CLEAR_PENDING_EXCEPTION; \ return(value); \ } \ } while (0) @@ -49,7 +48,6 @@ do { \ JavaThread* THREAD = JavaThread::thread_from_jni_environment(env); \ if (HAS_PENDING_EXCEPTION) { \ - CLEAR_PENDING_EXCEPTION; \ return; \ } \ } while (0) diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index c199c2a6a67..5f353998061 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java @@ -24,6 +24,7 @@ import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; import sun.management.ManagementFactoryHelper; import java.lang.reflect.Constructor; @@ -278,7 +279,8 @@ public abstract class CompilerWhiteBoxTest { } protected final int getCompLevel() { - return WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()); + NMethod nm = NMethod.get(method, testCase.isOsr()); + return nm == null ? COMP_LEVEL_NONE : nm.comp_level; } protected final boolean isCompilable() { diff --git a/hotspot/test/compiler/whitebox/GetNMethodTest.java b/hotspot/test/compiler/whitebox/GetNMethodTest.java new file mode 100644 index 00000000000..bb95f01b991 --- /dev/null +++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +import sun.hotspot.code.NMethod; + +/* + * @test GetNMethodTest + * @bug 8038240 + * @library /testlibrary /testlibrary/whitebox + * @build GetNMethodTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* GetNMethodTest + * @summary testing of WB::getNMethod() + * @author igor.ignatyev@oracle.com + */ +public class GetNMethodTest extends CompilerWhiteBoxTest { + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(GetNMethodTest::new, args); + } + + private GetNMethodTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + checkNotCompiled(); + + compile(); + checkCompiled(); + NMethod nmethod = NMethod.get(method, testCase.isOsr()); + if (IS_VERBOSE) { + System.out.println("nmethod = " + nmethod); + } + if (nmethod == null) { + throw new RuntimeException("nmethod of compiled method is null"); + } + if (nmethod.insts.length == 0) { + throw new RuntimeException("compiled method's instructions is empty"); + } + deoptimize(); + checkNotCompiled(); + nmethod = NMethod.get(method, testCase.isOsr()); + if (nmethod != null) { + throw new RuntimeException("nmethod of non-compiled method isn't null"); + } + } +} diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java index f37a6fc1d56..e35260c6d2f 100644 --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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 @@ -135,6 +135,7 @@ public class WhiteBox { public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); public native void clearMethodState(Executable method); public native int getMethodEntryBci(Executable method); + public native Object[] getNMethod(Executable method, boolean isOsr); // Intered strings public native boolean isInStringTable(String str); diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java new file mode 100644 index 00000000000..4bdb49d0b3e --- /dev/null +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, 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.hotspot.code; + +import java.lang.reflect.Executable; +import sun.hotspot.WhiteBox; + +public class NMethod { + private static final WhiteBox wb = WhiteBox.getWhiteBox(); + public static NMethod get(Executable method, boolean isOsr) { + Object[] obj = wb.getNMethod(method, isOsr); + return obj == null ? null : new NMethod(obj); + } + private NMethod(Object[] obj) { + assert obj.length == 2; + comp_level = (Integer) obj[0]; + insts = (byte[]) obj[1]; + } + public byte[] insts; + public int comp_level; + + @Override + public String toString() { + return "NMethod{" + + "insts=" + insts + + ", comp_level=" + comp_level + + '}'; + } +} From 45dd523fc6960693c1d2c855a0ae263b349c5889 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Thu, 27 Mar 2014 17:29:41 +0400 Subject: [PATCH 083/170] 8038193: Add command line option tests for BMI options Reviewed-by: kvn, iignatyev --- .../BMICommandLineOptionTestBase.java | 68 +++++++ .../arguments/BMISupportedCPUTest.java | 72 ++++++++ .../arguments/BMIUnsupportedCPUTest.java | 114 ++++++++++++ ...TestUseBMI1InstructionsOnSupportedCPU.java | 51 ++++++ ...stUseBMI1InstructionsOnUnsupportedCPU.java | 52 ++++++ ...LeadingZerosInstructionOnSupportedCPU.java | 52 ++++++ ...adingZerosInstructionOnUnsupportedCPU.java | 52 ++++++ ...railingZerosInstructionOnSupportedCPU.java | 72 ++++++++ ...ilingZerosInstructionOnUnsupportedCPU.java | 70 +++++++ .../com/oracle/java/testlibrary/ExitCode.java | 40 ++++ .../com/oracle/java/testlibrary/Utils.java | 36 +++- .../cli/CPUSpecificCommandLineOptionTest.java | 110 +++++++++++ .../cli/CommandLineOptionTest.java | 173 ++++++++++++++++++ 13 files changed, 961 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java create mode 100644 hotspot/test/compiler/arguments/BMISupportedCPUTest.java create mode 100644 hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java create mode 100644 hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java create mode 100644 hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java create mode 100644 hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java create mode 100644 hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java create mode 100644 hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java create mode 100644 hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java diff --git a/hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java b/hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java new file mode 100644 index 00000000000..6d4fa400dda --- /dev/null +++ b/hotspot/test/compiler/arguments/BMICommandLineOptionTestBase.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, 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. + */ + +import com.oracle.java.testlibrary.cli.*; + +/** + * Base class for all X86 bit manipulation related command line options. + */ +public abstract class BMICommandLineOptionTestBase + extends CPUSpecificCommandLineOptionTest { + + public static final String LZCNT_WARNING = + "lzcnt instruction is not available on this CPU"; + public static final String TZCNT_WARNING = + "tzcnt instruction is not available on this CPU"; + public static final String BMI1_WARNING = + "BMI1 instructions are not available on this CPU"; + + protected final String optionName; + protected final String warningMessage; + protected final String errorMessage; + + /** + * Construct new test on {@code optionName} option. + * + * @param optionName Name of the option to be tested + * without -XX:[+-] prefix. + * @param warningMessage Message that can occur in VM output + * if CPU on test box does not support + * features required by the option. + * @param supportedCPUFeatures CPU features requires by the option, + * that should be supported on test box. + * @param unsupportedCPUFeatures CPU features requires by the option, + * that should not be supported on test box. + */ + public BMICommandLineOptionTestBase(String optionName, + String warningMessage, + String supportedCPUFeatures[], + String unsupportedCPUFeatures[]) { + super(".*", supportedCPUFeatures, unsupportedCPUFeatures); + this.optionName = optionName; + this.warningMessage = warningMessage; + this.errorMessage = CommandLineOptionTest. + UNRECOGNIZED_OPTION_ERROR_FORMAT.format(optionName); + } + +} + diff --git a/hotspot/test/compiler/arguments/BMISupportedCPUTest.java b/hotspot/test/compiler/arguments/BMISupportedCPUTest.java new file mode 100644 index 00000000000..c0af31fd766 --- /dev/null +++ b/hotspot/test/compiler/arguments/BMISupportedCPUTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, 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. + */ + +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +/** + * Test on bit manipulation related command line options, + * that should be executed on CPU that supports all required + * features. + */ +public class BMISupportedCPUTest extends BMICommandLineOptionTestBase { + + /** + * Construct new test on {@code optionName} option. + * + * @param optionName Name of the option to be tested + * without -XX:[+-] prefix. + * @param warningMessage Message that can occur in VM output + * if CPU on test box does not support + * features required by the option. + * @param cpuFeatures CPU features requires by the option. + */ + public BMISupportedCPUTest(String optionName, + String warningMessage, + String... cpuFeatures) { + super(optionName, warningMessage, cpuFeatures, null); + } + + @Override + public void runTestCases() throws Throwable { + // verify that VM will succesfully start up whithout warnings + CommandLineOptionTest. + verifyJVMStartup("-XX:+" + optionName, + null, new String[] { warningMessage }, + ExitCode.OK); + + // verify that VM will succesfully start up whithout warnings + CommandLineOptionTest. + verifyJVMStartup("-XX:-" + optionName, + null, new String[] { warningMessage }, + ExitCode.OK); + + // verify that on appropriate CPU option in on by default + CommandLineOptionTest.verifyOptionValue(optionName, "true"); + + // verify that option could be explicitly turned off + CommandLineOptionTest.verifyOptionValue(optionName, "false", + "-XX:-" + optionName); + } +} + diff --git a/hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java b/hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java new file mode 100644 index 00000000000..7a78c74e579 --- /dev/null +++ b/hotspot/test/compiler/arguments/BMIUnsupportedCPUTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014, 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. + */ + +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +/** + * Test on bit manipulation related command line options, + * that should be executed on CPU that does not support + * required features. + */ +public class BMIUnsupportedCPUTest extends BMICommandLineOptionTestBase { + + /** + * Construct new test on {@code optionName} option. + * + * @param optionName Name of the option to be tested + * without -XX:[+-] prefix. + * @param warningMessage Message that can occur in VM output + * if CPU on test box does not support + * features required by the option. + * @param cpuFeatures CPU features requires by the option. + */ + public BMIUnsupportedCPUTest(String optionName, + String warningMessage, + String... cpuFeatures) { + super(optionName, warningMessage, null, cpuFeatures); + } + + @Override + public void runTestCases() throws Throwable { + if (Platform.isX86() || Platform.isX64()) { + unsupportedX86CPUTestCases(); + } else { + unsupportedNonX86CPUTestCases(); + } + } + + /** + * Run test cases common for all bit manipulation related VM options + * targeted to X86 CPU that does not support required features. + * + * @throws Throwable if test failed. + */ + public void unsupportedX86CPUTestCases() throws Throwable { + + // verify that VM will succesfully start up, but output will + // contain a warning + CommandLineOptionTest. + verifyJVMStartup("-XX:+" + optionName, + new String[] { warningMessage }, + new String[] { errorMessage }, + ExitCode.OK); + + // verify that VM will succesfully startup without any warnings + CommandLineOptionTest. + verifyJVMStartup("-XX:-" + optionName, + null, + new String[] { warningMessage, errorMessage }, + ExitCode.OK); + + // verify that on unsupported CPUs option is off by default + CommandLineOptionTest.verifyOptionValue(optionName, "false"); + + // verify that on unsupported CPUs option will be off even if + // it was explicitly turned on by uset + CommandLineOptionTest.verifyOptionValue(optionName, "false", + "-XX:+" + optionName); + + } + + /** + * Run test cases common for all bit manipulation related VM options + * targeted to non-X86 CPU that does not support required features. + * + * @throws Throwable if test failed. + */ + public void unsupportedNonX86CPUTestCases() throws Throwable { + + // verify that VM known nothing about tested option + CommandLineOptionTest. + verifyJVMStartup("-XX:+" + optionName, + new String[] { errorMessage }, + null, + ExitCode.FAIL); + + CommandLineOptionTest. + verifyJVMStartup("-XX:-" + optionName, + new String[] { errorMessage }, + null, + ExitCode.FAIL); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java new file mode 100644 index 00000000000..559c3a6a643 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnSupportedCPU.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify processing of UseBMI1Instructions option on CPU with + * BMI1 feature support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseBMI1InstructionsOnSupportedCPU + * BMISupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestUseBMI1InstructionsOnSupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +public class TestUseBMI1InstructionsOnSupportedCPU + extends BMISupportedCPUTest { + + public TestUseBMI1InstructionsOnSupportedCPU() { + super("UseBMI1Instructions", BMI1_WARNING, "bmi1"); + } + + public static void main(String args[]) throws Throwable { + new TestUseBMI1InstructionsOnSupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java new file mode 100644 index 00000000000..3df8d659cf0 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseBMI1InstructionsOnUnsupportedCPU.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify processing of UseBMI1Instructions option on CPU without + * BMI1 feature support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseBMI1InstructionsOnUnsupportedCPU + * BMIUnsupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI TestUseBMI1InstructionsOnUnsupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +public class TestUseBMI1InstructionsOnUnsupportedCPU + extends BMIUnsupportedCPUTest { + + public TestUseBMI1InstructionsOnUnsupportedCPU() { + super("UseBMI1Instructions", BMI1_WARNING, "bmi1"); + } + + public static void main(String args[]) throws Throwable { + new TestUseBMI1InstructionsOnUnsupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java new file mode 100644 index 00000000000..c8437748341 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnSupportedCPU.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify processing of UseCountLeadingZerosInstruction option + * on CPU with LZCNT support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountLeadingZerosInstructionOnSupportedCPU + * BMISupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountLeadingZerosInstructionOnSupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +public class TestUseCountLeadingZerosInstructionOnSupportedCPU + extends BMISupportedCPUTest { + + public TestUseCountLeadingZerosInstructionOnSupportedCPU() { + super("UseCountLeadingZerosInstruction", LZCNT_WARNING, "lzcnt"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountLeadingZerosInstructionOnSupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java new file mode 100644 index 00000000000..e2ffba28a43 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountLeadingZerosInstructionOnUnsupportedCPU.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify processing of UseCountLeadingZerosInstruction option + * on CPU without LZCNT support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountLeadingZerosInstructionOnUnsupportedCPU + * BMIUnsupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountLeadingZerosInstructionOnUnsupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +public class TestUseCountLeadingZerosInstructionOnUnsupportedCPU + extends BMIUnsupportedCPUTest { + + public TestUseCountLeadingZerosInstructionOnUnsupportedCPU() { + super("UseCountLeadingZerosInstruction", LZCNT_WARNING, "lzcnt"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountLeadingZerosInstructionOnUnsupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java new file mode 100644 index 00000000000..995d450e365 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify processing of UseCountTrailingZerosInstruction option + * on CPU with TZCNT (BMI1 feature) support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountTrailingZerosInstructionOnSupportedCPU + * BMISupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountTrailingZerosInstructionOnSupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +public class TestUseCountTrailingZerosInstructionOnSupportedCPU + extends BMISupportedCPUTest { + + public TestUseCountTrailingZerosInstructionOnSupportedCPU() { + super("UseCountTrailingZerosInstruction", TZCNT_WARNING, "bmi1"); + } + + @Override + public void runTestCases() throws Throwable { + + super.runTestCases(); + + // verify that option will be disabled if all BMI1 instuctions + // are explicitly disabled + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "false", + "-XX:-UseBMI1Instructions"); + + // verify that option could be turned on even if other BMI1 + // instructions were turned off + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "true", + "-XX:-UseBMI1Instructions", + "-XX:+UseCountTrailingZerosInstruction"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountTrailingZerosInstructionOnSupportedCPU().test(); + } +} + diff --git a/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java new file mode 100644 index 00000000000..86853aab0c5 --- /dev/null +++ b/hotspot/test/compiler/arguments/TestUseCountTrailingZerosInstructionOnUnsupportedCPU.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014, 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 8031321 + * @summary Verify processing of UseCountTrailingZerosInstruction option + * on CPU without TZCNT instuction (BMI1 feature) support. + * @library /testlibrary /testlibrary/whitebox + * @build TestUseCountTrailingZerosInstructionOnUnsupportedCPU + * BMIUnsupportedCPUTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * TestUseCountTrailingZerosInstructionOnUnsupportedCPU + */ + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; +import com.oracle.java.testlibrary.cli.*; + +public class TestUseCountTrailingZerosInstructionOnUnsupportedCPU + extends BMIUnsupportedCPUTest { + + public TestUseCountTrailingZerosInstructionOnUnsupportedCPU() { + super("UseCountTrailingZerosInstruction", TZCNT_WARNING, "bmi1"); + } + + @Override + public void unsupportedX86CPUTestCases() throws Throwable { + + super.unsupportedX86CPUTestCases(); + + // verify that option will not be turned on during + // UseBMI1Instuctions processing + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "false", + "-XX:+UseBMI1Instructions"); + + CommandLineOptionTest. + verifyOptionValue("UseCountTrailingZerosInstruction", "false", + "-XX:+UseCountTrailingZerosInstruction", + "-XX:+UseBMI1Instructions"); + } + + public static void main(String args[]) throws Throwable { + new TestUseCountTrailingZerosInstructionOnUnsupportedCPU().test(); + } +} + diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java new file mode 100644 index 00000000000..2db3be2d26d --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ExitCode.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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 com.oracle.java.testlibrary; + +/** + * Exit code values that could be returned by the JVM. + */ +public enum ExitCode { + OK(0), + FAIL(1), + CRASH(134); + + public final int value; + + ExitCode(int value) { + this.value = value; + } +} + diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java index a0031e706ec..03fd773e0a3 100644 --- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -107,6 +107,40 @@ public final class Utils { return opts.toArray(new String[0]); } + /** + * Returns the default JTReg arguments for a jvm running a test without + * options that matches regular expresions in {@code filters}. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @param filters Regular expressions used to filter out options. + * @return An array of options, or an empty array if no opptions. + */ + public static String[] getFilteredTestJavaOpts(String... filters) { + String options[] = getTestJavaOpts(); + + if (filters.length == 0) { + return options; + } + + List filteredOptions = new ArrayList(options.length); + Pattern patterns[] = new Pattern[filters.length]; + for (int i = 0; i < filters.length; i++) { + patterns[i] = Pattern.compile(filters[i]); + } + + for (String option : options) { + boolean matched = false; + for (int i = 0; i < patterns.length && !matched; i++) { + Matcher matcher = patterns[i].matcher(option); + matched = matcher.find(); + } + if (!matched) { + filteredOptions.add(option); + } + } + + return filteredOptions.toArray(new String[filteredOptions.size()]); + } + /** * Combines given arguments with default JTReg arguments for a jvm running a test. * This is the combination of JTReg arguments test.vm.opts and test.java.opts diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java new file mode 100644 index 00000000000..a300e038d29 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CPUSpecificCommandLineOptionTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014, 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 com.oracle.java.testlibrary.cli; + +import sun.hotspot.cpuinfo.CPUInfo; +import com.oracle.java.testlibrary.*; + +/** + * Base class for command line options tests that + * requires specific CPU arch or specific CPU features. + */ +public abstract class CPUSpecificCommandLineOptionTest + extends CommandLineOptionTest { + + private String cpuArchPattern; + private String supportedCPUFeatures[]; + private String unsupportedCPUFeatures[]; + + /** + * Create new CPU specific test instance that does not + * require any CPU features. + * + * @param cpuArchPattern Regular expression that should + * match os.arch. + */ + public CPUSpecificCommandLineOptionTest(String cpuArchPattern) { + this(cpuArchPattern, null, null); + } + + /** + * Create new CPU specific test instance that does not + * require from CPU support of {@code supportedCPUFeatures} features + * and no support of {@code unsupportedCPUFeatures}. + * + * @param cpuArchPattern Regular expression that should + * match os.arch. + * @param supportedCPUFeatures Array with names of features that + * should be supported by CPU. If null, + * then no features have to be supported. + * @param unsupportedCPUFeatures Array with names of features that + * should not be supported by CPU. + * If null, then CPU may support any + * features. + */ + public CPUSpecificCommandLineOptionTest(String cpuArchPattern, + String supportedCPUFeatures[], + String unsupportedCPUFeatures[]) { + this.cpuArchPattern = cpuArchPattern; + this.supportedCPUFeatures = supportedCPUFeatures; + this.unsupportedCPUFeatures = unsupportedCPUFeatures; + } + + /** + * Check that CPU on test box has appropriate architecture, support all + * required features and does not support all features that should not be + * supported. + * + * @return true if CPU on test box fulfill all requirements. + */ + @Override + public boolean checkPreconditions() { + if (!Platform.getOsArch().matches(cpuArchPattern)) { + System.out.println("CPU arch does not match " + cpuArchPattern); + return false; + } + + if (supportedCPUFeatures != null) { + for (String feature : supportedCPUFeatures) { + if (!CPUInfo.hasFeature(feature)) { + System.out.println("CPU does not support " + feature + + " feature"); + return false; + } + } + } + + if (unsupportedCPUFeatures != null) { + for (String feature : unsupportedCPUFeatures) { + if (CPUInfo.hasFeature(feature)) { + System.out.println("CPU support " + feature + " feature"); + return false; + } + } + } + + return true; + } +} + diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java new file mode 100644 index 00000000000..d4d4e7c743a --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cli/CommandLineOptionTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2014, 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 com.oracle.java.testlibrary.cli; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import com.oracle.java.testlibrary.*; + +/** + * Base class for command line option tests. + */ +public abstract class CommandLineOptionTest { + + public static final String UNRECOGNIZED_OPTION_ERROR_FORMAT = + "Unrecognized VM option '[+-]?%s'"; + + public static final String printFlagsFinalFormat = "%s\\s*:?=\\s*%s"; + + /** + * Verify that JVM startup behaviour matches our expectations. + * + * @param option The option that should be passed to JVM + * @param excpectedMessages Array of patterns that should occur + * in JVM output. If null then + * JVM output could be empty. + * @param unexpectedMessages Array of patterns that should not + * occur in JVM output. If null then + * JVM output could be empty. + * @param exitCode expected exit code. + * @throws Throwable if verification fails or some other issues occur. + */ + public static void verifyJVMStartup(String option, + String expectedMessages[], + String unexpectedMessages[], + ExitCode exitCode) + throws Throwable { + + OutputAnalyzer outputAnalyzer = + ProcessTools.executeTestJvm(option, "-version"); + + outputAnalyzer.shouldHaveExitValue(exitCode.value); + + if (expectedMessages != null) { + for (String expectedMessage : expectedMessages) { + outputAnalyzer.shouldMatch(expectedMessage); + } + } + + if (unexpectedMessages != null) { + for (String unexpectedMessage : unexpectedMessages) { + outputAnalyzer.shouldNotMatch(unexpectedMessage); + } + } + } + + /** + * Verify that value of specified JVM option is the same as + * expected value. + * This method filter out option with {@code optionName} + * name from test java options. + * + * @param optionName Name of tested option. + * @param expectedValue Expected value of tested option. + * @param additionalVMOpts Additonal options that should be + * passed to JVM. + * @throws Throwable if verification fails or some other issues occur. + */ + public static void verifyOptionValue(String optionName, + String expectedValue, + String... additionalVMOpts) + throws Throwable { + verifyOptionValue(optionName, expectedValue, true, additionalVMOpts); + } + + /** + * Verify that value of specified JVM option is the same as + * expected value. + * This method filter out option with {@code optionName} + * name from test java options. + * + * @param optionName Name of tested option. + * @param expectedValue Expected value of tested option. + * @param addTestVmOptions If true, then test VM options + * will be used. + * @param additionalVMOpts Additonal options that should be + * passed to JVM. + * @throws Throwable if verification fails or some other issues occur. + */ + public static void verifyOptionValue(String optionName, + String expectedValue, + boolean addTestVmOptions, + String... additionalVMOpts) + throws Throwable { + + List vmOpts = new ArrayList(); + + if (addTestVmOptions) { + Collections.addAll(vmOpts, + Utils.getFilteredTestJavaOpts(optionName)); + } + Collections.addAll(vmOpts, additionalVMOpts); + Collections.addAll(vmOpts, new String[] { + "-XX:+PrintFlagsFinal", + "-version" + }); + + ProcessBuilder processBuilder = + ProcessTools. + createJavaProcessBuilder(vmOpts. + toArray(new String[vmOpts.size()])); + + OutputAnalyzer outputAnalyzer = + new OutputAnalyzer(processBuilder.start()); + + outputAnalyzer.shouldHaveExitValue(0); + outputAnalyzer.shouldMatch(String. + format(printFlagsFinalFormat, + optionName, + expectedValue)); + } + + + /** + * Run command line option test. + * + * @throws Throwable if test failed. + */ + public final void test() throws Throwable { + if (checkPreconditions()) { + runTestCases(); + } + } + + /** + * Check that all preconditions for test execution are met. + * + * @return true if test could be executed. + */ + public boolean checkPreconditions() { + return true; + } + + /** + * Run test cases. + * + * @throws Throwable if test failed. + */ + public abstract void runTestCases() throws Throwable; +} + From 7ea75c6bbbdc6cc41e422d8284f5c9eaab75efb9 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 27 Mar 2014 19:39:18 +0530 Subject: [PATCH 084/170] 8038456: improve nasgen type checks and use specific return type for @Function, @SpecializedFunctio methods Reviewed-by: lagergren, jlaskey --- .../internal/tools/nasgen/MemberInfo.java | 286 +++++++++++++----- .../tools/nasgen/StringConstants.java | 3 + .../internal/objects/ArrayBufferView.java | 2 +- .../nashorn/internal/objects/NativeArray.java | 32 +- .../internal/objects/NativeArrayBuffer.java | 4 +- .../internal/objects/NativeBoolean.java | 4 +- .../internal/objects/NativeDataView.java | 6 +- .../nashorn/internal/objects/NativeDate.java | 105 ++++--- .../nashorn/internal/objects/NativeDebug.java | 10 +- .../nashorn/internal/objects/NativeError.java | 2 +- .../internal/objects/NativeEvalError.java | 2 +- .../internal/objects/NativeFloat32Array.java | 8 +- .../internal/objects/NativeFloat64Array.java | 8 +- .../internal/objects/NativeFunction.java | 10 +- .../internal/objects/NativeInt16Array.java | 8 +- .../internal/objects/NativeInt32Array.java | 8 +- .../internal/objects/NativeInt8Array.java | 8 +- .../internal/objects/NativeJSAdapter.java | 2 +- .../nashorn/internal/objects/NativeJava.java | 4 +- .../internal/objects/NativeJavaImporter.java | 2 +- .../internal/objects/NativeNumber.java | 14 +- .../internal/objects/NativeObject.java | 31 +- .../internal/objects/NativeRangeError.java | 2 +- .../objects/NativeReferenceError.java | 2 +- .../internal/objects/NativeRegExp.java | 26 +- .../internal/objects/NativeString.java | 64 ++-- .../internal/objects/NativeSyntaxError.java | 2 +- .../internal/objects/NativeTypeError.java | 2 +- .../internal/objects/NativeURIError.java | 2 +- .../internal/objects/NativeUint16Array.java | 8 +- .../internal/objects/NativeUint32Array.java | 8 +- .../internal/objects/NativeUint8Array.java | 8 +- .../objects/NativeUint8ClampedArray.java | 8 +- 33 files changed, 413 insertions(+), 278 deletions(-) diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java index c43bdf52512..e47f8b160ad 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java @@ -22,40 +22,62 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.nashorn.internal.tools.nasgen; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Type; import jdk.nashorn.internal.objects.annotations.Where; +import jdk.nashorn.internal.runtime.ScriptObject; /** * Details about a Java method or field annotated with any of the field/method * annotations from the jdk.nashorn.internal.objects.annotations package. */ public final class MemberInfo implements Cloneable { + // class loader of this class + private static ClassLoader myLoader = MemberInfo.class.getClassLoader(); + /** * The different kinds of available class annotations */ public static enum Kind { - /** This is a script class */ + + /** + * This is a script class + */ SCRIPT_CLASS, - /** This is a constructor */ + /** + * This is a constructor + */ CONSTRUCTOR, - /** This is a function */ + /** + * This is a function + */ FUNCTION, - /** This is a getter */ + /** + * This is a getter + */ GETTER, - /** This is a setter */ + /** + * This is a setter + */ SETTER, - /** This is a property */ + /** + * This is a property + */ PROPERTY, - /** This is a specialized version of a function */ + /** + * This is a specialized version of a function + */ SPECIALIZED_FUNCTION, - /** This is a specialized version of a constructor */ + /** + * This is a specialized version of a constructor + */ SPECIALIZED_CONSTRUCTOR } @@ -194,6 +216,7 @@ public final class MemberInfo implements Cloneable { /** * Check whether this MemberInfo is a getter that resides in the instance + * * @return true if instance setter */ boolean isInstanceSetter() { @@ -245,92 +268,201 @@ public final class MemberInfo implements Cloneable { } void verify() { - if (kind == Kind.CONSTRUCTOR) { - final Type returnType = Type.getReturnType(javaDesc); - if (! returnType.toString().equals(OBJECT_DESC)) { - error("return value should be of Object type, found" + returnType); - } - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length < 2) { - error("constructor methods should have at least 2 args"); - } - if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) { - error("first argument should be of boolean type, found" + argTypes[0]); - } - if (! argTypes[1].toString().equals(OBJECT_DESC)) { - error("second argument should be of Object type, found" + argTypes[0]); - } + switch (kind) { + case CONSTRUCTOR: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isJSObjectType(returnType)) { + error("return value of a @Constructor method should be of Object type, found " + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 2) { + error("@Constructor methods should have at least 2 args"); + } + if (!argTypes[0].equals(Type.BOOLEAN_TYPE)) { + error("first argument of a @Constructor method should be of boolean type, found " + argTypes[0]); + } + if (!isJavaLangObject(argTypes[1])) { + error("second argument of a @Constructor method should be of Object type, found " + argTypes[0]); + } - if (argTypes.length > 2) { - for (int i = 2; i < argTypes.length - 1; i++) { - if (! argTypes[i].toString().equals(OBJECT_DESC)) { - error(i + "'th argument should be of Object type, found " + argTypes[i]); + if (argTypes.length > 2) { + for (int i = 2; i < argTypes.length - 1; i++) { + if (!isJavaLangObject(argTypes[i])) { + error(i + "'th argument of a @Constructor method should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgTypeDesc = argTypes[argTypes.length - 1].getDescriptor(); + final boolean isVarArg = lastArgTypeDesc.equals(OBJECT_ARRAY_DESC); + if (!lastArgTypeDesc.equals(OBJECT_DESC) && !isVarArg) { + error("last argument of a @Constructor method is neither Object nor Object[] type: " + lastArgTypeDesc); + } + + if (isVarArg && argTypes.length > 3) { + error("vararg of a @Constructor method has more than 3 arguments"); } } - - final String lastArgType = argTypes[argTypes.length - 1].toString(); - final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); - if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { - error("last argument is neither Object nor Object[] type: " + lastArgType); + } + break; + case SPECIALIZED_CONSTRUCTOR: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isJSObjectType(returnType)) { + error("return value of a @SpecializedConstructor method should be a valid JS type, found " + returnType); } - - if (isVarArg && argTypes.length > 3) { - error("vararg constructor has more than 3 arguments"); - } - } - } else if (kind == Kind.FUNCTION) { - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length < 1) { - error("function methods should have at least 1 arg"); - } - if (! argTypes[0].toString().equals(OBJECT_DESC)) { - error("first argument should be of Object type, found" + argTypes[0]); - } - - if (argTypes.length > 1) { - for (int i = 1; i < argTypes.length - 1; i++) { - if (! argTypes[i].toString().equals(OBJECT_DESC)) { - error(i + "'th argument should be of Object type, found " + argTypes[i]); + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + for (int i = 0; i < argTypes.length; i++) { + if (!isValidJSType(argTypes[i])) { + error(i + "'th argument of a @SpecializedConstructor method is not valid JS type, found " + argTypes[i]); } } - - final String lastArgType = argTypes[argTypes.length - 1].toString(); - final boolean isVarArg = lastArgType.equals(OBJECT_ARRAY_DESC); - if (!lastArgType.equals(OBJECT_DESC) && !isVarArg) { - error("last argument is neither Object nor Object[] type: " + lastArgType); + } + break; + case FUNCTION: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isValidJSType(returnType)) { + error("return value of a @Function method should be a valid JS type, found " + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length < 1) { + error("@Function methods should have at least 1 arg"); + } + if (!isJavaLangObject(argTypes[0])) { + error("first argument of a @Function method should be of Object type, found " + argTypes[0]); } - if (isVarArg && argTypes.length > 2) { - error("vararg function has more than 2 arguments"); + if (argTypes.length > 1) { + for (int i = 1; i < argTypes.length - 1; i++) { + if (!isJavaLangObject(argTypes[i])) { + error(i + "'th argument of a @Function method should be of Object type, found " + argTypes[i]); + } + } + + final String lastArgTypeDesc = argTypes[argTypes.length - 1].getDescriptor(); + final boolean isVarArg = lastArgTypeDesc.equals(OBJECT_ARRAY_DESC); + if (!lastArgTypeDesc.equals(OBJECT_DESC) && !isVarArg) { + error("last argument of a @Function method is neither Object nor Object[] type: " + lastArgTypeDesc); + } + + if (isVarArg && argTypes.length > 2) { + error("vararg @Function method has more than 2 arguments"); + } } } - } else if (kind == Kind.GETTER) { - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length != 1) { - error("getter methods should have one argument"); + break; + case SPECIALIZED_FUNCTION: { + final Type returnType = Type.getReturnType(javaDesc); + if (!isValidJSType(returnType)) { + error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType); + } + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + for (int i = 0; i < argTypes.length; i++) { + if (!isValidJSType(argTypes[i])) { + error(i + "'th argument of a @SpecializedFunction method is not valid JS type, found " + argTypes[i]); + } + } } - if (! argTypes[0].toString().equals(OBJECT_DESC)) { - error("first argument of getter should be of Object type, found: " + argTypes[0]); + break; + case GETTER: { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 1) { + error("@Getter methods should have one argument"); + } + if (!isJavaLangObject(argTypes[0])) { + error("first argument of a @Getter method should be of Object type, found: " + argTypes[0]); + } + + final Type returnType = Type.getReturnType(javaDesc); + if (!isJavaLangObject(returnType)) { + error("return type of a @Getter method should be Object, found: " + javaDesc); + } } - if (Type.getReturnType(javaDesc).equals(Type.VOID_TYPE)) { - error("return type of getter should not be void"); + break; + case SETTER: { + final Type[] argTypes = Type.getArgumentTypes(javaDesc); + if (argTypes.length != 2) { + error("@Setter methods should have two arguments"); + } + if (!isJavaLangObject(argTypes[0])) { + error("first argument of a @Setter method should be of Object type, found: " + argTypes[0]); + } + if (!Type.getReturnType(javaDesc).toString().equals("V")) { + error("return type of of a @Setter method should be void, found: " + Type.getReturnType(javaDesc)); + } } - } else if (kind == Kind.SETTER) { - final Type[] argTypes = Type.getArgumentTypes(javaDesc); - if (argTypes.length != 2) { - error("setter methods should have two arguments"); - } - if (! argTypes[0].toString().equals(OBJECT_DESC)) { - error("first argument of setter should be of Object type, found: " + argTypes[0]); - } - if (!Type.getReturnType(javaDesc).toString().equals("V")) { - error("return type of setter should be void, found: " + Type.getReturnType(javaDesc)); + break; + case PROPERTY: { + if (where == Where.CONSTRUCTOR) { + if (isStatic()) { + if (!isFinal()) { + error("static Where.CONSTRUCTOR @Property should be final"); + } + + if (!isJSPrimitiveType(Type.getType(javaDesc))) { + error("static Where.CONSTRUCTOR @Property should be a JS primitive"); + } + } + } else if (where == Where.PROTOTYPE) { + if (isStatic()) { + if (!isFinal()) { + error("static Where.PROTOTYPE @Property should be final"); + } + + if (!isJSPrimitiveType(Type.getType(javaDesc))) { + error("static Where.PROTOTYPE @Property should be a JS primitive"); + } + } + } } } } + private static boolean isValidJSType(final Type type) { + return isJSPrimitiveType(type) || isJSObjectType(type); + } + + private static boolean isJSPrimitiveType(final Type type) { + switch (type.getSort()) { + case Type.BOOLEAN: + case Type.INT: + case Type.LONG: + case Type.DOUBLE: + return true; + default: + return false; + } + } + + private static boolean isJSObjectType(final Type type) { + return isJavaLangObject(type) || isJavaLangString(type) || isScriptObject(type); + } + + private static boolean isJavaLangObject(final Type type) { + return type.getDescriptor().equals(OBJECT_DESC); + } + + private static boolean isJavaLangString(final Type type) { + return type.getDescriptor().equals(STRING_DESC); + } + + private static boolean isScriptObject(final Type type) { + if (type.getDescriptor().equals(SCRIPTOBJECT_DESC)) { + return true; + } + + if (type.getSort() == Type.OBJECT) { + try { + final Class clazz = Class.forName(type.getClassName(), false, myLoader); + return ScriptObject.class.isAssignableFrom(clazz); + } catch (final ClassNotFoundException cnfe) { + return false; + } + } + + return false; + } + private void error(final String msg) { - throw new RuntimeException(javaName + javaDesc + " : " + msg); + throw new RuntimeException(javaName + " of type " + javaDesc + " : " + msg); } /** diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java index dd947033d34..1d724187dbe 100644 --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java @@ -61,6 +61,8 @@ public interface StringConstants { static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName(); static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName(); static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor(); + static final String STRING_TYPE = TYPE_STRING.getInternalName(); + static final String STRING_DESC = TYPE_STRING.getDescriptor(); static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class); static final String ARRAYLIST_TYPE = TYPE_ARRAYLIST.getInternalName(); static final String COLLECTION_TYPE = TYPE_COLLECTION.getInternalName(); @@ -129,6 +131,7 @@ public interface StringConstants { // ScriptObject static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName(); + static final String SCRIPTOBJECT_DESC = TYPE_SCRIPTOBJECT.getDescriptor(); static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP); static final String GETTER_PREFIX = "G$"; diff --git a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java index 7bd1d2f91dd..c29af8515c9 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java +++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java @@ -382,7 +382,7 @@ abstract class ArrayBufferView extends ScriptObject { return (int) (length & Integer.MAX_VALUE); } - protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) { + protected static ScriptObject subarrayImpl(final Object self, final Object begin0, final Object end0) { final ArrayBufferView arrayView = ((ArrayBufferView)self); final int elementLength = arrayView.elementLength(); final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index d95caf2c665..6f07cb9dbc4 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -389,7 +389,7 @@ public final class NativeArray extends ScriptObject { * @return true if argument is an array */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isArray(final Object self, final Object arg) { + public static boolean isArray(final Object self, final Object arg) { return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray()); } @@ -488,7 +488,7 @@ public final class NativeArray extends ScriptObject { * @return locale specific string representation for array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleString(final Object self) { + public static String toLocaleString(final Object self) { final StringBuilder sb = new StringBuilder(); final Iterator iter = arrayLikeIterator(self, true); @@ -534,7 +534,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @Constructor(arity = 1) - public static Object construct(final boolean newObj, final Object self, final Object... args) { + public static NativeArray construct(final boolean newObj, final Object self, final Object... args) { switch (args.length) { case 0: return new NativeArray(0); @@ -587,7 +587,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self) { + public static NativeArray construct(final boolean newObj, final Object self) { return new NativeArray(0); } @@ -602,7 +602,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self, final int length) { + public static NativeArray construct(final boolean newObj, final Object self, final int length) { if (length >= 0) { return new NativeArray(length); } @@ -621,7 +621,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self, final long length) { + public static NativeArray construct(final boolean newObj, final Object self, final long length) { if (length >= 0L && length <= JSType.MAX_UINT) { return new NativeArray(length); } @@ -640,7 +640,7 @@ public final class NativeArray extends ScriptObject { * @return the new NativeArray */ @SpecializedConstructor - public static Object construct(final boolean newObj, final Object self, final double length) { + public static NativeArray construct(final boolean newObj, final Object self, final double length) { final long uint32length = JSType.toUint32(length); if (uint32length == length) { @@ -658,7 +658,7 @@ public final class NativeArray extends ScriptObject { * @return resulting NativeArray */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object concat(final Object self, final Object... args) { + public static NativeArray concat(final Object self, final Object... args) { final ArrayList list = new ArrayList<>(); concatToList(list, Global.toObject(self)); @@ -705,7 +705,7 @@ public final class NativeArray extends ScriptObject { * @return string representation after join */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object join(final Object self, final Object separator) { + public static String join(final Object self, final Object separator) { final StringBuilder sb = new StringBuilder(); final Iterator iter = arrayLikeIterator(self, true); final String sep = separator == ScriptRuntime.UNDEFINED ? "," : JSType.toString(separator); @@ -973,7 +973,7 @@ public final class NativeArray extends ScriptObject { * @return sorted array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object sort(final Object self, final Object comparefn) { + public static ScriptObject sort(final Object self, final Object comparefn) { try { final ScriptObject sobj = (ScriptObject) self; final long len = JSType.toUint32(sobj.getLength()); @@ -1177,7 +1177,7 @@ public final class NativeArray extends ScriptObject { * @return index of element, or -1 if not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object indexOf(final Object self, final Object searchElement, final Object fromIndex) { + public static long indexOf(final Object self, final Object searchElement, final Object fromIndex) { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); @@ -1213,7 +1213,7 @@ public final class NativeArray extends ScriptObject { * @return index of element, or -1 if not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object lastIndexOf(final Object self, final Object... args) { + public static long lastIndexOf(final Object self, final Object... args) { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); @@ -1248,7 +1248,7 @@ public final class NativeArray extends ScriptObject { * @return true if callback function return true for every element in the array, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object every(final Object self, final Object callbackfn, final Object thisArg) { + public static boolean every(final Object self, final Object callbackfn, final Object thisArg) { return applyEvery(Global.toObject(self), callbackfn, thisArg); } @@ -1272,7 +1272,7 @@ public final class NativeArray extends ScriptObject { * @return true if callback function returned true for any element in the array, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object some(final Object self, final Object callbackfn, final Object thisArg) { + public static boolean some(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, false) { private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER(); @@ -1313,7 +1313,7 @@ public final class NativeArray extends ScriptObject { * @return array with elements transformed by map function */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object map(final Object self, final Object callbackfn, final Object thisArg) { + public static NativeArray map(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, null) { private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER(); @@ -1342,7 +1342,7 @@ public final class NativeArray extends ScriptObject { * @return filtered array */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object filter(final Object self, final Object callbackfn, final Object thisArg) { + public static NativeArray filter(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { private long to = 0; private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java index 49a61c96df3..70c97daf27b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java @@ -45,7 +45,7 @@ final class NativeArrayBuffer extends ScriptObject { private static PropertyMap $nasgenmap$; @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { + public static NativeArrayBuffer constructor(final boolean newObj, final Object self, final Object... args) { if (args.length == 0) { throw new RuntimeException("missing length argument"); } @@ -81,7 +81,7 @@ final class NativeArrayBuffer extends ScriptObject { } @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object slice(final Object self, final Object begin0, final Object end0) { + public static NativeArrayBuffer slice(final Object self, final Object begin0, final Object end0) { final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self; int begin = JSType.toInt32(begin0); int end = end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : arrayBuffer.getByteLength(); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java index f737a6c898b..d645d6dd4e6 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java @@ -110,7 +110,7 @@ public final class NativeBoolean extends ScriptObject { * @return string representation of this boolean */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return getBoolean(self).toString(); } @@ -121,7 +121,7 @@ public final class NativeBoolean extends ScriptObject { * @return value of this boolean */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static boolean valueOf(final Object self) { return getBoolean(self); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java index 93b5f09f90c..414ff8ae5ce 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java @@ -131,7 +131,7 @@ public class NativeDataView extends ScriptObject { * @return newly constructed DataView object */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { + public static NativeDataView constructor(final boolean newObj, final Object self, final Object... args) { if (args.length == 0 || !(args[0] instanceof NativeArrayBuffer)) { throw typeError("not.an.arraybuffer.in.dataview"); } @@ -157,7 +157,7 @@ public class NativeDataView extends ScriptObject { * @return newly constructed DataView object */ @SpecializedConstructor - public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) { + public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) { if (!(arrBuf instanceof NativeArrayBuffer)) { throw typeError("not.an.arraybuffer.in.dataview"); } @@ -175,7 +175,7 @@ public class NativeDataView extends ScriptObject { * @return newly constructed DataView object */ @SpecializedConstructor - public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) { + public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) { if (!(arrBuf instanceof NativeArrayBuffer)) { throw typeError("not.an.arraybuffer.in.dataview"); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java index 34e27f173ac..b3661df7eb2 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java @@ -226,7 +226,7 @@ public final class NativeDate extends ScriptObject { * @return Date interpreted from the string, or NaN for illegal values */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object parse(final Object self, final Object string) { + public static double parse(final Object self, final Object string) { return parseDateString(JSType.toString(string)); } @@ -238,7 +238,7 @@ public final class NativeDate extends ScriptObject { * @return a time clip according to the ECMA specification */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 7, where = Where.CONSTRUCTOR) - public static Object UTC(final Object self, final Object... args) { + public static double UTC(final Object self, final Object... args) { final NativeDate nd = new NativeDate(0); final double[] d = convertCtorArgs(args); final double time = d == null ? Double.NaN : timeClip(makeDate(d)); @@ -253,8 +253,8 @@ public final class NativeDate extends ScriptObject { * @return a Date that points to the current moment in time */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object now(final Object self) { - return (double)System.currentTimeMillis(); + public static long now(final Object self) { + return System.currentTimeMillis(); } /** @@ -264,7 +264,7 @@ public final class NativeDate extends ScriptObject { * @return string value that represents the Date in the current time zone */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return toStringImpl(self, FORMAT_DATE_TIME); } @@ -275,7 +275,7 @@ public final class NativeDate extends ScriptObject { * @return string value with the "date" part of the Date in the current time zone */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toDateString(final Object self) { + public static String toDateString(final Object self) { return toStringImpl(self, FORMAT_DATE); } @@ -286,7 +286,7 @@ public final class NativeDate extends ScriptObject { * @return string value with "time" part of Date in the current time zone */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toTimeString(final Object self) { + public static String toTimeString(final Object self) { return toStringImpl(self, FORMAT_TIME); } @@ -297,7 +297,7 @@ public final class NativeDate extends ScriptObject { * @return string value that represents the Data in the current time zone and locale */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleString(final Object self) { + public static String toLocaleString(final Object self) { return toStringImpl(self, FORMAT_LOCAL_DATE_TIME); } @@ -308,7 +308,7 @@ public final class NativeDate extends ScriptObject { * @return string value with the "date" part of the Date in the current time zone and locale */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleDateString(final Object self) { + public static String toLocaleDateString(final Object self) { return toStringImpl(self, FORMAT_LOCAL_DATE); } @@ -319,7 +319,7 @@ public final class NativeDate extends ScriptObject { * @return string value with the "time" part of Date in the current time zone and locale */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleTimeString(final Object self) { + public static String toLocaleTimeString(final Object self) { return toStringImpl(self, FORMAT_LOCAL_TIME); } @@ -330,7 +330,7 @@ public final class NativeDate extends ScriptObject { * @return valueOf - a number which is this time value */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static double valueOf(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null) ? nd.getTime() : Double.NaN; } @@ -342,7 +342,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getTime(final Object self) { + public static double getTime(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null) ? nd.getTime() : Double.NaN; } @@ -365,7 +365,7 @@ public final class NativeDate extends ScriptObject { * @return UTC full year */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCFullYear(final Object self) { + public static double getUTCFullYear(final Object self) { return getUTCField(self, YEAR); } @@ -376,7 +376,7 @@ public final class NativeDate extends ScriptObject { * @return year */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getYear(final Object self) { + public static double getYear(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null && nd.isValidDate()) ? (yearFromTime(nd.getLocalTime()) - 1900) : Double.NaN; } @@ -388,7 +388,7 @@ public final class NativeDate extends ScriptObject { * @return month */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getMonth(final Object self) { + public static double getMonth(final Object self) { return getField(self, MONTH); } @@ -399,7 +399,7 @@ public final class NativeDate extends ScriptObject { * @return UTC month */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCMonth(final Object self) { + public static double getUTCMonth(final Object self) { return getUTCField(self, MONTH); } @@ -410,7 +410,7 @@ public final class NativeDate extends ScriptObject { * @return date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getDate(final Object self) { + public static double getDate(final Object self) { return getField(self, DAY); } @@ -421,7 +421,7 @@ public final class NativeDate extends ScriptObject { * @return UTC Date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCDate(final Object self) { + public static double getUTCDate(final Object self) { return getUTCField(self, DAY); } @@ -432,7 +432,7 @@ public final class NativeDate extends ScriptObject { * @return day */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getDay(final Object self) { + public static double getDay(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null && nd.isValidDate()) ? weekDay(nd.getLocalTime()) : Double.NaN; } @@ -444,7 +444,7 @@ public final class NativeDate extends ScriptObject { * @return UTC day */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCDay(final Object self) { + public static double getUTCDay(final Object self) { final NativeDate nd = getNativeDate(self); return (nd != null && nd.isValidDate()) ? weekDay(nd.getTime()) : Double.NaN; } @@ -456,7 +456,7 @@ public final class NativeDate extends ScriptObject { * @return hours */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getHours(final Object self) { + public static double getHours(final Object self) { return getField(self, HOUR); } @@ -467,7 +467,7 @@ public final class NativeDate extends ScriptObject { * @return UTC hours */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCHours(final Object self) { + public static double getUTCHours(final Object self) { return getUTCField(self, HOUR); } @@ -478,7 +478,7 @@ public final class NativeDate extends ScriptObject { * @return minutes */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getMinutes(final Object self) { + public static double getMinutes(final Object self) { return getField(self, MINUTE); } @@ -489,7 +489,7 @@ public final class NativeDate extends ScriptObject { * @return UTC minutes */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCMinutes(final Object self) { + public static double getUTCMinutes(final Object self) { return getUTCField(self, MINUTE); } @@ -500,7 +500,7 @@ public final class NativeDate extends ScriptObject { * @return seconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getSeconds(final Object self) { + public static double getSeconds(final Object self) { return getField(self, SECOND); } @@ -511,7 +511,7 @@ public final class NativeDate extends ScriptObject { * @return UTC seconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCSeconds(final Object self) { + public static double getUTCSeconds(final Object self) { return getUTCField(self, SECOND); } @@ -522,7 +522,7 @@ public final class NativeDate extends ScriptObject { * @return milliseconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getMilliseconds(final Object self) { + public static double getMilliseconds(final Object self) { return getField(self, MILLISECOND); } @@ -533,7 +533,7 @@ public final class NativeDate extends ScriptObject { * @return UTC milliseconds */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getUTCMilliseconds(final Object self) { + public static double getUTCMilliseconds(final Object self) { return getUTCField(self, MILLISECOND); } @@ -544,7 +544,7 @@ public final class NativeDate extends ScriptObject { * @return time zone offset or NaN if N/A */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object getTimezoneOffset(final Object self) { + public static double getTimezoneOffset(final Object self) { final NativeDate nd = getNativeDate(self); if (nd != null && nd.isValidDate()) { final long msec = (long) nd.getTime(); @@ -561,7 +561,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object setTime(final Object self, final Object time) { + public static double setTime(final Object self, final Object time) { final NativeDate nd = getNativeDate(self); final double num = timeClip(JSType.toNumber(time)); nd.setTime(num); @@ -576,7 +576,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setMilliseconds(final Object self, final Object... args) { + public static double setMilliseconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MILLISECOND, args, true); return nd.getTime(); @@ -590,7 +590,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setUTCMilliseconds(final Object self, final Object... args) { + public static double setUTCMilliseconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MILLISECOND, args, false); return nd.getTime(); @@ -604,7 +604,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setSeconds(final Object self, final Object... args) { + public static double setSeconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, SECOND, args, true); return nd.getTime(); @@ -618,7 +618,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setUTCSeconds(final Object self, final Object... args) { + public static double setUTCSeconds(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, SECOND, args, false); return nd.getTime(); @@ -632,7 +632,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setMinutes(final Object self, final Object... args) { + public static double setMinutes(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MINUTE, args, true); return nd.getTime(); @@ -646,7 +646,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setUTCMinutes(final Object self, final Object... args) { + public static double setUTCMinutes(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MINUTE, args, false); return nd.getTime(); @@ -660,7 +660,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4) - public static Object setHours(final Object self, final Object... args) { + public static double setHours(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, HOUR, args, true); return nd.getTime(); @@ -674,7 +674,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4) - public static Object setUTCHours(final Object self, final Object... args) { + public static double setUTCHours(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, HOUR, args, false); return nd.getTime(); @@ -688,7 +688,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setDate(final Object self, final Object... args) { + public static double setDate(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, DAY, args, true); return nd.getTime(); @@ -702,7 +702,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object setUTCDate(final Object self, final Object... args) { + public static double setUTCDate(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, DAY, args, false); return nd.getTime(); @@ -716,7 +716,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setMonth(final Object self, final Object... args) { + public static double setMonth(final Object self, final Object... args) { final NativeDate nd = getNativeDate(self); setFields(nd, MONTH, args, true); return nd.getTime(); @@ -730,7 +730,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2) - public static Object setUTCMonth(final Object self, final Object... args) { + public static double setUTCMonth(final Object self, final Object... args) { final NativeDate nd = ensureNativeDate(self); setFields(nd, MONTH, args, false); return nd.getTime(); @@ -744,7 +744,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setFullYear(final Object self, final Object... args) { + public static double setFullYear(final Object self, final Object... args) { final NativeDate nd = ensureNativeDate(self); if (nd.isValidDate()) { setFields(nd, YEAR, args, true); @@ -767,7 +767,7 @@ public final class NativeDate extends ScriptObject { * @return time */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3) - public static Object setUTCFullYear(final Object self, final Object... args) { + public static double setUTCFullYear(final Object self, final Object... args) { final NativeDate nd = ensureNativeDate(self); if (nd.isValidDate()) { setFields(nd, YEAR, args, false); @@ -786,7 +786,7 @@ public final class NativeDate extends ScriptObject { * @return NativeDate */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object setYear(final Object self, final Object year) { + public static double setYear(final Object self, final Object year) { final NativeDate nd = getNativeDate(self); if (isNaN(nd.getTime())) { nd.setTime(utc(0, nd.getTimeZone())); @@ -813,7 +813,7 @@ public final class NativeDate extends ScriptObject { * @return string representation of date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toUTCString(final Object self) { + public static String toUTCString(final Object self) { return toGMTStringImpl(self); } @@ -826,7 +826,7 @@ public final class NativeDate extends ScriptObject { * @return string representation of date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toGMTString(final Object self) { + public static String toGMTString(final Object self) { return toGMTStringImpl(self); } @@ -837,7 +837,7 @@ public final class NativeDate extends ScriptObject { * @return string representation of date */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toISOString(final Object self) { + public static String toISOString(final Object self) { return toISOStringImpl(self); } @@ -1282,14 +1282,14 @@ public final class NativeDate extends ScriptObject { } } - private static Object getField(final Object self, final int field) { + private static double getField(final Object self, final int field) { final NativeDate nd = getNativeDate(self); - return (nd != null && nd.isValidDate()) ? valueFromTime(field, nd.getLocalTime()) : Double.NaN; + return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getLocalTime()) : Double.NaN; } - private static Object getUTCField(final Object self, final int field) { + private static double getUTCField(final Object self, final int field) { final NativeDate nd = getNativeDate(self); - return (nd != null && nd.isValidDate()) ? valueFromTime(field, nd.getTime()) : Double.NaN; + return (nd != null && nd.isValidDate()) ? (double)valueFromTime(field, nd.getTime()) : Double.NaN; } private static void setFields(final NativeDate nd, final int fieldId, final Object[] args, final boolean local) { @@ -1344,5 +1344,4 @@ public final class NativeDate extends ScriptObject { private TimeZone getTimeZone() { return timezone; } - } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java index 59b7b2fe379..5d80c37b06b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -116,7 +116,7 @@ public final class NativeDebug extends ScriptObject { * @return true if reference identity */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object identical(final Object self, final Object obj1, final Object obj2) { + public static boolean identical(final Object self, final Object obj1, final Object obj2) { return obj1 == obj2; } @@ -144,7 +144,7 @@ public final class NativeDebug extends ScriptObject { * @return return {@link Object#equals(Object)} for objects. */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object equals(final Object self, final Object obj1, final Object obj2) { + public static boolean equals(final Object self, final Object obj1, final Object obj2) { return Objects.equals(obj1, obj2); } @@ -156,7 +156,7 @@ public final class NativeDebug extends ScriptObject { * @return Java string representation of {@code obj} */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object toJavaString(final Object self, final Object obj) { + public static String toJavaString(final Object self, final Object obj) { return Objects.toString(obj); } @@ -168,7 +168,7 @@ public final class NativeDebug extends ScriptObject { * @return string representation */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object toIdentString(final Object self, final Object obj) { + public static String toIdentString(final Object self, final Object obj) { if (obj == null) { return "null"; } @@ -185,7 +185,7 @@ public final class NativeDebug extends ScriptObject { * @return listener count */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object getListenerCount(final Object self, final Object obj) { + public static int getListenerCount(final Object self, final Object obj) { return (obj instanceof ScriptObject) ? PropertyListeners.getListenerCount((ScriptObject) obj) : 0; } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java index 3dea27288b0..1b6b809412f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java @@ -126,7 +126,7 @@ public final class NativeError extends ScriptObject { * @return NativeError instance */ @Constructor - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeError(msg); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java index 2b343ede673..586c7cffb31 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java @@ -98,7 +98,7 @@ public final class NativeEvalError extends ScriptObject { * @return new EvalError */ @Constructor(name = "EvalError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeEvalError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeEvalError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java index b96c81c96f9..a9dfb7a4c6f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java @@ -136,8 +136,8 @@ public final class NativeFloat32Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeFloat32Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeFloat32Array)constructorImpl(args, FACTORY); } NativeFloat32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -192,8 +192,8 @@ public final class NativeFloat32Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeFloat32Array subarray(final Object self, final Object begin, final Object end) { + return (NativeFloat32Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java index af9251f44e1..61b58807f8f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java @@ -146,8 +146,8 @@ public final class NativeFloat64Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeFloat64Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeFloat64Array)constructorImpl(args, FACTORY); } NativeFloat64Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -202,8 +202,8 @@ public final class NativeFloat64Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeFloat64Array subarray(final Object self, final Object begin, final Object end) { + return (NativeFloat64Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java index d092cfb6bcb..3d45cc1f48a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java @@ -71,7 +71,7 @@ public final class NativeFunction { * @return string representation of Function */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { if (!(self instanceof ScriptFunction)) { throw typeError("not.a.function", ScriptRuntime.safeToString(self)); } @@ -174,7 +174,7 @@ public final class NativeFunction { * @return function with bound arguments */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object bind(final Object self, final Object... args) { + public static ScriptFunction bind(final Object self, final Object... args) { if (!(self instanceof ScriptFunction)) { throw typeError("not.a.function", ScriptRuntime.safeToString(self)); } @@ -199,7 +199,7 @@ public final class NativeFunction { * @return source for function */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toSource(final Object self) { + public static String toSource(final Object self) { if (!(self instanceof ScriptFunction)) { throw typeError("not.a.function", ScriptRuntime.safeToString(self)); } @@ -217,7 +217,7 @@ public final class NativeFunction { * @return new NativeFunction */ @Constructor(arity = 1) - public static Object function(final boolean newObj, final Object self, final Object... args) { + public static ScriptFunction function(final boolean newObj, final Object self, final Object... args) { final StringBuilder sb = new StringBuilder(); sb.append("(function ("); @@ -253,7 +253,7 @@ public final class NativeFunction { final Global global = Global.instance(); - return Global.directEval(global, sb.toString(), global, "", global.isStrictContext()); + return (ScriptFunction)Global.directEval(global, sb.toString(), global, "", global.isStrictContext()); } private static void checkFunctionParameters(final String params) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java index e24691afd38..f6aa2054a36 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java @@ -100,8 +100,8 @@ public final class NativeInt16Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeInt16Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeInt16Array)constructorImpl(args, FACTORY); } NativeInt16Array(final NativeArrayBuffer buffer, final int byteOffset, final int byteLength) { @@ -151,8 +151,8 @@ public final class NativeInt16Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeInt16Array subarray(final Object self, final Object begin, final Object end) { + return (NativeInt16Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java index b25f84951d2..643bd81699f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java @@ -103,8 +103,8 @@ public final class NativeInt32Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeInt32Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeInt32Array)constructorImpl(args, FACTORY); } NativeInt32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -154,8 +154,8 @@ public final class NativeInt32Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeInt32Array subarray(final Object self, final Object begin, final Object end) { + return (NativeInt32Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java index e50691076b2..5822c6d5017 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java @@ -93,8 +93,8 @@ public final class NativeInt8Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeInt8Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeInt8Array)constructorImpl(args, FACTORY); } NativeInt8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -144,8 +144,8 @@ public final class NativeInt8Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeInt8Array subarray(final Object self, final Object begin, final Object end) { + return (NativeInt8Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java index b71b4276cd8..84036a328f9 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java @@ -536,7 +536,7 @@ public final class NativeJSAdapter extends ScriptObject { * @return new NativeJSAdapter */ @Constructor - public static Object construct(final boolean isNew, final Object self, final Object... args) { + public static NativeJSAdapter construct(final boolean isNew, final Object self, final Object... args) { Object proto = UNDEFINED; Object overrides = UNDEFINED; Object adaptee; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java index b863e24f2a5..7879bab4f4b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java @@ -75,7 +75,7 @@ public final class NativeJava { * @see #type(Object, Object) */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isType(final Object self, final Object type) { + public static boolean isType(final Object self, final Object type) { return type instanceof StaticClass; } @@ -338,7 +338,7 @@ public final class NativeJava { * null. */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object from(final Object self, final Object objArray) { + public static NativeArray from(final Object self, final Object objArray) { if (objArray == null) { return null; } else if (objArray instanceof Collection) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java index 49be8a7c473..40ecbffca9a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java @@ -86,7 +86,7 @@ public final class NativeJavaImporter extends ScriptObject { * @return NativeJavaImporter instance */ @Constructor(arity = 1) - public static Object constructor(final boolean isNew, final Object self, final Object... args) { + public static NativeJavaImporter constructor(final boolean isNew, final Object self, final Object... args) { return new NativeJavaImporter(args); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java index 4181d205051..a95587efddb 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java @@ -185,7 +185,7 @@ public final class NativeNumber extends ScriptObject { * @return number in decimal fixed point notation */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toFixed(final Object self, final Object fractionDigits) { + public static String toFixed(final Object self, final Object fractionDigits) { final int f = JSType.toInteger(fractionDigits); if (f < 0 || f > 20) { throw rangeError("invalid.fraction.digits", "toFixed"); @@ -217,7 +217,7 @@ public final class NativeNumber extends ScriptObject { * @return number in decimal exponential notation */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toExponential(final Object self, final Object fractionDigits) { + public static String toExponential(final Object self, final Object fractionDigits) { final double x = getNumberValue(self); final boolean trimZeros = fractionDigits == UNDEFINED; final int f = trimZeros ? 16 : JSType.toInteger(fractionDigits); @@ -245,7 +245,7 @@ public final class NativeNumber extends ScriptObject { * @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision} */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toPrecision(final Object self, final Object precision) { + public static String toPrecision(final Object self, final Object precision) { final double x = getNumberValue(self); if (precision == UNDEFINED) { return JSType.toString(x); @@ -278,7 +278,7 @@ public final class NativeNumber extends ScriptObject { * @return string representation of this Number in the given radix */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self, final Object radix) { + public static String toString(final Object self, final Object radix) { if (radix != UNDEFINED) { final int intRadix = JSType.toInteger(radix); if (intRadix != 10) { @@ -299,7 +299,7 @@ public final class NativeNumber extends ScriptObject { * @return localized string for this Number */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleString(final Object self) { + public static String toLocaleString(final Object self) { return JSType.toString(getNumberValue(self)); } @@ -308,10 +308,10 @@ public final class NativeNumber extends ScriptObject { * ECMA 15.7.4.4 Number.prototype.valueOf ( ) * * @param self self reference - * @return boxed number value for this Number + * @return number value for this Number */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static double valueOf(final Object self) { return getNumberValue(self); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java index 26335f631e8..9cde4faf417 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java @@ -111,7 +111,7 @@ public final class NativeObject { * @return the 'obj' object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) { + public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) { Global.checkObject(obj); final ScriptObject sobj = (ScriptObject)obj; if (buf instanceof ByteBuffer) { @@ -203,7 +203,7 @@ public final class NativeObject { * @return array of property names */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object getOwnPropertyNames(final Object self, final Object obj) { + public static ScriptObject getOwnPropertyNames(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return new NativeArray(((ScriptObject)obj).getOwnKeys(true)); } else if (obj instanceof ScriptObjectMirror) { @@ -222,7 +222,7 @@ public final class NativeObject { * @return object created */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object create(final Object self, final Object proto, final Object props) { + public static ScriptObject create(final Object self, final Object proto, final Object props) { if (proto != null) { Global.checkObject(proto); } @@ -248,10 +248,11 @@ public final class NativeObject { * @return object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) { + public static ScriptObject defineProperty(final Object self, final Object obj, final Object prop, final Object attr) { Global.checkObject(obj); - ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true); - return obj; + final ScriptObject sobj = (ScriptObject)obj; + sobj.defineOwnProperty(JSType.toString(prop), attr, true); + return sobj; } /** @@ -263,7 +264,7 @@ public final class NativeObject { * @return object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object defineProperties(final Object self, final Object obj, final Object props) { + public static ScriptObject defineProperties(final Object self, final Object obj, final Object props) { Global.checkObject(obj); final ScriptObject sobj = (ScriptObject)obj; @@ -342,7 +343,7 @@ public final class NativeObject { * @return true if sealed, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isSealed(final Object self, final Object obj) { + public static boolean isSealed(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).isSealed(); } else if (obj instanceof ScriptObjectMirror) { @@ -360,7 +361,7 @@ public final class NativeObject { * @return true if object is frozen, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isFrozen(final Object self, final Object obj) { + public static boolean isFrozen(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).isFrozen(); } else if (obj instanceof ScriptObjectMirror) { @@ -378,7 +379,7 @@ public final class NativeObject { * @return true if object is extensible, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object isExtensible(final Object self, final Object obj) { + public static boolean isExtensible(final Object self, final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).isExtensible(); } else if (obj instanceof ScriptObjectMirror) { @@ -396,7 +397,7 @@ public final class NativeObject { * @return array of keys in object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static Object keys(final Object self, final Object obj) { + public static ScriptObject keys(final Object self, final Object obj) { if (obj instanceof ScriptObject) { final ScriptObject sobj = (ScriptObject)obj; return new NativeArray(sobj.getOwnKeys(false)); @@ -453,7 +454,7 @@ public final class NativeObject { * @return ToString of object */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return ScriptRuntime.builtinObjectToString(self); } @@ -506,7 +507,7 @@ public final class NativeObject { * @return true if property exists in object */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object hasOwnProperty(final Object self, final Object v) { + public static boolean hasOwnProperty(final Object self, final Object v) { // Convert ScriptObjects to primitive with String.class hint // but no need to convert other primitives to string. final Object key = JSType.toPrimitive(v, String.class); @@ -523,7 +524,7 @@ public final class NativeObject { * @return true if object is prototype of v */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object isPrototypeOf(final Object self, final Object v) { + public static boolean isPrototypeOf(final Object self, final Object v) { if (!(v instanceof ScriptObject)) { return false; } @@ -549,7 +550,7 @@ public final class NativeObject { * @return true if property is enumerable */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object propertyIsEnumerable(final Object self, final Object v) { + public static boolean propertyIsEnumerable(final Object self, final Object v) { final String str = JSType.toString(v); final Object obj = Global.toObject(self); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java index 4b2bebcfd2d..ff3ac7b77c0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java @@ -98,7 +98,7 @@ public final class NativeRangeError extends ScriptObject { * @return new RangeError */ @Constructor(name = "RangeError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeRangeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeRangeError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java index 504f16ecd6c..741901796b0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java @@ -98,7 +98,7 @@ public final class NativeReferenceError extends ScriptObject { * @return new ReferenceError */ @Constructor(name = "ReferenceError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeReferenceError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeReferenceError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java index 04b828bfc21..89a9a828455 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -122,7 +122,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @Constructor(arity = 2) - public static Object constructor(final boolean isNew, final Object self, final Object... args) { + public static NativeRegExp constructor(final boolean isNew, final Object self, final Object... args) { if (args.length > 1) { return newRegExp(args[0], args[1]); } else if (args.length > 0) { @@ -142,7 +142,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @SpecializedConstructor - public static Object constructor(final boolean isNew, final Object self) { + public static NativeRegExp constructor(final boolean isNew, final Object self) { return new NativeRegExp("", ""); } @@ -157,7 +157,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @SpecializedConstructor - public static Object constructor(final boolean isNew, final Object self, final Object pattern) { + public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern) { return newRegExp(pattern, UNDEFINED); } @@ -173,7 +173,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @SpecializedConstructor - public static Object constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) { + public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) { return newRegExp(pattern, flags); } @@ -283,7 +283,7 @@ public final class NativeRegExp extends ScriptObject { * @return new NativeRegExp */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object compile(final Object self, final Object pattern, final Object flags) { + public static ScriptObject compile(final Object self, final Object pattern, final Object flags) { final NativeRegExp regExp = checkRegExp(self); final NativeRegExp compiled = newRegExp(pattern, flags); // copy over regexp to 'self' @@ -302,7 +302,7 @@ public final class NativeRegExp extends ScriptObject { * @return array containing the matches or {@code null} if no match */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object exec(final Object self, final Object string) { + public static ScriptObject exec(final Object self, final Object string) { return checkRegExp(self).exec(JSType.toString(string)); } @@ -314,7 +314,7 @@ public final class NativeRegExp extends ScriptObject { * @return true if matches found, false otherwise */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object test(final Object self, final Object string) { + public static boolean test(final Object self, final Object string) { return checkRegExp(self).test(JSType.toString(string)); } @@ -325,7 +325,7 @@ public final class NativeRegExp extends ScriptObject { * @return string version of regexp */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return checkRegExp(self).toString(); } @@ -618,7 +618,7 @@ public final class NativeRegExp extends ScriptObject { * @param string String to match. * @return NativeArray of matches, string or null. */ - public Object exec(final String string) { + public NativeRegExpExecResult exec(final String string) { final RegExpResult match = execInner(string); if (match == null) { @@ -635,7 +635,7 @@ public final class NativeRegExp extends ScriptObject { * @param string String to match. * @return True if a match is found. */ - public Object test(final String string) { + public boolean test(final String string) { return execInner(string) != null; } @@ -649,7 +649,7 @@ public final class NativeRegExp extends ScriptObject { * @param replacement Replacement string. * @return String with substitutions. */ - Object replace(final String string, final String replacement, final ScriptFunction function) { + String replace(final String string, final String replacement, final ScriptFunction function) { final RegExpMatcher matcher = regexp.match(string); if (matcher == null) { @@ -804,7 +804,7 @@ public final class NativeRegExp extends ScriptObject { * @param limit Split limit. * @return Array of substrings. */ - Object split(final String string, final long limit) { + NativeArray split(final String string, final long limit) { if (limit == 0L) { return new NativeArray(); } @@ -867,7 +867,7 @@ public final class NativeRegExp extends ScriptObject { * @param string String to match. * @return Index of match. */ - Object search(final String string) { + int search(final String string) { final RegExpResult match = execInner(string); if (match == null) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java index c75b2b00362..51edf75a44f 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java @@ -425,7 +425,7 @@ public final class NativeString extends ScriptObject { * @return string with arguments translated to charcodes */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1, where = Where.CONSTRUCTOR) - public static Object fromCharCode(final Object self, final Object... args) { + public static String fromCharCode(final Object self, final Object... args) { final char[] buf = new char[args.length]; int index = 0; for (final Object arg : args) { @@ -441,7 +441,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final Object value) { + public static String fromCharCode(final Object self, final Object value) { try { return "" + (char)JSType.toUint16(((Number)value).doubleValue()); } catch (final ClassCastException e) { @@ -456,7 +456,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final int value) { + public static String fromCharCode(final Object self, final int value) { return "" + (char)(value & 0xffff); } @@ -467,7 +467,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final long value) { + public static String fromCharCode(final Object self, final long value) { return "" + (char)((int)value & 0xffff); } @@ -478,7 +478,7 @@ public final class NativeString extends ScriptObject { * @return string with one charcode */ @SpecializedFunction - public static Object fromCharCode(final Object self, final double value) { + public static String fromCharCode(final Object self, final double value) { return "" + (char)JSType.toUint16(value); } @@ -488,7 +488,7 @@ public final class NativeString extends ScriptObject { * @return self as string */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toString(final Object self) { + public static String toString(final Object self) { return getString(self); } @@ -498,7 +498,7 @@ public final class NativeString extends ScriptObject { * @return self as string */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object valueOf(final Object self) { + public static String valueOf(final Object self) { return getString(self); } @@ -509,7 +509,7 @@ public final class NativeString extends ScriptObject { * @return string representing the char at the given position */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object charAt(final Object self, final Object pos) { + public static String charAt(final Object self, final Object pos) { return charAtImpl(checkObjectToString(self), JSType.toInteger(pos)); } @@ -546,7 +546,7 @@ public final class NativeString extends ScriptObject { * @return number representing charcode at position */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object charCodeAt(final Object self, final Object pos) { + public static double charCodeAt(final Object self, final Object pos) { return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos)); } @@ -601,7 +601,7 @@ public final class NativeString extends ScriptObject { * @return position of first match or -1 */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object indexOf(final Object self, final Object search, final Object pos) { + public static int indexOf(final Object self, final Object search, final Object pos) { final String str = checkObjectToString(self); return str.indexOf(JSType.toString(search), JSType.toInteger(pos)); } @@ -649,7 +649,7 @@ public final class NativeString extends ScriptObject { * @return last position of match or -1 */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static Object lastIndexOf(final Object self, final Object search, final Object pos) { + public static int lastIndexOf(final Object self, final Object search, final Object pos) { final String str = checkObjectToString(self); final String searchStr = JSType.toString(search); @@ -680,7 +680,7 @@ public final class NativeString extends ScriptObject { * @return result of locale sensitive comparison operation between {@code self} and {@code that} */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object localeCompare(final Object self, final Object that) { + public static double localeCompare(final Object self, final Object that) { final String str = checkObjectToString(self); final Collator collator = Collator.getInstance(Global.getEnv()._locale); @@ -698,7 +698,7 @@ public final class NativeString extends ScriptObject { * @return array of regexp matches */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object match(final Object self, final Object regexp) { + public static ScriptObject match(final Object self, final Object regexp) { final String str = checkObjectToString(self); @@ -745,7 +745,7 @@ public final class NativeString extends ScriptObject { * @return string after replacement */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object replace(final Object self, final Object string, final Object replacement) { + public static String replace(final Object self, final Object string, final Object replacement) { final String str = checkObjectToString(self); @@ -771,7 +771,7 @@ public final class NativeString extends ScriptObject { * @return offset where match occurred */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object search(final Object self, final Object string) { + public static int search(final Object self, final Object string) { final String str = checkObjectToString(self); final NativeRegExp nativeRegExp = Global.toRegExp(string == UNDEFINED ? "" : string); @@ -788,7 +788,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object slice(final Object self, final Object start, final Object end) { + public static String slice(final Object self, final Object start, final Object end) { final String str = checkObjectToString(self); if (end == UNDEFINED) { @@ -805,7 +805,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final int start) { + public static String slice(final Object self, final int start) { final String str = checkObjectToString(self); final int from = (start < 0) ? Math.max(str.length() + start, 0) : Math.min(start, str.length()); @@ -820,7 +820,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final double start) { + public static String slice(final Object self, final double start) { return slice(self, (int)start); } @@ -833,7 +833,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final int start, final int end) { + public static String slice(final Object self, final int start, final int end) { final String str = checkObjectToString(self); final int len = str.length(); @@ -853,7 +853,7 @@ public final class NativeString extends ScriptObject { * @return sliced out substring */ @SpecializedFunction - public static Object slice(final Object self, final double start, final double end) { + public static String slice(final Object self, final double start, final double end) { return slice(self, (int)start, (int)end); } @@ -866,7 +866,7 @@ public final class NativeString extends ScriptObject { * @return array object in which splits have been placed */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object split(final Object self, final Object separator, final Object limit) { + public static ScriptObject split(final Object self, final Object separator, final Object limit) { final String str = checkObjectToString(self); final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit); @@ -882,7 +882,7 @@ public final class NativeString extends ScriptObject { return splitString(str, JSType.toString(separator), lim); } - private static Object splitString(String str, String separator, long limit) { + private static ScriptObject splitString(String str, String separator, long limit) { if (separator.isEmpty()) { final int length = (int) Math.min(str.length(), limit); final Object[] array = new Object[length]; @@ -923,7 +923,7 @@ public final class NativeString extends ScriptObject { * @return substring given start and length of section */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object substr(final Object self, final Object start, final Object length) { + public static String substr(final Object self, final Object start, final Object length) { final String str = JSType.toString(self); final int strLength = str.length(); @@ -946,7 +946,7 @@ public final class NativeString extends ScriptObject { * @return substring given start and end indexes */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object substring(final Object self, final Object start, final Object end) { + public static String substring(final Object self, final Object start, final Object end) { final String str = checkObjectToString(self); if (end == UNDEFINED) { @@ -1026,7 +1026,7 @@ public final class NativeString extends ScriptObject { * @return string to lower case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLowerCase(final Object self) { + public static String toLowerCase(final Object self) { return checkObjectToString(self).toLowerCase(Locale.ROOT); } @@ -1036,7 +1036,7 @@ public final class NativeString extends ScriptObject { * @return string to locale sensitive lower case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleLowerCase(final Object self) { + public static String toLocaleLowerCase(final Object self) { return checkObjectToString(self).toLowerCase(Global.getEnv()._locale); } @@ -1046,7 +1046,7 @@ public final class NativeString extends ScriptObject { * @return string to upper case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toUpperCase(final Object self) { + public static String toUpperCase(final Object self) { return checkObjectToString(self).toUpperCase(Locale.ROOT); } @@ -1056,7 +1056,7 @@ public final class NativeString extends ScriptObject { * @return string to locale sensitive upper case */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object toLocaleUpperCase(final Object self) { + public static String toLocaleUpperCase(final Object self) { return checkObjectToString(self).toUpperCase(Global.getEnv()._locale); } @@ -1066,7 +1066,7 @@ public final class NativeString extends ScriptObject { * @return string trimmed from whitespace */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object trim(final Object self) { + public static String trim(final Object self) { final String str = checkObjectToString(self); int start = 0; @@ -1088,7 +1088,7 @@ public final class NativeString extends ScriptObject { * @return string trimmed left from whitespace */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object trimLeft(final Object self) { + public static String trimLeft(final Object self) { final String str = checkObjectToString(self); int start = 0; @@ -1107,7 +1107,7 @@ public final class NativeString extends ScriptObject { * @return string trimmed right from whitespace */ @Function(attributes = Attribute.NOT_ENUMERABLE) - public static Object trimRight(final Object self) { + public static String trimRight(final Object self) { final String str = checkObjectToString(self); int start = 0; @@ -1120,7 +1120,7 @@ public final class NativeString extends ScriptObject { return str.substring(start, end + 1); } - private static Object newObj(final Object self, final CharSequence str) { + private static ScriptObject newObj(final Object self, final CharSequence str) { return new NativeString(str); } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java index 6515f3cc2e6..db7debb0151 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java @@ -94,7 +94,7 @@ public final class NativeSyntaxError extends ScriptObject { * @return new SyntaxError */ @Constructor(name = "SyntaxError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeSyntaxError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeSyntaxError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java index f799b1767d0..6e5a4934f2c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java @@ -94,7 +94,7 @@ public final class NativeTypeError extends ScriptObject { * @return new TypeError */ @Constructor(name = "TypeError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeTypeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeTypeError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java index fd59bc8a209..cf5fdaa041c 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java @@ -93,7 +93,7 @@ public final class NativeURIError extends ScriptObject { * @return new URIError */ @Constructor(name = "URIError") - public static Object constructor(final boolean newObj, final Object self, final Object msg) { + public static NativeURIError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeURIError(msg); } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java index ee91aef3b35..8aa3d628308 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java @@ -99,8 +99,8 @@ public final class NativeUint16Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint16Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint16Array)constructorImpl(args, FACTORY); } NativeUint16Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -150,8 +150,8 @@ public final class NativeUint16Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint16Array subarray(final Object self, final Object begin, final Object end) { + return (NativeUint16Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java index 58909dbaf52..738122466d8 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java @@ -118,8 +118,8 @@ public final class NativeUint32Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint32Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint32Array)constructorImpl(args, FACTORY); } NativeUint32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -169,8 +169,8 @@ public final class NativeUint32Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint32Array subarray(final Object self, final Object begin, final Object end) { + return (NativeUint32Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java index 0db1bee6f8d..1f30456350a 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java @@ -92,8 +92,8 @@ public final class NativeUint8Array extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint8Array constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint8Array)constructorImpl(args, FACTORY); } NativeUint8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -143,8 +143,8 @@ public final class NativeUint8Array extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint8Array subarray(final Object self, final Object begin, final Object end) { + return (NativeUint8Array)ArrayBufferView.subarrayImpl(self, begin, end); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java index f0db743cb21..d757ee3ab1d 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java @@ -109,8 +109,8 @@ public final class NativeUint8ClampedArray extends ArrayBufferView { * @return new typed array */ @Constructor(arity = 1) - public static Object constructor(final boolean newObj, final Object self, final Object... args) { - return constructorImpl(args, FACTORY); + public static NativeUint8ClampedArray constructor(final boolean newObj, final Object self, final Object... args) { + return (NativeUint8ClampedArray)constructorImpl(args, FACTORY); } NativeUint8ClampedArray(final NativeArrayBuffer buffer, final int byteOffset, final int length) { @@ -160,8 +160,8 @@ public final class NativeUint8ClampedArray extends ArrayBufferView { * @return sub array */ @Function(attributes = Attribute.NOT_ENUMERABLE) - protected static Object subarray(final Object self, final Object begin, final Object end) { - return ArrayBufferView.subarrayImpl(self, begin, end); + protected static NativeUint8ClampedArray subarray(final Object self, final Object begin, final Object end) { + return (NativeUint8ClampedArray)ArrayBufferView.subarrayImpl(self, begin, end); } @Override From fb9c998b1df3098a436ba33d5d8464fc47eac1ef Mon Sep 17 00:00:00 2001 From: Eric McCorkle Date: Thu, 27 Mar 2014 18:41:28 -0400 Subject: [PATCH 085/170] 8035768: Move TypeAnnotationPosition from Attribute.Compound to Attribute.TypeCompound Move position field into Compound, making Compound into a kind of "proto-annotation", representing the situation before we know what an Annotation's kink is Reviewed-by: jjg --- .../com/sun/tools/javac/code/Attribute.java | 129 +++++++++--------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java index ebcac8c0c19..14b238b2827 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java @@ -141,6 +141,7 @@ public abstract class Attribute implements AnnotationValue { * access this attribute. */ public final List> values; + public TypeAnnotationPosition position; private boolean synthesized = false; @@ -154,10 +155,67 @@ public abstract class Attribute implements AnnotationValue { } public Compound(Type type, - List> values) { + List> values, + TypeAnnotationPosition position) { super(type); this.values = values; + this.position = position; } + + public Compound(Type type, + List> values) { + this(type, values, null); + } + + @Override + public TypeAnnotationPosition getPosition() { + if (hasUnknownPosition()) { + if (values.size() != 0) { + Name valueName = values.head.fst.name.table.names.value; + Pair res = getElemPair(valueName); + position = res == null ? null : res.snd.getPosition(); + } + } + return position; + } + + public boolean isContainerTypeCompound() { + if (isSynthesized() && values.size() == 1) + return getFirstEmbeddedTC() != null; + return false; + } + + private Compound getFirstEmbeddedTC() { + if (values.size() == 1) { + Pair val = values.get(0); + if (val.fst.getSimpleName().contentEquals("value") + && val.snd instanceof Array) { + Array arr = (Array) val.snd; + if (arr.values.length != 0 + && arr.values[0] instanceof Attribute.TypeCompound) + return (Attribute.TypeCompound) arr.values[0]; + } + } + return null; + } + + public boolean tryFixPosition() { + if (!isContainerTypeCompound()) + return false; + + Compound from = getFirstEmbeddedTC(); + if (from != null && from.position != null && + from.position.type != TargetType.UNKNOWN) { + position = from.position; + return true; + } + return false; + } + + public boolean hasUnknownPosition() { + return position.type == TargetType.UNKNOWN; + } + public void accept(Visitor v) { v.visitCompound(this); } /** @@ -215,16 +273,6 @@ public abstract class Attribute implements AnnotationValue { return (DeclaredType) type; } - @Override - public TypeAnnotationPosition getPosition() { - if (values.size() != 0) { - Name valueName = values.head.fst.name.table.names.value; - Pair res = getElemPair(valueName); - return res == null ? null : res.snd.getPosition(); - } - return null; - } - public Map getElementValues() { Map valmap = new LinkedHashMap<>(); for (Pair value : values) @@ -234,62 +282,15 @@ public abstract class Attribute implements AnnotationValue { } public static class TypeCompound extends Compound { - public TypeAnnotationPosition position; - public TypeCompound(Compound compound, - TypeAnnotationPosition position) { - this(compound.type, compound.values, position); + TypeAnnotationPosition position) { + super(compound.type, compound.values, position); } + public TypeCompound(Type type, - List> values, - TypeAnnotationPosition position) { - super(type, values); - this.position = position; - } - - @Override - public TypeAnnotationPosition getPosition() { - if (hasUnknownPosition()) { - position = super.getPosition(); - } - return position; - } - - public boolean hasUnknownPosition() { - return position.type == TargetType.UNKNOWN; - } - - public boolean isContainerTypeCompound() { - if (isSynthesized() && values.size() == 1) - return getFirstEmbeddedTC() != null; - return false; - } - - private TypeCompound getFirstEmbeddedTC() { - if (values.size() == 1) { - Pair val = values.get(0); - if (val.fst.getSimpleName().contentEquals("value") - && val.snd instanceof Array) { - Array arr = (Array) val.snd; - if (arr.values.length != 0 - && arr.values[0] instanceof Attribute.TypeCompound) - return (Attribute.TypeCompound) arr.values[0]; - } - } - return null; - } - - public boolean tryFixPosition() { - if (!isContainerTypeCompound()) - return false; - - TypeCompound from = getFirstEmbeddedTC(); - if (from != null && from.position != null && - from.position.type != TargetType.UNKNOWN) { - position = from.position; - return true; - } - return false; + List> values, + TypeAnnotationPosition position) { + super(type, values, position); } } From 0a8095d53ab53a4eaea8c862f49b4bc20b04aa8e Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Fri, 28 Mar 2014 13:24:07 +0530 Subject: [PATCH 086/170] 8038615: test262 repo is now a git repo in github Reviewed-by: lagergren, hannesw --- nashorn/README | 9 +++++++-- nashorn/make/build.xml | 14 ++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/nashorn/README b/nashorn/README index 52b30919065..242d6077b67 100644 --- a/nashorn/README +++ b/nashorn/README @@ -81,13 +81,13 @@ TestNG library and placing its jar file into the lib subdirectory: After that, you can run the tests using: cd make - ant test + ant clean test You can also run the ECMA-262 test suite with Nashorn. In order to do that, you will need to get a copy of it and put it in test/script/external/test262 directory. A convenient way to do it is: - hg clone http://hg.ecmascript.org/tests/test262/ test/script/external/test262 + git clone https://github.com/tc39/test262 test/script/external/test262 Alternatively, you can check it out elsewhere and make test/script/external/test262 a symbolic link to that directory. After @@ -95,6 +95,11 @@ you've done this, you can run the ECMA-262 tests using: cd nashorn~jdk8/nashorn/make ant test262 + +Ant target to get/update external test suites: + + ant externals + ant update-externals These tests take time, so we have a parallelized runner for them that takes advantage of all processor cores on the computer: diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 74eae86a588..3c1954a2afd 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -42,6 +42,9 @@ + + + @@ -503,18 +506,17 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { - - + + - + - - + + - From 4cbd014b295c4bfb7a2840b24d3c444187378237 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 28 Mar 2014 14:59:56 +0100 Subject: [PATCH 087/170] 8038340: Cleanup and fix sysroot and devkit handling on Linux and Solaris Reviewed-by: ihse --- common/autoconf/basics.m4 | 142 ++- common/autoconf/build-performance.m4 | 4 +- common/autoconf/configure.ac | 3 + common/autoconf/flags.m4 | 40 +- common/autoconf/generated-configure.sh | 1157 +++++++++++++++--------- common/autoconf/libraries.m4 | 109 ++- common/autoconf/spec.gmk.in | 7 +- common/autoconf/toolchain.m4 | 34 +- common/bin/compare.sh | 2 +- make/common/NativeCompilation.gmk | 6 + make/devkit/Makefile | 2 +- make/devkit/Tools.gmk | 27 +- 12 files changed, 971 insertions(+), 562 deletions(-) diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 17ed7906f67..649f8ddfc29 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -46,10 +46,24 @@ AC_DEFUN([ADD_JVM_ARG_IF_OK], # Appends a string to a path variable, only adding the : when needed. AC_DEFUN([BASIC_APPEND_TO_PATH], [ - if test "x[$]$1" = x; then - $1="$2" - else - $1="[$]$1:$2" + if test "x$2" != x; then + if test "x[$]$1" = x; then + $1="$2" + else + $1="[$]$1:$2" + fi + fi +]) + +# Prepends a string to a path variable, only adding the : when needed. +AC_DEFUN([BASIC_PREPEND_TO_PATH], +[ + if test "x$2" != x; then + if test "x[$]$1" = x; then + $1="$2" + else + $1="$2:[$]$1" + fi fi ]) @@ -442,43 +456,95 @@ AC_DEFUN_ONCE([BASIC_SETUP_PATHS], # Locate the directory of this script. AUTOCONF_DIR=$TOPDIR/common/autoconf +]) + +AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], +[ + AC_ARG_WITH([devkit], [AS_HELP_STRING([--with-devkit], + [use this devkit for compilers, tools and resources])], + [ + BASIC_FIXUP_PATH([with_devkit]) + DEVKIT_ROOT="$with_devkit" + # Check for a meta data info file in the root of the devkit + if test -f "$DEVKIT_ROOT/devkit.info"; then + # This potentially sets the following: + # DEVKIT_NAME: A descriptive name of the devkit + # DEVKIT_TOOLCHAIN_PATH: Corresponds to --with-toolchain-path + # DEVKIT_EXTRA_PATH: Corresponds to --with-extra-path + # DEVKIT_SYSROOT: Corresponds to --with-sysroot + . $DEVKIT_ROOT/devkit.info + fi + + AC_MSG_CHECKING([for devkit]) + if test "x$DEVKIT_NAME" != x; then + AC_MSG_RESULT([$DEVKIT_NAME in $DEVKIT_ROOT]) + else + AC_MSG_RESULT([$DEVKIT_ROOT]) + fi + + if test "x$DEVKIT_EXTRA_PATH" != x; then + BASIC_PREPEND_TO_PATH([EXTRA_PATH],$DEVKIT_EXTRA_PATH) + fi + + # Fallback default of just /bin if DEVKIT_PATH is not defined + if test "x$DEVKIT_TOOLCHAIN_PATH" = x; then + DEVKIT_TOOLCHAIN_PATH="$DEVKIT_ROOT/bin" + fi + BASIC_PREPEND_TO_PATH([TOOLCHAIN_PATH],$DEVKIT_TOOLCHAIN_PATH) + + # If DEVKIT_SYSROOT is set, use that, otherwise try a couple of known + # places for backwards compatiblity. + if test "x$DEVKIT_SYSROOT" != x; then + SYSROOT="$DEVKIT_SYSROOT" + elif test -d "$DEVKIT_ROOT/$host_alias/libc"; then + SYSROOT="$DEVKIT_ROOT/$host_alias/libc" + elif test -d "$DEVKIT_ROOT/$host/sys-root"; then + SYSROOT="$DEVKIT_ROOT/$host/sys-root" + fi + ] + ) + + # You can force the sysroot if the sysroot encoded into the compiler tools + # is not correct. + AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root], + [alias for --with-sysroot for backwards compatability])], + [SYSROOT=$with_sys_root] + ) + + AC_ARG_WITH(sysroot, [AS_HELP_STRING([--with-sysroot], + [use this directory as sysroot)])], + [SYSROOT=$with_sysroot] + ) + + AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], + [alias for --with-toolchain-path for backwards compatibility])], + [BASIC_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_tools_dir)] + ) + + AC_ARG_WITH([toolchain-path], [AS_HELP_STRING([--with-toolchain-path], + [prepend these directories when searching for toolchain binaries (compilers etc)])], + [BASIC_PREPEND_TO_PATH([TOOLCHAIN_PATH],$with_toolchain_path)] + ) + + AC_ARG_WITH([extra-path], [AS_HELP_STRING([--with-extra-path], + [prepend these directories to the default path])], + [BASIC_PREPEND_TO_PATH([EXTRA_PATH],$with_extra_path)] + ) + + # Prepend the extra path to the global path + BASIC_PREPEND_TO_PATH([PATH],$EXTRA_PATH) if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then # Add extra search paths on solaris for utilities like ar and as etc... PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" fi - # You can force the sys-root if the sys-root encoded into the cross compiler tools - # is not correct. - AC_ARG_WITH(sys-root, [AS_HELP_STRING([--with-sys-root], - [pass this sys-root to the compilers and tools (for cross-compiling)])]) - - if test "x$with_sys_root" != x; then - SYS_ROOT=$with_sys_root - else - SYS_ROOT=/ - fi - AC_SUBST(SYS_ROOT) - - AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], - [search this directory for compilers and tools (for cross-compiling)])], - [TOOLS_DIR=$with_tools_dir] - ) - - AC_ARG_WITH([devkit], [AS_HELP_STRING([--with-devkit], - [use this directory as base for tools-dir and sys-root (for cross-compiling)])], - [ - if test "x$with_sys_root" != x; then - AC_MSG_ERROR([Cannot specify both --with-devkit and --with-sys-root at the same time]) - fi - BASIC_FIXUP_PATH([with_devkit]) - BASIC_APPEND_TO_PATH([TOOLS_DIR],$with_devkit/bin) - if test -d "$with_devkit/$host_alias/libc"; then - SYS_ROOT=$with_devkit/$host_alias/libc - elif test -d "$with_devkit/$host/sys-root"; then - SYS_ROOT=$with_devkit/$host/sys-root - fi - ]) + AC_MSG_CHECKING([for sysroot]) + AC_MSG_RESULT([$SYSROOT]) + AC_MSG_CHECKING([for toolchain path]) + AC_MSG_RESULT([$TOOLCHAIN_PATH]) + AC_MSG_CHECKING([for extra path]) + AC_MSG_RESULT([$EXTRA_PATH]) ]) AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], @@ -648,10 +714,10 @@ AC_DEFUN([BASIC_CHECK_GNU_MAKE], fi if test "x$FOUND_MAKE" = x; then - if test "x$TOOLS_DIR" != x; then - # We have a tools-dir, check that as well before giving up. + if test "x$TOOLCHAIN_PATH" != x; then + # We have a toolchain path, check that as well before giving up. OLD_PATH=$PATH - PATH=$TOOLS_DIR:$PATH + PATH=$TOOLCHAIN_PATH:$PATH AC_PATH_PROGS(CHECK_TOOLSDIR_GMAKE, gmake) BASIC_CHECK_MAKE_VERSION("$CHECK_TOOLSDIR_GMAKE", [gmake in tools-dir]) if test "x$FOUND_MAKE" = x; then diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index 500c3adb702..22a62748a13 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -169,8 +169,8 @@ AC_DEFUN([BPERF_SETUP_CCACHE], if test "x$enable_ccache" = xyes; then AC_MSG_RESULT([yes]) OLD_PATH="$PATH" - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi BASIC_REQUIRE_PROGS(CCACHE, ccache) CCACHE_STATUS="enabled" diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index a96a1d2bf0b..ec0d7490d59 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -100,6 +100,9 @@ JDKOPT_SETUP_DEBUG_LEVEL # With basic setup done, call the custom early hook. CUSTOM_EARLY_HOOK +# Check if we have devkits, extra paths or sysroot set. +BASIC_SETUP_DEVKIT + # To properly create a configuration name, we need to have the OpenJDK target # and options (variants and debug level) parsed. BASIC_SETUP_OUTPUT_DIR diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 1024b9400d6..a3f0803b0fe 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -119,6 +119,32 @@ AC_DEFUN_ONCE([FLAGS_SETUP_INIT_FLAGS], # FIXME: likely bug, should be CCXXFLAGS_JDK? or one for C or CXX. CCXXFLAGS="$CCXXFLAGS -nologo" fi + + if test "x$SYSROOT" != "x"; then + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + # Solaris Studio does not have a concept of sysroot. Instead we must + # make sure the default include and lib dirs are appended to each + # compile and link command line. + SYSROOT_CFLAGS="-I$SYSROOT/usr/include" + SYSROOT_LDFLAGS="-L$SYSROOT/usr/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/usr/ccs/lib$OPENJDK_TARGET_CPU_ISADIR" + fi + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + SYSROOT_CFLAGS="--sysroot=\"$SYSROOT\"" + SYSROOT_LDFLAGS="--sysroot=\"$SYSROOT\"" + elif test "x$TOOLCHAIN_TYPE" = xclang; then + SYSROOT_CFLAGS="-isysroot \"$SYSROOT\"" + SYSROOT_LDFLAGS="-isysroot \"$SYSROOT\"" + fi + # Propagate the sysroot args to hotspot + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $SYSROOT_LDFLAGS" + fi + AC_SUBST(SYSROOT_CFLAGS) + AC_SUBST(SYSROOT_LDFLAGS) ]) AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS], @@ -421,9 +447,9 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], LDFLAGS_JDK="${LDFLAGS_JDK} $with_extra_ldflags" # Hotspot needs these set in their legacy form - LEGACY_EXTRA_CFLAGS=$with_extra_cflags - LEGACY_EXTRA_CXXFLAGS=$with_extra_cxxflags - LEGACY_EXTRA_LDFLAGS=$with_extra_ldflags + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $with_extra_cflags" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $with_extra_cxxflags" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $with_extra_ldflags" AC_SUBST(LEGACY_EXTRA_CFLAGS) AC_SUBST(LEGACY_EXTRA_CXXFLAGS) @@ -521,7 +547,13 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_LITTLE_ENDIAN" fi else - CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they + # are defined in the system? + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN=" + else + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + fi fi # Setup target OS define. Use OS target name but in upper case. diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 6b7a52bd273..dd040cee005 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -664,7 +664,6 @@ FREETYPE_BUNDLE_LIB_PATH FREETYPE_LIBS FREETYPE_CFLAGS CUPS_CFLAGS -OPENWIN_HOME X_EXTRA_LIBS X_LIBS X_PRE_LIBS @@ -708,6 +707,8 @@ SET_EXECUTABLE_ORIGIN SHARED_LIBRARY_FLAGS CXX_FLAG_REORDER C_FLAG_REORDER +SYSROOT_LDFLAGS +SYSROOT_CFLAGS RC_FLAGS AR_OUT_OPTION LD_OUT_OPTION @@ -760,7 +761,7 @@ CXXFLAGS CXX ac_ct_PROPER_COMPILER_CXX PROPER_COMPILER_CXX -TOOLS_DIR_CXX +TOOLCHAIN_PATH_CXX POTENTIAL_CXX OBJEXT EXEEXT @@ -771,7 +772,7 @@ CFLAGS CC ac_ct_PROPER_COMPILER_CC PROPER_COMPILER_CC -TOOLS_DIR_CC +TOOLCHAIN_PATH_CC POTENTIAL_CC VS_PATH VS_LIB @@ -887,7 +888,6 @@ SET_OPENJDK BUILD_LOG_WRAPPER BUILD_LOG_PREVIOUS BUILD_LOG -SYS_ROOT TOPDIR PATH_SEP ZERO_ARCHDEF @@ -1020,9 +1020,6 @@ ac_subst_files='' ac_user_opts=' enable_option_checking with_target_bits -with_sys_root -with_tools_dir -with_devkit enable_openjdk_only with_custom_make_dir with_jdk_variant @@ -1030,6 +1027,12 @@ with_jvm_interpreter with_jvm_variants enable_debug with_debug_level +with_devkit +with_sys_root +with_sysroot +with_tools_dir +with_toolchain_path +with_extra_path with_conf_name with_builddeps_conf with_builddeps_server @@ -1848,12 +1851,6 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-target-bits build 32-bit or 64-bit binaries (for platforms that support it), e.g. --with-target-bits=32 [guessed] - --with-sys-root pass this sys-root to the compilers and tools (for - cross-compiling) - --with-tools-dir search this directory for compilers and tools (for - cross-compiling) - --with-devkit use this directory as base for tools-dir and - sys-root (for cross-compiling) --with-custom-make-dir Deprecated. Option is kept for backwards compatibility and is ignored --with-jdk-variant JDK variant to build (normal) [normal] @@ -1863,6 +1860,14 @@ Optional Packages: [server] --with-debug-level set the debug level (release, fastdebug, slowdebug, optimized (HotSpot build only)) [release] + --with-devkit use this devkit for compilers, tools and resources + --with-sys-root alias for --with-sysroot for backwards compatability + --with-sysroot use this directory as sysroot) + --with-tools-dir alias for --with-toolchain-path for backwards + compatibility + --with-toolchain-path prepend these directories when searching for + toolchain binaries (compilers etc) + --with-extra-path prepend these directories to the default path --with-conf-name use this as the name of the configuration [generated from important configuration options] --with-builddeps-conf use this configuration file for the builddeps @@ -3325,6 +3330,9 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Appends a string to a path variable, only adding the : when needed. +# Prepends a string to a path variable, only adding the : when needed. + + # This will make sure the given variable points to a full and proper # path. This means: # 1) There will be no spaces in the path. On posix platforms, @@ -3407,6 +3415,8 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + #%%% Simple tools %%% # Check if we have found a usable version of make @@ -4233,7 +4243,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1395652496 +DATE_WHEN_GENERATED=1395839362 ############################################################################### # @@ -14240,180 +14250,6 @@ $as_echo "$as_me: The path of TOPDIR, which resolves as \"$path\", is invalid." # Locate the directory of this script. AUTOCONF_DIR=$TOPDIR/common/autoconf - if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then - # Add extra search paths on solaris for utilities like ar and as etc... - PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" - fi - - # You can force the sys-root if the sys-root encoded into the cross compiler tools - # is not correct. - -# Check whether --with-sys-root was given. -if test "${with_sys_root+set}" = set; then : - withval=$with_sys_root; -fi - - - if test "x$with_sys_root" != x; then - SYS_ROOT=$with_sys_root - else - SYS_ROOT=/ - fi - - - -# Check whether --with-tools-dir was given. -if test "${with_tools_dir+set}" = set; then : - withval=$with_tools_dir; TOOLS_DIR=$with_tools_dir - -fi - - - -# Check whether --with-devkit was given. -if test "${with_devkit+set}" = set; then : - withval=$with_devkit; - if test "x$with_sys_root" != x; then - as_fn_error $? "Cannot specify both --with-devkit and --with-sys-root at the same time" "$LINENO" 5 - fi - - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - - # Input might be given as Windows format, start by converting to - # unix format. - path="$with_devkit" - new_path=`$CYGPATH -u "$path"` - - # Cygwin tries to hide some aspects of the Windows file system, such that binaries are - # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered - # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then - # "foo.exe" is OK but "foo" is an error. - # - # This test is therefore slightly more accurate than "test -f" to check for file precense. - # It is also a way to make sure we got the proper file name for the real test later on. - test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` - if test "x$test_shortpath" = x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 -$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} - as_fn_error $? "Cannot locate the the path of with_devkit" "$LINENO" 5 - fi - - # Call helper function which possibly converts this using DOS-style short mode. - # If so, the updated path is stored in $new_path. - - input_path="$new_path" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - shortmode_path=`$CYGPATH -s -m -a "$input_path"` - path_after_shortmode=`$CYGPATH -u "$shortmode_path"` - if test "x$path_after_shortmode" != "x$input_to_shortpath"; then - # Going to short mode and back again did indeed matter. Since short mode is - # case insensitive, let's make it lowercase to improve readability. - shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Now convert it back to Unix-stile (cygpath) - input_path=`$CYGPATH -u "$shortmode_path"` - new_path="$input_path" - fi - fi - - test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` - if test "x$test_cygdrive_prefix" = x; then - # As a simple fix, exclude /usr/bin since it's not a real path. - if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then - # The path is in a Cygwin special directory (e.g. /home). We need this converted to - # a path prefixed by /cygdrive for fixpath to work. - new_path="$CYGWIN_ROOT_PATH$input_path" - fi - fi - - - if test "x$path" != "x$new_path"; then - with_devkit="$new_path" - { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 -$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} - fi - - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - - path="$with_devkit" - has_colon=`$ECHO $path | $GREP ^.:` - new_path="$path" - if test "x$has_colon" = x; then - # Not in mixed or Windows style, start by that. - new_path=`cmd //c echo $path` - fi - - - input_path="$new_path" - # Check if we need to convert this using DOS-style short mode. If the path - # contains just simple characters, use it. Otherwise (spaces, weird characters), - # take no chances and rewrite it. - # Note: m4 eats our [], so we need to use [ and ] instead. - has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` - if test "x$has_forbidden_chars" != x; then - # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) - new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - fi - - - windows_path="$new_path" - if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then - unix_path=`$CYGPATH -u "$windows_path"` - new_path="$unix_path" - elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then - unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` - new_path="$unix_path" - fi - - if test "x$path" != "x$new_path"; then - with_devkit="$new_path" - { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 -$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} - fi - - # Save the first 10 bytes of this path to the storage, so fixpath can work. - all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") - - else - # We're on a posix platform. Hooray! :) - path="$with_devkit" - has_space=`$ECHO "$path" | $GREP " "` - if test "x$has_space" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 -$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} - as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 - fi - - # Use eval to expand a potential ~ - eval path="$path" - if test ! -f "$path" && test ! -d "$path"; then - as_fn_error $? "The path of with_devkit, which resolves as \"$path\", is not found." "$LINENO" 5 - fi - - with_devkit="`cd "$path"; $THEPWDCMD -L`" - fi - - - if test "x$TOOLS_DIR" = x; then - TOOLS_DIR="$with_devkit/bin" - else - TOOLS_DIR="$TOOLS_DIR:$with_devkit/bin" - fi - - if test -d "$with_devkit/$host_alias/libc"; then - SYS_ROOT=$with_devkit/$host_alias/libc - elif test -d "$with_devkit/$host/sys-root"; then - SYS_ROOT=$with_devkit/$host/sys-root - fi - -fi - - # Setup default logging of stdout and stderr to build.log in the output root. BUILD_LOG='$(OUTPUT_ROOT)/build.log' @@ -14800,6 +14636,291 @@ $as_echo "$DEBUG_LEVEL" >&6; } # With basic setup done, call the custom early hook. +# Check if we have devkits, extra paths or sysroot set. + + +# Check whether --with-devkit was given. +if test "${with_devkit+set}" = set; then : + withval=$with_devkit; + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$with_devkit" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of with_devkit" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + with_devkit="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$with_devkit" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + with_devkit="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting with_devkit to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting with_devkit to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$with_devkit" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of with_devkit, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of with_devkit, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of with_devkit, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + with_devkit="`cd "$path"; $THEPWDCMD -L`" + fi + + DEVKIT_ROOT="$with_devkit" + # Check for a meta data info file in the root of the devkit + if test -f "$DEVKIT_ROOT/devkit.info"; then + # This potentially sets the following: + # DEVKIT_NAME: A descriptive name of the devkit + # DEVKIT_TOOLCHAIN_PATH: Corresponds to --with-toolchain-path + # DEVKIT_EXTRA_PATH: Corresponds to --with-extra-path + # DEVKIT_SYSROOT: Corresponds to --with-sysroot + . $DEVKIT_ROOT/devkit.info + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for devkit" >&5 +$as_echo_n "checking for devkit... " >&6; } + if test "x$DEVKIT_NAME" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVKIT_NAME in $DEVKIT_ROOT" >&5 +$as_echo "$DEVKIT_NAME in $DEVKIT_ROOT" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEVKIT_ROOT" >&5 +$as_echo "$DEVKIT_ROOT" >&6; } + fi + + if test "x$DEVKIT_EXTRA_PATH" != x; then + + if test "x$DEVKIT_EXTRA_PATH" != x; then + if test "x$EXTRA_PATH" = x; then + EXTRA_PATH="$DEVKIT_EXTRA_PATH" + else + EXTRA_PATH="$DEVKIT_EXTRA_PATH:$EXTRA_PATH" + fi + fi + + fi + + # Fallback default of just /bin if DEVKIT_PATH is not defined + if test "x$DEVKIT_TOOLCHAIN_PATH" = x; then + DEVKIT_TOOLCHAIN_PATH="$DEVKIT_ROOT/bin" + fi + + if test "x$DEVKIT_TOOLCHAIN_PATH" != x; then + if test "x$TOOLCHAIN_PATH" = x; then + TOOLCHAIN_PATH="$DEVKIT_TOOLCHAIN_PATH" + else + TOOLCHAIN_PATH="$DEVKIT_TOOLCHAIN_PATH:$TOOLCHAIN_PATH" + fi + fi + + + # If DEVKIT_SYSROOT is set, use that, otherwise try a couple of known + # places for backwards compatiblity. + if test "x$DEVKIT_SYSROOT" != x; then + SYSROOT="$DEVKIT_SYSROOT" + elif test -d "$DEVKIT_ROOT/$host_alias/libc"; then + SYSROOT="$DEVKIT_ROOT/$host_alias/libc" + elif test -d "$DEVKIT_ROOT/$host/sys-root"; then + SYSROOT="$DEVKIT_ROOT/$host/sys-root" + fi + + +fi + + + # You can force the sysroot if the sysroot encoded into the compiler tools + # is not correct. + +# Check whether --with-sys-root was given. +if test "${with_sys_root+set}" = set; then : + withval=$with_sys_root; SYSROOT=$with_sys_root + +fi + + + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; SYSROOT=$with_sysroot + +fi + + + +# Check whether --with-tools-dir was given. +if test "${with_tools_dir+set}" = set; then : + withval=$with_tools_dir; + if test "x$with_tools_dir" != x; then + if test "x$TOOLCHAIN_PATH" = x; then + TOOLCHAIN_PATH="$with_tools_dir" + else + TOOLCHAIN_PATH="$with_tools_dir:$TOOLCHAIN_PATH" + fi + fi + + +fi + + + +# Check whether --with-toolchain-path was given. +if test "${with_toolchain_path+set}" = set; then : + withval=$with_toolchain_path; + if test "x$with_toolchain_path" != x; then + if test "x$TOOLCHAIN_PATH" = x; then + TOOLCHAIN_PATH="$with_toolchain_path" + else + TOOLCHAIN_PATH="$with_toolchain_path:$TOOLCHAIN_PATH" + fi + fi + + +fi + + + +# Check whether --with-extra-path was given. +if test "${with_extra_path+set}" = set; then : + withval=$with_extra_path; + if test "x$with_extra_path" != x; then + if test "x$EXTRA_PATH" = x; then + EXTRA_PATH="$with_extra_path" + else + EXTRA_PATH="$with_extra_path:$EXTRA_PATH" + fi + fi + + +fi + + + # Prepend the extra path to the global path + + if test "x$EXTRA_PATH" != x; then + if test "x$PATH" = x; then + PATH="$EXTRA_PATH" + else + PATH="$EXTRA_PATH:$PATH" + fi + fi + + + if test "x$OPENJDK_BUILD_OS" = "xsolaris"; then + # Add extra search paths on solaris for utilities like ar and as etc... + PATH="$PATH:/usr/ccs/bin:/usr/sfw/bin:/opt/csw/bin" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SYSROOT" >&5 +$as_echo "$SYSROOT" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for toolchain path" >&5 +$as_echo_n "checking for toolchain path... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLCHAIN_PATH" >&5 +$as_echo "$TOOLCHAIN_PATH" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra path" >&5 +$as_echo_n "checking for extra path... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXTRA_PATH" >&5 +$as_echo "$EXTRA_PATH" >&6; } + + # To properly create a configuration name, we need to have the OpenJDK target # and options (variants and debug level) parsed. @@ -16107,10 +16228,10 @@ $as_echo "$as_me: Rewriting FOUND_MAKE to \"$new_complete\"" >&6;} fi if test "x$FOUND_MAKE" = x; then - if test "x$TOOLS_DIR" != x; then - # We have a tools-dir, check that as well before giving up. + if test "x$TOOLCHAIN_PATH" != x; then + # We have a toolchain path, check that as well before giving up. OLD_PATH=$PATH - PATH=$TOOLS_DIR:$PATH + PATH=$TOOLCHAIN_PATH:$PATH for ac_prog in gmake do # Extract the first word of "$ac_prog", so it can be a program name with args. @@ -27348,170 +27469,12 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c PATH="/usr/ccs/bin:$PATH" fi - # Finally add TOOLS_DIR at the beginning, to allow --with-tools-dir to + # Finally add TOOLCHAIN_PATH at the beginning, to allow --with-tools-dir to # override all other locations. - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi - # If a devkit is found on the builddeps server, then prepend its path to the - # PATH variable. If there are cross compilers available in the devkit, these - # will be found by AC_PROG_CC et al. - DEVKIT= - - - if test "x$with_builddeps_server" != x || test "x$with_builddeps_conf" != x; then - # Source the builddeps file again, to make sure it uses the latest variables! - . $builddepsfile - # Look for a target and build machine specific resource! - eval resource=\${builddep_devkit_BUILD_${rewritten_build_var}_TARGET_${rewritten_target_var}} - if test "x$resource" = x; then - # Ok, lets instead look for a target specific resource - eval resource=\${builddep_devkit_TARGET_${rewritten_target_var}} - fi - if test "x$resource" = x; then - # Ok, lets instead look for a build specific resource - eval resource=\${builddep_devkit_BUILD_${rewritten_build_var}} - fi - if test "x$resource" = x; then - # Ok, lets instead look for a generic resource - # (The devkit comes from M4 and not the shell, thus no need for eval here.) - resource=${builddep_devkit} - fi - if test "x$resource" != x; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Using builddeps $resource for devkit" >&5 -$as_echo "$as_me: Using builddeps $resource for devkit" >&6;} - # If the resource in the builddeps.conf file is an existing directory, - # for example /java/linux/cups - if test -d ${resource}; then - depdir=${resource} - else - - # devkit is for example mymodule - # $resource is for example libs/general/libmymod_1_2_3.zip - # $with_builddeps_server is for example ftp://mybuilddeps.myserver.com/builddeps - # $with_builddeps_dir is for example /localhome/builddeps - # depdir is the name of the variable into which we store the depdir, eg MYMOD - # Will download ftp://mybuilddeps.myserver.com/builddeps/libs/general/libmymod_1_2_3.zip and - # unzip into the directory: /localhome/builddeps/libmymod_1_2_3 - filename=`basename $resource` - filebase=`echo $filename | sed 's/\.[^\.]*$//'` - filebase=${filename%%.*} - extension=${filename#*.} - installdir=$with_builddeps_dir/$filebase - if test ! -f $installdir/$filename.unpacked; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Downloading build dependency devkit from $with_builddeps_server/$resource and installing into $installdir" >&5 -$as_echo "$as_me: Downloading build dependency devkit from $with_builddeps_server/$resource and installing into $installdir" >&6;} - if test ! -d $installdir; then - mkdir -p $installdir - fi - if test ! -d $installdir; then - as_fn_error $? "Could not create directory $installdir" "$LINENO" 5 - fi - tmpfile=`mktemp $installdir/devkit.XXXXXXXXX` - touch $tmpfile - if test ! -f $tmpfile; then - as_fn_error $? "Could not create files in directory $installdir" "$LINENO" 5 - fi - - # $with_builddeps_server/$resource is the ftp://abuilddeps.server.com/libs/cups.zip - # $tmpfile is the local file name for the downloaded file. - VALID_TOOL=no - if test "x$BDEPS_FTP" = xwget; then - VALID_TOOL=yes - wget -O $tmpfile $with_builddeps_server/$resource - fi - if test "x$BDEPS_FTP" = xlftp; then - VALID_TOOL=yes - lftp -c "get $with_builddeps_server/$resource -o $tmpfile" - fi - if test "x$BDEPS_FTP" = xftp; then - VALID_TOOL=yes - FTPSERVER=`echo $with_builddeps_server/$resource | cut -f 3 -d '/'` - FTPPATH=`echo $with_builddeps_server/$resource | cut -f 4- -d '/'` - FTPUSERPWD=${FTPSERVER%%@*} - if test "x$FTPSERVER" != "x$FTPUSERPWD"; then - FTPUSER=${userpwd%%:*} - FTPPWD=${userpwd#*@} - FTPSERVER=${FTPSERVER#*@} - else - FTPUSER=ftp - FTPPWD=ftp - fi - # the "pass" command does not work on some - # ftp clients (read ftp.exe) but if it works, - # passive mode is better! - ( \ - echo "user $FTPUSER $FTPPWD" ; \ - echo "pass" ; \ - echo "bin" ; \ - echo "get $FTPPATH $tmpfile" ; \ - ) | ftp -in $FTPSERVER - fi - if test "x$VALID_TOOL" != xyes; then - as_fn_error $? "I do not know how to use the tool: $BDEPS_FTP" "$LINENO" 5 - fi - - mv $tmpfile $installdir/$filename - if test ! -s $installdir/$filename; then - as_fn_error $? "Could not download $with_builddeps_server/$resource" "$LINENO" 5 - fi - case "$extension" in - zip) echo "Unzipping $installdir/$filename..." - (cd $installdir ; rm -f $installdir/$filename.unpacked ; $BDEPS_UNZIP $installdir/$filename > /dev/null && touch $installdir/$filename.unpacked) - ;; - tar.gz) echo "Untaring $installdir/$filename..." - (cd $installdir ; rm -f $installdir/$filename.unpacked ; tar xzf $installdir/$filename && touch $installdir/$filename.unpacked) - ;; - tgz) echo "Untaring $installdir/$filename..." - (cd $installdir ; rm -f $installdir/$filename.unpacked ; tar xzf $installdir/$filename && touch $installdir/$filename.unpacked) - ;; - *) as_fn_error $? "Cannot handle build depency archive with extension $extension" "$LINENO" 5 - ;; - esac - fi - if test -f $installdir/$filename.unpacked; then - depdir=$installdir - fi - - fi - # Source the builddeps file again, because in the previous command, the depdir - # was updated to point at the current build dependency install directory. - . $builddepsfile - # Now extract variables from the builddeps.conf files. - theroot=${builddep_devkit_ROOT} - thecflags=${builddep_devkit_CFLAGS} - thelibs=${builddep_devkit_LIBS} - if test "x$depdir" = x; then - as_fn_error $? "Could not download build dependency devkit" "$LINENO" 5 - fi - DEVKIT=$depdir - if test "x$theroot" != x; then - DEVKIT="$theroot" - fi - if test "x$thecflags" != x; then - DEVKIT_CFLAGS="$thecflags" - fi - if test "x$thelibs" != x; then - DEVKIT_LIBS="$thelibs" - fi - - # Found devkit - PATH="$DEVKIT/bin:$PATH" - SYS_ROOT="$DEVKIT/${rewritten_target}/sys-root" - if test "x$x_includes" = "xNONE"; then - x_includes="$SYS_ROOT/usr/include/X11" - fi - if test "x$x_libraries" = "xNONE"; then - x_libraries="$SYS_ROOT/usr/lib" - fi - - - fi - - fi - - # # Setup the compilers (CC and CXX) @@ -27594,25 +27557,25 @@ done # used. CC= - # If TOOLS_DIR is set, check for all compiler names in there first + # If TOOLCHAIN_PATH is set, check for all compiler names in there first # before checking the rest of the PATH. # FIXME: Now that we prefix the TOOLS_DIR to the PATH in the PRE_DETECTION # step, this should not be necessary. - if test -n "$TOOLS_DIR"; then + if test -n "$TOOLCHAIN_PATH"; then PATH_save="$PATH" - PATH="$TOOLS_DIR" + PATH="$TOOLCHAIN_PATH" for ac_prog in $SEARCH_LIST do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_TOOLS_DIR_CC+:} false; then : +if ${ac_cv_path_TOOLCHAIN_PATH_CC+:} false; then : $as_echo_n "(cached) " >&6 else - case $TOOLS_DIR_CC in + case $TOOLCHAIN_PATH_CC in [\\/]* | ?:[\\/]*) - ac_cv_path_TOOLS_DIR_CC="$TOOLS_DIR_CC" # Let the user override the test with a path. + ac_cv_path_TOOLCHAIN_PATH_CC="$TOOLCHAIN_PATH_CC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -27622,7 +27585,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_TOOLS_DIR_CC="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_TOOLCHAIN_PATH_CC="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -27633,20 +27596,20 @@ IFS=$as_save_IFS ;; esac fi -TOOLS_DIR_CC=$ac_cv_path_TOOLS_DIR_CC -if test -n "$TOOLS_DIR_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLS_DIR_CC" >&5 -$as_echo "$TOOLS_DIR_CC" >&6; } +TOOLCHAIN_PATH_CC=$ac_cv_path_TOOLCHAIN_PATH_CC +if test -n "$TOOLCHAIN_PATH_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLCHAIN_PATH_CC" >&5 +$as_echo "$TOOLCHAIN_PATH_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - test -n "$TOOLS_DIR_CC" && break + test -n "$TOOLCHAIN_PATH_CC" && break done - CC=$TOOLS_DIR_CC + CC=$TOOLCHAIN_PATH_CC PATH="$PATH_save" fi @@ -29300,25 +29263,25 @@ done # used. CXX= - # If TOOLS_DIR is set, check for all compiler names in there first + # If TOOLCHAIN_PATH is set, check for all compiler names in there first # before checking the rest of the PATH. # FIXME: Now that we prefix the TOOLS_DIR to the PATH in the PRE_DETECTION # step, this should not be necessary. - if test -n "$TOOLS_DIR"; then + if test -n "$TOOLCHAIN_PATH"; then PATH_save="$PATH" - PATH="$TOOLS_DIR" + PATH="$TOOLCHAIN_PATH" for ac_prog in $SEARCH_LIST do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_TOOLS_DIR_CXX+:} false; then : +if ${ac_cv_path_TOOLCHAIN_PATH_CXX+:} false; then : $as_echo_n "(cached) " >&6 else - case $TOOLS_DIR_CXX in + case $TOOLCHAIN_PATH_CXX in [\\/]* | ?:[\\/]*) - ac_cv_path_TOOLS_DIR_CXX="$TOOLS_DIR_CXX" # Let the user override the test with a path. + ac_cv_path_TOOLCHAIN_PATH_CXX="$TOOLCHAIN_PATH_CXX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -29328,7 +29291,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_TOOLS_DIR_CXX="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_TOOLCHAIN_PATH_CXX="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -29339,20 +29302,20 @@ IFS=$as_save_IFS ;; esac fi -TOOLS_DIR_CXX=$ac_cv_path_TOOLS_DIR_CXX -if test -n "$TOOLS_DIR_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLS_DIR_CXX" >&5 -$as_echo "$TOOLS_DIR_CXX" >&6; } +TOOLCHAIN_PATH_CXX=$ac_cv_path_TOOLCHAIN_PATH_CXX +if test -n "$TOOLCHAIN_PATH_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLCHAIN_PATH_CXX" >&5 +$as_echo "$TOOLCHAIN_PATH_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - test -n "$TOOLS_DIR_CXX" && break + test -n "$TOOLCHAIN_PATH_CXX" && break done - CXX=$TOOLS_DIR_CXX + CXX=$TOOLCHAIN_PATH_CXX PATH="$PATH_save" fi @@ -40760,6 +40723,32 @@ $as_echo "$tool_specified" >&6; } CCXXFLAGS="$CCXXFLAGS -nologo" fi + if test "x$SYSROOT" != "x"; then + if test "x$TOOLCHAIN_TYPE" = xsolstudio; then + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + # Solaris Studio does not have a concept of sysroot. Instead we must + # make sure the default include and lib dirs are appended to each + # compile and link command line. + SYSROOT_CFLAGS="-I$SYSROOT/usr/include" + SYSROOT_LDFLAGS="-L$SYSROOT/usr/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT/usr/ccs/lib$OPENJDK_TARGET_CPU_ISADIR" + fi + elif test "x$TOOLCHAIN_TYPE" = xgcc; then + SYSROOT_CFLAGS="--sysroot=\"$SYSROOT\"" + SYSROOT_LDFLAGS="--sysroot=\"$SYSROOT\"" + elif test "x$TOOLCHAIN_TYPE" = xclang; then + SYSROOT_CFLAGS="-isysroot \"$SYSROOT\"" + SYSROOT_LDFLAGS="-isysroot \"$SYSROOT\"" + fi + # Propagate the sysroot args to hotspot + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $SYSROOT_CFLAGS" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $SYSROOT_LDFLAGS" + fi + + + # FIXME: Currently we must test this after toolchain but before flags. Fix! @@ -41608,9 +41597,9 @@ fi LDFLAGS_JDK="${LDFLAGS_JDK} $with_extra_ldflags" # Hotspot needs these set in their legacy form - LEGACY_EXTRA_CFLAGS=$with_extra_cflags - LEGACY_EXTRA_CXXFLAGS=$with_extra_cxxflags - LEGACY_EXTRA_LDFLAGS=$with_extra_ldflags + LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS $with_extra_cflags" + LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS $with_extra_cxxflags" + LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS $with_extra_ldflags" @@ -41708,7 +41697,13 @@ fi CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_LITTLE_ENDIAN" fi else - CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + # Same goes for _BIG_ENDIAN. Do we really need to set *ENDIAN on Solaris if they + # are defined in the system? + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN=" + else + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -D_BIG_ENDIAN" + fi fi # Setup target OS define. Use OS target name but in upper case. @@ -42271,21 +42266,23 @@ $as_echo "no" >&6; } # Check if the user has specified sysroot, but not --x-includes or --x-libraries. # Make a simple check for the libraries at the sysroot, and setup --x-includes and # --x-libraries for the sysroot, if that seems to be correct. - if test "x$SYS_ROOT" != "x/"; then - if test "x$x_includes" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/X11R6/include" - elif test -f "$SYS_ROOT/usr/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/include" + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + if test "x$SYSROOT" != "x"; then + if test "x$x_includes" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/X11R6/include" + elif test -f "$SYSROOT/usr/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/include" + fi fi - fi - if test "x$x_libraries" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/X11R6/lib" - elif test "$SYS_ROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - x_libraries="$SYS_ROOT/usr/lib64" - elif test -f "$SYS_ROOT/usr/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/lib" + if test "x$x_libraries" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/X11R6/lib" + elif test "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + x_libraries="$SYSROOT/usr/lib64" + elif test -f "$SYSROOT/usr/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/lib" + fi fi fi fi @@ -43017,10 +43014,13 @@ fi if test "x$OPENJDK_TARGET_OS" = xsolaris; then OPENWIN_HOME="/usr/openwin" + X_CFLAGS="-I$SYSROOT$OPENWIN_HOME/include -I$SYSROOT$OPENWIN_HOME/include/X11/extensions" + X_LIBS="-L$SYSROOT$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR" fi - - # # Weird Sol10 something check...TODO change to try compile # @@ -43319,14 +43319,14 @@ done # package installation locations. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cups headers" >&5 $as_echo_n "checking for cups headers... " >&6; } - if test -s /opt/sfw/cups/include/cups/cups.h; then + if test -s $SYSROOT/opt/sfw/cups/include/cups/cups.h; then # An SFW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/sfw/cups/include" - elif test -s /opt/csw/include/cups/cups.h; then + CUPS_CFLAGS="-I$SYSROOT/opt/sfw/cups/include" + elif test -s $SYSROOT/opt/csw/include/cups/cups.h; then # A CSW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/csw/include" + CUPS_CFLAGS="-I$SYSROOT/opt/csw/include" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CUPS_FOUND" >&5 $as_echo "$CUPS_FOUND" >&6; } @@ -43919,9 +43919,11 @@ $as_echo "yes (using builddeps)" >&6; } fi fi - if test "x$FOUND_FREETYPE" != xyes; then - # Check modules using pkg-config, but only if we have it (ugly output results otherwise) - if test "x$PKG_CONFIG" != x; then + # If we have a sysroot, assume that's where we are supposed to look and skip pkg-config. + if test "x$SYSROOT" = x; then + if test "x$FOUND_FREETYPE" != xyes; then + # Check modules using pkg-config, but only if we have it (ugly output results otherwise) + if test "x$PKG_CONFIG" != x; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FREETYPE" >&5 @@ -43989,23 +43991,24 @@ else $as_echo "yes" >&6; } FOUND_FREETYPE=yes fi - if test "x$FOUND_FREETYPE" = xyes; then - # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` - # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 - if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` - fi - # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. - if test "x$BUNDLE_FREETYPE" = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype using pkg-config, but ignoring since we can not bundle that" >&5 + if test "x$FOUND_FREETYPE" = xyes; then + # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` + # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 + if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` + fi + # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. + if test "x$BUNDLE_FREETYPE" = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype using pkg-config, but ignoring since we can not bundle that" >&5 $as_echo "$as_me: Found freetype using pkg-config, but ignoring since we can not bundle that" >&6;} - FOUND_FREETYPE=no - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype" >&5 + FOUND_FREETYPE=no + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype" >&5 $as_echo_n "checking for freetype... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (using pkg-config)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (using pkg-config)" >&5 $as_echo "yes (using pkg-config)" >&6; } + fi fi fi fi @@ -44619,12 +44622,7 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; } fi else - if test "x$SYS_ROOT" = "x/"; then - FREETYPE_ROOT= - else - FREETYPE_ROOT="$SYS_ROOT" - fi - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr" POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" @@ -44917,7 +44915,7 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; } if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr/X11" + FREETYPE_BASE_DIR="$SYSROOT/usr/X11" POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" @@ -45211,7 +45209,301 @@ $as_echo "$FREETYPE_LIB_PATH" >&6; } fi if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr/sfw" + + POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" + POTENTIAL_FREETYPE_LIB_PATH="$FREETYPE_BASE_DIR/lib" + METHOD="well-known location" + + # First check if the files exists. + if test -s "$POTENTIAL_FREETYPE_INCLUDE_PATH/ft2build.h"; then + # We found an arbitrary include file. That's a good sign. + { $as_echo "$as_me:${as_lineno-$LINENO}: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&5 +$as_echo "$as_me: Found freetype include files at $POTENTIAL_FREETYPE_INCLUDE_PATH using $METHOD" >&6;} + FOUND_FREETYPE=yes + + FREETYPE_LIB_NAME="${LIBRARY_PREFIX}freetype${SHARED_LIBRARY_SUFFIX}" + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location." >&6;} + FOUND_FREETYPE=no + else + if test "x$OPENJDK_TARGET_OS" = xwindows; then + # On Windows, we will need both .lib and .dll file. + if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/freetype.lib"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Could not find $POTENTIAL_FREETYPE_LIB_PATH/freetype.lib. Ignoring location." >&5 +$as_echo "$as_me: Could not find $POTENTIAL_FREETYPE_LIB_PATH/freetype.lib. Ignoring location." >&6;} + FOUND_FREETYPE=no + fi + elif test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64 && test -s "$POTENTIAL_FREETYPE_LIB_PATH/amd64/$FREETYPE_LIB_NAME"; then + # On solaris-x86_86, default is (normally) PATH/lib/amd64. Update our guess! + POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH/amd64" + fi + fi + fi + + if test "x$FOUND_FREETYPE" = xyes; then + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_INCLUDE_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_INCLUDE_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_INCLUDE_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_INCLUDE_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + POTENTIAL_FREETYPE_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`" + fi + + + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$POTENTIAL_FREETYPE_LIB_PATH" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of POTENTIAL_FREETYPE_LIB_PATH" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-stile (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + POTENTIAL_FREETYPE_LIB_PATH="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting POTENTIAL_FREETYPE_LIB_PATH to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a posix platform. Hooray! :) + path="$POTENTIAL_FREETYPE_LIB_PATH" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of POTENTIAL_FREETYPE_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + POTENTIAL_FREETYPE_LIB_PATH="`cd "$path"; $THEPWDCMD -L`" + fi + + + FREETYPE_INCLUDE_PATH="$POTENTIAL_FREETYPE_INCLUDE_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype includes" >&5 +$as_echo_n "checking for freetype includes... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_INCLUDE_PATH" >&5 +$as_echo "$FREETYPE_INCLUDE_PATH" >&6; } + FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype libraries" >&5 +$as_echo_n "checking for freetype libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LIB_PATH" >&5 +$as_echo "$FREETYPE_LIB_PATH" >&6; } + fi + + fi + + if test "x$FOUND_FREETYPE" != xyes; then + FREETYPE_BASE_DIR="$SYSROOT/usr" if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then POTENTIAL_FREETYPE_INCLUDE_PATH="$FREETYPE_BASE_DIR/include" @@ -46687,7 +46979,9 @@ $as_echo "$as_me: Downloading build dependency alsa from $with_builddeps_server/ fi fi - if test "x$ALSA_FOUND" = xno; then + # Do not try pkg-config if we have a sysroot set. + if test "x$SYSROOT" = x; then + if test "x$ALSA_FOUND" = xno; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA" >&5 @@ -46755,6 +47049,7 @@ else $as_echo "yes" >&6; } ALSA_FOUND=yes fi + fi fi if test "x$ALSA_FOUND" = xno; then for ac_header in alsa/asoundlib.h @@ -47634,7 +47929,7 @@ fi # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so) if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then - LIBCXX="/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" + LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" fi # TODO better (platform agnostic) test @@ -48559,8 +48854,8 @@ $as_echo_n "checking is ccache enabled... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } OLD_PATH="$PATH" - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4 index 6dca4aad3c6..1546529ce80 100644 --- a/common/autoconf/libraries.m4 +++ b/common/autoconf/libraries.m4 @@ -110,21 +110,23 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], # Check if the user has specified sysroot, but not --x-includes or --x-libraries. # Make a simple check for the libraries at the sysroot, and setup --x-includes and # --x-libraries for the sysroot, if that seems to be correct. - if test "x$SYS_ROOT" != "x/"; then - if test "x$x_includes" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/X11R6/include" - elif test -f "$SYS_ROOT/usr/include/X11/Xlib.h"; then - x_includes="$SYS_ROOT/usr/include" + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + if test "x$SYSROOT" != "x"; then + if test "x$x_includes" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/X11R6/include" + elif test -f "$SYSROOT/usr/include/X11/Xlib.h"; then + x_includes="$SYSROOT/usr/include" + fi fi - fi - if test "x$x_libraries" = xNONE; then - if test -f "$SYS_ROOT/usr/X11R6/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/X11R6/lib" - elif test "$SYS_ROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - x_libraries="$SYS_ROOT/usr/lib64" - elif test -f "$SYS_ROOT/usr/lib/libX11.so"; then - x_libraries="$SYS_ROOT/usr/lib" + if test "x$x_libraries" = xNONE; then + if test -f "$SYSROOT/usr/X11R6/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/X11R6/lib" + elif test "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + x_libraries="$SYSROOT/usr/lib64" + elif test -f "$SYSROOT/usr/lib/libX11.so"; then + x_libraries="$SYSROOT/usr/lib" + fi fi fi fi @@ -146,9 +148,12 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], if test "x$OPENJDK_TARGET_OS" = xsolaris; then OPENWIN_HOME="/usr/openwin" + X_CFLAGS="-I$SYSROOT$OPENWIN_HOME/include -I$SYSROOT$OPENWIN_HOME/include/X11/extensions" + X_LIBS="-L$SYSROOT$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -L$SYSROOT$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ + -R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR" fi - AC_SUBST(OPENWIN_HOME) - # # Weird Sol10 something check...TODO change to try compile @@ -237,14 +242,14 @@ AC_DEFUN_ONCE([LIB_SETUP_CUPS], # Getting nervous now? Lets poke around for standard Solaris third-party # package installation locations. AC_MSG_CHECKING([for cups headers]) - if test -s /opt/sfw/cups/include/cups/cups.h; then + if test -s $SYSROOT/opt/sfw/cups/include/cups/cups.h; then # An SFW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/sfw/cups/include" - elif test -s /opt/csw/include/cups/cups.h; then + CUPS_CFLAGS="-I$SYSROOT/opt/sfw/cups/include" + elif test -s $SYSROOT/opt/csw/include/cups/cups.h; then # A CSW package seems to be installed! CUPS_FOUND=yes - CUPS_CFLAGS="-I/opt/csw/include" + CUPS_CFLAGS="-I$SYSROOT/opt/csw/include" fi AC_MSG_RESULT([$CUPS_FOUND]) fi @@ -398,24 +403,27 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], fi fi - if test "x$FOUND_FREETYPE" != xyes; then - # Check modules using pkg-config, but only if we have it (ugly output results otherwise) - if test "x$PKG_CONFIG" != x; then - PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no]) - if test "x$FOUND_FREETYPE" = xyes; then - # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` - # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 - if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then - FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` - fi - # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. - if test "x$BUNDLE_FREETYPE" = xyes; then - AC_MSG_NOTICE([Found freetype using pkg-config, but ignoring since we can not bundle that]) - FOUND_FREETYPE=no - else - AC_MSG_CHECKING([for freetype]) - AC_MSG_RESULT([yes (using pkg-config)]) + # If we have a sysroot, assume that's where we are supposed to look and skip pkg-config. + if test "x$SYSROOT" = x; then + if test "x$FOUND_FREETYPE" != xyes; then + # Check modules using pkg-config, but only if we have it (ugly output results otherwise) + if test "x$PKG_CONFIG" != x; then + PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no]) + if test "x$FOUND_FREETYPE" = xyes; then + # On solaris, pkg_check adds -lz to freetype libs, which isn't necessary for us. + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` + # 64-bit libs for Solaris x86 are installed in the amd64 subdirectory, change lib to lib/amd64 + if test "x$OPENJDK_TARGET_OS" = xsolaris && test "x$OPENJDK_TARGET_CPU" = xx86_64; then + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` + fi + # BDEPS_CHECK_MODULE will set FREETYPE_CFLAGS and _LIBS, but we don't get a lib path for bundling. + if test "x$BUNDLE_FREETYPE" = xyes; then + AC_MSG_NOTICE([Found freetype using pkg-config, but ignoring since we can not bundle that]) + FOUND_FREETYPE=no + else + AC_MSG_CHECKING([for freetype]) + AC_MSG_RESULT([yes (using pkg-config)]) + fi fi fi fi @@ -433,21 +441,21 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE], LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) fi else - if test "x$SYS_ROOT" = "x/"; then - FREETYPE_ROOT= - else - FREETYPE_ROOT="$SYS_ROOT" - fi - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr" LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr/X11" + FREETYPE_BASE_DIR="$SYSROOT/usr/X11" LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) fi if test "x$FOUND_FREETYPE" != xyes; then - FREETYPE_BASE_DIR="$FREETYPE_ROOT/usr" + FREETYPE_BASE_DIR="$SYSROOT/usr/sfw" + LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib], [well-known location]) + fi + + if test "x$FOUND_FREETYPE" != xyes; then + FREETYPE_BASE_DIR="$SYSROOT/usr" if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then LIB_CHECK_POTENTIAL_FREETYPE([$FREETYPE_BASE_DIR/include], [$FREETYPE_BASE_DIR/lib/x86_64-linux-gnu], [well-known location]) else @@ -577,8 +585,11 @@ AC_DEFUN_ONCE([LIB_SETUP_ALSA], if test "x$ALSA_FOUND" = xno; then BDEPS_CHECK_MODULE(ALSA, alsa, xxx, [ALSA_FOUND=yes], [ALSA_FOUND=no]) fi - if test "x$ALSA_FOUND" = xno; then - PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) + # Do not try pkg-config if we have a sysroot set. + if test "x$SYSROOT" = x; then + if test "x$ALSA_FOUND" = xno; then + PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) + fi fi if test "x$ALSA_FOUND" = xno; then AC_CHECK_HEADERS([alsa/asoundlib.h], @@ -917,7 +928,7 @@ AC_DEFUN_ONCE([LIB_SETUP_STATIC_LINK_LIBSTDCPP], # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so) if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then - LIBCXX="/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" + LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1" fi # TODO better (platform agnostic) test diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 5cd0185fbaa..c793d0e5c63 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -130,10 +130,8 @@ ifeq ($(OPENJDK_TARGET_OS), windows) export LIB:=@VS_LIB@ endif -# The sys root where standard headers and libraries are found. -# Usually not needed since the configure script should have -# taken it into account already when setting CFLAGS et al. -SYS_ROOT:=@SYS_ROOT@ +SYSROOT_CFLAGS := @SYSROOT_CFLAGS@ +SYSROOT_LDFLAGS := @SYSROOT_LDFLAGS@ # Paths to the source code ADD_SRC_ROOT:=@ADD_SRC_ROOT@ @@ -294,7 +292,6 @@ RMICONNECTOR_IIOP=@RMICONNECTOR_IIOP@ # Necessary additional compiler flags to compile X11 X_CFLAGS:=@X_CFLAGS@ X_LIBS:=@X_LIBS@ -OPENWIN_HOME:=@OPENWIN_HOME@ # The lowest required version of macosx to enforce compatiblity for MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@ diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index ba57a850219..af1b7adfd80 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -202,29 +202,11 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], PATH="/usr/ccs/bin:$PATH" fi - # Finally add TOOLS_DIR at the beginning, to allow --with-tools-dir to + # Finally add TOOLCHAIN_PATH at the beginning, to allow --with-tools-dir to # override all other locations. - if test "x$TOOLS_DIR" != x; then - PATH=$TOOLS_DIR:$PATH + if test "x$TOOLCHAIN_PATH" != x; then + PATH=$TOOLCHAIN_PATH:$PATH fi - - # If a devkit is found on the builddeps server, then prepend its path to the - # PATH variable. If there are cross compilers available in the devkit, these - # will be found by AC_PROG_CC et al. - DEVKIT= - BDEPS_CHECK_MODULE(DEVKIT, devkit, xxx, - [ - # Found devkit - PATH="$DEVKIT/bin:$PATH" - SYS_ROOT="$DEVKIT/${rewritten_target}/sys-root" - if test "x$x_includes" = "xNONE"; then - x_includes="$SYS_ROOT/usr/include/X11" - fi - if test "x$x_libraries" = "xNONE"; then - x_libraries="$SYS_ROOT/usr/lib" - fi - ], - []) ]) # Restore path, etc @@ -396,15 +378,15 @@ AC_DEFUN([TOOLCHAIN_FIND_COMPILER], # used. $1= - # If TOOLS_DIR is set, check for all compiler names in there first + # If TOOLCHAIN_PATH is set, check for all compiler names in there first # before checking the rest of the PATH. # FIXME: Now that we prefix the TOOLS_DIR to the PATH in the PRE_DETECTION # step, this should not be necessary. - if test -n "$TOOLS_DIR"; then + if test -n "$TOOLCHAIN_PATH"; then PATH_save="$PATH" - PATH="$TOOLS_DIR" - AC_PATH_PROGS(TOOLS_DIR_$1, $SEARCH_LIST) - $1=$TOOLS_DIR_$1 + PATH="$TOOLCHAIN_PATH" + AC_PATH_PROGS(TOOLCHAIN_PATH_$1, $SEARCH_LIST) + $1=$TOOLCHAIN_PATH_$1 PATH="$PATH_save" fi diff --git a/common/bin/compare.sh b/common/bin/compare.sh index 08c0d6bb229..ff88bb1fbb9 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -114,7 +114,7 @@ diff_text() { fi if test "x$SUFFIX" = "xproperties"; then # Run through nawk to add possibly missing newline at end of file. - $CAT $OTHER_FILE | $NAWK '{ print }' > $OTHER_FILE.cleaned + $CAT $OTHER_FILE | $NAWK '{ print }' | LC_ALL=C $SORT > $OTHER_FILE.cleaned # Disable this exception since we aren't changing the properties cleaning method yet. # $CAT $OTHER_FILE | $SED -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' -e 's/#.*/#/g' \ # | $SED -f "$SRC_ROOT/common/makefiles/support/unicode2x.sed" \ diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 361ea8d4c13..6dabbb4f53e 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -369,6 +369,10 @@ define SetupNativeCompilation $$(error Unknown value for OPTIMIZATION: $$($1_OPTIMIZATION)) endif + # Add sys root specific cflags last + $1_EXTRA_CFLAGS += $(SYSROOT_CFLAGS) + $1_EXTRA_CXXFLAGS += $(SYSROOT_CFLAGS) + # Now call add_native_source for each source file we are going to compile. $$(foreach p,$$($1_SRCS), \ $$(eval $$(call add_native_source,$1,$$p,$$($1_OBJECT_DIR), \ @@ -414,6 +418,8 @@ define SetupNativeCompilation $1_EXTRA_LDFLAGS += $(call SET_SHARED_LIBRARY_MAPFILE,$$($1_REAL_MAPFILE)) endif + $1_EXTRA_LDFLAGS += $(SYSROOT_LDFLAGS) + # Need to make sure TARGET is first on list $1 := $$($1_TARGET) ifeq ($$($1_STATIC_LIBRARY),) diff --git a/make/devkit/Makefile b/make/devkit/Makefile index a6a5ca9e9ae..0776f54b488 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -75,7 +75,7 @@ ifeq (,$(SKIP_ME)) $(foreach p,$(filter-out $(me),$(platforms)),$(eval $(p) : $$(me))) endif -OUTPUT_ROOT = $(abspath ../../../build/devkit) +OUTPUT_ROOT = $(abspath ../../build/devkit) RESULT = $(OUTPUT_ROOT)/result submakevars = HOST=$@ BUILD=$(me) \ diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 457dacb8e9d..c2460105b7f 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -49,8 +49,8 @@ ARCH := $(word 1,$(subst -, ,$(TARGET))) # Define external dependencies # Latest that could be made to work. -gcc_ver := gcc-4.7.3 -binutils_ver := binutils-2.22 +gcc_ver := gcc-4.8.2 +binutils_ver := binutils-2.24 ccache_ver := ccache-3.1.9 mpfr_ver := mpfr-3.0.1 gmp_ver := gmp-4.3.2 @@ -64,6 +64,7 @@ GMP := http://ftp.gnu.org/pub/gnu/gmp/${gmp_ver}.tar.bz2 MPC := http://www.multiprecision.org/mpc/download/${mpc_ver}.tar.gz # RPMs in OEL5.5 +LINUX_VERSION := OEL5.5 RPM_LIST := \ kernel-headers \ glibc-2 glibc-headers glibc-devel \ @@ -121,7 +122,7 @@ RESULT := $(OUTPUT_ROOT)/result BUILDDIR := $(OUTPUT_ROOT)/$(HOST)/$(TARGET) PREFIX := $(RESULT)/$(HOST) TARGETDIR := $(PREFIX)/$(TARGET) -SYSROOT := $(TARGETDIR)/sys-root +SYSROOT := $(TARGETDIR)/sysroot DOWNLOAD := $(OUTPUT_ROOT)/download SRCDIR := $(OUTPUT_ROOT)/src @@ -184,7 +185,7 @@ $(foreach p,$(RPM_FILE_LIST),$(eval $(call unrpm,$(p)))) ########################################################################################## -# Note: MUST create a /usr/lib even if not really needed. +# Note: MUST create a /usr/lib even if not really needed. # gcc will use a path relative to it to resolve lib64. (x86_64). # we're creating multi-lib compiler with 32bit libc as well, so we should # have it anyway, but just to make sure... @@ -459,15 +460,31 @@ $(TARGETDIR)/%.done : $(BUILDDIR)/%/Makefile ########################################################################################## +$(PREFIX)/devkit.info: FRC + @echo 'Creating devkit.info in the root of the kit' + rm -f $@ + touch $@ + echo '# This file describes to configure how to interpret the contents of this' >> $@ + echo '# devkit' >> $@ + echo '' >> $@ + echo 'DEVKIT_NAME="$(gcc_ver) - $(LINUX_VERSION)"' >> $@ + echo 'DEVKIT_TOOLCHAIN_PATH="$$DEVKIT_ROOT/bin"' >> $@ + echo 'DEVKIT_SYSROOT="$$DEVKIT_ROOT/$$host/sysroot"' >> $@ + +########################################################################################## + bfdlib : $(bfdlib) binutils : $(binutils) rpms : $(rpms) libs : $(libs) sysroot : rpms libs gcc : sysroot $(gcc) $(gccpatch) -all : binutils gcc bfdlib +all : binutils gcc bfdlib $(PREFIX)/devkit.info # this is only built for host. so separate. ccache : $(ccache) +# Force target +FRC: + .PHONY : gcc all binutils bfdlib link_libs rpms libs sysroot From f5d6f0ceb8b0b36a4323cc393dfc480faf904220 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Sat, 29 Mar 2014 14:54:48 +0400 Subject: [PATCH 088/170] 8038393: [TESTBUG] ciReplay/* tests fail after 8034775 Reviewed-by: kvn --- hotspot/test/compiler/ciReplay/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh index 608f68e551a..f992ff39fc2 100644 --- a/hotspot/test/compiler/ciReplay/common.sh +++ b/hotspot/test/compiler/ciReplay/common.sh @@ -218,7 +218,7 @@ generate_replay() { -XX:VMThreadStackSize=512 \ -XX:CompilerThreadStackSize=512 \ -XX:ParallelGCThreads=1 \ - -XX:CICompilerCount=1 \ + -XX:CICompilerCount=2 \ -Xcomp \ -XX:CICrashAt=1 \ -XX:+CreateMinidumpOnCrash \ From e08ccd0e48cb50b311604bab962fd6f4d026830d Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Sat, 29 Mar 2014 11:06:33 -0700 Subject: [PATCH 089/170] 8029143: javadoc standard doclet should add Functional Interface blurb when @FunctionalInterface annotation is present Reviewed-by: ksrini --- .../classes/com/sun/javadoc/ClassDoc.java | 9 ------ .../doclets/formats/html/ClassWriterImpl.java | 18 ++++++++++-- .../com/sun/tools/javadoc/ClassDocImpl.java | 4 --- .../com/sun/tools/javadoc/RootDocImpl.java | 7 ++++- .../testLambdaFeature/TestLambdaFeature.java | 9 ++++-- .../sun/javadoc/testLambdaFeature/pkg/A.java | 3 +- .../testLambdaFeature/pkg1/FuncInf.java | 1 + .../testLambdaFeature/pkg1/NotAFuncInf.java | 29 +++++++++++++++++++ 8 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java diff --git a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java index 092f79bf528..b6e89031270 100644 --- a/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java +++ b/langtools/src/share/classes/com/sun/javadoc/ClassDoc.java @@ -74,15 +74,6 @@ public interface ClassDoc extends ProgramElementDoc, Type { */ boolean isExternalizable(); - /** - * Return true if this class can be used as a target type of a lambda expression - * or method reference. - * - * @return true if this class can be used as a target type of a lambda expression - * or method reference. - */ - boolean isFunctionalInterface(); - /** * Return the serialization methods for this class or * interface. diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java index a1ac09529d7..ebcb7b64cf3 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -29,6 +29,7 @@ import java.util.*; import com.sun.javadoc.*; import com.sun.tools.javac.jvm.Profile; +import com.sun.tools.javadoc.RootDocImpl; import com.sun.tools.doclets.formats.html.markup.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.builders.*; @@ -528,7 +529,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter * {@inheritDoc} */ public void addFunctionalInterfaceInfo (Content classInfoTree) { - if (classDoc.isFunctionalInterface()) { + if (isFunctionalInterface()) { Content dt = HtmlTree.DT(getResource("doclet.Functional_Interface")); Content dl = HtmlTree.DL(dt); Content dd = new HtmlTree(HtmlTag.DD); @@ -538,6 +539,19 @@ public class ClassWriterImpl extends SubWriterHolderWriter } } + public boolean isFunctionalInterface() { + if (configuration.root instanceof RootDocImpl) { + RootDocImpl root = (RootDocImpl) configuration.root; + AnnotationDesc[] annotationDescList = classDoc.annotations(); + for (AnnotationDesc annoDesc : annotationDescList) { + if (root.isFunctionalInterface(annoDesc)) { + return true; + } + } + } + return false; + } + /** * {@inheritDoc} */ diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java index 7428b97e0f6..f9fcaa74864 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java @@ -288,10 +288,6 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { return false; } - public boolean isFunctionalInterface() { - return env.types.isFunctionalInterface(tsym) && env.source.allowLambda(); - } - /** * Return the package that this class is contained in. */ diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java index 9046bc02a6b..25ab5561dee 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -381,6 +381,11 @@ public class RootDocImpl extends DocImpl implements RootDoc { env.initDoclint(opts, customTagNames); } + public boolean isFunctionalInterface(AnnotationDesc annotationDesc) { + return annotationDesc.annotationType().qualifiedName().equals( + env.syms.functionalInterfaceType.toString()) && env.source.allowLambda(); + } + public boolean showTagMessages() { return env.showTagMessages(); } diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java b/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java index 0fb47c1eddc..dc0a04db0b5 100644 --- a/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/TestLambdaFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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,7 +23,7 @@ /* * @test - * @bug 8004893 8022738 + * @bug 8004893 8022738 8029143 * @summary Make sure that the lambda feature changes work fine in * javadoc. * @author bpatel @@ -87,6 +87,11 @@ public class TestLambdaFeature extends JavadocTester { "
default default void defaultMethod()
"}, {BUG_ID + FS + "pkg" + FS + "B.html", "default void"}, + {BUG_ID + FS + "pkg1" + FS + "NotAFuncInf.html", + "
" + NL + "
Functional Interface:
" + NL + + "
This is a functional interface and can therefore be used as " + + "the assignment target for a lambda expression or method " + + "reference.
" + NL + "
"}, {BUG_ID + FS + "pkg" + FS + "B.html", "
" + NL + "
Functional Interface:
"} }; diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java index c52f249b491..8e5992baebf 100644 --- a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg/A.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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 @@ package pkg; +@FunctionalInterface public interface A { public void method1(); diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java index 566acf596ca..bace6ea9b98 100644 --- a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/FuncInf.java @@ -23,6 +23,7 @@ package pkg1; +@FunctionalInterface public interface FuncInf { V call() throws Exception; diff --git a/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java new file mode 100644 index 00000000000..24ad4cd393e --- /dev/null +++ b/langtools/test/com/sun/javadoc/testLambdaFeature/pkg1/NotAFuncInf.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 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 pkg1; + +public interface NotAFuncInf { + + V call() throws Exception; +} From fa3b0a8f47fd2b93c5a0a797d3dbe3fb3a2450aa Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 31 Mar 2014 09:08:53 +0200 Subject: [PATCH 090/170] 8031755: Type speculation should be used to optimize explicit null checks Feed profiling data about reference nullness to type speculation. Reviewed-by: kvn, iveresov --- hotspot/src/share/vm/ci/ciMethod.cpp | 77 +-- hotspot/src/share/vm/ci/ciMethod.hpp | 8 +- hotspot/src/share/vm/oops/methodData.cpp | 2 + hotspot/src/share/vm/oops/methodData.hpp | 2 +- hotspot/src/share/vm/opto/connode.cpp | 14 +- hotspot/src/share/vm/opto/doCall.cpp | 11 +- hotspot/src/share/vm/opto/graphKit.cpp | 115 +++- hotspot/src/share/vm/opto/graphKit.hpp | 17 +- hotspot/src/share/vm/opto/library_call.cpp | 8 +- hotspot/src/share/vm/opto/parse2.cpp | 14 +- hotspot/src/share/vm/opto/phaseX.cpp | 2 +- hotspot/src/share/vm/opto/type.cpp | 627 +++++++++++------- hotspot/src/share/vm/opto/type.hpp | 186 +++--- hotspot/src/share/vm/runtime/arguments.cpp | 4 - .../src/share/vm/runtime/deoptimization.cpp | 1 + .../src/share/vm/runtime/deoptimization.hpp | 13 +- 16 files changed, 683 insertions(+), 418 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index c927b10a030..9cbed6f0d69 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -581,14 +581,14 @@ void ciMethod::assert_call_type_ok(int bci) { * Check whether profiling provides a type for the argument i to the * call at bci bci * - * @param bci bci of the call - * @param i argument number - * @return profiled type + * @param [in]bci bci of the call + * @param [in]i argument number + * @param [out]type profiled type of argument, NULL if none + * @param [out]maybe_null true if null was seen for argument + * @return true if profiling exists * - * If the profile reports that the argument may be null, return false - * at least for now. */ -ciKlass* ciMethod::argument_profiled_type(int bci, int i) { +bool ciMethod::argument_profiled_type(int bci, int i, ciKlass*& type, bool& maybe_null) { if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) { ciProfileData* data = method_data()->bci_to_data(bci); if (data != NULL) { @@ -596,82 +596,77 @@ ciKlass* ciMethod::argument_profiled_type(int bci, int i) { assert_virtual_call_type_ok(bci); ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData(); if (i >= call->number_of_arguments()) { - return NULL; - } - ciKlass* type = call->valid_argument_type(i); - if (type != NULL && !call->argument_maybe_null(i)) { - return type; + return false; } + type = call->valid_argument_type(i); + maybe_null = call->argument_maybe_null(i); + return true; } else if (data->is_CallTypeData()) { assert_call_type_ok(bci); ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData(); if (i >= call->number_of_arguments()) { - return NULL; - } - ciKlass* type = call->valid_argument_type(i); - if (type != NULL && !call->argument_maybe_null(i)) { - return type; + return false; } + type = call->valid_argument_type(i); + maybe_null = call->argument_maybe_null(i); + return true; } } } - return NULL; + return false; } /** * Check whether profiling provides a type for the return value from * the call at bci bci * - * @param bci bci of the call - * @return profiled type + * @param [in]bci bci of the call + * @param [out]type profiled type of argument, NULL if none + * @param [out]maybe_null true if null was seen for argument + * @return true if profiling exists * - * If the profile reports that the argument may be null, return false - * at least for now. */ -ciKlass* ciMethod::return_profiled_type(int bci) { +bool ciMethod::return_profiled_type(int bci, ciKlass*& type, bool& maybe_null) { if (MethodData::profile_return() && method_data() != NULL && method_data()->is_mature()) { ciProfileData* data = method_data()->bci_to_data(bci); if (data != NULL) { if (data->is_VirtualCallTypeData()) { assert_virtual_call_type_ok(bci); ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData(); - ciKlass* type = call->valid_return_type(); - if (type != NULL && !call->return_maybe_null()) { - return type; - } + type = call->valid_return_type(); + maybe_null = call->return_maybe_null(); + return true; } else if (data->is_CallTypeData()) { assert_call_type_ok(bci); ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData(); - ciKlass* type = call->valid_return_type(); - if (type != NULL && !call->return_maybe_null()) { - return type; - } + type = call->valid_return_type(); + maybe_null = call->return_maybe_null(); + return true; } } } - return NULL; + return false; } /** * Check whether profiling provides a type for the parameter i * - * @param i parameter number - * @return profiled type + * @param [in]i parameter number + * @param [out]type profiled type of parameter, NULL if none + * @param [out]maybe_null true if null was seen for parameter + * @return true if profiling exists * - * If the profile reports that the argument may be null, return false - * at least for now. */ -ciKlass* ciMethod::parameter_profiled_type(int i) { +bool ciMethod::parameter_profiled_type(int i, ciKlass*& type, bool& maybe_null) { if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) { ciParametersTypeData* parameters = method_data()->parameters_type_data(); if (parameters != NULL && i < parameters->number_of_parameters()) { - ciKlass* type = parameters->valid_parameter_type(i); - if (type != NULL && !parameters->parameter_maybe_null(i)) { - return type; - } + type = parameters->valid_parameter_type(i); + maybe_null = parameters->parameter_maybe_null(i); + return true; } } - return NULL; + return false; } diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index d7ddba87b8e..959867410cd 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -234,10 +234,10 @@ class ciMethod : public ciMetadata { ciCallProfile call_profile_at_bci(int bci); int interpreter_call_site_count(int bci); - // Does type profiling provide a useful type at this point? - ciKlass* argument_profiled_type(int bci, int i); - ciKlass* parameter_profiled_type(int i); - ciKlass* return_profiled_type(int bci); + // Does type profiling provide any useful information at this point? + bool argument_profiled_type(int bci, int i, ciKlass*& type, bool& maybe_null); + bool parameter_profiled_type(int i, ciKlass*& type, bool& maybe_null); + bool return_profiled_type(int bci, ciKlass*& type, bool& maybe_null); ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 20b36e9514d..a0d55ecfd79 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -801,6 +801,8 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) { case Bytecodes::_invokeinterface: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: + case Bytecodes::_ifnull: + case Bytecodes::_ifnonnull: case Bytecodes::_invokestatic: #ifdef COMPILER2 return UseTypeSpeculation; diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index c763779c351..32443db79ac 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -2052,7 +2052,7 @@ public: // Whole-method sticky bits and flags enum { - _trap_hist_limit = 19, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 20, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index 0a71bc598e4..baf8f4f0434 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -399,7 +399,7 @@ Node *ConstraintCastNode::Identity( PhaseTransform *phase ) { // Take 'join' of input and cast-up type const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const { if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; -const Type* ft = phase->type(in(1))->filter_speculative(_type); + const Type* ft = phase->type(in(1))->filter_speculative(_type); #ifdef ASSERT // Previous versions of this function had some special case logic, @@ -493,7 +493,17 @@ const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const { result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); } } - return result; + + // This is the code from TypePtr::xmeet() that prevents us from + // having 2 ways to represent the same type. We have to replicate it + // here because we don't go through meet/join. + if (result->remove_speculative() == result->speculative()) { + result = result->remove_speculative(); + } + + // Same as above: because we don't go through meet/join, remove the + // speculative type if we know we won't use it. + return result->cleanup_speculative(); // JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES. // FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR! diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index d56f460ea6d..2816f2d0a94 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -249,8 +249,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool } CallGenerator* miss_cg; Deoptimization::DeoptReason reason = morphism == 2 ? - Deoptimization::Reason_bimorphic : - (speculative_receiver_type == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check); + Deoptimization::Reason_bimorphic : Deoptimization::reason_class_check(speculative_receiver_type != NULL); if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) && !too_many_traps(jvms->method(), jvms->bci(), reason) ) { @@ -631,13 +630,7 @@ void Parse::do_call() { } BasicType ct = ctype->basic_type(); if (ct == T_OBJECT || ct == T_ARRAY) { - ciKlass* better_type = method()->return_profiled_type(bci()); - if (UseTypeSpeculation && better_type != NULL) { - // If profiling reports a single type for the return value, - // feed it to the type system so it can propagate it as a - // speculative type - record_profile_for_speculation(stack(sp()-1), better_type); - } + record_profiled_return_for_speculation(); } } diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index a710d6c32c9..838e9758da7 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -612,10 +612,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) { // Usual case: Bail to interpreter. // Reserve the right to recompile if we haven't seen anything yet. - assert(!Deoptimization::reason_is_speculate(reason), "unsupported"); + ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : NULL; Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile; if (treat_throw_as_hot - && (method()->method_data()->trap_recompiled_at(bci(), NULL) + && (method()->method_data()->trap_recompiled_at(bci(), m) || C->too_many_traps(reason))) { // We cannot afford to take more traps here. Suffer in the interpreter. if (C->log() != NULL) @@ -1181,7 +1181,8 @@ extern int explicit_null_checks_inserted, Node* GraphKit::null_check_common(Node* value, BasicType type, // optional arguments for variations: bool assert_null, - Node* *null_control) { + Node* *null_control, + bool speculative) { assert(!assert_null || null_control == NULL, "not both at once"); if (stopped()) return top(); if (!GenerateCompilerNullChecks && !assert_null && null_control == NULL) { @@ -1291,13 +1292,13 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // Branch to failure if null float ok_prob = PROB_MAX; // a priori estimate: nulls never happen Deoptimization::DeoptReason reason; - if (assert_null) + if (assert_null) { reason = Deoptimization::Reason_null_assert; - else if (type == T_OBJECT) - reason = Deoptimization::Reason_null_check; - else + } else if (type == T_OBJECT) { + reason = Deoptimization::reason_null_check(speculative); + } else { reason = Deoptimization::Reason_div0_check; - + } // %%% Since Reason_unhandled is not recorded on a per-bytecode basis, // ciMethodData::has_trap_at will return a conservative -1 if any // must-be-null assertion has failed. This could cause performance @@ -2120,21 +2121,36 @@ void GraphKit::round_double_arguments(ciMethod* dest_method) { * * @param n node that the type applies to * @param exact_kls type from profiling + * @param maybe_null did profiling see null? * * @return node with improved type */ -Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) { +Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls, bool maybe_null) { const Type* current_type = _gvn.type(n); assert(UseTypeSpeculation, "type speculation must be on"); - const TypeOopPtr* speculative = current_type->speculative(); + const TypePtr* speculative = current_type->speculative(); + // Should the klass from the profile be recorded in the speculative type? if (current_type->would_improve_type(exact_kls, jvms()->depth())) { const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls); const TypeOopPtr* xtype = tklass->as_instance_type(); assert(xtype->klass_is_exact(), "Should be exact"); + // Any reason to believe n is not null (from this profiling or a previous one)? + const TypePtr* ptr = (maybe_null && current_type->speculative_maybe_null()) ? TypePtr::BOTTOM : TypePtr::NOTNULL; // record the new speculative type's depth - speculative = xtype->with_inline_depth(jvms()->depth()); + speculative = xtype->cast_to_ptr_type(ptr->ptr())->is_ptr(); + speculative = speculative->with_inline_depth(jvms()->depth()); + } else if (current_type->would_improve_ptr(maybe_null)) { + // Profiling report that null was never seen so we can change the + // speculative type to non null ptr. + assert(!maybe_null, "nothing to improve"); + if (speculative == NULL) { + speculative = TypePtr::NOTNULL; + } else { + const TypePtr* ptr = TypePtr::NOTNULL; + speculative = speculative->cast_to_ptr_type(ptr->ptr())->is_ptr(); + } } if (speculative != current_type->speculative()) { @@ -2167,7 +2183,15 @@ Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) { return n; } ciKlass* exact_kls = profile_has_unique_klass(); - return record_profile_for_speculation(n, exact_kls); + bool maybe_null = true; + if (java_bc() == Bytecodes::_checkcast || + java_bc() == Bytecodes::_instanceof || + java_bc() == Bytecodes::_aastore) { + ciProfileData* data = method()->method_data()->bci_to_data(bci()); + bool maybe_null = data == NULL ? true : data->as_BitData()->null_seen(); + } + return record_profile_for_speculation(n, exact_kls, maybe_null); + return n; } /** @@ -2187,9 +2211,10 @@ void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) { const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms); if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) { - ciKlass* better_type = method()->argument_profiled_type(bci(), i); - if (better_type != NULL) { - record_profile_for_speculation(argument(j), better_type); + bool maybe_null = true; + ciKlass* better_type = NULL; + if (method()->argument_profiled_type(bci(), i, better_type, maybe_null)) { + record_profile_for_speculation(argument(j), better_type, maybe_null); } i++; } @@ -2206,15 +2231,34 @@ void GraphKit::record_profiled_parameters_for_speculation() { } for (int i = 0, j = 0; i < method()->arg_size() ; i++) { if (_gvn.type(local(i))->isa_oopptr()) { - ciKlass* better_type = method()->parameter_profiled_type(j); - if (better_type != NULL) { - record_profile_for_speculation(local(i), better_type); + bool maybe_null = true; + ciKlass* better_type = NULL; + if (method()->parameter_profiled_type(j, better_type, maybe_null)) { + record_profile_for_speculation(local(i), better_type, maybe_null); } j++; } } } +/** + * Record profiling data from return value profiling at an invoke with + * the type system so that it can propagate it (speculation) + */ +void GraphKit::record_profiled_return_for_speculation() { + if (!UseTypeSpeculation) { + return; + } + bool maybe_null = true; + ciKlass* better_type = NULL; + if (method()->return_profiled_type(bci(), better_type, maybe_null)) { + // If profiling reports a single type for the return value, + // feed it to the type system so it can propagate it as a + // speculative type + record_profile_for_speculation(stack(sp()-1), better_type, maybe_null); + } +} + void GraphKit::round_double_result(ciMethod* dest_method) { // A non-strict method may return a double value which has an extended // exponent, but this must not be visible in a caller which is 'strict' @@ -2294,10 +2338,12 @@ Node* GraphKit::dstore_rounding(Node* n) { // Null check oop. Set null-path control into Region in slot 3. // Make a cast-not-nullness use the other not-null control. Return cast. Node* GraphKit::null_check_oop(Node* value, Node* *null_control, - bool never_see_null, bool safe_for_replace) { + bool never_see_null, + bool safe_for_replace, + bool speculative) { // Initial NULL check taken path (*null_control) = top(); - Node* cast = null_check_common(value, T_OBJECT, false, null_control); + Node* cast = null_check_common(value, T_OBJECT, false, null_control, speculative); // Generate uncommon_trap: if (never_see_null && (*null_control) != top()) { @@ -2308,7 +2354,8 @@ Node* GraphKit::null_check_oop(Node* value, Node* *null_control, PreserveJVMState pjvms(this); set_control(*null_control); replace_in_map(value, null()); - uncommon_trap(Deoptimization::Reason_null_check, + Deoptimization::DeoptReason reason = Deoptimization::reason_null_check(speculative); + uncommon_trap(reason, Deoptimization::Action_make_not_entrant); (*null_control) = top(); // NULL path is dead } @@ -2732,11 +2779,16 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass, // recompile; the offending check will be recompiled to handle NULLs. // If we see several offending BCIs, then all checks in the // method will be recompiled. -bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { +bool GraphKit::seems_never_null(Node* obj, ciProfileData* data, bool& speculating) { + speculating = !_gvn.type(obj)->speculative_maybe_null(); + Deoptimization::DeoptReason reason = Deoptimization::reason_null_check(speculating); if (UncommonNullCast // Cutout for this technique && obj != null() // And not the -Xcomp stupid case? - && !too_many_traps(Deoptimization::Reason_null_check) + && !too_many_traps(reason) ) { + if (speculating) { + return true; + } if (data == NULL) // Edge case: no mature data. Be optimistic here. return true; @@ -2746,6 +2798,7 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here"); return !data->as_BitData()->null_seen(); } + speculating = false; return false; } @@ -2758,7 +2811,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj, bool safe_for_replace) { if (!UseTypeProfile || !TypeProfileCasts) return NULL; - Deoptimization::DeoptReason reason = spec_klass == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check; + Deoptimization::DeoptReason reason = Deoptimization::reason_class_check(spec_klass != NULL); // Make sure we haven't already deoptimized from this tactic. if (too_many_traps(reason)) @@ -2811,7 +2864,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, // type == NULL if profiling tells us this object is always null if (type != NULL) { Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check; - Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check; + Deoptimization::DeoptReason null_reason = Deoptimization::Reason_speculate_null_check; if (!too_many_traps(null_reason) && !too_many_traps(class_reason)) { Node* not_null_obj = NULL; @@ -2819,7 +2872,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, // there's no need for a null check if (!not_null) { Node* null_ctl = top(); - not_null_obj = null_check_oop(obj, &null_ctl, true, true); + not_null_obj = null_check_oop(obj, &null_ctl, true, true, true); assert(null_ctl->is_top(), "no null control here"); } else { not_null_obj = obj; @@ -2867,12 +2920,13 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode data = method()->method_data()->bci_to_data(bci()); } + bool speculative_not_null = false; bool never_see_null = (ProfileDynamicTypes // aggressive use of profile - && seems_never_null(obj, data)); + && seems_never_null(obj, data, speculative_not_null)); // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? @@ -2995,12 +3049,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, C->set_has_split_ifs(true); // Has chance for split-if optimization // Use null-cast information if it is available + bool speculative_not_null = false; bool never_see_null = ((failure_control == NULL) // regular case only - && seems_never_null(obj, data)); + && seems_never_null(obj, data, speculative_not_null)); // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); - Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace); + Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null); // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 703b8d8f2a6..0d2c6b07a81 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -351,9 +351,11 @@ class GraphKit : public Phase { // Return the value cast to not-null. // Be clever about equivalent dominating null checks. Node* null_check_common(Node* value, BasicType type, - bool assert_null = false, Node* *null_control = NULL); + bool assert_null = false, + Node* *null_control = NULL, + bool speculative = false); Node* null_check(Node* value, BasicType type = T_OBJECT) { - return null_check_common(value, type); + return null_check_common(value, type, false, NULL, !_gvn.type(value)->speculative_maybe_null()); } Node* null_check_receiver() { assert(argument(0)->bottom_type()->isa_ptr(), "must be"); @@ -382,10 +384,12 @@ class GraphKit : public Phase { // If safe_for_replace, then we can replace the value with the cast // in the parsing map (the cast is guaranteed to dominate the map) Node* null_check_oop(Node* value, Node* *null_control, - bool never_see_null = false, bool safe_for_replace = false); + bool never_see_null = false, + bool safe_for_replace = false, + bool speculative = false); // Check the null_seen bit. - bool seems_never_null(Node* obj, ciProfileData* data); + bool seems_never_null(Node* obj, ciProfileData* data, bool& speculating); // Check for unique class for receiver at call ciKlass* profile_has_unique_klass() { @@ -399,10 +403,11 @@ class GraphKit : public Phase { } // record type from profiling with the type system - Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls); - Node* record_profiled_receiver_for_speculation(Node* n); + Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls, bool maybe_null); void record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc); void record_profiled_parameters_for_speculation(); + void record_profiled_return_for_speculation(); + Node* record_profiled_receiver_for_speculation(Node* n); // Use the type profile to narrow an object type. Node* maybe_cast_profiled_receiver(Node* not_null_obj, diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 065776dd421..af27b0a9899 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -4658,7 +4658,7 @@ bool LibraryCallKit::inline_arraycopy() { ciKlass* src_k = NULL; if (!has_src) { - src_k = src_type->speculative_type(); + src_k = src_type->speculative_type_not_null(); if (src_k != NULL && src_k->is_array_klass()) { could_have_src = true; } @@ -4666,7 +4666,7 @@ bool LibraryCallKit::inline_arraycopy() { ciKlass* dest_k = NULL; if (!has_dest) { - dest_k = dest_type->speculative_type(); + dest_k = dest_type->speculative_type_not_null(); if (dest_k != NULL && dest_k->is_array_klass()) { could_have_dest = true; } @@ -4738,13 +4738,13 @@ bool LibraryCallKit::inline_arraycopy() { ciKlass* src_k = top_src->klass(); ciKlass* dest_k = top_dest->klass(); if (!src_spec) { - src_k = src_type->speculative_type(); + src_k = src_type->speculative_type_not_null(); if (src_k != NULL && src_k->is_array_klass()) { could_have_src = true; } } if (!dest_spec) { - dest_k = dest_type->speculative_type(); + dest_k = dest_type->speculative_type_not_null(); if (dest_k != NULL && dest_k->is_array_klass()) { could_have_dest = true; } diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index f82d246c381..2b038172021 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -1288,7 +1288,7 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest, (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { TypeNode* ccast = new (C) CheckCastPPNode(control(), obj, tboth); const Type* tcc = ccast->as_Type()->type(); - assert(tcc != obj_type && tcc->higher_equal_speculative(obj_type), "must improve"); + assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. _gvn.set_type_bottom(ccast); @@ -1352,7 +1352,7 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest, if (ccast != NULL) { const Type* tcc = ccast->as_Type()->type(); - assert(tcc != tval && tcc->higher_equal_speculative(tval), "must improve"); + assert(tcc != tval && tcc->higher_equal(tval), "must improve"); // Delay transform() call to allow recovery of pre-cast value // at the control merge. ccast->set_req(0, control()); @@ -1393,7 +1393,7 @@ Node* Parse::optimize_cmp_with_klass(Node* c) { Node* addp = load_klass->in(2); Node* obj = addp->in(AddPNode::Address); const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); - if (obj_type->speculative_type() != NULL) { + if (obj_type->speculative_type_not_null() != NULL) { ciKlass* k = obj_type->speculative_type(); inc_sp(2); obj = maybe_cast_profiled_obj(obj, k); @@ -2277,6 +2277,14 @@ void Parse::do_one_bytecode() { maybe_add_safepoint(iter().get_dest()); a = null(); b = pop(); + if (!_gvn.type(b)->speculative_maybe_null() && + !too_many_traps(Deoptimization::Reason_speculate_null_check)) { + inc_sp(1); + Node* null_ctl = top(); + b = null_check_oop(b, &null_ctl, true, true, true); + assert(null_ctl->is_top(), "no null control here"); + dec_sp(1); + } c = _gvn.transform( new (C) CmpPNode(b, a) ); do_ifnull(btest, c); break; diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index fd08b065c5f..b3b30850d19 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -330,7 +330,7 @@ void NodeHash::check_no_speculative_types() { Node *sentinel_node = sentinel(); for (uint i = 0; i < max; ++i) { Node *n = at(i); - if(n != NULL && n != sentinel_node && n->is_Type()) { + if(n != NULL && n != sentinel_node && n->is_Type() && n->outcnt() > 0) { TypeNode* tn = n->as_Type(); const Type* t = tn->type(); const Type* t_no_spec = t->remove_speculative(); diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 4a7ad22b2c1..0f011e04864 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -350,9 +350,9 @@ void Type::Initialize_shared(Compile* current) { floop[1] = TypeInt::INT; TypeTuple::LOOPBODY = TypeTuple::make( 2, floop ); - TypePtr::NULL_PTR= TypePtr::make( AnyPtr, TypePtr::Null, 0 ); - TypePtr::NOTNULL = TypePtr::make( AnyPtr, TypePtr::NotNull, OffsetBot ); - TypePtr::BOTTOM = TypePtr::make( AnyPtr, TypePtr::BotPTR, OffsetBot ); + TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, 0); + TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, OffsetBot); + TypePtr::BOTTOM = TypePtr::make(AnyPtr, TypePtr::BotPTR, OffsetBot); TypeRawPtr::BOTTOM = TypeRawPtr::make( TypePtr::BotPTR ); TypeRawPtr::NOTNULL= TypeRawPtr::make( TypePtr::NotNull ); @@ -372,7 +372,7 @@ void Type::Initialize_shared(Compile* current) { false, 0, oopDesc::mark_offset_in_bytes()); TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), false, 0, oopDesc::klass_offset_in_bytes()); - TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot, NULL); + TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot); TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot); @@ -620,8 +620,8 @@ bool Type::interface_vs_oop(const Type *t) const { return true; } // Now check the speculative parts as well - const TypeOopPtr* this_spec = isa_oopptr() != NULL ? isa_oopptr()->speculative() : NULL; - const TypeOopPtr* t_spec = t->isa_oopptr() != NULL ? t->isa_oopptr()->speculative() : NULL; + const TypePtr* this_spec = isa_ptr() != NULL ? is_ptr()->speculative() : NULL; + const TypePtr* t_spec = t->isa_ptr() != NULL ? t->is_ptr()->speculative() : NULL; if (this_spec != NULL && t_spec != NULL) { if (this_spec->interface_vs_oop_helper(t_spec)) { return true; @@ -1975,6 +1975,25 @@ const Type* TypeAry::remove_speculative() const { return make(_elem->remove_speculative(), _size, _stable); } +/** + * Return same type with cleaned up speculative part of element + */ +const Type* TypeAry::cleanup_speculative() const { + return make(_elem->cleanup_speculative(), _size, _stable); +} + +/** + * Return same type but with a different inline depth (used for speculation) + * + * @param depth depth to meet with + */ +const TypePtr* TypePtr::with_inline_depth(int depth) const { + if (!UseInlineDepthForSpeculativeTypes) { + return this; + } + return make(AnyPtr, _ptr, _offset, _speculative, depth); +} + //----------------------interface_vs_oop--------------------------------------- #ifdef ASSERT bool TypeAry::interface_vs_oop(const Type *t) const { @@ -2179,15 +2198,15 @@ const TypePtr::PTR TypePtr::ptr_meet[TypePtr::lastPTR][TypePtr::lastPTR] = { }; //------------------------------make------------------------------------------- -const TypePtr *TypePtr::make( TYPES t, enum PTR ptr, int offset ) { - return (TypePtr*)(new TypePtr(t,ptr,offset))->hashcons(); +const TypePtr *TypePtr::make(TYPES t, enum PTR ptr, int offset, const TypePtr* speculative, int inline_depth) { + return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons(); } //------------------------------cast_to_ptr_type------------------------------- const Type *TypePtr::cast_to_ptr_type(PTR ptr) const { assert(_base == AnyPtr, "subclass must override cast_to_ptr_type"); if( ptr == _ptr ) return this; - return make(_base, ptr, _offset); + return make(_base, ptr, _offset, _speculative, _inline_depth); } //------------------------------get_con---------------------------------------- @@ -2198,7 +2217,29 @@ intptr_t TypePtr::get_con() const { //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. -const Type *TypePtr::xmeet( const Type *t ) const { +const Type *TypePtr::xmeet(const Type *t) const { + const Type* res = xmeet_helper(t); + if (res->isa_ptr() == NULL) { + return res; + } + + const TypePtr* res_ptr = res->is_ptr(); + if (res_ptr->speculative() != NULL) { + // type->speculative() == NULL means that speculation is no better + // than type, i.e. type->speculative() == type. So there are 2 + // ways to represent the fact that we have no useful speculative + // data and we should use a single one to be able to test for + // equality between types. Check whether type->speculative() == + // type and set speculative to NULL if it is the case. + if (res_ptr->remove_speculative() == res_ptr->speculative()) { + return res_ptr->remove_speculative(); + } + } + + return res; +} + +const Type *TypePtr::xmeet_helper(const Type *t) const { // Perform a fast test for common case; meeting the same types together. if( this == t ) return this; // Meeting same type-rep? @@ -2221,7 +2262,9 @@ const Type *TypePtr::xmeet( const Type *t ) const { case AnyPtr: { // Meeting to AnyPtrs const TypePtr *tp = t->is_ptr(); - return make( AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()) ); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); + return make(AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()), speculative, depth); } case RawPtr: // For these, flip the call around to cut down case OopPtr: @@ -2260,7 +2303,7 @@ const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = { BotPTR, NotNull, Constant, Null, AnyNull, TopPTR }; const Type *TypePtr::xdual() const { - return new TypePtr( AnyPtr, dual_ptr(), dual_offset() ); + return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), dual_speculative(), dual_inline_depth()); } //------------------------------xadd_offset------------------------------------ @@ -2281,20 +2324,245 @@ int TypePtr::xadd_offset( intptr_t offset ) const { //------------------------------add_offset------------------------------------- const TypePtr *TypePtr::add_offset( intptr_t offset ) const { - return make( AnyPtr, _ptr, xadd_offset(offset) ); + return make(AnyPtr, _ptr, xadd_offset(offset), _speculative, _inline_depth); } //------------------------------eq--------------------------------------------- // Structural equality check for Type representations bool TypePtr::eq( const Type *t ) const { const TypePtr *a = (const TypePtr*)t; - return _ptr == a->ptr() && _offset == a->offset(); + return _ptr == a->ptr() && _offset == a->offset() && eq_speculative(a) && _inline_depth == a->_inline_depth; } //------------------------------hash------------------------------------------- // Type-specific hashing function. int TypePtr::hash(void) const { - return _ptr + _offset; + return _ptr + _offset + hash_speculative() + _inline_depth; +; +} + +/** + * Return same type without a speculative part + */ +const Type* TypePtr::remove_speculative() const { + if (_speculative == NULL) { + return this; + } + assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth"); + return make(AnyPtr, _ptr, _offset, NULL, _inline_depth); +} + +/** + * Return same type but drop speculative part if we know we won't use + * it + */ +const Type* TypePtr::cleanup_speculative() const { + if (speculative() == NULL) { + return this; + } + const Type* no_spec = remove_speculative(); + // If this is NULL_PTR then we don't need the speculative type + // (with_inline_depth in case the current type inline depth is + // InlineDepthTop) + if (no_spec == NULL_PTR->with_inline_depth(inline_depth())) { + return no_spec; + } + if (above_centerline(speculative()->ptr())) { + return no_spec; + } + const TypeOopPtr* spec_oopptr = speculative()->isa_oopptr(); + // If the speculative may be null and is an inexact klass then it + // doesn't help + if (speculative()->maybe_null() && (spec_oopptr == NULL || !spec_oopptr->klass_is_exact())) { + return no_spec; + } + return this; +} + +/** + * dual of the speculative part of the type + */ +const TypePtr* TypePtr::dual_speculative() const { + if (_speculative == NULL) { + return NULL; + } + return _speculative->dual()->is_ptr(); +} + +/** + * meet of the speculative parts of 2 types + * + * @param other type to meet with + */ +const TypePtr* TypePtr::xmeet_speculative(const TypePtr* other) const { + bool this_has_spec = (_speculative != NULL); + bool other_has_spec = (other->speculative() != NULL); + + if (!this_has_spec && !other_has_spec) { + return NULL; + } + + // If we are at a point where control flow meets and one branch has + // a speculative type and the other has not, we meet the speculative + // type of one branch with the actual type of the other. If the + // actual type is exact and the speculative is as well, then the + // result is a speculative type which is exact and we can continue + // speculation further. + const TypePtr* this_spec = _speculative; + const TypePtr* other_spec = other->speculative(); + + if (!this_has_spec) { + this_spec = this; + } + + if (!other_has_spec) { + other_spec = other; + } + + return this_spec->meet(other_spec)->is_ptr(); +} + +/** + * dual of the inline depth for this type (used for speculation) + */ +int TypePtr::dual_inline_depth() const { + return -inline_depth(); +} + +/** + * meet of 2 inline depths (used for speculation) + * + * @param depth depth to meet with + */ +int TypePtr::meet_inline_depth(int depth) const { + return MAX2(inline_depth(), depth); +} + +/** + * Are the speculative parts of 2 types equal? + * + * @param other type to compare this one to + */ +bool TypePtr::eq_speculative(const TypePtr* other) const { + if (_speculative == NULL || other->speculative() == NULL) { + return _speculative == other->speculative(); + } + + if (_speculative->base() != other->speculative()->base()) { + return false; + } + + return _speculative->eq(other->speculative()); +} + +/** + * Hash of the speculative part of the type + */ +int TypePtr::hash_speculative() const { + if (_speculative == NULL) { + return 0; + } + + return _speculative->hash(); +} + +/** + * add offset to the speculative part of the type + * + * @param offset offset to add + */ +const TypePtr* TypePtr::add_offset_speculative(intptr_t offset) const { + if (_speculative == NULL) { + return NULL; + } + return _speculative->add_offset(offset)->is_ptr(); +} + +/** + * return exact klass from the speculative type if there's one + */ +ciKlass* TypePtr::speculative_type() const { + if (_speculative != NULL && _speculative->isa_oopptr()) { + const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr(); + if (speculative->klass_is_exact()) { + return speculative->klass(); + } + } + return NULL; +} + +/** + * return true if speculative type may be null + */ +bool TypePtr::speculative_maybe_null() const { + if (_speculative != NULL) { + const TypePtr* speculative = _speculative->join(this)->is_ptr(); + return speculative->maybe_null(); + } + return true; +} + +/** + * Same as TypePtr::speculative_type() but return the klass only if + * the speculative tells us is not null + */ +ciKlass* TypePtr::speculative_type_not_null() const { + if (speculative_maybe_null()) { + return NULL; + } + return speculative_type(); +} + +/** + * Check whether new profiling would improve speculative type + * + * @param exact_kls class from profiling + * @param inline_depth inlining depth of profile point + * + * @return true if type profile is valuable + */ +bool TypePtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const { + // no profiling? + if (exact_kls == NULL) { + return false; + } + // no speculative type or non exact speculative type? + if (speculative_type() == NULL) { + return true; + } + // If the node already has an exact speculative type keep it, + // unless it was provided by profiling that is at a deeper + // inlining level. Profiling at a higher inlining depth is + // expected to be less accurate. + if (_speculative->inline_depth() == InlineDepthBottom) { + return false; + } + assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison"); + return inline_depth < _speculative->inline_depth(); +} + +/** + * Check whether new profiling would improve ptr (= tells us it is non + * null) + * + * @param maybe_null true if profiling tells the ptr may be null + * + * @return true if ptr profile is valuable + */ +bool TypePtr::would_improve_ptr(bool maybe_null) const { + // profiling doesn't tell us anything useful + if (maybe_null) { + return false; + } + // We already know this is not be null + if (!this->maybe_null()) { + return false; + } + // We already know the speculative type cannot be null + if (!speculative_maybe_null()) { + return false; + } + return true; } //------------------------------dump2------------------------------------------ @@ -2309,6 +2577,32 @@ void TypePtr::dump2( Dict &d, uint depth, outputStream *st ) const { if( _offset == OffsetTop ) st->print("+top"); else if( _offset == OffsetBot ) st->print("+bot"); else if( _offset ) st->print("+%d", _offset); + dump_inline_depth(st); + dump_speculative(st); +} + +/** + *dump the speculative part of the type + */ +void TypePtr::dump_speculative(outputStream *st) const { + if (_speculative != NULL) { + st->print(" (speculative="); + _speculative->dump_on(st); + st->print(")"); + } +} + +/** + *dump the inline depth of the type + */ +void TypePtr::dump_inline_depth(outputStream *st) const { + if (_inline_depth != InlineDepthBottom) { + if (_inline_depth == InlineDepthTop) { + st->print(" (inline_depth=InlineDepthTop)"); + } else { + st->print(" (inline_depth=%d)", _inline_depth); + } + } } #endif @@ -2399,7 +2693,7 @@ const Type *TypeRawPtr::xmeet( const Type *t ) const { case TypePtr::Null: if( _ptr == TypePtr::TopPTR ) return t; return TypeRawPtr::BOTTOM; - case TypePtr::NotNull: return TypePtr::make( AnyPtr, meet_ptr(TypePtr::NotNull), tp->meet_offset(0) ); + case TypePtr::NotNull: return TypePtr::make(AnyPtr, meet_ptr(TypePtr::NotNull), tp->meet_offset(0), tp->speculative(), tp->inline_depth()); case TypePtr::AnyNull: if( _ptr == TypePtr::Constant) return this; return make( meet_ptr(TypePtr::AnyNull) ); @@ -2463,16 +2757,15 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { const TypeOopPtr *TypeOopPtr::BOTTOM; //------------------------------TypeOopPtr------------------------------------- -TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) - : TypePtr(t, ptr, offset), +TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, + int instance_id, const TypePtr* speculative, int inline_depth) + : TypePtr(t, ptr, offset, speculative, inline_depth), _const_oop(o), _klass(k), _klass_is_exact(xk), _is_ptr_to_narrowoop(false), _is_ptr_to_narrowklass(false), _is_ptr_to_boxed_value(false), - _instance_id(instance_id), - _speculative(speculative), - _inline_depth(inline_depth){ + _instance_id(instance_id) { if (Compile::current()->eliminate_boxing() && (t == InstPtr) && (offset > 0) && xk && (k != 0) && k->is_instance_klass()) { _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset); @@ -2538,8 +2831,8 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o } //------------------------------make------------------------------------------- -const TypeOopPtr *TypeOopPtr::make(PTR ptr, - int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) { +const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id, + const TypePtr* speculative, int inline_depth) { assert(ptr != Constant, "no constant generic pointers"); ciKlass* k = Compile::current()->env()->Object_klass(); bool xk = false; @@ -2582,28 +2875,6 @@ const TypeKlassPtr* TypeOopPtr::as_klass_type() const { return TypeKlassPtr::make(xk? Constant: NotNull, k, 0); } -const Type *TypeOopPtr::xmeet(const Type *t) const { - const Type* res = xmeet_helper(t); - if (res->isa_oopptr() == NULL) { - return res; - } - - const TypeOopPtr* res_oopptr = res->is_oopptr(); - if (res_oopptr->speculative() != NULL) { - // type->speculative() == NULL means that speculation is no better - // than type, i.e. type->speculative() == type. So there are 2 - // ways to represent the fact that we have no useful speculative - // data and we should use a single one to be able to test for - // equality between types. Check whether type->speculative() == - // type and set speculative to NULL if it is the case. - if (res_oopptr->remove_speculative() == res_oopptr->speculative()) { - return res_oopptr->remove_speculative(); - } - } - - return res; -} - //------------------------------meet------------------------------------------- // Compute the MEET of two types. It returns a new Type object. const Type *TypeOopPtr::xmeet_helper(const Type *t) const { @@ -2641,19 +2912,20 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const { const TypePtr *tp = t->is_ptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case Null: - if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset); + if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); // else fall through: case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = _speculative; - return make(ptr, offset, instance_id, speculative, _inline_depth); + return make(ptr, offset, instance_id, speculative, depth); } case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); default: typerr(t); } } @@ -2661,7 +2933,7 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const { case OopPtr: { // Meeting to other OopPtrs const TypeOopPtr *tp = t->is_oopptr(); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative, depth); } @@ -2859,9 +3131,7 @@ const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculativ bool TypeOopPtr::eq( const Type *t ) const { const TypeOopPtr *a = (const TypeOopPtr*)t; if (_klass_is_exact != a->_klass_is_exact || - _instance_id != a->_instance_id || - !eq_speculative(a) || - _inline_depth != a->_inline_depth) return false; + _instance_id != a->_instance_id) return false; ciObject* one = const_oop(); ciObject* two = a->const_oop(); if (one == NULL || two == NULL) { @@ -2878,8 +3148,6 @@ int TypeOopPtr::hash(void) const { (const_oop() ? const_oop()->hash() : 0) + _klass_is_exact + _instance_id + - hash_speculative() + - _inline_depth + TypePtr::hash(); } @@ -2903,27 +3171,6 @@ void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const { dump_inline_depth(st); dump_speculative(st); } - -/** - *dump the speculative part of the type - */ -void TypeOopPtr::dump_speculative(outputStream *st) const { - if (_speculative != NULL) { - st->print(" (speculative="); - _speculative->dump_on(st); - st->print(")"); - } -} - -void TypeOopPtr::dump_inline_depth(outputStream *st) const { - if (_inline_depth != InlineDepthBottom) { - if (_inline_depth == InlineDepthTop) { - st->print(" (inline_depth=InlineDepthTop)"); - } else { - st->print(" (inline_depth=%d)", _inline_depth); - } - } -} #endif //------------------------------singleton-------------------------------------- @@ -2951,50 +3198,31 @@ const Type* TypeOopPtr::remove_speculative() const { return make(_ptr, _offset, _instance_id, NULL, _inline_depth); } +/** + * Return same type but drop speculative part if we know we won't use + * it + */ +const Type* TypeOopPtr::cleanup_speculative() const { + // If the klass is exact and the ptr is not null then there's + // nothing that the speculative type can help us with + if (klass_is_exact() && !maybe_null()) { + return remove_speculative(); + } + return TypePtr::cleanup_speculative(); +} + /** * Return same type but with a different inline depth (used for speculation) * * @param depth depth to meet with */ -const TypeOopPtr* TypeOopPtr::with_inline_depth(int depth) const { +const TypePtr* TypeOopPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } return make(_ptr, _offset, _instance_id, _speculative, depth); } -/** - * Check whether new profiling would improve speculative type - * - * @param exact_kls class from profiling - * @param inline_depth inlining depth of profile point - * - * @return true if type profile is valuable - */ -bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const { - // no way to improve an already exact type - if (klass_is_exact()) { - return false; - } - // no profiling? - if (exact_kls == NULL) { - return false; - } - // no speculative type or non exact speculative type? - if (speculative_type() == NULL) { - return true; - } - // If the node already has an exact speculative type keep it, - // unless it was provided by profiling that is at a deeper - // inlining level. Profiling at a higher inlining depth is - // expected to be less accurate. - if (_speculative->inline_depth() == InlineDepthBottom) { - return false; - } - assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison"); - return inline_depth < _speculative->inline_depth(); -} - //------------------------------meet_instance_id-------------------------------- int TypeOopPtr::meet_instance_id( int instance_id ) const { // Either is 'TOP' instance? Return the other instance! @@ -3013,102 +3241,19 @@ int TypeOopPtr::dual_instance_id( ) const { } /** - * meet of the speculative parts of 2 types + * Check whether new profiling would improve speculative type * - * @param other type to meet with - */ -const TypeOopPtr* TypeOopPtr::xmeet_speculative(const TypeOopPtr* other) const { - bool this_has_spec = (_speculative != NULL); - bool other_has_spec = (other->speculative() != NULL); - - if (!this_has_spec && !other_has_spec) { - return NULL; - } - - // If we are at a point where control flow meets and one branch has - // a speculative type and the other has not, we meet the speculative - // type of one branch with the actual type of the other. If the - // actual type is exact and the speculative is as well, then the - // result is a speculative type which is exact and we can continue - // speculation further. - const TypeOopPtr* this_spec = _speculative; - const TypeOopPtr* other_spec = other->speculative(); - - if (!this_has_spec) { - this_spec = this; - } - - if (!other_has_spec) { - other_spec = other; - } - - return this_spec->meet_speculative(other_spec)->is_oopptr(); -} - -/** - * dual of the speculative part of the type - */ -const TypeOopPtr* TypeOopPtr::dual_speculative() const { - if (_speculative == NULL) { - return NULL; - } - return _speculative->dual()->is_oopptr(); -} - -/** - * add offset to the speculative part of the type + * @param exact_kls class from profiling + * @param inline_depth inlining depth of profile point * - * @param offset offset to add + * @return true if type profile is valuable */ -const TypeOopPtr* TypeOopPtr::add_offset_speculative(intptr_t offset) const { - if (_speculative == NULL) { - return NULL; - } - return _speculative->add_offset(offset)->is_oopptr(); -} - -/** - * Are the speculative parts of 2 types equal? - * - * @param other type to compare this one to - */ -bool TypeOopPtr::eq_speculative(const TypeOopPtr* other) const { - if (_speculative == NULL || other->speculative() == NULL) { - return _speculative == other->speculative(); - } - - if (_speculative->base() != other->speculative()->base()) { +bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const { + // no way to improve an already exact type + if (klass_is_exact()) { return false; } - - return _speculative->eq(other->speculative()); -} - -/** - * Hash of the speculative part of the type - */ -int TypeOopPtr::hash_speculative() const { - if (_speculative == NULL) { - return 0; - } - - return _speculative->hash(); -} - -/** - * dual of the inline depth for this type (used for speculation) - */ -int TypeOopPtr::dual_inline_depth() const { - return -inline_depth(); -} - -/** - * meet of 2 inline depth (used for speculation) - * - * @param depth depth to meet with - */ -int TypeOopPtr::meet_inline_depth(int depth) const { - return MAX2(inline_depth(), depth); + return TypePtr::would_improve_type(exact_kls, inline_depth); } //============================================================================= @@ -3120,8 +3265,10 @@ const TypeInstPtr *TypeInstPtr::MARK; const TypeInstPtr *TypeInstPtr::KLASS; //------------------------------TypeInstPtr------------------------------------- -TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative, int inline_depth) - : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), _name(k->name()) { +TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, + int instance_id, const TypePtr* speculative, int inline_depth) + : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), + _name(k->name()) { assert(k != NULL && (k->is_loaded() || o == NULL), "cannot have constants with non-loaded klass"); @@ -3134,7 +3281,7 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr, ciObject* o, int offset, int instance_id, - const TypeOopPtr* speculative, + const TypePtr* speculative, int inline_depth) { assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance"); // Either const_oop() is NULL or else ptr is Constant @@ -3217,7 +3364,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const { int off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); int instance_id = meet_instance_id(tinst->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tinst); + const TypePtr* speculative = xmeet_speculative(tinst); int depth = meet_inline_depth(tinst->inline_depth()); const TypeInstPtr *loaded = is_loaded() ? this : tinst; @@ -3295,7 +3442,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); switch (ptr) { case TopPTR: @@ -3346,7 +3493,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return make(ptr, klass(), klass_is_exact(), (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth); @@ -3354,7 +3501,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { case NotNull: case BotPTR: { int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth); } @@ -3367,20 +3514,21 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { const TypePtr *tp = t->is_ptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); + int instance_id = meet_instance_id(InstanceTop); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case Null: - if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); // else fall through to AnyNull case TopPTR: case AnyNull: { - int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = _speculative; return make(ptr, klass(), klass_is_exact(), - (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, _inline_depth); + (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth); } case NotNull: case BotPTR: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, speculative,depth); default: typerr(t); } } @@ -3407,7 +3555,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { int off = meet_offset( tinst->offset() ); PTR ptr = meet_ptr( tinst->ptr() ); int instance_id = meet_instance_id(tinst->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tinst); + const TypePtr* speculative = xmeet_speculative(tinst); int depth = meet_inline_depth(tinst->inline_depth()); // Check for easy case; klasses are equal (and perhaps not loaded!) @@ -3563,6 +3711,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const { // class hierarchy - which means we have to fall to at least NotNull. if( ptr == TopPTR || ptr == AnyNull || ptr == Constant ) ptr = NotNull; + instance_id = InstanceBot; // Now we find the LCA of Java classes @@ -3655,7 +3804,8 @@ void TypeInstPtr::dump2( Dict &d, uint depth, outputStream *st ) const { //------------------------------add_offset------------------------------------- const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const { - return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id, add_offset_speculative(offset)); + return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), + _instance_id, add_offset_speculative(offset), _inline_depth); } const Type *TypeInstPtr::remove_speculative() const { @@ -3663,10 +3813,11 @@ const Type *TypeInstPtr::remove_speculative() const { return this; } assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth"); - return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL, _inline_depth); + return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, + _instance_id, NULL, _inline_depth); } -const TypeOopPtr *TypeInstPtr::with_inline_depth(int depth) const { +const TypePtr *TypeInstPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } @@ -3687,7 +3838,8 @@ const TypeAryPtr *TypeAryPtr::FLOATS; const TypeAryPtr *TypeAryPtr::DOUBLES; //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) { +const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id, const TypePtr* speculative, int inline_depth) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); if (!xk) xk = ary->ary_must_be_exact(); @@ -3697,7 +3849,9 @@ const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool } //------------------------------make------------------------------------------- -const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth, bool is_autobox_cache) { +const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id, const TypePtr* speculative, int inline_depth, + bool is_autobox_cache) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" ); @@ -3807,7 +3961,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const TypeAry* new_ary = TypeAry::make(elem, size(), stable); - return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id); + return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth); } //-----------------------------stable_dimension-------------------------------- @@ -3868,18 +4022,17 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int depth = meet_inline_depth(tp->inline_depth()); + const TypePtr* speculative = xmeet_speculative(tp); switch (tp->ptr()) { case TopPTR: case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = xmeet_speculative(tp); return make(ptr, (ptr == Constant ? const_oop() : NULL), _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); } case BotPTR: case NotNull: { int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth); } default: ShouldNotReachHere(); @@ -3891,20 +4044,21 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { const TypePtr *tp = t->is_ptr(); int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); + const TypePtr* speculative = xmeet_speculative(tp); + int depth = meet_inline_depth(tp->inline_depth()); switch (tp->ptr()) { case TopPTR: return this; case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); case Null: - if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth); // else fall through to AnyNull case AnyNull: { int instance_id = meet_instance_id(InstanceTop); - const TypeOopPtr* speculative = _speculative; return make(ptr, (ptr == Constant ? const_oop() : NULL), - _ary, _klass, _klass_is_exact, offset, instance_id, speculative, _inline_depth); + _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth); } default: ShouldNotReachHere(); } @@ -3920,7 +4074,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary(); PTR ptr = meet_ptr(tap->ptr()); int instance_id = meet_instance_id(tap->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tap); + const TypePtr* speculative = xmeet_speculative(tap); int depth = meet_inline_depth(tap->inline_depth()); ciKlass* lazy_klass = NULL; if (tary->_elem->isa_int()) { @@ -3949,7 +4103,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); - return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); + return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); } bool xk = false; @@ -4001,7 +4155,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const { int offset = meet_offset(tp->offset()); PTR ptr = meet_ptr(tp->ptr()); int instance_id = meet_instance_id(tp->instance_id()); - const TypeOopPtr* speculative = xmeet_speculative(tp); + const TypePtr* speculative = xmeet_speculative(tp); int depth = meet_inline_depth(tp->inline_depth()); switch (ptr) { case TopPTR: @@ -4125,7 +4279,7 @@ const Type *TypeAryPtr::remove_speculative() const { return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth); } -const TypeOopPtr *TypeAryPtr::with_inline_depth(int depth) const { +const TypePtr *TypeAryPtr::with_inline_depth(int depth) const { if (!UseInlineDepthForSpeculativeTypes) { return this; } @@ -4250,6 +4404,13 @@ const TypeNarrowOop* TypeNarrowOop::make(const TypePtr* type) { return (const TypeNarrowOop*)(new TypeNarrowOop(type))->hashcons(); } +const Type* TypeNarrowOop::remove_speculative() const { + return make(_ptrtype->remove_speculative()->is_ptr()); +} + +const Type* TypeNarrowOop::cleanup_speculative() const { + return make(_ptrtype->cleanup_speculative()->is_ptr()); +} #ifndef PRODUCT void TypeNarrowOop::dump2( Dict & d, uint depth, outputStream *st ) const { @@ -4376,7 +4537,7 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const { PTR ptr = meet_ptr(tp->ptr()); switch (tp->ptr()) { case Null: - if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset); + if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); // else fall through: case TopPTR: case AnyNull: { @@ -4384,7 +4545,7 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const { } case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); default: typerr(t); } } @@ -4698,12 +4859,12 @@ const Type *TypeKlassPtr::xmeet( const Type *t ) const { case TopPTR: return this; case Null: - if( ptr == Null ) return TypePtr::make( AnyPtr, ptr, offset ); + if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); case AnyNull: return make( ptr, klass(), offset ); case BotPTR: case NotNull: - return TypePtr::make(AnyPtr, ptr, offset); + return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth()); default: typerr(t); } } diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index c587e145e33..071c12bf0b6 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -224,7 +224,7 @@ public: } // Variant that keeps the speculative part of the types const Type *meet_speculative(const Type *t) const { - return meet_helper(t, true); + return meet_helper(t, true)->cleanup_speculative(); } // WIDEN: 'widens' for Ints and other range types virtual const Type *widen( const Type *old, const Type* limit ) const { return this; } @@ -247,7 +247,7 @@ public: } // Variant that keeps the speculative part of the types const Type *join_speculative(const Type *t) const { - return join_helper(t, true); + return join_helper(t, true)->cleanup_speculative(); } // Modified version of JOIN adapted to the needs Node::Value. @@ -259,7 +259,7 @@ public: } // Variant that keeps the speculative part of the types const Type *filter_speculative(const Type *kills) const { - return filter_helper(kills, true); + return filter_helper(kills, true)->cleanup_speculative(); } #ifdef ASSERT @@ -414,15 +414,18 @@ public: bool require_constant = false, bool is_autobox_cache = false); - // Speculative type. See TypeInstPtr - virtual const TypeOopPtr* speculative() const { return NULL; } - virtual ciKlass* speculative_type() const { return NULL; } + // Speculative type helper methods. See TypePtr. + virtual const TypePtr* speculative() const { return NULL; } + virtual ciKlass* speculative_type() const { return NULL; } + virtual ciKlass* speculative_type_not_null() const { return NULL; } + virtual bool speculative_maybe_null() const { return true; } + virtual const Type* remove_speculative() const { return this; } + virtual const Type* cleanup_speculative() const { return this; } + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const { return exact_kls != NULL; } + virtual bool would_improve_ptr(bool maybe_null) const { return !maybe_null; } const Type* maybe_remove_speculative(bool include_speculative) const; - virtual const Type* remove_speculative() const { return this; } - virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const { - return exact_kls != NULL; - } + virtual bool maybe_null() const { return true; } private: // support arrays @@ -679,6 +682,7 @@ public: virtual const Type *xdual() const; // Compute dual right now. bool ary_must_be_exact() const; // true if arrays of such are never generic virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; #ifdef ASSERT // One type is interface, the other is oop virtual bool interface_vs_oop(const Type *t) const; @@ -761,13 +765,48 @@ class TypePtr : public Type { public: enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR }; protected: - TypePtr( TYPES t, PTR ptr, int offset ) : Type(t), _ptr(ptr), _offset(offset) {} - virtual bool eq( const Type *t ) const; - virtual int hash() const; // Type specific hashing + TypePtr(TYPES t, PTR ptr, int offset, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom) : + Type(t), _ptr(ptr), _offset(offset), _speculative(speculative), + _inline_depth(inline_depth) {} static const PTR ptr_meet[lastPTR][lastPTR]; static const PTR ptr_dual[lastPTR]; static const char * const ptr_msg[lastPTR]; + enum { + InlineDepthBottom = INT_MAX, + InlineDepthTop = -InlineDepthBottom + }; + + // Extra type information profiling gave us. We propagate it the + // same way the rest of the type info is propagated. If we want to + // use it, then we have to emit a guard: this part of the type is + // not something we know but something we speculate about the type. + const TypePtr* _speculative; + // For speculative types, we record at what inlining depth the + // profiling point that provided the data is. We want to favor + // profile data coming from outer scopes which are likely better for + // the current compilation. + int _inline_depth; + + // utility methods to work on the speculative part of the type + const TypePtr* dual_speculative() const; + const TypePtr* xmeet_speculative(const TypePtr* other) const; + bool eq_speculative(const TypePtr* other) const; + int hash_speculative() const; + const TypePtr* add_offset_speculative(intptr_t offset) const; +#ifndef PRODUCT + void dump_speculative(outputStream *st) const; +#endif + + // utility methods to work on the inline depth of the type + int dual_inline_depth() const; + int meet_inline_depth(int depth) const; +#ifndef PRODUCT + void dump_inline_depth(outputStream *st) const; +#endif + public: const int _offset; // Offset into oop, with TOP & BOT const PTR _ptr; // Pointer equivalence class @@ -775,7 +814,9 @@ public: const int offset() const { return _offset; } const PTR ptr() const { return _ptr; } - static const TypePtr *make( TYPES t, PTR ptr, int offset ); + static const TypePtr *make(TYPES t, PTR ptr, int offset, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -784,10 +825,13 @@ public: int xadd_offset( intptr_t offset ) const; virtual const TypePtr *add_offset( intptr_t offset ) const; + virtual bool eq(const Type *t) const; + virtual int hash() const; // Type specific hashing virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous virtual const Type *xmeet( const Type *t ) const; + virtual const Type *xmeet_helper( const Type *t ) const; int meet_offset( int offset ) const; int dual_offset( ) const; virtual const Type *xdual() const; // Compute dual right now. @@ -802,6 +846,20 @@ public: return ptr_dual[ ptr_meet[ ptr_dual[in_ptr] ] [ dual_ptr() ] ]; } + // Speculative type helper methods. + virtual const TypePtr* speculative() const { return _speculative; } + int inline_depth() const { return _inline_depth; } + virtual ciKlass* speculative_type() const; + virtual ciKlass* speculative_type_not_null() const; + virtual bool speculative_maybe_null() const; + virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; + virtual bool would_improve_ptr(bool maybe_null) const; + virtual const TypePtr* with_inline_depth(int depth) const; + + virtual bool maybe_null() const { return meet_ptr(Null) == ptr(); } + // Tests for relation to centerline of type lattice: static bool above_centerline(PTR ptr) { return (ptr <= AnyNull); } static bool below_centerline(PTR ptr) { return (ptr >= NotNull); } @@ -850,7 +908,8 @@ public: // Some kind of oop (Java pointer), either klass or instance or array. class TypeOopPtr : public TypePtr { protected: - TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth); + TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, + const TypePtr* speculative, int inline_depth); public: virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -861,10 +920,6 @@ public: }; protected: - enum { - InlineDepthBottom = INT_MAX, - InlineDepthTop = -InlineDepthBottom - }; // Oop is NULL, unless this is a constant oop. ciObject* _const_oop; // Constant oop // If _klass is NULL, then so is _sig. This is an unloaded klass. @@ -880,38 +935,11 @@ protected: // This is the the node index of the allocation node creating this instance. int _instance_id; - // Extra type information profiling gave us. We propagate it the - // same way the rest of the type info is propagated. If we want to - // use it, then we have to emit a guard: this part of the type is - // not something we know but something we speculate about the type. - const TypeOopPtr* _speculative; - // For speculative types, we record at what inlining depth the - // profiling point that provided the data is. We want to favor - // profile data coming from outer scopes which are likely better for - // the current compilation. - int _inline_depth; - static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact); int dual_instance_id() const; int meet_instance_id(int uid) const; - // utility methods to work on the speculative part of the type - const TypeOopPtr* dual_speculative() const; - const TypeOopPtr* xmeet_speculative(const TypeOopPtr* other) const; - bool eq_speculative(const TypeOopPtr* other) const; - int hash_speculative() const; - const TypeOopPtr* add_offset_speculative(intptr_t offset) const; -#ifndef PRODUCT - void dump_speculative(outputStream *st) const; -#endif - // utility methods to work on the inline depth of the type - int dual_inline_depth() const; - int meet_inline_depth(int depth) const; -#ifndef PRODUCT - void dump_inline_depth(outputStream *st) const; -#endif - // Do not allow interface-vs.-noninterface joins to collapse to top. virtual const Type *filter_helper(const Type *kills, bool include_speculative) const; @@ -941,7 +969,9 @@ public: bool not_null_elements = false); // Make a generic (unclassed) pointer to an oop. - static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom); + static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); ciObject* const_oop() const { return _const_oop; } virtual ciKlass* klass() const { return _klass; } @@ -955,7 +985,6 @@ public: bool is_known_instance() const { return _instance_id > 0; } int instance_id() const { return _instance_id; } bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; } - virtual const TypeOopPtr* speculative() const { return _speculative; } virtual intptr_t get_con() const; @@ -969,10 +998,13 @@ public: const TypeKlassPtr* as_klass_type() const; virtual const TypePtr *add_offset( intptr_t offset ) const; - // Return same type without a speculative part - virtual const Type* remove_speculative() const; - virtual const Type *xmeet(const Type *t) const; + // Speculative type helper methods. + virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; + virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; + virtual const Type *xdual() const; // Compute dual right now. // the core of the computation of the meet for TypeOopPtr and for its subclasses virtual const Type *xmeet_helper(const Type *t) const; @@ -982,29 +1014,14 @@ public: #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; #endif - - // Return the speculative type if any - ciKlass* speculative_type() const { - if (_speculative != NULL) { - const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr(); - if (speculative->klass_is_exact()) { - return speculative->klass(); - } - } - return NULL; - } - int inline_depth() const { - return _inline_depth; - } - virtual const TypeOopPtr* with_inline_depth(int depth) const; - virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const; }; //------------------------------TypeInstPtr------------------------------------ // Class of Java object pointers, pointing either to non-array Java instances // or to a Klass* (including array klasses). class TypeInstPtr : public TypeOopPtr { - TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth); + TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, + const TypePtr* speculative, int inline_depth); virtual bool eq( const Type *t ) const; virtual int hash() const; // Type specific hashing @@ -1040,7 +1057,10 @@ class TypeInstPtr : public TypeOopPtr { } // Make a pointer to an oop. - static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom); + static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, + int instance_id = InstanceBot, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); /** Create constant type for a constant boxed value */ const Type* get_const_boxed_value() const; @@ -1057,9 +1077,10 @@ class TypeInstPtr : public TypeOopPtr { virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const; virtual const TypePtr *add_offset( intptr_t offset ) const; - // Return same type without a speculative part + + // Speculative type helper methods. virtual const Type* remove_speculative() const; - virtual const TypeOopPtr* with_inline_depth(int depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; @@ -1081,7 +1102,8 @@ class TypeInstPtr : public TypeOopPtr { // Class of Java array pointers class TypeAryPtr : public TypeOopPtr { TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, - int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative, int inline_depth) + int offset, int instance_id, bool is_autobox_cache, + const TypePtr* speculative, int inline_depth) : TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth), _ary(ary), _is_autobox_cache(is_autobox_cache) @@ -1120,9 +1142,15 @@ public: bool is_autobox_cache() const { return _is_autobox_cache; } - static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom); + static const TypeAryPtr *make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id = InstanceBot, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom); // Constant pointer to array - static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom, bool is_autobox_cache= false); + static const TypeAryPtr *make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, + int instance_id = InstanceBot, + const TypePtr* speculative = NULL, + int inline_depth = InlineDepthBottom, bool is_autobox_cache = false); // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; @@ -1136,9 +1164,10 @@ public: virtual bool empty(void) const; // TRUE if type is vacuous virtual const TypePtr *add_offset( intptr_t offset ) const; - // Return same type without a speculative part + + // Speculative type helper methods. virtual const Type* remove_speculative() const; - virtual const TypeOopPtr* with_inline_depth(int depth) const; + virtual const TypePtr* with_inline_depth(int depth) const; // the core of the computation of the meet of 2 types virtual const Type *xmeet_helper(const Type *t) const; @@ -1367,9 +1396,8 @@ public: static const TypeNarrowOop *BOTTOM; static const TypeNarrowOop *NULL_PTR; - virtual const Type* remove_speculative() const { - return make(_ptrtype->remove_speculative()->is_ptr()); - } + virtual const Type* remove_speculative() const; + virtual const Type* cleanup_speculative() const; #ifndef PRODUCT virtual void dump2( Dict &d, uint depth, outputStream *st ) const; diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index ac3a0f1d276..f642754c253 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3801,10 +3801,6 @@ jint Arguments::apply_ergo() { AlwaysIncrementalInline = false; } #endif - if (IncrementalInline && FLAG_IS_DEFAULT(MaxNodeLimit)) { - // incremental inlining: bump MaxNodeLimit - FLAG_SET_DEFAULT(MaxNodeLimit, (intx)75000); - } if (!UseTypeSpeculation && FLAG_IS_DEFAULT(TypeProfileLevel)) { // nothing to use the profiling, turn if off FLAG_SET_DEFAULT(TypeProfileLevel, 0); diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index ea4f1f1220f..8e3b14c1671 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1839,6 +1839,7 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = { "predicate", "loop_limit_check", "speculate_class_check", + "speculate_null_check", "rtm_state_change" }; const char* Deoptimization::_trap_action_name[Action_LIMIT] = { diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index f896a70341a..eb8e2cbdede 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -60,6 +60,7 @@ class Deoptimization : AllStatic { Reason_predicate, // compiler generated predicate failed Reason_loop_limit_check, // compiler generated loop limits check failed Reason_speculate_class_check, // saw unexpected object class from type speculation + Reason_speculate_null_check, // saw unexpected null from type speculation Reason_rtm_state_change, // rtm state change detected Reason_LIMIT, // Note: Keep this enum in sync. with _trap_reason_name. @@ -315,17 +316,27 @@ class Deoptimization : AllStatic { return Reason_null_check; // recorded per BCI as a null check else if (reason == Reason_speculate_class_check) return Reason_class_check; + else if (reason == Reason_speculate_null_check) + return Reason_null_check; else return Reason_none; } static bool reason_is_speculate(int reason) { - if (reason == Reason_speculate_class_check) { + if (reason == Reason_speculate_class_check || reason == Reason_speculate_null_check) { return true; } return false; } + static DeoptReason reason_null_check(bool speculative) { + return speculative ? Deoptimization::Reason_speculate_null_check : Deoptimization::Reason_null_check; + } + + static DeoptReason reason_class_check(bool speculative) { + return speculative ? Deoptimization::Reason_speculate_class_check : Deoptimization::Reason_class_check; + } + static uint per_method_trap_limit(int reason) { return reason_is_speculate(reason) ? (uint)PerMethodSpecTrapLimit : (uint)PerMethodTrapLimit; } From b21d142f016360986212a941659115c0c96a3426 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 31 Mar 2014 10:35:06 +0200 Subject: [PATCH 091/170] 8037970: make PrintMethodData a diagnostic options Make PrintMethodData a diagnostic options for performance investigation Reviewed-by: kvn, iveresov --- .../share/vm/classfile/classLoaderData.cpp | 14 +++ .../share/vm/classfile/classLoaderData.hpp | 2 + .../share/vm/interpreter/bytecodeTracer.cpp | 3 - .../share/vm/interpreter/bytecodeTracer.hpp | 5 +- hotspot/src/share/vm/oops/method.cpp | 13 +-- hotspot/src/share/vm/oops/method.hpp | 9 +- hotspot/src/share/vm/oops/methodData.cpp | 29 ----- hotspot/src/share/vm/oops/methodData.hpp | 40 ------- hotspot/src/share/vm/runtime/globals.hpp | 2 +- hotspot/src/share/vm/runtime/java.cpp | 108 +++++++++--------- 10 files changed, 83 insertions(+), 142 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 269007adcab..efd141332dc 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -135,6 +135,14 @@ void ClassLoaderData::classes_do(void f(Klass * const)) { } } +void ClassLoaderData::methods_do(void f(Method*)) { + for (Klass* k = _klasses; k != NULL; k = k->next_link()) { + if (k->oop_is_instance()) { + InstanceKlass::cast(k)->methods_do(f); + } + } +} + void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { // Lock to avoid classes being modified/added/removed during iteration MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); @@ -624,6 +632,12 @@ void ClassLoaderDataGraph::classes_do(void f(Klass* const)) { } } +void ClassLoaderDataGraph::methods_do(void f(Method*)) { + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->methods_do(f); + } +} + void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->loaded_classes_do(klass_closure); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index de29726d844..e03d1625045 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -78,6 +78,7 @@ class ClassLoaderDataGraph : public AllStatic { static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim); static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); + static void methods_do(void f(Method*)); static void loaded_classes_do(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(BoolObjectClosure* is_alive); @@ -189,6 +190,7 @@ class ClassLoaderData : public CHeapObj { void classes_do(void f(Klass*)); void loaded_classes_do(KlassClosure* klass_closure); void classes_do(void f(InstanceKlass*)); + void methods_do(void f(Method*)); // Deallocate free list during class unloading. void free_deallocate_list(); diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp index 1892940f216..36867113eff 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp @@ -35,8 +35,6 @@ #include "runtime/timer.hpp" -#ifndef PRODUCT - // Standard closure for BytecodeTracer: prints the current bytecode // and its attributes using bytecode-specific information. @@ -600,4 +598,3 @@ void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) { } } } -#endif // PRODUCT diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp index 5dc78e0ac1a..9e5837139a2 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.hpp @@ -34,8 +34,7 @@ // By specialising the BytecodeClosure, all kinds of bytecode traces can // be done. -#ifndef PRODUCT -// class BytecodeTracer is only used by TraceBytecodes option +// class BytecodeTracer is used by TraceBytecodes option and PrintMethodData class BytecodeClosure; class BytecodeTracer: AllStatic { @@ -60,6 +59,4 @@ class BytecodeClosure { virtual void trace(methodHandle method, address bcp, outputStream* st) = 0; }; -#endif // !PRODUCT - #endif // SHARE_VM_INTERPRETER_BYTECODETRACER_HPP diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index d97a626ebf4..53890e6db13 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -329,14 +329,12 @@ bool Method::was_executed_more_than(int n) { } } -#ifndef PRODUCT void Method::print_invocation_count() { if (is_static()) tty->print("static "); if (is_final()) tty->print("final "); if (is_synchronized()) tty->print("synchronized "); if (is_native()) tty->print("native "); - method_holder()->name()->print_symbol_on(tty); - tty->print("."); + tty->print("%s::", method_holder()->external_name()); name()->print_symbol_on(tty); signature()->print_symbol_on(tty); @@ -349,12 +347,12 @@ void Method::print_invocation_count() { tty->print_cr (" interpreter_invocation_count: %8d ", interpreter_invocation_count()); tty->print_cr (" invocation_counter: %8d ", invocation_count()); tty->print_cr (" backedge_counter: %8d ", backedge_count()); +#ifndef PRODUCT if (CountCompiledCalls) { tty->print_cr (" compiled_invocation_count: %8d ", compiled_invocation_count()); } - -} #endif +} // Build a MethodData* object to hold information about this method // collected in the interpreter. @@ -1443,10 +1441,6 @@ void Method::print_name(outputStream* st) { #endif // !PRODUCT || INCLUDE_JVMTI -//----------------------------------------------------------------------------------- -// Non-product code - -#ifndef PRODUCT void Method::print_codes_on(outputStream* st) const { print_codes_on(0, code_size(), st); } @@ -1460,7 +1454,6 @@ void Method::print_codes_on(int from, int to, outputStream* st) const { BytecodeTracer::set_closure(BytecodeTracer::std_closure()); while (s.next() >= 0) BytecodeTracer::trace(mh, s.bcp(), st); } -#endif // not PRODUCT // Simple compression of line number tables. We use a regular compressed stream, except that we compress deltas diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 98598dbeeff..91c8be25b27 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -429,6 +429,9 @@ class Method : public Metadata { #ifndef PRODUCT int compiled_invocation_count() const { return _compiled_invocation_count; } void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; } +#else + // for PrintMethodData in a product build + int compiled_invocation_count() const { return 0; } #endif // not PRODUCT // Clear (non-shared space) pointers which could not be relevant @@ -497,10 +500,8 @@ class Method : public Metadata { // Interpreter oopmap support void mask_for(int bci, InterpreterOopMap* mask); -#ifndef PRODUCT // operations on invocation counter void print_invocation_count(); -#endif // byte codes void set_code(address code) { return constMethod()->set_code(code); } @@ -509,8 +510,8 @@ class Method : public Metadata { // prints byte codes void print_codes() const { print_codes_on(tty); } - void print_codes_on(outputStream* st) const PRODUCT_RETURN; - void print_codes_on(int from, int to, outputStream* st) const PRODUCT_RETURN; + void print_codes_on(outputStream* st) const; + void print_codes_on(int from, int to, outputStream* st) const; // method parameters bool has_method_parameters() const diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index a0d55ecfd79..17d80ca5a9f 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -115,7 +115,6 @@ void ProfileData::print_data_on(outputStream* st, const MethodData* md) const { print_data_on(st, print_data_on_helper(md)); } -#ifndef PRODUCT void ProfileData::print_shared(outputStream* st, const char* name, const char* extra) const { st->print("bci: %d", bci()); st->fill_to(tab_width_one); @@ -138,7 +137,6 @@ void ProfileData::print_shared(outputStream* st, const char* name, const char* e void ProfileData::tab(outputStream* st, bool first) const { st->fill_to(first ? tab_width_one : tab_width_two); } -#endif // !PRODUCT // ================================================================== // BitData @@ -147,23 +145,19 @@ void ProfileData::tab(outputStream* st, bool first) const { // whether a checkcast bytecode has seen a null value. -#ifndef PRODUCT void BitData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "BitData", extra); } -#endif // !PRODUCT // ================================================================== // CounterData // // A CounterData corresponds to a simple counter. -#ifndef PRODUCT void CounterData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "CounterData", extra); st->print_cr("count(%u)", count()); } -#endif // !PRODUCT // ================================================================== // JumpData @@ -188,12 +182,10 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) { set_displacement(offset); } -#ifndef PRODUCT void JumpData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "JumpData", extra); st->print_cr("taken(%u) displacement(%d)", taken(), displacement()); } -#endif // !PRODUCT int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) { // Parameter profiling include the receiver @@ -342,7 +334,6 @@ bool TypeEntriesAtCall::arguments_profiling_enabled() { return MethodData::profile_arguments(); } -#ifndef PRODUCT void TypeEntries::print_klass(outputStream* st, intptr_t k) { if (is_type_none(k)) { st->print("none"); @@ -398,7 +389,6 @@ void VirtualCallTypeData::print_data_on(outputStream* st, const char* extra) con _ret.print_data_on(st); } } -#endif // ================================================================== // ReceiverTypeData @@ -417,7 +407,6 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { } } -#ifndef PRODUCT void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; @@ -447,7 +436,6 @@ void VirtualCallData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "VirtualCallData", extra); print_receiver_data_on(st); } -#endif // !PRODUCT // ================================================================== // RetData @@ -499,7 +487,6 @@ DataLayout* RetData::advance(MethodData *md, int bci) { } #endif // CC_INTERP -#ifndef PRODUCT void RetData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "RetData", extra); uint row; @@ -516,7 +503,6 @@ void RetData::print_data_on(outputStream* st, const char* extra) const { } } } -#endif // !PRODUCT // ================================================================== // BranchData @@ -534,7 +520,6 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) { set_displacement(offset); } -#ifndef PRODUCT void BranchData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "BranchData", extra); st->print_cr("taken(%u) displacement(%d)", @@ -542,7 +527,6 @@ void BranchData::print_data_on(outputStream* st, const char* extra) const { tab(st); st->print_cr("not taken(%u)", not_taken()); } -#endif // ================================================================== // MultiBranchData @@ -608,7 +592,6 @@ void MultiBranchData::post_initialize(BytecodeStream* stream, } } -#ifndef PRODUCT void MultiBranchData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "MultiBranchData", extra); st->print_cr("default_count(%u) displacement(%d)", @@ -620,9 +603,7 @@ void MultiBranchData::print_data_on(outputStream* st, const char* extra) const { count_at(i), displacement_at(i)); } } -#endif -#ifndef PRODUCT void ArgInfoData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "ArgInfoData", extra); int nargs = number_of_args(); @@ -632,8 +613,6 @@ void ArgInfoData::print_data_on(outputStream* st, const char* extra) const { st->cr(); } -#endif - int ParametersTypeData::compute_cell_count(Method* m) { if (!MethodData::profile_parameters_for_method(m)) { return 0; @@ -654,7 +633,6 @@ bool ParametersTypeData::profiling_enabled() { return MethodData::profile_parameters(); } -#ifndef PRODUCT void ParametersTypeData::print_data_on(outputStream* st, const char* extra) const { st->print("parameter types", extra); _parameters.print_data_on(st); @@ -666,7 +644,6 @@ void SpeculativeTrapData::print_data_on(outputStream* st, const char* extra) con method()->print_short_name(st); st->cr(); } -#endif // ================================================================== // MethodData* @@ -1359,8 +1336,6 @@ ArgInfoData *MethodData::arg_info() { // Printing -#ifndef PRODUCT - void MethodData::print_on(outputStream* st) const { assert(is_methodData(), "should be method data"); st->print("method data for "); @@ -1369,15 +1344,12 @@ void MethodData::print_on(outputStream* st) const { print_data_on(st); } -#endif //PRODUCT - void MethodData::print_value_on(outputStream* st) const { assert(is_methodData(), "should be method data"); st->print("method data for "); method()->print_value_on(st); } -#ifndef PRODUCT void MethodData::print_data_on(outputStream* st) const { ResourceMark rm; ProfileData* data = first_data(); @@ -1418,7 +1390,6 @@ void MethodData::print_data_on(outputStream* st) const { if (dp >= end) return; } } -#endif #if INCLUDE_SERVICES // Size Statistics diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index 32443db79ac..66a1d1fa719 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -280,12 +280,10 @@ class ProfileData : public ResourceObj { friend class ReturnTypeEntry; friend class TypeStackSlotEntries; private: -#ifndef PRODUCT enum { tab_width_one = 16, tab_width_two = 36 }; -#endif // !PRODUCT // This is a pointer to a section of profiling data. DataLayout* _data; @@ -521,10 +519,8 @@ public: void print_data_on(outputStream* st, const MethodData* md) const; -#ifndef PRODUCT void print_shared(outputStream* st, const char* name, const char* extra) const; void tab(outputStream* st, bool first = false) const; -#endif }; // BitData @@ -583,9 +579,7 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // CounterData @@ -646,9 +640,7 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // JumpData @@ -733,9 +725,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // Entries in a ProfileData object to record types: it can either be @@ -808,9 +798,7 @@ public: return with_status((intptr_t)k, in); } -#ifndef PRODUCT static void print_klass(outputStream* st, intptr_t k); -#endif // GC support static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p); @@ -919,9 +907,7 @@ public: // GC support void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); -#ifndef PRODUCT void print_data_on(outputStream* st) const; -#endif }; // Type entry used for return from a call. A single cell to record the @@ -964,9 +950,7 @@ public: // GC support void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); -#ifndef PRODUCT void print_data_on(outputStream* st) const; -#endif }; // Entries to collect type information at a call: contains arguments @@ -1144,9 +1128,7 @@ public: } } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // ReceiverTypeData @@ -1288,10 +1270,8 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_receiver_data_on(outputStream* st) const; void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // VirtualCallData @@ -1332,9 +1312,7 @@ public: } #endif // CC_INTERP -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // VirtualCallTypeData @@ -1458,9 +1436,7 @@ public: } } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // RetData @@ -1561,9 +1537,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // BranchData @@ -1639,9 +1613,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // ArrayData @@ -1832,9 +1804,7 @@ public: // Specific initialization. void post_initialize(BytecodeStream* stream, MethodData* mdo); -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; class ArgInfoData : public ArrayData { @@ -1859,9 +1829,7 @@ public: array_set_int_at(arg, val); } -#ifndef PRODUCT void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // ParametersTypeData @@ -1920,9 +1888,7 @@ public: _parameters.clean_weak_klass_links(is_alive_closure); } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif static ByteSize stack_slot_offset(int i) { return cell_offset(stack_slot_local_offset(i)); @@ -1976,9 +1942,7 @@ public: set_intptr_at(method_offset, (intptr_t)m); } -#ifndef PRODUCT virtual void print_data_on(outputStream* st, const char* extra = NULL) const; -#endif }; // MethodData* @@ -2457,15 +2421,11 @@ public: void set_size(int object_size_in_bytes) { _size = object_size_in_bytes; } // Printing -#ifndef PRODUCT void print_on (outputStream* st) const; -#endif void print_value_on(outputStream* st) const; -#ifndef PRODUCT // printing support for method data void print_data_on(outputStream* st) const; -#endif const char* internal_name() const { return "{method data}"; } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index d2de68b1103..dec779c97c7 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2832,7 +2832,7 @@ class CommandLineFlags { "number of method invocations/branches (expressed as % of " \ "CompileThreshold) before using the method's profile") \ \ - develop(bool, PrintMethodData, false, \ + diagnostic(bool, PrintMethodData, false, \ "Print the results of +ProfileInterpreter at end of run") \ \ develop(bool, VerifyDataPointer, trueInDebug, \ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index b467587c834..231f3fe7249 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -98,21 +98,14 @@ #endif -#ifndef PRODUCT - -// Statistics printing (method invocation histogram) - -GrowableArray* collected_invoked_methods; - -void collect_invoked_methods(Method* m) { - if (m->invocation_count() + m->compiled_invocation_count() >= 1 ) { - collected_invoked_methods->push(m); - } -} - - GrowableArray* collected_profiled_methods; +int compare_methods(Method** a, Method** b) { + // %%% there can be 32-bit overflow here + return ((*b)->invocation_count() + (*b)->compiled_invocation_count()) + - ((*a)->invocation_count() + (*a)->compiled_invocation_count()); +} + void collect_profiled_methods(Method* m) { Thread* thread = Thread::current(); // This HandleMark prevents a huge amount of handles from being added @@ -125,14 +118,54 @@ void collect_profiled_methods(Method* m) { } } +void print_method_profiling_data() { + if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) { + ResourceMark rm; + HandleMark hm; + collected_profiled_methods = new GrowableArray(1024); + ClassLoaderDataGraph::methods_do(collect_profiled_methods); + collected_profiled_methods->sort(&compare_methods); -int compare_methods(Method** a, Method** b) { - // %%% there can be 32-bit overflow here - return ((*b)->invocation_count() + (*b)->compiled_invocation_count()) - - ((*a)->invocation_count() + (*a)->compiled_invocation_count()); + int count = collected_profiled_methods->length(); + int total_size = 0; + if (count > 0) { + for (int index = 0; index < count; index++) { + Method* m = collected_profiled_methods->at(index); + ttyLocker ttyl; + tty->print_cr("------------------------------------------------------------------------"); + m->print_invocation_count(); + tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); + tty->cr(); + // Dump data on parameters if any + if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { + tty->fill_to(2); + m->method_data()->parameters_type_data()->print_data_on(tty); + } + m->print_codes(); + total_size += m->method_data()->size_in_bytes(); + } + tty->print_cr("------------------------------------------------------------------------"); + tty->print_cr("Total MDO size: %d bytes", total_size); + } + } } +#ifndef PRODUCT + +// Statistics printing (method invocation histogram) + +GrowableArray* collected_invoked_methods; + +void collect_invoked_methods(Method* m) { + if (m->invocation_count() + m->compiled_invocation_count() >= 1 ) { + collected_invoked_methods->push(m); + } +} + + + + void print_method_invocation_histogram() { ResourceMark rm; HandleMark hm; @@ -173,37 +206,6 @@ void print_method_invocation_histogram() { SharedRuntime::print_call_statistics(comp_total); } -void print_method_profiling_data() { - ResourceMark rm; - HandleMark hm; - collected_profiled_methods = new GrowableArray(1024); - SystemDictionary::methods_do(collect_profiled_methods); - collected_profiled_methods->sort(&compare_methods); - - int count = collected_profiled_methods->length(); - int total_size = 0; - if (count > 0) { - for (int index = 0; index < count; index++) { - Method* m = collected_profiled_methods->at(index); - ttyLocker ttyl; - tty->print_cr("------------------------------------------------------------------------"); - //m->print_name(tty); - m->print_invocation_count(); - tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes()); - tty->cr(); - // Dump data on parameters if any - if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) { - tty->fill_to(2); - m->method_data()->parameters_type_data()->print_data_on(tty); - } - m->print_codes(); - total_size += m->method_data()->size_in_bytes(); - } - tty->print_cr("------------------------------------------------------------------------"); - tty->print_cr("Total MDO size: %d bytes", total_size); - } -} - void print_bytecode_count() { if (CountBytecodes || TraceBytecodes || StopInterpreterAt) { tty->print_cr("[BytecodeCounter::counter_value = %d]", BytecodeCounter::counter_value()); @@ -281,9 +283,9 @@ void print_statistics() { if (CountCompiledCalls) { print_method_invocation_histogram(); } - if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) { - print_method_profiling_data(); - } + + print_method_profiling_data(); + if (TimeCompiler) { COMPILER2_PRESENT(Compile::print_timers();) } @@ -373,6 +375,10 @@ void print_statistics() { void print_statistics() { + if (PrintMethodData) { + print_method_profiling_data(); + } + if (CITime) { CompileBroker::print_times(); } From 5f57e465a6c2b01d674f4fa14aa260fa65085d79 Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Mon, 31 Mar 2014 10:43:20 +0200 Subject: [PATCH 092/170] 8036030: Update JAX-WS RI integration to latest version JAX-WS RI upgrade from 2.2.9-b130926.1035 to 2.2.10-b140228.1436; Reviewed-by: chegar --- .../sun/codemodel/internal/JDefinedClass.java | 19 +- .../internal/util/EncoderFactory.java | 30 +- .../internal/util/MS1252Encoder.java | 223 ----- .../internal/util/SingleByteEncoder.java | 159 ---- .../codemodel/internal/util/Surrogate.java | 355 ------- .../writer/OutputStreamCodeWriter.java | 73 ++ .../internal/jxc/MessageBundle.properties | 6 +- .../internal/jxc/MessageBundle_de.properties | 6 +- .../internal/jxc/MessageBundle_es.properties | 6 +- .../internal/jxc/MessageBundle_fr.properties | 6 +- .../internal/jxc/MessageBundle_it.properties | 6 +- .../internal/jxc/MessageBundle_ja.properties | 6 +- .../internal/jxc/MessageBundle_ko.properties | 6 +- .../jxc/MessageBundle_pt_BR.properties | 6 +- .../jxc/MessageBundle_zh_CN.properties | 6 +- .../jxc/MessageBundle_zh_TW.properties | 6 +- .../modeler/annotation/WebServiceVisitor.java | 9 +- .../sun/tools/internal/ws/version.properties | 10 +- .../internal/xjc/MessageBundle.properties | 12 +- .../internal/xjc/MessageBundle_de.properties | 12 +- .../internal/xjc/MessageBundle_es.properties | 12 +- .../internal/xjc/MessageBundle_fr.properties | 12 +- .../internal/xjc/MessageBundle_it.properties | 12 +- .../internal/xjc/MessageBundle_ja.properties | 12 +- .../internal/xjc/MessageBundle_ko.properties | 12 +- .../xjc/MessageBundle_pt_BR.properties | 12 +- .../xjc/MessageBundle_zh_CN.properties | 12 +- .../xjc/MessageBundle_zh_TW.properties | 12 +- .../reader/xmlschema/bindinfo/BIProperty.java | 15 +- .../impl/RuntimeBuiltinLeafInfoImpl.java | 17 +- .../internal/bind/v2/model/nav/Navigator.java | 6 +- .../v2/model/nav/ReflectionNavigator.java | 4 +- .../property/SingleMapNodeProperty.java | 63 +- .../bind/v2/schemagen/XmlSchemaGenerator.java | 26 +- .../messaging/saaj/LazyEnvelopeSource.java | 50 + .../saaj/client/p2p/HttpSOAPConnection.java | 5 +- .../packaging/mime/MessagingException.java | 4 +- .../mime/internet/BMMimeMultipart.java | 31 +- .../packaging/mime/internet/MimeBodyPart.java | 16 +- .../mime/internet/MimeMultipart.java | 8 +- .../mime/internet/MimePullMultipart.java | 4 +- .../packaging/mime/util/ASCIIUtility.java | 7 +- .../saaj/soap/AttachmentPartImpl.java | 16 +- .../messaging/saaj/soap/Envelope.java | 7 +- .../messaging/saaj/soap/EnvelopeFactory.java | 81 +- .../messaging/saaj/soap/LazyEnvelope.java | 61 ++ .../saaj/soap/MessageFactoryImpl.java | 35 +- .../messaging/saaj/soap/MessageImpl.java | 72 +- .../messaging/saaj/soap/SOAPDocumentImpl.java | 6 +- .../messaging/saaj/soap/SOAPPartImpl.java | 20 +- .../messaging/saaj/soap/StaxBridge.java | 67 ++ .../saaj/soap/StaxLazySourceBridge.java | 105 ++ .../messaging/saaj/soap/StaxReaderBridge.java | 78 ++ .../messaging/saaj/soap/impl/BodyImpl.java | 150 ++- .../messaging/saaj/soap/impl/ElementImpl.java | 29 +- .../saaj/soap/impl/EnvelopeImpl.java | 98 +- .../messaging/saaj/soap/impl/FaultImpl.java | 10 +- .../messaging/saaj/soap/impl/HeaderImpl.java | 3 +- ...{CommentImpl.java => SOAPCommentImpl.java} | 6 +- .../impl/{TextImpl.java => SOAPTextImpl.java} | 6 +- .../saaj/soap/ver1_1/Message1_1Impl.java | 8 +- .../saaj/soap/ver1_1/SOAPPart1_1Impl.java | 7 +- .../saaj/soap/ver1_2/Fault1_2Impl.java | 6 +- .../saaj/soap/ver1_2/Message1_2Impl.java | 8 +- .../saaj/soap/ver1_2/SOAPPart1_2Impl.java | 7 +- .../messaging/saaj/util/JAXMStreamSource.java | 14 +- .../messaging/saaj/util/ParserPool.java | 14 +- .../util/stax/LazyEnvelopeStaxReader.java | 359 +++++++ .../mimepull/CleanUpExecutorFactory.java | 6 +- .../org/jvnet/mimepull/WeakDataFile.java | 55 +- .../internal/org/jvnet/staxex/Base64Data.java | 15 +- .../internal/org/jvnet/staxex/BinaryText.java | 40 + .../org/jvnet/staxex/MtomEnabled.java | 39 + .../org/jvnet/staxex/StAxSOAPBody.java | 81 ++ .../jvnet/staxex/StreamingDataHandler.java | 11 +- .../jvnet/staxex/util/DOMStreamReader.java | 895 ++++++++++++++++++ .../org/jvnet/staxex/util/DummyLocation.java | 55 ++ .../org/jvnet/staxex/util/FinalArrayList.java | 46 + .../jvnet/staxex/util/MtomStreamWriter.java | 42 + .../jvnet/staxex/util/SaajStaxReaderEx.java | 153 +++ .../org/jvnet/staxex/util/SaajStaxWriter.java | 330 +++++++ .../jvnet/staxex/util/SaajStaxWriterEx.java | 244 +++++ .../XMLStreamReaderToXMLStreamWriter.java | 297 ++++++ .../ws/addressing/EPRSDDocumentFilter.java | 4 +- .../api/addressing/WSEndpointReference.java | 4 +- .../ws/api/message/FilterMessageImpl.java | 4 +- .../xml/internal/ws/api/message/Message.java | 30 +- .../ws/api/message/MessageWrapper.java | 11 +- .../xml/internal/ws/api/message/Packet.java | 45 +- .../ws/api/message/StreamingSOAP.java | 11 +- .../ws/api/message/saaj/SAAJFactory.java | 5 +- .../ws/api/message/saaj/SaajStaxWriter.java | 4 +- .../xml/internal/ws/client/sei/SEIStub.java | 6 +- .../ws/developer/StreamingDataHandler.java | 13 +- .../internal/ws/encoding/ContentTypeImpl.java | 3 +- .../xml/internal/ws/encoding/MimeCodec.java | 4 +- .../xml/internal/ws/encoding/MtomCodec.java | 16 +- .../internal/ws/encoding/xml/XMLMessage.java | 9 +- .../ws/message/AbstractMessageImpl.java | 16 +- .../xml/internal/ws/message/DOMMessage.java | 5 +- .../internal/ws/message/EmptyMessageImpl.java | 5 +- .../ws/message/jaxb/JAXBDispatchMessage.java | 7 +- .../internal/ws/message/jaxb/JAXBMessage.java | 38 +- .../internal/ws/message/saaj/SAAJMessage.java | 9 +- .../message/source/ProtocolSourceMessage.java | 4 +- .../stream/PayloadStreamReaderMessage.java | 4 +- .../ws/message/stream/StreamMessage.java | 48 +- .../xml/internal/ws/policy/PolicyMapUtil.java | 17 +- .../privateutil/Localization.properties | 3 +- .../privateutil/LocalizationMessages.java | 14 +- .../ws/policy/privateutil/PolicyUtils.java | 9 +- .../internal/ws/server/EndpointFactory.java | 292 ++++-- .../internal/ws/server/SDDocumentImpl.java | 4 +- .../ws/server/ServiceDefinitionImpl.java | 19 +- .../internal/ws/server/WSDLGenResolver.java | 8 +- .../xml/internal/ws/spi/db/FieldGetter.java | 46 +- .../xml/internal/ws/spi/db/FieldSetter.java | 38 +- .../ws/spi/db/JAXBWrapperAccessor.java | 154 ++- .../xml/internal/ws/spi/db/MethodGetter.java | 48 +- .../xml/internal/ws/spi/db/MethodSetter.java | 41 +- .../ws/spi/db/PropertyGetterBase.java | 13 +- .../ws/spi/db/PropertySetterBase.java | 21 +- .../ws/streaming/MtomStreamWriter.java | 5 +- .../ws/transport/http/HttpAdapter.java | 215 ++++- .../http/client/HttpTransportPipe.java | 11 +- .../xml/internal/ws/util/version.properties | 10 +- .../xml/XMLStreamReaderToXMLStreamWriter.java | 4 +- .../internal/ws/wsdl/writer/WSDLPatcher.java | 4 +- .../javax/xml/bind/JAXBException.java | 6 +- .../xml/bind/TypeConstraintException.java | 7 +- 130 files changed, 4760 insertions(+), 1430 deletions(-) delete mode 100644 jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java delete mode 100644 jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java delete mode 100644 jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java rename jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/{CommentImpl.java => SOAPCommentImpl.java} (95%) rename jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/{TextImpl.java => SOAPTextImpl.java} (94%) create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java create mode 100644 jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java index faf99d0a4d4..d0b234864d1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java +++ b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/JDefinedClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -71,6 +71,9 @@ public class JDefinedClass /** Static initializer, if this class has one */ private JBlock init = null; + /** Instance initializer, if this class has one */ + private JBlock instanceInit = null; + /** class javadoc */ private JDocComment jdoc = null; @@ -517,6 +520,18 @@ public class JDefinedClass return init; } + /** + * Creates, if necessary, and returns the instance initializer + * for this class. + * + * @return JBlock containing initialization statements for this class + */ + public JBlock instanceInit() { + if (instanceInit == null) + instanceInit = new JBlock(); + return instanceInit; + } + /** * Adds a constructor to this class. * @@ -793,6 +808,8 @@ public class JDefinedClass f.d(field); if (init != null) f.nl().p("static").s(init); + if (instanceInit != null) + f.nl().s(instanceInit); for (JMethod m : constructors) { f.nl().d(m); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java index 15905039cc8..f11c4e376d6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/EncoderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -28,46 +28,20 @@ */ package com.sun.codemodel.internal.util; -import java.lang.reflect.Constructor; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; /** * Creates {@link CharsetEncoder} from a charset name. * - * Fixes a MS1252 handling bug in JDK1.4.2. - * * @author * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) */ public class EncoderFactory { - public static CharsetEncoder createEncoder( String encodin ) { + public static CharsetEncoder createEncoder( String encodin ) { Charset cs = Charset.forName(System.getProperty("file.encoding")); CharsetEncoder encoder = cs.newEncoder(); - - if( cs.getClass().getName().equals("sun.nio.cs.MS1252") ) { - try { - // at least JDK1.4.2_01 has a bug in MS1252 encoder. - // specifically, it returns true for any character. - // return a correct encoder to workaround this problem - - // statically binding to MS1252Encoder will cause a Link error - // (at least in IBM JDK1.4.1) - @SuppressWarnings("unchecked") - Class ms1252encoder = (Class) Class.forName("com.sun.codemodel.internal.util.MS1252Encoder"); - Constructor c = ms1252encoder.getConstructor(new Class[]{ - Charset.class - }); - return c.newInstance(new Object[]{cs}); - } catch( Throwable t ) { - // if something funny happens, ignore it and fall back to - // a broken MS1252 encoder. It's probably still better - // than choking here. - return encoder; - } - } - return encoder; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java deleted file mode 100644 index 709dee31ac5..00000000000 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/MS1252Encoder.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 1997, 2012, 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. - */ - -/* - * @(#)$Id: MS1252Encoder.java,v 1.2 2005/09/10 19:07:33 kohsuke Exp $ - */ -package com.sun.codemodel.internal.util; - -import java.nio.charset.Charset; - -/** - * MS1252 encoder that corrects a bug in JDK1.4.2_01. - * - *

- * See - * http://www.microsoft.com/globaldev/reference/sbcs/1252.htm - * for the normative definition. - * - * This code depends on Sun internal package, so we have to make sure - * it won't be executed on other JDKs. - */ -public final class MS1252Encoder extends SingleByteEncoder { - - public MS1252Encoder(Charset cs) { - super(cs, index1, index2, 0xFF00, 0x00FF, 8); - } - - private final static String index2 = - "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" + - "\b\t\n\u000B\f\r\u000E\u000F" + - "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" + - "\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" + - "\u0020\u0021\"\u0023\u0024\u0025\u0026\'" + - "\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F" + - "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037" + - "\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F" + - "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047" + - "\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F" + - "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057" + - "\u0058\u0059\u005A\u005B\\\u005D\u005E\u005F" + - "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067" + - "\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F" + - "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077" + - "\u0078\u0079\u007A\u007B\u007C\u007D\u007E\u007F" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u00A0\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7" + - "\u00A8\u00A9\u00AA\u00AB\u00AC\u00AD\u00AE\u00AF" + - "\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6\u00B7" + - "\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF" + - "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7" + - "\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF" + - "\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7" + - "\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF" + - "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7" + - "\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF" + - "\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7" + - "\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u008C\u009C\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u008A\u009A\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u009F\u0000\u0000\u0000\u0000\u008E\u009E\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0083\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0088\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0098\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0096\u0097\u0000" + - "\u0000\u0000\u0091\u0092\u0082\u0000\u0093\u0094" + - "\u0084\u0000\u0086\u0087\u0095\u0000\u0000\u0000" + - "\u0085\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0089\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u008B\u009B\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0080\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0099\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + - "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"; - - private final static short index1[] = { - 0, 256, 461, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 698, 920, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, - }; - - public boolean canEncode(char c) { - char test = index2.charAt( index1[(c&0xFF00)>>8] + (c&0xFF) ); - return test!=0; - } - -} diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java deleted file mode 100644 index 3ae1afba7f8..00000000000 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/SingleByteEncoder.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 1997, 2012, 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. - */ - -/* - * @(#)SingleByteEncoder.java 1.14 03/01/23 - */ - -package com.sun.codemodel.internal.util; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; - -import sun.nio.cs.Surrogate; - - -abstract class SingleByteEncoder - extends CharsetEncoder -{ - - private final short index1[]; - private final String index2; - private final int mask1; - private final int mask2; - private final int shift; - - private final Surrogate.Parser sgp = new Surrogate.Parser(); - - protected SingleByteEncoder(Charset cs, - short[] index1, String index2, - int mask1, int mask2, int shift) - { - super(cs, 1.0f, 1.0f); - this.index1 = index1; - this.index2 = index2; - this.mask1 = mask1; - this.mask2 = mask2; - this.shift = shift; - } - - public boolean canEncode(char c) { - char testEncode; - testEncode = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - if (testEncode == '\u0000') - return false; - else - return true; - } - - private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { - char[] sa = src.array(); - int sp = src.arrayOffset() + src.position(); - int sl = src.arrayOffset() + src.limit(); - sp = (sp <= sl ? sp : sl); - byte[] da = dst.array(); - int dp = dst.arrayOffset() + dst.position(); - int dl = dst.arrayOffset() + dst.limit(); - dp = (dp <= dl ? dp : dl); - - try { - while (sp < sl) { - char c = sa[sp]; - if (Surrogate.is(c)) { - if (sgp.parse(c, sa, sp, sl) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (dl - dp < 1) - return CoderResult.OVERFLOW; - - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); - - sp++; - da[dp++] = (byte)e; - } - return CoderResult.UNDERFLOW; - } finally { - src.position(sp - src.arrayOffset()); - dst.position(dp - dst.arrayOffset()); - } - } - - private CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) { - int mark = src.position(); - try { - while (src.hasRemaining()) { - char c = src.get(); - if (Surrogate.is(c)) { - if (sgp.parse(c, src) < 0) - return sgp.error(); - return sgp.unmappableResult(); - } - if (c >= '\uFFFE') - return CoderResult.unmappableForLength(1); - if (!dst.hasRemaining()) - return CoderResult.OVERFLOW; - - char e = index2.charAt(index1[(c & mask1) >> shift] - + (c & mask2)); - - // If output byte is zero because input char is zero - // then character is mappable, o.w. fail - if (e == '\u0000' && c != '\u0000') - return CoderResult.unmappableForLength(1); - - mark++; - dst.put((byte)e); - } - return CoderResult.UNDERFLOW; - } finally { - src.position(mark); - } - } - - protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { - if (true && src.hasArray() && dst.hasArray()) - return encodeArrayLoop(src, dst); - else - return encodeBufferLoop(src, dst); - } - - public byte encode(char inputChar) { - return (byte)index2.charAt(index1[(inputChar & mask1) >> shift] + - (inputChar & mask2)); - } -} diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java deleted file mode 100644 index 51bb024c042..00000000000 --- a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/util/Surrogate.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (c) 1997, 2012, 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. - */ - -package com.sun.codemodel.internal.util; - -import java.nio.CharBuffer; -import java.nio.charset.CoderResult; - - -/** - * Utility class for dealing with surrogates. - * - * @author Mark Reinhold - * @version 1.11, 03/01/23 - */ - -class Surrogate { - - private Surrogate() { } - - // UTF-16 surrogate-character ranges - // - public static final char MIN_HIGH = '\uD800'; - public static final char MAX_HIGH = '\uDBFF'; - public static final char MIN_LOW = '\uDC00'; - public static final char MAX_LOW = '\uDFFF'; - public static final char MIN = MIN_HIGH; - public static final char MAX = MAX_LOW; - - // Range of UCS-4 values that need surrogates in UTF-16 - // - public static final int UCS4_MIN = 0x10000; - public static final int UCS4_MAX = (1 << 20) + UCS4_MIN - 1; - - /** - * Tells whether or not the given UTF-16 value is a high surrogate. - */ - public static boolean isHigh(int c) { - return (MIN_HIGH <= c) && (c <= MAX_HIGH); - } - - /** - * Tells whether or not the given UTF-16 value is a low surrogate. - */ - public static boolean isLow(int c) { - return (MIN_LOW <= c) && (c <= MAX_LOW); - } - - /** - * Tells whether or not the given UTF-16 value is a surrogate character, - */ - public static boolean is(int c) { - return (MIN <= c) && (c <= MAX); - } - - /** - * Tells whether or not the given UCS-4 character must be represented as a - * surrogate pair in UTF-16. - */ - public static boolean neededFor(int uc) { - return (uc >= UCS4_MIN) && (uc <= UCS4_MAX); - } - - /** - * Returns the high UTF-16 surrogate for the given UCS-4 character. - */ - public static char high(int uc) { - return (char)(0xd800 | (((uc - UCS4_MIN) >> 10) & 0x3ff)); - } - - /** - * Returns the low UTF-16 surrogate for the given UCS-4 character. - */ - public static char low(int uc) { - return (char)(0xdc00 | ((uc - UCS4_MIN) & 0x3ff)); - } - - /** - * Converts the given surrogate pair into a 32-bit UCS-4 character. - */ - public static int toUCS4(char c, char d) { - return (((c & 0x3ff) << 10) | (d & 0x3ff)) + 0x10000; - } - - /** - * Surrogate parsing support. Charset implementations may use instances of - * this class to handle the details of parsing UTF-16 surrogate pairs. - */ - public static class Parser { - - public Parser() { } - - private int character; // UCS-4 - private CoderResult error = CoderResult.UNDERFLOW; - private boolean isPair; - - /** - * Returns the UCS-4 character previously parsed. - */ - public int character() { - return character; - } - - /** - * Tells whether or not the previously-parsed UCS-4 character was - * originally represented by a surrogate pair. - */ - public boolean isPair() { - return isPair; - } - - /** - * Returns the number of UTF-16 characters consumed by the previous - * parse. - */ - public int increment() { - return isPair ? 2 : 1; - } - - /** - * If the previous parse operation detected an error, return the object - * describing that error. - */ - public CoderResult error() { - return error; - } - - /** - * Returns an unmappable-input result object, with the appropriate - * input length, for the previously-parsed character. - */ - public CoderResult unmappableResult() { - return CoderResult.unmappableForLength(isPair ? 2 : 1); - } - - /** - * Parses a UCS-4 character from the given source buffer, handling - * surrogates. - * - * @param c The first character - * @param in The source buffer, from which one more character - * will be consumed if c is a high surrogate - * - * @return Either a parsed UCS-4 character, in which case the isPair() - * and increment() methods will return meaningful values, or - * -1, in which case error() will return a descriptive result - * object - */ - public int parse(char c, CharBuffer in) { - if (isHigh(c)) { - if (!in.hasRemaining()) { - error = CoderResult.UNDERFLOW; - return -1; - } - char d = in.get(); - if (isLow(d)) { - character = toUCS4(c, d); - isPair = true; - error = null; - return character; - } - error = CoderResult.malformedForLength(1); - return -1; - } - if (isLow(c)) { - error = CoderResult.malformedForLength(1); - return -1; - } - character = c; - isPair = false; - error = null; - return character; - } - - /** - * Parses a UCS-4 character from the given source buffer, handling - * surrogates. - * - * @param c The first character - * @param ia The input array, from which one more character - * will be consumed if c is a high surrogate - * @param ip The input index - * @param il The input limit - * - * @return Either a parsed UCS-4 character, in which case the isPair() - * and increment() methods will return meaningful values, or - * -1, in which case error() will return a descriptive result - * object - */ - public int parse(char c, char[] ia, int ip, int il) { - if (isHigh(c)) { - if (il - ip < 2) { - error = CoderResult.UNDERFLOW; - return -1; - } - char d = ia[ip + 1]; - if (isLow(d)) { - character = toUCS4(c, d); - isPair = true; - error = null; - return character; - } - error = CoderResult.malformedForLength(1); - return -1; - } - if (isLow(c)) { - error = CoderResult.malformedForLength(1); - return -1; - } - character = c; - isPair = false; - error = null; - return character; - } - - } - - /** - * Surrogate generation support. Charset implementations may use instances - * of this class to handle the details of generating UTF-16 surrogate - * pairs. - */ - public static class Generator { - - public Generator() { } - - private CoderResult error = CoderResult.OVERFLOW; - - /** - * If the previous generation operation detected an error, return the - * object describing that error. - */ - public CoderResult error() { - return error; - } - - /** - * Generates one or two UTF-16 characters to represent the given UCS-4 - * character. - * - * @param uc The UCS-4 character - * @param len The number of input bytes from which the UCS-4 value - * was constructed (used when creating result objects) - * @param dst The destination buffer, to which one or two UTF-16 - * characters will be written - * - * @return Either a positive count of the number of UTF-16 characters - * written to the destination buffer, or -1, in which case - * error() will return a descriptive result object - */ - public int generate(int uc, int len, CharBuffer dst) { - if (uc <= 0xffff) { - if (is(uc)) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (dst.remaining() < 1) { - error = CoderResult.OVERFLOW; - return -1; - } - dst.put((char)uc); - error = null; - return 1; - } - if (uc < UCS4_MIN) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (uc <= UCS4_MAX) { - if (dst.remaining() < 2) { - error = CoderResult.OVERFLOW; - return -1; - } - dst.put(high(uc)); - dst.put(low(uc)); - error = null; - return 2; - } - error = CoderResult.unmappableForLength(len); - return -1; - } - - /** - * Generates one or two UTF-16 characters to represent the given UCS-4 - * character. - * - * @param uc The UCS-4 character - * @param len The number of input bytes from which the UCS-4 value - * was constructed (used when creating result objects) - * @param da The destination array, to which one or two UTF-16 - * characters will be written - * @param dp The destination position - * @param dl The destination limit - * - * @return Either a positive count of the number of UTF-16 characters - * written to the destination buffer, or -1, in which case - * error() will return a descriptive result object - */ - public int generate(int uc, int len, char[] da, int dp, int dl) { - if (uc <= 0xffff) { - if (is(uc)) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (dl - dp < 1) { - error = CoderResult.OVERFLOW; - return -1; - } - da[dp] = (char)uc; - error = null; - return 1; - } - if (uc < UCS4_MIN) { - error = CoderResult.malformedForLength(len); - return -1; - } - if (uc <= UCS4_MAX) { - if (dl - dp < 2) { - error = CoderResult.OVERFLOW; - return -1; - } - da[dp] = high(uc); - da[dp + 1] = low(uc); - error = null; - return 2; - } - error = CoderResult.unmappableForLength(len); - return -1; - } - - } - -} diff --git a/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java new file mode 100644 index 00000000000..76a0c9aecbf --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/codemodel/internal/writer/OutputStreamCodeWriter.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +/** + * Output all source files into a single stream. + * + * This is primarily for test purposes. + * + * @author + * Aleksei Valikov (valikov@gmx.net) + */ +package com.sun.codemodel.internal.writer; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import com.sun.codemodel.internal.CodeWriter; +import com.sun.codemodel.internal.JPackage; + +public class OutputStreamCodeWriter extends CodeWriter { + private final PrintStream out; + + /** + * @param os + * This stream will be closed at the end of the code generation. + */ + public OutputStreamCodeWriter(OutputStream os, String encoding) { + try { + this.out = new PrintStream(os, false, encoding); + } catch (UnsupportedEncodingException ueex) { + throw new IllegalArgumentException(ueex); + } + this.encoding = encoding; + } + + public OutputStream openBinary(JPackage pkg, String fileName) + throws IOException { + return new FilterOutputStream(out) { + public void close() { + // don't let this stream close + } + }; + } + + public void close() throws IOException { + out.close(); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties index 527ef0f4edd..dccb9d28c58 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -30,10 +30,10 @@ BASEDIR_DOESNT_EXIST = \ Non-existent directory: {0} VERSION = \ - schemagen 2.2.8-b130911.1802 + schemagen 2.2.9-b140218.1920 FULLVERSION = \ - schemagen full version "2.2.8-b130911.1802" + schemagen full version "2.2.9-b140218.1920" USAGE = \ Usage: schemagen [-options ...] \n\ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties index 0bd53b420ed..5a4be779856 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Nicht erkanntes {0} in Zeile {1} Spalte {2} BASEDIR_DOESNT_EXIST = Nicht vorhandenes Verzeichnis: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen vollst\u00E4ndige Version "2.2.8-b130911.1802" +FULLVERSION = schemagen vollst\u00E4ndige Version "2.2.9-b140218.1920" USAGE = Verwendung: schemagen [-options ...] \nOptionen: \n\\ \\ \\ \\ -d : Gibt an, wo die von Prozessor und javac generierten Klassendateien gespeichert werden sollen\n\\ \\ \\ \\ -cp : Gibt an, wo die vom Benutzer angegebenen Dateien gespeichert sind\n\\ \\ \\ \\ -classpath : Gibt an, wo die vom Benutzer angegebenen Dateien gespeichert sind\n\\ \\ \\ \\ -encoding : Gibt die Codierung f\u00FCr die Annotationsverarbeitung/den javac-Aufruf an \n\\ \\ \\ \\ -episode : Generiert Episodendatei f\u00FCr separate Kompilierung\n\\ \\ \\ \\ -version : Zeigt Versionsinformation an\n\\ \\ \\ \\ -fullversion : Zeigt vollst\u00E4ndige Versionsinformationen an\n\\ \\ \\ \\ -help : Zeigt diese Verwendungsmeldung an diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties index 98e9702f276..938fbb767c6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Aparece un {0} inesperado en la l\u00EDnea {1} y la colu BASEDIR_DOESNT_EXIST = Directorio no existente: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = versi\u00F3n completa de schemagen "2.2.8-b130911.1802" +FULLVERSION = versi\u00F3n completa de schemagen "2.2.9-b140218.1920" USAGE = Sintaxis: schemagen [-options ...] \nOpciones: \n\\ \\ \\ \\ -d : especifique d\u00F3nde se colocan los archivos de clase generados por javac y el procesador\n\\ \\ \\ \\ -cp : especifique d\u00F3nde se encuentran los archivos especificados por el usuario\n\\ \\ \\ \\ -encoding : especifique la codificaci\u00F3n que se va a utilizar para el procesamiento de anotaciones/llamada de javac\n\\ \\ \\ \\ -episode : genera un archivo de episodio para una compilaci\u00F3n diferente\n\\ \\ \\ \\ -version : muestra la informaci\u00F3n de la versi\u00F3n\n\\ \\ \\ \\ -fullversion : muestra la informaci\u00F3n completa de la versi\u00F3n\n\\ \\ \\ \\ -help : muestra este mensaje de sintaxis diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties index 10c3b15b701..183fdfdcb8d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Un \u00E9l\u00E9ment {0} inattendu appara\u00EEt \u00E0 BASEDIR_DOESNT_EXIST = R\u00E9pertoire {0} inexistant -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = version compl\u00E8te de schemagen "2.2.8-b130911.1802" +FULLVERSION = version compl\u00E8te de schemagen "2.2.9-b140218.1920" USAGE = Syntaxe : schemagen [-options ...] \nOptions : \n\ \ \ \ -d : indiquez o\u00F9 placer les fichiers de classe g\u00E9n\u00E9r\u00E9s par le processeur et le compilateur javac\n\ \ \ \ -cp : indiquez o\u00F9 trouver les fichiers sp\u00E9cifi\u00E9s par l'utilisateur\n\ \ \ \ -classpath : indiquez o\u00F9 trouver les fichiers sp\u00E9cifi\u00E9s par l'utilisateur\n\ \ \ \ -encoding : indiquez l'encodage \u00E0 utiliser pour l'appel de javac/traitement de l'annotation \n\ \ \ \ -episode : g\u00E9n\u00E9rez un fichier d'\u00E9pisode pour la compilation s\u00E9par\u00E9e\n\ \ \ \ -version : affichez les informations de version\n\ \ \ \ -fullversion : affichez les informations compl\u00E8tes de version\n\ \ \ \ -help : affichez ce message de syntaxe diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties index 4cb120188fc..9275c115286 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = {0} imprevisto visualizzato sulla riga {1} colonna {2} BASEDIR_DOESNT_EXIST = Directory non esistente: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = versione completa schemagen "2.2.8-b130911.1802" +FULLVERSION = versione completa schemagen "2.2.9-b140218.1920" USAGE = Uso: schemagen [-options ...] \nOpzioni: \n\ \ \ \ -d : specifica dove posizionare il processore e i file della classe generata javac\n\ \ \ \ -cp : specifica dove trovare i file specificati dall'utente\n\ \ \ \ -classpath : specifica dove trovare i file specificati dall'utente\n\ \ \ \ -encoding : specifica la codifica da usare per l'elaborazione dell'annotazione/richiamo javac \n\ \ \ \ -episode : genera il file di episodio per la compilazione separata\n\ \ \ \ -version : visualizza le informazioni sulla versione\n\ \ \ \ -fullversion : visualizza le informazioni sulla versione completa\n\ \ \ \ -help : visualizza questo messaggio sull'uso diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties index 5e2fb5d1f46..f55d2632a9e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u4E88\u671F\u3057\u306A\u3044{0}\u304C\u884C{1}\u3001\u BASEDIR_DOESNT_EXIST = \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728\u3057\u307E\u305B\u3093: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b130911.1802" +FULLVERSION = schemagen\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.9-b140218.1920" USAGE = \u4F7F\u7528\u65B9\u6CD5: schemagen [-options ...] \n\u30AA\u30D7\u30B7\u30E7\u30F3: \n\ \ \ \ -d : \u30D7\u30ED\u30BB\u30C3\u30B5\u304A\u3088\u3073javac\u304C\u751F\u6210\u3057\u305F\u30AF\u30E9\u30B9\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u7F6E\u304F\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -cp : \u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3059\u308B\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -classpath : \u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3059\u308B\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -encoding : \u6CE8\u91C8\u51E6\u7406/javac\u547C\u51FA\u3057\u306B\u4F7F\u7528\u3059\u308B\u30A8\u30F3\u30B3\u30FC\u30C7\u30A3\u30F3\u30B0\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -episode : \u30B3\u30F3\u30D1\u30A4\u30EB\u3054\u3068\u306B\u30A8\u30D4\u30BD\u30FC\u30C9\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u751F\u6210\u3057\u307E\u3059\n\ \ \ \ -version : \u30D0\u30FC\u30B8\u30E7\u30F3\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\n\ \ \ \ -fullversion : \u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\n\ \ \ \ -help : \u3053\u306E\u4F7F\u7528\u4F8B\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u8868\u793A\u3057\u307E\u3059 diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties index 2a2936f39fe..0070635d69d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \uC608\uC0C1\uCE58 \uC54A\uC740 {0}\uC774(\uAC00) {1}\uD BASEDIR_DOESNT_EXIST = \uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uB514\uB809\uD1A0\uB9AC: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen \uC815\uC2DD \uBC84\uC804 "2.2.8-b130911.1802" +FULLVERSION = schemagen \uC815\uC2DD \uBC84\uC804 "2.2.9-b140218.1920" USAGE = \uC0AC\uC6A9\uBC95: schemagen [-options ...] \n\uC635\uC158: \n\ \ \ \ -d : \uD504\uB85C\uC138\uC11C \uBC0F javac\uC5D0\uC11C \uC0DD\uC131\uD55C \uD074\uB798\uC2A4 \uD30C\uC77C\uC744 \uBC30\uCE58\uD560 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -cp : \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -classpath : \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -encoding : \uC8FC\uC11D \uCC98\uB9AC/javac \uD638\uCD9C\uC5D0 \uC0AC\uC6A9\uD560 \uC778\uCF54\uB529\uC744 \uC9C0\uC815\uD569\uB2C8\uB2E4. \n\ \ \ \ -episode : \uBCC4\uB3C4 \uCEF4\uD30C\uC77C\uC744 \uC704\uD574 episode \uD30C\uC77C\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.\n\ \ \ \ -version : \uBC84\uC804 \uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4.\n\ \ \ \ -fullversion : \uC815\uC2DD \uBC84\uC804 \uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4.\n\ \ \ \ -help : \uC774 \uC0AC\uC6A9\uBC95 \uBA54\uC2DC\uC9C0\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties index 148448e1e1f..3ef7960b487 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = {0} inesperado aparece na linha {1} coluna {2} BASEDIR_DOESNT_EXIST = Diret\u00F3rio n\u00E3o existente: {0} -VERSION = gera\u00E7\u00E3o do esquema 2.2.8-b130911.1802 +VERSION = gera\u00E7\u00E3o do esquema 2.2.9-b140218.1920 -FULLVERSION = vers\u00E3o completa da gera\u00E7\u00E3o do esquema "2.2.8-b130911.1802" +FULLVERSION = vers\u00E3o completa da gera\u00E7\u00E3o do esquema "2.2.9-b140218.1920" USAGE = Uso: gera\u00E7\u00E3o do esquema [-options ...] \nOp\u00E7\u00F5es: \n\\ \\ \\ \\ -d : especificar onde colocar o processador e os arquivos da classe gerados por javac\n\\ \\ \\ \\ -cp : especificar onde localizar arquivos especificados pelo usu\u00E1rio\n\\ \\ \\ \\ -classpath : especificar onde localizar os arquivos especificados pelo usu\u00E1rio\n\\ \\ \\ \\ -encoding : especificar codifica\u00E7\u00E3o a ser usada para processamento de anota\u00E7\u00E3o/chamada javac \n\\ \\ \\ \\ -episode : gerar arquivo do epis\u00F3dio para compila\u00E7\u00E3o separada\n\\ \\ \\ \\ -version : exibir informa\u00E7\u00F5es da vers\u00E3o\n\\ \\ \\ \\ -fullversion : exibir informa\u00E7\u00F5es da vers\u00E3o completa\n\\ \\ \\ \\ -help : exibir esta mensagem de uso diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties index 09bac14c324..d800201019c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u5728\u7B2C {1} \u884C, \u7B2C {2} \u5217\u51FA\u73B0\u BASEDIR_DOESNT_EXIST = \u4E0D\u5B58\u5728\u7684\u76EE\u5F55: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" USAGE = \u7528\u6CD5: schemagen [-options ...] \n\u9009\u9879: \n\ \ \ \ -d : \u6307\u5B9A\u653E\u7F6E\u5904\u7406\u7A0B\u5E8F\u548C javac \u751F\u6210\u7684\u7C7B\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -cp : \u6307\u5B9A\u67E5\u627E\u7528\u6237\u6307\u5B9A\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -classpath : \u6307\u5B9A\u67E5\u627E\u7528\u6237\u6307\u5B9A\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -encoding : \u6307\u5B9A\u7528\u4E8E\u6CE8\u91CA\u5904\u7406/javac \u8C03\u7528\u7684\u7F16\u7801\n\ \ \ \ -episode : \u751F\u6210\u7247\u6BB5\u6587\u4EF6\u4EE5\u4F9B\u5355\u72EC\u7F16\u8BD1\n\ \ \ \ -version : \u663E\u793A\u7248\u672C\u4FE1\u606F\n\ \ \ \ -fullversion : \u663E\u793A\u5B8C\u6574\u7684\u7248\u672C\u4FE1\u606F\n\ \ \ \ -help : \u663E\u793A\u6B64\u7528\u6CD5\u6D88\u606F diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties index 08fb9fe24e3..6976c6faf3c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u672A\u9810\u671F\u7684 {0} \u986F\u793A\u65BC\u884C {1 BASEDIR_DOESNT_EXIST = \u4E0D\u5B58\u5728\u7684\u76EE\u9304: {0} -VERSION = schemagen 2.2.8-b130911.1802 +VERSION = schemagen 2.2.9-b140218.1920 -FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" USAGE = \u7528\u6CD5: schemagen [-options ...] \n\u9078\u9805: \n\\ \\ \\ \\ -d : \u6307\u5B9A\u8655\u7406\u5668\u4EE5\u53CA javac \u7522\u751F\u7684\u985E\u5225\u6A94\u6848\u653E\u7F6E\u4F4D\u7F6E\n\\ \\ \\ \\ -cp : \u6307\u5B9A\u8981\u5C0B\u627E\u4F7F\u7528\u8005\u6307\u5B9A\u6A94\u6848\u7684\u4F4D\u7F6E\n\\ \\ \\ \\ -classpath : \u6307\u5B9A\u8981\u5C0B\u627E\u4F7F\u7528\u8005\u6307\u5B9A\u6A94\u6848\u7684\u4F4D\u7F6E\n\\ \\ \\ \\ -encoding : \u6307\u5B9A\u8981\u7528\u65BC\u8A3B\u89E3\u8655\u7406/javac \u547C\u53EB\u7684\u7DE8\u78BC \n\\ \\ \\ \\ -episode : \u7522\u751F\u7368\u7ACB\u7DE8\u8B6F\u7684\u4E8B\u4EF6 (episode) \u6A94\u6848\n\\ \\ \\ \\ -version : \u986F\u793A\u7248\u672C\u8CC7\u8A0A\n\\ \\ \\ \\ -fullversion : \u986F\u793A\u5B8C\u6574\u7248\u672C\u8CC7\u8A0A\n\\ \\ \\ \\ -help : \u986F\u793A\u6B64\u7528\u6CD5\u8A0A\u606F diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java index 26c868d716e..ec8e5ec6abb 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/annotation/WebServiceVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -31,7 +31,6 @@ import com.sun.tools.internal.ws.util.ClassNameInfo; import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle; import com.sun.xml.internal.ws.model.RuntimeModeler; -import javax.annotation.processing.ProcessingEnvironment; import javax.jws.Oneway; import javax.jws.WebMethod; import javax.jws.WebParam; @@ -609,12 +608,6 @@ public abstract class WebServiceVisitor extends SimpleElementVisitor6 +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn Driver.FilePrologComment = \ - This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 \n\ + This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.9-b140218.1920 \n\ See http://java.sun.com/xml/jaxb \n\ Any modifications to this file will be lost upon recompilation of the source schema. \n\ Generated on: {0} \n Driver.Version = \ - xjc 2.2.8-b130911.1802 + xjc 2.2.9-b140218.1920 Driver.FullVersion = \ - xjc full version "2.2.8-b130911.1802" + xjc full version "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties index 6c14d7cf277..51d70085075 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = Ein Schema wird kompiliert ... Driver.FailedToGenerateCode = Code konnte nicht erzeugt werden. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 generiert \nSiehe http://java.sun.com/xml/jaxb \n\u00c4nderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. \nGeneriert: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.9-b140218.1920 generiert \nSiehe http://java.sun.com/xml/jaxb \n\u00c4nderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. \nGeneriert: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc vollst\u00E4ndige Version "2.2.8-b130911.1802" +Driver.FullVersion = xjc vollst\u00E4ndige Version "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties index e62bf41d574..acdbffd5ad1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = Compilando un esquema... Driver.FailedToGenerateCode = Fallo al producir c\u00f3digo. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Este archivo ha sido generado por la arquitectura JavaTM para la implantaci\u00f3n de la referencia de enlace (JAXB) XML v2.2.8-b130911.1802 \nVisite http://java.sun.com/xml/jaxb \nTodas las modificaciones realizadas en este archivo se perder\u00e1n si se vuelve a compilar el esquema de origen. \nGenerado el: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Este archivo ha sido generado por la arquitectura JavaTM para la implantaci\u00f3n de la referencia de enlace (JAXB) XML v2.2.9-b140218.1920 \nVisite http://java.sun.com/xml/jaxb \nTodas las modificaciones realizadas en este archivo se perder\u00e1n si se vuelve a compilar el esquema de origen. \nGenerado el: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = versi\u00F3n completa de xjc "2.2.8-b130911.1802" +Driver.FullVersion = versi\u00F3n completa de xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties index 36adafe095a..76aec21fd2d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = compilation d'un sch\u00e9ma... Driver.FailedToGenerateCode = Echec de la production du code. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par l''impl\u00e9mentation de r\u00e9f\u00e9rence JavaTM Architecture for XML Binding (JAXB), v2.2.8-b130911.1802 \nVoir http://java.sun.com/xml/jaxb \nToute modification apport\u00e9e \u00e0 ce fichier sera perdue lors de la recompilation du sch\u00e9ma source. \nG\u00e9n\u00e9r\u00e9 le : {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par l''impl\u00e9mentation de r\u00e9f\u00e9rence JavaTM Architecture for XML Binding (JAXB), v2.2.9-b140218.1920 \nVoir http://java.sun.com/xml/jaxb \nToute modification apport\u00e9e \u00e0 ce fichier sera perdue lors de la recompilation du sch\u00e9ma source. \nG\u00e9n\u00e9r\u00e9 le : {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = version compl\u00E8te xjc "2.2.8-b130911.1802" +Driver.FullVersion = version compl\u00E8te xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties index 93b1533ec2a..9a9a5332e5c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = compilazione di uno schema in corso... Driver.FailedToGenerateCode = Produzione del codice non riuscita. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Questo file \u00e8 stato generato dall''architettura JavaTM per XML Binding (JAXB) Reference Implementation, v2.2.8-b130911.1802 \nVedere http://java.sun.com/xml/jaxb \nQualsiasi modifica a questo file andr\u00e0 persa durante la ricompilazione dello schema di origine. \nGenerato il: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Questo file \u00e8 stato generato dall''architettura JavaTM per XML Binding (JAXB) Reference Implementation, v2.2.9-b140218.1920 \nVedere http://java.sun.com/xml/jaxb \nQualsiasi modifica a questo file andr\u00e0 persa durante la ricompilazione dello schema di origine. \nGenerato il: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = versione completa xjc "2.2.8-b130911.1802" +Driver.FullVersion = versione completa xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties index 088938a1b7f..8fc9f7b12fd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \u30b9\u30ad\u30fc\u30de\u306e\u30b3\u30f3\u30d1\u30a4\ Driver.FailedToGenerateCode = \u30b3\u30fc\u30c9\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3001JavaTM Architecture for XML Binding(JAXB) Reference Implementation\u3001v2.2.8-b130911.1802\u306b\u3088\u3063\u3066\u751f\u6210\u3055\u308c\u307e\u3057\u305f \nhttp://java.sun.com/xml/jaxb\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044 \n\u30bd\u30fc\u30b9\u30fb\u30b9\u30ad\u30fc\u30de\u306e\u518d\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306b\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u306f\u5931\u308f\u308c\u307e\u3059\u3002 \n\u751f\u6210\u65e5: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3001JavaTM Architecture for XML Binding(JAXB) Reference Implementation\u3001v2.2.9-b140218.1920\u306b\u3088\u3063\u3066\u751f\u6210\u3055\u308c\u307e\u3057\u305f \nhttp://java.sun.com/xml/jaxb\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044 \n\u30bd\u30fc\u30b9\u30fb\u30b9\u30ad\u30fc\u30de\u306e\u518d\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306b\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u306f\u5931\u308f\u308c\u307e\u3059\u3002 \n\u751f\u6210\u65e5: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b130911.1802" +Driver.FullVersion = xjc\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties index 5d2bc734884..7a34340441a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \uc2a4\ud0a4\ub9c8\ub97c \ucef4\ud30c\uc77c\ud558\ub294 Driver.FailedToGenerateCode = \ucf54\ub4dc \uc0dd\uc131\uc744 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \uc774 \ud30c\uc77c\uc740 JAXB(JavaTM Architecture for XML Binding) \ucc38\uc870 \uad6c\ud604 2.2.8-b130911.1802 \ubc84\uc804\uc744 \ud1b5\ud574 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \nhttp://java.sun.com/xml/jaxb\ub97c \ucc38\uc870\ud558\uc2ed\uc2dc\uc624. \n\uc774 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uba74 \uc18c\uc2a4 \uc2a4\ud0a4\ub9c8\ub97c \uc7ac\ucef4\ud30c\uc77c\ud560 \ub54c \uc218\uc815 \uc0ac\ud56d\uc774 \uc190\uc2e4\ub429\ub2c8\ub2e4. \n\uc0dd\uc131 \ub0a0\uc9dc: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \uc774 \ud30c\uc77c\uc740 JAXB(JavaTM Architecture for XML Binding) \ucc38\uc870 \uad6c\ud604 2.2.9-b140218.1920 \ubc84\uc804\uc744 \ud1b5\ud574 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \nhttp://java.sun.com/xml/jaxb\ub97c \ucc38\uc870\ud558\uc2ed\uc2dc\uc624. \n\uc774 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uba74 \uc18c\uc2a4 \uc2a4\ud0a4\ub9c8\ub97c \uc7ac\ucef4\ud30c\uc77c\ud560 \ub54c \uc218\uc815 \uc0ac\ud56d\uc774 \uc190\uc2e4\ub429\ub2c8\ub2e4. \n\uc0dd\uc131 \ub0a0\uc9dc: {0} \n -Driver.Version = XJC 2.2.8-b130911.1802 +Driver.Version = XJC 2.2.9-b140218.1920 -Driver.FullVersion = XJC \uC815\uC2DD \uBC84\uC804 "2.2.8-b130911.1802" +Driver.FullVersion = XJC \uC815\uC2DD \uBC84\uC804 "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties index 04bad425657..3f422db793f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = compilando um esquema... Driver.FailedToGenerateCode = Falha ao produzir o c\u00f3digo. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = Este arquivo foi gerado pela Arquitetura JavaTM para Implementa\u00e7\u00e3o de Refer\u00eancia (JAXB) de Bind XML, v2.2.8-b130911.1802 \nConsulte http://java.sun.com/xml/jaxb \nTodas as modifica\u00e7\u00f5es neste arquivo ser\u00e3o perdidas ap\u00f3s a recompila\u00e7\u00e3o do esquema de origem. \nGerado em: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = Este arquivo foi gerado pela Arquitetura JavaTM para Implementa\u00e7\u00e3o de Refer\u00eancia (JAXB) de Bind XML, v2.2.9-b140218.1920 \nConsulte http://java.sun.com/xml/jaxb \nTodas as modifica\u00e7\u00f5es neste arquivo ser\u00e3o perdidas ap\u00f3s a recompila\u00e7\u00e3o do esquema de origem. \nGerado em: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = vers\u00E3o completa de xjc "2.2.8-b130911.1802" +Driver.FullVersion = vers\u00E3o completa de xjc "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties index adf97c7caff..4a858e47f17 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \u6b63\u5728\u7f16\u8bd1\u6a21\u5f0f... Driver.FailedToGenerateCode = \u65e0\u6cd5\u751f\u6210\u4ee3\u7801\u3002 -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \u6b64\u6587\u4ef6\u662f\u7531 JavaTM Architecture for XML Binding (JAXB) \u5f15\u7528\u5b9e\u73b0 v2.2.8-b130911.1802 \u751f\u6210\u7684\n\u8bf7\u8bbf\u95ee http://java.sun.com/xml/jaxb \n\u5728\u91cd\u65b0\u7f16\u8bd1\u6e90\u6a21\u5f0f\u65f6, \u5bf9\u6b64\u6587\u4ef6\u7684\u6240\u6709\u4fee\u6539\u90fd\u5c06\u4e22\u5931\u3002\n\u751f\u6210\u65f6\u95f4: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \u6b64\u6587\u4ef6\u662f\u7531 JavaTM Architecture for XML Binding (JAXB) \u5f15\u7528\u5b9e\u73b0 v2.2.9-b140218.1920 \u751f\u6210\u7684\n\u8bf7\u8bbf\u95ee http://java.sun.com/xml/jaxb \n\u5728\u91cd\u65b0\u7f16\u8bd1\u6e90\u6a21\u5f0f\u65f6, \u5bf9\u6b64\u6587\u4ef6\u7684\u6240\u6709\u4fee\u6539\u90fd\u5c06\u4e22\u5931\u3002\n\u751f\u6210\u65f6\u95f4: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties index a8684e5ea84..add02eb0f7b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -96,14 +96,14 @@ Driver.CompilingSchema = \u6b63\u5728\u7de8\u8b6f\u7db1\u8981... Driver.FailedToGenerateCode = \u7121\u6cd5\u7522\u751f\u7a0b\u5f0f\u78bc. -# DO NOT localize the 2.2.8-b130911.1802 string - it is a token for an mvn -Driver.FilePrologComment = \u6b64\u6a94\u6848\u662f\u7531 JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 \u6240\u7522\u751f \n\u8acb\u53c3\u95b1 http://java.sun.com/xml/jaxb \n\u4e00\u65e6\u91cd\u65b0\u7de8\u8b6f\u4f86\u6e90\u7db1\u8981, \u5c0d\u6b64\u6a94\u6848\u6240\u505a\u7684\u4efb\u4f55\u4fee\u6539\u90fd\u5c07\u6703\u907a\u5931. \n\u7522\u751f\u6642\u9593: {0} \n +# DO NOT localize the 2.2.9-b140218.1920 string - it is a token for an mvn +Driver.FilePrologComment = \u6b64\u6a94\u6848\u662f\u7531 JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.9-b140218.1920 \u6240\u7522\u751f \n\u8acb\u53c3\u95b1 http://java.sun.com/xml/jaxb \n\u4e00\u65e6\u91cd\u65b0\u7de8\u8b6f\u4f86\u6e90\u7db1\u8981, \u5c0d\u6b64\u6a94\u6848\u6240\u505a\u7684\u4efb\u4f55\u4fee\u6539\u90fd\u5c07\u6703\u907a\u5931. \n\u7522\u751f\u6642\u9593: {0} \n -Driver.Version = xjc 2.2.8-b130911.1802 +Driver.Version = xjc 2.2.9-b140218.1920 -Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.8-b130911.1802" +Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.9-b140218.1920" -Driver.BuildID = 2.2.8-b130911.1802 +Driver.BuildID = 2.2.9-b140218.1920 # for JDK integration - include version in source zip jaxb.jdk.version=@@JAXB_JDK_VERSION@@ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java index c209cd7e688..ba8e6f4f50a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BIProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -468,25 +468,22 @@ public final class BIProperty extends AbstractDeclarationImpl { r = ct.get(getBuilder().model); } else { FieldRendererFactory frf = getBuilder().fieldRendererFactory; - - if(prop.isOptionalPrimitive()) { + // according to the spec we should bahave as in jaxb1. So we ignore possiblity that property could be nullable + switch(opm) { // the property type can be primitive type if we are to ignore absence - switch(opm) { case PRIMITIVE: r = frf.getRequiredUnboxed(); break; case WRAPPER: // force the wrapper type - r = frf.getSingle(); + r = prop.isOptionalPrimitive() ? frf.getSingle() : frf.getDefault(); break; case ISSET: - r = frf.getSinglePrimitiveAccess(); + r = prop.isOptionalPrimitive() ? frf.getSinglePrimitiveAccess() : frf.getDefault(); break; default: throw new Error(); - } - } else { - r = frf.getDefault(); + } } if(opm==OptionalPropertyMode.ISSET) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java index f1a28b6a729..e7ff4433460 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -91,6 +91,9 @@ import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data; import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext; import com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx; import com.sun.xml.internal.bind.v2.util.DataSourceSource; +import java.util.logging.Logger; +import com.sun.xml.internal.bind.Util; +import java.util.logging.Level; import org.xml.sax.SAXException; @@ -105,6 +108,8 @@ import org.xml.sax.SAXException; public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl implements RuntimeBuiltinLeafInfo, Transducer { + private static final Logger logger = Util.getClassLogger(); + private RuntimeBuiltinLeafInfoImpl(Class type, QName... typeNames) { super(type, typeNames); LEAVES.put(type,this); @@ -196,6 +201,7 @@ public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl< public static final List> builtinBeanInfos; public static final String MAP_ANYURI_TO_URI = "mapAnyUriToUri"; + public static final String USE_OLD_GMONTH_MAPPING = "jaxb.ri.useOldGmonthMapping"; static { @@ -960,7 +966,14 @@ public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl< m.put(DatatypeConstants.DATETIME, "%Y-%M-%DT%h:%m:%s"+ "%z"); m.put(DatatypeConstants.DATE, "%Y-%M-%D" +"%z"); m.put(DatatypeConstants.TIME, "%h:%m:%s"+ "%z"); - m.put(DatatypeConstants.GMONTH, "--%M--%z"); + if (System.getProperty(USE_OLD_GMONTH_MAPPING) == null) { + m.put(DatatypeConstants.GMONTH, "--%M%z"); // E2-12 Error. http://www.w3.org/2001/05/xmlschema-errata#e2-12 + } else { // backw. compatibility + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Old GMonth mapping used."); + } + m.put(DatatypeConstants.GMONTH, "--%M--%z"); + } m.put(DatatypeConstants.GDAY, "---%D" + "%z"); m.put(DatatypeConstants.GYEAR, "%Y" + "%z"); m.put(DatatypeConstants.GYEARMONTH, "%Y-%M" + "%z"); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java index 69cf28b7b5c..b5ee5e65e2f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/Navigator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -25,10 +25,6 @@ package com.sun.xml.internal.bind.v2.model.nav; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.lang.reflect.Type; import java.util.Collection; import com.sun.xml.internal.bind.v2.runtime.Location; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java index 665001f88cf..7f25c89d688 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/nav/ReflectionNavigator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -550,7 +550,7 @@ import com.sun.xml.internal.bind.v2.runtime.Location; @Override public Class loadObjectFactory(Class referencePoint, String pkg) { - ClassLoader cl= SecureLoader.getClassClassLoader(referencePoint); + ClassLoader cl = SecureLoader.getClassClassLoader(referencePoint); if (cl == null) cl = SecureLoader.getSystemClassLoader(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java index 1d1a34638a8..be203b6681b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleMapNodeProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,22 +140,23 @@ final class SingleMapNodeProperty extends PropertyImpl */ private final Loader itemsLoader = new Loader(false) { - private ThreadLocal target = new ThreadLocal(); - private ThreadLocal map = new ThreadLocal(); - private int depthCounter = 0; // needed to clean ThreadLocals + private ThreadLocal> target = new ThreadLocal>(); + private ThreadLocal> map = new ThreadLocal>(); @Override public void startElement(UnmarshallingContext.State state, TagName ea) throws SAXException { // create or obtain the Map object try { - target.set((BeanT)state.prev.target); - map.set(acc.get(target.get())); - depthCounter++; - if(map.get() == null) { - map.set(ClassFactory.create(mapImplClass)); - } - map.get().clear(); - state.target = map.get(); + BeanT target = (BeanT) state.prev.target; + ValueT mapValue = acc.get(target); + if(mapValue == null) + mapValue = ClassFactory.create(mapImplClass); + else + mapValue.clear(); + + Stack.push(this.target, target); + Stack.push(map, mapValue); + state.target = mapValue; } catch (AccessorException e) { // recover from error by setting a dummy Map that receives and discards the values handleGenericException(e,true); @@ -167,11 +168,7 @@ final class SingleMapNodeProperty extends PropertyImpl public void leaveElement(State state, TagName ea) throws SAXException { super.leaveElement(state, ea); try { - acc.set(target.get(), map.get()); - if (--depthCounter == 0) { - target.remove(); - map.remove(); - } + acc.set(Stack.pop(target), Stack.pop(map)); } catch (AccessorException ex) { handleGenericException(ex,true); } @@ -289,4 +286,36 @@ final class SingleMapNodeProperty extends PropertyImpl return acc; return null; } + + private static final class Stack { + private Stack parent; + private T value; + + private Stack(Stack parent, T value) { + this.parent = parent; + this.value = value; + } + + private Stack(T value) { + this.value = value; + } + + private static void push(ThreadLocal> holder, T value) { + Stack parent = holder.get(); + if (parent == null) + holder.set(new Stack(value)); + else + holder.set(new Stack(parent, value)); + } + + private static T pop(ThreadLocal> holder) { + Stack current = holder.get(); + if (current.parent == null) + holder.remove(); + else + holder.set(current.parent); + return current.value; + } + + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java index 30c80801592..7633e1ce017 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -1070,18 +1070,22 @@ public final class XmlSchemaGenerator { } Collection refs = propInfo.ref(); - TypeInfo ti; - if ((refs != null) && (!refs.isEmpty()) && (elemName != null) - && ((ti = refs.iterator().next()) == null || ti instanceof ClassInfoImpl)) { - ClassInfoImpl cImpl = (ClassInfoImpl)ti; - if ((cImpl != null) && (cImpl.getElementName() != null)) { - e.ref(new QName(cImpl.getElementName().getNamespaceURI(), tn.getLocalPart())); - } else { - e.ref(new QName("", tn.getLocalPart())); + if ((refs != null) && (!refs.isEmpty()) && (elemName != null)){ + ClassInfoImpl cImpl = null; + for (TypeInfo ref : refs) { + if (ref == null || ref instanceof ClassInfoImpl) { + if (elemName.equals(((ClassInfoImpl)ref).getElementName())) { + cImpl = (ClassInfoImpl) ref; + break; + } + } } - } else { + if (cImpl != null) + e.ref(new QName(cImpl.getElementName().getNamespaceURI(), tn.getLocalPart())); + else + e.ref(new QName("", tn.getLocalPart())); + } else e.ref(tn); - } } } else { e.name(tn.getLocalPart()); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.java new file mode 100644 index 00000000000..151ae98e1fe --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/LazyEnvelopeSource.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.messaging.saaj; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +/** + * LazyEnvelopeSource provides the source to create lazy Envelope + * + * @author shih-chang.chen@oracle.com + */ +public interface LazyEnvelopeSource extends javax.xml.transform.Source { + /** + * Retrieve payload qname without materializing its contents + * @return + * @throws SOAPException + */ + public QName getPayloadQName(); + public XMLStreamReader readToBodyStarTag() throws XMLStreamException; + public XMLStreamReader readPayload(); + public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException; + public boolean isPayloadStreamReader(); +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java index eeccdf1db4f..46e21c05e03 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/client/p2p/HttpSOAPConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -621,7 +621,8 @@ class HttpSOAPConnection extends SOAPConnection { String plain = user + ":"; byte[] nameBytes = plain.getBytes(); - byte[] passwdBytes = password.getBytes(); + byte[] passwdBytes = (password == null ? new byte[0] : password + .getBytes()); // concatenate user name and password bytes and encode them byte[] concat = new byte[nameBytes.length + passwdBytes.length]; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java index e9b74eecd68..6a5ca2ccd23 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/MessagingException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -84,7 +84,7 @@ public class MessagingException extends Exception { * * @return next Exception, null if none. */ - public Exception getNextException() { + public synchronized Exception getNextException() { return next; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java index eac9d5b465e..f2f053f148d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/BMMimeMultipart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -40,7 +40,6 @@ import com.sun.xml.internal.messaging.saaj.packaging.mime.*; import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*; import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; -import com.sun.xml.internal.messaging.saaj.util.FinalArrayList; /** * The MimeMultipart class is an implementation of the abstract Multipart @@ -393,13 +392,12 @@ public class BMMimeMultipart extends MimeMultipart { int i; int l = pattern.length; int lx = l -1; - int bufferLength = 0; BitSet eof = new BitSet(1); long[] posVector = new long[1]; while (true) { is.mark(l); - bufferLength = readNext(is, buffer, l, eof, posVector, sin); + readNext(is, buffer, l, eof, posVector, sin); if (eof.get(0)) { // End of stream return false; @@ -561,7 +559,7 @@ public class BMMimeMultipart extends MimeMultipart { if (prevBuffer[s-1] == (byte)13) { // if buffer[0] == (byte)10 if (buffer[0] == (byte)10) { - int j=lx-1; + int j; for(j = lx-1; j > 0; j--) { if (buffer[j+1] != pattern[j]) { break; @@ -695,7 +693,6 @@ public class BMMimeMultipart extends MimeMultipart { * Iterates through all the parts and outputs each Mime part * separated by a boundary. */ - byte[] buf = new byte[1024]; public void writeTo(OutputStream os) throws IOException, MessagingException { @@ -715,19 +712,25 @@ public class BMMimeMultipart extends MimeMultipart { if (in != null) { OutputUtil.writeln(bnd, os); // put out boundary if ((os instanceof ByteOutputStream) && lazyAttachments) { - ((ByteOutputStream)os).write(in); + ((ByteOutputStream) os).write(in); } else { - ByteOutputStream baos = new ByteOutputStream(in.available()); - baos.write(in); - baos.writeTo(os); - // reset the inputstream so that we can support a - //getAttachment later - in = baos.newInputStream(); + ByteOutputStream baos = null; + try { + baos = new ByteOutputStream(in.available()); + baos.write(in); + baos.writeTo(os); + // reset the inputstream so that we can support a + // getAttachment later + in = baos.newInputStream(); + } finally { + if (baos != null) + baos.close(); + } } // this will endup writing the end boundary } else { - // put out last boundary + // put out last boundary OutputUtil.writeAsAscii(bnd, os); OutputUtil.writeAsAscii("--", os); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java index 314f7d2873d..c19c1dc5c2d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeBodyPart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -193,13 +193,17 @@ public final class MimeBodyPart { SharedInputStream sis = (SharedInputStream) is; contentStream = sis.newStream(sis.getPosition(), -1); } else { + ByteOutputStream bos = null; try { - ByteOutputStream bos = new ByteOutputStream(); + bos = new ByteOutputStream(); bos.write(is); content = bos.getBytes(); contentLength = bos.getCount(); } catch (IOException ioex) { throw new MessagingException("Error reading input stream", ioex); + } finally { + if (bos != null) + bos.close(); } } @@ -1075,8 +1079,12 @@ public final class MimeBodyPart { */ protected void updateHeaders() throws MessagingException { DataHandler dh = getDataHandler(); - if (dh == null) // Huh ? - return; + /* + * Code flow indicates null is never returned from + * getdataHandler() - findbugs + */ + //if (dh == null) // Huh ? + // return; try { String type = dh.getContentType(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java index 8a367fa0f15..a0017194f65 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimeMultipart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -318,6 +318,7 @@ public class MimeMultipart { byte[] bndbytes = ASCIIUtility.getBytes(boundary); int bl = bndbytes.length; + ByteOutputStream buf = null; try { // Skip the preamble LineInputStream lin = new LineInputStream(in); @@ -370,7 +371,7 @@ public class MimeMultipart { if (!in.markSupported()) throw new MessagingException("Stream doesn't support mark"); - ByteOutputStream buf = null; + buf = null; // if we don't have a shared input stream, we copy the data if (sin == null) buf = new ByteOutputStream(); @@ -471,6 +472,9 @@ public class MimeMultipart { } } catch (IOException ioex) { throw new MessagingException("IO Error", ioex); + } finally { + if (buf != null) + buf.close(); } if (!ignoreMissingEndBoundary && !foundClosingBoundary && sin== null) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java index bdef4532e48..0044a5c31cc 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/internet/MimePullMultipart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -107,7 +107,7 @@ public class MimePullMultipart extends MimeMultipart { List prts = mm.getAttachments(); for(MIMEPart part : prts) { if (part != soapPart) { - AttachmentPart attach = new AttachmentPartImpl(part); + new AttachmentPartImpl(part); this.addBodyPart(new MimeBodyPart(part)); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java index 22fd2c488fc..48a56e8068c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/packaging/mime/util/ASCIIUtility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -141,10 +141,13 @@ public class ASCIIUtility { * Use {@link ByteOutputStream} and {@link ByteOutputStream#write(InputStream)}. */ public static byte[] getBytes(InputStream is) throws IOException { - ByteOutputStream bos = new ByteOutputStream(); + ByteOutputStream bos = null; try { + bos = new ByteOutputStream(); bos.write(is); } finally { + if (bos != null) + bos.close(); is.close(); } return bos.toByteArray(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java index 8d91b5ce769..76f6802b50d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/AttachmentPartImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -138,7 +138,6 @@ public class AttachmentPartImpl extends AttachmentPart { } public int getSize() throws SOAPException { - byte[] bytes; if (mimePart != null) { try { return mimePart.read().available(); @@ -388,6 +387,7 @@ public class AttachmentPartImpl extends AttachmentPart { } dataHandler = null; InputStream decoded = null; + ByteOutputStream bos = null; try { decoded = MimeUtility.decode(content, "base64"); InternetHeaders hdrs = new InternetHeaders(); @@ -395,7 +395,7 @@ public class AttachmentPartImpl extends AttachmentPart { //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart // Ctor with inputStream causes problems based on the InputStream // has markSupported()==true - ByteOutputStream bos = new ByteOutputStream(); + bos = new ByteOutputStream(); bos.write(decoded); rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos.getCount()); setMimeHeader("Content-Type", contentType); @@ -403,8 +403,11 @@ public class AttachmentPartImpl extends AttachmentPart { log.log(Level.SEVERE, "SAAJ0578.soap.attachment.setbase64content.exception", e); throw new SOAPExceptionImpl(e.getLocalizedMessage()); } finally { + if (bos != null) + bos.close(); try { - decoded.close(); + if (decoded != null) + decoded.close(); } catch (IOException ex) { throw new SOAPException(ex); } @@ -478,13 +481,14 @@ public class AttachmentPartImpl extends AttachmentPart { mimePart = null; } dataHandler = null; + ByteOutputStream bos = null; try { InternetHeaders hdrs = new InternetHeaders(); hdrs.setHeader("Content-Type", contentType); //TODO: reading the entire attachment here is ineffcient. Somehow the MimeBodyPart // Ctor with inputStream causes problems based on whether the InputStream has // markSupported()==true or false - ByteOutputStream bos = new ByteOutputStream(); + bos = new ByteOutputStream(); bos.write(content); rawContent = new MimeBodyPart(hdrs, bos.getBytes(), bos.getCount()); setMimeHeader("Content-Type", contentType); @@ -492,6 +496,8 @@ public class AttachmentPartImpl extends AttachmentPart { log.log(Level.SEVERE, "SAAJ0576.soap.attachment.setrawcontent.exception", e); throw new SOAPExceptionImpl(e.getLocalizedMessage()); } finally { + if (bos != null) + bos.close(); try { content.close(); } catch (IOException ex) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java index 14dc496ba4c..607e8c36c68 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/Envelope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.OutputStream; import javax.xml.soap.SOAPEnvelope; +import javax.xml.soap.SOAPException; import javax.xml.transform.Source; /** @@ -52,4 +53,8 @@ public interface Envelope extends SOAPEnvelope { * Output the content. */ void output(OutputStream out, boolean isFastInfoset) throws IOException; + + void setStaxBridge(StaxBridge bridge) throws SOAPException; + + StaxBridge getStaxBridge() throws SOAPException; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java index 62fb9df4e6d..907c8ef9d91 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/EnvelopeFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -29,18 +29,22 @@ import java.util.logging.Logger; import javax.xml.parsers.SAXParser; import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; +import com.sun.xml.internal.messaging.saaj.LazyEnvelopeSource; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.util.*; - import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; /** @@ -58,20 +62,73 @@ public class EnvelopeFactory { public static Envelope createEnvelope(Source src, SOAPPartImpl soapPart) throws SOAPException { + if (src instanceof JAXMStreamSource) { + try { + if (!SOAPPartImpl.lazyContentLength) { + ((JAXMStreamSource) src).reset(); + } + } catch (java.io.IOException ioe) { + log.severe("SAAJ0515.source.reset.exception"); + throw new SOAPExceptionImpl(ioe); + } + } + if (src instanceof LazyEnvelopeSource) { + return lazy((LazyEnvelopeSource)src, soapPart); + } + if (soapPart.message.isLazySoapBodyParsing()) { + return parseEnvelopeStax(src, soapPart); + } else { + return parseEnvelopeSax(src, soapPart); + } + } + + private static Envelope lazy(LazyEnvelopeSource src, SOAPPartImpl soapPart) throws SOAPException { + try { + StaxBridge staxBridge = new StaxLazySourceBridge(src, soapPart); + staxBridge.bridgeEnvelopeAndHeaders(); + Envelope env = (Envelope) soapPart.getEnvelope(); + env.setStaxBridge(staxBridge); + return env; + } catch (XMLStreamException e) { + throw new SOAPException(e); + } + } + + static private XMLInputFactory xmlInputFactory = null; + + private static Envelope parseEnvelopeStax(Source src, SOAPPartImpl soapPart) + throws SOAPException { + XMLStreamReader streamReader = null; + if (src instanceof StAXSource) { + streamReader = ((StAXSource) src).getXMLStreamReader(); + } + try { + if (streamReader == null) { + if (xmlInputFactory == null) xmlInputFactory = XMLInputFactory.newInstance(); + streamReader = xmlInputFactory.createXMLStreamReader(src); + } +// SaajStaxWriter saajWriter = new SaajStaxWriter(soapPart.message, soapPart.document); +// XMLStreamReaderToXMLStreamWriter readerWriterBridge = new XMLStreamReaderToXMLStreamWriter( +// streamReader, saajWriter, soapPart.getSOAPNamespace()); + + StaxBridge readerWriterBridge = new StaxReaderBridge(streamReader, soapPart); + //bridge will stop reading at body element, and parse upon request, so save it + //on the envelope + readerWriterBridge.bridgeEnvelopeAndHeaders(); + + Envelope env = (Envelope) soapPart.getEnvelope(); + env.setStaxBridge(readerWriterBridge); + return env; + } catch (Exception e) { + throw new SOAPException(e); + } + } + private static Envelope parseEnvelopeSax(Source src, SOAPPartImpl soapPart) + throws SOAPException { // Insert SAX filter to disallow Document Type Declarations since // they are not legal in SOAP SAXParser saxParser = null; if (src instanceof StreamSource) { - if (src instanceof JAXMStreamSource) { - try { - if (!SOAPPartImpl.lazyContentLength) { - ((JAXMStreamSource) src).reset(); - } - } catch (java.io.IOException ioe) { - log.severe("SAAJ0515.source.reset.exception"); - throw new SOAPExceptionImpl(ioe); - } - } try { saxParser = parserPool.get(); } catch (Exception e) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java new file mode 100644 index 00000000000..1f83ca5cfde --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/LazyEnvelope.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005, 2014, 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. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +public interface LazyEnvelope extends Envelope { + public XMLStreamReader getPayloadReader() throws SOAPException; + public boolean isLazy(); + public void writeTo(XMLStreamWriter writer) throws XMLStreamException, SOAPException; + + /** + * Retrieve payload qname without materializing its contents + * @return + * @throws SOAPException + */ + public QName getPayloadQName() throws SOAPException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param localName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(String localName) throws SOAPException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param qName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(QName qName) throws SOAPException; +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java index 9caff62d096..d7a0226671b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -29,6 +29,7 @@ import java.io.*; import java.util.logging.Logger; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ContentType; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ParseException; @@ -66,12 +67,44 @@ public class MessageFactoryImpl extends MessageFactory { throw new UnsupportedOperationException(); } + public SOAPMessage createMessage(String protocol) throws SOAPException { + if (SOAPConstants.SOAP_1_1_PROTOCOL.equals(protocol)) + return new com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl(); + else + return new com.sun.xml.internal.messaging.saaj.soap.ver1_2.Message1_2Impl(); + } + public SOAPMessage createMessage(boolean isFastInfoset, boolean acceptFastInfoset) throws SOAPException { throw new UnsupportedOperationException(); } + public SOAPMessage createMessage(MimeHeaders headers, XMLStreamReader reader) throws SOAPException, IOException { + String contentTypeString = MessageImpl.getContentType(headers); + + if (listener != null) { + throw new SOAPException("Listener OutputStream is not supported with XMLStreamReader"); + } + + try { + ContentType contentType = new ContentType(contentTypeString); + int stat = MessageImpl.identifyContentType(contentType); + + if (MessageImpl.isSoap1_1Content(stat)) { + return new Message1_1Impl(headers,contentType,stat,reader); + } else if (MessageImpl.isSoap1_2Content(stat)) { + return new Message1_2Impl(headers,contentType,stat,reader); + } else { + log.severe("SAAJ0530.soap.unknown.Content-Type"); + throw new SOAPExceptionImpl("Unrecognized Content-Type"); + } + } catch (ParseException e) { + log.severe("SAAJ0531.soap.cannot.parse.Content-Type"); + throw new SOAPExceptionImpl( + "Unable to parse content type: " + e.getMessage()); + } + } public SOAPMessage createMessage(MimeHeaders headers, InputStream in) throws SOAPException, IOException { String contentTypeString = MessageImpl.getContentType(headers); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java index 5a5405ce91e..e9691568d5e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,9 @@ import java.util.logging.Logger; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import com.sun.xml.internal.messaging.saaj.packaging.mime.Header; @@ -110,6 +112,8 @@ public abstract class MessageImpl private InputStream inputStreamAfterSaveChanges = null; + public static final String LAZY_SOAP_BODY_PARSING = "saaj.lazy.soap.body"; + // switch back to old MimeMultipart incase of problem private static boolean switchOffBM = false; private static boolean switchOffLazyAttachment = false; @@ -341,7 +345,12 @@ public abstract class MessageImpl } - private void init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in) throws SOAPExceptionImpl { + public MessageImpl(MimeHeaders headers, ContentType ct, int stat, + XMLStreamReader reader) throws SOAPExceptionImpl { + init(headers, stat, ct, reader); + } + + private void init(MimeHeaders headers, int stat, final ContentType contentType, final Object input) throws SOAPExceptionImpl { this.headers = headers; try { @@ -382,20 +391,42 @@ public abstract class MessageImpl + " Expected: " + getExpectedContentType()); } - + InputStream in = null; + XMLStreamReader rdr = null; + if (input instanceof InputStream) { + in = (InputStream) input; + } else { + //is a StAX reader + rdr = (XMLStreamReader) input; + } if ((stat & PLAIN_XML_FLAG) != 0) { - if (isFastInfoset) { - getSOAPPart().setContent( - FastInfosetReflection.FastInfosetSource_new(in)); + if (in != null) { + if (isFastInfoset) { + getSOAPPart().setContent( + FastInfosetReflection.FastInfosetSource_new(in)); + } else { + initCharsetProperty(contentType); + getSOAPPart().setContent(new StreamSource(in)); + } } else { - initCharsetProperty(contentType); - getSOAPPart().setContent(new StreamSource(in)); + //is a StAX reader + if (isFastInfoset) { + //need to get FI stax reader + } else { + initCharsetProperty(contentType); + getSOAPPart().setContent(new StAXSource(rdr)); + } } } - else if ((stat & MIME_MULTIPART_FLAG) != 0) { + else if ((stat & MIME_MULTIPART_FLAG) != 0 && in == null) { + //only parse multipart in the inputstream case + //in stax reader case, we would be given the attachments separately + getSOAPPart().setContent(new StAXSource(rdr)); + } else if ((stat & MIME_MULTIPART_FLAG) != 0) { + final InputStream finalIn = in; DataSource ds = new DataSource() { public InputStream getInputStream() { - return in; + return finalIn; } public OutputStream getOutputStream() { @@ -487,7 +518,17 @@ public abstract class MessageImpl } } - if (soapPartInputStream == null && soapMessagePart != null) { + // findbugs correctly points out that we'd NPE instantiating + // the ContentType (just below here) if soapMessagePart were + // null. Hence are better off throwing a controlled exception + // at this point if it is null. + if (soapMessagePart == null) { + log.severe("SAAJ0510.soap.cannot.create.envelope"); + throw new SOAPExceptionImpl( + "Unable to create envelope from given source: SOAP part not found"); + } + + if (soapPartInputStream == null) { soapPartInputStream = soapMessagePart.getInputStream(); } @@ -541,6 +582,15 @@ public abstract class MessageImpl } } + public boolean isLazySoapBodyParsing() { + Object lazyParsingProp = getProperty(LAZY_SOAP_BODY_PARSING); + if (lazyParsingProp == null) return false; + if (lazyParsingProp instanceof Boolean) { + return ((Boolean) lazyParsingProp).booleanValue(); + } else { + return Boolean.valueOf(lazyParsingProp.toString()); + } + } public Object getProperty(String property) { return (String) properties.get(property); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java index 891342ab257..7dac69841a9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPDocumentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -107,11 +107,11 @@ public class SOAPDocumentImpl extends DocumentImpl implements SOAPDocument { } public org.w3c.dom.Text createTextNode(String data) { - return new TextImpl(this, data); + return new SOAPTextImpl(this, data); } public Comment createComment(String data) { - return new CommentImpl(this, data); + return new SOAPCommentImpl(this, data); } public CDATASection createCDATASection(String data) throws DOMException { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java index d30a316f06b..19cc1b4ec30 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/SOAPPartImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -245,12 +245,18 @@ public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument { * getBytes() is called on a ByteInputStream. */ if (!(is instanceof ByteInputStream)) { - ByteOutputStream bout = new ByteOutputStream(); - bout.write(is); + ByteOutputStream bout = null; + try { + bout = new ByteOutputStream(); + bout.write(is); - // source.setInputStream(new ByteInputStream(...)) - FastInfosetReflection.FastInfosetSource_setInputStream( - source, bout.newInputStream()); + // source.setInputStream(new ByteInputStream(...)) + FastInfosetReflection.FastInfosetSource_setInputStream( + source, bout.newInputStream()); + } finally { + if (bout != null) + bout.close(); + } } this.source = source; } @@ -811,4 +817,6 @@ public abstract class SOAPPartImpl extends SOAPPart implements SOAPDocument { public String getSourceCharsetEncoding() { return sourceCharsetEncoding; } + + public abstract String getSOAPNamespace(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java new file mode 100644 index 00000000000..cf014b15623 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxBridge.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import com.sun.xml.internal.org.jvnet.staxex.util.SaajStaxWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + + +/** + * StaxBridge builds Envelope using a XMLStreamReaderToXMLStreamWriter + * + * @author shih-chang.chen@oracle.com + */ +public abstract class StaxBridge { + protected SaajStaxWriter saajWriter; + protected XMLStreamReaderToXMLStreamWriter readerToWriter; + protected XMLStreamReaderToXMLStreamWriter.Breakpoint breakpoint; + + + public StaxBridge(SOAPPartImpl soapPart) throws SOAPException { + readerToWriter = new XMLStreamReaderToXMLStreamWriter(); + saajWriter = new SaajStaxWriter(soapPart.message, soapPart.getSOAPNamespace()); + } + + public void bridgeEnvelopeAndHeaders() throws XMLStreamException { + readerToWriter.bridge(breakpoint); + } + + public void bridgePayload() throws XMLStreamException { + readerToWriter.bridge(breakpoint); + } + + abstract public XMLStreamReader getPayloadReader(); + + abstract public QName getPayloadQName(); + + abstract public String getPayloadAttributeValue(String attName) ; + + abstract public String getPayloadAttributeValue(QName attName) ; +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java new file mode 100644 index 00000000000..07da44736bb --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxLazySourceBridge.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import com.sun.xml.internal.messaging.saaj.LazyEnvelopeSource; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + + +/** + * StaxBridge builds Envelope from LazyEnvelopeSource + * + * @author shih-chang.chen@oracle.com + */ +public class StaxLazySourceBridge extends StaxBridge { + private LazyEnvelopeSource lazySource; + + public StaxLazySourceBridge(LazyEnvelopeSource src, SOAPPartImpl soapPart) throws SOAPException { + super(soapPart); + lazySource = src; + final String soapEnvNS = soapPart.getSOAPNamespace(); + try { + breakpoint = new XMLStreamReaderToXMLStreamWriter.Breakpoint(src.readToBodyStarTag(), saajWriter) { + public boolean proceedAfterStartElement() { + if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ + return false; + } else + return true; + } + }; + } catch (XMLStreamException e) { + throw new SOAPException(e); + } + } + + @Override + public XMLStreamReader getPayloadReader() { + return lazySource.readPayload(); +// throw new UnsupportedOperationException(); + } + + @Override + public QName getPayloadQName() { + return lazySource.getPayloadQName(); + } + + @Override + public String getPayloadAttributeValue(String attName) { + if (lazySource.isPayloadStreamReader()) { + XMLStreamReader reader = lazySource.readPayload(); + if (reader.getEventType() == reader.START_ELEMENT) { + return reader.getAttributeValue(null, attName); + } + } + return null; + } + + @Override + public String getPayloadAttributeValue(QName attName) { + if (lazySource.isPayloadStreamReader()) { + XMLStreamReader reader = lazySource.readPayload(); + if (reader.getEventType() == reader.START_ELEMENT) { + return reader.getAttributeValue(attName.getNamespaceURI(), attName.getLocalPart()); + } + } + return null; + } + + public void bridgePayload() throws XMLStreamException { + //Assuming out is at Body + writePayloadTo(saajWriter); + } + + public void writePayloadTo(XMLStreamWriter writer) throws XMLStreamException { + lazySource.writePayloadTo(writer); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java new file mode 100644 index 00000000000..9010a88368d --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/StaxReaderBridge.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.messaging.saaj.soap; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamReader; + +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + +/** + * StaxBridge builds Envelope using a XMLStreamReaderToXMLStreamWriter + * + * @author shih-chang.chen@oracle.com + */ +public class StaxReaderBridge extends StaxBridge { + private XMLStreamReader in; + + public StaxReaderBridge(XMLStreamReader reader, SOAPPartImpl soapPart) throws SOAPException { + super(soapPart); + in = reader; + final String soapEnvNS = soapPart.getSOAPNamespace(); + breakpoint = new XMLStreamReaderToXMLStreamWriter.Breakpoint(reader, saajWriter) { + boolean seenBody = false; + boolean stopedAtBody = false; + public boolean proceedBeforeStartElement() { + if (stopedAtBody) return true; + if (seenBody) { + stopedAtBody = true; + return false; + } + if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ + seenBody = true; + } + return true; + } + }; + } + + public XMLStreamReader getPayloadReader() { + return in; + } + + public QName getPayloadQName() { + return (in.getEventType() == in.START_ELEMENT) ? in.getName() : null; + } + + public String getPayloadAttributeValue(String attName) { + return (in.getEventType() == in.START_ELEMENT) ? in.getAttributeValue(null, attName) : null; + } + + public String getPayloadAttributeValue(QName attName) { + return (in.getEventType() == in.START_ELEMENT) ? in.getAttributeValue(attName.getNamespaceURI(), attName.getLocalPart()) : null; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java index 562386156f6..e761588902d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/BodyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -31,14 +31,18 @@ import java.util.logging.Level; import javax.xml.namespace.QName; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; +import org.w3c.dom.Node; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; +import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; /** @@ -48,6 +52,9 @@ import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; */ public abstract class BodyImpl extends ElementImpl implements SOAPBody { private SOAPFault fault; +// private XMLStreamReaderToXMLStreamWriter staxBridge; + private StaxBridge staxBridge; + private boolean payloadStreamRead = false; protected BodyImpl(SOAPDocumentImpl ownerDoc, NameImpl bodyName) { super(ownerDoc, bodyName); @@ -136,13 +143,22 @@ public abstract class BodyImpl extends ElementImpl implements SOAPBody { } public boolean hasFault() { - initializeFault(); - return fault != null; + QName payloadQName = getPayloadQName(); + return getFaultQName().equals(payloadQName); + } + + private Object getFaultQName() { + return new QName(getNamespaceURI(), "Fault"); } public SOAPFault getFault() { - if (hasFault()) + if (hasFault()) { + if (fault == null) { + //initialize fault member + fault = (SOAPFault) getFirstChildElement(); + } return fault; + } return null; } @@ -322,4 +338,130 @@ public abstract class BodyImpl extends ElementImpl implements SOAPBody { return document; } + private void materializePayloadWrapException() { + try { + materializePayload(); + } catch (SOAPException e) { + throw new RuntimeException(e); + } + } + private void materializePayload() throws SOAPException { + if (staxBridge != null) { + if (payloadStreamRead) { + //the payload has already been read via stream reader and the + //stream has been exhausted already. Throw an + //exception since we are now trying to materialize as DOM and + //there is no stream left to read + throw new SOAPException("SOAPBody payload stream has been fully read - cannot materialize as DOM!"); + } + try { + staxBridge.bridgePayload(); + staxBridge = null; + payloadStreamRead = true; + } catch (XMLStreamException e) { + throw new SOAPException(e); + } + } + } + + @Override + public boolean hasChildNodes() { + boolean hasChildren = super.hasChildNodes(); + //to answer this question we need to know _whether_ we have at least one child + //So no need to materialize body if we already know we have a header child + if (!hasChildren) { + materializePayloadWrapException(); + } + return super.hasChildNodes(); + } + + @Override + public NodeList getChildNodes() { + materializePayloadWrapException(); + return super.getChildNodes(); + } + + @Override + public Node getFirstChild() { + Node child = super.getFirstChild(); + if (child == null) { + materializePayloadWrapException(); + } + return super.getFirstChild(); + } + + public Node getFirstChildNoMaterialize() { + return super.getFirstChild(); + } + + @Override + public Node getLastChild() { + materializePayloadWrapException(); + return super.getLastChild(); + } + + XMLStreamReader getPayloadReader() { + return staxBridge.getPayloadReader(); + } + + void setStaxBridge(StaxBridge bridge) { + this.staxBridge = bridge; + } + + StaxBridge getStaxBridge() { + return staxBridge; + } + + void setPayloadStreamRead() { + this.payloadStreamRead = true; + } + + QName getPayloadQName() { + if (staxBridge != null) { + return staxBridge.getPayloadQName(); + } else { + //not lazy - Just get first child element and return its name + Element elem = getFirstChildElement(); + if (elem != null) { + String ns = elem.getNamespaceURI(); + String pref = elem.getPrefix(); + String local = elem.getLocalName(); + if (pref != null) return new QName(ns, local, pref); + if (ns != null) return new QName(ns, local); + return new QName(local); + } + } + return null; + } + + String getPayloadAttributeValue(String attName) { + if (staxBridge != null) { + return staxBridge.getPayloadAttributeValue(attName); + } else { + //not lazy -Just get first child element and return its attribute + Element elem = getFirstChildElement(); + if (elem != null) { + return elem.getAttribute(localName); + } + } + return null; + } + + String getPayloadAttributeValue(QName attNAme) { + if (staxBridge != null) { + return staxBridge.getPayloadAttributeValue(attNAme); + } else { + //not lazy -Just get first child element and return its attribute + Element elem = getFirstChildElement(); + if (elem != null) { + return elem.getAttributeNS(attNAme.getNamespaceURI(), attNAme.getLocalPart()); + } + } + return null; + } + + public boolean isLazy() { + return (staxBridge != null && !payloadStreamRead); + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java index 475bdffd244..59288cd8388 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/ElementImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -51,7 +51,7 @@ public class ElementImpl public static final String XENC_NS = "http://www.w3.org/2001/04/xmlenc#".intern(); public static final String WSU_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd".intern(); - private AttributeManager encodingStyleAttribute = new AttributeManager(); + private transient AttributeManager encodingStyleAttribute = new AttributeManager(); protected QName elementQName; @@ -424,7 +424,32 @@ public class ElementImpl } + Element getFirstChildElement() { + Node child = getFirstChild(); + while (child != null) { + if (child instanceof Element) { + return ((Element) child); + } + child = child.getNextSibling(); + } + return null; + } + protected SOAPElement findChild(NameImpl name) { + Node eachChild = getFirstChild(); + while (eachChild != null) { + if (eachChild instanceof SOAPElement) { + SOAPElement eachChildSoap = (SOAPElement) eachChild; + if (eachChildSoap.getElementName().equals(name)) { + return eachChildSoap; + } + } + eachChild = eachChild.getNextSibling(); + } + return null; + } + + protected SOAPElement findAndConvertChildElement(NameImpl name) { Iterator eachChild = getChildElementNodes(); while (eachChild.hasNext()) { SOAPElement child = (SOAPElement) eachChild.next(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java index 68454737ec2..08412891f6a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/EnvelopeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -29,30 +29,36 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.util.Iterator; import java.util.logging.Level; -import org.w3c.dom.Document; import javax.xml.namespace.QName; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.sax.*; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; -import com.sun.xml.internal.messaging.saaj.soap.Envelope; +import com.sun.xml.internal.messaging.saaj.soap.LazyEnvelope; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; +import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; +import com.sun.xml.internal.messaging.saaj.soap.StaxLazySourceBridge; import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; +import com.sun.xml.internal.messaging.saaj.util.stax.LazyEnvelopeStaxReader; import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; +import com.sun.xml.internal.org.jvnet.staxex.util.DOMStreamReader; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; + /** * Our implementation of the SOAP envelope. * * @author Anil Vijendran (anil@sun.com) */ -public abstract class EnvelopeImpl extends ElementImpl implements Envelope { +public abstract class EnvelopeImpl extends ElementImpl implements LazyEnvelope { protected HeaderImpl header; protected BodyImpl body; String omitXmlDecl = "yes"; @@ -103,11 +109,9 @@ public abstract class EnvelopeImpl extends ElementImpl implements Envelope { NameImpl bodyName = getBodyName(prefix); HeaderImpl header = null; - SOAPElement firstChild = null; + SOAPElement firstChild = (SOAPElement) getFirstChildElement(); - Iterator eachChild = getChildElementNodes(); - if (eachChild.hasNext()) { - firstChild = (SOAPElement) eachChild.next(); + if (firstChild != null) { if (firstChild.getElementName().equals(headerName)) { log.severe("SAAJ0120.impl.header.already.exists"); throw new SOAPExceptionImpl("Can't add a header when one is already present."); @@ -254,6 +258,7 @@ public abstract class EnvelopeImpl extends ElementImpl implements Envelope { public void output(OutputStream out) throws IOException { try { +// materializeBody(); Transformer transformer = EfficientStreamingTransformer.newTransformer(); @@ -357,4 +362,77 @@ public abstract class EnvelopeImpl extends ElementImpl implements Envelope { + elementQName.getLocalPart() + " to " + newName.getLocalPart()); } + + @Override + public void setStaxBridge(StaxBridge bridge) throws SOAPException { + //set it on the body + ((BodyImpl) getBody()).setStaxBridge(bridge); + } + + @Override + public StaxBridge getStaxBridge() throws SOAPException { + return ((BodyImpl) getBody()).getStaxBridge(); + } + + @Override + public XMLStreamReader getPayloadReader() throws SOAPException { + return ((BodyImpl) getBody()).getPayloadReader(); + } + + @Override + public void writeTo(final XMLStreamWriter writer) throws XMLStreamException, SOAPException { + StaxBridge readBridge = this.getStaxBridge(); + if (readBridge != null && readBridge instanceof StaxLazySourceBridge) { +// StaxSoapWriteBridge writingBridge = new StaxSoapWriteBridge(this); +// writingBridge.write(writer); + final String soapEnvNS = this.getNamespaceURI(); + final DOMStreamReader reader = new DOMStreamReader(this); + XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); + writingBridge.bridge( new XMLStreamReaderToXMLStreamWriter.Breakpoint(reader, writer) { + public boolean proceedAfterStartElement() { + if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ + return false; + } else + return true; + } + });//bridgeToBodyStartTag + ((StaxLazySourceBridge)readBridge).writePayloadTo(writer); + writer.writeEndElement();//body + writer.writeEndElement();//env + writer.writeEndDocument(); + writer.flush(); + } else { + LazyEnvelopeStaxReader lazyEnvReader = new LazyEnvelopeStaxReader(this); + XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); + writingBridge.bridge(lazyEnvReader, writer); +// writingBridge.bridge(new XMLStreamReaderToXMLStreamWriter.Breakpoint(lazyEnvReader, writer)); + } + //Assume the staxBridge is exhausted now since we would have read the body reader + ((BodyImpl) getBody()).setPayloadStreamRead(); + } + + @Override + public QName getPayloadQName() throws SOAPException { + return ((BodyImpl) getBody()).getPayloadQName(); + } + + @Override + public String getPayloadAttributeValue(String localName) throws SOAPException { + return ((BodyImpl) getBody()).getPayloadAttributeValue(localName); + } + + @Override + public String getPayloadAttributeValue(QName qName) throws SOAPException { + return ((BodyImpl) getBody()).getPayloadAttributeValue(qName); + } + + @Override + public boolean isLazy() { + try { + return ((BodyImpl) getBody()).isLazy(); + } catch (SOAPException e) { + return false; + } + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java index c6f7bb8de52..218ce0a7f5c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/FaultImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,17 +70,17 @@ public abstract class FaultImpl extends ElementImpl implements SOAPFault { protected void findFaultCodeElement() { this.faultCodeElement = - (SOAPFaultElement) findChild(getFaultCodeName()); + (SOAPFaultElement) findAndConvertChildElement(getFaultCodeName()); } protected void findFaultActorElement() { this.faultActorElement = - (SOAPFaultElement) findChild(getFaultActorName()); + (SOAPFaultElement) findAndConvertChildElement(getFaultActorName()); } protected void findFaultStringElement() { this.faultStringElement = - (SOAPFaultElement) findChild(getFaultStringName()); + (SOAPFaultElement) findAndConvertChildElement(getFaultStringName()); } public void setFaultCode(String faultCode) throws SOAPException { @@ -162,7 +162,7 @@ public abstract class FaultImpl extends ElementImpl implements SOAPFault { protected void initializeDetail() { NameImpl detailName = getDetailName(); - detail = (Detail) findChild(detailName); + detail = (Detail) findAndConvertChildElement(detailName); } public Detail getDetail() { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java index 26b3291e79e..74fb2045959 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/HeaderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,6 +32,7 @@ import javax.xml.namespace.QName; import javax.xml.soap.*; import org.w3c.dom.Element; +import org.w3c.dom.Node; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPCommentImpl.java similarity index 95% rename from jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java rename to jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPCommentImpl.java index 8711b29bf92..c306beb74f9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/CommentImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPCommentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -37,7 +37,7 @@ import org.w3c.dom.Text; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; -public class CommentImpl +public class SOAPCommentImpl extends com.sun.org.apache.xerces.internal.dom.CommentImpl implements javax.xml.soap.Text, org.w3c.dom.Comment { @@ -47,7 +47,7 @@ public class CommentImpl protected static ResourceBundle rb = log.getResourceBundle(); - public CommentImpl(SOAPDocumentImpl ownerDoc, String text) { + public SOAPCommentImpl(SOAPDocumentImpl ownerDoc, String text) { super(ownerDoc, text); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPTextImpl.java similarity index 94% rename from jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java rename to jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPTextImpl.java index ce30ebee5cf..c088928ba90 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/TextImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/impl/SOAPTextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 javax.xml.soap.SOAPException; import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants; -public class TextImpl +public class SOAPTextImpl extends com.sun.org.apache.xerces.internal.dom.TextImpl implements javax.xml.soap.Text, org.w3c.dom.Text { @@ -41,7 +41,7 @@ public class TextImpl Logger.getLogger(LogDomainConstants.SOAP_IMPL_DOMAIN, "com.sun.xml.internal.messaging.saaj.soap.impl.LocalStrings"); - public TextImpl(SOAPDocumentImpl ownerDoc, String text) { + public SOAPTextImpl(SOAPDocumentImpl ownerDoc, String text) { super(ownerDoc, text); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java index 2f51b167c00..e52640fc399 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/Message1_1Impl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -35,6 +35,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ContentType; @@ -70,6 +71,11 @@ public class Message1_1Impl extends MessageImpl implements SOAPConstants { super(headers,ct,stat,in); } + public Message1_1Impl(MimeHeaders headers, ContentType ct, int stat, XMLStreamReader reader) + throws SOAPExceptionImpl { + super(headers,ct,stat,reader); + } + public SOAPPart getSOAPPart() { if (soapPartImpl == null) { soapPartImpl = new SOAPPart1_1Impl(this); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java index ebb038e042d..35a0d1025fd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_1/SOAPPart1_1Impl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -90,4 +90,9 @@ public class SOAPPart1_1Impl extends SOAPPartImpl implements SOAPConstants { return new SOAPPart1_1Impl(); } + @Override + public String getSOAPNamespace() { + return SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE; + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java index 5c08f028d0b..0733ebb68c3 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Fault1_2Impl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -284,7 +284,7 @@ public class Fault1_2Impl extends FaultImpl { } public String getFaultNode() { - SOAPElement faultNode = findChild(getFaultNodeName()); + SOAPElement faultNode = findAndConvertChildElement(getFaultNodeName()); if (faultNode == null) { return null; } @@ -292,7 +292,7 @@ public class Fault1_2Impl extends FaultImpl { } public void setFaultNode(String uri) throws SOAPException { - SOAPElement faultNode = findChild(getFaultNodeName()); + SOAPElement faultNode = findAndConvertChildElement(getFaultNodeName()); if (faultNode != null) { faultNode.detachNode(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java index 87401620028..b63c8ed4f55 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/Message1_2Impl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,6 +33,7 @@ import java.io.IOException; import java.io.InputStream; import javax.xml.soap.*; +import javax.xml.stream.XMLStreamReader; import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ContentType; @@ -63,6 +64,11 @@ public class Message1_2Impl extends MessageImpl implements SOAPConstants{ super(headers,ct,stat,in); } + public Message1_2Impl(MimeHeaders headers, ContentType ct, int stat, XMLStreamReader reader) + throws SOAPExceptionImpl { + super(headers,ct,stat,reader); + } + public SOAPPart getSOAPPart() { if (soapPartImpl == null) soapPartImpl = new SOAPPart1_2Impl(this); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java index e9681792a85..396c21fb06b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/ver1_2/SOAPPart1_2Impl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -87,4 +87,9 @@ public class SOAPPart1_2Impl extends SOAPPartImpl implements SOAPConstants{ return new SOAPPart1_2Impl(); } + @Override + public String getSOAPNamespace() { + return SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE; + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java index b2a440880cd..02580c00e4c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/JAXMStreamSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -47,9 +47,15 @@ public class JAXMStreamSource extends StreamSource { } else if (is instanceof ByteInputStream) { this.in = (ByteInputStream) is; } else { - ByteOutputStream bout = new ByteOutputStream(); - bout.write(is); - this.in = bout.newInputStream(); + ByteOutputStream bout = null; + try { + bout = new ByteOutputStream(); + bout.write(is); + this.in = bout.newInputStream(); + } finally { + if (bout != null) + bout.close(); + } } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java index 1f3be836648..b9c503c9f7f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/ParserPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -40,17 +40,15 @@ import org.xml.sax.SAXNotSupportedException; * Pool of SAXParser objects */ public class ParserPool { - private final BlockingQueue queue; + private final BlockingQueue queue; private SAXParserFactory factory; - private int capacity; public ParserPool(int capacity) { - this.capacity = capacity; - queue = new ArrayBlockingQueue(capacity); + queue = new ArrayBlockingQueue(capacity); //factory = SAXParserFactory.newInstance(); factory = new com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl(); factory.setNamespaceAware(true); - for (int i=0; i < capacity; i++) { + for (int i = 0; i < capacity; i++) { try { queue.put(factory.newSAXParser()); } catch (InterruptedException ex) { @@ -75,8 +73,8 @@ public class ParserPool { } - public void put(SAXParser parser) { - queue.offer(parser); + public boolean put(SAXParser parser) { + return queue.offer(parser); } public void returnParser(SAXParser saxParser) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java new file mode 100644 index 00000000000..c8765a4667c --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/util/stax/LazyEnvelopeStaxReader.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.messaging.saaj.util.stax; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.w3c.dom.Node; + +import com.sun.xml.internal.messaging.saaj.soap.impl.BodyImpl; +import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl; + +/** + * "Hybrid" reader which + * @author desagar + * + */ +public class LazyEnvelopeStaxReader extends com.sun.xml.internal.org.jvnet.staxex.util.DOMStreamReader { +// EnvelopeImpl env; + XMLStreamReader payloadReader = null; + boolean usePayloadReaderDelegate = false; + private QName bodyQName; + + public LazyEnvelopeStaxReader(EnvelopeImpl env) throws SOAPException, XMLStreamException { + super(env); +// this.env = env; + bodyQName = new QName(env.getNamespaceURI(), "Body"); + payloadReader = env.getStaxBridge().getPayloadReader(); + int eventType = getEventType(); + while (eventType != START_ELEMENT) { + eventType = nextTag(); + } + } + + public Object getProperty(String name) throws IllegalArgumentException { + if (usePayloadReaderDelegate) return payloadReader.getProperty(name); + return super.getProperty(name); + } + + public int next() throws XMLStreamException { +// boolean previouslyUsingPayloadReader = usePayloadReaderDelegate; + //call checkReaderStatus to advance to payloadReader if needed + checkReaderStatus(true); + + if (usePayloadReaderDelegate) return payloadReader.getEventType(); + + //if we just moved to payload reader, don't advance the pointer +// if (usePayloadReaderDelegate && !previouslyUsingPayloadReader) return payloadReader.getEventType(); + +// if (usePayloadReaderDelegate) return payloadReader.next(); + return getEventType(); + } + + public void require(int type, String namespaceURI, String localName) + throws XMLStreamException { + if (usePayloadReaderDelegate) payloadReader.require(type, namespaceURI, localName); + else super.require(type, namespaceURI, localName); + } + + public String getElementText() throws XMLStreamException { + if (usePayloadReaderDelegate) return payloadReader.getElementText(); + return super.getElementText(); + } + + public int nextTag() throws XMLStreamException { + if (usePayloadReaderDelegate) return payloadReader.nextTag(); + return super.nextTag(); + } + + public boolean hasNext() throws XMLStreamException { + checkReaderStatus(false); + boolean hasNext; + if (usePayloadReaderDelegate) { + hasNext = payloadReader.hasNext(); + } else { + hasNext = super.hasNext(); + } + + /*if (!hasNext && payloadReader != null) { + usePayloadReaderDelegate = true; + hasNext = payloadReader.hasNext(); + }*/ + return hasNext; + } + + private void checkReaderStatus(boolean advanceToNext) throws XMLStreamException { + //if we are using payloadReader, make sure it is not exhausted + //if it is, return to DOM based reader for remaining end elements (body and envelope) + if (usePayloadReaderDelegate) { + if (!payloadReader.hasNext()) { + usePayloadReaderDelegate = false; + } + } else if (START_ELEMENT == getEventType()) { + //if not on payload reader, check if we need to switch to payload reader + + //if the current event is the SOAP body element start, + //and the body is lazy, switch to the payload reader + if (bodyQName.equals(getName())) { + //if we are just switching to payload reader, don't advance...payload reader + //will already be on the first payload element + usePayloadReaderDelegate = true; + advanceToNext = false; + } + } + + if (advanceToNext) { + if (usePayloadReaderDelegate) { + payloadReader.next(); + } else { + super.next(); + } + } + } + + public void close() throws XMLStreamException { + if (usePayloadReaderDelegate) payloadReader.close(); + else super.close(); + } + + public String getNamespaceURI(String prefix) { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceURI(prefix); + return super.getNamespaceURI(prefix); + } + + public boolean isStartElement() { + if (usePayloadReaderDelegate) return payloadReader.isStartElement(); + return super.isStartElement(); + } + + public boolean isEndElement() { + if (usePayloadReaderDelegate) return payloadReader.isEndElement(); + return super.isEndElement(); + } + + public boolean isCharacters() { + if (usePayloadReaderDelegate) return payloadReader.isCharacters(); + return super.isEndElement(); + } + + public boolean isWhiteSpace() { + if (usePayloadReaderDelegate) return payloadReader.isWhiteSpace(); + return super.isWhiteSpace(); + } + + public String getAttributeValue(String namespaceURI, String localName) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeValue(namespaceURI, localName); + return super.getAttributeValue(namespaceURI, localName); + } + + public int getAttributeCount() { + if (usePayloadReaderDelegate) return payloadReader.getAttributeCount(); + return super.getAttributeCount(); + } + + public QName getAttributeName(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeName(index); + return super.getAttributeName(index); + } + + public String getAttributeNamespace(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeNamespace(index); + return super.getAttributeNamespace(index); + } + + public String getAttributeLocalName(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeLocalName(index); + return super.getAttributeLocalName(index); + } + + public String getAttributePrefix(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributePrefix(index); + return super.getAttributePrefix(index); + } + + public String getAttributeType(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeType(index); + return super.getAttributeType(index); + } + + public String getAttributeValue(int index) { + if (usePayloadReaderDelegate) return payloadReader.getAttributeValue(index); + return super.getAttributeValue(index); + } + + public boolean isAttributeSpecified(int index) { + if (usePayloadReaderDelegate) return payloadReader.isAttributeSpecified(index); + return super.isAttributeSpecified(index); + } + + public int getNamespaceCount() { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceCount(); + return super.getNamespaceCount(); + } + + public String getNamespacePrefix(int index) { + if (usePayloadReaderDelegate) return payloadReader.getNamespacePrefix(index); + return super.getNamespacePrefix(index); + } + + public String getNamespaceURI(int index) { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceURI(index); + return super.getNamespaceURI(index); + } + + public NamespaceContext getNamespaceContext() { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceContext(); + return super.getNamespaceContext(); + } + + public int getEventType() { + if (usePayloadReaderDelegate) return payloadReader.getEventType(); + return super.getEventType(); + } + + public String getText() { + if (usePayloadReaderDelegate) return payloadReader.getText(); + return super.getText(); + } + + public char[] getTextCharacters() { + if (usePayloadReaderDelegate) return payloadReader.getTextCharacters(); + return super.getTextCharacters(); + } + + public int getTextCharacters(int sourceStart, char[] target, + int targetStart, int length) throws XMLStreamException { + if (usePayloadReaderDelegate) return payloadReader.getTextCharacters(sourceStart, target, targetStart, + length); + return super.getTextCharacters(sourceStart, target, targetStart, length); + } + + public int getTextStart() { + if (usePayloadReaderDelegate) return payloadReader.getTextStart(); + return super.getTextStart(); + } + + public int getTextLength() { + if (usePayloadReaderDelegate) return payloadReader.getTextLength(); + return super.getTextLength(); + } + + public String getEncoding() { + if (usePayloadReaderDelegate) return payloadReader.getEncoding(); + return super.getEncoding(); + } + + public boolean hasText() { + if (usePayloadReaderDelegate) return payloadReader.hasText(); + return super.hasText(); + } + + public Location getLocation() { + if (usePayloadReaderDelegate) return payloadReader.getLocation(); + return super.getLocation(); + } + + public QName getName() { + if (usePayloadReaderDelegate) return payloadReader.getName(); + return super.getName(); + } + + public String getLocalName() { + if (usePayloadReaderDelegate) return payloadReader.getLocalName(); + return super.getLocalName(); + } + + public boolean hasName() { + if (usePayloadReaderDelegate) return payloadReader.hasName(); + return super.hasName(); + } + + public String getNamespaceURI() { + if (usePayloadReaderDelegate) return payloadReader.getNamespaceURI(); + return super.getNamespaceURI(); + } + + public String getPrefix() { + if (usePayloadReaderDelegate) return payloadReader.getPrefix(); + return super.getPrefix(); + } + + public String getVersion() { + if (usePayloadReaderDelegate) return payloadReader.getVersion(); + return super.getVersion(); + } + + public boolean isStandalone() { + if (usePayloadReaderDelegate) return payloadReader.isStandalone(); + return super.isStandalone(); + } + + public boolean standaloneSet() { + if (usePayloadReaderDelegate) return payloadReader.standaloneSet(); + return super.standaloneSet(); + } + + public String getCharacterEncodingScheme() { + if (usePayloadReaderDelegate) return payloadReader.getCharacterEncodingScheme(); + return super.getCharacterEncodingScheme(); + } + + public String getPITarget() { + if (usePayloadReaderDelegate) return payloadReader.getPITarget(); + return super.getPITarget(); + } + + public String getPIData() { + if (usePayloadReaderDelegate) return payloadReader.getPIData(); + return super.getPIData(); + } + + //make sure that message is not realized as a result of call + //to getFirstChild + protected Node getFirstChild(Node node) { + if (node instanceof BodyImpl) { + return ((BodyImpl) node).getFirstChildNoMaterialize(); + } else { + return node.getFirstChild(); + } + } + + protected Node getNextSibling(Node node) { + if (node instanceof BodyImpl) { + //body is not expected to have a next sibling - even if it does + //we would have to materialize the node to retrieve it. + //Since we don't want to materialize it right now, just return null + return null; + } + return node.getNextSibling(); + } + +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java index 2621bc48818..e81a24319bd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/CleanUpExecutorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -25,7 +25,7 @@ package com.sun.xml.internal.org.jvnet.mimepull; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; public abstract class CleanUpExecutorFactory { private static final String DEFAULT_PROPERTY_NAME = CleanUpExecutorFactory.class @@ -42,5 +42,5 @@ public abstract class CleanUpExecutorFactory { } } - public abstract Executor getExecutor(); + public abstract ScheduledExecutorService getScheduledExecutorService(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java index 23e54a0ac79..5eda7fe70a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/WeakDataFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -25,6 +25,8 @@ package com.sun.xml.internal.org.jvnet.mimepull; +import java.util.concurrent.TimeUnit; + import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -32,7 +34,7 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,6 +47,7 @@ import java.util.logging.Logger; final class WeakDataFile extends WeakReference { private static final Logger LOGGER = Logger.getLogger(WeakDataFile.class.getName()); + private static int TIMEOUT = 10; //milliseconds //private static final int MAX_ITERATIONS = 2; private static ReferenceQueue refQueue = new ReferenceQueue(); private static List refList = new ArrayList(); @@ -52,28 +55,22 @@ final class WeakDataFile extends WeakReference { private final RandomAccessFile raf; private static boolean hasCleanUpExecutor = false; static { + int delay = 10; + try { + delay = Integer.getInteger("com.sun.xml.internal.org.jvnet.mimepull.delay", 10); + } catch (SecurityException se) { + if (LOGGER.isLoggable(Level.CONFIG)) { + LOGGER.log(Level.CONFIG, "Cannot read ''{0}'' property, using defaults.", + new Object[] {"com.sun.xml.internal.org.jvnet.mimepull.delay"}); + } + } CleanUpExecutorFactory executorFactory = CleanUpExecutorFactory.newInstance(); if (executorFactory!=null) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Initializing clean up executor for MIMEPULL: {0}", executorFactory.getClass().getName()); } - Executor executor = executorFactory.getExecutor(); - executor.execute(new Runnable() { - @Override - public void run() { - WeakDataFile weak; - while (true) { - try { - weak = (WeakDataFile) refQueue.remove(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file); - } - weak.close(); - } catch (InterruptedException e) { - } - } - } - }); + ScheduledExecutorService scheduler = executorFactory.getScheduledExecutorService(); + scheduler.scheduleWithFixedDelay(new CleanupRunnable(), delay, delay, TimeUnit.SECONDS); hasCleanUpExecutor = true; } } @@ -157,4 +154,24 @@ final class WeakDataFile extends WeakReference { weak.close(); } } + +private static class CleanupRunnable implements Runnable { + @Override + public void run() { + try { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Running cleanup task"); + } + WeakDataFile weak = (WeakDataFile) refQueue.remove(TIMEOUT); + while (weak != null) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file); + } + weak.close(); + weak = (WeakDataFile) refQueue.remove(TIMEOUT); + } + } catch (InterruptedException e) { + } + } +} } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java index 62d6dcaab95..4fc6afdfa83 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/Base64Data.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -62,6 +62,7 @@ public class Base64Data implements CharSequence, Cloneable { private DataHandler dataHandler; private byte[] data; + private String hrefCid; /** * Length of the valid data in {@link #data}. @@ -531,4 +532,16 @@ public class Base64Data implements CharSequence, Cloneable { // // } + public String getHrefCid() { + if (hrefCid == null && dataHandler != null && dataHandler instanceof StreamingDataHandler) { + hrefCid = ((StreamingDataHandler)dataHandler).getHrefCid(); + } + return hrefCid; + } + + public void setHrefCid(final String cid) { + this.hrefCid = cid; + if (dataHandler != null && dataHandler instanceof StreamingDataHandler) ((StreamingDataHandler)dataHandler).setHrefCid(cid); + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java new file mode 100644 index 00000000000..d3f5e887b34 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/BinaryText.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex; + +import javax.activation.DataHandler; +import javax.xml.soap.SOAPException; +import javax.xml.soap.Text; + +/** + * BinaryText represents a MTOM attachment. + * + * @author shih-chang.chen@oracle.com + */ +public interface BinaryText extends Text { + public String getHref(); + public DataHandler getDataHandler() throws SOAPException; +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java new file mode 100644 index 00000000000..d3ce3ef7bbd --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/MtomEnabled.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex; + +import javax.activation.DataHandler; + +/** + * A SOAPElement implementation may support this interface to allow MTOM attachments. + * + * @author shih-chang.chen@oracle.com + */ +public interface MtomEnabled { + BinaryText addBinaryText(byte[] bytes); + BinaryText addBinaryText(String contentType, byte[] bytes); + BinaryText addBinaryText(String href, DataHandler dl); +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java new file mode 100644 index 00000000000..ff1b1f8713c --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StAxSOAPBody.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +/** + * A StAxSOAPBody is a SOAPBody that allows to be loaded from a StAX style payload. + * + * @author shih-chang.chen@oracle.com + */ +public interface StAxSOAPBody { + + /** + * The StAxSOAPBody represents the StAX source of SOAPBody payload. + */ + public static interface Payload { + + /** + * Retrieve payload qname without materializing its contents + * @return + * @throws SOAPException + */ + public QName getPayloadQName(); + + public XMLStreamReader readPayload() throws XMLStreamException; + + public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param localName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(String localName) throws XMLStreamException; + + /** + * Retrieve payload attribute value without materializing its contents + * @param qName + * @return + * @throws SOAPException + */ + public String getPayloadAttributeValue(QName qName) throws XMLStreamException; + + public void materialize() throws SOAPException; + } + + public void setPayload(Payload src) throws SOAPException; + + public Payload getPayload()throws SOAPException; + + public boolean hasStaxPayload(); + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java index 409cea5c67e..dda4a38f36a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/StreamingDataHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2014, 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 @@ -52,6 +52,8 @@ import java.net.URL; */ public abstract class StreamingDataHandler extends DataHandler implements Closeable { + private String hrefCid; + public StreamingDataHandler(Object o, String s) { super(o, s); } @@ -142,4 +144,11 @@ public abstract class StreamingDataHandler extends DataHandler implements Closea */ public abstract void close() throws IOException; + public String getHrefCid() { + return hrefCid; + } + + public void setHrefCid(final String cid) { + this.hrefCid = cid; + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java new file mode 100644 index 00000000000..74b73f7f0ca --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DOMStreamReader.java @@ -0,0 +1,895 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import static org.w3c.dom.Node.*; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.Collections; +import java.util.Iterator; + +/** + * Create an {@link XMLStreamReader} on top of a DOM tree. + * + *

+ * Since various libraries as well as users often create "incorrect" DOM node, + * this class spends a lot of efforts making sure that broken DOM trees are + * nevertheless interpreted correctly. + * + *

+ * For example, if a DOM level + * 1 tree is passed, each method will attempt to return the correct value + * by using {@link Node#getNodeName()}. + * + *

+ * Similarly, if DOM is missing explicit namespace declarations, + * this class attempts to emulate necessary declarations. + * + * + * @author Santiago.PericasGeertsen@sun.com + * @author Kohsuke Kawaguchi + */ +public class DOMStreamReader implements XMLStreamReader, NamespaceContext { + + /** + * Current DOM node being traversed. + */ + protected Node _current; + + /** + * Starting node of the subtree being traversed. + */ + private Node _start; + + /** + * Named mapping for attributes and NS decls for the current node. + */ + private NamedNodeMap _namedNodeMap; + + /** + * If the reader points at {@link #CHARACTERS the text node}, + * its whole value. + * + *

+ * This is simply a cache of {@link Text#getWholeText()} of {@link #_current}, + * but when a large binary data sent as base64 text, this could get very much + * non-trivial. + */ + protected String wholeText; + + /** + * List of attributes extracted from _namedNodeMap. + */ + private final FinalArrayList _currentAttributes = new FinalArrayList(); + + /** + * {@link Scope} buffer. + */ + protected Scope[] scopes = new Scope[8]; + + /** + * Depth of the current element. The first element gets depth==0. + * Also used as the index to {@link #scopes}. + */ + protected int depth = 0; + + /** + * State of this reader. Any of the valid states defined in StAX' + * XMLStreamConstants class. + */ + protected int _state; + + /** + * Namespace declarations on one element. + * + * Instances are reused. + */ + protected static final class Scope { + /** + * Scope for the parent element. + */ + final Scope parent; + + /** + * List of namespace declarations extracted from _namedNodeMap + */ + final FinalArrayList currentNamespaces = new FinalArrayList(); + + /** + * Additional namespace declarations obtained as a result of "fixing" DOM tree, + * which were not part of the original DOM tree. + * + * One entry occupies two spaces (prefix followed by URI.) + */ + final FinalArrayList additionalNamespaces = new FinalArrayList(); + + Scope(Scope parent) { + this.parent = parent; + } + + void reset() { + currentNamespaces.clear(); + additionalNamespaces.clear(); + } + + int getNamespaceCount() { + return currentNamespaces.size()+additionalNamespaces.size()/2; + } + + String getNamespacePrefix(int index) { + int sz = currentNamespaces.size(); + if(index< sz) { + Attr attr = currentNamespaces.get(index); + String result = attr.getLocalName(); + if (result == null) { + result = QName.valueOf(attr.getNodeName()).getLocalPart(); + } + return result.equals("xmlns") ? null : result; + } else { + return additionalNamespaces.get((index-sz)*2); + } + } + + String getNamespaceURI(int index) { + int sz = currentNamespaces.size(); + if(index< sz) { + return currentNamespaces.get(index).getValue(); + } else { + return additionalNamespaces.get((index-sz)*2+1); + } + } + + /** + * Returns the prefix bound to the given URI, or null. + * This method recurses to the parent. + */ + String getPrefix(String nsUri) { + for( Scope sp=this; sp!=null; sp=sp.parent ) { + for( int i=sp.currentNamespaces.size()-1; i>=0; i--) { + String result = getPrefixForAttr(sp.currentNamespaces.get(i),nsUri); + if(result!=null) + return result; + } + for( int i=sp.additionalNamespaces.size()-2; i>=0; i-=2 ) + if(sp.additionalNamespaces.get(i+1).equals(nsUri)) + return sp.additionalNamespaces.get(i); + } + return null; + } + + /** + * Returns the namespace URI bound by the given prefix. + * + * @param prefix + * Prefix to look up. + */ + String getNamespaceURI(String prefix) { + String nsDeclName = prefix.length()==0 ? "xmlns" : "xmlns:"+prefix; + + for( Scope sp=this; sp!=null; sp=sp.parent ) { + for( int i=sp.currentNamespaces.size()-1; i>=0; i--) { + Attr a = sp.currentNamespaces.get(i); + if(a.getNodeName().equals(nsDeclName)) + return a.getValue(); + } + for( int i=sp.additionalNamespaces.size()-2; i>=0; i-=2 ) + if(sp.additionalNamespaces.get(i).equals(prefix)) + return sp.additionalNamespaces.get(i+1); + } + return null; + } + } + + + public DOMStreamReader() { + } + + public DOMStreamReader(Node node) { + setCurrentNode(node); + } + + public void setCurrentNode(Node node) { + scopes[0] = new Scope(null); + depth=0; + + _start = _current = node; + _state = START_DOCUMENT; + // verifyDOMIntegrity(node); + // displayDOM(node, System.out); + } + + public void close() throws XMLStreamException { + } + + /** + * Called when the current node is {@link Element} to look at attribute list + * (which contains both ns decl and attributes in DOM) and split them + * to attributes-proper and namespace decls. + */ + protected void splitAttributes() { + // Clear attribute and namespace lists + _currentAttributes.clear(); + + Scope scope = allocateScope(); + + _namedNodeMap = _current.getAttributes(); + if (_namedNodeMap != null) { + final int n = _namedNodeMap.getLength(); + for (int i = 0; i < n; i++) { + final Attr attr = (Attr) _namedNodeMap.item(i); + final String attrName = attr.getNodeName(); + if (attrName.startsWith("xmlns:") || attrName.equals("xmlns")) { // NS decl? + scope.currentNamespaces.add(attr); + } + else { + _currentAttributes.add(attr); + } + } + } + + // verify that all the namespaces used in element and attributes are indeed available + ensureNs(_current); + for( int i=_currentAttributes.size()-1; i>=0; i-- ) { + Attr a = _currentAttributes.get(i); + if(fixNull(a.getNamespaceURI()).length()>0) + ensureNs(a); // no need to declare "" for attributes in the default namespace + } + } + + /** + * Sub-routine of {@link #splitAttributes()}. + * + *

+ * Makes sure that the namespace URI/prefix used in the given node is available, + * and if not, declare it on the current scope to "fix" it. + * + * It's often common to create DOM trees without putting namespace declarations, + * and this makes sure that such DOM tree will be properly marshalled. + */ + private void ensureNs(Node n) { + String prefix = fixNull(n.getPrefix()); + String uri = fixNull(n.getNamespaceURI()); + + Scope scope = scopes[depth]; + + String currentUri = scope.getNamespaceURI(prefix); + + if(prefix.length()==0) { + currentUri = fixNull(currentUri); + if(currentUri.equals(uri)) + return; // declared correctly + } else { + if(currentUri!=null && currentUri.equals(uri)) + return; // declared correctly + } + + if(prefix.equals("xml") || prefix.equals("xmlns")) + return; // implicitly declared namespaces + + // needs to be declared + scope.additionalNamespaces.add(prefix); + scope.additionalNamespaces.add(uri); + } + + /** + * Allocate new {@link Scope} for {@link #splitAttributes()}. + */ + private Scope allocateScope() { + if(scopes.length==++depth) { + Scope[] newBuf = new Scope[scopes.length*2]; + System.arraycopy(scopes,0,newBuf,0,scopes.length); + scopes = newBuf; + } + Scope scope = scopes[depth]; + if(scope==null) { + scope = scopes[depth] = new Scope(scopes[depth-1]); + } else { + scope.reset(); + } + return scope; + } + + public int getAttributeCount() { + if (_state == START_ELEMENT) + return _currentAttributes.size(); + throw new IllegalStateException("DOMStreamReader: getAttributeCount() called in illegal state"); + } + + /** + * Return an attribute's local name. Handle the case of DOM level 1 nodes. + */ + public String getAttributeLocalName(int index) { + if (_state == START_ELEMENT) { + String localName = _currentAttributes.get(index).getLocalName(); + return (localName != null) ? localName : + QName.valueOf(_currentAttributes.get(index).getNodeName()).getLocalPart(); + } + throw new IllegalStateException("DOMStreamReader: getAttributeLocalName() called in illegal state"); + } + + /** + * Return an attribute's qname. Handle the case of DOM level 1 nodes. + */ + public QName getAttributeName(int index) { + if (_state == START_ELEMENT) { + Node attr = _currentAttributes.get(index); + String localName = attr.getLocalName(); + if (localName != null) { + String prefix = attr.getPrefix(); + String uri = attr.getNamespaceURI(); + return new QName(fixNull(uri), localName, fixNull(prefix)); + } + else { + return QName.valueOf(attr.getNodeName()); + } + } + throw new IllegalStateException("DOMStreamReader: getAttributeName() called in illegal state"); + } + + public String getAttributeNamespace(int index) { + if (_state == START_ELEMENT) { + String uri = _currentAttributes.get(index).getNamespaceURI(); + return fixNull(uri); + } + throw new IllegalStateException("DOMStreamReader: getAttributeNamespace() called in illegal state"); + } + + public String getAttributePrefix(int index) { + if (_state == START_ELEMENT) { + String prefix = _currentAttributes.get(index).getPrefix(); + return fixNull(prefix); + } + throw new IllegalStateException("DOMStreamReader: getAttributePrefix() called in illegal state"); + } + + public String getAttributeType(int index) { + if (_state == START_ELEMENT) { + return "CDATA"; + } + throw new IllegalStateException("DOMStreamReader: getAttributeType() called in illegal state"); + } + + public String getAttributeValue(int index) { + if (_state == START_ELEMENT) { + return _currentAttributes.get(index).getNodeValue(); + } + throw new IllegalStateException("DOMStreamReader: getAttributeValue() called in illegal state"); + } + + public String getAttributeValue(String namespaceURI, String localName) { + if (_state == START_ELEMENT) { + if (_namedNodeMap != null) { + Node attr = _namedNodeMap.getNamedItemNS(namespaceURI, localName); + return attr != null ? attr.getNodeValue() : null; + } + return null; + } + throw new IllegalStateException("DOMStreamReader: getAttributeValue() called in illegal state"); + } + + public String getCharacterEncodingScheme() { + return null; + } + + public String getElementText() throws javax.xml.stream.XMLStreamException { + throw new RuntimeException("DOMStreamReader: getElementText() not implemented"); + } + + public String getEncoding() { + return null; + } + + public int getEventType() { + return _state; + } + + /** + * Return an element's local name. Handle the case of DOM level 1 nodes. + */ + public String getLocalName() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String localName = _current.getLocalName(); + return localName != null ? localName : + QName.valueOf(_current.getNodeName()).getLocalPart(); + } + else if (_state == ENTITY_REFERENCE) { + return _current.getNodeName(); + } + throw new IllegalStateException("DOMStreamReader: getAttributeValue() called in illegal state"); + } + + public Location getLocation() { + return DummyLocation.INSTANCE; + } + + /** + * Return an element's qname. Handle the case of DOM level 1 nodes. + */ + public javax.xml.namespace.QName getName() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String localName = _current.getLocalName(); + if (localName != null) { + String prefix = _current.getPrefix(); + String uri = _current.getNamespaceURI(); + return new QName(fixNull(uri), localName, fixNull(prefix)); + } + else { + return QName.valueOf(_current.getNodeName()); + } + } + throw new IllegalStateException("DOMStreamReader: getName() called in illegal state"); + } + + public NamespaceContext getNamespaceContext() { + return this; + } + + /** + * Verifies the current state to see if we can return the scope, and do so + * if appropriate. + * + * Used to implement a bunch of StAX API methods that have the same usage restriction. + */ + private Scope getCheckedScope() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + return scopes[depth]; + } + throw new IllegalStateException("DOMStreamReader: neither on START_ELEMENT nor END_ELEMENT"); + } + + public int getNamespaceCount() { + return getCheckedScope().getNamespaceCount(); + } + + public String getNamespacePrefix(int index) { + return getCheckedScope().getNamespacePrefix(index); + } + + public String getNamespaceURI(int index) { + return getCheckedScope().getNamespaceURI(index); + } + + public String getNamespaceURI() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String uri = _current.getNamespaceURI(); + return fixNull(uri); + } + return null; + } + + /** + * This method is not particularly fast, but shouldn't be called very + * often. If we start to use it more, we should keep track of the + * NS declarations using a NamespaceContext implementation instead. + */ + public String getNamespaceURI(String prefix) { + if (prefix == null) { + throw new IllegalArgumentException("DOMStreamReader: getNamespaceURI(String) call with a null prefix"); + } + else if (prefix.equals("xml")) { + return "http://www.w3.org/XML/1998/namespace"; + } + else if (prefix.equals("xmlns")) { + return "http://www.w3.org/2000/xmlns/"; + } + + // check scopes + String nsUri = scopes[depth].getNamespaceURI(prefix); + if(nsUri!=null) return nsUri; + + // then ancestors above start node + Node node = findRootElement(); + String nsDeclName = prefix.length()==0 ? "xmlns" : "xmlns:"+prefix; + while (node.getNodeType() != DOCUMENT_NODE) { + // Is ns declaration on this element? + NamedNodeMap namedNodeMap = node.getAttributes(); + Attr attr = (Attr) namedNodeMap.getNamedItem(nsDeclName); + if (attr != null) + return attr.getValue(); + node = node.getParentNode(); + } + return null; + } + + public String getPrefix(String nsUri) { + if (nsUri == null) { + throw new IllegalArgumentException("DOMStreamReader: getPrefix(String) call with a null namespace URI"); + } + else if (nsUri.equals("http://www.w3.org/XML/1998/namespace")) { + return "xml"; + } + else if (nsUri.equals("http://www.w3.org/2000/xmlns/")) { + return "xmlns"; + } + + // check scopes + String prefix = scopes[depth].getPrefix(nsUri); + if(prefix!=null) return prefix; + + // then ancestors above start node + Node node = findRootElement(); + + while (node.getNodeType() != DOCUMENT_NODE) { + // Is ns declaration on this element? + NamedNodeMap namedNodeMap = node.getAttributes(); + for( int i=namedNodeMap.getLength()-1; i>=0; i-- ) { + Attr attr = (Attr)namedNodeMap.item(i); + prefix = getPrefixForAttr(attr,nsUri); + if(prefix!=null) + return prefix; + } + node = node.getParentNode(); + } + return null; + } + + /** + * Finds the root element node of the traversal. + */ + private Node findRootElement() { + int type; + + Node node = _start; + while ((type = node.getNodeType()) != DOCUMENT_NODE + && type != ELEMENT_NODE) { + node = node.getParentNode(); + } + return node; + } + + /** + * If the given attribute is a namespace declaration for the given namespace URI, + * return its prefix. Otherwise null. + */ + private static String getPrefixForAttr(Attr attr, String nsUri) { + String attrName = attr.getNodeName(); + if (!attrName.startsWith("xmlns:") && !attrName.equals("xmlns")) + return null; // not nsdecl + + if(attr.getValue().equals(nsUri)) { + if(attrName.equals("xmlns")) + return ""; + String localName = attr.getLocalName(); + return (localName != null) ? localName : + QName.valueOf(attrName).getLocalPart(); + } + + return null; + } + + public Iterator getPrefixes(String nsUri) { + // This is an incorrect implementation, + // but AFAIK it's not used in the JAX-WS runtime + String prefix = getPrefix(nsUri); + if(prefix==null) return Collections.emptyList().iterator(); + else return Collections.singletonList(prefix).iterator(); + } + + public String getPIData() { + if (_state == PROCESSING_INSTRUCTION) { + return ((ProcessingInstruction) _current).getData(); + } + return null; + } + + public String getPITarget() { + if (_state == PROCESSING_INSTRUCTION) { + return ((ProcessingInstruction) _current).getTarget(); + } + return null; + } + + public String getPrefix() { + if (_state == START_ELEMENT || _state == END_ELEMENT) { + String prefix = _current.getPrefix(); + return fixNull(prefix); + } + return null; + } + + public Object getProperty(String str) throws IllegalArgumentException { + return null; + } + + public String getText() { + if (_state == CHARACTERS) + return wholeText; + if(_state == CDATA || _state == COMMENT || _state == ENTITY_REFERENCE) + return _current.getNodeValue(); + throw new IllegalStateException("DOMStreamReader: getTextLength() called in illegal state"); + } + + public char[] getTextCharacters() { + return getText().toCharArray(); + } + + public int getTextCharacters(int sourceStart, char[] target, int targetStart, + int targetLength) throws XMLStreamException { + String text = getText(); + int copiedSize = Math.min(targetLength, text.length() - sourceStart); + text.getChars(sourceStart, sourceStart + copiedSize, target, targetStart); + + return copiedSize; + } + + public int getTextLength() { + return getText().length(); + } + + public int getTextStart() { + if (_state == CHARACTERS || _state == CDATA || _state == COMMENT || _state == ENTITY_REFERENCE) { + return 0; + } + throw new IllegalStateException("DOMStreamReader: getTextStart() called in illegal state"); + } + + public String getVersion() { + return null; + } + + public boolean hasName() { + return (_state == START_ELEMENT || _state == END_ELEMENT); + } + + public boolean hasNext() throws javax.xml.stream.XMLStreamException { + return (_state != END_DOCUMENT); + } + + public boolean hasText() { + if (_state == CHARACTERS || _state == CDATA || _state == COMMENT || _state == ENTITY_REFERENCE) { + return getText().trim().length() > 0; + } + return false; + } + + public boolean isAttributeSpecified(int param) { + return false; + } + + public boolean isCharacters() { + return (_state == CHARACTERS); + } + + public boolean isEndElement() { + return (_state == END_ELEMENT); + } + + public boolean isStandalone() { + return true; + } + + public boolean isStartElement() { + return (_state == START_ELEMENT); + } + + public boolean isWhiteSpace() { + if (_state == CHARACTERS || _state == CDATA) + return getText().trim().length()==0; + return false; + } + + private static int mapNodeTypeToState(int nodetype) { + switch (nodetype) { + case CDATA_SECTION_NODE: + return CDATA; + case COMMENT_NODE: + return COMMENT; + case ELEMENT_NODE: + return START_ELEMENT; + case ENTITY_NODE: + return ENTITY_DECLARATION; + case ENTITY_REFERENCE_NODE: + return ENTITY_REFERENCE; + case NOTATION_NODE: + return NOTATION_DECLARATION; + case PROCESSING_INSTRUCTION_NODE: + return PROCESSING_INSTRUCTION; + case TEXT_NODE: + return CHARACTERS; + default: + throw new RuntimeException("DOMStreamReader: Unexpected node type"); + } + } + + public int next() throws XMLStreamException { + while(true) { + int r = _next(); + switch (r) { + case CHARACTERS: + // if we are currently at text node, make sure that this is a meaningful text node. + Node prev = _current.getPreviousSibling(); + if(prev!=null && prev.getNodeType()==Node.TEXT_NODE) + continue; // nope. this is just a continuation of previous text that should be invisible + + Text t = (Text)_current; + wholeText = t.getWholeText(); + if(wholeText.length()==0) + continue; // nope. this is empty text. + return CHARACTERS; + case START_ELEMENT: + splitAttributes(); + return START_ELEMENT; + default: + return r; + } + } + } + + protected int _next() throws XMLStreamException { + Node child; + + switch (_state) { + case END_DOCUMENT: + throw new IllegalStateException("DOMStreamReader: Calling next() at END_DOCUMENT"); + case START_DOCUMENT: + // Don't skip document element if this is a fragment + if (_current.getNodeType() == ELEMENT_NODE) { + return (_state = START_ELEMENT); + } + + child = _current.getFirstChild(); + if (child == null) { + return (_state = END_DOCUMENT); + } + else { + _current = child; + return (_state = mapNodeTypeToState(_current.getNodeType())); + } + case START_ELEMENT: + child = _current.getFirstChild(); + if (child == null) { + return (_state = END_ELEMENT); + } + else { + _current = child; + return (_state = mapNodeTypeToState(_current.getNodeType())); + } + case END_ELEMENT: + case CHARACTERS: + case COMMENT: + case CDATA: + case ENTITY_REFERENCE: + case PROCESSING_INSTRUCTION: + if (_state == END_ELEMENT) depth--; + // If at the end of this fragment, then terminate traversal + if (_current == _start) { + return (_state = END_DOCUMENT); + } + + Node sibling = _current.getNextSibling(); + if (sibling == null) { + _current = _current.getParentNode(); + // getParentNode() returns null for fragments + _state = (_current == null || _current.getNodeType() == DOCUMENT_NODE) ? + END_DOCUMENT : END_ELEMENT; + return _state; + } + else { + _current = sibling; + return (_state = mapNodeTypeToState(_current.getNodeType())); + } + case DTD: + case ATTRIBUTE: + case NAMESPACE: + default: + throw new RuntimeException("DOMStreamReader: Unexpected internal state"); + } + } + + public int nextTag() throws javax.xml.stream.XMLStreamException { + int eventType = next(); + while (eventType == CHARACTERS && isWhiteSpace() + || eventType == CDATA && isWhiteSpace() + || eventType == SPACE + || eventType == PROCESSING_INSTRUCTION + || eventType == COMMENT) + { + eventType = next(); + } + if (eventType != START_ELEMENT && eventType != END_ELEMENT) { + throw new XMLStreamException("DOMStreamReader: Expected start or end tag"); + } + return eventType; + } + + public void require(int type, String namespaceURI, String localName) + throws javax.xml.stream.XMLStreamException + { + if (type != _state) { + throw new XMLStreamException("DOMStreamReader: Required event type not found"); + } + if (namespaceURI != null && !namespaceURI.equals(getNamespaceURI())) { + throw new XMLStreamException("DOMStreamReader: Required namespaceURI not found"); + } + if (localName != null && !localName.equals(getLocalName())) { + throw new XMLStreamException("DOMStreamReader: Required localName not found"); + } + } + + public boolean standaloneSet() { + return true; + } + + + + // -- Debugging ------------------------------------------------------ +/* + private static void displayDOM(Node node, java.io.OutputStream ostream) { + try { + System.out.println("\n====\n"); + XmlUtil.newTransformer().transform( + new DOMSource(node), new StreamResult(ostream)); + System.out.println("\n====\n"); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void verifyDOMIntegrity(Node node) { + switch (node.getNodeType()) { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + + // DOM level 1? + if (node.getLocalName() == null) { + System.out.println("WARNING: DOM level 1 node found"); + System.out.println(" -> node.getNodeName() = " + node.getNodeName()); + System.out.println(" -> node.getNamespaceURI() = " + node.getNamespaceURI()); + System.out.println(" -> node.getLocalName() = " + node.getLocalName()); + System.out.println(" -> node.getPrefix() = " + node.getPrefix()); + } + + if (node.getNodeType() == ATTRIBUTE_NODE) return; + + NamedNodeMap attrs = node.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + verifyDOMIntegrity(attrs.item(i)); + } + case DOCUMENT_NODE: + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + verifyDOMIntegrity(children.item(i)); + } + } + } +*/ + + private static String fixNull(String s) { + if(s==null) return ""; + else return s; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java new file mode 100644 index 00000000000..8bcd3b83584 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/DummyLocation.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import javax.xml.stream.Location; + +/** + * {@link Location} that returns no info. + * + * @author Santiago.PericasGeertsen@sun.com + */ +public final class DummyLocation implements Location { + private DummyLocation() {} + + public static final Location INSTANCE = new DummyLocation(); + + public int getCharacterOffset() { + return -1; + } + public int getColumnNumber() { + return -1; + } + public int getLineNumber() { + return -1; + } + public String getPublicId() { + return null; + } + public String getSystemId() { + return null; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java new file mode 100644 index 00000000000..1c1eedbaa86 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/FinalArrayList.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * {@link ArrayList} with a final marker to help JIT. + * @author Kohsuke Kawaguchi + */ +public final class FinalArrayList extends ArrayList { + public FinalArrayList(int initialCapacity) { + super(initialCapacity); + } + + public FinalArrayList() { + } + + public FinalArrayList(Collection collection) { + super(collection); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java new file mode 100644 index 00000000000..a3435408de8 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/MtomStreamWriter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.stream.XMLStreamWriter; + +/** + * A {@link XMLStreamWriter} that used for MTOM encoding may provide its own + * {@link AttachmentMarshaller}. The marshaller could do processing based on + * MTOM threshold, and make decisions about inlining the attachment data or not. + * + * @author Jitendra Kotamraju + * @see JAXBMessage + * @see MtomCodec + */ +public interface MtomStreamWriter { + AttachmentMarshaller getAttachmentMarshaller(); +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java new file mode 100644 index 00000000000..75afe2b1351 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxReaderEx.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.util.Iterator; + +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; +import javax.xml.stream.XMLStreamException; + +import com.sun.xml.internal.org.jvnet.staxex.Base64Data; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; +import com.sun.xml.internal.org.jvnet.staxex.BinaryText; + +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * SaajStaxReaderEx + * + * @author shih-chang.chen@oracle.com + */ +public class SaajStaxReaderEx extends DOMStreamReader implements XMLStreamReaderEx { + //TODO extends com.sun.xml.internal.ws.streaming.DOMStreamReader + private BinaryText binaryText = null; + private Base64Data base64AttData = null; + + public SaajStaxReaderEx(SOAPElement se) { + super(se); + } + + @Override + public int next() throws XMLStreamException { + binaryText = null; + base64AttData = null; + while(true) { + int r = _next(); + switch (r) { + case CHARACTERS: + if (_current instanceof BinaryText) { + binaryText = (BinaryText) _current; + base64AttData = new Base64Data(); + try { + base64AttData.set(binaryText.getDataHandler()); +//System.out.println("--------------- debug SaajStaxReaderEx binaryText " + binaryText); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } else { + // if we are currently at text node, make sure that this is a meaningful text node. + Node prev = _current.getPreviousSibling(); + if(prev!=null && prev.getNodeType()==Node.TEXT_NODE) + continue; // nope. this is just a continuation of previous text that should be invisible + + Text t = (Text)_current; + wholeText = t.getWholeText(); + if(wholeText.length()==0) + continue; // nope. this is empty text. + } + return CHARACTERS; + case START_ELEMENT: + splitAttributes(); + return START_ELEMENT; + default: + return r; + } + } + } + + @Override + public String getElementTextTrim() throws XMLStreamException { + // TODO Auto-generated method stub + return null; + } + + @Override + public CharSequence getPCDATA() throws XMLStreamException { + return (binaryText != null) ? base64AttData : getText(); + } + + @Override + public com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx getNamespaceContext() { + return new com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx() { + + @Override + public String getNamespaceURI(String prefix) { + return _current.lookupNamespaceURI(prefix); + } + + @Override + public String getPrefix(String uri) { + return _current.lookupPrefix(uri); + } + + @Override + public Iterator getPrefixes(String arg0) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Iterator iterator() { + // TODO Auto-generated method stub + return null; + } + + }; + } + + + @Override + public int getTextLength() { + return (binaryText != null) ? base64AttData.length() : super.getTextLength(); + } + + @Override + public int getTextStart() { + return (binaryText != null) ? 0: super.getTextStart(); + } + + @Override + public char[] getTextCharacters() { + if (binaryText != null) { + char[] chars = new char[base64AttData.length()]; + base64AttData.writeTo(chars, 0); + return chars; + } + return super.getTextCharacters(); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java new file mode 100644 index 00000000000..8020bea1de4 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriter.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.util.Arrays; +import java.util.Iterator; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.w3c.dom.Comment; +import org.w3c.dom.Node; + +/** + * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface. + * + * @author shih-chang.chen@oracle.com + */ +public class SaajStaxWriter implements XMLStreamWriter { + + protected SOAPMessage soap; + protected String envURI; + protected SOAPElement currentElement; + + static final protected String Envelope = "Envelope"; + static final protected String Header = "Header"; + static final protected String Body = "Body"; + static final protected String xmlns = "xmlns"; + + public SaajStaxWriter(final SOAPMessage msg, String uri) throws SOAPException { + soap = msg; + this.envURI = uri; + } + + public SOAPMessage getSOAPMessage() { + return soap; + } + + protected SOAPElement getEnvelope() throws SOAPException { + return soap.getSOAPPart().getEnvelope(); + } + + @Override + public void writeStartElement(final String localName) throws XMLStreamException { + try { + currentElement = currentElement.addChildElement(localName); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeStartElement(final String ns, final String ln) throws XMLStreamException { + writeStartElement(null, ln, ns); + } + + @Override + public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException { + try { + if (envURI.equals(ns)) { + if (Envelope.equals(ln)) { + currentElement = getEnvelope(); + fixPrefix(prefix); + return; + } else if (Header.equals(ln)) { + currentElement = soap.getSOAPHeader(); + fixPrefix(prefix); + return; + } else if (Body.equals(ln)) { + currentElement = soap.getSOAPBody(); + fixPrefix(prefix); + return; + } + } + currentElement = (prefix == null) ? + currentElement.addChildElement(new QName(ns, ln)) : + currentElement.addChildElement(ln, prefix, ns); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + private void fixPrefix(final String prfx) throws XMLStreamException { + String oldPrfx = currentElement.getPrefix(); + if (prfx != null && !prfx.equals(oldPrfx)) { + currentElement.setPrefix(prfx); + } + } + + @Override + public void writeEmptyElement(final String uri, final String ln) throws XMLStreamException { + writeStartElement(null, ln, uri); + } + + @Override + public void writeEmptyElement(final String prefix, final String ln, final String uri) throws XMLStreamException { + writeStartElement(prefix, ln, uri); + } + + @Override + public void writeEmptyElement(final String ln) throws XMLStreamException { + writeStartElement(null, ln, null); + } + + @Override + public void writeEndElement() throws XMLStreamException { + if (currentElement != null) currentElement = currentElement.getParentElement(); + } + + @Override + public void writeEndDocument() throws XMLStreamException { + } + + @Override + public void close() throws XMLStreamException { + } + + @Override + public void flush() throws XMLStreamException { + } + + @Override + public void writeAttribute(final String ln, final String val) throws XMLStreamException { + writeAttribute(null, null, ln, val); + } + + @Override + public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException { + try { + if (ns == null) { + if (prefix == null && xmlns.equals(ln)) { + currentElement.addNamespaceDeclaration("", value); + } else { + currentElement.setAttributeNS("", ln, value); + } + } else { + QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix); + currentElement.addAttribute(name, value); + } + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeAttribute(final String ns, final String ln, final String val) throws XMLStreamException { + writeAttribute(null, ns, ln, val); + } + + @Override + public void writeNamespace(String prefix, final String uri) throws XMLStreamException { + + // make prefix default if null or "xmlns" (according to javadoc) + if (prefix == null || "xmlns".equals(prefix)) { + prefix = ""; + } + + try { + currentElement.addNamespaceDeclaration(prefix, uri); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeDefaultNamespace(final String uri) throws XMLStreamException { + writeNamespace("", uri); + } + + @Override + public void writeComment(final String data) throws XMLStreamException { + Comment c = soap.getSOAPPart().createComment(data); + currentElement.appendChild(c); + } + + @Override + public void writeProcessingInstruction(final String target) throws XMLStreamException { + Node n = soap.getSOAPPart().createProcessingInstruction(target, ""); + currentElement.appendChild(n); + } + + @Override + public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException { + Node n = soap.getSOAPPart().createProcessingInstruction(target, data); + currentElement.appendChild(n); + } + + @Override + public void writeCData(final String data) throws XMLStreamException { + Node n = soap.getSOAPPart().createCDATASection(data); + currentElement.appendChild(n); + } + + @Override + public void writeDTD(final String dtd) throws XMLStreamException { + //TODO ... Don't do anything here + } + + @Override + public void writeEntityRef(final String name) throws XMLStreamException { + Node n = soap.getSOAPPart().createEntityReference(name); + currentElement.appendChild(n); + } + + @Override + public void writeStartDocument() throws XMLStreamException { + } + + @Override + public void writeStartDocument(final String version) throws XMLStreamException { + if (version != null) soap.getSOAPPart().setXmlVersion(version); + } + + @Override + public void writeStartDocument(final String encoding, final String version) throws XMLStreamException { + if (version != null) soap.getSOAPPart().setXmlVersion(version); + if (encoding != null) { + try { + soap.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + } + + @Override + public void writeCharacters(final String text) throws XMLStreamException { + try { + currentElement.addTextNode(text); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException { + char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len); + try { + currentElement.addTextNode(new String(chr)); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public String getPrefix(final String uri) throws XMLStreamException { + return currentElement.lookupPrefix(uri); + } + + @Override + public void setPrefix(final String prefix, final String uri) throws XMLStreamException { + try { + this.currentElement.addNamespaceDeclaration(prefix, uri); + } catch (SOAPException e) { + throw new XMLStreamException(e); + } + } + + @Override + public void setDefaultNamespace(final String uri) throws XMLStreamException { + setPrefix("", uri); + } + + @Override + public void setNamespaceContext(final NamespaceContext context)throws XMLStreamException { + throw new UnsupportedOperationException(); + } + + @Override + public Object getProperty(final String name) throws IllegalArgumentException { + //TODO the following line is to make eclipselink happy ... they are aware of this problem - + if (javax.xml.stream.XMLOutputFactory.IS_REPAIRING_NAMESPACES.equals(name)) return Boolean.FALSE; + return null; + } + + @Override + public NamespaceContext getNamespaceContext() { + return new NamespaceContext() { + public String getNamespaceURI(final String prefix) { + return currentElement.getNamespaceURI(prefix); + } + public String getPrefix(final String namespaceURI) { + return currentElement.lookupPrefix(namespaceURI); + } + public Iterator getPrefixes(final String namespaceURI) { + return new Iterator() { + String prefix = getPrefix(namespaceURI); + public boolean hasNext() { + return (prefix != null); + } + public Object next() { + if (!hasNext()) throw new java.util.NoSuchElementException(); + String next = prefix; + prefix = null; + return next; + } + public void remove() {} + }; + } + }; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java new file mode 100644 index 00000000000..e8b22cf46bd --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/SaajStaxWriterEx.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Iterator; +import java.util.UUID; + +import javax.activation.DataHandler; +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.stream.XMLStreamException; + +import com.sun.xml.internal.org.jvnet.staxex.Base64Data; +import com.sun.xml.internal.org.jvnet.staxex.BinaryText; +import com.sun.xml.internal.org.jvnet.staxex.MtomEnabled; +import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx; +import com.sun.xml.internal.org.jvnet.staxex.StreamingDataHandler; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; +// +//import com.sun.xml.internal.ws.api.message.saaj.SaajStaxWriter; +//import com.sun.xml.internal.ws.developer.StreamingDataHandler; +//import com.sun.xml.internal.ws.streaming.MtomStreamWriter; + +/** + * SaajStaxWriterEx converts XMLStreamWriterEx calls to build an orasaaj SOAPMessage with BinaryTextImpl. + * + * @author shih-chang.chen@oracle.com + */ +public class SaajStaxWriterEx extends SaajStaxWriter implements XMLStreamWriterEx, MtomStreamWriter { + + static final protected String xopNS = "http://www.w3.org/2004/08/xop/include"; + static final protected String Include = "Include"; + static final protected String href = "href"; + + private enum State {xopInclude, others}; + private State state = State.others; + private BinaryText binaryText; + + public SaajStaxWriterEx(SOAPMessage msg, String uri) throws SOAPException { + super(msg, uri); + } + + public void writeStartElement(String prefix, String ln, String ns) throws XMLStreamException { + if (xopNS.equals(ns) && Include.equals(ln)) { + state = State.xopInclude; + return; + } else { + super.writeStartElement(prefix, ln, ns); + } + } + + @Override + public void writeEndElement() throws XMLStreamException { + if (state.equals(State.xopInclude)) { + state = State.others; + } else { + super.writeEndElement(); + } + } + + @Override + public void writeAttribute(String prefix, String ns, String ln, String value) throws XMLStreamException { + if (binaryText != null && href.equals(ln)) { + return; + } else { + super.writeAttribute(prefix, ns, ln, value); + } + } + +// @Override +// public void writeComment(String data) throws XMLStreamException { +// ((ElementImpl)currentElement).addCommentNode(data); +// } +// +// @Override +// public void writeCData(String data) throws XMLStreamException { +// CDataTextImpl cdt = new CDataTextImpl(soap.getSOAPPart(), data); +// currentElement.appendChild(cdt); +// } + + @Override + public NamespaceContextEx getNamespaceContext() { + return new NamespaceContextEx() { + public String getNamespaceURI(String prefix) { + return currentElement.getNamespaceURI(prefix); + } + public String getPrefix(String namespaceURI) { + return currentElement.lookupPrefix(namespaceURI); + } + public Iterator getPrefixes(final String namespaceURI) { + return new Iterator() { + String prefix = getPrefix(namespaceURI); + public boolean hasNext() { + return (prefix != null); + } + public Object next() { + if (prefix == null) throw new java.util.NoSuchElementException(); + String next = prefix; + prefix = null; + return next; + } + public void remove() {} + }; + } + public Iterator iterator() { + return new Iterator() { + public boolean hasNext() { return false; } + public Binding next() { return null; } + public void remove() {} + }; + } + }; + } + + @Override + public void writeBinary(DataHandler data) throws XMLStreamException { +// binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl)soap, null, currentElement.getOwnerDocument(), data); +// currentElement.appendChild(binaryText); + addBinaryText(data); + } + + @Override + public OutputStream writeBinary(String arg0) throws XMLStreamException { + return null; + } + + @Override + public void writeBinary(byte[] data, int offset, int length, String contentType) throws XMLStreamException { +// if (mtomThreshold == -1 || mtomThreshold > length) return null; + byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); + if (currentElement instanceof MtomEnabled) { + binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); + } else { + throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); + } + } + + @Override + public void writePCDATA(CharSequence arg0) throws XMLStreamException { + if (arg0 instanceof Base64Data) { + // The fix of StreamReaderBufferCreator preserves this dataHandler + addBinaryText(((Base64Data) arg0).getDataHandler()); + } else { + // We should not normally get here as we expect a DataHandler, + // but this is the most general solution. If we do get + // something other than a Data Handler, create a Text node with + // the data. Another alternative would be to throw an exception, + // but in the most general case, we don't know whether this input + // is expected. + try { + currentElement.addTextNode(arg0.toString()); + } catch (SOAPException e) { + throw new XMLStreamException("Cannot add Text node", e); + } + } + } + + static private String encodeCid() { + String cid = "example.jaxws.sun.com"; + String name = UUID.randomUUID() + "@"; + return name + cid; + } + + private String addBinaryText(DataHandler data) { + String hrefOrCid = null; + if (data instanceof StreamingDataHandler) { + hrefOrCid = ((StreamingDataHandler) data).getHrefCid(); + } + if (hrefOrCid == null) hrefOrCid = encodeCid(); + + String prefixedCid = (hrefOrCid.startsWith("cid:")) ? hrefOrCid : "cid:" + hrefOrCid; + // Should we do the threshold processing on DataHandler ? But that would be + // expensive as DataHolder need to read the data again from its source + //binaryText = BinaryTextImpl.createBinaryTextFromDataHandler((MessageImpl) soap, prefixedCid, currentElement.getOwnerDocument(), data); + //currentElement.appendChild(binaryText); + if (currentElement instanceof MtomEnabled) { + binaryText = ((MtomEnabled) currentElement).addBinaryText(prefixedCid, data); + } else { + throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); + } + return hrefOrCid; + } + + public AttachmentMarshaller getAttachmentMarshaller() { + return new AttachmentMarshaller() { + @Override + public String addMtomAttachment(DataHandler data, String ns, String ln) { +// if (mtomThreshold == -1) return null; + String hrefOrCid = addBinaryText(data); +// return binaryText.getHref(); + return hrefOrCid; + } + + @Override + public String addMtomAttachment(byte[] data, int offset, int length, String mimeType, String ns, String ln) { +// if (mtomThreshold == -1 || mtomThreshold > length) return null; + byte[] bytes = (offset == 0 && length == data.length) ? data : Arrays.copyOfRange(data, offset, offset + length); +// binaryText = (BinaryTextImpl) ((ElementImpl) currentElement).addAsBase64TextNode(bytes); + if (currentElement instanceof MtomEnabled) { + binaryText = ((MtomEnabled) currentElement).addBinaryText(bytes); + } else { + throw new IllegalStateException("The currentElement is not MtomEnabled " + currentElement); + } + return binaryText.getHref(); + } + + @Override + public String addSwaRefAttachment(DataHandler data) { + return "cid:"+encodeCid(); + } + + @Override + public boolean isXOPPackage() { + return true; + } + }; + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java new file mode 100644 index 00000000000..94643273907 --- /dev/null +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/util/XMLStreamReaderToXMLStreamWriter.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 1997, 2014, 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. + */ + +package com.sun.xml.internal.org.jvnet.staxex.util; + +import java.io.IOException; + +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.XMLConstants; + +import com.sun.xml.internal.org.jvnet.staxex.Base64Data; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; +import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; + +/** + * Reads a sub-tree from {@link XMLStreamReader} and writes to {@link XMLStreamWriter} + * as-is. + * + *

+ * This class can be sub-classed to implement a simple transformation logic. + * + * @author Kohsuke Kawaguchi + * @author Ryan Shoemaker + */ +public class XMLStreamReaderToXMLStreamWriter { + + static public class Breakpoint { + protected XMLStreamReader reader; + protected XMLStreamWriter writer; + + public Breakpoint(XMLStreamReader r, XMLStreamWriter w) { reader = r; writer = w; } + + public XMLStreamReader reader() { return reader; } + public XMLStreamWriter writer() { return writer; } + public boolean proceedBeforeStartElement() { return true; } + public boolean proceedAfterStartElement() { return true; } + } + + private static final int BUF_SIZE = 4096; + + protected XMLStreamReader in; + protected XMLStreamWriter out; + + private char[] buf; + + boolean optimizeBase64Data = false; + + AttachmentMarshaller mtomAttachmentMarshaller; + + /** + * Reads one subtree and writes it out. + * + *

+ * The {@link XMLStreamWriter} never receives a start/end document event. + * Those need to be written separately by the caller. + */ + public void bridge(XMLStreamReader in, XMLStreamWriter out) throws XMLStreamException { + bridge(in, out, null); + } + + public void bridge(Breakpoint breakPoint) throws XMLStreamException { + bridge(breakPoint.reader(), breakPoint.writer(), breakPoint); + } + + private void bridge(XMLStreamReader in, XMLStreamWriter out, Breakpoint breakPoint) throws XMLStreamException { + assert in!=null && out!=null; + this.in = in; + this.out = out; + + optimizeBase64Data = (in instanceof XMLStreamReaderEx); + + if (out instanceof XMLStreamWriterEx && out instanceof MtomStreamWriter) { + mtomAttachmentMarshaller = ((MtomStreamWriter) out).getAttachmentMarshaller(); + } + // remembers the nest level of elements to know when we are done. + int depth=0; + + buf = new char[BUF_SIZE]; + + // if the parser is at the start tag, proceed to the first element + int event = getEventType(); + + if( event!=XMLStreamConstants.START_ELEMENT) + throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event); + + do { + // These are all of the events listed in the javadoc for + // XMLEvent. + // The spec only really describes 11 of them. + switch (event) { + case XMLStreamConstants.START_ELEMENT : + if (breakPoint != null && !breakPoint.proceedBeforeStartElement()) return; + depth++; + handleStartElement(); + if (breakPoint != null && !breakPoint.proceedAfterStartElement()) return; + break; + case XMLStreamConstants.END_ELEMENT : + handleEndElement(); + depth--; + if(depth==0) + return; + break; + case XMLStreamConstants.CHARACTERS : + handleCharacters(); + break; + case XMLStreamConstants.ENTITY_REFERENCE : + handleEntityReference(); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION : + handlePI(); + break; + case XMLStreamConstants.COMMENT : + handleComment(); + break; + case XMLStreamConstants.DTD : + handleDTD(); + break; + case XMLStreamConstants.CDATA : + handleCDATA(); + break; + case XMLStreamConstants.SPACE : + handleSpace(); + break; + case XMLStreamConstants.END_DOCUMENT: + throw new XMLStreamException("Malformed XML at depth="+depth+", Reached EOF. Event="+event); + default : + throw new XMLStreamException("Cannot process event: " + event); + } + + event=getNextEvent(); + } while (depth!=0); + } + + protected void handlePI() throws XMLStreamException { + out.writeProcessingInstruction( + in.getPITarget(), + in.getPIData()); + } + + + protected void handleCharacters() throws XMLStreamException { + + CharSequence c = null; + + if (optimizeBase64Data) { + c = ((XMLStreamReaderEx)in).getPCDATA(); + } + + if ((c != null) && (c instanceof Base64Data)) { + if (mtomAttachmentMarshaller != null) { + Base64Data b64d = (Base64Data) c; + ((XMLStreamWriterEx)out).writeBinary(b64d.getDataHandler()); + } else { + try { + ((Base64Data)c).writeTo(out); + } catch (IOException e) { + throw new XMLStreamException(e); + } + } + } else { + for (int start=0,read=buf.length; read == buf.length; start+=buf.length) { + read = in.getTextCharacters(start, buf, 0, buf.length); + out.writeCharacters(buf, 0, read); + } + } + } + + protected void handleEndElement() throws XMLStreamException { + out.writeEndElement(); + } + + protected void handleStartElement() throws XMLStreamException { + String nsUri = in.getNamespaceURI(); + if(nsUri==null) + out.writeStartElement(in.getLocalName()); + else + out.writeStartElement( + fixNull(in.getPrefix()), + in.getLocalName(), + nsUri + ); + + // start namespace bindings + int nsCount = in.getNamespaceCount(); + for (int i = 0; i < nsCount; i++) { + out.writeNamespace( + in.getNamespacePrefix(i), + fixNull(in.getNamespaceURI(i))); // zephyr doesn't like null, I don't know what is correct, so just fix null to "" for now + } + + // write attributes + int attCount = in.getAttributeCount(); + for (int i = 0; i < attCount; i++) { + handleAttribute(i); + } + } + + /** + * Writes out the {@code i}-th attribute of the current element. + * + *

+ * Used from {@link #handleStartElement()}. + */ + protected void handleAttribute(int i) throws XMLStreamException { + String nsUri = in.getAttributeNamespace(i); + String prefix = in.getAttributePrefix(i); + if (fixNull(nsUri).equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { + //Its a namespace decl, ignore as it is already written. + return; + } + + if(nsUri==null || prefix == null || prefix.equals("")) { + out.writeAttribute( + in.getAttributeLocalName(i), + in.getAttributeValue(i) + ); + } else { + out.writeAttribute( + prefix, + nsUri, + in.getAttributeLocalName(i), + in.getAttributeValue(i) + ); + } + } + + protected void handleDTD() throws XMLStreamException { + out.writeDTD(in.getText()); + } + + protected void handleComment() throws XMLStreamException { + out.writeComment(in.getText()); + } + + protected void handleEntityReference() throws XMLStreamException { + out.writeEntityRef(in.getText()); + } + + protected void handleSpace() throws XMLStreamException { + handleCharacters(); + } + + protected void handleCDATA() throws XMLStreamException { + out.writeCData(in.getText()); + } + + private static String fixNull(String s) { + if(s==null) return ""; + else return s; + } + + private int getEventType() throws XMLStreamException { + int event = in.getEventType(); + // if the parser is at the start tag, proceed to the first element + //Note - need to do this every time because we could be using a composite reader + if(event == XMLStreamConstants.START_DOCUMENT) { + // nextTag doesn't correctly handle DTDs + while( !in.isStartElement() ) { + event = in.next(); + if (event == XMLStreamConstants.COMMENT) + handleComment(); + } + } + return event; + } + + private int getNextEvent() throws XMLStreamException { + in.next(); + return getEventType(); + } +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java index b2d19ce7433..e1f39b91ea9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/EPRSDDocumentFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -30,7 +30,7 @@ import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; import com.sun.xml.internal.ws.api.addressing.AddressingVersion; import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.server.WSEndpointImpl; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import com.sun.istack.internal.Nullable; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java index b6b16abebe8..68ec6b5e1b4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/addressing/WSEndpointReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -52,7 +52,7 @@ import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; import com.sun.xml.internal.ws.util.DOMUtil; import com.sun.xml.internal.ws.util.xml.XMLStreamWriterFilter; import com.sun.xml.internal.ws.util.xml.XmlUtil; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import org.w3c.dom.Element; import org.xml.sax.*; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java index 6cbc2f9153e..194ba0a5810 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/FilterMessageImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -158,7 +158,7 @@ public class FilterMessageImpl extends Message { } public Message copy() { - return delegate.copy(); + return delegate.copy().copyFrom(delegate); } public @NotNull String getID(@NotNull WSBinding binding) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java index cd473a7aec6..c118e6639d0 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Message.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -196,6 +196,12 @@ import java.util.UUID; */ public abstract class Message { + // See Packet for doc. + private boolean isProtocolMessage = false; + // next two are package protected - should only be used from Packet + boolean isProtocolMessage() { return isProtocolMessage; } + void setIsProtocolMessage() { isProtocolMessage = true; } + /** * Returns true if headers are present in the message. * @@ -724,11 +730,33 @@ public abstract class Message { *

* The restrictions placed on the use of copied {@link Message} can be * relaxed if necessary, but it will make the copy method more expensive. + * + *

IMPORTANT

+ *

WHEN YOU IMPLEMENT OR CHANGE A {@link .copy()} METHOD, YOU MUST + * USE THE {@link copyFrom(Message)} METHOD IN THE IMPLEMENTATION. */ // TODO: update the class javadoc with 'lifescope' // and move the discussion about life scope there. public abstract Message copy(); + /** + * The {@link Message#copy()} method is used as a shorthand + * throughout the codecase in place of calling a copy constructor. + * However, that shorthand make it difficult to have a concrete + * method here in the base to do common work. + * + *

Rather than have each {@code copy} method duplicate code, the + * following method is used in each {@code copy} implementation. + * It MUST be called. + * + * @return The Message that calls {@code copyFrom} inside the + * {@code copy} method after the copy constructor + */ + public final Message copyFrom(Message m) { + isProtocolMessage = m.isProtocolMessage; + return this; + } + /** * Retuns a unique id for the message. The id can be used for various things, * like debug assistance, logging, and MIME encoding(say for boundary). diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java index 708c09710b2..a27a6be98bc 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/MessageWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -93,6 +93,11 @@ class MessageWrapper extends StreamMessage { return delegate.equals(obj); } + @Override + boolean isProtocolMessage() { return delegate.isProtocolMessage(); } + @Override + void setIsProtocolMessage() { delegate.setIsProtocolMessage(); } + @Override public boolean hasHeaders() { return delegate.hasHeaders(); @@ -105,7 +110,7 @@ class MessageWrapper extends StreamMessage { @Override public String toString() { - return delegate.toString(); + return "{MessageWrapper: " + delegate.toString() + "}"; } @Override @@ -214,7 +219,7 @@ class MessageWrapper extends StreamMessage { @Override public Message copy() { - return delegate.copy(); + return delegate.copy().copyFrom(delegate); } @Override diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java index fc981a9e622..1bc4ca6b974 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Packet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -248,6 +248,26 @@ public final class Packet if (message != null) this.message.setMessageMedadata(this); } + // ALL NEW PACKETS SHOULD HAVE THIS AS false. + // SETTING TO true MUST BE DONE EXPLICITLY, + // NOT VIA COPYING/RELATING PACKETS. + public boolean isProtocolMessage() { + return message != null && message.isProtocolMessage(); + } + public void setIsProtocolMessage() { + assert message != null; + message.setIsProtocolMessage(); + } + + private String userStateId; + public String getUserStateId() { + return userStateId; + } + public void setUserStateId(final String x) { + assert x != null && x.length() <= 256; + userStateId = x; + } + private WSDLOperationMapping wsdlOperationMapping = null; private QName wsdlOperation; @@ -894,6 +914,7 @@ public final class Packet response.component = request.component; response.mtomAcceptable = request.mtomAcceptable; response.mtomRequest = request.mtomRequest; + response.userStateId = request.userStateId; // copy other properties that need to be copied. is there any? } @@ -1255,6 +1276,12 @@ public final class Packet return getCodec().encode(this, buffer); } + /** + * This content type may be set by one of the following ways: + * (1) By the codec as a result of decoding an incoming message + * (2) Cached by a codec after encoding the message + * (3) By a caller of Codec.decode(InputStream, String contentType, Packet) + */ private ContentType contentType; /** @@ -1410,6 +1437,13 @@ public final class Packet //Use the getter to make sure all the logic is executed correctly MTOMFeature myMtomFeature = getMtomFeature(); if(myMtomFeature != null && myMtomFeature.isEnabled()) { + //If the content type is set already on this outbound Packet, + //(e.g.) through Codec.decode(InputStream, String contentType, Packet) + //and it is a non-mtom content type, then don't use mtom to encode it + ContentType curContentType = getInternalContentType(); + if (curContentType != null && !isMtomContentType(curContentType)) { + return false; + } //On client, always use XOP encoding if MTOM is enabled //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding //if either request is XOP encoded (mtomRequest) or @@ -1432,11 +1466,14 @@ public final class Packet } private boolean isMtomContentType() { - return (getInternalContentType() != null) && - (getInternalContentType().getContentType().contains("application/xop+xml")); + return (getInternalContentType() != null && isMtomContentType(getInternalContentType())); } - /** + private boolean isMtomContentType(ContentType cType) { + return cType.getContentType().contains("application/xop+xml"); + } + + /** * @deprecated */ public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java index e84ae576f10..ad8ab56b0ad 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/StreamingSOAP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,8 +25,17 @@ package com.sun.xml.internal.ws.api.message; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; public interface StreamingSOAP { public XMLStreamReader readEnvelope(); + public QName getPayloadQName(); + public XMLStreamReader readToBodyStarTag() throws XMLStreamException; + public XMLStreamReader readPayload() throws XMLStreamException; + public void writeToBodyStart(XMLStreamWriter w) throws XMLStreamException; + public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException; + public boolean isPayloadStreamReader(); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java index a1bd1da3fc9..7bbbc064e61 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SAAJFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -36,6 +36,7 @@ import javax.xml.soap.SOAPMessage; import javax.xml.stream.XMLStreamException; import org.xml.sax.SAXException; +import com.sun.xml.internal.org.jvnet.staxex.util.SaajStaxWriter; import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; import com.sun.xml.internal.ws.api.SOAPVersion; @@ -265,7 +266,7 @@ public class SAAJFactory { */ public SOAPMessage readAsSOAPMessage(final SOAPVersion soapVersion, final Message message) throws SOAPException { SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); - SaajStaxWriter writer = new SaajStaxWriter(msg); + SaajStaxWriter writer = new SaajStaxWriter(msg, soapVersion.nsUri); try { message.writeTo(writer); } catch (XMLStreamException e) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java index 6414593fee7..5786a0a2831 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/saaj/SaajStaxWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -42,6 +42,8 @@ import org.w3c.dom.Node; /** * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface. * + * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.SaajStaxWriter + * * @author shih-chang.chen@oracle.com */ public class SaajStaxWriter implements XMLStreamWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java index 9ad1f6edfba..fd331c9ff49 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/SEIStub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -28,7 +28,6 @@ package com.sun.xml.internal.ws.client.sei; import com.sun.istack.internal.NotNull; import com.sun.istack.internal.Nullable; import com.sun.xml.internal.ws.api.SOAPVersion; -import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; import com.sun.xml.internal.ws.api.client.WSPortInfo; import com.sun.xml.internal.ws.api.databinding.Databinding; import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; @@ -167,8 +166,7 @@ public final class SEIStub extends Stub implements InvocationHandler { if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) { throw new IllegalStateException("Passed object is not proxy!"); } - Class declaringClass = method.getDeclaringClass(); - if (method == null || declaringClass == null + if (method == null || method.getDeclaringClass() == null || Modifier.isStatic(method.getModifiers())) { throw new IllegalStateException("Invoking static method is not allowed!"); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java index 9ba60a2c77d..5eaad4dbf23 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/developer/StreamingDataHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -50,8 +50,6 @@ import javax.activation.DataSource; */ public abstract class StreamingDataHandler extends com.sun.xml.internal.org.jvnet.staxex.StreamingDataHandler { - private String hrefCid; - public StreamingDataHandler(Object o, String s) { super(o, s); } @@ -63,13 +61,4 @@ public abstract class StreamingDataHandler extends com.sun.xml.internal.org.jvne public StreamingDataHandler(DataSource dataSource) { super(dataSource); } - - public String getHrefCid() { - return hrefCid; - } - - public void setHrefCid(final String cid) { - this.hrefCid = cid; - } - } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java index f8b3da89f3b..f4d61f5d004 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/ContentTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -62,6 +62,7 @@ public final class ContentTypeImpl implements com.sun.xml.internal.ws.api.pipe.C try { internalContentType = new ContentType(contentType); tmpCharset = internalContentType.getParameter("charset"); + rootId = internalContentType.getParameter("start"); } catch(Exception e) { //Ignore the parsing exception. } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java index f060a34fdb0..fb8e5f2a5a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MimeCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -118,12 +118,14 @@ abstract class MimeCodec implements Codec { } ContentTypeImpl ctImpl = (ContentTypeImpl)getStaticContentType(packet); String boundary = ctImpl.getBoundary(); + String rootId = ctImpl.getRootId(); boolean hasAttachments = (boundary != null); Codec rootCodec = getMimeRootCodec(packet); if (hasAttachments) { writeln("--"+boundary, out); ContentType ct = rootCodec.getStaticContentType(packet); String ctStr = (ct != null) ? ct.getContentType() : rootCodec.getMimeType(); + if (rootId != null) writeln("Content-ID: " + rootId, out); writeln("Content-Type: " + ctStr, out); writeln(out); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java index 0db9233e6be..4d8194371a7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/MtomCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -112,9 +112,15 @@ public class MtomCodec extends MimeCodec { } public static ContentType getStaticContentTypeStatic(Packet packet, SOAPVersion version) { - ContentType ct = (ContentType) packet.getInternalContentType(); - if ( ct != null ) return ct; - + ContentTypeImpl ct = (ContentTypeImpl) packet.getInternalContentType(); + if ( ct != null ) { + //Note - this case of boundary = null or root content ID = null should never happen + //after a recent bug fix in Packet.shouldUseMtom logic, but just in + //case we get here with a Packet that has a non-null content type with + //a null boundary, the content type of the Packet will be reset + if (ct.getBoundary() != null && ct.getRootId() != null) + return ct; + } String uuid = UUID.randomUUID().toString(); String boundary = "uuid:" + uuid; String rootId = ""; @@ -327,7 +333,7 @@ public class MtomCodec extends MimeCodec { } public static class MtomStreamWriterImpl extends XMLStreamWriterFilter implements XMLStreamWriterEx, - MtomStreamWriter, HasEncoding { + com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter, HasEncoding { private final List mtomAttachments; private final String boundary; private final MTOMFeature myMtomFeature; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java index f9f8e989c25..3680ef09c8e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -326,7 +326,7 @@ public final class XMLMessage { } public Message copy() { - return getMessage().copy(); + return getMessage().copy().copyFrom(getMessage()); } protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { @@ -449,7 +449,7 @@ public final class XMLMessage { } public Message copy() { - return getMessage().copy(); + return getMessage().copy().copyFrom(getMessage()); } protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { @@ -507,6 +507,7 @@ public final class XMLMessage { super(that.soapVersion); this.ds = that.ds; this.headerList = HeaderList.copy(that.headerList); + this.copyFrom(that); } public boolean hasUnconsumedDataSource() { @@ -560,7 +561,7 @@ public final class XMLMessage { } public Message copy() { - return new UnknownContent(this); + return new UnknownContent(this).copyFrom(this); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java index 056b31b9efd..81a23a28fa4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/AbstractMessageImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -120,6 +120,7 @@ public abstract class AbstractMessageImpl extends Message { */ protected AbstractMessageImpl(AbstractMessageImpl that) { this.soapVersion = that.soapVersion; + this.copyFrom(that); } @Override @@ -150,11 +151,7 @@ public abstract class AbstractMessageImpl extends Message { hasAttachments()? new AttachmentUnmarshallerImpl(getAttachments()) : null ); } - /** - * Default implementation that relies on {@link #writePayloadTo(XMLStreamWriter)} - */ - @Override - public void writeTo(XMLStreamWriter w) throws XMLStreamException { + public void writeToBodyStart(XMLStreamWriter w) throws XMLStreamException { String soapNsUri = soapVersion.nsUri; w.writeStartDocument(); w.writeStartElement("S","Envelope",soapNsUri); @@ -169,7 +166,14 @@ public abstract class AbstractMessageImpl extends Message { } // write the body w.writeStartElement("S","Body",soapNsUri); + } + /** + * Default implementation that relies on {@link #writePayloadTo(XMLStreamWriter)} + */ + @Override + public void writeTo(XMLStreamWriter w) throws XMLStreamException { + writeToBodyStart(w); writePayloadTo(w); w.writeEndElement(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java index 4052989b4bf..24b5a22f1ee 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/DOMMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -80,6 +80,7 @@ public final class DOMMessage extends AbstractMessageImpl { super(that); this.headers = HeaderList.copy(that.headers); this.payload = that.payload; + this.copyFrom(that); } public boolean hasHeaders() { @@ -150,7 +151,7 @@ public final class DOMMessage extends AbstractMessageImpl { } public Message copy() { - return new DOMMessage(this); + return new DOMMessage(this).copyFrom(this); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java index 1ca4f0bab43..470ecf54bb8 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/EmptyMessageImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -76,6 +76,7 @@ public class EmptyMessageImpl extends AbstractMessageImpl { super(that); this.headers = new HeaderList(that.headers); this.attachmentSet = that.attachmentSet; + this.copyFrom(that); } public boolean hasHeaders() { @@ -115,7 +116,7 @@ public class EmptyMessageImpl extends AbstractMessageImpl { } public Message copy() { - return new EmptyMessageImpl(this); + return new EmptyMessageImpl(this).copyFrom(this); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java index 4d3c82f84a6..b1896ab93bd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBDispatchMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 com.sun.xml.internal.ws.message.AbstractMessageImpl; import com.sun.xml.internal.ws.message.PayloadElementSniffer; import com.sun.xml.internal.ws.spi.db.BindingContext; import com.sun.xml.internal.ws.spi.db.XMLBridge; -import com.sun.xml.internal.ws.streaming.MtomStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter; import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil; import org.xml.sax.ContentHandler; import org.xml.sax.ErrorHandler; @@ -87,6 +87,7 @@ public class JAXBDispatchMessage extends AbstractMessageImpl { jaxbObject = that.jaxbObject; rawContext = that.rawContext; bridge = that.bridge; + copyFrom(that); } public JAXBDispatchMessage(JAXBContext rawContext, Object jaxbObject, SOAPVersion soapVersion) { @@ -178,7 +179,7 @@ public class JAXBDispatchMessage extends AbstractMessageImpl { @Override public Message copy() { - return new JAXBDispatchMessage(this); + return new JAXBDispatchMessage(this).copyFrom(this); } @Override diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java index 28047945b83..8d7891350b5 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/jaxb/JAXBMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -46,7 +46,7 @@ import com.sun.xml.internal.ws.spi.db.BindingContextFactory; import com.sun.xml.internal.ws.spi.db.XMLBridge; import com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil; import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; -import com.sun.xml.internal.ws.streaming.MtomStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite.ElemInfo; @@ -240,6 +240,7 @@ public final class JAXBMessage extends AbstractMessageImpl implements StreamingS this.jaxbObject = that.jaxbObject; this.bridge = that.bridge; this.rawContext = that.rawContext; + this.copyFrom(that); } @Override @@ -411,7 +412,7 @@ public final class JAXBMessage extends AbstractMessageImpl implements StreamingS @Override public Message copy() { - return new JAXBMessage(this); + return new JAXBMessage(this).copyFrom(this); } public XMLStreamReader readEnvelope() { @@ -443,4 +444,35 @@ public final class JAXBMessage extends AbstractMessageImpl implements StreamingS throw new RuntimeException(e); } } + + public boolean isPayloadStreamReader() { return false; } + + public QName getPayloadQName() { + return new QName(getPayloadNamespaceURI(), getPayloadLocalPart()); + } + + public XMLStreamReader readToBodyStarTag() { + int base = soapVersion.ordinal()*3; + this.envelopeTag = DEFAULT_TAGS.get(base); + this.bodyTag = DEFAULT_TAGS.get(base+2); + List hReaders = new java.util.ArrayList(); + ElemInfo envElem = new ElemInfo(envelopeTag, null); + ElemInfo bdyElem = new ElemInfo(bodyTag, envElem); + for (Header h : getHeaders().asList()) { + try { + hReaders.add(h.readHeader()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + XMLStreamReader soapHeader = null; + if(hReaders.size()>0) { + headerTag = DEFAULT_TAGS.get(base+1); + ElemInfo hdrElem = new ElemInfo(headerTag, envElem); + soapHeader = new XMLReaderComposite(hdrElem, hReaders.toArray(new XMLStreamReader[hReaders.size()])); + } + XMLStreamReader soapBody = new XMLReaderComposite(bdyElem, new XMLStreamReader[]{}); + XMLStreamReader[] soapContent = (soapHeader != null) ? new XMLStreamReader[]{soapHeader, soapBody} : new XMLStreamReader[]{soapBody}; + return new XMLReaderComposite(envElem, soapContent); + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java index 72c054c869a..76f5d65e192 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/saaj/SAAJMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -492,9 +492,11 @@ public class SAAJMessage extends Message { * the {@link com.sun.xml.internal.ws.api.message.Message} implementation itself. */ public Message copy() { + Message result = null; try { + access(); if (!parsedMessage) { - return new SAAJMessage(readAsSOAPMessage()); + result = new SAAJMessage(readAsSOAPMessage()); } else { SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody(); @@ -503,8 +505,9 @@ public class SAAJMessage extends Message { newBody.appendChild(n); } addAttributes(newBody, bodyAttrs); - return new SAAJMessage(getHeaders(), getAttachments(), msg, soapVersion); + result = new SAAJMessage(getHeaders(), getAttachments(), msg, soapVersion); } + return result.copyFrom(this); } catch (SOAPException e) { throw new WebServiceException(e); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java index ad2fa7bed90..afdf853d443 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/source/ProtocolSourceMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -98,7 +98,7 @@ public class ProtocolSourceMessage extends Message { } public Message copy() { - return sm.copy(); + return sm.copy().copyFrom(sm); } public Source readEnvelopeAsSource() { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java index 7e025be7690..9b9ff8c8e6b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/PayloadStreamReaderMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -107,7 +107,7 @@ public class PayloadStreamReaderMessage extends AbstractMessageImpl { } public Message copy() { - return message.copy(); + return message.copy().copyFrom(message); } @Override diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java index 244471d1ab8..93e12e256d6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -50,7 +50,7 @@ import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; import com.sun.xml.internal.ws.util.xml.DummyLocation; import com.sun.xml.internal.ws.util.xml.StAXSource; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.util.xml.XMLReaderComposite.ElemInfo; import org.xml.sax.ContentHandler; @@ -61,6 +61,7 @@ import org.xml.sax.helpers.NamespaceSupport; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; import javax.xml.stream.*; import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT; @@ -415,11 +416,7 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP writeEnvelope(sw); } - /** - * This method should be called when the StreamMessage is created with a payload - * @param writer - */ - private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException { + public void writeToBodyStart(XMLStreamWriter writer) throws XMLStreamException { if ( envelopeReader != null ) readEnvelope(this); writer.writeStartDocument(); envelopeTag.writeStart(writer); @@ -437,6 +434,15 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP writer.writeEndElement(); } bodyTag.writeStart(writer); + + } + + /** + * This method should be called when the StreamMessage is created with a payload + * @param writer + */ + private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException { + writeToBodyStart(writer); if(hasPayload()) writePayloadTo(writer); writer.writeEndElement(); @@ -550,7 +556,7 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP proceedToRootElement(reader); proceedToRootElement(clone); - return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion); + return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion).copyFrom(this); } catch (XMLStreamException e) { throw new WebServiceException("Failed to copy a message",e); } @@ -763,4 +769,30 @@ public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP // the pipe line. return new MutableXMLStreamBuffer(); } + + public boolean isPayloadStreamReader() { return true; } + + public QName getPayloadQName() { + return this.hasPayload() ? new QName(payloadNamespaceURI, payloadLocalName) : null; + } + + public XMLStreamReader readToBodyStarTag() { + if ( envelopeReader != null ) readEnvelope(this); + List hReaders = new java.util.ArrayList(); + ElemInfo envElem = new ElemInfo(envelopeTag, null); + ElemInfo hdrElem = (headerTag != null) ? new ElemInfo(headerTag, envElem) : null; + ElemInfo bdyElem = new ElemInfo(bodyTag, envElem); + for (Header h : getHeaders().asList()) { + try { + hReaders.add(h.readHeader()); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + XMLStreamReader soapHeader = (hdrElem != null) ? new XMLReaderComposite(hdrElem, hReaders.toArray(new XMLStreamReader[hReaders.size()])) : null; + XMLStreamReader[] payload = {}; + XMLStreamReader soapBody = new XMLReaderComposite(bdyElem, payload); + XMLStreamReader[] soapContent = (soapHeader != null) ? new XMLStreamReader[]{soapHeader, soapBody} : new XMLStreamReader[]{soapBody}; + return new XMLReaderComposite(envElem, soapContent); + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java index 67433587cb6..7eed07d9470 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/PolicyMapUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -34,6 +34,7 @@ import com.sun.xml.internal.ws.policy.subject.WsdlBindingSubject; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; +import java.util.Map.Entry; import javax.xml.namespace.QName; /** @@ -102,17 +103,17 @@ public class PolicyMapUtil { } final PolicyMapKeyConverter converter = new PolicyMapKeyConverter(serviceName, portName); - for (WsdlBindingSubject wsdlSubject : subjectToPolicies.keySet()) { - final PolicySubject newSubject = new PolicySubject(wsdlSubject, subjectToPolicies.get(wsdlSubject)); + for (Entry> entry : subjectToPolicies.entrySet()) { + WsdlBindingSubject wsdlSubject = entry.getKey(); + Collection policySet = entry.getValue(); + final PolicySubject newSubject = new PolicySubject(wsdlSubject, policySet); PolicyMapKey mapKey = converter.getPolicyMapKey(wsdlSubject); if (wsdlSubject.isBindingSubject()) { policyMap.putSubject(ScopeType.ENDPOINT, mapKey, newSubject); - } - else if (wsdlSubject.isBindingOperationSubject()) { + } else if (wsdlSubject.isBindingOperationSubject()) { policyMap.putSubject(ScopeType.OPERATION, mapKey, newSubject); - } - else if (wsdlSubject.isBindingMessageSubject()) { + } else if (wsdlSubject.isBindingMessageSubject()) { switch (wsdlSubject.getMessageType()) { case INPUT: policyMap.putSubject(ScopeType.INPUT_MESSAGE, mapKey, newSubject); @@ -123,6 +124,8 @@ public class PolicyMapUtil { case FAULT: policyMap.putSubject(ScopeType.FAULT_MESSAGE, mapKey, newSubject); break; + default: + break; } } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties index d12659622ad..ed591119b2f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/Localization.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2014, 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 @@ -118,3 +118,4 @@ WSP_0092_CHARACTER_DATA_UNEXPECTED=WSP0092: Character data in unexpected element WSP_0093_INVALID_URI=WSP0093: Invalid URI "{0}" at location {1} WSP_0094_INVALID_URN=WSP0094: Internal implementation error. Apparently failed to pass valid URN. WSP_0095_INVALID_BOOLEAN_VALUE=WSP0095: A value of boolean type may have one of the values "true", "false", "1", "0". This value was "{0}". +WSP_0096_ERROR_WHILE_COMBINE=WSP0096: Error while combining {0}. diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java index 4f28cb2cb61..2283e8806a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/LocalizationMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -76,6 +76,18 @@ public final class LocalizationMessages { return localizer.localize(localizableWSP_0081_UNABLE_TO_INSERT_CHILD(arg0, arg1)); } + public static Localizable localizableWSP_0096_ERROR_WHILE_COMBINE(Object arg0) { + return messageFactory.getMessage("WSP_0096_ERROR_WHILE_COMBINE", arg0); + } + + /** + * WSP0096: Error while combining {0}. + * + */ + public static String WSP_0096_ERROR_WHILE_COMBINE(Object arg0) { + return localizer.localize(localizableWSP_0096_ERROR_WHILE_COMBINE(arg0)); + } + public static Localizable localizableWSP_0018_UNABLE_TO_ACCESS_POLICY_SOURCE_MODEL(Object arg0) { return messageFactory.getMessage("WSP_0018_UNABLE_TO_ACCESS_POLICY_SOURCE_MODEL", arg0); } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java index ec537d88358..975464e6eb9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/policy/privateutil/PolicyUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -39,6 +39,7 @@ import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Queue; +import java.util.logging.Level; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -200,6 +201,7 @@ public final class PolicyUtils { } public static class Collections { + private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyUtils.Collections.class); /** * TODO javadocs * @@ -245,7 +247,10 @@ public final class PolicyUtils { } else if (optionSize == 1) { base.addAll(option); } else { - optionProcessingQueue.offer(option); + boolean entered = optionProcessingQueue.offer(option); + if (!entered) { + throw LOGGER.logException(new RuntimePolicyUtilsException(LocalizationMessages.WSP_0096_ERROR_WHILE_COMBINE(option)), false, Level.WARNING); + } finalCombinationsSize *= optionSize; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java index c78aef5ffbf..ae5bf29bb1b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/EndpointFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -89,11 +89,16 @@ import javax.xml.ws.soap.SOAPBinding; import java.io.IOException; import java.net.URL; +import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; /** @@ -189,13 +194,24 @@ public class EndpointFactory { invoker = InstanceResolver.createDefault(implType).createInvoker(); } - List md = new ArrayList(); - if(metadata!=null) + // Performance analysis indicates that reading and parsing imported schemas is + // a major component of Endpoint creation time. Therefore, modify SDDocumentSource + // handling to delay iterating collection as long as possible. + Collection md = new CollectionCollection(); + if(primaryWsdl!=null) { + if(metadata!=null) { + Iterator it = metadata.iterator(); + if (it.hasNext() && primaryWsdl.equals(it.next())) + md.addAll(metadata); + else { + md.add(primaryWsdl); + md.addAll(metadata); + } + } else + md.add(primaryWsdl); + } else if(metadata!=null) md.addAll(metadata); - if(primaryWsdl!=null && !md.contains(primaryWsdl)) - md.add(primaryWsdl); - if(container==null) container = ContainerResolver.getInstance().getContainer(); @@ -227,7 +243,7 @@ public class EndpointFactory { } // Categorises the documents as WSDL, Schema etc - List docList = categoriseMetadata(md, serviceName, portTypeName); + Collection docList = categoriseMetadata(md.iterator(), serviceName, portTypeName); // Finds the primary WSDL and makes sure that metadata doesn't have // two concrete or abstract WSDLs SDDocumentImpl primaryDoc = primaryWsdl != null ? SDDocumentImpl.create(primaryWsdl,serviceName,portTypeName) : findPrimary(docList); @@ -326,50 +342,87 @@ public class EndpointFactory { * * @param primaryDoc primary WSDL doc * @param docList complete metadata - * @return new metadata that doesn't contain extraneous documnets. + * @return new metadata that doesn't contain extraneous documents. */ - private static List findMetadataClosure(SDDocumentImpl primaryDoc, List docList, EntityResolver resolver) { - // create a map for old metadata - Map oldMap = new HashMap(); - for(SDDocumentImpl doc : docList) { - oldMap.put(doc.getSystemId().toString(), doc); - } - // create a map for new metadata - Map newMap = new HashMap(); - newMap.put(primaryDoc.getSystemId().toString(), primaryDoc); + private static Collection findMetadataClosure( + final SDDocumentImpl primaryDoc, final Collection docList, final EntityResolver resolver) { + return new AbstractCollection() { + @Override + public Iterator iterator() { + // create a map for old metadata + Map oldMap = new HashMap(); + Iterator oldDocs = docList.iterator(); - List remaining = new ArrayList(); - remaining.addAll(primaryDoc.getImports()); - while(!remaining.isEmpty()) { - String url = remaining.remove(0); - SDDocumentImpl doc = oldMap.get(url); - if (doc == null) { - // old metadata doesn't have this imported doc, may be external - if (resolver != null) { - try { - InputSource source = resolver.resolveEntity(null, url); - if (source != null) { - MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); - XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream()); - xsb.createFromXMLStreamReader(reader); + // create a map for new metadata + Map newMap = new HashMap(); + newMap.put(primaryDoc.getSystemId().toString(), primaryDoc); - SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb); - doc = SDDocumentImpl.create(sdocSource, null, null); - } - } catch (Exception ex) { - ex.printStackTrace(); + List remaining = new ArrayList(); + remaining.addAll(primaryDoc.getImports()); + while(!remaining.isEmpty()) { + String url = remaining.remove(0); + SDDocumentImpl doc = oldMap.get(url); + if (doc == null) { + while (oldDocs.hasNext()) { + SDDocumentImpl old = oldDocs.next(); + String id = old.getSystemId().toString(); + oldMap.put(id, old); + if (id.equals(url)) { + doc = old; + break; + } } + + if (doc == null) { + // old metadata doesn't have this imported doc, may be external + if (resolver != null) { + try { + InputSource source = resolver.resolveEntity(null, url); + if (source != null) { + MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer(); + XMLStreamReader reader = XmlUtil.newXMLInputFactory(true).createXMLStreamReader(source.getByteStream()); + xsb.createFromXMLStreamReader(reader); + + SDDocumentSource sdocSource = SDDocumentImpl.create(new URL(url), xsb); + doc = SDDocumentImpl.create(sdocSource, null, null); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + } + // Check if new metadata already contains this doc + if (doc != null && !newMap.containsKey(url)) { + newMap.put(url, doc); + remaining.addAll(doc.getImports()); + } } + + return newMap.values().iterator(); } - // Check if new metadata already contains this doc - if (doc != null && !newMap.containsKey(url)) { - newMap.put(url, doc); - remaining.addAll(doc.getImports()); + + @Override + public int size() { + int size = 0; + Iterator it = iterator(); + while (it.hasNext()) { + it.next(); + size++; + } + return size; } - } - List newMetadata = new ArrayList(); - newMetadata.addAll(newMap.values()); - return newMetadata; + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + return docList.isEmpty(); + } + }; } private static void processHandlerAnnotation(WSBinding binding, Class implType, QName serviceName, QName portName) { @@ -599,7 +652,7 @@ public class EndpointFactory { * Generates the WSDL and XML Schema for the endpoint if necessary * It generates WSDL only for SOAP1.1, and for XSOAP1.2 bindings */ - private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, List docs, + private static SDDocumentImpl generateWSDL(WSBinding binding, AbstractSEIModelImpl seiModel, Collection docs, Container container, Class implType) { BindingID bindingId = binding.getBindingId(); if (!bindingId.canGenerateWSDL()) { @@ -634,14 +687,59 @@ public class EndpointFactory { /** * Builds {@link SDDocumentImpl} from {@link SDDocumentSource}. */ - private static List categoriseMetadata( - List src, QName serviceName, QName portTypeName) { + private static Collection categoriseMetadata( + final Iterator src, final QName serviceName, final QName portTypeName) { - List r = new ArrayList(src.size()); - for (SDDocumentSource doc : src) { - r.add(SDDocumentImpl.create(doc,serviceName,portTypeName)); - } - return r; + return new AbstractCollection() { + private final Collection theConverted = new ArrayList(); + + @Override + public boolean add(SDDocumentImpl arg0) { + return theConverted.add(arg0); + } + + @Override + public Iterator iterator() { + return new Iterator() { + private Iterator convIt = theConverted.iterator(); + @Override + public boolean hasNext() { + if (convIt != null && convIt.hasNext()) + return true; + return src.hasNext(); + } + + @Override + public SDDocumentImpl next() { + if (convIt != null && convIt.hasNext()) + return convIt.next(); + convIt = null; + if (!src.hasNext()) + throw new NoSuchElementException(); + SDDocumentImpl next = SDDocumentImpl.create(src.next(),serviceName,portTypeName); + theConverted.add(next); + return next; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + if (!theConverted.isEmpty()) + return false; + return !src.hasNext(); + } + }; } /** @@ -675,7 +773,7 @@ public class EndpointFactory { * @return primay wsdl document, null if is not there in the docList * */ - private static @Nullable SDDocumentImpl findPrimary(@NotNull List docList) { + private static @Nullable SDDocumentImpl findPrimary(@NotNull Collection docList) { SDDocumentImpl primaryDoc = null; boolean foundConcrete = false; boolean foundAbstract = false; @@ -710,7 +808,7 @@ public class EndpointFactory { * @param container container in which this service is running * @return non-null wsdl port object */ - private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, List metadata, + private static @NotNull WSDLPort getWSDLPort(SDDocumentSource primaryWsdl, Collection metadata, @NotNull QName serviceName, @NotNull QName portName, Container container, EntityResolver resolver) { URL wsdlUrl = primaryWsdl.getSystemId(); @@ -746,13 +844,12 @@ public class EndpointFactory { * {@link XMLEntityResolver} that can resolve to {@link SDDocumentSource}s. */ private static final class EntityResolverImpl implements XMLEntityResolver { - private Map metadata = new HashMap(); + private Iterator origMetadata; + private Map metadata = new ConcurrentHashMap(); private EntityResolver resolver; - public EntityResolverImpl(List metadata, EntityResolver resolver) { - for (SDDocumentSource doc : metadata) { - this.metadata.put(doc.getSystemId().toExternalForm(),doc); - } + public EntityResolverImpl(Collection metadata, EntityResolver resolver) { + this.origMetadata = metadata.iterator(); this.resolver = resolver; } @@ -761,6 +858,15 @@ public class EndpointFactory { SDDocumentSource doc = metadata.get(systemId); if (doc != null) return new Parser(doc); + synchronized(this) { + while(origMetadata.hasNext()) { + doc = origMetadata.next(); + String extForm = doc.getSystemId().toExternalForm(); + this.metadata.put(extForm,doc); + if (systemId.equals(extForm)) + return new Parser(doc); + } + } } if (resolver != null) { try { @@ -780,4 +886,72 @@ public class EndpointFactory { private static final Logger logger = Logger.getLogger( com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint"); + + private static class CollectionCollection extends AbstractCollection { + + private final Collection> cols = new ArrayList>(); + + @Override + public Iterator iterator() { + final Iterator> colIt = cols.iterator(); + return new Iterator() { + private Iterator current = null; + + @Override + public boolean hasNext() { + if (current == null || !current.hasNext()) { + do { + if (!colIt.hasNext()) + return false; + current = colIt.next().iterator(); + } while (!current.hasNext()); + return true; + } + return true; + } + + @Override + public T next() { + if (!hasNext()) + throw new NoSuchElementException(); + return current.next(); + } + + @Override + public void remove() { + if (current == null) + throw new IllegalStateException(); + current.remove(); + } + }; + } + + @Override + public int size() { + int size = 0; + for (Collection c : cols) + size += c.size(); + return size; + } + + @Override + public boolean add(T arg0) { + return cols.add(Collections.singleton(arg0)); + } + + @Override + public boolean addAll(Collection arg0) { + return cols.add(arg0); + } + + @Override + public void clear() { + cols.clear(); + } + + @Override + public boolean isEmpty() { + return !iterator().hasNext(); + } + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java index b7417af236b..5dd13151ece 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/SDDocumentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -31,7 +31,7 @@ import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; import com.sun.xml.internal.ws.wsdl.SDDocumentResolver; import com.sun.xml.internal.ws.util.RuntimeVersion; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.wsdl.parser.ParserUtil; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import com.sun.xml.internal.ws.wsdl.writer.DocumentLocationResolver; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java index 07e09ab5cae..e31e77d872b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/ServiceDefinitionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,6 +32,7 @@ import com.sun.xml.internal.ws.api.server.ServiceDefinition; import com.sun.xml.internal.ws.wsdl.SDDocumentResolver; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -47,7 +48,7 @@ import java.util.Map; * @author Kohsuke Kawaguchi */ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumentResolver { - private final List docs; + private final Collection docs; private final Map bySystemId; private final @NotNull SDDocumentImpl primaryWsdl; @@ -65,12 +66,20 @@ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumen * There must be at least one entry. * The first document is considered {@link #getPrimary() primary}. */ - public ServiceDefinitionImpl(List docs, @NotNull SDDocumentImpl primaryWsdl) { + public ServiceDefinitionImpl(Collection docs, @NotNull SDDocumentImpl primaryWsdl) { assert docs.contains(primaryWsdl); this.docs = docs; this.primaryWsdl = primaryWsdl; + this.bySystemId = new HashMap(); + } + + private boolean isInitialized = false; + + private synchronized void init() { + if (isInitialized) + return; + isInitialized = true; - this.bySystemId = new HashMap(docs.size()); for (SDDocumentImpl doc : docs) { bySystemId.put(doc.getURL().toExternalForm(),doc); doc.setFilters(filters); @@ -95,6 +104,7 @@ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumen } public Iterator iterator() { + init(); return (Iterator)docs.iterator(); } @@ -106,6 +116,7 @@ public final class ServiceDefinitionImpl implements ServiceDefinition, SDDocumen * null if none is found. */ public SDDocument resolve(String systemId) { + init(); return bySystemId.get(systemId); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java index 0dbd8f0ab09..46fa601d429 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSDLGenResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -35,9 +35,11 @@ import javax.xml.namespace.QName; import javax.xml.transform.Result; import javax.xml.ws.Holder; import javax.xml.ws.WebServiceException; + import java.net.URL; import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,7 +52,7 @@ import java.util.Map; */ final class WSDLGenResolver implements com.oracle.webservices.internal.api.databinding.WSDLResolver { - private final List docs; + private final Collection docs; private final List newDocs = new ArrayList(); private SDDocumentSource concreteWsdlSource; @@ -65,7 +67,7 @@ final class WSDLGenResolver implements com.oracle.webservices.internal.api.datab private final QName serviceName; private final QName portTypeName; - public WSDLGenResolver(@NotNull List docs,QName serviceName,QName portTypeName) { + public WSDLGenResolver(@NotNull Collection docs,QName serviceName,QName portTypeName) { this.docs = docs; this.serviceName = serviceName; this.portTypeName = portTypeName; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java index ab01d6be48b..145f5be3911 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -26,9 +26,7 @@ package com.sun.xml.internal.ws.spi.db; import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import javax.xml.ws.WebServiceException; /** @@ -42,6 +40,7 @@ public class FieldGetter extends PropertyGetterBase { protected Field field; public FieldGetter(Field f) { + verifyWrapperType(f.getDeclaringClass()); field = f; type = f.getType(); } @@ -50,43 +49,12 @@ public class FieldGetter extends PropertyGetterBase { return field; } - static class PrivilegedGetter implements PrivilegedExceptionAction { - private Object value; - private Field field; - private Object instance; - public PrivilegedGetter(Field field, Object instance) { - super(); - this.field = field; - this.instance = instance; - } - public Object run() throws IllegalAccessException { - if (!field.isAccessible()) { - field.setAccessible(true); - } - value = field.get(instance); - return null; - } - } - public Object get(final Object instance) { - if (field.isAccessible()) { - try { - return field.get(instance); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - PrivilegedGetter privilegedGetter = new PrivilegedGetter(field, instance); - try { - AccessController.doPrivileged(privilegedGetter); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return privilegedGetter.value; + try { + return field.get(instance); + } catch (Exception e) { + throw new WebServiceException(e); } - return null; } public A getAnnotation(Class annotationType) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java index fb606389ab1..10ae6b8d131 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/FieldSetter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -26,10 +26,8 @@ package com.sun.xml.internal.ws.spi.db; import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - +import javax.xml.ws.WebServiceException; +import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; /** * FieldSetter @@ -41,6 +39,7 @@ public class FieldSetter extends PropertySetterBase { protected Field field; public FieldSetter(Field f) { + verifyWrapperType(f.getDeclaringClass()); field = f; type = f.getType(); } @@ -49,29 +48,12 @@ public class FieldSetter extends PropertySetterBase { return field; } - public void set(final Object instance, final Object resource) { - if (field.isAccessible()) { - try { - field.set(instance, resource); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws IllegalAccessException { - if (!field.isAccessible()) { - field.setAccessible(true); - } - field.set(instance, resource); - return null; - } - }); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + public void set(final Object instance, final Object val) { + final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; + try { + field.set(instance, resource); + } catch (Exception e) { + throw new WebServiceException(e); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java index 248c61c8939..9c0800e995b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/JAXBWrapperAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,8 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.namespace.QName; +import javax.xml.ws.WebServiceException; +import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; /** * JAXBWrapperAccessor @@ -58,6 +60,7 @@ public class JAXBWrapperAccessor extends WrapperAccessor { protected HashMap elementDeclaredTypes; public JAXBWrapperAccessor(Class wrapperBean) { + verifyWrapperType(wrapperBean); contentClass = (Class) wrapperBean; HashMap setByQName = new HashMap(); @@ -142,18 +145,16 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } - // _return - if (fieldName.startsWith("_") && !localName.startsWith("_")) { - fieldName = fieldName.substring(1); + Method setMethod = accessor(publicSetters, fieldName, localName); + Method getMethod = accessor(publicGetters, fieldName, localName); + if ( isProperty(field, getMethod, setMethod) ) { + PropertySetter setter = createPropertySetter(field, setMethod); + PropertyGetter getter = createPropertyGetter(field, getMethod); + setByQName.put(qname, setter); + setByLocalpart.put(localName, setter); + getByQName.put(qname, getter); + getByLocalpart.put(localName, getter); } - Method setMethod = publicSetters.get(fieldName); - Method getMethod = publicGetters.get(fieldName); - PropertySetter setter = createPropertySetter(field, setMethod); - PropertyGetter getter = createPropertyGetter(field, getMethod); - setByQName.put(qname, setter); - setByLocalpart.put(localName, setter); - getByQName.put(qname, getter); - getByLocalpart.put(localName, getter); } if (this.elementLocalNameCollision) { this.propertySetters = setByQName; @@ -166,7 +167,25 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } - static protected List getAllFields(Class clz) { + static private Method accessor(HashMap map, String fieldName, String localName) { + Method a = map.get(fieldName); + if (a == null) a = map.get(localName); + if (a == null && fieldName.startsWith("_")) a = map.get(fieldName.substring(1)); + return a; + } + + static private boolean isProperty(Field field, Method getter, Method setter) { + if (java.lang.reflect.Modifier.isPublic(field.getModifiers())) return true; + if (getter == null) return false; + if (setter == null) { + return java.util.Collection.class.isAssignableFrom(field.getType()) || + java.util.Map.class.isAssignableFrom(field.getType()) ; + } else { + return true; + } + } + + static private List getAllFields(Class clz) { List list = new ArrayList(); while (!Object.class.equals(clz)) { list.addAll(Arrays.asList(getDeclaredFields(clz))); @@ -175,23 +194,20 @@ public class JAXBWrapperAccessor extends WrapperAccessor { return list; } - static protected Field[] getDeclaredFields(final Class clz) { + static private Field[] getDeclaredFields(final Class clz) { try { - return (System.getSecurityManager() == null) ? clz .getDeclaredFields() : - AccessController.doPrivileged(new PrivilegedExceptionAction() { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override public Field[] run() throws IllegalAccessException { return clz.getDeclaredFields(); } }); } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; + throw new WebServiceException(e); } } - static protected PropertyGetter createPropertyGetter(Field field, Method getMethod) { + static private PropertyGetter createPropertyGetter(Field field, Method getMethod) { if (!field.isAccessible()) { if (getMethod != null) { MethodGetter methodGetter = new MethodGetter(getMethod); @@ -200,10 +216,10 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } } - return new FieldGetter(field); + return new PrivFieldGetter(field); } - static protected PropertySetter createPropertySetter(Field field, + static private PropertySetter createPropertySetter(Field field, Method setter) { if (!field.isAccessible()) { if (setter != null) { @@ -213,7 +229,7 @@ public class JAXBWrapperAccessor extends WrapperAccessor { } } } - return new FieldSetter(field); + return new PrivFieldSetter(field); } private Class getElementDeclaredType(QName name) { @@ -238,10 +254,10 @@ public class JAXBWrapperAccessor extends WrapperAccessor { public Object get(Object bean) throws DatabindingException { Object val; if (isJAXBElement) { - JAXBElement jaxbElement = (JAXBElement) getter.get(bean); + JAXBElement jaxbElement = (JAXBElement) JAXBWrapperAccessor.get(getter, bean); val = (jaxbElement == null) ? null : jaxbElement.getValue(); } else { - val = getter.get(bean); + val = JAXBWrapperAccessor.get(getter, bean); } if (val == null && isListType) { val = new java.util.ArrayList(); @@ -255,11 +271,95 @@ public class JAXBWrapperAccessor extends WrapperAccessor { if (isJAXBElement) { JAXBElement jaxbElement = new JAXBElement( n, elementDeclaredType, contentClass, value); - setter.set(bean, jaxbElement); + JAXBWrapperAccessor.set(setter, bean, jaxbElement); } else { - setter.set(bean, value); + JAXBWrapperAccessor.set(setter, bean, value); } } }; } + + static private Object get(PropertyGetter getter, Object wrapperInstance) { + return (getter instanceof PrivFieldGetter)? + ((PrivFieldGetter)getter).getPriv(wrapperInstance): + getter.get(wrapperInstance); + } + + static private void set(PropertySetter setter, Object wrapperInstance, Object value) { + if (setter instanceof PrivFieldSetter) + ((PrivFieldSetter)setter).setPriv(wrapperInstance, value); + else + setter.set(wrapperInstance, value); + } + + + static private class PrivFieldSetter extends FieldSetter { + private PrivFieldSetter(Field f) { + super(f); + } + private void setPriv(final Object instance, final Object val) { + final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; + if (field.isAccessible()) { + try { + field.set(instance, resource); + } catch (Exception e) { + throw new WebServiceException(e); + } + } else { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws IllegalAccessException { + if (!field.isAccessible()) { + field.setAccessible(true); + } + field.set(instance, resource); + return null; + } + }); + } catch (PrivilegedActionException e) { + throw new WebServiceException(e); + } + } + } + } + + static private class PrivFieldGetter extends FieldGetter { + private PrivFieldGetter(Field f) { + super(f); + } + static private class PrivilegedGetter implements PrivilegedExceptionAction { + private Object value; + private Field field; + private Object instance; + public PrivilegedGetter(Field field, Object instance) { + super(); + this.field = field; + this.instance = instance; + } + public Object run() throws IllegalAccessException { + if (!field.isAccessible()) { + field.setAccessible(true); + } + value = field.get(instance); + return null; + } + } + private Object getPriv(final Object instance) { + if (field.isAccessible()) { + try { + return field.get(instance); + } catch (Exception e) { + throw new WebServiceException(e); + } + } else { + PrivilegedGetter privilegedGetter = new PrivilegedGetter(field, instance); + try { + AccessController.doPrivileged(privilegedGetter); + } catch (PrivilegedActionException e) { + throw new WebServiceException(e); + } + return privilegedGetter.value; + } + } + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java index 67608951af0..99100dfdf2c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -26,9 +26,7 @@ package com.sun.xml.internal.ws.spi.db; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import javax.xml.ws.WebServiceException; /** @@ -41,6 +39,7 @@ public class MethodGetter extends PropertyGetterBase { private Method method; public MethodGetter(Method m) { + verifyWrapperType(m.getDeclaringClass()); method = m; type = m.getReturnType(); } @@ -54,49 +53,12 @@ public class MethodGetter extends PropertyGetterBase { return (A) method.getAnnotation(c); } - - static class PrivilegedGetter implements PrivilegedExceptionAction { - private Object value; - private Method method; - private Object instance; - public PrivilegedGetter(Method m, Object instance) { - super(); - this.method = m; - this.instance = instance; - } - public Object run() throws IllegalAccessException { - if (!method.isAccessible()) { - method.setAccessible(true); - } - try { - value = method.invoke(instance, new Object[0]); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - } - public Object get(final Object instance) { final Object[] args = new Object[0]; try { - if (method.isAccessible()) { - return method.invoke(instance, args); - } else { - PrivilegedGetter privilegedGetter = new PrivilegedGetter(method, instance); - try { - AccessController.doPrivileged(privilegedGetter); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return privilegedGetter.value; - } + return method.invoke(instance, args); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + throw new WebServiceException(e); } - return null; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java index 15b14b44294..b641d094b14 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/MethodSetter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -25,10 +25,9 @@ package com.sun.xml.internal.ws.spi.db; +import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import javax.xml.ws.WebServiceException; /** @@ -41,6 +40,7 @@ public class MethodSetter extends PropertySetterBase { private Method method; public MethodSetter(Method m) { + verifyWrapperType(m.getDeclaringClass()); method = m; type = m.getParameterTypes()[0]; } @@ -54,34 +54,13 @@ public class MethodSetter extends PropertySetterBase { return (A) method.getAnnotation(c); } - public void set(final Object instance, Object resource) { + public void set(final Object instance, Object val) { + final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; final Object[] args = {resource}; - if (method.isAccessible()) { - try { - method.invoke(instance, args); - } catch (Exception e) { - e.printStackTrace(); - } - } else { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws IllegalAccessException { - if (!method.isAccessible()) { - method.setAccessible(true); - } - try { - method.invoke(instance, args); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - }); - } catch (PrivilegedActionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + try { + method.invoke(instance, args); + } catch (Exception e) { + throw new WebServiceException(e); } } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java index f87cad25886..e2d4fa87910 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertyGetterBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -25,6 +25,8 @@ package com.sun.xml.internal.ws.spi.db; +import javax.xml.ws.WebServiceException; + /** * This is the Gtter of a bean property. * @@ -46,7 +48,7 @@ public abstract class PropertyGetterBase implements PropertyGetter { method.getName().length() > 3) { return true; } else { - if (method.getReturnType().equals(boolean.class) && + if ((method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)) && method.getName().startsWith("is") && method.getName().length() > 2) { return true; @@ -55,4 +57,11 @@ public abstract class PropertyGetterBase implements PropertyGetter { } return false; } + + static void verifyWrapperType(Class wrapperType) { + String className = wrapperType.getName(); + if (className.startsWith("java.") || className.startsWith("javax.")) { + throw new WebServiceException("Invalid wrapper type " + className); + } + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java index 834653f3782..585f83a4b41 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/spi/db/PropertySetterBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -25,6 +25,9 @@ package com.sun.xml.internal.ws.spi.db; +import java.util.HashMap; +import java.util.Map; + /** * This is the Setter of a bean property. * @author shih-chang.chen@oracle.com @@ -44,4 +47,20 @@ public abstract class PropertySetterBase implements PropertySetter { method.getParameterTypes() != null && method.getParameterTypes().length == 1); } + + /** + * Uninitialized map keyed by their classes. + */ + private static final Map uninitializedValues = new HashMap(); + static { + uninitializedValues.put(byte.class, Byte.valueOf((byte) 0)); + uninitializedValues.put(boolean.class, false); + uninitializedValues.put(char.class, Character.valueOf((char) 0)); + uninitializedValues.put(float.class, Float.valueOf(0)); + uninitializedValues.put(double.class, Double.valueOf(0)); + uninitializedValues.put(int.class, Integer.valueOf(0)); + uninitializedValues.put(long.class, Long.valueOf(0)); + uninitializedValues.put(short.class, Short.valueOf((short) 0)); + } + static protected Object uninitializedValue(Class cls) { return uninitializedValues.get(cls); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java index fccf3febc70..3605c48ce8f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/streaming/MtomStreamWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -36,9 +36,12 @@ import javax.xml.stream.XMLStreamWriter; * {@link AttachmentMarshaller}. The marshaller could do processing based on * MTOM threshold, and make decisions about inlining the attachment data or not. * + * * @author Jitendra Kotamraju * @see JAXBMessage * @see MtomCodec + * + * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.MtomStreamWriter */ public interface MtomStreamWriter { AttachmentMarshaller getAttachmentMarshaller(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java index 452eb985cec..d0f2e601da0 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/HttpAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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,11 +32,14 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.HttpURLConnection; +import java.util.AbstractMap; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -172,43 +175,187 @@ public class HttpAdapter extends Adapter { * * @param sdef service definition */ - public final void initWSDLMap(ServiceDefinition sdef) { - this.serviceDefinition = sdef; - if(sdef==null) { + public final void initWSDLMap(final ServiceDefinition serviceDefinition) { + this.serviceDefinition = serviceDefinition; + if(serviceDefinition==null) { wsdls = Collections.emptyMap(); revWsdls = Collections.emptyMap(); } else { - wsdls = new HashMap(); // wsdl=1 --> Doc - // Sort WSDL, Schema documents based on SystemId so that the same - // document gets wsdl=x mapping - Map systemIds = new TreeMap(); - for (SDDocument sdd : sdef) { - if (sdd == sdef.getPrimary()) { // No sorting for Primary WSDL - wsdls.put("wsdl", sdd); - wsdls.put("WSDL", sdd); - } else { - systemIds.put(sdd.getURL().toString(), sdd); - } - } + wsdls = new AbstractMap() { + private Map delegate = null; - int wsdlnum = 1; - int xsdnum = 1; - for (Entry e : systemIds.entrySet()) { - SDDocument sdd = e.getValue(); - if (sdd.isWSDL()) { - wsdls.put("wsdl="+(wsdlnum++),sdd); - } - if (sdd.isSchema()) { - wsdls.put("xsd="+(xsdnum++),sdd); - } - } + private synchronized Map delegate() { + if (delegate != null) + return delegate; - revWsdls = new HashMap(); // Doc --> wsdl=1 - for (Entry e : wsdls.entrySet()) { - if (!e.getKey().equals("WSDL")) { // map Doc --> wsdl, not WSDL - revWsdls.put(e.getValue(),e.getKey()); + delegate = new HashMap(); // wsdl=1 --> Doc + // Sort WSDL, Schema documents based on SystemId so that the same + // document gets wsdl=x mapping + Map systemIds = new TreeMap(); + for (SDDocument sdd : serviceDefinition) { + if (sdd == serviceDefinition.getPrimary()) { // No sorting for Primary WSDL + delegate.put("wsdl", sdd); + delegate.put("WSDL", sdd); + } else { + systemIds.put(sdd.getURL().toString(), sdd); + } + } + + int wsdlnum = 1; + int xsdnum = 1; + for (Entry e : systemIds.entrySet()) { + SDDocument sdd = e.getValue(); + if (sdd.isWSDL()) { + delegate.put("wsdl="+(wsdlnum++),sdd); + } + if (sdd.isSchema()) { + delegate.put("xsd="+(xsdnum++),sdd); + } + } + + return delegate; } - } + + @Override + public void clear() { + delegate().clear(); + } + + @Override + public boolean containsKey(Object arg0) { + return delegate().containsKey(arg0); + } + + @Override + public boolean containsValue(Object arg0) { + return delegate.containsValue(arg0); + } + + @Override + public SDDocument get(Object arg0) { + return delegate().get(arg0); + } + + @Override + public boolean isEmpty() { + return delegate().isEmpty(); + } + + @Override + public Set keySet() { + return delegate().keySet(); + } + + @Override + public SDDocument put(String arg0, SDDocument arg1) { + return delegate().put(arg0, arg1); + } + + @Override + public void putAll( + Map arg0) { + delegate().putAll(arg0); + } + + @Override + public SDDocument remove(Object arg0) { + return delegate().remove(arg0); + } + + @Override + public int size() { + return delegate().size(); + } + + @Override + public Collection values() { + return delegate().values(); + } + + @Override + public Set> entrySet() { + return delegate().entrySet(); + } + }; + + revWsdls = new AbstractMap() { + private Map delegate = null; + + private synchronized Map delegate() { + if (delegate != null) + return delegate; + + delegate = new HashMap(); // Doc --> wsdl=1 + for (Entry e : wsdls.entrySet()) { + if (!e.getKey().equals("WSDL")) { // map Doc --> wsdl, not WSDL + delegate.put(e.getValue(),e.getKey()); + } + } + + return delegate; + } + + @Override + public void clear() { + delegate().clear(); + } + + @Override + public boolean containsKey(Object key) { + return delegate().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate().containsValue(value); + } + + @Override + public Set> entrySet() { + return delegate().entrySet(); + } + + @Override + public String get(Object key) { + return delegate().get(key); + } + + @Override + public boolean isEmpty() { + // TODO Auto-generated method stub + return super.isEmpty(); + } + + @Override + public Set keySet() { + return delegate().keySet(); + } + + @Override + public String put(SDDocument key, String value) { + return delegate().put(key, value); + } + + @Override + public void putAll(Map m) { + delegate().putAll(m); + } + + @Override + public String remove(Object key) { + return delegate().remove(key); + } + + @Override + public int size() { + return delegate().size(); + } + + @Override + public Collection values() { + return delegate().values(); + } + }; } } @@ -981,7 +1128,9 @@ public class HttpAdapter extends Adapter { } } try { - setPublishStatus(Boolean.getBoolean(HttpAdapter.class.getName() + ".publishStatusPage")); + if (System.getProperty(HttpAdapter.class.getName() + ".publishStatusPage") != null) { + setPublishStatus(Boolean.getBoolean(HttpAdapter.class.getName() + ".publishStatusPage")); + } } catch (SecurityException se) { if (LOGGER.isLoggable(Level.CONFIG)) { LOGGER.log(Level.CONFIG, "Cannot read ''{0}'' property, using defaults.", diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java index f8633d182dc..004a122adbf 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -257,7 +257,14 @@ public class HttpTransportPipe extends AbstractTubeImpl { // Allows only certain http status codes for a binding. For all // other status codes, throws exception checkStatusCode(responseStream, con); // throws ClientTransportException - + //To avoid zero-length chunk for One-Way + if (cl ==-1 && con.statusCode == 202 && "Accepted".equals(con.statusMessage) && responseStream != null) { + ByteArrayBuffer buf = new ByteArrayBuffer(); + buf.write(responseStream); //What is within the responseStream? + responseStream.close(); + responseStream = (buf.size()==0)? null : buf.newInputStream(); + buf.close(); + } Packet reply = request.createClientResponse(null); reply.wasTransportSecure = con.isSecure(); if (responseStream != null) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties index c0aaf9f9fa7..188bd319f70 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/version.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2014, 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,7 +23,7 @@ # questions. # -build-id=2.2.9-b130926.1035 -build-version=JAX-WS RI 2.2.9-b130926.1035 -major-version=2.2.9 -svn-revision=8c29a9a53251ff741fca1664a8221dc876b2eac8 +build-id=2.2.10-b140228.1436 +build-version=JAX-WS RI 2.2.10-b140228.1436 +major-version=2.2.10 +svn-revision=e1d4708e8a2aee1ae9d38313452e14ce4b67851a diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java index 7a2abce1811..14ad9743353 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/util/xml/XMLStreamReaderToXMLStreamWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -48,6 +48,8 @@ import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; * * @author Kohsuke Kawaguchi * @author Ryan Shoemaker + * + * @deprecated use com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter */ public class XMLStreamReaderToXMLStreamWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java index 3b6bb7cf309..17f5fe7a3fd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/ws/wsdl/writer/WSDLPatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -27,7 +27,7 @@ package com.sun.xml.internal.ws.wsdl.writer; import com.sun.istack.internal.NotNull; import com.sun.xml.internal.ws.api.server.PortAddressResolver; -import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter; +import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants; import com.sun.xml.internal.ws.addressing.W3CAddressingConstants; import com.sun.xml.internal.ws.addressing.v200408.MemberSubmissionAddressingConstants; diff --git a/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java b/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java index c6b94d64920..218dceb7ae3 100644 --- a/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java +++ b/jaxws/src/share/jaxws_classes/javax/xml/bind/JAXBException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -48,7 +48,7 @@ public class JAXBException extends Exception { * Exception reference * */ - private volatile Throwable linkedException; + private Throwable linkedException; static final long serialVersionUID = -5621384651494307979L; @@ -133,7 +133,7 @@ public class JAXBException extends Exception { * indicates that the linked exception does not exist or * is unknown). */ - public void setLinkedException( Throwable exception ) { + public synchronized void setLinkedException( Throwable exception ) { this.linkedException = exception; } diff --git a/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java b/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java index 9189d21135c..24a295b8d02 100644 --- a/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java +++ b/jaxws/src/share/jaxws_classes/javax/xml/bind/TypeConstraintException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -57,9 +57,8 @@ public class TypeConstraintException extends java.lang.RuntimeException { * Exception reference * */ - private volatile Throwable linkedException; + private Throwable linkedException; - static final long serialVersionUID = -3059799699420143848L; /** * Construct a TypeConstraintException with the specified detail message. The @@ -142,7 +141,7 @@ public class TypeConstraintException extends java.lang.RuntimeException { * indicates that the linked exception does not exist or * is unknown). */ - public void setLinkedException( Throwable exception ) { + public synchronized void setLinkedException( Throwable exception ) { this.linkedException = exception; } From 1f5e01e4f4487816166538a346562e6c75ef8c81 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Tue, 1 Apr 2014 07:46:51 +0200 Subject: [PATCH 093/170] 8038829: G1: More useful information in a few assert messages Reviewed-by: sjohanss, jmasa --- .../src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index bc2e624ac25..f81d35d3230 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -6598,13 +6598,13 @@ public: if (hr->is_young()) { // TODO } else if (hr->startsHumongous()) { - assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->region_num())); + assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrs_index())); _humongous_count.increment(1u, hr->capacity()); } else if (hr->is_empty()) { - assert(hr->containing_set() == _free_list, err_msg("Heap region %u is empty but not on the free list.", hr->region_num())); + assert(hr->containing_set() == _free_list, err_msg("Heap region %u is empty but not on the free list.", hr->hrs_index())); _free_count.increment(1u, hr->capacity()); } else { - assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->region_num())); + assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrs_index())); _old_count.increment(1u, hr->capacity()); } return false; From f67a3b7e04f7f660f170f137c717828fd455f9ec Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 2 Apr 2014 09:17:38 +0200 Subject: [PATCH 094/170] 8038498: Fix includes and C inlining after 8035330 Change 8035330: Remove G1ParScanPartialArrayClosure and G1ParScanHeapEvacClosure broke the debug build on AIX. The method do_oop_partial_array() is added in a header, but requires the inline function par_write_ref() through several inlined calls. In some cpp files, like arguments.cpp, par_write_ref() is not defined as the corresponding inline header and is not included. The AIX debug VM does not start because of the missing symbol. This change solves this by cleaning up include dependencies. Reviewed-by: tschatzl, stefank --- .../gc_implementation/g1/dirtyCardQueue.cpp | 1 + .../gc_implementation/g1/g1CollectedHeap.cpp | 23 +++ .../gc_implementation/g1/g1CollectedHeap.hpp | 151 ++---------------- .../g1/g1CollectedHeap.inline.hpp | 143 +++++++++++++++++ .../vm/gc_implementation/g1/sparsePRT.hpp | 2 +- 5 files changed, 182 insertions(+), 138 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp index 7bdb98f161f..ddebcf53088 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc_implementation/g1/dirtyCardQueue.hpp" +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "runtime/atomic.hpp" #include "runtime/mutexLocker.hpp" diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index f81d35d3230..e9ef8ff5d6c 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -3529,6 +3529,29 @@ public: } }; +bool G1CollectedHeap::is_obj_dead_cond(const oop obj, + const HeapRegion* hr, + const VerifyOption vo) const { + switch (vo) { + case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr); + case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr); + case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); + default: ShouldNotReachHere(); + } + return false; // keep some compilers happy +} + +bool G1CollectedHeap::is_obj_dead_cond(const oop obj, + const VerifyOption vo) const { + switch (vo) { + case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj); + case VerifyOption_G1UseNextMarking: return is_obj_ill(obj); + case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); + default: ShouldNotReachHere(); + } + return false; // keep some compilers happy +} + void G1CollectedHeap::print_on(outputStream* st) const { st->print(" %-20s", "garbage-first heap"); st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 4d0ff5369e4..8716c60c592 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -706,19 +706,7 @@ public: // This is a fast test on whether a reference points into the // collection set or not. Assume that the reference // points into the heap. - bool in_cset_fast_test(oop obj) { - assert(_in_cset_fast_test != NULL, "sanity"); - assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj)); - // no need to subtract the bottom of the heap from obj, - // _in_cset_fast_test is biased - uintx index = cast_from_oop(obj) >> HeapRegion::LogOfHRGrainBytes; - bool ret = _in_cset_fast_test[index]; - // let's make sure the result is consistent with what the slower - // test returns - assert( ret || !obj_in_cs(obj), "sanity"); - assert(!ret || obj_in_cs(obj), "sanity"); - return ret; - } + inline bool in_cset_fast_test(oop obj); void clear_cset_fast_test() { assert(_in_cset_fast_test_base != NULL, "sanity"); @@ -1250,9 +1238,7 @@ public: } } - void old_set_remove(HeapRegion* hr) { - _old_set.remove(hr); - } + inline void old_set_remove(HeapRegion* hr); size_t non_young_capacity_bytes() { return _old_set.total_capacity_bytes() + _humongous_set.total_capacity_bytes(); @@ -1343,7 +1329,7 @@ public: void heap_region_iterate(HeapRegionClosure* blk) const; // Return the region with the given index. It assumes the index is valid. - HeapRegion* region_at(uint index) const { return _hrs.at(index); } + inline HeapRegion* region_at(uint index) const; // Divide the heap region sequence into "chunks" of some size (the number // of regions divided by the number of parallel threads times some @@ -1472,10 +1458,7 @@ public: return true; } - bool is_in_young(const oop obj) { - HeapRegion* hr = heap_region_containing(obj); - return hr != NULL && hr->is_young(); - } + inline bool is_in_young(const oop obj); #ifdef ASSERT virtual bool is_in_partial_collection(const void* p); @@ -1488,9 +1471,7 @@ public: // pre-value that needs to be remembered; for the remembered-set // update logging post-barrier, we don't maintain remembered set // information for young gen objects. - virtual bool can_elide_initializing_store_barrier(oop new_obj) { - return is_in_young(new_obj); - } + virtual inline bool can_elide_initializing_store_barrier(oop new_obj); // Returns "true" iff the given word_size is "very large". static bool isHumongous(size_t word_size) { @@ -1584,23 +1565,9 @@ public: // Added if it is NULL it isn't dead. - bool is_obj_dead(const oop obj) const { - const HeapRegion* hr = heap_region_containing(obj); - if (hr == NULL) { - if (obj == NULL) return false; - else return true; - } - else return is_obj_dead(obj, hr); - } + inline bool is_obj_dead(const oop obj) const; - bool is_obj_ill(const oop obj) const { - const HeapRegion* hr = heap_region_containing(obj); - if (hr == NULL) { - if (obj == NULL) return false; - else return true; - } - else return is_obj_ill(obj, hr); - } + inline bool is_obj_ill(const oop obj) const; bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo); HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo); @@ -1694,26 +1661,10 @@ public: bool is_obj_dead_cond(const oop obj, const HeapRegion* hr, - const VerifyOption vo) const { - switch (vo) { - case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr); - case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr); - case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); - default: ShouldNotReachHere(); - } - return false; // keep some compilers happy - } + const VerifyOption vo) const; bool is_obj_dead_cond(const oop obj, - const VerifyOption vo) const { - switch (vo) { - case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj); - case VerifyOption_G1UseNextMarking: return is_obj_ill(obj); - case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked(); - default: ShouldNotReachHere(); - } - return false; // keep some compilers happy - } + const VerifyOption vo) const; // Printing @@ -1807,11 +1758,7 @@ protected: DirtyCardQueue& dirty_card_queue() { return _dcq; } G1SATBCardTableModRefBS* ctbs() { return _ct_bs; } - template void immediate_rs_update(HeapRegion* from, T* p, int tid) { - if (!from->is_survivor()) { - _g1_rem->par_write_ref(from, p, tid); - } - } + template inline void immediate_rs_update(HeapRegion* from, T* p, int tid); template void deferred_rs_update(HeapRegion* from, T* p, int tid) { // If the new value of the field points to the same region or @@ -1853,13 +1800,7 @@ public: refs()->push(ref); } - template void update_rs(HeapRegion* from, T* p, int tid) { - if (G1DeferredRSUpdate) { - deferred_rs_update(from, p, tid); - } else { - immediate_rs_update(from, p, tid); - } - } + template inline void update_rs(HeapRegion* from, T* p, int tid); HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) { HeapWord* obj = NULL; @@ -1983,54 +1924,7 @@ private: return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK); } - void do_oop_partial_array(oop* p) { - assert(has_partial_array_mask(p), "invariant"); - oop from_obj = clear_partial_array_mask(p); - - assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); - assert(from_obj->is_objArray(), "must be obj array"); - objArrayOop from_obj_array = objArrayOop(from_obj); - // The from-space object contains the real length. - int length = from_obj_array->length(); - - assert(from_obj->is_forwarded(), "must be forwarded"); - oop to_obj = from_obj->forwardee(); - assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); - objArrayOop to_obj_array = objArrayOop(to_obj); - // We keep track of the next start index in the length field of the - // to-space object. - int next_index = to_obj_array->length(); - assert(0 <= next_index && next_index < length, - err_msg("invariant, next index: %d, length: %d", next_index, length)); - - int start = next_index; - int end = length; - int remainder = end - start; - // We'll try not to push a range that's smaller than ParGCArrayScanChunk. - if (remainder > 2 * ParGCArrayScanChunk) { - end = start + ParGCArrayScanChunk; - to_obj_array->set_length(end); - // Push the remainder before we process the range in case another - // worker has run out of things to do and can steal it. - oop* from_obj_p = set_partial_array_mask(from_obj); - push_on_queue(from_obj_p); - } else { - assert(length == end, "sanity"); - // We'll process the final range for this object. Restore the length - // so that the heap remains parsable in case of evacuation failure. - to_obj_array->set_length(end); - } - _scanner.set_region(_g1h->heap_region_containing_raw(to_obj)); - // Process indexes [start,end). It will also process the header - // along with the first chunk (i.e., the chunk with start == 0). - // Note that at this point the length field of to_obj_array is not - // correct given that we are using it to keep track of the next - // start index. oop_iterate_range() (thankfully!) ignores the length - // field and only relies on the start / end parameters. It does - // however return the size of the object which will be incorrect. So - // we have to ignore it even if we wanted to use it. - to_obj_array->oop_iterate_range(&_scanner, start, end); - } + inline void do_oop_partial_array(oop* p); // This method is applied to the fields of the objects that have just been copied. template void do_oop_evac(T* p, HeapRegion* from) { @@ -2060,26 +1954,9 @@ public: oop copy_to_survivor_space(oop const obj); - template void deal_with_reference(T* ref_to_scan) { - if (!has_partial_array_mask(ref_to_scan)) { - // Note: we can use "raw" versions of "region_containing" because - // "obj_to_scan" is definitely in the heap, and is not in a - // humongous region. - HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan); - do_oop_evac(ref_to_scan, r); - } else { - do_oop_partial_array((oop*)ref_to_scan); - } - } + template inline void deal_with_reference(T* ref_to_scan); - void deal_with_reference(StarTask ref) { - assert(verify_task(ref), "sanity"); - if (ref.is_narrow()) { - deal_with_reference((narrowOop*)ref); - } else { - deal_with_reference((oop*)ref); - } - } + inline void deal_with_reference(StarTask ref); public: void trim_queue(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp index 91289d649c3..e3b8fd061a3 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp @@ -29,6 +29,7 @@ #include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/g1AllocRegion.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" +#include "gc_implementation/g1/g1RemSet.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegionSet.inline.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp" @@ -36,6 +37,9 @@ // Inline functions for G1CollectedHeap +// Return the region with the given index. It assumes the index is valid. +inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrs.at(index); } + template inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const { @@ -55,6 +59,10 @@ G1CollectedHeap::heap_region_containing_raw(const T addr) const { return res; } +inline void G1CollectedHeap::old_set_remove(HeapRegion* hr) { + _old_set.remove(hr); +} + inline bool G1CollectedHeap::obj_in_cs(oop obj) { HeapRegion* r = _hrs.addr_to_region((HeapWord*) obj); return r != NULL && r->in_collection_set(); @@ -151,6 +159,24 @@ inline bool G1CollectedHeap::isMarkedNext(oop obj) const { return _cm->nextMarkBitMap()->isMarked((HeapWord *)obj); } + +// This is a fast test on whether a reference points into the +// collection set or not. Assume that the reference +// points into the heap. +inline bool G1CollectedHeap::in_cset_fast_test(oop obj) { + assert(_in_cset_fast_test != NULL, "sanity"); + assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj)); + // no need to subtract the bottom of the heap from obj, + // _in_cset_fast_test is biased + uintx index = cast_from_oop(obj) >> HeapRegion::LogOfHRGrainBytes; + bool ret = _in_cset_fast_test[index]; + // let's make sure the result is consistent with what the slower + // test returns + assert( ret || !obj_in_cs(obj), "sanity"); + assert(!ret || obj_in_cs(obj), "sanity"); + return ret; +} + #ifndef PRODUCT // Support for G1EvacuationFailureALot @@ -224,4 +250,121 @@ inline void G1CollectedHeap::reset_evacuation_should_fail() { } #endif // #ifndef PRODUCT +inline bool G1CollectedHeap::is_in_young(const oop obj) { + HeapRegion* hr = heap_region_containing(obj); + return hr != NULL && hr->is_young(); +} + +// We don't need barriers for initializing stores to objects +// in the young gen: for the SATB pre-barrier, there is no +// pre-value that needs to be remembered; for the remembered-set +// update logging post-barrier, we don't maintain remembered set +// information for young gen objects. +inline bool G1CollectedHeap::can_elide_initializing_store_barrier(oop new_obj) { + return is_in_young(new_obj); +} + +inline bool G1CollectedHeap::is_obj_dead(const oop obj) const { + const HeapRegion* hr = heap_region_containing(obj); + if (hr == NULL) { + if (obj == NULL) return false; + else return true; + } + else return is_obj_dead(obj, hr); +} + +inline bool G1CollectedHeap::is_obj_ill(const oop obj) const { + const HeapRegion* hr = heap_region_containing(obj); + if (hr == NULL) { + if (obj == NULL) return false; + else return true; + } + else return is_obj_ill(obj, hr); +} + +template inline void G1ParScanThreadState::immediate_rs_update(HeapRegion* from, T* p, int tid) { + if (!from->is_survivor()) { + _g1_rem->par_write_ref(from, p, tid); + } +} + +template void G1ParScanThreadState::update_rs(HeapRegion* from, T* p, int tid) { + if (G1DeferredRSUpdate) { + deferred_rs_update(from, p, tid); + } else { + immediate_rs_update(from, p, tid); + } +} + + +inline void G1ParScanThreadState::do_oop_partial_array(oop* p) { + assert(has_partial_array_mask(p), "invariant"); + oop from_obj = clear_partial_array_mask(p); + + assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap."); + assert(from_obj->is_objArray(), "must be obj array"); + objArrayOop from_obj_array = objArrayOop(from_obj); + // The from-space object contains the real length. + int length = from_obj_array->length(); + + assert(from_obj->is_forwarded(), "must be forwarded"); + oop to_obj = from_obj->forwardee(); + assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); + objArrayOop to_obj_array = objArrayOop(to_obj); + // We keep track of the next start index in the length field of the + // to-space object. + int next_index = to_obj_array->length(); + assert(0 <= next_index && next_index < length, + err_msg("invariant, next index: %d, length: %d", next_index, length)); + + int start = next_index; + int end = length; + int remainder = end - start; + // We'll try not to push a range that's smaller than ParGCArrayScanChunk. + if (remainder > 2 * ParGCArrayScanChunk) { + end = start + ParGCArrayScanChunk; + to_obj_array->set_length(end); + // Push the remainder before we process the range in case another + // worker has run out of things to do and can steal it. + oop* from_obj_p = set_partial_array_mask(from_obj); + push_on_queue(from_obj_p); + } else { + assert(length == end, "sanity"); + // We'll process the final range for this object. Restore the length + // so that the heap remains parsable in case of evacuation failure. + to_obj_array->set_length(end); + } + _scanner.set_region(_g1h->heap_region_containing_raw(to_obj)); + // Process indexes [start,end). It will also process the header + // along with the first chunk (i.e., the chunk with start == 0). + // Note that at this point the length field of to_obj_array is not + // correct given that we are using it to keep track of the next + // start index. oop_iterate_range() (thankfully!) ignores the length + // field and only relies on the start / end parameters. It does + // however return the size of the object which will be incorrect. So + // we have to ignore it even if we wanted to use it. + to_obj_array->oop_iterate_range(&_scanner, start, end); +} + +template inline void G1ParScanThreadState::deal_with_reference(T* ref_to_scan) { + if (!has_partial_array_mask(ref_to_scan)) { + // Note: we can use "raw" versions of "region_containing" because + // "obj_to_scan" is definitely in the heap, and is not in a + // humongous region. + HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan); + do_oop_evac(ref_to_scan, r); + } else { + do_oop_partial_array((oop*)ref_to_scan); + } +} + +inline void G1ParScanThreadState::deal_with_reference(StarTask ref) { + assert(verify_task(ref), "sanity"); + if (ref.is_narrow()) { + deal_with_reference((narrowOop*)ref); + } else { + deal_with_reference((oop*)ref); + } +} + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_INLINE_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp index ccd51c92ec1..6094837d35a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_SPARSEPRT_HPP #define SHARE_VM_GC_IMPLEMENTATION_G1_SPARSEPRT_HPP -#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" #include "gc_implementation/g1/heapRegion.hpp" #include "memory/allocation.hpp" #include "memory/cardTableModRefBS.hpp" From 521e1207a70527eed7634dec976666cc7e893323 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 31 Mar 2014 14:02:40 +0200 Subject: [PATCH 095/170] 8033251: Use DWARF debug symbols for Linux 32-bit as default Reviewed-by: dcubed, dholmes, coleenp --- hotspot/make/linux/makefiles/gcc.make | 48 ++++----------------------- 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index 87ef16faed8..9d321ea7dc7 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -337,56 +337,20 @@ endif ifeq ($(DEBUG_BINARIES), true) CFLAGS += -g else - # Use the stabs format for debugging information (this is the default - # on gcc-2.91). It's good enough, has all the information about line - # numbers and local variables, and libjvm.so is only about 16M. - # Change this back to "-g" if you want the most expressive format. - # (warning: that could easily inflate libjvm.so to 150M!) - # Note: The Itanium gcc compiler crashes when using -gstabs. - DEBUG_CFLAGS/ia64 = -g - DEBUG_CFLAGS/amd64 = -g - DEBUG_CFLAGS/arm = -g - DEBUG_CFLAGS/ppc = -g - DEBUG_CFLAGS/ppc64 = -g DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) - ifeq ($(USE_CLANG), true) - # Clang doesn't understand -gstabs - DEBUG_CFLAGS += -g - else - DEBUG_CFLAGS += -gstabs - endif + DEBUG_CFLAGS += -g endif - + ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - FASTDEBUG_CFLAGS/ia64 = -g - FASTDEBUG_CFLAGS/amd64 = -g - FASTDEBUG_CFLAGS/arm = -g - FASTDEBUG_CFLAGS/ppc = -g - FASTDEBUG_CFLAGS/ppc64 = -g - FASTDEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) + FASTDEBUG_CFLAGS += $(FASTDEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(FASTDEBUG_CFLAGS/$(BUILDARCH)),) - ifeq ($(USE_CLANG), true) - # Clang doesn't understand -gstabs - FASTDEBUG_CFLAGS += -g - else - FASTDEBUG_CFLAGS += -gstabs - endif + FASTDEBUG_CFLAGS += -g endif - - OPT_CFLAGS/ia64 = -g - OPT_CFLAGS/amd64 = -g - OPT_CFLAGS/arm = -g - OPT_CFLAGS/ppc = -g - OPT_CFLAGS/ppc64 = -g + OPT_CFLAGS += $(OPT_CFLAGS/$(BUILDARCH)) ifeq ($(OPT_CFLAGS/$(BUILDARCH)),) - ifeq ($(USE_CLANG), true) - # Clang doesn't understand -gstabs - OPT_CFLAGS += -g - else - OPT_CFLAGS += -gstabs - endif + OPT_CFLAGS += -g endif endif endif From 384e2ee8ba97c026ba8c948521711dbf837a7b01 Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Mon, 31 Mar 2014 15:59:00 +0200 Subject: [PATCH 096/170] 8038307: JAX-WS conformance tests fail when running JCK-devtools-8 suite against RI in EBCDIC emulation mode Reviewed-by: chegar --- .../ws/processor/modeler/wsdl/PseudoSchemaBuilder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/PseudoSchemaBuilder.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/PseudoSchemaBuilder.java index b274b42114f..cfbb18b0bed 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/PseudoSchemaBuilder.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/PseudoSchemaBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -41,6 +41,7 @@ import javax.xml.namespace.QName; import java.io.ByteArrayInputStream; import java.io.StringReader; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.*; @@ -107,7 +108,7 @@ public class PseudoSchemaBuilder { } //add w3c EPR binding if(!(options.noAddressingBbinding) && options.target.isLaterThan(Options.Target.V2_1)){ - InputSource is = new InputSource(new ByteArrayInputStream(w3ceprSchemaBinding.getBytes())); + InputSource is = new InputSource(new ByteArrayInputStream(w3ceprSchemaBinding.getBytes(StandardCharsets.UTF_8))); is.setSystemId(sysId+(++i +1)); b.schemas.add(is); } From b712e5983d44971f4b875670a663269cbe5e7a52 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Mon, 31 Mar 2014 19:03:41 +0400 Subject: [PATCH 097/170] 8035437: Xerces Update: xml/serialize/DOMSerializerImpl Reviewed-by: lancea --- .../internal/dom/DOMStringListImpl.java | 71 +- .../internal/impl/XMLEntityManager.java | 74 +- .../serialize/BaseMarkupSerializer.java | 173 ++- .../internal/serialize/DOMSerializerImpl.java | 1169 ++++++++--------- .../internal/serialize/XML11Serializer.java | 217 +-- .../xml/internal/serialize/XMLSerializer.java | 127 +- 6 files changed, 904 insertions(+), 927 deletions(-) diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java b/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java index c5ce5ec2615..835a66fe1c4 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/dom/DOMStringListImpl.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 2001, 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -20,6 +21,7 @@ package com.sun.org.apache.xerces.internal.dom; +import java.util.ArrayList; import java.util.Vector; import org.w3c.dom.DOMStringList; @@ -35,47 +37,54 @@ import org.w3c.dom.DOMStringList; */ public class DOMStringListImpl implements DOMStringList { - //A collection of DOMString values - private Vector fStrings; + // A collection of DOMString values + private final ArrayList fStrings; /** * Construct an empty list of DOMStringListImpl */ public DOMStringListImpl() { - fStrings = new Vector(); + fStrings = new ArrayList(); } /** - * Construct an empty list of DOMStringListImpl + * Construct a DOMStringListImpl from an ArrayList */ - public DOMStringListImpl(Vector params) { + public DOMStringListImpl(ArrayList params) { fStrings = params; } - /** - * @see org.w3c.dom.DOMStringList#item(int) - */ - public String item(int index) { - try { - return (String) fStrings.elementAt(index); - } catch (ArrayIndexOutOfBoundsException e) { - return null; - } - } + /** + * Construct a DOMStringListImpl from a Vector + */ + public DOMStringListImpl(Vector params) { + fStrings = new ArrayList(params); + } - /** - * @see org.w3c.dom.DOMStringList#getLength() - */ - public int getLength() { - return fStrings.size(); + /** + * @see org.w3c.dom.DOMStringList#item(int) + */ + public String item(int index) { + final int length = getLength(); + if (index >= 0 && index < length) { + return (String) fStrings.get(index); } + return null; + } - /** - * @see org.w3c.dom.DOMStringList#contains(String) - */ - public boolean contains(String param) { - return fStrings.contains(param) ; - } + /** + * @see org.w3c.dom.DOMStringList#getLength() + */ + public int getLength() { + return fStrings.size(); + } + + /** + * @see org.w3c.dom.DOMStringList#contains(String) + */ + public boolean contains(String param) { + return fStrings.contains(param); + } /** * DOM Internal: diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java index 09a82608c14..988fd6f9c60 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java @@ -1,13 +1,14 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * reserved comment block + * DO NOT REMOVE OR ALTER! */ - /* - * Copyright 2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -52,7 +53,7 @@ import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Stack; -import javax.xml.XMLConstants; +import java.util.StringTokenizer; /** @@ -1810,7 +1811,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { userDir = userDir.replace(separator, '/'); int len = userDir.length(), ch; - StringBuffer buffer = new StringBuffer(len*3); + StringBuilder buffer = new StringBuilder(len*3); // change C:/blah to /C:/blah if (len >= 2 && userDir.charAt(1) == ':') { ch = Character.toUpperCase(userDir.charAt(0)); @@ -1880,6 +1881,61 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { return gUserDirURI; } + public static OutputStream createOutputStream(String uri) throws IOException { + // URI was specified. Handle relative URIs. + final String expanded = XMLEntityManager.expandSystemId(uri, null, true); + final URL url = new URL(expanded != null ? expanded : uri); + OutputStream out = null; + String protocol = url.getProtocol(); + String host = url.getHost(); + // Use FileOutputStream if this URI is for a local file. + if (protocol.equals("file") + && (host == null || host.length() == 0 || host.equals("localhost"))) { + File file = new File(getPathWithoutEscapes(url.getPath())); + if (!file.exists()) { + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + } + out = new FileOutputStream(file); + } + // Try to write to some other kind of URI. Some protocols + // won't support this, though HTTP should work. + else { + URLConnection urlCon = url.openConnection(); + urlCon.setDoInput(false); + urlCon.setDoOutput(true); + urlCon.setUseCaches(false); // Enable tunneling. + if (urlCon instanceof HttpURLConnection) { + // The DOM L3 REC says if we are writing to an HTTP URI + // it is to be done with an HTTP PUT. + HttpURLConnection httpCon = (HttpURLConnection) urlCon; + httpCon.setRequestMethod("PUT"); + } + out = urlCon.getOutputStream(); + } + return out; + } + + private static String getPathWithoutEscapes(String origPath) { + if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) { + // Locate the escape characters + StringTokenizer tokenizer = new StringTokenizer(origPath, "%"); + StringBuilder result = new StringBuilder(origPath.length()); + int size = tokenizer.countTokens(); + result.append(tokenizer.nextToken()); + for(int i = 1; i < size; ++i) { + String token = tokenizer.nextToken(); + // Decode the 2 digit hexadecimal number following % in '%nn' + result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue()); + result.append(token.substring(2)); + } + return result.toString(); + } + return origPath; + } + /** * Absolutizes a URI using the current value * of the "user.dir" property as the base URI. If diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java index 9bbdaec2fe9..3150b10d860 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -18,7 +19,6 @@ * limitations under the License. */ - // Sep 14, 2000: // Fixed comments to preserve whitespaces and add a line break // when indenting. Reported by Gervase Markham @@ -57,17 +57,13 @@ import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl; import com.sun.org.apache.xerces.internal.dom.DOMLocatorImpl; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.util.XMLChar; -import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.DocumentType; -import org.w3c.dom.DOMError; -import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.Element; -import org.w3c.dom.Entity; -import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import org.w3c.dom.Notation; import org.w3c.dom.ls.LSException; import org.w3c.dom.ls.LSSerializerFilter; import org.w3c.dom.traversal.NodeFilter; @@ -126,7 +122,7 @@ import org.xml.sax.ext.LexicalHandler; * @author Elena Litani, IBM * @author Sunitha Reddy, Sun Microsystems * @see Serializer - * @see LSSerializer + * @see org.w3c.dom.ls.LSSerializer */ public abstract class BaseMarkupSerializer implements ContentHandler, DocumentHandler, LexicalHandler, @@ -337,6 +333,9 @@ public abstract class BaseMarkupSerializer return true; } + protected void cleanup() { + fCurrentNode = null; + } protected void prepare() throws IOException @@ -409,6 +408,7 @@ public abstract class BaseMarkupSerializer reset(); prepare(); serializeNode( elem ); + cleanup(); _printer.flush(); if ( _printer.getException() != null ) throw _printer.getException(); @@ -438,7 +438,7 @@ public abstract class BaseMarkupSerializer * writer and output format. Throws an exception only if * an I/O exception occured while serializing. * - * @param elem The element to serialize + * @param frag The document fragment to serialize * @throws IOException An I/O exception occured while * serializing */ @@ -448,6 +448,7 @@ public abstract class BaseMarkupSerializer reset(); prepare(); serializeNode( frag ); + cleanup(); _printer.flush(); if ( _printer.getException() != null ) throw _printer.getException(); @@ -470,6 +471,7 @@ public abstract class BaseMarkupSerializer prepare(); serializeNode( doc ); serializePreRoot(); + cleanup(); _printer.flush(); if ( _printer.getException() != null ) throw _printer.getException(); @@ -530,22 +532,22 @@ public abstract class BaseMarkupSerializer if (!XMLChar.isValid(ch)) { // check if it is surrogate if (++index < end) { - surrogates(ch, chars[index]); + surrogates(ch, chars[index],true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; - } else { - if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0xF7 ) || - ch == '\n' || ch == '\r' || ch == '\t' ) { - _printer.printText((char)ch); - } else { - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";= ' ' && _encodingInfo.isPrintable(ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + _printer.printText(ch); + } + else { + // The character is not printable -- split CDATA section + _printer.printText("]]>&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";empty and afterElement set to false. * * @return The current element state - * @throws IOException An I/O exception occured while + * @throws IOException An I/O exception occurred while * serializing */ protected ElementState content() @@ -1415,7 +1411,6 @@ public abstract class BaseMarkupSerializer * whether the text is printed as CDATA or unescaped. * * @param text The text to print - * @param unescaped True is should print unescaped * @throws IOException An I/O exception occured while * serializing */ @@ -1430,9 +1425,6 @@ public abstract class BaseMarkupSerializer // state) or whether we are inside a CDATA section or entity. if ( state.inCData || state.doCData ) { - int index; - int saveIndent; - // Print a CDATA section. The text is not escaped, but ']]>' // appearing in the code must be identified and dealt with. // The contents of a text node is considered space preserving. @@ -1440,7 +1432,7 @@ public abstract class BaseMarkupSerializer _printer.printText("= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0xF7 ) || - ch == '\n' || ch == '\r' || ch == '\t' ) { - _printer.printText((char)ch); - } else { + } + if ( ( ch >= ' ' && _encodingInfo.isPrintable(ch) && ch != 0x7F ) || + ch == '\n' || ch == '\r' || ch == '\t' ) { + _printer.printText(ch); + } + else { - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";&#x"); _printer.printText(Integer.toHexString(supplemental)); _printer.printText("; 0 ) { - ch = chars[ start ]; + char ch = chars[ start ]; ++start; - if ( ch == '\n' || ch == '\r' || unescaped ) + if ( ch == '\n' || ch == '\r' || unescaped ) { _printer.printText( ch ); - else + } + else { printEscaped( ch ); + } } } else { // Not preserving spaces: print one part at a time, and @@ -1664,14 +1656,17 @@ public abstract class BaseMarkupSerializer // by printing mechanism. Line terminator is treated // no different than other text part. while ( length-- > 0 ) { - ch = chars[ start ]; + char ch = chars[ start ]; ++start; - if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) + if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) { _printer.printSpace(); - else if ( unescaped ) + } + else if ( unescaped ) { _printer.printText( ch ); - else + } + else { printEscaped( ch ); + } } } } @@ -1703,12 +1698,15 @@ public abstract class BaseMarkupSerializer // no different than other text part. for ( index = 0 ; index < text.length() ; ++index ) { ch = text.charAt( index ); - if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) + if ( ch == ' ' || ch == '\f' || ch == '\t' || ch == '\n' || ch == '\r' ) { _printer.printSpace(); - else if ( unescaped ) + } + else if ( unescaped ) { _printer.printText( ch ); - else + } + else { printEscaped( ch ); + } } } } @@ -1751,7 +1749,7 @@ public abstract class BaseMarkupSerializer _printer.printText( '&' ); _printer.printText( charRef ); _printer.printText( ';' ); - } else if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0xF7 ) || + } else if ( ( ch >= ' ' && _encodingInfo.isPrintable((char)ch) && ch != 0x7F ) || ch == '\n' || ch == '\r' || ch == '\t' ) { // Non printables are below ASCII space but not tab or line // terminator, ASCII delete, or above a certain Unicode threshold. @@ -1872,14 +1870,13 @@ public abstract class BaseMarkupSerializer { if ( _elementStateCount > 0 ) { /*Corrected by David Blondeau (blondeau@intalio.com)*/ - _prefixes = null; - //_prefixes = _elementStates[ _elementStateCount ].prefixes; + _prefixes = null; + //_prefixes = _elementStates[ _elementStateCount ].prefixes; -- _elementStateCount; return _elementStates[ _elementStateCount ]; - } else { - String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "Internal", null); - throw new IllegalStateException(msg); } + String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "Internal", null); + throw new IllegalStateException(msg); } @@ -1890,11 +1887,14 @@ public abstract class BaseMarkupSerializer * * @return True if in the state of the document */ - protected boolean isDocumentState() - { + protected boolean isDocumentState() { return _elementStateCount == 0; } + /** Clears document state. **/ + final void clearDocumentState() { + _elementStateCount = 0; + } /** * Returns the namespace prefix for the specified URI. @@ -1913,15 +1913,14 @@ public abstract class BaseMarkupSerializer if ( prefix != null ) return prefix; } - if ( _elementStateCount == 0 ) + if ( _elementStateCount == 0 ) { return null; - else { - for ( int i = _elementStateCount ; i > 0 ; --i ) { - if ( _elementStates[ i ].prefixes != null ) { - prefix = (String) _elementStates[ i ].prefixes.get( namespaceURI ); - if ( prefix != null ) - return prefix; - } + } + for ( int i = _elementStateCount ; i > 0 ; --i ) { + if ( _elementStates[ i ].prefixes != null ) { + prefix = (String) _elementStates[ i ].prefixes.get( namespaceURI ); + if ( prefix != null ) + return prefix; } } return null; diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java index fdced040897..c9b36c5b07a 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -17,21 +18,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.sun.org.apache.xml.internal.serialize; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.StringTokenizer; -import java.util.Vector; +import java.util.ArrayList; import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl; import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl; @@ -39,10 +34,6 @@ import com.sun.org.apache.xerces.internal.dom.DOMLocatorImpl; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.dom.DOMNormalizer; import com.sun.org.apache.xerces.internal.dom.DOMStringListImpl; -import org.w3c.dom.DOMConfiguration; -import org.w3c.dom.DOMError; -import org.w3c.dom.DOMErrorHandler; -import org.w3c.dom.DOMStringList; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; import com.sun.org.apache.xerces.internal.util.DOMUtil; @@ -52,26 +43,30 @@ import com.sun.org.apache.xerces.internal.util.XML11Char; import com.sun.org.apache.xerces.internal.util.XMLChar; import org.w3c.dom.Attr; import org.w3c.dom.Comment; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMError; +import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; import org.w3c.dom.ls.LSException; import org.w3c.dom.ls.LSOutput; import org.w3c.dom.ls.LSSerializer; import org.w3c.dom.ls.LSSerializerFilter; - /** - * EXPERIMENTAL: Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer by delegating serialization - * calls to XMLSerializer. - * LSSerializer provides an API for serializing (writing) a DOM document out in an - * XML document. The XML data is written to an output stream. - * During serialization of XML data, namespace fixup is done when possible as - * defined in DOM Level 3 Core, Appendix B. + * EXPERIMENTAL: Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer by + * delegating serialization calls to XMLSerializer. LSSerializer + * provides an API for serializing (writing) a DOM document out in an XML + * document. The XML data is written to an output stream. During serialization + * of XML data, namespace fixup is done when possible as defined in DOM Level 3 + * Core, Appendix B. * * @author Elena Litani, IBM * @author Gopal Sharma, Sun Microsystems @@ -84,7 +79,6 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // TODO: When DOM Level 3 goes to REC replace method calls using // reflection for: getXmlEncoding, getInputEncoding and getXmlEncoding // with regular static calls on the Document object. - // data // serializer private XMLSerializer serializer; @@ -95,35 +89,36 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { //Recognized parameters private DOMStringList fRecognizedParameters; - /** REVISIT: Currently we handle 3 different configurations, would be nice just have one configuration - * that has different recognized parameters depending if it is used in Core/LS. + /** + * REVISIT: Currently we handle 3 different configurations, would be nice + * just have one configuration that has different recognized parameters + * depending if it is used in Core/LS. */ protected short features = 0; - protected final static short NAMESPACES = 0x1<<0; - protected final static short WELLFORMED = 0x1<<1; - protected final static short ENTITIES = 0x1<<2; - protected final static short CDATA = 0x1<<3; - protected final static short SPLITCDATA = 0x1<<4; - protected final static short COMMENTS = 0x1<<5; - protected final static short DISCARDDEFAULT = 0x1<<6; - protected final static short INFOSET = 0x1<<7; - protected final static short XMLDECL = 0x1<<8; - protected final static short NSDECL = 0x1<<9; - protected final static short DOM_ELEMENT_CONTENT_WHITESPACE = 0x1<<10; - protected final static short FORMAT_PRETTY_PRINT = 0x1<<11; + protected final static short NAMESPACES = 0x1 << 0; + protected final static short WELLFORMED = 0x1 << 1; + protected final static short ENTITIES = 0x1 << 2; + protected final static short CDATA = 0x1 << 3; + protected final static short SPLITCDATA = 0x1 << 4; + protected final static short COMMENTS = 0x1 << 5; + protected final static short DISCARDDEFAULT = 0x1 << 6; + protected final static short INFOSET = 0x1 << 7; + protected final static short XMLDECL = 0x1 << 8; + protected final static short NSDECL = 0x1 << 9; + protected final static short DOM_ELEMENT_CONTENT_WHITESPACE = 0x1 << 10; + protected final static short PRETTY_PRINT = 0x1 << 11; // well-formness checking private DOMErrorHandler fErrorHandler = null; private final DOMErrorImpl fError = new DOMErrorImpl(); private final DOMLocatorImpl fLocator = new DOMLocatorImpl(); - private static final RuntimeException abort = new RuntimeException(); /** - * Constructs a new LSSerializer. - * The constructor turns on the namespace support in XMLSerializer and - * initializes the following fields: fNSBinder, fLocalNSBinder, fSymbolTable, - * fEmptySymbol, fXmlSymbol, fXmlnsSymbol, fNamespaceCounter, fFeatures. + * Constructs a new LSSerializer. The constructor turns on the namespace + * support in XMLSerializer and initializes the following + * fields: fNSBinder, fLocalNSBinder, fSymbolTable, fEmptySymbol, + * fXmlSymbol, fXmlnsSymbol, fNamespaceCounter, fFeatures. */ public DOMSerializerImpl() { // set default features @@ -142,24 +137,21 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { initSerializer(serializer); } - - // // LSSerializer methods // - - public DOMConfiguration getDomConfig(){ + public DOMConfiguration getDomConfig() { return this; } - /** DOM L3-EXPERIMENTAL: - * Setter for boolean and object parameters + /** + * DOM L3-EXPERIMENTAL: Setter for boolean and object parameters */ public void setParameter(String name, Object value) throws DOMException { if (value instanceof Boolean) { boolean state = ((Boolean) value).booleanValue(); - if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){ - if (state){ + if (name.equalsIgnoreCase(Constants.DOM_INFOSET)) { + if (state) { features &= ~ENTITIES; features &= ~CDATA; features |= NAMESPACES; @@ -169,54 +161,50 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { } // false does not have any effect } else if (name.equalsIgnoreCase(Constants.DOM_XMLDECL)) { - features = - (short) (state ? features | XMLDECL : features & ~XMLDECL); + features + = (short) (state ? features | XMLDECL : features & ~XMLDECL); } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { - features = - (short) (state + features + = (short) (state ? features | NAMESPACES : features & ~NAMESPACES); serializer.fNamespaces = state; } else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) { - features = - (short) (state + features + = (short) (state ? features | SPLITCDATA : features & ~SPLITCDATA); } else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)) { - features = - (short) (state + features + = (short) (state ? features | DISCARDDEFAULT : features & ~DISCARDDEFAULT); } else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) { - features = - (short) (state + features + = (short) (state ? features | WELLFORMED : features & ~WELLFORMED); - } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)){ - features = - (short) (state + } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)) { + features + = (short) (state ? features | ENTITIES : features & ~ENTITIES); - } - else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)){ - features = - (short) (state + } else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) { + features + = (short) (state ? features | CDATA : features & ~CDATA); - } - else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)){ - features = - (short) (state - ? features | COMMENTS - : features & ~COMMENTS); - } - else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)){ - features = - (short) (state - ? features | FORMAT_PRETTY_PRINT - : features & ~FORMAT_PRETTY_PRINT); - } - else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) + } else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { + features + = (short) (state + ? features | COMMENTS + : features & ~COMMENTS); + } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + features + = (short) (state + ? features | PRETTY_PRINT + : features & ~PRETTY_PRINT); + } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) || name.equalsIgnoreCase(Constants.DOM_VALIDATE) || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) @@ -224,85 +212,81 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { // true is not supported if (state) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } - }else if ( - name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { - //namespace-declaration has effect only if namespaces is true - features = - (short) (state - ? features | NSDECL - : features & ~NSDECL); - serializer.fNamespacePrefixes = state; + } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { + //namespace-declaration has effect only if namespaces is true + features + = (short) (state + ? features | NSDECL + : features & ~NSDECL); + serializer.fNamespacePrefixes = state; } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { // false is not supported if (!state) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_FOUND", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { if (value == null || value instanceof DOMErrorHandler) { - fErrorHandler = (DOMErrorHandler)value; + fErrorHandler = (DOMErrorHandler) value; } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "TYPE_MISMATCH_ERR", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "TYPE_MISMATCH_ERR", + new Object[]{name}); throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg); } - } else if ( - name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) + } else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE) || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS) && value != null) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_FOUND", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[]{name}); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } - /** DOM L3-EXPERIMENTAL: - * Check if parameter can be set + /** + * DOM L3-EXPERIMENTAL: Check if parameter can be set */ public boolean canSetParameter(String name, Object state) { - if (state == null) { return true; } if (state instanceof Boolean) { boolean value = ((Boolean) state).booleanValue(); - if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES) || name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA) || name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT) @@ -312,8 +296,8 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { || name.equalsIgnoreCase(Constants.DOM_ENTITIES) || name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS) || name.equalsIgnoreCase(Constants.DOM_COMMENTS) - || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS) - || name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + || name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT) + || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { // both values supported return true; } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) @@ -329,8 +313,8 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // false is not supported return value; } - } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER) && - state == null || state instanceof DOMErrorHandler) { + } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER) + && state == null || state instanceof DOMErrorHandler) { return true; } @@ -338,60 +322,57 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { } /** - * DOM Level 3 Core CR - Experimental. + * DOM Level 3 Core CR - Experimental. * - * The list of the parameters supported by this - * DOMConfiguration object and for which at least one value - * can be set by the application. Note that this list can also contain - * parameter names defined outside this specification. + * The list of the parameters supported by this + * DOMConfiguration object and for which at least one value can + * be set by the application. Note that this list can also contain parameter + * names defined outside this specification. */ public DOMStringList getParameterNames() { - if (fRecognizedParameters == null){ - Vector parameters = new Vector(); + if (fRecognizedParameters == null) { + ArrayList parameters = new ArrayList(); - //Add DOM recognized parameters - //REVISIT: Would have been nice to have a list of - //recognized parameters. - parameters.add(Constants.DOM_NAMESPACES); - parameters.add(Constants.DOM_SPLIT_CDATA); - parameters.add(Constants.DOM_DISCARD_DEFAULT_CONTENT); - parameters.add(Constants.DOM_XMLDECL); - parameters.add(Constants.DOM_CANONICAL_FORM); - parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); - parameters.add(Constants.DOM_VALIDATE); - parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); - parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); - parameters.add(Constants.DOM_FORMAT_PRETTY_PRINT); - //parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); - parameters.add(Constants.DOM_WELLFORMED); - parameters.add(Constants.DOM_INFOSET); - parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); - parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); - parameters.add(Constants.DOM_ENTITIES); - parameters.add(Constants.DOM_CDATA_SECTIONS); - parameters.add(Constants.DOM_COMMENTS); - parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS); - parameters.add(Constants.DOM_ERROR_HANDLER); - //parameters.add(Constants.DOM_SCHEMA_LOCATION); - //parameters.add(Constants.DOM_SCHEMA_TYPE); - - //Add recognized xerces features and properties - - fRecognizedParameters = new DOMStringListImpl(parameters); + //Add DOM recognized parameters + //REVISIT: Would have been nice to have a list of + //recognized parameters. + parameters.add(Constants.DOM_NAMESPACES); + parameters.add(Constants.DOM_SPLIT_CDATA); + parameters.add(Constants.DOM_DISCARD_DEFAULT_CONTENT); + parameters.add(Constants.DOM_XMLDECL); + parameters.add(Constants.DOM_CANONICAL_FORM); + parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA); + parameters.add(Constants.DOM_VALIDATE); + parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION); + parameters.add(Constants.DOM_DATATYPE_NORMALIZATION); + parameters.add(Constants.DOM_FORMAT_PRETTY_PRINT); + //parameters.add(Constants.DOM_NORMALIZE_CHARACTERS); + parameters.add(Constants.DOM_WELLFORMED); + parameters.add(Constants.DOM_INFOSET); + parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS); + parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE); + parameters.add(Constants.DOM_ENTITIES); + parameters.add(Constants.DOM_CDATA_SECTIONS); + parameters.add(Constants.DOM_COMMENTS); + parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS); + parameters.add(Constants.DOM_ERROR_HANDLER); + //parameters.add(Constants.DOM_SCHEMA_LOCATION); + //parameters.add(Constants.DOM_SCHEMA_TYPE); + //Add recognized xerces features and properties + fRecognizedParameters = new DOMStringListImpl(parameters); } return fRecognizedParameters; } - /** DOM L3-EXPERIMENTAL: - * Getter for boolean and object parameters + /** + * DOM L3-EXPERIMENTAL: Getter for boolean and object parameters */ public Object getParameter(String name) throws DOMException { - - if(name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)){ - return null; + if (name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) { + return null; } else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) { return ((features & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) { @@ -408,23 +389,23 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { return (features & WELLFORMED) != 0 ? Boolean.TRUE : Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) { return (features & NSDECL) != 0 ? Boolean.TRUE : Boolean.FALSE; - } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { - return (features & FORMAT_PRETTY_PRINT) != 0 ? Boolean.TRUE : Boolean.FALSE; - } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) || - name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { + } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) + || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) { return Boolean.TRUE; - }else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)){ - return ((features & DISCARDDEFAULT)!=0)?Boolean.TRUE:Boolean.FALSE; - }else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){ - if ((features & ENTITIES) == 0 && - (features & CDATA) == 0 && - (features & NAMESPACES) != 0 && - (features & NSDECL) != 0 && - (features & WELLFORMED) != 0 && - (features & COMMENTS) != 0) { - return Boolean.TRUE; - } - return Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)) { + return ((features & DISCARDDEFAULT) != 0) ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) { + return ((features & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE; + } else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)) { + if ((features & ENTITIES) == 0 + && (features & CDATA) == 0 + && (features & NAMESPACES) != 0 + && (features & NSDECL) != 0 + && (features & WELLFORMED) != 0 + && (features & COMMENTS) != 0) { + return Boolean.TRUE; + } + return Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM) || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA) || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION) @@ -434,64 +415,48 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { return Boolean.FALSE; } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) { return fErrorHandler; - } else if ( - name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) + } else if (name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION) || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_SUPPORTED", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_SUPPORTED", + new Object[]{name}); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } else { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "FEATURE_NOT_FOUND", - new Object[] { name }); + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "FEATURE_NOT_FOUND", + new Object[]{name}); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } - /** - * DOM L3 EXPERIMENTAL: - * Serialize the specified node as described above in the description of - * LSSerializer. The result of serializing the node is - * returned as a string. Writing a Document or Entity node produces a - * serialized form that is well formed XML. Writing other node types - * produces a fragment of text in a form that is not fully defined by + * DOM L3 EXPERIMENTAL: Serialize the specified node as described above in + * the description of LSSerializer. The result of serializing + * the node is returned as a string. Writing a Document or Entity node + * produces a serialized form that is well formed XML. Writing other node + * types produces a fragment of text in a form that is not fully defined by * this document, but that should be useful to a human for debugging or * diagnostic purposes. - * @param wnode The node to be written. - * @return Returns the serialized data - * @exception DOMException - * DOMSTRING_SIZE_ERR: The resulting string is too long to fit in a - * DOMString. - * @exception LSException - * SERIALIZE_ERR: Unable to serialize the node. DOM applications should - * attach a DOMErrorHandler using the parameter - * "error-handler" to get details on error. + * + * @param wnode The node to be written. + * @return Returns the serialized data + * @exception DOMException DOMSTRING_SIZE_ERR: The resulting string is too + * long to fit in a DOMString. + * @exception LSException SERIALIZE_ERR: Unable to serialize the node. DOM + * applications should attach a DOMErrorHandler using the + * parameter "error-handler" to get details on error. */ public String writeToString(Node wnode) throws DOMException, LSException { // determine which serializer to use: - Document doc = (wnode.getNodeType() == Node.DOCUMENT_NODE)?(Document)wnode:wnode.getOwnerDocument(); - Method getVersion = null; XMLSerializer ser = null; - String ver = null; - // this should run under JDK 1.1.8... - try { - getVersion = doc.getClass().getMethod("getXmlVersion", new Class[]{}); - if(getVersion != null ) { - ver = (String)getVersion.invoke(doc, (Object[]) null); - } - } catch (Exception e) { - // no way to test the version... - // ignore the exception - } - if(ver != null && ver.equals("1.1")) { - if(xml11Serializer == null) { + String ver = _getXmlVersion(wnode); + if (ver != null && ver.equals("1.1")) { + if (xml11Serializer == null) { xml11Serializer = new XML11Serializer(); initSerializer(xml11Serializer); } @@ -508,25 +473,21 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser._format.setEncoding("UTF-16"); ser.setOutputCharStream(destination); if (wnode.getNodeType() == Node.DOCUMENT_NODE) { - ser.serialize((Document)wnode); - } - else if (wnode.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { - ser.serialize((DocumentFragment)wnode); - } - else if (wnode.getNodeType() == Node.ELEMENT_NODE) { - ser.serialize((Element)wnode); - } - else if (wnode.getNodeType() == Node.TEXT_NODE || - wnode.getNodeType() == Node.COMMENT_NODE || - wnode.getNodeType() == Node.ENTITY_REFERENCE_NODE || - wnode.getNodeType() == Node.CDATA_SECTION_NODE || - wnode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) { + ser.serialize((Document) wnode); + } else if (wnode.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { + ser.serialize((DocumentFragment) wnode); + } else if (wnode.getNodeType() == Node.ELEMENT_NODE) { + ser.serialize((Element) wnode); + } else if (wnode.getNodeType() == Node.TEXT_NODE + || wnode.getNodeType() == Node.COMMENT_NODE + || wnode.getNodeType() == Node.ENTITY_REFERENCE_NODE + || wnode.getNodeType() == Node.CDATA_SECTION_NODE + || wnode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { ser.serialize(wnode); - } - else { + } else { String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.SERIALIZER_DOMAIN, - "unable-to-serialize-node", null); + DOMMessageFormatter.SERIALIZER_DOMAIN, + "unable-to-serialize-node", null); if (ser.fDOMErrorHandler != null) { DOMErrorImpl error = new DOMErrorImpl(); error.fType = "unable-to-serialize-node"; @@ -540,45 +501,42 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { // Rethrow LSException. throw lse; } catch (RuntimeException e) { - if (e == DOMNormalizer.abort){ + if (e == DOMNormalizer.abort) { // stopped at user request return null; } - throw (LSException) new LSException(LSException.SERIALIZE_ERR, e.toString()).initCause(e); + throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); } catch (IOException ioe) { // REVISIT: A generic IOException doesn't provide enough information // to determine that the serialized document is too large to fit // into a string. This could have thrown for some other reason. -- mrglavas String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "STRING_TOO_LONG", - new Object[] { ioe.getMessage()}); - throw (DOMException) new DOMException(DOMException.DOMSTRING_SIZE_ERR, msg).initCause(ioe); + DOMMessageFormatter.DOM_DOMAIN, + "STRING_TOO_LONG", + new Object[]{ioe.getMessage()}); + throw new DOMException(DOMException.DOMSTRING_SIZE_ERR, msg); + } finally { + ser.clearDocumentState(); } - return destination.toString(); } /** - * DOM L3 EXPERIMENTAL: - * The end-of-line sequence of characters to be used in the XML being - * written out. The only permitted values are these: + * DOM L3 EXPERIMENTAL: The end-of-line sequence of characters to be used in + * the XML being written out. The only permitted values are these: *
*
null
*
- * Use a default end-of-line sequence. DOM implementations should choose - * the default to match the usual convention for text files in the - * environment being used. Implementations must choose a default - * sequence that matches one of those allowed by 2.11 "End-of-Line - * Handling".
+ * Use a default end-of-line sequence. DOM implementations should choose the + * default to match the usual convention for text files in the environment + * being used. Implementations must choose a default sequence that matches + * one of those allowed by 2.11 "End-of-Line Handling". *
CR
*
The carriage-return character (#xD).
*
CR-LF
- *
The - * carriage-return and line-feed characters (#xD #xA).
+ *
The carriage-return and line-feed characters (#xD #xA).
*
LF
- *
The line-feed - * character (#xA).
+ *
The line-feed character (#xA).
*
*
The default value for this attribute is null. */ @@ -586,27 +544,22 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { serializer._format.setLineSeparator(newLine); } - /** - * DOM L3 EXPERIMENTAL: - * The end-of-line sequence of characters to be used in the XML being - * written out. The only permitted values are these: + * DOM L3 EXPERIMENTAL: The end-of-line sequence of characters to be used in + * the XML being written out. The only permitted values are these: *
*
null
*
- * Use a default end-of-line sequence. DOM implementations should choose - * the default to match the usual convention for text files in the - * environment being used. Implementations must choose a default - * sequence that matches one of those allowed by 2.11 "End-of-Line - * Handling".
+ * Use a default end-of-line sequence. DOM implementations should choose the + * default to match the usual convention for text files in the environment + * being used. Implementations must choose a default sequence that matches + * one of those allowed by 2.11 "End-of-Line Handling". *
CR
*
The carriage-return character (#xD).
*
CR-LF
- *
The - * carriage-return and line-feed characters (#xD #xA).
+ *
The carriage-return and line-feed characters (#xD #xA).
*
LF
- *
The line-feed - * character (#xA).
+ *
The line-feed character (#xA).
*
*
The default value for this attribute is null. */ @@ -614,23 +567,23 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { return serializer._format.getLineSeparator(); } - /** - * When the application provides a filter, the serializer will call out - * to the filter before serializing each Node. Attribute nodes are never - * passed to the filter. The filter implementation can choose to remove - * the node from the stream or to terminate the serialization early. + * When the application provides a filter, the serializer will call out to + * the filter before serializing each Node. Attribute nodes are never passed + * to the filter. The filter implementation can choose to remove the node + * from the stream or to terminate the serialization early. */ - public LSSerializerFilter getFilter(){ + public LSSerializerFilter getFilter() { return serializer.fDOMFilter; } + /** - * When the application provides a filter, the serializer will call out - * to the filter before serializing each Node. Attribute nodes are never - * passed to the filter. The filter implementation can choose to remove - * the node from the stream or to terminate the serialization early. + * When the application provides a filter, the serializer will call out to + * the filter before serializing each Node. Attribute nodes are never passed + * to the filter. The filter implementation can choose to remove the node + * from the stream or to terminate the serialization early. */ - public void setFilter(LSSerializerFilter filter){ + public void setFilter(LSSerializerFilter filter) { serializer.fDOMFilter = filter; } @@ -654,56 +607,44 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { }//copysettings /** - * Serialize the specified node as described above in the general - * description of the LSSerializer interface. The output - * is written to the supplied LSOutput. - *
When writing to a LSOutput, the encoding is found by - * looking at the encoding information that is reachable through the - * LSOutput and the item to be written (or its owner - * document) in this order: - *
    - *
  1. LSOutput.encoding, - *
  2. - *
  3. - * Document.actualEncoding, - *
  4. - *
  5. - * Document.xmlEncoding. - *
  6. - *
- *
If no encoding is reachable through the above properties, a - * default encoding of "UTF-8" will be used. - *
If the specified encoding is not supported an - * "unsupported-encoding" error is raised. - *
If no output is specified in the LSOutput, a - * "no-output-specified" error is raised. - * @param node The node to serialize. - * @param destination The destination for the serialized DOM. - * @return Returns true if node was - * successfully serialized and false in case the node - * couldn't be serialized. - */ - public boolean write(Node node, LSOutput destination) throws LSException{ + * Serialize the specified node as described above in the general + * description of the LSSerializer interface. The output is + * written to the supplied LSOutput. + *
When writing to a LSOutput, the encoding is found by + * looking at the encoding information that is reachable through the + * LSOutput and the item to be written (or its owner document) + * in this order: + *
    + *
  1. LSOutput.encoding, + *
  2. + *
  3. + * Document.actualEncoding, + *
  4. + *
  5. + * Document.xmlEncoding. + *
  6. + *
+ *
If no encoding is reachable through the above properties, a default + * encoding of "UTF-8" will be used. + *
If the specified encoding is not supported an "unsupported-encoding" + * error is raised. + *
If no output is specified in the LSOutput, a + * "no-output-specified" error is raised. + * + * @param node The node to serialize. + * @param destination The destination for the serialized DOM. + * @return Returns true if node was successfully + * serialized and false in case the node couldn't be + * serialized. + */ + public boolean write(Node node, LSOutput destination) throws LSException { - if (node == null) + if (node == null) { return false; - - Method getVersion = null; - XMLSerializer ser = null; - String ver = null; - Document fDocument =(node.getNodeType() == Node.DOCUMENT_NODE) - ? (Document) node - : node.getOwnerDocument(); - // this should run under JDK 1.1.8... - try { - getVersion = fDocument.getClass().getMethod("getXmlVersion", new Class[] {}); - if (getVersion != null) { - ver = (String) getVersion.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - //no way to test the version... - //ignore the exception } + + XMLSerializer ser = null; + String ver = _getXmlVersion(node); //determine which serializer to use: if (ver != null && ver.equals("1.1")) { if (xml11Serializer == null) { @@ -719,25 +660,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { String encoding = null; if ((encoding = destination.getEncoding()) == null) { - try { - Method getEncoding = - fDocument.getClass().getMethod("getInputEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + encoding = _getInputEncoding(node); if (encoding == null) { - try { - Method getEncoding = - fDocument.getClass().getMethod("getXmlEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + encoding = _getXmlEncoding(node); if (encoding == null) { encoding = "UTF-8"; } @@ -748,13 +673,13 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser._format.setEncoding(encoding); OutputStream outputStream = destination.getByteStream(); Writer writer = destination.getCharacterStream(); - String uri = destination.getSystemId(); + String uri = destination.getSystemId(); if (writer == null) { if (outputStream == null) { if (uri == null) { String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.SERIALIZER_DOMAIN, - "no-output-specified", null); + DOMMessageFormatter.SERIALIZER_DOMAIN, + "no-output-specified", null); if (ser.fDOMErrorHandler != null) { DOMErrorImpl error = new DOMErrorImpl(); error.fType = "no-output-specified"; @@ -763,81 +688,52 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser.fDOMErrorHandler.handleError(error); } throw new LSException(LSException.SERIALIZE_ERR, msg); + } else { + ser.setOutputByteStream(XMLEntityManager.createOutputStream(uri)); } - else { - // URI was specified. Handle relative URIs. - String expanded = XMLEntityManager.expandSystemId(uri, null, true); - URL url = new URL(expanded != null ? expanded : uri); - OutputStream out = null; - String protocol = url.getProtocol(); - String host = url.getHost(); - // Use FileOutputStream if this URI is for a local file. - if (protocol.equals("file") - && (host == null || host.length() == 0 || host.equals("localhost"))) { - out = new FileOutputStream(getPathWithoutEscapes(url.getFile())); - } - // Try to write to some other kind of URI. Some protocols - // won't support this, though HTTP should work. - else { - URLConnection urlCon = url.openConnection(); - urlCon.setDoInput(false); - urlCon.setDoOutput(true); - urlCon.setUseCaches(false); // Enable tunneling. - if (urlCon instanceof HttpURLConnection) { - // The DOM L3 LS CR says if we are writing to an HTTP URI - // it is to be done with an HTTP PUT. - HttpURLConnection httpCon = (HttpURLConnection) urlCon; - httpCon.setRequestMethod("PUT"); - } - out = urlCon.getOutputStream(); - } - ser.setOutputByteStream(out); - } - } - else { + } else { // byte stream was specified ser.setOutputByteStream(outputStream); } - } - else { + } else { // character stream is specified ser.setOutputCharStream(writer); } - if (node.getNodeType() == Node.DOCUMENT_NODE) + if (node.getNodeType() == Node.DOCUMENT_NODE) { ser.serialize((Document) node); - else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) + } else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { ser.serialize((DocumentFragment) node); - else if (node.getNodeType() == Node.ELEMENT_NODE) + } else if (node.getNodeType() == Node.ELEMENT_NODE) { ser.serialize((Element) node); - else if (node.getNodeType() == Node.TEXT_NODE || - node.getNodeType() == Node.COMMENT_NODE || - node.getNodeType() == Node.ENTITY_REFERENCE_NODE || - node.getNodeType() == Node.CDATA_SECTION_NODE || - node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) { + } else if (node.getNodeType() == Node.TEXT_NODE + || node.getNodeType() == Node.COMMENT_NODE + || node.getNodeType() == Node.ENTITY_REFERENCE_NODE + || node.getNodeType() == Node.CDATA_SECTION_NODE + || node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { ser.serialize(node); - } - else + } else { return false; - } catch( UnsupportedEncodingException ue) { + } + } catch (UnsupportedEncodingException ue) { if (ser.fDOMErrorHandler != null) { DOMErrorImpl error = new DOMErrorImpl(); error.fException = ue; - error.fType = "unsupported-encoding"; + error.fType = "unsupported-encoding"; error.fMessage = ue.getMessage(); - error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; + error.fSeverity = DOMError.SEVERITY_FATAL_ERROR; ser.fDOMErrorHandler.handleError(error); - } + } throw new LSException(LSException.SERIALIZE_ERR, - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.SERIALIZER_DOMAIN, - "unsupported-encoding", null)); - //return false; + DOMMessageFormatter.formatMessage( + DOMMessageFormatter.SERIALIZER_DOMAIN, + "unsupported-encoding", null)); + //return false; } catch (LSException lse) { // Rethrow LSException. throw lse; } catch (RuntimeException e) { - if (e == DOMNormalizer.abort){ + if (e == DOMNormalizer.abort) { // stopped at user request return false; } @@ -851,62 +747,48 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser.fDOMErrorHandler.handleError(error); } - e.printStackTrace(); throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } finally { + ser.clearDocumentState(); } return true; } //write /** - * Serialize the specified node as described above in the general - * description of the LSSerializer interface. The output - * is written to the supplied URI. - *
When writing to a URI, the encoding is found by looking at the - * encoding information that is reachable through the item to be written - * (or its owner document) in this order: - *
    - *
  1. - * Document.inputEncoding, - *
  2. - *
  3. - * Document.xmlEncoding. - *
  4. - *
- *
If no encoding is reachable through the above properties, a - * default encoding of "UTF-8" will be used. - *
If the specified encoding is not supported an - * "unsupported-encoding" error is raised. - * @param node The node to serialize. - * @param URI The URI to write to. - * @return Returns true if node was - * successfully serialized and false in case the node - * couldn't be serialized. - */ - public boolean writeToURI(Node node, String URI) throws LSException{ - if (node == null){ + * Serialize the specified node as described above in the general + * description of the LSSerializer interface. The output is + * written to the supplied URI. + *
When writing to a URI, the encoding is found by looking at the + * encoding information that is reachable through the item to be written (or + * its owner document) in this order: + *
    + *
  1. + * Document.inputEncoding, + *
  2. + *
  3. + * Document.xmlEncoding. + *
  4. + *
+ *
If no encoding is reachable through the above properties, a default + * encoding of "UTF-8" will be used. + *
If the specified encoding is not supported an "unsupported-encoding" + * error is raised. + * + * @param node The node to serialize. + * @param URI The URI to write to. + * @return Returns true if node was successfully + * serialized and false in case the node couldn't be + * serialized. + */ + public boolean writeToURI(Node node, String URI) throws LSException { + if (node == null) { return false; } - Method getXmlVersion = null; XMLSerializer ser = null; - String ver = null; - String encoding = null; + String ver = _getXmlVersion(node); - Document fDocument =(node.getNodeType() == Node.DOCUMENT_NODE) - ? (Document) node - : node.getOwnerDocument(); - // this should run under JDK 1.1.8... - try { - getXmlVersion = - fDocument.getClass().getMethod("getXmlVersion", new Class[] {}); - if (getXmlVersion != null) { - ver = (String) getXmlVersion.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // no way to test the version... - // ignore the exception - } if (ver != null && ver.equals("1.1")) { if (xml11Serializer == null) { xml11Serializer = new XML11Serializer(); @@ -919,25 +801,9 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser = serializer; } - try { - Method getEncoding = - fDocument.getClass().getMethod("getInputEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + String encoding = _getInputEncoding(node); if (encoding == null) { - try { - Method getEncoding = - fDocument.getClass().getMethod("getXmlEncoding", new Class[] {}); - if (getEncoding != null) { - encoding = (String) getEncoding.invoke(fDocument, (Object[]) null); - } - } catch (Exception e) { - // ignore the exception - } + encoding = _getXmlEncoding(node); if (encoding == null) { encoding = "UTF-8"; } @@ -946,55 +812,28 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { try { prepareForSerialization(ser, node); ser._format.setEncoding(encoding); + ser.setOutputByteStream(XMLEntityManager.createOutputStream(URI)); - // URI was specified. Handle relative URIs. - String expanded = XMLEntityManager.expandSystemId(URI, null, true); - URL url = new URL(expanded != null ? expanded : URI); - OutputStream out = null; - String protocol = url.getProtocol(); - String host = url.getHost(); - // Use FileOutputStream if this URI is for a local file. - if (protocol.equals("file") - && (host == null || host.length() == 0 || host.equals("localhost"))) { - out = new FileOutputStream(getPathWithoutEscapes(url.getFile())); - } - // Try to write to some other kind of URI. Some protocols - // won't support this, though HTTP should work. - else { - URLConnection urlCon = url.openConnection(); - urlCon.setDoInput(false); - urlCon.setDoOutput(true); - urlCon.setUseCaches(false); // Enable tunneling. - if (urlCon instanceof HttpURLConnection) { - // The DOM L3 LS CR says if we are writing to an HTTP URI - // it is to be done with an HTTP PUT. - HttpURLConnection httpCon = (HttpURLConnection) urlCon; - httpCon.setRequestMethod("PUT"); - } - out = urlCon.getOutputStream(); - } - ser.setOutputByteStream(out); - - if (node.getNodeType() == Node.DOCUMENT_NODE) + if (node.getNodeType() == Node.DOCUMENT_NODE) { ser.serialize((Document) node); - else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) + } else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { ser.serialize((DocumentFragment) node); - else if (node.getNodeType() == Node.ELEMENT_NODE) + } else if (node.getNodeType() == Node.ELEMENT_NODE) { ser.serialize((Element) node); - else if (node.getNodeType() == Node.TEXT_NODE || - node.getNodeType() == Node.COMMENT_NODE || - node.getNodeType() == Node.ENTITY_REFERENCE_NODE || - node.getNodeType() == Node.CDATA_SECTION_NODE || - node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) { + } else if (node.getNodeType() == Node.TEXT_NODE + || node.getNodeType() == Node.COMMENT_NODE + || node.getNodeType() == Node.ENTITY_REFERENCE_NODE + || node.getNodeType() == Node.CDATA_SECTION_NODE + || node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { ser.serialize(node); - } - else + } else { return false; + } } catch (LSException lse) { // Rethrow LSException. throw lse; } catch (RuntimeException e) { - if (e == DOMNormalizer.abort){ + if (e == DOMNormalizer.abort) { // stopped at user request return false; } @@ -1008,24 +847,24 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { ser.fDOMErrorHandler.handleError(error); } throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace(); + } finally { + ser.clearDocumentState(); } return true; } //writeURI - // // Private methods // - private void prepareForSerialization(XMLSerializer ser, Node node) { ser.reset(); ser.features = features; ser.fDOMErrorHandler = fErrorHandler; ser.fNamespaces = (features & NAMESPACES) != 0; ser.fNamespacePrefixes = (features & NSDECL) != 0; - ser._format.setOmitComments((features & COMMENTS)==0); + ser._format.setIndenting((features & PRETTY_PRINT) != 0); + ser._format.setOmitComments((features & COMMENTS) == 0); ser._format.setOmitXMLDeclaration((features & XMLDECL) == 0); - ser._format.setIndenting((features & FORMAT_PRETTY_PRINT) != 0); if ((features & WELLFORMED) != 0) { // REVISIT: this is inefficient implementation of well-formness. Instead, we should check @@ -1034,13 +873,13 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { root = node; Method versionChanged; boolean verifyNames = true; - Document document =(node.getNodeType() == Node.DOCUMENT_NODE) + Document document = (node.getNodeType() == Node.DOCUMENT_NODE) ? (Document) node : node.getOwnerDocument(); try { - versionChanged = document.getClass().getMethod("isXMLVersionChanged()", new Class[] {}); + versionChanged = document.getClass().getMethod("isXMLVersionChanged()", new Class[]{}); if (versionChanged != null) { - verifyNames = ((Boolean)versionChanged.invoke(document, (Object[]) null)).booleanValue(); + verifyNames = ((Boolean) versionChanged.invoke(document, (Object[]) null)).booleanValue(); } } catch (Exception e) { //no way to test the version... @@ -1053,59 +892,53 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { next = node.getFirstChild(); // No child nodes, so walk tree while (next == null) { - // Move to sibling if possible. - next = node.getNextSibling(); - if (next == null) { - node = node.getParentNode(); - if (root == node){ - next = null; - break; - } - next = node.getNextSibling(); - } + // Move to sibling if possible. + next = node.getNextSibling(); + if (next == null) { + node = node.getParentNode(); + if (root == node) { + next = null; + break; + } + next = node.getNextSibling(); + } } node = next; } - } - else { + } else { verify(node, verifyNames, false); } } } - - private void verify (Node node, boolean verifyNames, boolean xml11Version){ + private void verify(Node node, boolean verifyNames, boolean xml11Version) { int type = node.getNodeType(); fLocator.fRelatedNode = node; boolean wellformed; switch (type) { - case Node.DOCUMENT_NODE:{ + case Node.DOCUMENT_NODE: { break; } - case Node.DOCUMENT_TYPE_NODE:{ + case Node.DOCUMENT_TYPE_NODE: { break; } - case Node.ELEMENT_NODE:{ - if (verifyNames){ - if((features & NAMESPACES) != 0){ - wellformed = CoreDocumentImpl.isValidQName(node.getPrefix() , node.getLocalName(), xml11Version) ; + case Node.ELEMENT_NODE: { + if (verifyNames) { + if ((features & NAMESPACES) != 0) { + wellformed = CoreDocumentImpl.isValidQName(node.getPrefix(), node.getLocalName(), xml11Version); + } else { + wellformed = CoreDocumentImpl.isXMLName(node.getNodeName(), xml11Version); } - else{ - wellformed = CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version); - } - if (!wellformed){ - if (!wellformed){ - if (fErrorHandler != null) { - String msg = DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "wf-invalid-character-in-node-name", - new Object[]{"Element", node.getNodeName()}); - DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, - "wf-invalid-character-in-node-name"); - } - - } + if (!wellformed) { + if (fErrorHandler != null) { + String msg = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } } } @@ -1114,17 +947,17 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { for (int i = 0; i < attributes.getLength(); ++i) { Attr attr = (Attr) attributes.item(i); fLocator.fRelatedNode = attr; - DOMNormalizer.isAttrValueWF( fErrorHandler, fError, fLocator, - attributes, attr, attr.getValue(), xml11Version); + DOMNormalizer.isAttrValueWF(fErrorHandler, fError, fLocator, + attributes, attr, attr.getValue(), xml11Version); if (verifyNames) { - wellformed = CoreDocumentImpl.isXMLName( attr.getNodeName(), xml11Version); + wellformed = CoreDocumentImpl.isXMLName(attr.getNodeName(), xml11Version); if (!wellformed) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "wf-invalid-character-in-node-name", - new Object[] { "Attr", node.getNodeName()}); - DOMNormalizer.reportDOMError( fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Attr", node.getNodeName()}); + DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR, "wf-invalid-character-in-node-name"); } } @@ -1135,78 +968,156 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration { break; } - case Node.COMMENT_NODE: { - // only verify well-formness if comments included in the tree - if ((features & COMMENTS) != 0) - DOMNormalizer.isCommentWF(fErrorHandler, fError, fLocator, ((Comment)node).getData(), xml11Version); - break; - } - case Node.ENTITY_REFERENCE_NODE: { - // only if entity is preserved in the tree - if (verifyNames && (features & ENTITIES) != 0){ - CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version); - } - break; - - } - case Node.CDATA_SECTION_NODE: { - // verify content - DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); - // the ]]> string will be checked during serialization - break; - } - case Node.TEXT_NODE:{ - DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); - break; - } - case Node.PROCESSING_INSTRUCTION_NODE:{ - ProcessingInstruction pinode = (ProcessingInstruction)node ; - String target = pinode.getTarget(); - if (verifyNames) { - if (xml11Version) { - wellformed = XML11Char.isXML11ValidName(target); - } else { - wellformed = XMLChar.isValidName(target); - } - - if (!wellformed) { - String msg = - DOMMessageFormatter.formatMessage( - DOMMessageFormatter.DOM_DOMAIN, - "wf-invalid-character-in-node-name", - new Object[] { "Element", node.getNodeName()}); - DOMNormalizer.reportDOMError( - fErrorHandler, - fError, - fLocator, - msg, - DOMError.SEVERITY_FATAL_ERROR, - "wf-invalid-character-in-node-name"); + case Node.COMMENT_NODE: { + // only verify well-formness if comments included in the tree + if ((features & COMMENTS) != 0) { + DOMNormalizer.isCommentWF(fErrorHandler, fError, fLocator, ((Comment) node).getData(), xml11Version); } + break; } - DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), xml11Version); - break; - } - } + case Node.ENTITY_REFERENCE_NODE: { + // only if entity is preserved in the tree + if (verifyNames && (features & ENTITIES) != 0) { + CoreDocumentImpl.isXMLName(node.getNodeName(), xml11Version); + } + break; + } + case Node.CDATA_SECTION_NODE: { + // verify content + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); + // the ]]> string will be checked during serialization + break; + } + case Node.TEXT_NODE: { + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: { + ProcessingInstruction pinode = (ProcessingInstruction) node; + String target = pinode.getTarget(); + if (verifyNames) { + if (xml11Version) { + wellformed = XML11Char.isXML11ValidName(target); + } else { + wellformed = XMLChar.isValidName(target); + } + + if (!wellformed) { + String msg + = DOMMessageFormatter.formatMessage( + DOMMessageFormatter.DOM_DOMAIN, + "wf-invalid-character-in-node-name", + new Object[]{"Element", node.getNodeName()}); + DOMNormalizer.reportDOMError( + fErrorHandler, + fError, + fLocator, + msg, + DOMError.SEVERITY_FATAL_ERROR, + "wf-invalid-character-in-node-name"); + } + } + DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), xml11Version); + break; + } + } + fLocator.fRelatedNode = null; } - private String getPathWithoutEscapes(String origPath) { - if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) { - // Locate the escape characters - StringTokenizer tokenizer = new StringTokenizer(origPath, "%"); - StringBuffer result = new StringBuffer(origPath.length()); - int size = tokenizer.countTokens(); - result.append(tokenizer.nextToken()); - for(int i = 1; i < size; ++i) { - String token = tokenizer.nextToken(); - // Decode the 2 digit hexadecimal number following % in '%nn' - result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue()); - result.append(token.substring(2)); + private String _getXmlVersion(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetXmlVersionMethod.invoke(doc, (Object[]) null); + } // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } // Ignore all other exceptions and errors + catch (Throwable t) { } - return result.toString(); } - return origPath; + return null; } -}//DOMSerializerImpl + private String _getInputEncoding(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetInputEncodingMethod.invoke(doc, (Object[]) null); + } // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } // Ignore all other exceptions and errors + catch (Throwable t) { + } + } + return null; + } + + private String _getXmlEncoding(Node node) { + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) + ? (Document) node : node.getOwnerDocument(); + if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) { + try { + return (String) DocumentMethods.fgDocumentGetXmlEncodingMethod.invoke(doc, (Object[]) null); + } // The VM ran out of memory or there was some other serious problem. Re-throw. + catch (VirtualMachineError vme) { + throw vme; + } // ThreadDeath should always be re-thrown + catch (ThreadDeath td) { + throw td; + } // Ignore all other exceptions and errors + catch (Throwable t) { + } + } + return null; + } + + /** + * Holder of DOM Level 3 methods from org.w3c.dom.Document. + */ + static class DocumentMethods { + + // Method: org.w3c.dom.Document.getXmlVersion() + private static java.lang.reflect.Method fgDocumentGetXmlVersionMethod = null; + + // Method: org.w3c.dom.Document.getInputEncoding() + private static java.lang.reflect.Method fgDocumentGetInputEncodingMethod = null; + + // Method: org.w3c.dom.Document.getXmlEncoding() + private static java.lang.reflect.Method fgDocumentGetXmlEncodingMethod = null; + + // Flag indicating whether or not Document methods are available. + private static boolean fgDocumentMethodsAvailable = false; + + private DocumentMethods() { + } + + // Attempt to get methods for org.w3c.dom.Document on class initialization. + static { + try { + fgDocumentGetXmlVersionMethod = Document.class.getMethod("getXmlVersion", new Class[]{}); + fgDocumentGetInputEncodingMethod = Document.class.getMethod("getInputEncoding", new Class[]{}); + fgDocumentGetXmlEncodingMethod = Document.class.getMethod("getXmlEncoding", new Class[]{}); + fgDocumentMethodsAvailable = true; + } // ClassNotFoundException, NoSuchMethodException or SecurityException + // Whatever the case, we cannot retrieve the methods. + catch (Exception exc) { + fgDocumentGetXmlVersionMethod = null; + fgDocumentGetInputEncodingMethod = null; + fgDocumentGetXmlEncodingMethod = null; + fgDocumentMethodsAvailable = false; + } + } + } + +} //DOMSerializerImpl diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java index e1728cd7624..ced3ef5c4d5 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XML11Serializer.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -18,8 +19,6 @@ * limitations under the License. */ - - // Sep 14, 2000: // Fixed problem with namespace handling. Contributed by // David Blondeau @@ -33,22 +32,20 @@ // Aug 21, 2000: // Added ability to omit DOCTYPE declaration. - package com.sun.org.apache.xml.internal.serialize; - import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; -import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.util.NamespaceSupport; import com.sun.org.apache.xerces.internal.util.SymbolTable; import com.sun.org.apache.xerces.internal.util.XML11Char; import com.sun.org.apache.xerces.internal.util.XMLChar; -import org.xml.sax.SAXException; import org.w3c.dom.DOMError; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; /** * Implements an XML serializer supporting both DOM and SAX pretty @@ -62,9 +59,9 @@ import org.w3c.dom.DOMError; * The serializer supports both DOM and SAX. SAX serializing is done by firing * SAX events and using the serializer as a document handler. DOM serializing is done * by calling {@link #serialize(Document)} or by using DOM Level 3 - * {@link org.w3c.dom.ls.DOMSerializer} and - * serializing with {@link org.w3c.dom.ls.DOMSerializer#write}, - * {@link org.w3c.dom.ls.DOMSerializer#writeToString}. + * {@link org.w3c.dom.ls.LSSerializer} and + * serializing with {@link org.w3c.dom.ls.LSSerializer#write}, + * {@link org.w3c.dom.ls.LSSerializer#writeToString}. *

* If an I/O exception occurs while serializing, the serializer * will not throw an exception directly, but only throw it @@ -122,10 +119,6 @@ extends XMLSerializer { */ protected boolean fNamespaces = false; - - private boolean fPreserveSpace; - - /** * Constructs a new serializer. The serializer cannot be used without * calling {@link #setOutputCharStream} or {@link #setOutputByteStream} @@ -217,26 +210,27 @@ extends XMLSerializer { if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if (++index < end) { - surrogates(ch, chars[index]); + surrogates(ch, chars[index], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; - } else { - if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { - _printer.printText((char)ch); - } else { - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";= ' ' && _encodingInfo.isPrintable((char) ch))) { - _printer.printText((char) ch); - } else { - printHex(ch); - } + if (ch == '\n' || ch == '\r' || ch == '\t' || ch == 0x0085 || ch == 0x2028) { + printHex(ch); + } + else if (ch == '<') { + _printer.printText("<"); + } + else if (ch == '&') { + _printer.printText("&"); + } + else if (ch == '"') { + _printer.printText("""); + } + else if ((ch >= ' ' && _encodingInfo.isPrintable((char) ch))) { + _printer.printText((char) ch); + } + else { + printHex(ch); + } } } @@ -344,54 +345,55 @@ extends XMLSerializer { if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if (++index < length) { - surrogates(ch, text.charAt(index)); - } else { - fatalError( - "The character '" - + (char) ch - + "' is an invalid XML character"); + surrogates(ch, text.charAt(index), true); + } + else { + fatalError("The character '" + ch + "' is an invalid XML character"); } continue; - } else { - if (_encodingInfo.isPrintable((char) ch) - && XML11Char.isXML11ValidLiteral(ch)) { - _printer.printText((char) ch); - } else { - - // The character is not printable -- split CDATA section - _printer.printText("]]>&#x"); - _printer.printText(Integer.toHexString(ch)); - _printer.printText(";&#x"); + _printer.printText(Integer.toHexString(ch)); + _printer.printText(";'){ - // character sequence "]]>" can't appear in content, therefore - // we should escape '>' - _printer.printText(">"); - } else if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { + } + else if (ch == '>'){ + // character sequence "]]>" can't appear in content, therefore + // we should escape '>' + _printer.printText(">"); + } + else if ( _encodingInfo.isPrintable((char)ch) && XML11Char.isXML11ValidLiteral(ch)) { _printer.printText((char)ch); - } else { - printHex(ch); + } + else { + printHex(ch); } } - protected final void surrogates(int high, int low) throws IOException{ + protected final void surrogates(int high, int low, boolean inContent) throws IOException{ if (XMLChar.isHighSurrogate(high)) { if (!XMLChar.isLowSurrogate(low)) { //Invalid XML @@ -404,7 +406,7 @@ extends XMLSerializer { fatalError("The character '"+(char)supplemental+"' is an invalid XML character"); } else { - if (content().inCData ) { + if (inContent && content().inCData) { _printer.printText("]]>&#x"); _printer.printText(Integer.toHexString(supplemental)); _printer.printText("; 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if ( length-- > 0) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } - if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) + if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) { _printer.printText( ch ); - else + } + else { printXMLChar( ch ); + } } - } else { + } + else { // Not preserving spaces: print one part at a time, and // use spaces between parts to break them into different // lines. Spaces at beginning of line will be stripped // by printing mechanism. Line terminator is treated // no different than other text part. while ( length-- > 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XML11Char.isXML11Valid(ch)) { // check if it is surrogate if ( length-- > 0) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } - if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) + if ( unescaped && XML11Char.isXML11ValidLiteral(ch)) { _printer.printText( ch ); - else + } + else { printXMLChar( ch ); + } } } } - public boolean reset() { super.reset(); return true; - } } diff --git a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java index e33fb5171b0..884fd4b5fe5 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java @@ -3,11 +3,12 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2002,2004,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -18,8 +19,6 @@ * limitations under the License. */ - - // Sep 14, 2000: // Fixed problem with namespace handling. Contributed by // David Blondeau @@ -33,14 +32,13 @@ // Aug 21, 2000: // Added ability to omit DOCTYPE declaration. - package com.sun.org.apache.xml.internal.serialize; - import java.io.IOException; import java.io.OutputStream; import java.io.Writer; -import java.util.Enumeration; +import java.util.Iterator; +import java.util.Map; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.util.NamespaceSupport; @@ -50,6 +48,7 @@ import com.sun.org.apache.xerces.internal.util.XMLSymbols; import com.sun.org.apache.xerces.internal.xni.NamespaceContext; import org.w3c.dom.Attr; import org.w3c.dom.DOMError; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -71,9 +70,9 @@ import org.xml.sax.helpers.AttributesImpl; * The serializer supports both DOM and SAX. SAX serializing is done by firing * SAX events and using the serializer as a document handler. DOM serializing is done * by calling {@link #serialize(Document)} or by using DOM Level 3 - * {@link org.w3c.dom.ls.DOMSerializer} and - * serializing with {@link org.w3c.dom.ls.DOMSerializer#write}, - * {@link org.w3c.dom.ls.DOMSerializer#writeToString}. + * {@link org.w3c.dom.ls.LSSerializer} and + * serializing with {@link org.w3c.dom.ls.LSSerializer#write}, + * {@link org.w3c.dom.ls.LSSerializer#writeToString}. *

* If an I/O exception occurs while serializing, the serializer * will not throw an exception directly, but only throw it @@ -195,7 +194,7 @@ extends BaseMarkupSerializer { /** * This methods turns on namespace fixup algorithm during * DOM serialization. - * @see org.w3c.dom.ls.DOMSerializer + * @see org.w3c.dom.ls.LSSerializer * * @param namespaces */ @@ -222,7 +221,6 @@ extends BaseMarkupSerializer { ElementState state; String name; String value; - boolean addNSAttr = false; if (DEBUG) { System.out.println("==>startElement("+namespaceURI+","+localName+ @@ -277,13 +275,16 @@ extends BaseMarkupSerializer { if (namespaceURI != null && ! namespaceURI.equals( "" )) { String prefix; prefix = getPrefix( namespaceURI ); - if (prefix != null && prefix.length() > 0) + if (prefix != null && prefix.length() > 0) { rawName = prefix + ":" + localName; - else + } + else { rawName = localName; - } else + } + } + else { rawName = localName; - addNSAttr = true; + } } _printer.printText( '<' ); @@ -334,18 +335,18 @@ extends BaseMarkupSerializer { } if (_prefixes != null) { - Enumeration keys; - - keys = _prefixes.keys(); - while (keys.hasMoreElements()) { + Iterator entries = _prefixes.entrySet().iterator(); + while (entries.hasNext()) { _printer.printSpace(); - value = (String) keys.nextElement(); - name = (String) _prefixes.get( value ); + Map.Entry entry = (Map.Entry) entries.next(); + value = (String) entry.getKey(); + name = (String) entry.getValue(); if (name.length() == 0) { _printer.printText( "xmlns=\"" ); printEscaped( value ); _printer.printText( '"' ); - } else { + } + else { _printer.printText( "xmlns:" ); _printer.printText( name ); _printer.printText( "=\"" ); @@ -770,13 +771,11 @@ extends BaseMarkupSerializer { // xmlns:foo = "" } continue; - } else { // xmlns - // empty prefix is always bound ("" or some string) - - value = fSymbolTable.addSymbol(value); - fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value); - continue; } + // xmlns --- empty prefix is always bound ("" or some string) + value = fSymbolTable.addSymbol(value); + fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value); + continue; } // end-else: valid declaration } // end-if: namespace declaration } // end-for @@ -958,22 +957,20 @@ extends BaseMarkupSerializer { // xmlns:foo = "" } continue; - } else { // xmlns - // empty prefix is always bound ("" or some string) - - uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); - localUri=fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING); - value = fSymbolTable.addSymbol(value); - if (localUri == null ){ - // declaration was not printed while fixing element namespace binding - if (fNamespacePrefixes) { - printNamespaceAttr(XMLSymbols.EMPTY_STRING, value); - } - // case 4 does not apply here since attributes can't use - // default namespace - } - continue; } + // xmlns --- empty prefix is always bound ("" or some string) + uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING); + localUri= fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING); + value = fSymbolTable.addSymbol(value); + if (localUri == null ) { + // declaration was not printed while fixing element namespace binding + if (fNamespacePrefixes) { + printNamespaceAttr(XMLSymbols.EMPTY_STRING, value); + } + // case 4 does not apply here since attributes can't use + // default namespace + } + continue; } uri = fSymbolTable.addSymbol(uri); @@ -1195,8 +1192,6 @@ extends BaseMarkupSerializer { AttributesImpl attrsOnly; String rawName; int i; - int indexColon; - String prefix; int length; if (attrs == null) { @@ -1233,7 +1228,7 @@ extends BaseMarkupSerializer { int ch = source.charAt(i); if (!XMLChar.isValid(ch)) { if (++i < length) { - surrogates(ch, source.charAt(i)); + surrogates(ch, source.charAt(i), false); } else { fatalError("The character '" + (char) ch + "' is an invalid XML character"); } @@ -1291,16 +1286,17 @@ extends BaseMarkupSerializer { if (!XMLChar.isValid(ch)) { // check if it is surrogate if (++index 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XMLChar.isValid(ch)) { // check if it is surrogate if ( length-- > 0 ) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } @@ -1363,13 +1358,13 @@ extends BaseMarkupSerializer { // by printing mechanism. Line terminator is treated // no different than other text part. while ( length-- > 0 ) { - ch = chars[start++]; + char ch = chars[start++]; if (!XMLChar.isValid(ch)) { // check if it is surrogate if ( length-- > 0 ) { - surrogates(ch, chars[start++]); + surrogates(ch, chars[start++], true); } else { - fatalError("The character '"+(char)ch+"' is an invalid XML character"); + fatalError("The character '"+ch+"' is an invalid XML character"); } continue; } From 59ef7286094e5864341f5d268099cb270f272507 Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Mon, 31 Mar 2014 08:23:02 -0700 Subject: [PATCH 098/170] 7189721: nightly tests failed on JDI attaching If for some reason elf section with section names is not loaded to cache it attempts to read data using NULL section pointer. Reviewed-by: sspitsyn, sla, kevinw --- hotspot/agent/src/os/linux/symtab.c | 34 +++++++++++++---------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/hotspot/agent/src/os/linux/symtab.c b/hotspot/agent/src/os/linux/symtab.c index 7aae801ce20..077532a06f3 100644 --- a/hotspot/agent/src/os/linux/symtab.c +++ b/hotspot/agent/src/os/linux/symtab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -162,28 +162,27 @@ open_debug_file (const char *pathname, unsigned int crc) static struct elf_section *find_section_by_name(char *name, int fd, ELF_EHDR *ehdr, - ELF_SHDR *shbuf, struct elf_section *scn_cache) { - ELF_SHDR* cursct = NULL; char *strtab; int cnt; + int strtab_size; + // Section cache have to already contain data for e_shstrndx section. + // If it's not true - elf file is broken, so just bail out if (scn_cache[ehdr->e_shstrndx].c_data == NULL) { - if ((scn_cache[ehdr->e_shstrndx].c_data - = read_section_data(fd, ehdr, cursct)) == NULL) { - return NULL; - } + return NULL; } strtab = scn_cache[ehdr->e_shstrndx].c_data; + strtab_size = scn_cache[ehdr->e_shstrndx].c_shdr->sh_size; - for (cursct = shbuf, cnt = 0; - cnt < ehdr->e_shnum; - cnt++, cursct++) { - if (strcmp(cursct->sh_name + strtab, name) == 0) { - scn_cache[cnt].c_data = read_section_data(fd, ehdr, cursct); - return &scn_cache[cnt]; + for (cnt = 0; cnt < ehdr->e_shnum; ++cnt) { + if (scn_cache[cnt].c_shdr->sh_name < strtab_size) { + if (strcmp(scn_cache[cnt].c_shdr->sh_name + strtab, name) == 0) { + scn_cache[cnt].c_data = read_section_data(fd, ehdr, scn_cache[cnt].c_shdr); + return &scn_cache[cnt]; + } } } @@ -195,12 +194,11 @@ static struct elf_section *find_section_by_name(char *name, static int open_file_from_debug_link(const char *name, int fd, ELF_EHDR *ehdr, - ELF_SHDR *shbuf, struct elf_section *scn_cache) { int debug_fd; struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, - shbuf, scn_cache); + scn_cache); if (debug_link == NULL) return -1; char *debug_filename = debug_link->c_data; @@ -221,7 +219,6 @@ static int open_file_from_debug_link(const char *name, /* Look in the same directory as the object. */ strcpy(last_slash+1, debug_filename); - debug_fd = open_debug_file(debug_pathname, crc); if (debug_fd >= 0) { free(debug_pathname); @@ -261,10 +258,9 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t static struct symtab *build_symtab_from_debug_link(const char *name, int fd, ELF_EHDR *ehdr, - ELF_SHDR *shbuf, struct elf_section *scn_cache) { - fd = open_file_from_debug_link(name, fd, ehdr, shbuf, scn_cache); + fd = open_file_from_debug_link(name, fd, ehdr, scn_cache); if (fd >= 0) { struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); @@ -463,7 +459,7 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // Then, if that doesn't work, the debug link if (symtab == NULL) { - symtab = build_symtab_from_debug_link(filename, fd, &ehdr, shbuf, + symtab = build_symtab_from_debug_link(filename, fd, &ehdr, scn_cache); } From e3393701758b53c3b936fe1bb2d5df82ef1b48da Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 31 Mar 2014 21:27:25 +0200 Subject: [PATCH 099/170] 8035890: jdk8 javac -source 7 compiles test case it should not Ensuring source level checks are performed in two additional cases related to type annotations, adding specialized error message for annotations after method type parameters. Reviewed-by: jfranck, jjg --- .../com/sun/tools/javac/code/Source.java | 3 + .../sun/tools/javac/parser/JavacParser.java | 14 +- .../tools/javac/resources/compiler.properties | 5 + .../failures/CantAnnotateScoping.out | 3 +- .../failures/CheckErrorsForSource7.java | 195 ++++++++++++++++++ .../common/arrays/DeclarationAnnotation.out | 2 +- ...nsAfterTypeParamsNotSupportedInSource.java | 34 +++ 7 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java create mode 100644 langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java index ded0bb42a1f..517f5fc67a2 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java @@ -219,6 +219,9 @@ public enum Source { public boolean allowTypeAnnotations() { return compareTo(JDK1_8) >= 0; } + public boolean allowAnnotationsAfterTypeParams() { + return compareTo(JDK1_8) >= 0; + } public boolean allowRepeatedAnnotations() { return compareTo(JDK1_8) >= 0; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index aba1c7bc73a..14ea64f81fa 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -161,6 +161,7 @@ public class JavacParser implements Parser { this.allowStaticInterfaceMethods = source.allowStaticInterfaceMethods(); this.allowIntersectionTypesInCast = source.allowIntersectionTypesInCast(); this.allowTypeAnnotations = source.allowTypeAnnotations(); + this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams(); this.keepDocComments = keepDocComments; docComments = newDocCommentTable(keepDocComments, fac); this.keepLineMap = keepLineMap; @@ -254,6 +255,10 @@ public class JavacParser implements Parser { */ boolean allowTypeAnnotations; + /** Switch: should we allow annotations after the method type parameters? + */ + boolean allowAnnotationsAfterTypeParams; + /** Switch: is "this" allowed as an identifier? * This is needed to parse receiver types. */ @@ -2026,7 +2031,7 @@ public class JavacParser implements Parser { /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest ) */ JCExpression creator(int newpos, List typeArgs) { - List newAnnotations = annotationsOpt(Tag.ANNOTATION); + List newAnnotations = typeAnnotationsOpt(); switch (token.kind) { case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: @@ -3464,6 +3469,7 @@ public class JavacParser implements Parser { nextToken(); } else { if (annosAfterParams.nonEmpty()) { + checkAnnotationsAfterTypeParams(annosAfterParams.head.pos); mods.annotations = mods.annotations.appendList(annosAfterParams); if (mods.pos == Position.NOPOS) mods.pos = mods.annotations.head.pos; @@ -4063,6 +4069,12 @@ public class JavacParser implements Parser { allowTypeAnnotations = true; } } + void checkAnnotationsAfterTypeParams(int pos) { + if (!allowAnnotationsAfterTypeParams) { + log.error(pos, "annotations.after.type.params.not.supported.in.source", source.name); + allowAnnotationsAfterTypeParams = true; + } + } /* * a functional source tree and end position mappings diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 43b3c638527..bbaac453bc7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2324,6 +2324,11 @@ compiler.err.type.annotations.not.supported.in.source=\ type annotations are not supported in -source {0}\n\ (use -source 8 or higher to enable type annotations) +# 0: string +compiler.err.annotations.after.type.params.not.supported.in.source=\ + annotations after method type parameters are not supported in -source {0}\n\ +(use -source 8 or higher to enable annotations after method type parameters) + # 0: string compiler.err.repeatable.annotations.not.supported.in.source=\ repeated annotations are not supported in -source {0}\n\ diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out index d2144ab86b0..638b91d14ee 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out @@ -6,6 +6,7 @@ CantAnnotateScoping.java:47:18: compiler.err.cant.type.annotate.scoping.1: @TA CantAnnotateScoping.java:56:37: compiler.err.cant.type.annotate.scoping: @TA,@TA2 CantAnnotateScoping.java:40:14: compiler.err.cant.type.annotate.scoping.1: @TA CantAnnotateScoping.java:42:34: compiler.err.cant.type.annotate.scoping: @TA,@DA,@TA2 +CantAnnotateScoping.java:42:25: compiler.err.annotation.type.not.applicable CantAnnotateScoping.java:44:38: compiler.err.cant.type.annotate.scoping: @TA,@DA CantAnnotateScoping.java:44:34: compiler.err.annotation.type.not.applicable -10 errors \ No newline at end of file +11 errors diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java new file mode 100644 index 00000000000..56c8adf588e --- /dev/null +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CheckErrorsForSource7.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2014, 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 8035890 + * @summary Verify that the parser correctly checks for source level 8 on the new places where + * annotations can appear in 8. + * @run main CheckErrorsForSource7 CheckErrorsForSource7.java + */ +import java.io.File; +import java.io.IOException; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.Tree.Kind; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.file.JavacFileManager; + +/**For each place where an annotation can syntactically appear with -source 8, but not with + * -source 7, this test verifies that an error is correctly emitted from the parser for + * the annotation for -source 7. This test first gathers the occurrences of @TA from + * the CheckErrorsForSource7Data class below, and then repeatedly removes all these annotations + * except one and checks the parser reports an expected error. This is needed as as the parser + * typically produces only one 'insufficient source level' error for each new feature used. + */ +public class CheckErrorsForSource7 { + public static void main(String... args) throws IOException, URISyntaxException { + new CheckErrorsForSource7().run(args); + } + + private void run(String... args) throws IOException, URISyntaxException { + //the first and only parameter must be the name of the file to be analyzed: + if (args.length != 1) throw new IllegalStateException("Must provide source file!"); + File testSrc = new File(System.getProperty("test.src")); + File testFile = new File(testSrc, args[0]); + if (!testFile.canRead()) throw new IllegalStateException("Cannot read the test source"); + JavacFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); + + //gather spans of the @TA annotations into typeAnnotationSpans: + JavacTask task = JavacTool.create().getTask(null, + fm, + null, + Collections.emptyList(), + null, + fm.getJavaFileObjects(testFile)); + final Trees trees = Trees.instance(task); + final CompilationUnitTree cut = task.parse().iterator().next(); + final List typeAnnotationSpans = new ArrayList<>(); + + new TreePathScanner() { + @Override + public Void visitAnnotation(AnnotationTree node, Void p) { + if (node.getAnnotationType().getKind() == Kind.IDENTIFIER && + ((IdentifierTree) node.getAnnotationType()).getName().contentEquals("TA")) { + int start = (int) trees.getSourcePositions().getStartPosition(cut, node); + int end = (int) trees.getSourcePositions().getEndPosition(cut, node); + typeAnnotationSpans.add(new int[] {start, end}); + } + return null; + } + }.scan(cut, null); + + //sort the spans in the reverse order, to simplify removing them from the source: + Collections.sort(typeAnnotationSpans, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o2[0] - o1[0]; + } + }); + + //verify the errors are produce correctly: + String originalSource = cut.getSourceFile().getCharContent(false).toString(); + + for (int[] toKeep : typeAnnotationSpans) { + //prepare updated source code by removing all the annotations except the toKeep one: + String updated = originalSource; + + for (int[] span : typeAnnotationSpans) { + if (span == toKeep) continue; + + updated = updated.substring(0, span[0]) + updated.substring(span[1]); + } + + //parse and verify: + JavaFileObject updatedFile = new TestFO(cut.getSourceFile().toUri(), updated); + DiagnosticCollector errors = new DiagnosticCollector<>(); + JavacTask task2 = JavacTool.create().getTask(null, + fm, + errors, + Arrays.asList("-source", "7"), + null, + Arrays.asList(updatedFile)); + task2.parse(); + + boolean found = false; + + for (Diagnostic d : errors.getDiagnostics()) { + if (d.getKind() == Diagnostic.Kind.ERROR && EXPECTED_ERRORS.contains(d.getCode())) { + if (found) { + throw new IllegalStateException("More than one expected error found."); + } + found = true; + } + } + + if (!found) + throw new IllegalStateException("Did not produce proper errors for: " + updated); + } + } + + static final Set EXPECTED_ERRORS = new HashSet<>(Arrays.asList( + "compiler.err.type.annotations.not.supported.in.source", + "compiler.err.annotations.after.type.params.not.supported.in.source" + )); + + class TestFO extends SimpleJavaFileObject { + private final String content; + public TestFO(URI uri, String content) { + super(uri, Kind.SOURCE); + this.content = content; + } + + @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return content; + } + + @Override public boolean isNameCompatible(String simpleName, Kind kind) { + return true; + } + } +} + +//data on which the source level check is verified: +class CheckErrorsForSource7Data { + @Target(ElementType.TYPE_USE) + @interface TA { } + + Object n1 = new @TA ArrayList<@TA String>(); + Object n2 = new @TA Object() {}; + Object [] @TA [] arr @TA[]; + @TA int @TA[] ret(Object obj) @TA[] throws @TA Exception { + this.<@TA String>ret(null); + Object c1 = new @TA String[1]; + + int val = obj instanceof @TA String ? ((@TA String) obj).length() : 0; + List<@TA ?> l; + return null; + } + void vararg(String @TA ... args) { } + + abstract class C<@TA T extends @TA Number & @TA Runnable> + extends @TA ArrayList<@TA String> + implements java.util. @TA Comparator<@TA T> { } + + interface I extends java.util. @TA Comparator<@TA String> { } + +} diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out b/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out index 325094a615a..efb655727e1 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out @@ -1,5 +1,5 @@ +DeclarationAnnotation.java:13:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:10:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:11:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:12:21: compiler.err.annotation.type.not.applicable -DeclarationAnnotation.java:13:21: compiler.err.annotation.type.not.applicable 4 errors diff --git a/langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java b/langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java new file mode 100644 index 00000000000..9efc4c3d15b --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/AnnotationsAfterTypeParamsNotSupportedInSource.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 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. + */ + +// key: compiler.err.annotations.after.type.params.not.supported.in.source +// key: compiler.warn.source.no.bootclasspath +// options: -source 7 + +@interface Anno { } + +class AnnotationsAfterTypeParamsNotSupportedInSource { + @Anno int m() { + return 0; + } +} From 77d38feb95ceb6f8cd968909778c0b87aa1545c4 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 31 Mar 2014 13:08:03 -0700 Subject: [PATCH 100/170] 8038633: crash in VM_Version::get_processor_features() on startup Windows need an exception wrapper around getPsrInfo_stub() call in order to properly handle SEGV for YMM registers test. Reviewed-by: iveresov, iignatyev --- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 32 +++++++++++++------ hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 1 + hotspot/src/os/windows/vm/os_windows.cpp | 2 -- hotspot/src/os/windows/vm/os_windows.hpp | 2 -- .../src/os/windows/vm/os_windows.inline.hpp | 6 ++-- hotspot/src/share/vm/prims/jni.cpp | 2 +- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index 28b79b784f2..ba5fcb383c6 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -59,9 +59,9 @@ static BufferBlob* stub_blob; static const int stub_size = 600; extern "C" { - typedef void (*getPsrInfo_stub_t)(void*); + typedef void (*get_cpu_info_stub_t)(void*); } -static getPsrInfo_stub_t getPsrInfo_stub = NULL; +static get_cpu_info_stub_t get_cpu_info_stub = NULL; class VM_Version_StubGenerator: public StubCodeGenerator { @@ -69,7 +69,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} - address generate_getPsrInfo() { + address generate_get_cpu_info() { // Flags to test CPU type. const uint32_t HS_EFL_AC = 0x40000; const uint32_t HS_EFL_ID = 0x200000; @@ -81,13 +81,13 @@ class VM_Version_StubGenerator: public StubCodeGenerator { Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4; Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done; - StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub"); + StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub"); # define __ _masm-> address start = __ pc(); // - // void getPsrInfo(VM_Version::CpuidInfo* cpuid_info); + // void get_cpu_info(VM_Version::CpuidInfo* cpuid_info); // // LP64: rcx and rdx are first and second argument registers on windows @@ -385,6 +385,14 @@ class VM_Version_StubGenerator: public StubCodeGenerator { }; +void VM_Version::get_cpu_info_wrapper() { + get_cpu_info_stub(&_cpuid_info); +} + +#ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED + #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f() +#endif + void VM_Version::get_processor_features() { _cpu = 4; // 486 by default @@ -395,7 +403,11 @@ void VM_Version::get_processor_features() { if (!Use486InstrsOnly) { // Get raw processor info - getPsrInfo_stub(&_cpuid_info); + + // Some platforms (like Win*) need a wrapper around here + // in order to properly handle SEGV for YMM registers test. + CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(get_cpu_info_wrapper); + assert_is_initialized(); _cpu = extended_cpu_family(); _model = extended_cpu_model(); @@ -986,14 +998,14 @@ void VM_Version::initialize() { ResourceMark rm; // Making this stub must be FIRST use of assembler - stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size); + stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size); if (stub_blob == NULL) { - vm_exit_during_initialization("Unable to allocate getPsrInfo_stub"); + vm_exit_during_initialization("Unable to allocate get_cpu_info_stub"); } CodeBuffer c(stub_blob); VM_Version_StubGenerator g(&c); - getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t, - g.generate_getPsrInfo()); + get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t, + g.generate_get_cpu_info()); get_processor_features(); } diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index a3be0995ae1..51f6e4f2f4a 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -507,6 +507,7 @@ public: // The value used to check ymm register after signal handle static int ymm_test_value() { return 0xCAFEBABE; } + static void get_cpu_info_wrapper(); static void set_cpuinfo_segv_addr(address pc) { _cpuinfo_segv_addr = pc; } static bool is_cpuinfo_segv_addr(address pc) { return _cpuinfo_segv_addr == pc; } static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; } diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 1f4e12c132c..9f0f8a40ca6 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -2702,7 +2702,6 @@ address os::win32::fast_jni_accessor_wrapper(BasicType type) { } #endif -#ifndef PRODUCT void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) { // Install a win32 structured exception handler around the test // function call so the VM can generate an error dump if needed. @@ -2713,7 +2712,6 @@ void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) { // Nothing to do. } } -#endif // Virtual Memory diff --git a/hotspot/src/os/windows/vm/os_windows.hpp b/hotspot/src/os/windows/vm/os_windows.hpp index eaf751ec561..f3ea83d8242 100644 --- a/hotspot/src/os/windows/vm/os_windows.hpp +++ b/hotspot/src/os/windows/vm/os_windows.hpp @@ -101,9 +101,7 @@ class win32 { static address fast_jni_accessor_wrapper(BasicType); #endif -#ifndef PRODUCT static void call_test_func_with_wrapper(void (*funcPtr)(void)); -#endif // filter function to ignore faults on serializations page static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e); diff --git a/hotspot/src/os/windows/vm/os_windows.inline.hpp b/hotspot/src/os/windows/vm/os_windows.inline.hpp index a6d20d90b33..f014fc9eb56 100644 --- a/hotspot/src/os/windows/vm/os_windows.inline.hpp +++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp @@ -111,9 +111,7 @@ inline bool os::supports_monotonic_clock() { return win32::_has_performance_count; } -#ifndef PRODUCT - #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ - os::win32::call_test_func_with_wrapper(f) -#endif +#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ + os::win32::call_test_func_with_wrapper(f) #endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 3f06633e612..c3d588fd4c6 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -4001,7 +4001,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v } #ifndef PRODUCT - #ifndef TARGET_OS_FAMILY_windows + #ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f() #endif From 268191c838ea01413f94556009bdc2161c226ba3 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 31 Mar 2014 22:30:11 +0200 Subject: [PATCH 101/170] 8035751: Clean up Visual Studio detection logic Reviewed-by: erikj, tbell --- common/autoconf/generated-configure.sh | 114 +++++++++++++++---------- common/autoconf/toolchain.m4 | 6 ++ common/autoconf/toolchain_windows.m4 | 89 +++++++++---------- 3 files changed, 120 insertions(+), 89 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index dd040cee005..120e944331f 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -774,9 +774,9 @@ ac_ct_PROPER_COMPILER_CC PROPER_COMPILER_CC TOOLCHAIN_PATH_CC POTENTIAL_CC -VS_PATH VS_LIB VS_INCLUDE +VS_PATH CYGWIN_LINK EXE_SUFFIX OBJ_SUFFIX @@ -4243,7 +4243,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1395839362 +DATE_WHEN_GENERATED=1396297437 ############################################################################### # @@ -27353,47 +27353,62 @@ $as_echo "$as_me: Rewriting VS_ENV_CMD to \"$new_complete\"" >&6;} # Lets extract the variables that are set by vcvarsall.bat/vsvars32.bat/vsvars64.bat { $as_echo "$as_me:${as_lineno-$LINENO}: Trying to extract Visual Studio environment variables" >&5 $as_echo "$as_me: Trying to extract Visual Studio environment variables" >&6;} - cd $OUTPUT_ROOT - # FIXME: The code betweeen ---- was inlined from a separate script and is not properly adapted - # to autoconf standards. - #---- + # We need to create a couple of temporary files. + VS_ENV_TMP_DIR="$OUTPUT_ROOT/vs-env" + $MKDIR -p $VS_ENV_TMP_DIR - # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment) - # but calculate the difference in Cygwin environment before/after running it and then - # apply the diff. + # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment). + # Instead create a shell script which will set the relevant variables when run. + WINPATH_VS_ENV_CMD="$VS_ENV_CMD" - if test "x$OPENJDK_BUILD_OS_ENV" = xwindows.cygwin; then - _vs10varsall=`cygpath -a -m -s "$VS_ENV_CMD"` - _dosvs10varsall=`cygpath -a -w -s $_vs10varsall` - _dosbash=`cygpath -a -w -s \`which bash\`.*` - else - _dosvs10varsall=`cmd //c echo $VS_ENV_CMD` - _dosbash=`cmd //c echo \`which bash\`` - fi + unix_path="$WINPATH_VS_ENV_CMD" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + WINPATH_VS_ENV_CMD="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + WINPATH_VS_ENV_CMD="$windows_path" + fi - # generate the set of exported vars before/after the vs10 setup - $ECHO "@echo off" > localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export0" >> localdevenvtmp.bat - $ECHO "call $_dosvs10varsall $VS_ENV_ARGS" >> localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export1" >> localdevenvtmp.bat + WINPATH_BASH="$BASH" + + unix_path="$WINPATH_BASH" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + windows_path=`$CYGPATH -m "$unix_path"` + WINPATH_BASH="$windows_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + windows_path=`cmd //c echo $unix_path` + WINPATH_BASH="$windows_path" + fi + + + # Generate a DOS batch file which runs $VS_ENV_CMD, and then creates a shell + # script (executable by bash) that will setup the important variables. + EXTRACT_VC_ENV_BAT_FILE="$VS_ENV_TMP_DIR/extract-vs-env.bat" + $ECHO "@echo off" > $EXTRACT_VC_ENV_BAT_FILE + # This will end up something like: + # call C:/progra~2/micros~2.0/vc/bin/amd64/vcvars64.bat + $ECHO "call $WINPATH_VS_ENV_CMD $VS_ENV_ARGS" >> $EXTRACT_VC_ENV_BAT_FILE + # These will end up something like: + # C:/CygWin/bin/bash -c 'echo VS_PATH=\"$PATH\" > localdevenv.sh + # The trailing space for everyone except PATH is no typo, but is needed due + # to trailing \ in the Windows paths. These will be stripped later. + $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE # Now execute the newly created bat file. - # The | cat is to stop SetEnv.Cmd to mess with system colors on msys - cmd /c localdevenvtmp.bat | cat - - # apply the diff (less some non-vs10 vars named by "!") - $SORT localdevenvtmp.export0 | $GREP -v "!" > localdevenvtmp.export0.sort - $SORT localdevenvtmp.export1 | $GREP -v "!" > localdevenvtmp.export1.sort - $COMM -1 -3 localdevenvtmp.export0.sort localdevenvtmp.export1.sort > localdevenv.sh - - # cleanup - $RM localdevenvtmp* - #---- + # The | cat is to stop SetEnv.Cmd to mess with system colors on msys. + # Change directory so we don't need to mess with Windows paths in redirects. + cd $VS_ENV_TMP_DIR + cmd /c extract-vs-env.bat | $CAT cd $CURDIR - if test ! -s $OUTPUT_ROOT/localdevenv.sh; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + + if test ! -s $VS_ENV_TMP_DIR/set-vs-env.sh; then { $as_echo "$as_me:${as_lineno-$LINENO}: Could not succesfully extract the envionment variables needed for the VS setup." >&5 $as_echo "$as_me: Could not succesfully extract the envionment variables needed for the VS setup." >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Try setting --with-tools-dir to the VC/bin directory within the VS installation" >&5 @@ -27407,31 +27422,34 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c # the configure script to find and run the compiler in the proper way. { $as_echo "$as_me:${as_lineno-$LINENO}: Setting extracted environment variables" >&5 $as_echo "$as_me: Setting extracted environment variables" >&6;} - . $OUTPUT_ROOT/localdevenv.sh + . $VS_ENV_TMP_DIR/set-vs-env.sh + # Now we have VS_PATH, VS_INCLUDE, VS_LIB. For further checking, we + # also define VCINSTALLDIR, WindowsSdkDir and WINDOWSSDKDIR. else # We did not find a vsvars bat file, let's hope we are run from a VS command prompt. { $as_echo "$as_me:${as_lineno-$LINENO}: Cannot locate a valid Visual Studio installation, checking current environment" >&5 $as_echo "$as_me: Cannot locate a valid Visual Studio installation, checking current environment" >&6;} fi - # At this point, we should have corrent variables in the environment, or we can't continue. + # At this point, we should have correct variables in the environment, or we can't continue. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Visual Studio variables" >&5 $as_echo_n "checking for Visual Studio variables... " >&6; } if test "x$VCINSTALLDIR" != x || test "x$WindowsSDKDir" != x || test "x$WINDOWSSDKDIR" != x; then - if test "x$INCLUDE" = x || test "x$LIB" = x; then + if test "x$VS_INCLUDE" = x || test "x$VS_LIB" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: present but broken" >&5 $as_echo "present but broken" >&6; } as_fn_error $? "Your VC command prompt seems broken, INCLUDE and/or LIB is missing." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } - # Remove any trailing \ from INCLUDE and LIB to avoid trouble in spec.gmk. - VS_INCLUDE=`$ECHO "$INCLUDE" | $SED 's/\\\\$//'` - VS_LIB=`$ECHO "$LIB" | $SED 's/\\\\$//'` - # Remove any paths containing # (typically F#) as that messes up make - PATH=`$ECHO "$PATH" | $SED 's/[^:#]*#[^:]*://g'` - VS_PATH="$PATH" + # Remove any trailing "\" and " " from the variables. + VS_INCLUDE=`$ECHO "$VS_INCLUDE" | $SED 's/\\\\* *$//'` + VS_LIB=`$ECHO "$VS_LIB" | $SED 's/\\\\* *$//'` + VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'` + WindowsSDKDir=`$ECHO "$WindowsSDKDir" | $SED 's/\\\\* *$//'` + WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'` + @@ -27456,6 +27474,12 @@ $as_echo "$as_me: or run \"bash.exe -l\" from a VS command prompt and then run c as_fn_error $? "Cannot continue" "$LINENO" 5 fi + # Reset path to VS_PATH. It will include everything that was on PATH at the time we + # ran TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV. + PATH="$VS_PATH" + # The microsoft toolchain also requires INCLUDE and LIB to be set. + export INCLUDE="$VS_INCLUDE" + export LIB="$VS_LIB" fi # autoconf magic only relies on PATH, so update it if tools dir is specified diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index af1b7adfd80..b7c00d4f495 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -189,6 +189,12 @@ AC_DEFUN_ONCE([TOOLCHAIN_PRE_DETECTION], # it for DLL resolution in runtime. if test "x$OPENJDK_BUILD_OS" = "xwindows" && test "x$TOOLCHAIN_TYPE" = "xmicrosoft"; then TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV + # Reset path to VS_PATH. It will include everything that was on PATH at the time we + # ran TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV. + PATH="$VS_PATH" + # The microsoft toolchain also requires INCLUDE and LIB to be set. + export INCLUDE="$VS_INCLUDE" + export LIB="$VS_LIB" fi # autoconf magic only relies on PATH, so update it if tools dir is specified diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index 37da5554066..81d0a964a4d 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -141,46 +141,44 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV], # Lets extract the variables that are set by vcvarsall.bat/vsvars32.bat/vsvars64.bat AC_MSG_NOTICE([Trying to extract Visual Studio environment variables]) - cd $OUTPUT_ROOT - # FIXME: The code betweeen ---- was inlined from a separate script and is not properly adapted - # to autoconf standards. - #---- + # We need to create a couple of temporary files. + VS_ENV_TMP_DIR="$OUTPUT_ROOT/vs-env" + $MKDIR -p $VS_ENV_TMP_DIR - # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment) - # but calculate the difference in Cygwin environment before/after running it and then - # apply the diff. + # Cannot use the VS10 setup script directly (since it only updates the DOS subshell environment). + # Instead create a shell script which will set the relevant variables when run. + WINPATH_VS_ENV_CMD="$VS_ENV_CMD" + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH([WINPATH_VS_ENV_CMD]) + WINPATH_BASH="$BASH" + BASIC_WINDOWS_REWRITE_AS_WINDOWS_MIXED_PATH([WINPATH_BASH]) - if test "x$OPENJDK_BUILD_OS_ENV" = xwindows.cygwin; then - _vs10varsall=`cygpath -a -m -s "$VS_ENV_CMD"` - _dosvs10varsall=`cygpath -a -w -s $_vs10varsall` - _dosbash=`cygpath -a -w -s \`which bash\`.*` - else - _dosvs10varsall=`cmd //c echo $VS_ENV_CMD` - _dosbash=`cmd //c echo \`which bash\`` - fi - - # generate the set of exported vars before/after the vs10 setup - $ECHO "@echo off" > localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export0" >> localdevenvtmp.bat - $ECHO "call $_dosvs10varsall $VS_ENV_ARGS" >> localdevenvtmp.bat - $ECHO "$_dosbash -c \"export -p\" > localdevenvtmp.export1" >> localdevenvtmp.bat + # Generate a DOS batch file which runs $VS_ENV_CMD, and then creates a shell + # script (executable by bash) that will setup the important variables. + EXTRACT_VC_ENV_BAT_FILE="$VS_ENV_TMP_DIR/extract-vs-env.bat" + $ECHO "@echo off" > $EXTRACT_VC_ENV_BAT_FILE + # This will end up something like: + # call C:/progra~2/micros~2.0/vc/bin/amd64/vcvars64.bat + $ECHO "call $WINPATH_VS_ENV_CMD $VS_ENV_ARGS" >> $EXTRACT_VC_ENV_BAT_FILE + # These will end up something like: + # C:/CygWin/bin/bash -c 'echo VS_PATH=\"$PATH\" > localdevenv.sh + # The trailing space for everyone except PATH is no typo, but is needed due + # to trailing \ in the Windows paths. These will be stripped later. + $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE # Now execute the newly created bat file. - # The | cat is to stop SetEnv.Cmd to mess with system colors on msys - cmd /c localdevenvtmp.bat | cat - - # apply the diff (less some non-vs10 vars named by "!") - $SORT localdevenvtmp.export0 | $GREP -v "!" > localdevenvtmp.export0.sort - $SORT localdevenvtmp.export1 | $GREP -v "!" > localdevenvtmp.export1.sort - $COMM -1 -3 localdevenvtmp.export0.sort localdevenvtmp.export1.sort > localdevenv.sh - - # cleanup - $RM localdevenvtmp* - #---- + # The | cat is to stop SetEnv.Cmd to mess with system colors on msys. + # Change directory so we don't need to mess with Windows paths in redirects. + cd $VS_ENV_TMP_DIR + cmd /c extract-vs-env.bat | $CAT cd $CURDIR - if test ! -s $OUTPUT_ROOT/localdevenv.sh; then - AC_MSG_RESULT([no]) + + if test ! -s $VS_ENV_TMP_DIR/set-vs-env.sh; then AC_MSG_NOTICE([Could not succesfully extract the envionment variables needed for the VS setup.]) AC_MSG_NOTICE([Try setting --with-tools-dir to the VC/bin directory within the VS installation]) AC_MSG_NOTICE([or run "bash.exe -l" from a VS command prompt and then run configure from there.]) @@ -190,30 +188,33 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV], # Now set all paths and other env variables. This will allow the rest of # the configure script to find and run the compiler in the proper way. AC_MSG_NOTICE([Setting extracted environment variables]) - . $OUTPUT_ROOT/localdevenv.sh + . $VS_ENV_TMP_DIR/set-vs-env.sh + # Now we have VS_PATH, VS_INCLUDE, VS_LIB. For further checking, we + # also define VCINSTALLDIR, WindowsSdkDir and WINDOWSSDKDIR. else # We did not find a vsvars bat file, let's hope we are run from a VS command prompt. AC_MSG_NOTICE([Cannot locate a valid Visual Studio installation, checking current environment]) fi - # At this point, we should have corrent variables in the environment, or we can't continue. + # At this point, we should have correct variables in the environment, or we can't continue. AC_MSG_CHECKING([for Visual Studio variables]) if test "x$VCINSTALLDIR" != x || test "x$WindowsSDKDir" != x || test "x$WINDOWSSDKDIR" != x; then - if test "x$INCLUDE" = x || test "x$LIB" = x; then + if test "x$VS_INCLUDE" = x || test "x$VS_LIB" = x; then AC_MSG_RESULT([present but broken]) AC_MSG_ERROR([Your VC command prompt seems broken, INCLUDE and/or LIB is missing.]) else AC_MSG_RESULT([ok]) - # Remove any trailing \ from INCLUDE and LIB to avoid trouble in spec.gmk. - VS_INCLUDE=`$ECHO "$INCLUDE" | $SED 's/\\\\$//'` - VS_LIB=`$ECHO "$LIB" | $SED 's/\\\\$//'` - # Remove any paths containing # (typically F#) as that messes up make - PATH=`$ECHO "$PATH" | $SED 's/[[^:#]]*#[^:]*://g'` - VS_PATH="$PATH" + # Remove any trailing "\" and " " from the variables. + VS_INCLUDE=`$ECHO "$VS_INCLUDE" | $SED 's/\\\\* *$//'` + VS_LIB=`$ECHO "$VS_LIB" | $SED 's/\\\\* *$//'` + VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'` + WindowsSDKDir=`$ECHO "$WindowsSDKDir" | $SED 's/\\\\* *$//'` + WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'` + + AC_SUBST(VS_PATH) AC_SUBST(VS_INCLUDE) AC_SUBST(VS_LIB) - AC_SUBST(VS_PATH) fi else AC_MSG_RESULT([not found]) From 4643207df7404b92ef228c318a20fc4e7e0b83cb Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 31 Mar 2014 23:49:00 -0400 Subject: [PATCH 102/170] 8016039: jvm.lib is missing from export list unless building server Make the export declaration unconditional Reviewed-by: sla, sspitsyn --- hotspot/make/windows/makefiles/defs.make | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make index acf4d24d7e0..fe4b6c72fbf 100644 --- a/hotspot/make/windows/makefiles/defs.make +++ b/hotspot/make/windows/makefiles/defs.make @@ -260,7 +260,6 @@ ifeq ($(JVM_VARIANT_SERVER),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/jvm.map endif endif - EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib endif ifeq ($(JVM_VARIANT_CLIENT),true) EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt @@ -275,6 +274,8 @@ ifeq ($(JVM_VARIANT_CLIENT),true) endif endif +EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib + ifeq ($(BUILD_WIN_SA), 1) EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX) ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) From f190cc8c67eb3bf2f21c5ae90184d01657a9bd77 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 1 Apr 2014 03:59:01 -0700 Subject: [PATCH 103/170] 8038201: Clean up misleading usage of malloc() in init_system_properties_values() Remove the misleading malloc macro and cleanup the code Reviewed-by: dsamersoff, kvn --- .../cpu/ppc/vm/templateInterpreter_ppc.cpp | 2 +- hotspot/src/os/aix/vm/os_aix.cpp | 118 +++--- hotspot/src/os/bsd/vm/os_bsd.cpp | 359 +++++++++--------- hotspot/src/os/linux/vm/os_linux.cpp | 194 ++++------ hotspot/src/os/solaris/vm/os_solaris.cpp | 357 ++++++++--------- 5 files changed, 463 insertions(+), 567 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index 2e19fca081d..f22fbae29c3 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -1672,7 +1672,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) { //__ flush_bundle(); address entry = __ pc(); - char *bname = NULL; + const char *bname = NULL; uint tsize = 0; switch(state) { case ftos: diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 5629d49603d..8167665f66b 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -60,8 +60,8 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" #include "services/runtimeService.hpp" @@ -70,16 +70,6 @@ #include "utilities/events.hpp" #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" -#ifdef TARGET_ARCH_ppc -# include "assembler_ppc.inline.hpp" -# include "nativeInst_ppc.hpp" -#endif -#ifdef COMPILER1 -#include "c1/c1_Runtime1.hpp" -#endif -#ifdef COMPILER2 -#include "opto/runtime.hpp" -#endif // put OS-includes here (sorted alphabetically) #include @@ -378,13 +368,14 @@ void os::Aix::query_multipage_support() { assert(_page_size == SIZE_4K, "surprise!"); - // query default data page size (default page size for C-Heap, pthread stacks and .bss). + // Query default data page size (default page size for C-Heap, pthread stacks and .bss). // Default data page size is influenced either by linker options (-bdatapsize) // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. size_t data_page_size = SIZE_4K; { void* p = ::malloc(SIZE_16M); + guarantee(p != NULL, "malloc failed"); data_page_size = os::Aix::query_pagesize(p); ::free(p); } @@ -511,85 +502,76 @@ query_multipage_support_end: } // end os::Aix::query_multipage_support() - -// The code for this method was initially derived from the version in os_linux.cpp +// The code for this method was initially derived from the version in os_linux.cpp. void os::init_system_properties_values() { - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) + #define DEFAULT_LIBPATH "/usr/lib:/lib" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" + // Buffer that fits several sprintfs. + // Note that the space for the trailing null is provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + // sysclasspath, java_home, dll_dir - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); + { + char *pslash; + os::jvm_path(buf, bufsize); - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; // get rid of /libjvm.so - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; // get rid of /{client|server|hotspot} - } - - dll_path = malloc(strlen(buf) + 1); - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - - if (pslash != NULL) { + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. pslash = strrchr(buf, '/'); if (pslash != NULL) { - *pslash = '\0'; // get rid of / + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { pslash = strrchr(buf, '/'); if (pslash != NULL) { - *pslash = '\0'; // get rid of /lib + *pslash = '\0'; // Get rid of /. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. + } } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } - home_path = malloc(strlen(buf) + 1); - strcpy(home_path, buf); - Arguments::set_java_home(home_path); + // Where to look for native libraries. - if (!set_boot_path('/', ':')) return; - - // Where to look for native libraries - - // On Aix we get the user setting of LIBPATH + // On Aix we get the user setting of LIBPATH. // Eventually, all the library path setting will be done here. - char *ld_library_path; - - // Construct the invariant part of ld_library_path. - ld_library_path = (char *) malloc(sizeof(DEFAULT_LIBPATH)); - sprintf(ld_library_path, DEFAULT_LIBPATH); - - // Get the user setting of LIBPATH, and prepended it. - char *v = ::getenv("LIBPATH"); - if (v == NULL) { - v = ""; - } - - char *t = ld_library_path; - // That's +1 for the colon and +1 for the trailing '\0' - ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", v, t); + // Get the user setting of LIBPATH. + const char *v = ::getenv("LIBPATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + // Concatenate user and invariant part of ld_library_path. + // That's +1 for the colon and +1 for the trailing '\0'. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, strlen(v) + 1 + sizeof(DEFAULT_LIBPATH) + 1, mtInternal); + sprintf(ld_library_path, "%s%s" DEFAULT_LIBPATH, v, v_colon); Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); - // Extensions directories - char* cbuf = malloc(strlen(Arguments::get_java_home()) + sizeof(EXTENSIONS_DIR)); - sprintf(cbuf, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); - Arguments::set_ext_dirs(cbuf); + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); // Endorsed standards default directory. - cbuf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(cbuf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(cbuf); + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); -#undef malloc #undef DEFAULT_LIBPATH #undef EXTENSIONS_DIR #undef ENDORSED_DIR diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 79ea15941aa..2a71edf0028 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -306,9 +306,6 @@ static const char *get_home() { #endif void os::init_system_properties_values() { -// char arch[12]; -// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch)); - // The next steps are taken in the product version: // // Obtain the JAVA_HOME value from the location of libjvm.so. @@ -335,199 +332,205 @@ void os::init_system_properties_values() { // Important note: if the location of libjvm.so changes this // code needs to be changed accordingly. - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) -#define getenv(n) ::getenv(n) - -/* - * See ld(1): - * The linker uses the following search paths to locate required - * shared libraries: - * 1: ... - * ... - * 7: The default directories, normally /lib and /usr/lib. - */ +// See ld(1): +// The linker uses the following search paths to locate required +// shared libraries: +// 1: ... +// ... +// 7: The default directories, normally /lib and /usr/lib. #ifndef DEFAULT_LIBPATH #define DEFAULT_LIBPATH "/lib:/usr/lib" #endif +// Base path of extensions installed on the system. +#define SYS_EXT_DIR "/usr/java/packages" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" -#define REG_DIR "/usr/java/packages" -#ifdef __APPLE__ -#define SYS_EXTENSIONS_DIR "/Library/Java/Extensions" -#define SYS_EXTENSIONS_DIRS SYS_EXTENSIONS_DIR ":/Network" SYS_EXTENSIONS_DIR ":/System" SYS_EXTENSIONS_DIR ":/usr/lib/java" - const char *user_home_dir = get_home(); - // the null in SYS_EXTENSIONS_DIRS counts for the size of the colon after user_home_dir - int system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) + - sizeof(SYS_EXTENSIONS_DIRS); -#endif - - { - /* sysclasspath, java_home, dll_dir */ - { - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); - - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /{client|server|hotspot} */ - dll_path = malloc(strlen(buf) + 1); - if (dll_path == NULL) - return; - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; /* get rid of / (/lib on macosx) */ #ifndef __APPLE__ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /lib */ -#endif - } - } - home_path = malloc(strlen(buf) + 1); - if (home_path == NULL) - return; - strcpy(home_path, buf); - Arguments::set_java_home(home_path); + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); - if (!set_boot_path('/', ':')) - return; + // sysclasspath, java_home, dll_dir + { + char *pslash; + os::jvm_path(buf, bufsize); + + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. } + Arguments::set_dll_dir(buf); - /* - * Where to look for native libraries - * - * Note: Due to a legacy implementation, most of the library path - * is set in the launcher. This was to accomodate linking restrictions - * on legacy Bsd implementations (which are no longer supported). - * Eventually, all the library path setting will be done here. - * - * However, to prevent the proliferation of improperly built native - * libraries, the new path component /usr/java/packages is added here. - * Eventually, all the library path setting will be done here. - */ - { - char *ld_library_path; - - /* - * Construct the invariant part of ld_library_path. Note that the - * space for the colon and the trailing null are provided by the - * nulls included by the sizeof operator (so actually we allocate - * a byte more than necessary). - */ -#ifdef __APPLE__ - ld_library_path = (char *) malloc(system_ext_size); - sprintf(ld_library_path, "%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, user_home_dir); -#else - ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") + - strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH)); - sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch); -#endif - - /* - * Get the user setting of LD_LIBRARY_PATH, and prepended it. It - * should always exist (until the legacy problem cited above is - * addressed). - */ -#ifdef __APPLE__ - // Prepend the default path with the JAVA_LIBRARY_PATH so that the app launcher code can specify a directory inside an app wrapper - char *l = getenv("JAVA_LIBRARY_PATH"); - if (l != NULL) { - char *t = ld_library_path; - /* That's +1 for the colon and +1 for the trailing '\0' */ - ld_library_path = (char *) malloc(strlen(l) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", l, t); - free(t); + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. } - - char *v = getenv("DYLD_LIBRARY_PATH"); -#else - char *v = getenv("LD_LIBRARY_PATH"); -#endif - if (v != NULL) { - char *t = ld_library_path; - /* That's +1 for the colon and +1 for the trailing '\0' */ - ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", v, t); - free(t); - } - -#ifdef __APPLE__ - // Apple's Java6 has "." at the beginning of java.library.path. - // OpenJDK on Windows has "." at the end of java.library.path. - // OpenJDK on Linux and Solaris don't have "." in java.library.path - // at all. To ease the transition from Apple's Java6 to OpenJDK7, - // "." is appended to the end of java.library.path. Yes, this - // could cause a change in behavior, but Apple's Java6 behavior - // can be achieved by putting "." at the beginning of the - // JAVA_LIBRARY_PATH environment variable. - { - char *t = ld_library_path; - // that's +3 for appending ":." and the trailing '\0' - ld_library_path = (char *) malloc(strlen(t) + 3); - sprintf(ld_library_path, "%s:%s", t, "."); - free(t); - } -#endif - - Arguments::set_library_path(ld_library_path); - } - - /* - * Extensions directories. - * - * Note that the space for the colon and the trailing null are provided - * by the nulls included by the sizeof operator (so actually one byte more - * than necessary is allocated). - */ - { -#ifdef __APPLE__ - char *buf = malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + system_ext_size); - sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" - SYS_EXTENSIONS_DIRS, user_home_dir, Arguments::get_java_home()); -#else - char *buf = malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR)); - sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR, - Arguments::get_java_home()); -#endif - - Arguments::set_ext_dirs(buf); - } - - /* Endorsed standards default directory. */ - { - char * buf; - buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); + } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } -#ifdef __APPLE__ + // Where to look for native libraries. + // + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Bsd implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/java/packages is added here. + // Eventually, all the library path setting will be done here. + { + // Get the user setting of LD_LIBRARY_PATH, and prepended it. It + // should always exist (until the legacy problem cited above is + // addressed). + const char *v = ::getenv("LD_LIBRARY_PATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + // That's +1 for the colon and +1 for the trailing '\0'. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, + strlen(v) + 1 + + sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1, + mtInternal); + sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch); + Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); + } + + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + +#else // __APPLE__ + +#define SYS_EXTENSIONS_DIR "/Library/Java/Extensions" +#define SYS_EXTENSIONS_DIRS SYS_EXTENSIONS_DIR ":/Network" SYS_EXTENSIONS_DIR ":/System" SYS_EXTENSIONS_DIR ":/usr/lib/java" + + const char *user_home_dir = get_home(); + // The null in SYS_EXTENSIONS_DIRS counts for the size of the colon after user_home_dir. + size_t system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) + + sizeof(SYS_EXTENSIONS_DIRS); + + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // for dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + system_ext_size, // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + + // sysclasspath, java_home, dll_dir + { + char *pslash; + os::jvm_path(buf, bufsize); + + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. + } + } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); + } + + // Where to look for native libraries. + // + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Bsd implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/java/packages is added here. + // Eventually, all the library path setting will be done here. + { + // Get the user setting of LD_LIBRARY_PATH, and prepended it. It + // should always exist (until the legacy problem cited above is + // addressed). + // Prepend the default path with the JAVA_LIBRARY_PATH so that the app launcher code + // can specify a directory inside an app wrapper + const char *l = ::getenv("JAVA_LIBRARY_PATH"); + const char *l_colon = ":"; + if (l == NULL) { l = ""; l_colon = ""; } + + const char *v = ::getenv("DYLD_LIBRARY_PATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + + // Apple's Java6 has "." at the beginning of java.library.path. + // OpenJDK on Windows has "." at the end of java.library.path. + // OpenJDK on Linux and Solaris don't have "." in java.library.path + // at all. To ease the transition from Apple's Java6 to OpenJDK7, + // "." is appended to the end of java.library.path. Yes, this + // could cause a change in behavior, but Apple's Java6 behavior + // can be achieved by putting "." at the beginning of the + // JAVA_LIBRARY_PATH environment variable. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, + strlen(v) + 1 + strlen(l) + 1 + + system_ext_size + 3, + mtInternal); + sprintf(ld_library_path, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.", + v, v_colon, l, l_colon, user_home_dir); + Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); + } + + // Extensions directories. + // + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator (so actually one byte more + // than necessary is allocated). + sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, + user_home_dir, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + #undef SYS_EXTENSIONS_DIR -#endif -#undef malloc -#undef getenv +#undef SYS_EXTENSIONS_DIRS + +#endif // __APPLE__ + +#undef SYS_EXT_DIR #undef EXTENSIONS_DIR #undef ENDORSED_DIR - - // Done - return; } //////////////////////////////////////////////////////////////////////////////// @@ -3091,7 +3094,7 @@ void os::Bsd::set_signal_handler(int sig, bool set_installed) { sigAct.sa_sigaction = signalHandler; sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } -#if __APPLE__ +#ifdef __APPLE__ // Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV // (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages" // if the signal handler declares it will handle it on alternate stack. diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 77dfc54bd7b..e9192178ff8 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -319,9 +319,6 @@ void os::Linux::initialize_system_info() { } void os::init_system_properties_values() { -// char arch[12]; -// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch)); - // The next steps are taken in the product version: // // Obtain the JAVA_HOME value from the location of libjvm.so. @@ -348,140 +345,101 @@ void os::init_system_properties_values() { // Important note: if the location of libjvm.so changes this // code needs to be changed accordingly. - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) -#define getenv(n) ::getenv(n) - -/* - * See ld(1): - * The linker uses the following search paths to locate required - * shared libraries: - * 1: ... - * ... - * 7: The default directories, normally /lib and /usr/lib. - */ +// See ld(1): +// The linker uses the following search paths to locate required +// shared libraries: +// 1: ... +// ... +// 7: The default directories, normally /lib and /usr/lib. #if defined(AMD64) || defined(_LP64) && (defined(SPARC) || defined(PPC) || defined(S390)) #define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib" #else #define DEFAULT_LIBPATH "/lib:/usr/lib" #endif +// Base path of extensions installed on the system. +#define SYS_EXT_DIR "/usr/java/packages" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" -#define REG_DIR "/usr/java/packages" + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + + // sysclasspath, java_home, dll_dir { - /* sysclasspath, java_home, dll_dir */ - { - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); + char *pslash; + os::jvm_path(buf, bufsize); - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */ + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /. pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /{client|server|hotspot} */ - dll_path = malloc(strlen(buf) + 1); - if (dll_path == NULL) - return; - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; /* get rid of / */ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /lib */ - } + *pslash = '\0'; // Get rid of /lib. } - - home_path = malloc(strlen(buf) + 1); - if (home_path == NULL) - return; - strcpy(home_path, buf); - Arguments::set_java_home(home_path); - - if (!set_boot_path('/', ':')) - return; - } - - /* - * Where to look for native libraries - * - * Note: Due to a legacy implementation, most of the library path - * is set in the launcher. This was to accomodate linking restrictions - * on legacy Linux implementations (which are no longer supported). - * Eventually, all the library path setting will be done here. - * - * However, to prevent the proliferation of improperly built native - * libraries, the new path component /usr/java/packages is added here. - * Eventually, all the library path setting will be done here. - */ - { - char *ld_library_path; - - /* - * Construct the invariant part of ld_library_path. Note that the - * space for the colon and the trailing null are provided by the - * nulls included by the sizeof operator (so actually we allocate - * a byte more than necessary). - */ - ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") + - strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH)); - sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch); - - /* - * Get the user setting of LD_LIBRARY_PATH, and prepended it. It - * should always exist (until the legacy problem cited above is - * addressed). - */ - char *v = getenv("LD_LIBRARY_PATH"); - if (v != NULL) { - char *t = ld_library_path; - /* That's +1 for the colon and +1 for the trailing '\0' */ - ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1); - sprintf(ld_library_path, "%s:%s", v, t); - } - Arguments::set_library_path(ld_library_path); - } - - /* - * Extensions directories. - * - * Note that the space for the colon and the trailing null are provided - * by the nulls included by the sizeof operator (so actually one byte more - * than necessary is allocated). - */ - { - char *buf = malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR)); - sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR, - Arguments::get_java_home()); - Arguments::set_ext_dirs(buf); - } - - /* Endorsed standards default directory. */ - { - char * buf; - buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); + } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } -#undef malloc -#undef getenv + // Where to look for native libraries. + // + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Linux implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/java/packages is added here. + // Eventually, all the library path setting will be done here. + { + // Get the user setting of LD_LIBRARY_PATH, and prepended it. It + // should always exist (until the legacy problem cited above is + // addressed). + const char *v = ::getenv("LD_LIBRARY_PATH"); + const char *v_colon = ":"; + if (v == NULL) { v = ""; v_colon = ""; } + // That's +1 for the colon and +1 for the trailing '\0'. + char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, + strlen(v) + 1 + + sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1, + mtInternal); + sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch); + Arguments::set_library_path(ld_library_path); + FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal); + } + + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + +#undef DEFAULT_LIBPATH +#undef SYS_EXT_DIR #undef EXTENSIONS_DIR #undef ENDORSED_DIR - - // Done - return; } //////////////////////////////////////////////////////////////////////////////// diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 54b78261856..16976d65f97 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -580,9 +580,6 @@ bool os::have_special_privileges() { void os::init_system_properties_values() { - char arch[12]; - sysinfo(SI_ARCHITECTURE, arch, sizeof(arch)); - // The next steps are taken in the product version: // // Obtain the JAVA_HOME value from the location of libjvm.so. @@ -609,218 +606,174 @@ void os::init_system_properties_values() { // Important note: if the location of libjvm.so changes this // code needs to be changed accordingly. - // The next few definitions allow the code to be verbatim: -#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal) -#define free(p) FREE_C_HEAP_ARRAY(char, p, mtInternal) -#define getenv(n) ::getenv(n) - +// Base path of extensions installed on the system. +#define SYS_EXT_DIR "/usr/jdk/packages" #define EXTENSIONS_DIR "/lib/ext" #define ENDORSED_DIR "/lib/endorsed" -#define COMMON_DIR "/usr/jdk/packages" + char cpu_arch[12]; + // Buffer that fits several sprintfs. + // Note that the space for the colon and the trailing null are provided + // by the nulls included by the sizeof operator. + const size_t bufsize = + MAX4((size_t)MAXPATHLEN, // For dll_dir & friends. + sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch), // invariant ld_library_path + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir + (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); + + // sysclasspath, java_home, dll_dir { - /* sysclasspath, java_home, dll_dir */ - { - char *home_path; - char *dll_path; - char *pslash; - char buf[MAXPATHLEN]; - os::jvm_path(buf, sizeof(buf)); + char *pslash; + os::jvm_path(buf, bufsize); - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */ + // Found the full path to libjvm.so. + // Now cut the path to /jre if we can. + *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /{client|server|hotspot}. + } + Arguments::set_dll_dir(buf); + + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /. pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /{client|server|hotspot} */ - dll_path = malloc(strlen(buf) + 1); - if (dll_path == NULL) - return; - strcpy(dll_path, buf); - Arguments::set_dll_dir(dll_path); - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; /* get rid of / */ - pslash = strrchr(buf, '/'); - if (pslash != NULL) - *pslash = '\0'; /* get rid of /lib */ - } + *pslash = '\0'; // Get rid of /lib. } - - home_path = malloc(strlen(buf) + 1); - if (home_path == NULL) - return; - strcpy(home_path, buf); - Arguments::set_java_home(home_path); - - if (!set_boot_path('/', ':')) - return; - } - - /* - * Where to look for native libraries - */ - { - // Use dlinfo() to determine the correct java.library.path. - // - // If we're launched by the Java launcher, and the user - // does not set java.library.path explicitly on the commandline, - // the Java launcher sets LD_LIBRARY_PATH for us and unsets - // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case - // dlinfo returns LD_LIBRARY_PATH + crle settings (including - // /usr/lib), which is exactly what we want. - // - // If the user does set java.library.path, it completely - // overwrites this setting, and always has. - // - // If we're not launched by the Java launcher, we may - // get here with any/all of the LD_LIBRARY_PATH[_32|64] - // settings. Again, dlinfo does exactly what we want. - - Dl_serinfo _info, *info = &_info; - Dl_serpath *path; - char* library_path; - char *common_path; - int i; - - // determine search path count and required buffer size - if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { - vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); - } - - // allocate new buffer and initialize - info = (Dl_serinfo*)malloc(_info.dls_size); - if (info == NULL) { - vm_exit_out_of_memory(_info.dls_size, OOM_MALLOC_ERROR, - "init_system_properties_values info"); - } - info->dls_size = _info.dls_size; - info->dls_cnt = _info.dls_cnt; - - // obtain search path information - if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { - free(info); - vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); - } - - path = &info->dls_serpath[0]; - - // Note: Due to a legacy implementation, most of the library path - // is set in the launcher. This was to accomodate linking restrictions - // on legacy Solaris implementations (which are no longer supported). - // Eventually, all the library path setting will be done here. - // - // However, to prevent the proliferation of improperly built native - // libraries, the new path component /usr/jdk/packages is added here. - - // Determine the actual CPU architecture. - char cpu_arch[12]; - sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch)); -#ifdef _LP64 - // If we are a 64-bit vm, perform the following translations: - // sparc -> sparcv9 - // i386 -> amd64 - if (strcmp(cpu_arch, "sparc") == 0) - strcat(cpu_arch, "v9"); - else if (strcmp(cpu_arch, "i386") == 0) - strcpy(cpu_arch, "amd64"); -#endif - - // Construct the invariant part of ld_library_path. Note that the - // space for the colon and the trailing null are provided by the - // nulls included by the sizeof operator. - size_t bufsize = sizeof(COMMON_DIR) + sizeof("/lib/") + strlen(cpu_arch); - common_path = malloc(bufsize); - if (common_path == NULL) { - free(info); - vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR, - "init_system_properties_values common_path"); - } - sprintf(common_path, COMMON_DIR "/lib/%s", cpu_arch); - - // struct size is more than sufficient for the path components obtained - // through the dlinfo() call, so only add additional space for the path - // components explicitly added here. - bufsize = info->dls_size + strlen(common_path); - library_path = malloc(bufsize); - if (library_path == NULL) { - free(info); - free(common_path); - vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR, - "init_system_properties_values library_path"); - } - library_path[0] = '\0'; - - // Construct the desired Java library path from the linker's library - // search path. - // - // For compatibility, it is optimal that we insert the additional path - // components specific to the Java VM after those components specified - // in LD_LIBRARY_PATH (if any) but before those added by the ld.so - // infrastructure. - if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it - strcpy(library_path, common_path); - } else { - int inserted = 0; - for (i = 0; i < info->dls_cnt; i++, path++) { - uint_t flags = path->dls_flags & LA_SER_MASK; - if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { - strcat(library_path, common_path); - strcat(library_path, os::path_separator()); - inserted = 1; - } - strcat(library_path, path->dls_name); - strcat(library_path, os::path_separator()); - } - // eliminate trailing path separator - library_path[strlen(library_path)-1] = '\0'; - } - - // happens before argument parsing - can't use a trace flag - // tty->print_raw("init_system_properties_values: native lib path: "); - // tty->print_raw_cr(library_path); - - // callee copies into its own buffer - Arguments::set_library_path(library_path); - - free(common_path); - free(library_path); - free(info); - } - - /* - * Extensions directories. - * - * Note that the space for the colon and the trailing null are provided - * by the nulls included by the sizeof operator (so actually one byte more - * than necessary is allocated). - */ - { - char *buf = (char *) malloc(strlen(Arguments::get_java_home()) + - sizeof(EXTENSIONS_DIR) + sizeof(COMMON_DIR) + - sizeof(EXTENSIONS_DIR)); - sprintf(buf, "%s" EXTENSIONS_DIR ":" COMMON_DIR EXTENSIONS_DIR, - Arguments::get_java_home()); - Arguments::set_ext_dirs(buf); - } - - /* Endorsed standards default directory. */ - { - char * buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR)); - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); + } } + Arguments::set_java_home(buf); + set_boot_path('/', ':'); } -#undef malloc -#undef free -#undef getenv + // Where to look for native libraries. + { + // Use dlinfo() to determine the correct java.library.path. + // + // If we're launched by the Java launcher, and the user + // does not set java.library.path explicitly on the commandline, + // the Java launcher sets LD_LIBRARY_PATH for us and unsets + // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case + // dlinfo returns LD_LIBRARY_PATH + crle settings (including + // /usr/lib), which is exactly what we want. + // + // If the user does set java.library.path, it completely + // overwrites this setting, and always has. + // + // If we're not launched by the Java launcher, we may + // get here with any/all of the LD_LIBRARY_PATH[_32|64] + // settings. Again, dlinfo does exactly what we want. + + Dl_serinfo info_sz, *info = &info_sz; + Dl_serpath *path; + char *library_path; + char *common_path = buf; + + // Determine search path count and required buffer size. + if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); + } + + // Allocate new buffer and initialize. + info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal); + info->dls_size = info_sz.dls_size; + info->dls_cnt = info_sz.dls_cnt; + + // Obtain search path information. + if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + FREE_C_HEAP_ARRAY(char, info, mtInternal); + vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); + } + + path = &info->dls_serpath[0]; + + // Note: Due to a legacy implementation, most of the library path + // is set in the launcher. This was to accomodate linking restrictions + // on legacy Solaris implementations (which are no longer supported). + // Eventually, all the library path setting will be done here. + // + // However, to prevent the proliferation of improperly built native + // libraries, the new path component /usr/jdk/packages is added here. + + // Determine the actual CPU architecture. + sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch)); +#ifdef _LP64 + // If we are a 64-bit vm, perform the following translations: + // sparc -> sparcv9 + // i386 -> amd64 + if (strcmp(cpu_arch, "sparc") == 0) { + strcat(cpu_arch, "v9"); + } else if (strcmp(cpu_arch, "i386") == 0) { + strcpy(cpu_arch, "amd64"); + } +#endif + + // Construct the invariant part of ld_library_path. + sprintf(common_path, SYS_EXT_DIR "/lib/%s", cpu_arch); + + // Struct size is more than sufficient for the path components obtained + // through the dlinfo() call, so only add additional space for the path + // components explicitly added here. + size_t library_path_size = info->dls_size + strlen(common_path); + library_path = (char *)NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal); + library_path[0] = '\0'; + + // Construct the desired Java library path from the linker's library + // search path. + // + // For compatibility, it is optimal that we insert the additional path + // components specific to the Java VM after those components specified + // in LD_LIBRARY_PATH (if any) but before those added by the ld.so + // infrastructure. + if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it. + strcpy(library_path, common_path); + } else { + int inserted = 0; + int i; + for (i = 0; i < info->dls_cnt; i++, path++) { + uint_t flags = path->dls_flags & LA_SER_MASK; + if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { + strcat(library_path, common_path); + strcat(library_path, os::path_separator()); + inserted = 1; + } + strcat(library_path, path->dls_name); + strcat(library_path, os::path_separator()); + } + // Eliminate trailing path separator. + library_path[strlen(library_path)-1] = '\0'; + } + + // happens before argument parsing - can't use a trace flag + // tty->print_raw("init_system_properties_values: native lib path: "); + // tty->print_raw_cr(library_path); + + // Callee copies into its own buffer. + Arguments::set_library_path(library_path); + + FREE_C_HEAP_ARRAY(char, library_path, mtInternal); + FREE_C_HEAP_ARRAY(char, info, mtInternal); + } + + // Extensions directories. + sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); + Arguments::set_ext_dirs(buf); + + // Endorsed standards default directory. + sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); + Arguments::set_endorsed_dirs(buf); + + FREE_C_HEAP_ARRAY(char, buf, mtInternal); + +#undef SYS_EXT_DIR #undef EXTENSIONS_DIR #undef ENDORSED_DIR -#undef COMMON_DIR - } void os::breakpoint() { From 91dcc35215b5fd610417966ecc4e9a6edfc9814d Mon Sep 17 00:00:00 2001 From: David Simms Date: Tue, 1 Apr 2014 15:45:36 +0200 Subject: [PATCH 104/170] 8037295: Add size_t versions of Atomic::add, dec, and inc Reviewed-by: dholmes, fparain --- .../gc_implementation/g1/heapRegionRemSet.hpp | 12 ++++-------- hotspot/src/share/vm/runtime/atomic.hpp | 5 ++++- .../src/share/vm/runtime/atomic.inline.hpp | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 46b174548a9..0a080dbbf45 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -245,7 +245,7 @@ private: enum ParIterState { Unclaimed, Claimed, Complete }; volatile ParIterState _iter_state; - volatile jlong _iter_claimed; + volatile size_t _iter_claimed; // Unused unless G1RecordHRRSOops is true. @@ -319,16 +319,12 @@ public: bool iter_is_complete(); // Support for claiming blocks of cards during iteration - size_t iter_claimed() const { return (size_t)_iter_claimed; } + size_t iter_claimed() const { return _iter_claimed; } // Claim the next block of cards size_t iter_claimed_next(size_t step) { - size_t current, next; - do { - current = iter_claimed(); - next = current + step; - } while (Atomic::cmpxchg((jlong)next, &_iter_claimed, (jlong)current) != (jlong)current); - return current; + return Atomic::add(step, &_iter_claimed) - step; } + void reset_for_par_iteration(); bool verify_ready_for_par_iteration() { diff --git a/hotspot/src/share/vm/runtime/atomic.hpp b/hotspot/src/share/vm/runtime/atomic.hpp index 9ca5fce97e7..5b46b530b51 100644 --- a/hotspot/src/share/vm/runtime/atomic.hpp +++ b/hotspot/src/share/vm/runtime/atomic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, 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 @@ -57,6 +57,7 @@ class Atomic : AllStatic { // Atomically add to a location, return updated value inline static jint add (jint add_value, volatile jint* dest); + inline static size_t add (size_t add_value, volatile size_t* dest); inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest); inline static void* add_ptr(intptr_t add_value, volatile void* dest); // See comment above about using jlong atomics on 32-bit platforms @@ -65,12 +66,14 @@ class Atomic : AllStatic { // Atomically increment location inline static void inc (volatile jint* dest); static void inc (volatile jshort* dest); + inline static void inc (volatile size_t* dest); inline static void inc_ptr(volatile intptr_t* dest); inline static void inc_ptr(volatile void* dest); // Atomically decrement a location inline static void dec (volatile jint* dest); static void dec (volatile jshort* dest); + inline static void dec (volatile size_t* dest); inline static void dec_ptr(volatile intptr_t* dest); inline static void dec_ptr(volatile void* dest); diff --git a/hotspot/src/share/vm/runtime/atomic.inline.hpp b/hotspot/src/share/vm/runtime/atomic.inline.hpp index 2906719452d..e3983ef6b55 100644 --- a/hotspot/src/share/vm/runtime/atomic.inline.hpp +++ b/hotspot/src/share/vm/runtime/atomic.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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,4 +70,21 @@ # include "atomic_bsd_zero.inline.hpp" #endif +// size_t casts... +#if (SIZE_MAX != UINTPTR_MAX) +#error size_t is not WORD_SIZE, interesting platform, but missing implementation here +#endif + +inline size_t Atomic::add(size_t add_value, volatile size_t* dest) { + return (size_t) add_ptr((intptr_t) add_value, (volatile intptr_t*) dest); +} + +inline void Atomic::inc(volatile size_t* dest) { + inc_ptr((volatile intptr_t*) dest); +} + +inline void Atomic::dec(volatile size_t* dest) { + dec_ptr((volatile intptr_t*) dest); +} + #endif // SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP From 6db303a3012cdce863b329c7c582ca4bf311faea Mon Sep 17 00:00:00 2001 From: Morris Meyer Date: Tue, 1 Apr 2014 09:05:20 -0700 Subject: [PATCH 105/170] 8001532: C2 node files refactoring Split C2 node files into cast, convert, countbits, intrinsic, move, narrowptr and opaquenode classes Reviewed-by: kvn, morris --- hotspot/src/share/vm/opto/addnode.cpp | 1 + hotspot/src/share/vm/opto/callGenerator.cpp | 2 +- hotspot/src/share/vm/opto/callnode.cpp | 1 + hotspot/src/share/vm/opto/castnode.cpp | 294 ++++ hotspot/src/share/vm/opto/castnode.hpp | 119 ++ hotspot/src/share/vm/opto/cfgnode.cpp | 3 + hotspot/src/share/vm/opto/chaitin.cpp | 1 + hotspot/src/share/vm/opto/classes.cpp | 7 + hotspot/src/share/vm/opto/compile.cpp | 1 + hotspot/src/share/vm/opto/connode.cpp | 1319 ----------------- hotspot/src/share/vm/opto/connode.hpp | 622 +------- hotspot/src/share/vm/opto/convertnode.cpp | 512 +++++++ hotspot/src/share/vm/opto/convertnode.hpp | 215 +++ hotspot/src/share/vm/opto/countbitsnode.cpp | 119 ++ hotspot/src/share/vm/opto/countbitsnode.hpp | 94 ++ hotspot/src/share/vm/opto/divnode.cpp | 2 + hotspot/src/share/vm/opto/doCall.cpp | 1 + hotspot/src/share/vm/opto/escape.cpp | 1 + .../src/share/vm/opto/generateOptoStub.cpp | 2 +- hotspot/src/share/vm/opto/graphKit.cpp | 4 + hotspot/src/share/vm/opto/idealKit.hpp | 1 + hotspot/src/share/vm/opto/ifg.cpp | 1 - hotspot/src/share/vm/opto/intrinsicnode.cpp | 82 + hotspot/src/share/vm/opto/intrinsicnode.hpp | 127 ++ hotspot/src/share/vm/opto/library_call.cpp | 6 + hotspot/src/share/vm/opto/loopPredicate.cpp | 2 + hotspot/src/share/vm/opto/loopTransform.cpp | 3 + hotspot/src/share/vm/opto/loopUnswitch.cpp | 2 + hotspot/src/share/vm/opto/loopnode.cpp | 1 + hotspot/src/share/vm/opto/loopopts.cpp | 2 + hotspot/src/share/vm/opto/macro.cpp | 5 +- hotspot/src/share/vm/opto/matcher.cpp | 2 +- hotspot/src/share/vm/opto/memnode.cpp | 55 +- hotspot/src/share/vm/opto/memnode.hpp | 82 - hotspot/src/share/vm/opto/movenode.cpp | 398 +++++ hotspot/src/share/vm/opto/movenode.hpp | 152 ++ hotspot/src/share/vm/opto/mulnode.cpp | 1 + hotspot/src/share/vm/opto/narrowptrnode.cpp | 113 ++ hotspot/src/share/vm/opto/narrowptrnode.hpp | 119 ++ hotspot/src/share/vm/opto/opaquenode.cpp | 63 + hotspot/src/share/vm/opto/opaquenode.hpp | 91 ++ hotspot/src/share/vm/opto/parse1.cpp | 2 + hotspot/src/share/vm/opto/parse2.cpp | 2 + hotspot/src/share/vm/opto/parse3.cpp | 1 + hotspot/src/share/vm/opto/phaseX.cpp | 1 - hotspot/src/share/vm/opto/runtime.cpp | 1 - hotspot/src/share/vm/opto/split_if.cpp | 2 +- hotspot/src/share/vm/opto/subnode.cpp | 2 +- hotspot/src/share/vm/opto/superword.cpp | 3 + hotspot/src/share/vm/opto/superword.hpp | 1 - .../src/share/vm/precompiled/precompiled.hpp | 8 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 6 + 52 files changed, 2574 insertions(+), 2083 deletions(-) create mode 100644 hotspot/src/share/vm/opto/castnode.cpp create mode 100644 hotspot/src/share/vm/opto/castnode.hpp create mode 100644 hotspot/src/share/vm/opto/convertnode.cpp create mode 100644 hotspot/src/share/vm/opto/convertnode.hpp create mode 100644 hotspot/src/share/vm/opto/countbitsnode.cpp create mode 100644 hotspot/src/share/vm/opto/countbitsnode.hpp create mode 100644 hotspot/src/share/vm/opto/intrinsicnode.cpp create mode 100644 hotspot/src/share/vm/opto/intrinsicnode.hpp create mode 100644 hotspot/src/share/vm/opto/movenode.cpp create mode 100644 hotspot/src/share/vm/opto/movenode.hpp create mode 100644 hotspot/src/share/vm/opto/narrowptrnode.cpp create mode 100644 hotspot/src/share/vm/opto/narrowptrnode.hpp create mode 100644 hotspot/src/share/vm/opto/opaquenode.cpp create mode 100644 hotspot/src/share/vm/opto/opaquenode.hpp diff --git a/hotspot/src/share/vm/opto/addnode.cpp b/hotspot/src/share/vm/opto/addnode.cpp index 045e4f20918..a586eba1322 100644 --- a/hotspot/src/share/vm/opto/addnode.cpp +++ b/hotspot/src/share/vm/opto/addnode.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index a655f27b540..2a263639948 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -33,8 +33,8 @@ #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 31c004cd8ac..cfe86b1c312 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -27,6 +27,7 @@ #include "compiler/oopMap.hpp" #include "opto/callGenerator.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/escape.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/castnode.cpp b/hotspot/src/share/vm/opto/castnode.cpp new file mode 100644 index 00000000000..b8a35a72df9 --- /dev/null +++ b/hotspot/src/share/vm/opto/castnode.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2014, 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 "opto/addnode.hpp" +#include "opto/castnode.hpp" +#include "opto/connode.hpp" +#include "opto/matcher.hpp" +#include "opto/phaseX.hpp" +#include "opto/subnode.hpp" +#include "opto/type.hpp" + +//============================================================================= +// If input is already higher or equal to cast type, then this is an identity. +Node *ConstraintCastNode::Identity( PhaseTransform *phase ) { + return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this; +} + +//------------------------------Value------------------------------------------ +// Take 'join' of input and cast-up type +const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const { + if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; + const Type* ft = phase->type(in(1))->filter_speculative(_type); + +#ifdef ASSERT + // Previous versions of this function had some special case logic, + // which is no longer necessary. Make sure of the required effects. + switch (Opcode()) { + case Op_CastII: + { + const Type* t1 = phase->type(in(1)); + if( t1 == Type::TOP ) assert(ft == Type::TOP, "special case #1"); + const Type* rt = t1->join_speculative(_type); + if (rt->empty()) assert(ft == Type::TOP, "special case #2"); + break; + } + case Op_CastPP: + if (phase->type(in(1)) == TypePtr::NULL_PTR && + _type->isa_ptr() && _type->is_ptr()->_ptr == TypePtr::NotNull) + assert(ft == Type::TOP, "special case #3"); + break; + } +#endif //ASSERT + + return ft; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; +} + +//------------------------------Ideal_DU_postCCP------------------------------- +// Throw away cast after constant propagation +Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + const Type *t = ccp->type(in(1)); + ccp->hash_delete(this); + set_type(t); // Turn into ID function + ccp->hash_insert(this); + return this; +} + + +//============================================================================= + +//------------------------------Ideal_DU_postCCP------------------------------- +// If not converting int->oop, throw away cast after constant propagation +Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + const Type *t = ccp->type(in(1)); + if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) { + return NULL; // do not transform raw pointers or narrow oops + } + return ConstraintCastNode::Ideal_DU_postCCP(ccp); +} + + + +//============================================================================= +//------------------------------Identity--------------------------------------- +// If input is already higher or equal to cast type, then this is an identity. +Node *CheckCastPPNode::Identity( PhaseTransform *phase ) { + // Toned down to rescue meeting at a Phi 3 different oops all implementing + // the same interface. CompileTheWorld starting at 502, kd12rc1.zip. + return (phase->type(in(1)) == phase->type(this)) ? in(1) : this; +} + +//------------------------------Value------------------------------------------ +// Take 'join' of input and cast-up type, unless working with an Interface +const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const { + if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; + + const Type *inn = phase->type(in(1)); + if( inn == Type::TOP ) return Type::TOP; // No information yet + + const TypePtr *in_type = inn->isa_ptr(); + const TypePtr *my_type = _type->isa_ptr(); + const Type *result = _type; + if( in_type != NULL && my_type != NULL ) { + TypePtr::PTR in_ptr = in_type->ptr(); + if( in_ptr == TypePtr::Null ) { + result = in_type; + } else if( in_ptr == TypePtr::Constant ) { + // Casting a constant oop to an interface? + // (i.e., a String to a Comparable?) + // Then return the interface. + const TypeOopPtr *jptr = my_type->isa_oopptr(); + assert( jptr, "" ); + result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type)) + ? my_type->cast_to_ptr_type( TypePtr::NotNull ) + : in_type; + } else { + result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); + } + } + + // This is the code from TypePtr::xmeet() that prevents us from + // having 2 ways to represent the same type. We have to replicate it + // here because we don't go through meet/join. + if (result->remove_speculative() == result->speculative()) { + result = result->remove_speculative(); + } + + // Same as above: because we don't go through meet/join, remove the + // speculative type if we know we won't use it. + return result->cleanup_speculative(); + + // JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES. + // FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR! + + // + // Remove this code after overnight run indicates no performance + // loss from not performing JOIN at CheckCastPPNode + // + // const TypeInstPtr *in_oop = in->isa_instptr(); + // const TypeInstPtr *my_oop = _type->isa_instptr(); + // // If either input is an 'interface', return destination type + // assert (in_oop == NULL || in_oop->klass() != NULL, ""); + // assert (my_oop == NULL || my_oop->klass() != NULL, ""); + // if( (in_oop && in_oop->klass()->is_interface()) + // ||(my_oop && my_oop->klass()->is_interface()) ) { + // TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR; + // // Preserve cast away nullness for interfaces + // if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) { + // return my_oop->cast_to_ptr_type(TypePtr::NotNull); + // } + // return _type; + // } + // + // // Neither the input nor the destination type is an interface, + // + // // history: JOIN used to cause weird corner case bugs + // // return (in == TypeOopPtr::NULL_PTR) ? in : _type; + // // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops. + // // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr + // const Type *join = in->join(_type); + // // Check if join preserved NotNull'ness for pointers + // if( join->isa_ptr() && _type->isa_ptr() ) { + // TypePtr::PTR join_ptr = join->is_ptr()->_ptr; + // TypePtr::PTR type_ptr = _type->is_ptr()->_ptr; + // // If there isn't any NotNull'ness to preserve + // // OR if join preserved NotNull'ness then return it + // if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null || + // join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) { + // return join; + // } + // // ELSE return same old type as before + // return _type; + // } + // // Not joining two pointers + // return join; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape){ + return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *CastX2PNode::Value( PhaseTransform *phase ) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + if (t->base() == Type_X && t->singleton()) { + uintptr_t bits = (uintptr_t) t->is_intptr_t()->get_con(); + if (bits == 0) return TypePtr::NULL_PTR; + return TypeRawPtr::make((address) bits); + } + return CastX2PNode::bottom_type(); +} + +//------------------------------Idealize--------------------------------------- +static inline bool fits_in_int(const Type* t, bool but_not_min_int = false) { + if (t == Type::TOP) return false; + const TypeX* tl = t->is_intptr_t(); + jint lo = min_jint; + jint hi = max_jint; + if (but_not_min_int) ++lo; // caller wants to negate the value w/o overflow + return (tl->_lo >= lo) && (tl->_hi <= hi); +} + +static inline Node* addP_of_X2P(PhaseGVN *phase, + Node* base, + Node* dispX, + bool negate = false) { + if (negate) { + dispX = new (phase->C) SubXNode(phase->MakeConX(0), phase->transform(dispX)); + } + return new (phase->C) AddPNode(phase->C->top(), + phase->transform(new (phase->C) CastX2PNode(base)), + phase->transform(dispX)); +} + +Node *CastX2PNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // convert CastX2P(AddX(x, y)) to AddP(CastX2P(x), y) if y fits in an int + int op = in(1)->Opcode(); + Node* x; + Node* y; + switch (op) { + case Op_SubX: + x = in(1)->in(1); + // Avoid ideal transformations ping-pong between this and AddP for raw pointers. + if (phase->find_intptr_t_con(x, -1) == 0) + break; + y = in(1)->in(2); + if (fits_in_int(phase->type(y), true)) { + return addP_of_X2P(phase, x, y, true); + } + break; + case Op_AddX: + x = in(1)->in(1); + y = in(1)->in(2); + if (fits_in_int(phase->type(y))) { + return addP_of_X2P(phase, x, y); + } + if (fits_in_int(phase->type(x))) { + return addP_of_X2P(phase, y, x); + } + break; + } + return NULL; +} + +//------------------------------Identity--------------------------------------- +Node *CastX2PNode::Identity( PhaseTransform *phase ) { + if (in(1)->Opcode() == Op_CastP2X) return in(1)->in(1); + return this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *CastP2XNode::Value( PhaseTransform *phase ) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + if (t->base() == Type::RawPtr && t->singleton()) { + uintptr_t bits = (uintptr_t) t->is_rawptr()->get_con(); + return TypeX::make(bits); + } + return CastP2XNode::bottom_type(); +} + +Node *CastP2XNode::Ideal(PhaseGVN *phase, bool can_reshape) { + return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; +} + +//------------------------------Identity--------------------------------------- +Node *CastP2XNode::Identity( PhaseTransform *phase ) { + if (in(1)->Opcode() == Op_CastX2P) return in(1)->in(1); + return this; +} diff --git a/hotspot/src/share/vm/opto/castnode.hpp b/hotspot/src/share/vm/opto/castnode.hpp new file mode 100644 index 00000000000..d0f97c9b249 --- /dev/null +++ b/hotspot/src/share/vm/opto/castnode.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 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_OPTO_CASTNODE_HPP +#define SHARE_VM_OPTO_CASTNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + + +//------------------------------ConstraintCastNode----------------------------- +// cast to a different range +class ConstraintCastNode: public TypeNode { + public: + ConstraintCastNode (Node *n, const Type *t ): TypeNode(t,2) { + init_class_id(Class_ConstraintCast); + init_req(1, n); + } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual int Opcode() const; + virtual uint ideal_reg() const = 0; + virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +}; + +//------------------------------CastIINode------------------------------------- +// cast integer to integer (different range) +class CastIINode: public ConstraintCastNode { + public: + CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------CastPPNode------------------------------------- +// cast pointer to pointer (different type) +class CastPPNode: public ConstraintCastNode { + public: + CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {} + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegP; } + virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +}; + +//------------------------------CheckCastPPNode-------------------------------- +// for _checkcast, cast pointer to pointer (different type), without JOIN, +class CheckCastPPNode: public TypeNode { + public: + CheckCastPPNode( Node *c, Node *n, const Type *t ) : TypeNode(t,2) { + init_class_id(Class_CheckCastPP); + init_req(0, c); + init_req(1, n); + } + + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual int Opcode() const; + virtual uint ideal_reg() const { return Op_RegP; } + // No longer remove CheckCast after CCP as it gives me a place to hang + // the proper address type - which is required to compute anti-deps. + //virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +}; + + +//------------------------------CastX2PNode------------------------------------- +// convert a machine-pointer-sized integer to a raw pointer +class CastX2PNode : public Node { + public: + CastX2PNode( Node *n ) : Node(NULL, n) {} + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegP; } + virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } +}; + +//------------------------------CastP2XNode------------------------------------- +// Used in both 32-bit and 64-bit land. +// Used for card-marks and unsafe pointer math. +class CastP2XNode : public Node { + public: + CastP2XNode( Node *ctrl, Node *n ) : Node(ctrl, n) {} + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegX; } + virtual const Type *bottom_type() const { return TypeX_X; } + // Return false to keep node from moving away from an associated card mark. + virtual bool depends_only_on_test() const { return false; } +}; + + + +#endif // SHARE_VM_OPTO_CASTNODE_HPP diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index 25223035f29..02ec25fda2d 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -29,8 +29,11 @@ #include "opto/addnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" +#include "opto/movenode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/regmask.hpp" diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 5a1040aac48..24328546fec 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -37,6 +37,7 @@ #include "opto/indexSet.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" +#include "opto/movenode.hpp" #include "opto/opcodes.hpp" #include "opto/rootnode.hpp" diff --git a/hotspot/src/share/vm/opto/classes.cpp b/hotspot/src/share/vm/opto/classes.cpp index dadc72726e3..a3113922209 100644 --- a/hotspot/src/share/vm/opto/classes.cpp +++ b/hotspot/src/share/vm/opto/classes.cpp @@ -25,17 +25,24 @@ #include "precompiled.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" +#include "opto/countbitsnode.hpp" #include "opto/divnode.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" #include "opto/mathexactnode.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/multnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/node.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/vectornode.hpp" diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 9c77dd0cf0b..07c20ac4570 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -51,6 +51,7 @@ #include "opto/mathexactnode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/node.hpp" #include "opto/opcodes.hpp" #include "opto/output.hpp" diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp index baf8f4f0434..8485aba1303 100644 --- a/hotspot/src/share/vm/opto/connode.cpp +++ b/hotspot/src/share/vm/opto/connode.cpp @@ -66,1323 +66,4 @@ ConNode *ConNode::make( Compile* C, const Type *t ) { return NULL; } -//============================================================================= -/* -The major change is for CMoveP and StrComp. They have related but slightly -different problems. They both take in TWO oops which are both null-checked -independently before the using Node. After CCP removes the CastPP's they need -to pick up the guarding test edge - in this case TWO control edges. I tried -various solutions, all have problems: -(1) Do nothing. This leads to a bug where we hoist a Load from a CMoveP or a -StrComp above a guarding null check. I've seen both cases in normal -Xcomp -testing. - -(2) Plug the control edge from 1 of the 2 oops in. Apparent problem here is -to figure out which test post-dominates. The real problem is that it doesn't -matter which one you pick. After you pick up, the dominating-test elider in -IGVN can remove the test and allow you to hoist up to the dominating test on -the chosen oop bypassing the test on the not-chosen oop. Seen in testing. -Oops. - -(3) Leave the CastPP's in. This makes the graph more accurate in some sense; -we get to keep around the knowledge that an oop is not-null after some test. -Alas, the CastPP's interfere with GVN (some values are the regular oop, some -are the CastPP of the oop, all merge at Phi's which cannot collapse, etc). -This cost us 10% on SpecJVM, even when I removed some of the more trivial -cases in the optimizer. Removing more useless Phi's started allowing Loads to -illegally float above null checks. I gave up on this approach. - -(4) Add BOTH control edges to both tests. Alas, too much code knows that -control edges are in slot-zero ONLY. Many quick asserts fail; no way to do -this one. Note that I really want to allow the CMoveP to float and add both -control edges to the dependent Load op - meaning I can select early but I -cannot Load until I pass both tests. - -(5) Do not hoist CMoveP and StrComp. To this end I added the v-call -depends_only_on_test(). No obvious performance loss on Spec, but we are -clearly conservative on CMoveP (also so on StrComp but that's unlikely to -matter ever). - -*/ - - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Move constants to the right. -Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(0) && remove_dead_region(phase, can_reshape) ) return this; - // Don't bother trying to transform a dead node - if( in(0) && in(0)->is_top() ) return NULL; - assert( !phase->eqv(in(Condition), this) && - !phase->eqv(in(IfFalse), this) && - !phase->eqv(in(IfTrue), this), "dead loop in CMoveNode::Ideal" ); - if( phase->type(in(Condition)) == Type::TOP ) - return NULL; // return NULL when Condition is dead - - if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) { - if( in(Condition)->is_Bool() ) { - BoolNode* b = in(Condition)->as_Bool(); - BoolNode* b2 = b->negate(phase); - return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type ); - } - } - return NULL; -} - -//------------------------------is_cmove_id------------------------------------ -// Helper function to check for CMOVE identity. Shared with PhiNode::Identity -Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ) { - // Check for Cmp'ing and CMove'ing same values - if( (phase->eqv(cmp->in(1),f) && - phase->eqv(cmp->in(2),t)) || - // Swapped Cmp is OK - (phase->eqv(cmp->in(2),f) && - phase->eqv(cmp->in(1),t)) ) { - // Give up this identity check for floating points because it may choose incorrect - // value around 0.0 and -0.0 - if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD ) - return NULL; - // Check for "(t==f)?t:f;" and replace with "f" - if( b->_test._test == BoolTest::eq ) - return f; - // Allow the inverted case as well - // Check for "(t!=f)?t:f;" and replace with "t" - if( b->_test._test == BoolTest::ne ) - return t; - } - return NULL; -} - -//------------------------------Identity--------------------------------------- -// Conditional-move is an identity if both inputs are the same, or the test -// true or false. -Node *CMoveNode::Identity( PhaseTransform *phase ) { - if( phase->eqv(in(IfFalse),in(IfTrue)) ) // C-moving identical inputs? - return in(IfFalse); // Then it doesn't matter - if( phase->type(in(Condition)) == TypeInt::ZERO ) - return in(IfFalse); // Always pick left(false) input - if( phase->type(in(Condition)) == TypeInt::ONE ) - return in(IfTrue); // Always pick right(true) input - - // Check for CMove'ing a constant after comparing against the constant. - // Happens all the time now, since if we compare equality vs a constant in - // the parser, we "know" the variable is constant on one path and we force - // it. Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a - // conditional move: "x = (x==0)?0:x;". Yucko. This fix is slightly more - // general in that we don't need constants. - if( in(Condition)->is_Bool() ) { - BoolNode *b = in(Condition)->as_Bool(); - Node *cmp = b->in(1); - if( cmp->is_Cmp() ) { - Node *id = is_cmove_id( phase, cmp, in(IfTrue), in(IfFalse), b ); - if( id ) return id; - } - } - - return this; -} - -//------------------------------Value------------------------------------------ -// Result is the meet of inputs -const Type *CMoveNode::Value( PhaseTransform *phase ) const { - if( phase->type(in(Condition)) == Type::TOP ) - return Type::TOP; - return phase->type(in(IfFalse))->meet_speculative(phase->type(in(IfTrue))); -} - -//------------------------------make------------------------------------------- -// Make a correctly-flavored CMove. Since _type is directly determined -// from the inputs we do not need to specify it here. -CMoveNode *CMoveNode::make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ) { - switch( t->basic_type() ) { - case T_INT: return new (C) CMoveINode( bol, left, right, t->is_int() ); - case T_FLOAT: return new (C) CMoveFNode( bol, left, right, t ); - case T_DOUBLE: return new (C) CMoveDNode( bol, left, right, t ); - case T_LONG: return new (C) CMoveLNode( bol, left, right, t->is_long() ); - case T_OBJECT: return new (C) CMovePNode( c, bol, left, right, t->is_oopptr() ); - case T_ADDRESS: return new (C) CMovePNode( c, bol, left, right, t->is_ptr() ); - case T_NARROWOOP: return new (C) CMoveNNode( c, bol, left, right, t ); - default: - ShouldNotReachHere(); - return NULL; - } -} - -//============================================================================= -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Check for conversions to boolean -Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Try generic ideal's first - Node *x = CMoveNode::Ideal(phase, can_reshape); - if( x ) return x; - - // If zero is on the left (false-case, no-move-case) it must mean another - // constant is on the right (otherwise the shared CMove::Ideal code would - // have moved the constant to the right). This situation is bad for Intel - // and a don't-care for Sparc. It's bad for Intel because the zero has to - // be manifested in a register with a XOR which kills flags, which are live - // on input to the CMoveI, leading to a situation which causes excessive - // spilling on Intel. For Sparc, if the zero in on the left the Sparc will - // zero a register via G0 and conditionally-move the other constant. If the - // zero is on the right, the Sparc will load the first constant with a - // 13-bit set-lo and conditionally move G0. See bug 4677505. - if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) { - if( in(Condition)->is_Bool() ) { - BoolNode* b = in(Condition)->as_Bool(); - BoolNode* b2 = b->negate(phase); - return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type ); - } - } - - // Now check for booleans - int flip = 0; - - // Check for picking from zero/one - if( phase->type(in(IfFalse)) == TypeInt::ZERO && phase->type(in(IfTrue)) == TypeInt::ONE ) { - flip = 1 - flip; - } else if( phase->type(in(IfFalse)) == TypeInt::ONE && phase->type(in(IfTrue)) == TypeInt::ZERO ) { - } else return NULL; - - // Check for eq/ne test - if( !in(1)->is_Bool() ) return NULL; - BoolNode *bol = in(1)->as_Bool(); - if( bol->_test._test == BoolTest::eq ) { - } else if( bol->_test._test == BoolTest::ne ) { - flip = 1-flip; - } else return NULL; - - // Check for vs 0 or 1 - if( !bol->in(1)->is_Cmp() ) return NULL; - const CmpNode *cmp = bol->in(1)->as_Cmp(); - if( phase->type(cmp->in(2)) == TypeInt::ZERO ) { - } else if( phase->type(cmp->in(2)) == TypeInt::ONE ) { - // Allow cmp-vs-1 if the other input is bounded by 0-1 - if( phase->type(cmp->in(1)) != TypeInt::BOOL ) - return NULL; - flip = 1 - flip; - } else return NULL; - - // Convert to a bool (flipped) - // Build int->bool conversion -#ifndef PRODUCT - if( PrintOpto ) tty->print_cr("CMOV to I2B"); -#endif - Node *n = new (phase->C) Conv2BNode( cmp->in(1) ); - if( flip ) - n = new (phase->C) XorINode( phase->transform(n), phase->intcon(1) ); - - return n; -} - -//============================================================================= -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Check for absolute value -Node *CMoveFNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Try generic ideal's first - Node *x = CMoveNode::Ideal(phase, can_reshape); - if( x ) return x; - - int cmp_zero_idx = 0; // Index of compare input where to look for zero - int phi_x_idx = 0; // Index of phi input where to find naked x - - // Find the Bool - if( !in(1)->is_Bool() ) return NULL; - BoolNode *bol = in(1)->as_Bool(); - // Check bool sense - switch( bol->_test._test ) { - case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; - case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; - case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; - case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; - default: return NULL; break; - } - - // Find zero input of CmpF; the other input is being abs'd - Node *cmpf = bol->in(1); - if( cmpf->Opcode() != Op_CmpF ) return NULL; - Node *X = NULL; - bool flip = false; - if( phase->type(cmpf->in(cmp_zero_idx)) == TypeF::ZERO ) { - X = cmpf->in(3 - cmp_zero_idx); - } else if (phase->type(cmpf->in(3 - cmp_zero_idx)) == TypeF::ZERO) { - // The test is inverted, we should invert the result... - X = cmpf->in(cmp_zero_idx); - flip = true; - } else { - return NULL; - } - - // If X is found on the appropriate phi input, find the subtract on the other - if( X != in(phi_x_idx) ) return NULL; - int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; - Node *sub = in(phi_sub_idx); - - // Allow only SubF(0,X) and fail out for all others; NegF is not OK - if( sub->Opcode() != Op_SubF || - sub->in(2) != X || - phase->type(sub->in(1)) != TypeF::ZERO ) return NULL; - - Node *abs = new (phase->C) AbsFNode( X ); - if( flip ) - abs = new (phase->C) SubFNode(sub->in(1), phase->transform(abs)); - - return abs; -} - -//============================================================================= -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Check for absolute value -Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // Try generic ideal's first - Node *x = CMoveNode::Ideal(phase, can_reshape); - if( x ) return x; - - int cmp_zero_idx = 0; // Index of compare input where to look for zero - int phi_x_idx = 0; // Index of phi input where to find naked x - - // Find the Bool - if( !in(1)->is_Bool() ) return NULL; - BoolNode *bol = in(1)->as_Bool(); - // Check bool sense - switch( bol->_test._test ) { - case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; - case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; - case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; - case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; - default: return NULL; break; - } - - // Find zero input of CmpD; the other input is being abs'd - Node *cmpd = bol->in(1); - if( cmpd->Opcode() != Op_CmpD ) return NULL; - Node *X = NULL; - bool flip = false; - if( phase->type(cmpd->in(cmp_zero_idx)) == TypeD::ZERO ) { - X = cmpd->in(3 - cmp_zero_idx); - } else if (phase->type(cmpd->in(3 - cmp_zero_idx)) == TypeD::ZERO) { - // The test is inverted, we should invert the result... - X = cmpd->in(cmp_zero_idx); - flip = true; - } else { - return NULL; - } - - // If X is found on the appropriate phi input, find the subtract on the other - if( X != in(phi_x_idx) ) return NULL; - int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; - Node *sub = in(phi_sub_idx); - - // Allow only SubD(0,X) and fail out for all others; NegD is not OK - if( sub->Opcode() != Op_SubD || - sub->in(2) != X || - phase->type(sub->in(1)) != TypeD::ZERO ) return NULL; - - Node *abs = new (phase->C) AbsDNode( X ); - if( flip ) - abs = new (phase->C) SubDNode(sub->in(1), phase->transform(abs)); - - return abs; -} - - -//============================================================================= -// If input is already higher or equal to cast type, then this is an identity. -Node *ConstraintCastNode::Identity( PhaseTransform *phase ) { - return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this; -} - -//------------------------------Value------------------------------------------ -// Take 'join' of input and cast-up type -const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const { - if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; - const Type* ft = phase->type(in(1))->filter_speculative(_type); - -#ifdef ASSERT - // Previous versions of this function had some special case logic, - // which is no longer necessary. Make sure of the required effects. - switch (Opcode()) { - case Op_CastII: - { - const Type* t1 = phase->type(in(1)); - if( t1 == Type::TOP ) assert(ft == Type::TOP, "special case #1"); - const Type* rt = t1->join_speculative(_type); - if (rt->empty()) assert(ft == Type::TOP, "special case #2"); - break; - } - case Op_CastPP: - if (phase->type(in(1)) == TypePtr::NULL_PTR && - _type->isa_ptr() && _type->is_ptr()->_ptr == TypePtr::NotNull) - assert(ft == Type::TOP, "special case #3"); - break; - } -#endif //ASSERT - - return ft; -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; -} - -//------------------------------Ideal_DU_postCCP------------------------------- -// Throw away cast after constant propagation -Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - const Type *t = ccp->type(in(1)); - ccp->hash_delete(this); - set_type(t); // Turn into ID function - ccp->hash_insert(this); - return this; -} - - -//============================================================================= - -//------------------------------Ideal_DU_postCCP------------------------------- -// If not converting int->oop, throw away cast after constant propagation -Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - const Type *t = ccp->type(in(1)); - if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) { - return NULL; // do not transform raw pointers or narrow oops - } - return ConstraintCastNode::Ideal_DU_postCCP(ccp); -} - - - -//============================================================================= -//------------------------------Identity--------------------------------------- -// If input is already higher or equal to cast type, then this is an identity. -Node *CheckCastPPNode::Identity( PhaseTransform *phase ) { - // Toned down to rescue meeting at a Phi 3 different oops all implementing - // the same interface. CompileTheWorld starting at 502, kd12rc1.zip. - return (phase->type(in(1)) == phase->type(this)) ? in(1) : this; -} - -//------------------------------Value------------------------------------------ -// Take 'join' of input and cast-up type, unless working with an Interface -const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const { - if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP; - - const Type *inn = phase->type(in(1)); - if( inn == Type::TOP ) return Type::TOP; // No information yet - - const TypePtr *in_type = inn->isa_ptr(); - const TypePtr *my_type = _type->isa_ptr(); - const Type *result = _type; - if( in_type != NULL && my_type != NULL ) { - TypePtr::PTR in_ptr = in_type->ptr(); - if( in_ptr == TypePtr::Null ) { - result = in_type; - } else if( in_ptr == TypePtr::Constant ) { - // Casting a constant oop to an interface? - // (i.e., a String to a Comparable?) - // Then return the interface. - const TypeOopPtr *jptr = my_type->isa_oopptr(); - assert( jptr, "" ); - result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type)) - ? my_type->cast_to_ptr_type( TypePtr::NotNull ) - : in_type; - } else { - result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) ); - } - } - - // This is the code from TypePtr::xmeet() that prevents us from - // having 2 ways to represent the same type. We have to replicate it - // here because we don't go through meet/join. - if (result->remove_speculative() == result->speculative()) { - result = result->remove_speculative(); - } - - // Same as above: because we don't go through meet/join, remove the - // speculative type if we know we won't use it. - return result->cleanup_speculative(); - - // JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES. - // FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR! - - // - // Remove this code after overnight run indicates no performance - // loss from not performing JOIN at CheckCastPPNode - // - // const TypeInstPtr *in_oop = in->isa_instptr(); - // const TypeInstPtr *my_oop = _type->isa_instptr(); - // // If either input is an 'interface', return destination type - // assert (in_oop == NULL || in_oop->klass() != NULL, ""); - // assert (my_oop == NULL || my_oop->klass() != NULL, ""); - // if( (in_oop && in_oop->klass()->is_interface()) - // ||(my_oop && my_oop->klass()->is_interface()) ) { - // TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR; - // // Preserve cast away nullness for interfaces - // if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) { - // return my_oop->cast_to_ptr_type(TypePtr::NotNull); - // } - // return _type; - // } - // - // // Neither the input nor the destination type is an interface, - // - // // history: JOIN used to cause weird corner case bugs - // // return (in == TypeOopPtr::NULL_PTR) ? in : _type; - // // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops. - // // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr - // const Type *join = in->join(_type); - // // Check if join preserved NotNull'ness for pointers - // if( join->isa_ptr() && _type->isa_ptr() ) { - // TypePtr::PTR join_ptr = join->is_ptr()->_ptr; - // TypePtr::PTR type_ptr = _type->is_ptr()->_ptr; - // // If there isn't any NotNull'ness to preserve - // // OR if join preserved NotNull'ness then return it - // if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null || - // join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) { - // return join; - // } - // // ELSE return same old type as before - // return _type; - // } - // // Not joining two pointers - // return join; -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape){ - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; -} - - -Node* DecodeNNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_EncodeP()) { - // (DecodeN (EncodeP p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *DecodeNNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - if (t == TypeNarrowOop::NULL_PTR) return TypePtr::NULL_PTR; - - assert(t->isa_narrowoop(), "only narrowoop here"); - return t->make_ptr(); -} - -Node* EncodePNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_DecodeN()) { - // (EncodeP (DecodeN p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *EncodePNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - if (t == TypePtr::NULL_PTR) return TypeNarrowOop::NULL_PTR; - - assert(t->isa_oop_ptr(), "only oopptr here"); - return t->make_narrowoop(); -} - - -Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { - return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); -} - -Node* DecodeNKlassNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_EncodePKlass()) { - // (DecodeNKlass (EncodePKlass p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *DecodeNKlassNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - assert(t != TypeNarrowKlass::NULL_PTR, "null klass?"); - - assert(t->isa_narrowklass(), "only narrow klass ptr here"); - return t->make_ptr(); -} - -Node* EncodePKlassNode::Identity(PhaseTransform* phase) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - - if (in(1)->is_DecodeNKlass()) { - // (EncodePKlass (DecodeNKlass p)) -> p - return in(1)->in(1); - } - return this; -} - -const Type *EncodePKlassNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if (t == Type::TOP) return Type::TOP; - assert (t != TypePtr::NULL_PTR, "null klass?"); - - assert(UseCompressedClassPointers && t->isa_klassptr(), "only klass ptr here"); - return t->make_narrowklass(); -} - - -//============================================================================= -//------------------------------Identity--------------------------------------- -Node *Conv2BNode::Identity( PhaseTransform *phase ) { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return in(1); - if( t == TypeInt::ZERO ) return in(1); - if( t == TypeInt::ONE ) return in(1); - if( t == TypeInt::BOOL ) return in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *Conv2BNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == TypeInt::ZERO ) return TypeInt::ZERO; - if( t == TypePtr::NULL_PTR ) return TypeInt::ZERO; - const TypePtr *tp = t->isa_ptr(); - if( tp != NULL ) { - if( tp->ptr() == TypePtr::AnyNull ) return Type::TOP; - if( tp->ptr() == TypePtr::Constant) return TypeInt::ONE; - if (tp->ptr() == TypePtr::NotNull) return TypeInt::ONE; - return TypeInt::BOOL; - } - if (t->base() != Type::Int) return TypeInt::BOOL; - const TypeInt *ti = t->is_int(); - if( ti->_hi < 0 || ti->_lo > 0 ) return TypeInt::ONE; - return TypeInt::BOOL; -} - - -// The conversions operations are all Alpha sorted. Please keep it that way! -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvD2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return Type::FLOAT; - const TypeD *td = t->is_double_constant(); - return TypeF::make( (float)td->getd() ); -} - -//------------------------------Identity--------------------------------------- -// Float's can be converted to doubles with no loss of bits. Hence -// converting a float to a double and back to a float is a NOP. -Node *ConvD2FNode::Identity(PhaseTransform *phase) { - return (in(1)->Opcode() == Op_ConvF2D) ? in(1)->in(1) : this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvD2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return TypeInt::INT; - const TypeD *td = t->is_double_constant(); - return TypeInt::make( SharedRuntime::d2i( td->getd() ) ); -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvD2INode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundDouble ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//------------------------------Identity--------------------------------------- -// Int's can be converted to doubles with no loss of bits. Hence -// converting an integer to a double and back to an integer is a NOP. -Node *ConvD2INode::Identity(PhaseTransform *phase) { - return (in(1)->Opcode() == Op_ConvI2D) ? in(1)->in(1) : this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvD2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return TypeLong::LONG; - const TypeD *td = t->is_double_constant(); - return TypeLong::make( SharedRuntime::d2l( td->getd() ) ); -} - -//------------------------------Identity--------------------------------------- -Node *ConvD2LNode::Identity(PhaseTransform *phase) { - // Remove ConvD2L->ConvL2D->ConvD2L sequences. - if( in(1) ->Opcode() == Op_ConvL2D && - in(1)->in(1)->Opcode() == Op_ConvD2L ) - return in(1)->in(1); - return this; -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvD2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundDouble ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvF2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return Type::DOUBLE; - const TypeF *tf = t->is_float_constant(); - return TypeD::make( (double)tf->getf() ); -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvF2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return TypeInt::INT; - const TypeF *tf = t->is_float_constant(); - return TypeInt::make( SharedRuntime::f2i( tf->getf() ) ); -} - -//------------------------------Identity--------------------------------------- -Node *ConvF2INode::Identity(PhaseTransform *phase) { - // Remove ConvF2I->ConvI2F->ConvF2I sequences. - if( in(1) ->Opcode() == Op_ConvI2F && - in(1)->in(1)->Opcode() == Op_ConvF2I ) - return in(1)->in(1); - return this; -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvF2INode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundFloat ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvF2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return TypeLong::LONG; - const TypeF *tf = t->is_float_constant(); - return TypeLong::make( SharedRuntime::f2l( tf->getf() ) ); -} - -//------------------------------Identity--------------------------------------- -Node *ConvF2LNode::Identity(PhaseTransform *phase) { - // Remove ConvF2L->ConvL2F->ConvF2L sequences. - if( in(1) ->Opcode() == Op_ConvL2F && - in(1)->in(1)->Opcode() == Op_ConvF2L ) - return in(1)->in(1); - return this; -} - -//------------------------------Ideal------------------------------------------ -// If converting to an int type, skip any rounding nodes -Node *ConvF2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if( in(1)->Opcode() == Op_RoundFloat ) - set_req(1,in(1)->in(1)); - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvI2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - if( ti->is_con() ) return TypeD::make( (double)ti->get_con() ); - return bottom_type(); -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvI2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - if( ti->is_con() ) return TypeF::make( (float)ti->get_con() ); - return bottom_type(); -} - -//------------------------------Identity--------------------------------------- -Node *ConvI2FNode::Identity(PhaseTransform *phase) { - // Remove ConvI2F->ConvF2I->ConvI2F sequences. - if( in(1) ->Opcode() == Op_ConvF2I && - in(1)->in(1)->Opcode() == Op_ConvI2F ) - return in(1)->in(1); - return this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvI2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - const Type* tl = TypeLong::make(ti->_lo, ti->_hi, ti->_widen); - // Join my declared type against my incoming type. - tl = tl->filter(_type); - return tl; -} - -#ifdef _LP64 -static inline bool long_ranges_overlap(jlong lo1, jlong hi1, - jlong lo2, jlong hi2) { - // Two ranges overlap iff one range's low point falls in the other range. - return (lo2 <= lo1 && lo1 <= hi2) || (lo1 <= lo2 && lo2 <= hi1); -} -#endif - -//------------------------------Ideal------------------------------------------ -Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { - const TypeLong* this_type = this->type()->is_long(); - Node* this_changed = NULL; - - // If _major_progress, then more loop optimizations follow. Do NOT - // remove this node's type assertion until no more loop ops can happen. - // The progress bit is set in the major loop optimizations THEN comes the - // call to IterGVN and any chance of hitting this code. Cf. Opaque1Node. - if (can_reshape && !phase->C->major_progress()) { - const TypeInt* in_type = phase->type(in(1))->isa_int(); - if (in_type != NULL && this_type != NULL && - (in_type->_lo != this_type->_lo || - in_type->_hi != this_type->_hi)) { - // Although this WORSENS the type, it increases GVN opportunities, - // because I2L nodes with the same input will common up, regardless - // of slightly differing type assertions. Such slight differences - // arise routinely as a result of loop unrolling, so this is a - // post-unrolling graph cleanup. Choose a type which depends only - // on my input. (Exception: Keep a range assertion of >=0 or <0.) - jlong lo1 = this_type->_lo; - jlong hi1 = this_type->_hi; - int w1 = this_type->_widen; - if (lo1 != (jint)lo1 || - hi1 != (jint)hi1 || - lo1 > hi1) { - // Overflow leads to wraparound, wraparound leads to range saturation. - lo1 = min_jint; hi1 = max_jint; - } else if (lo1 >= 0) { - // Keep a range assertion of >=0. - lo1 = 0; hi1 = max_jint; - } else if (hi1 < 0) { - // Keep a range assertion of <0. - lo1 = min_jint; hi1 = -1; - } else { - lo1 = min_jint; hi1 = max_jint; - } - const TypeLong* wtype = TypeLong::make(MAX2((jlong)in_type->_lo, lo1), - MIN2((jlong)in_type->_hi, hi1), - MAX2((int)in_type->_widen, w1)); - if (wtype != type()) { - set_type(wtype); - // Note: this_type still has old type value, for the logic below. - this_changed = this; - } - } - } - -#ifdef _LP64 - // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) , - // but only if x and y have subranges that cannot cause 32-bit overflow, - // under the assumption that x+y is in my own subrange this->type(). - - // This assumption is based on a constraint (i.e., type assertion) - // established in Parse::array_addressing or perhaps elsewhere. - // This constraint has been adjoined to the "natural" type of - // the incoming argument in(0). We know (because of runtime - // checks) - that the result value I2L(x+y) is in the joined range. - // Hence we can restrict the incoming terms (x, y) to values such - // that their sum also lands in that range. - - // This optimization is useful only on 64-bit systems, where we hope - // the addition will end up subsumed in an addressing mode. - // It is necessary to do this when optimizing an unrolled array - // copy loop such as x[i++] = y[i++]. - - // On 32-bit systems, it's better to perform as much 32-bit math as - // possible before the I2L conversion, because 32-bit math is cheaper. - // There's no common reason to "leak" a constant offset through the I2L. - // Addressing arithmetic will not absorb it as part of a 64-bit AddL. - - Node* z = in(1); - int op = z->Opcode(); - if (op == Op_AddI || op == Op_SubI) { - Node* x = z->in(1); - Node* y = z->in(2); - assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal"); - if (phase->type(x) == Type::TOP) return this_changed; - if (phase->type(y) == Type::TOP) return this_changed; - const TypeInt* tx = phase->type(x)->is_int(); - const TypeInt* ty = phase->type(y)->is_int(); - const TypeLong* tz = this_type; - jlong xlo = tx->_lo; - jlong xhi = tx->_hi; - jlong ylo = ty->_lo; - jlong yhi = ty->_hi; - jlong zlo = tz->_lo; - jlong zhi = tz->_hi; - jlong vbit = CONST64(1) << BitsPerInt; - int widen = MAX2(tx->_widen, ty->_widen); - if (op == Op_SubI) { - jlong ylo0 = ylo; - ylo = -yhi; - yhi = -ylo0; - } - // See if x+y can cause positive overflow into z+2**32 - if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo+vbit, zhi+vbit)) { - return this_changed; - } - // See if x+y can cause negative overflow into z-2**32 - if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo-vbit, zhi-vbit)) { - return this_changed; - } - // Now it's always safe to assume x+y does not overflow. - // This is true even if some pairs x,y might cause overflow, as long - // as that overflow value cannot fall into [zlo,zhi]. - - // Confident that the arithmetic is "as if infinite precision", - // we can now use z's range to put constraints on those of x and y. - // The "natural" range of x [xlo,xhi] can perhaps be narrowed to a - // more "restricted" range by intersecting [xlo,xhi] with the - // range obtained by subtracting y's range from the asserted range - // of the I2L conversion. Here's the interval arithmetic algebra: - // x == z-y == [zlo,zhi]-[ylo,yhi] == [zlo,zhi]+[-yhi,-ylo] - // => x in [zlo-yhi, zhi-ylo] - // => x in [zlo-yhi, zhi-ylo] INTERSECT [xlo,xhi] - // => x in [xlo MAX zlo-yhi, xhi MIN zhi-ylo] - jlong rxlo = MAX2(xlo, zlo - yhi); - jlong rxhi = MIN2(xhi, zhi - ylo); - // And similarly, x changing place with y: - jlong rylo = MAX2(ylo, zlo - xhi); - jlong ryhi = MIN2(yhi, zhi - xlo); - if (rxlo > rxhi || rylo > ryhi) { - return this_changed; // x or y is dying; don't mess w/ it - } - if (op == Op_SubI) { - jlong rylo0 = rylo; - rylo = -ryhi; - ryhi = -rylo0; - } - - Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) ); - Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) ); - switch (op) { - case Op_AddI: return new (phase->C) AddLNode(cx, cy); - case Op_SubI: return new (phase->C) SubLNode(cx, cy); - default: ShouldNotReachHere(); - } - } -#endif //_LP64 - - return this_changed; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvL2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if( tl->is_con() ) return TypeD::make( (double)tl->get_con() ); - return bottom_type(); -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *ConvL2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if( tl->is_con() ) return TypeF::make( (float)tl->get_con() ); - return bottom_type(); -} - -//============================================================================= -//----------------------------Identity----------------------------------------- -Node *ConvL2INode::Identity( PhaseTransform *phase ) { - // Convert L2I(I2L(x)) => x - if (in(1)->Opcode() == Op_ConvI2L) return in(1)->in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *ConvL2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if (tl->is_con()) - // Easy case. - return TypeInt::make((jint)tl->get_con()); - return bottom_type(); -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. -// Blow off prior masking to int -Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) { - Node *andl = in(1); - uint andl_op = andl->Opcode(); - if( andl_op == Op_AndL ) { - // Blow off prior masking to int - if( phase->type(andl->in(2)) == TypeLong::make( 0xFFFFFFFF ) ) { - set_req(1,andl->in(1)); - return this; - } - } - - // Swap with a prior add: convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) - // This replaces an 'AddL' with an 'AddI'. - if( andl_op == Op_AddL ) { - // Don't do this for nodes which have more than one user since - // we'll end up computing the long add anyway. - if (andl->outcnt() > 1) return NULL; - - Node* x = andl->in(1); - Node* y = andl->in(2); - assert( x != andl && y != andl, "dead loop in ConvL2INode::Ideal" ); - if (phase->type(x) == Type::TOP) return NULL; - if (phase->type(y) == Type::TOP) return NULL; - Node *add1 = phase->transform(new (phase->C) ConvL2INode(x)); - Node *add2 = phase->transform(new (phase->C) ConvL2INode(y)); - return new (phase->C) AddINode(add1,add2); - } - - // Disable optimization: LoadL->ConvL2I ==> LoadI. - // It causes problems (sizes of Load and Store nodes do not match) - // in objects initialization code and Escape Analysis. - return NULL; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *CastX2PNode::Value( PhaseTransform *phase ) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - if (t->base() == Type_X && t->singleton()) { - uintptr_t bits = (uintptr_t) t->is_intptr_t()->get_con(); - if (bits == 0) return TypePtr::NULL_PTR; - return TypeRawPtr::make((address) bits); - } - return CastX2PNode::bottom_type(); -} - -//------------------------------Idealize--------------------------------------- -static inline bool fits_in_int(const Type* t, bool but_not_min_int = false) { - if (t == Type::TOP) return false; - const TypeX* tl = t->is_intptr_t(); - jint lo = min_jint; - jint hi = max_jint; - if (but_not_min_int) ++lo; // caller wants to negate the value w/o overflow - return (tl->_lo >= lo) && (tl->_hi <= hi); -} - -static inline Node* addP_of_X2P(PhaseGVN *phase, - Node* base, - Node* dispX, - bool negate = false) { - if (negate) { - dispX = new (phase->C) SubXNode(phase->MakeConX(0), phase->transform(dispX)); - } - return new (phase->C) AddPNode(phase->C->top(), - phase->transform(new (phase->C) CastX2PNode(base)), - phase->transform(dispX)); -} - -Node *CastX2PNode::Ideal(PhaseGVN *phase, bool can_reshape) { - // convert CastX2P(AddX(x, y)) to AddP(CastX2P(x), y) if y fits in an int - int op = in(1)->Opcode(); - Node* x; - Node* y; - switch (op) { - case Op_SubX: - x = in(1)->in(1); - // Avoid ideal transformations ping-pong between this and AddP for raw pointers. - if (phase->find_intptr_t_con(x, -1) == 0) - break; - y = in(1)->in(2); - if (fits_in_int(phase->type(y), true)) { - return addP_of_X2P(phase, x, y, true); - } - break; - case Op_AddX: - x = in(1)->in(1); - y = in(1)->in(2); - if (fits_in_int(phase->type(y))) { - return addP_of_X2P(phase, x, y); - } - if (fits_in_int(phase->type(x))) { - return addP_of_X2P(phase, y, x); - } - break; - } - return NULL; -} - -//------------------------------Identity--------------------------------------- -Node *CastX2PNode::Identity( PhaseTransform *phase ) { - if (in(1)->Opcode() == Op_CastP2X) return in(1)->in(1); - return this; -} - -//============================================================================= -//------------------------------Value------------------------------------------ -const Type *CastP2XNode::Value( PhaseTransform *phase ) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - if (t->base() == Type::RawPtr && t->singleton()) { - uintptr_t bits = (uintptr_t) t->is_rawptr()->get_con(); - return TypeX::make(bits); - } - return CastP2XNode::bottom_type(); -} - -Node *CastP2XNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL; -} - -//------------------------------Identity--------------------------------------- -Node *CastP2XNode::Identity( PhaseTransform *phase ) { - if (in(1)->Opcode() == Op_CastX2P) return in(1)->in(1); - return this; -} - - -//============================================================================= -//------------------------------Identity--------------------------------------- -// Remove redundant roundings -Node *RoundFloatNode::Identity( PhaseTransform *phase ) { - assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); - // Do not round constants - if (phase->type(in(1))->base() == Type::FloatCon) return in(1); - int op = in(1)->Opcode(); - // Redundant rounding - if( op == Op_RoundFloat ) return in(1); - // Already rounded - if( op == Op_Parm ) return in(1); - if( op == Op_LoadF ) return in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *RoundFloatNode::Value( PhaseTransform *phase ) const { - return phase->type( in(1) ); -} - -//============================================================================= -//------------------------------Identity--------------------------------------- -// Remove redundant roundings. Incoming arguments are already rounded. -Node *RoundDoubleNode::Identity( PhaseTransform *phase ) { - assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); - // Do not round constants - if (phase->type(in(1))->base() == Type::DoubleCon) return in(1); - int op = in(1)->Opcode(); - // Redundant rounding - if( op == Op_RoundDouble ) return in(1); - // Already rounded - if( op == Op_Parm ) return in(1); - if( op == Op_LoadD ) return in(1); - if( op == Op_ConvF2D ) return in(1); - if( op == Op_ConvI2D ) return in(1); - return this; -} - -//------------------------------Value------------------------------------------ -const Type *RoundDoubleNode::Value( PhaseTransform *phase ) const { - return phase->type( in(1) ); -} - - -//============================================================================= -// Do not allow value-numbering -uint Opaque1Node::hash() const { return NO_HASH; } -uint Opaque1Node::cmp( const Node &n ) const { - return (&n == this); // Always fail except on self -} - -//------------------------------Identity--------------------------------------- -// If _major_progress, then more loop optimizations follow. Do NOT remove -// the opaque Node until no more loop ops can happen. Note the timing of -// _major_progress; it's set in the major loop optimizations THEN comes the -// call to IterGVN and any chance of hitting this code. Hence there's no -// phase-ordering problem with stripping Opaque1 in IGVN followed by some -// more loop optimizations that require it. -Node *Opaque1Node::Identity( PhaseTransform *phase ) { - return phase->C->major_progress() ? this : in(1); -} - -//============================================================================= -// A node to prevent unwanted optimizations. Allows constant folding. Stops -// value-numbering, most Ideal calls or Identity functions. This Node is -// specifically designed to prevent the pre-increment value of a loop trip -// counter from being live out of the bottom of the loop (hence causing the -// pre- and post-increment values both being live and thus requiring an extra -// temp register and an extra move). If we "accidentally" optimize through -// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus -// it's OK to be slightly sloppy on optimizations here. - -// Do not allow value-numbering -uint Opaque2Node::hash() const { return NO_HASH; } -uint Opaque2Node::cmp( const Node &n ) const { - return (&n == this); // Always fail except on self -} - - -//------------------------------Value------------------------------------------ -const Type *MoveL2DNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeLong *tl = t->is_long(); - if( !tl->is_con() ) return bottom_type(); - JavaValue v; - v.set_jlong(tl->get_con()); - return TypeD::make( v.get_jdouble() ); -} - -//------------------------------Value------------------------------------------ -const Type *MoveI2FNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - const TypeInt *ti = t->is_int(); - if( !ti->is_con() ) return bottom_type(); - JavaValue v; - v.set_jint(ti->get_con()); - return TypeF::make( v.get_jfloat() ); -} - -//------------------------------Value------------------------------------------ -const Type *MoveF2INode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::FLOAT ) return TypeInt::INT; - const TypeF *tf = t->is_float_constant(); - JavaValue v; - v.set_jfloat(tf->getf()); - return TypeInt::make( v.get_jint() ); -} - -//------------------------------Value------------------------------------------ -const Type *MoveD2LNode::Value( PhaseTransform *phase ) const { - const Type *t = phase->type( in(1) ); - if( t == Type::TOP ) return Type::TOP; - if( t == Type::DOUBLE ) return TypeLong::LONG; - const TypeD *td = t->is_double_constant(); - JavaValue v; - v.set_jdouble(td->getd()); - return TypeLong::make( v.get_jlong() ); -} - -//------------------------------Value------------------------------------------ -const Type* CountLeadingZerosINode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-6 - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 1; - unsigned int x = i; - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); - } - return TypeInt::INT; -} - -//------------------------------Value------------------------------------------ -const Type* CountLeadingZerosLNode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-6 - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 1; - unsigned int x = (((julong) l) >> 32); - if (x == 0) { n += 32; x = (int) l; } - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); - } - return TypeInt::INT; -} - -//------------------------------Value------------------------------------------ -const Type* CountTrailingZerosINode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-14 - int y; - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 31; - y = i << 16; if (y != 0) { n = n - 16; i = y; } - y = i << 8; if (y != 0) { n = n - 8; i = y; } - y = i << 4; if (y != 0) { n = n - 4; i = y; } - y = i << 2; if (y != 0) { n = n - 2; i = y; } - y = i << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); - } - return TypeInt::INT; -} - -//------------------------------Value------------------------------------------ -const Type* CountTrailingZerosLNode::Value(PhaseTransform* phase) const { - const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-14 - int x, y; - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 63; - y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32); - y = x << 16; if (y != 0) { n = n - 16; x = y; } - y = x << 8; if (y != 0) { n = n - 8; x = y; } - y = x << 4; if (y != 0) { n = n - 4; x = y; } - y = x << 2; if (y != 0) { n = n - 2; x = y; } - y = x << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); - } - return TypeInt::INT; -} diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp index 5f6b5a7c9b1..a25e4c128a0 100644 --- a/hotspot/src/share/vm/opto/connode.hpp +++ b/hotspot/src/share/vm/opto/connode.hpp @@ -139,630 +139,16 @@ public: }; -//------------------------------BinaryNode------------------------------------- -// Place holder for the 2 conditional inputs to a CMove. CMove needs 4 -// inputs: the Bool (for the lt/gt/eq/ne bits), the flags (result of some -// compare), and the 2 values to select between. The Matcher requires a -// binary tree so we break it down like this: -// (CMove (Binary bol cmp) (Binary src1 src2)) -class BinaryNode : public Node { -public: - BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { } - virtual int Opcode() const; - virtual uint ideal_reg() const { return 0; } -}; - -//------------------------------CMoveNode-------------------------------------- -// Conditional move -class CMoveNode : public TypeNode { -public: - enum { Control, // When is it safe to do this cmove? - Condition, // Condition controlling the cmove - IfFalse, // Value if condition is false - IfTrue }; // Value if condition is true - CMoveNode( Node *bol, Node *left, Node *right, const Type *t ) : TypeNode(t,4) - { - init_class_id(Class_CMove); - // all inputs are nullified in Node::Node(int) - // init_req(Control,NULL); - init_req(Condition,bol); - init_req(IfFalse,left); - init_req(IfTrue,right); - } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - static CMoveNode *make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ); - // Helper function to spot cmove graph shapes - static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ); -}; - -//------------------------------CMoveDNode------------------------------------- -class CMoveDNode : public CMoveNode { -public: - CMoveDNode( Node *bol, Node *left, Node *right, const Type* t) : CMoveNode(bol,left,right,t){} - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); -}; - -//------------------------------CMoveFNode------------------------------------- -class CMoveFNode : public CMoveNode { -public: - CMoveFNode( Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) {} - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); -}; - -//------------------------------CMoveINode------------------------------------- -class CMoveINode : public CMoveNode { -public: - CMoveINode( Node *bol, Node *left, Node *right, const TypeInt *ti ) : CMoveNode(bol,left,right,ti){} - virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); -}; - -//------------------------------CMoveLNode------------------------------------- -class CMoveLNode : public CMoveNode { -public: - CMoveLNode(Node *bol, Node *left, Node *right, const TypeLong *tl ) : CMoveNode(bol,left,right,tl){} - virtual int Opcode() const; -}; - -//------------------------------CMovePNode------------------------------------- -class CMovePNode : public CMoveNode { -public: - CMovePNode( Node *c, Node *bol, Node *left, Node *right, const TypePtr* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } - virtual int Opcode() const; -}; - -//------------------------------CMoveNNode------------------------------------- -class CMoveNNode : public CMoveNode { -public: - CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } - virtual int Opcode() const; -}; - -//------------------------------ConstraintCastNode----------------------------- -// cast to a different range -class ConstraintCastNode: public TypeNode { -public: - ConstraintCastNode (Node *n, const Type *t ): TypeNode(t,2) { - init_class_id(Class_ConstraintCast); - init_req(1, n); - } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual int Opcode() const; - virtual uint ideal_reg() const = 0; - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); -}; - -//------------------------------CastIINode------------------------------------- -// cast integer to integer (different range) -class CastIINode: public ConstraintCastNode { -public: - CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {} - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------CastPPNode------------------------------------- -// cast pointer to pointer (different type) -class CastPPNode: public ConstraintCastNode { -public: - CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {} - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegP; } - virtual Node *Ideal_DU_postCCP( PhaseCCP * ); -}; - -//------------------------------CheckCastPPNode-------------------------------- -// for _checkcast, cast pointer to pointer (different type), without JOIN, -class CheckCastPPNode: public TypeNode { -public: - CheckCastPPNode( Node *c, Node *n, const Type *t ) : TypeNode(t,2) { - init_class_id(Class_CheckCastPP); - init_req(0, c); - init_req(1, n); - } - - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegP; } - // No longer remove CheckCast after CCP as it gives me a place to hang - // the proper address type - which is required to compute anti-deps. - //virtual Node *Ideal_DU_postCCP( PhaseCCP * ); -}; - - -//------------------------------EncodeNarrowPtr-------------------------------- -class EncodeNarrowPtrNode : public TypeNode { - protected: - EncodeNarrowPtrNode(Node* value, const Type* type): - TypeNode(type, 2) { - init_class_id(Class_EncodeNarrowPtr); - init_req(0, NULL); - init_req(1, value); - } - public: - virtual uint ideal_reg() const { return Op_RegN; } - virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); -}; - -//------------------------------EncodeP-------------------------------- -// Encodes an oop pointers into its compressed form -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class EncodePNode : public EncodeNarrowPtrNode { - public: - EncodePNode(Node* value, const Type* type): - EncodeNarrowPtrNode(value, type) { - init_class_id(Class_EncodeP); - } - virtual int Opcode() const; - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - -//------------------------------EncodePKlass-------------------------------- -// Encodes a klass pointer into its compressed form -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class EncodePKlassNode : public EncodeNarrowPtrNode { - public: - EncodePKlassNode(Node* value, const Type* type): - EncodeNarrowPtrNode(value, type) { - init_class_id(Class_EncodePKlass); - } - virtual int Opcode() const; - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - -//------------------------------DecodeNarrowPtr-------------------------------- -class DecodeNarrowPtrNode : public TypeNode { - protected: - DecodeNarrowPtrNode(Node* value, const Type* type): - TypeNode(type, 2) { - init_class_id(Class_DecodeNarrowPtr); - init_req(0, NULL); - init_req(1, value); - } - public: - virtual uint ideal_reg() const { return Op_RegP; } -}; - -//------------------------------DecodeN-------------------------------- -// Converts a narrow oop into a real oop ptr. -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class DecodeNNode : public DecodeNarrowPtrNode { - public: - DecodeNNode(Node* value, const Type* type): - DecodeNarrowPtrNode(value, type) { - init_class_id(Class_DecodeN); - } - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); -}; - -//------------------------------DecodeNKlass-------------------------------- -// Converts a narrow klass pointer into a real klass ptr. -// Takes an extra argument which is the real heap base as a long which -// may be useful for code generation in the backend. -class DecodeNKlassNode : public DecodeNarrowPtrNode { - public: - DecodeNKlassNode(Node* value, const Type* type): - DecodeNarrowPtrNode(value, type) { - init_class_id(Class_DecodeNKlass); - } - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); -}; - -//------------------------------Conv2BNode------------------------------------- -// Convert int/pointer to a Boolean. Map zero to zero, all else to 1. -class Conv2BNode : public Node { -public: - Conv2BNode( Node *i ) : Node(0,i) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::BOOL; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegI; } -}; - -// The conversions operations are all Alpha sorted. Please keep it that way! -//------------------------------ConvD2FNode------------------------------------ -// Convert double to float -class ConvD2FNode : public Node { -public: - ConvD2FNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegF; } -}; - -//------------------------------ConvD2INode------------------------------------ -// Convert Double to Integer -class ConvD2INode : public Node { -public: - ConvD2INode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------ConvD2LNode------------------------------------ -// Convert Double to Long -class ConvD2LNode : public Node { -public: - ConvD2LNode( Node *dbl ) : Node(0,dbl) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegL; } -}; - -//------------------------------ConvF2DNode------------------------------------ -// Convert Float to a Double. -class ConvF2DNode : public Node { -public: - ConvF2DNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegD; } -}; - -//------------------------------ConvF2INode------------------------------------ -// Convert float to integer -class ConvF2INode : public Node { -public: - ConvF2INode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------ConvF2LNode------------------------------------ -// Convert float to long -class ConvF2LNode : public Node { -public: - ConvF2LNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegL; } -}; - -//------------------------------ConvI2DNode------------------------------------ -// Convert Integer to Double -class ConvI2DNode : public Node { -public: - ConvI2DNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegD; } -}; - -//------------------------------ConvI2FNode------------------------------------ -// Convert Integer to Float -class ConvI2FNode : public Node { -public: - ConvI2FNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegF; } -}; - -//------------------------------ConvI2LNode------------------------------------ -// Convert integer to long -class ConvI2LNode : public TypeNode { -public: - ConvI2LNode(Node *in1, const TypeLong* t = TypeLong::INT) - : TypeNode(t, 2) - { init_req(1, in1); } - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegL; } -}; - -//------------------------------ConvL2DNode------------------------------------ -// Convert Long to Double -class ConvL2DNode : public Node { -public: - ConvL2DNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegD; } -}; - -//------------------------------ConvL2FNode------------------------------------ -// Convert Long to Float -class ConvL2FNode : public Node { -public: - ConvL2FNode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual const Type *Value( PhaseTransform *phase ) const; - virtual uint ideal_reg() const { return Op_RegF; } -}; - -//------------------------------ConvL2INode------------------------------------ -// Convert long to integer -class ConvL2INode : public Node { -public: - ConvL2INode( Node *in1 ) : Node(0,in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//------------------------------CastX2PNode------------------------------------- -// convert a machine-pointer-sized integer to a raw pointer -class CastX2PNode : public Node { -public: - CastX2PNode( Node *n ) : Node(NULL, n) {} - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegP; } - virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } -}; - -//------------------------------CastP2XNode------------------------------------- -// Used in both 32-bit and 64-bit land. -// Used for card-marks and unsafe pointer math. -class CastP2XNode : public Node { -public: - CastP2XNode( Node *ctrl, Node *n ) : Node(ctrl, n) {} - virtual int Opcode() const; - virtual const Type *Value( PhaseTransform *phase ) const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual Node *Identity( PhaseTransform *phase ); - virtual uint ideal_reg() const { return Op_RegX; } - virtual const Type *bottom_type() const { return TypeX_X; } - // Return false to keep node from moving away from an associated card mark. - virtual bool depends_only_on_test() const { return false; } -}; - //------------------------------ThreadLocalNode-------------------------------- // Ideal Node which returns the base of ThreadLocalStorage. class ThreadLocalNode : public Node { public: - ThreadLocalNode( ) : Node((Node*)Compile::current()->root()) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM;} - virtual uint ideal_reg() const { return Op_RegP; } -}; - -//------------------------------LoadReturnPCNode------------------------------- -class LoadReturnPCNode: public Node { -public: - LoadReturnPCNode(Node *c) : Node(c) { } - virtual int Opcode() const; - virtual uint ideal_reg() const { return Op_RegP; } + ThreadLocalNode( ) : Node((Node*)Compile::current()->root()) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM;} + virtual uint ideal_reg() const { return Op_RegP; } }; -//-----------------------------RoundFloatNode---------------------------------- -class RoundFloatNode: public Node { -public: - RoundFloatNode(Node* c, Node *in1): Node(c, in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual uint ideal_reg() const { return Op_RegF; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - - -//-----------------------------RoundDoubleNode--------------------------------- -class RoundDoubleNode: public Node { -public: - RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual Node *Identity( PhaseTransform *phase ); - virtual const Type *Value( PhaseTransform *phase ) const; -}; - -//------------------------------Opaque1Node------------------------------------ -// A node to prevent unwanted optimizations. Allows constant folding. -// Stops value-numbering, Ideal calls or Identity functions. -class Opaque1Node : public Node { - virtual uint hash() const ; // { return NO_HASH; } - virtual uint cmp( const Node &n ) const; -public: - Opaque1Node( Compile* C, Node *n ) : Node(0,n) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); - C->add_macro_node(this); - } - // Special version for the pre-loop to hold the original loop limit - // which is consumed by range check elimination. - Opaque1Node( Compile* C, Node *n, Node* orig_limit ) : Node(0,n,orig_limit) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); - C->add_macro_node(this); - } - Node* original_loop_limit() { return req()==3 ? in(2) : NULL; } - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual Node *Identity( PhaseTransform *phase ); -}; - -//------------------------------Opaque2Node------------------------------------ -// A node to prevent unwanted optimizations. Allows constant folding. Stops -// value-numbering, most Ideal calls or Identity functions. This Node is -// specifically designed to prevent the pre-increment value of a loop trip -// counter from being live out of the bottom of the loop (hence causing the -// pre- and post-increment values both being live and thus requiring an extra -// temp register and an extra move). If we "accidentally" optimize through -// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus -// it's OK to be slightly sloppy on optimizations here. -class Opaque2Node : public Node { - virtual uint hash() const ; // { return NO_HASH; } - virtual uint cmp( const Node &n ) const; -public: - Opaque2Node( Compile* C, Node *n ) : Node(0,n) { - // Put it on the Macro nodes list to removed during macro nodes expansion. - init_flags(Flag_is_macro); - C->add_macro_node(this); - } - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } -}; - -//------------------------------Opaque3Node------------------------------------ -// A node to prevent unwanted optimizations. Will be optimized only during -// macro nodes expansion. -class Opaque3Node : public Opaque2Node { - int _opt; // what optimization it was used for -public: - enum { RTM_OPT }; - Opaque3Node(Compile* C, Node *n, int opt) : Opaque2Node(C, n), _opt(opt) {} - virtual int Opcode() const; - bool rtm_opt() const { return (_opt == RTM_OPT); } -}; - - -//----------------------PartialSubtypeCheckNode-------------------------------- -// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass -// array for an instance of the superklass. Set a hidden internal cache on a -// hit (cache is checked with exposed code in gen_subtype_check()). Return -// not zero for a miss or zero for a hit. -class PartialSubtypeCheckNode : public Node { -public: - PartialSubtypeCheckNode(Node* c, Node* sub, Node* super) : Node(c,sub,super) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } - virtual uint ideal_reg() const { return Op_RegP; } -}; - -// -class MoveI2FNode : public Node { - public: - MoveI2FNode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } - virtual uint ideal_reg() const { return Op_RegF; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -class MoveL2DNode : public Node { - public: - MoveL2DNode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -class MoveF2INode : public Node { - public: - MoveF2INode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } - virtual uint ideal_reg() const { return Op_RegI; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -class MoveD2LNode : public Node { - public: - MoveD2LNode( Node *value ) : Node(0,value) {} - virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } - virtual uint ideal_reg() const { return Op_RegL; } - virtual const Type* Value( PhaseTransform *phase ) const; -}; - -//---------- CountBitsNode ----------------------------------------------------- -class CountBitsNode : public Node { -public: - CountBitsNode(Node* in1) : Node(0, in1) {} - const Type* bottom_type() const { return TypeInt::INT; } - virtual uint ideal_reg() const { return Op_RegI; } -}; - -//---------- CountLeadingZerosINode -------------------------------------------- -// Count leading zeros (0-bit count starting from MSB) of an integer. -class CountLeadingZerosINode : public CountBitsNode { -public: - CountLeadingZerosINode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- CountLeadingZerosLNode -------------------------------------------- -// Count leading zeros (0-bit count starting from MSB) of a long. -class CountLeadingZerosLNode : public CountBitsNode { -public: - CountLeadingZerosLNode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- CountTrailingZerosINode ------------------------------------------- -// Count trailing zeros (0-bit count starting from LSB) of an integer. -class CountTrailingZerosINode : public CountBitsNode { -public: - CountTrailingZerosINode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- CountTrailingZerosLNode ------------------------------------------- -// Count trailing zeros (0-bit count starting from LSB) of a long. -class CountTrailingZerosLNode : public CountBitsNode { -public: - CountTrailingZerosLNode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; - virtual const Type* Value(PhaseTransform* phase) const; -}; - -//---------- PopCountINode ----------------------------------------------------- -// Population count (bit count) of an integer. -class PopCountINode : public CountBitsNode { -public: - PopCountINode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; -}; - -//---------- PopCountLNode ----------------------------------------------------- -// Population count (bit count) of a long. -class PopCountLNode : public CountBitsNode { -public: - PopCountLNode(Node* in1) : CountBitsNode(in1) {} - virtual int Opcode() const; -}; #endif // SHARE_VM_OPTO_CONNODE_HPP diff --git a/hotspot/src/share/vm/opto/convertnode.cpp b/hotspot/src/share/vm/opto/convertnode.cpp new file mode 100644 index 00000000000..bf09d3fbb90 --- /dev/null +++ b/hotspot/src/share/vm/opto/convertnode.cpp @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2014, 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 "opto/addnode.hpp" +#include "opto/convertnode.hpp" +#include "opto/matcher.hpp" +#include "opto/phaseX.hpp" +#include "opto/subnode.hpp" + +//============================================================================= +//------------------------------Identity--------------------------------------- +Node *Conv2BNode::Identity( PhaseTransform *phase ) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + if( t == TypeInt::ZERO ) return in(1); + if( t == TypeInt::ONE ) return in(1); + if( t == TypeInt::BOOL ) return in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *Conv2BNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == TypeInt::ZERO ) return TypeInt::ZERO; + if( t == TypePtr::NULL_PTR ) return TypeInt::ZERO; + const TypePtr *tp = t->isa_ptr(); + if( tp != NULL ) { + if( tp->ptr() == TypePtr::AnyNull ) return Type::TOP; + if( tp->ptr() == TypePtr::Constant) return TypeInt::ONE; + if (tp->ptr() == TypePtr::NotNull) return TypeInt::ONE; + return TypeInt::BOOL; + } + if (t->base() != Type::Int) return TypeInt::BOOL; + const TypeInt *ti = t->is_int(); + if( ti->_hi < 0 || ti->_lo > 0 ) return TypeInt::ONE; + return TypeInt::BOOL; +} + + +// The conversions operations are all Alpha sorted. Please keep it that way! +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvD2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return Type::FLOAT; + const TypeD *td = t->is_double_constant(); + return TypeF::make( (float)td->getd() ); +} + +//------------------------------Identity--------------------------------------- +// Float's can be converted to doubles with no loss of bits. Hence +// converting a float to a double and back to a float is a NOP. +Node *ConvD2FNode::Identity(PhaseTransform *phase) { + return (in(1)->Opcode() == Op_ConvF2D) ? in(1)->in(1) : this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvD2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return TypeInt::INT; + const TypeD *td = t->is_double_constant(); + return TypeInt::make( SharedRuntime::d2i( td->getd() ) ); +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvD2INode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundDouble ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//------------------------------Identity--------------------------------------- +// Int's can be converted to doubles with no loss of bits. Hence +// converting an integer to a double and back to an integer is a NOP. +Node *ConvD2INode::Identity(PhaseTransform *phase) { + return (in(1)->Opcode() == Op_ConvI2D) ? in(1)->in(1) : this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvD2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return TypeLong::LONG; + const TypeD *td = t->is_double_constant(); + return TypeLong::make( SharedRuntime::d2l( td->getd() ) ); +} + +//------------------------------Identity--------------------------------------- +Node *ConvD2LNode::Identity(PhaseTransform *phase) { + // Remove ConvD2L->ConvL2D->ConvD2L sequences. + if( in(1) ->Opcode() == Op_ConvL2D && + in(1)->in(1)->Opcode() == Op_ConvD2L ) + return in(1)->in(1); + return this; +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvD2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundDouble ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvF2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return Type::DOUBLE; + const TypeF *tf = t->is_float_constant(); + return TypeD::make( (double)tf->getf() ); +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvF2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return TypeInt::INT; + const TypeF *tf = t->is_float_constant(); + return TypeInt::make( SharedRuntime::f2i( tf->getf() ) ); +} + +//------------------------------Identity--------------------------------------- +Node *ConvF2INode::Identity(PhaseTransform *phase) { + // Remove ConvF2I->ConvI2F->ConvF2I sequences. + if( in(1) ->Opcode() == Op_ConvI2F && + in(1)->in(1)->Opcode() == Op_ConvF2I ) + return in(1)->in(1); + return this; +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvF2INode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundFloat ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvF2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return TypeLong::LONG; + const TypeF *tf = t->is_float_constant(); + return TypeLong::make( SharedRuntime::f2l( tf->getf() ) ); +} + +//------------------------------Identity--------------------------------------- +Node *ConvF2LNode::Identity(PhaseTransform *phase) { + // Remove ConvF2L->ConvL2F->ConvF2L sequences. + if( in(1) ->Opcode() == Op_ConvL2F && + in(1)->in(1)->Opcode() == Op_ConvF2L ) + return in(1)->in(1); + return this; +} + +//------------------------------Ideal------------------------------------------ +// If converting to an int type, skip any rounding nodes +Node *ConvF2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(1)->Opcode() == Op_RoundFloat ) + set_req(1,in(1)->in(1)); + return NULL; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvI2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + if( ti->is_con() ) return TypeD::make( (double)ti->get_con() ); + return bottom_type(); +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvI2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + if( ti->is_con() ) return TypeF::make( (float)ti->get_con() ); + return bottom_type(); +} + +//------------------------------Identity--------------------------------------- +Node *ConvI2FNode::Identity(PhaseTransform *phase) { + // Remove ConvI2F->ConvF2I->ConvI2F sequences. + if( in(1) ->Opcode() == Op_ConvF2I && + in(1)->in(1)->Opcode() == Op_ConvI2F ) + return in(1)->in(1); + return this; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvI2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + const Type* tl = TypeLong::make(ti->_lo, ti->_hi, ti->_widen); + // Join my declared type against my incoming type. + tl = tl->filter(_type); + return tl; +} + +#ifdef _LP64 +static inline bool long_ranges_overlap(jlong lo1, jlong hi1, + jlong lo2, jlong hi2) { + // Two ranges overlap iff one range's low point falls in the other range. + return (lo2 <= lo1 && lo1 <= hi2) || (lo1 <= lo2 && lo2 <= hi1); +} +#endif + +//------------------------------Ideal------------------------------------------ +Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + const TypeLong* this_type = this->type()->is_long(); + Node* this_changed = NULL; + + // If _major_progress, then more loop optimizations follow. Do NOT + // remove this node's type assertion until no more loop ops can happen. + // The progress bit is set in the major loop optimizations THEN comes the + // call to IterGVN and any chance of hitting this code. Cf. Opaque1Node. + if (can_reshape && !phase->C->major_progress()) { + const TypeInt* in_type = phase->type(in(1))->isa_int(); + if (in_type != NULL && this_type != NULL && + (in_type->_lo != this_type->_lo || + in_type->_hi != this_type->_hi)) { + // Although this WORSENS the type, it increases GVN opportunities, + // because I2L nodes with the same input will common up, regardless + // of slightly differing type assertions. Such slight differences + // arise routinely as a result of loop unrolling, so this is a + // post-unrolling graph cleanup. Choose a type which depends only + // on my input. (Exception: Keep a range assertion of >=0 or <0.) + jlong lo1 = this_type->_lo; + jlong hi1 = this_type->_hi; + int w1 = this_type->_widen; + if (lo1 != (jint)lo1 || + hi1 != (jint)hi1 || + lo1 > hi1) { + // Overflow leads to wraparound, wraparound leads to range saturation. + lo1 = min_jint; hi1 = max_jint; + } else if (lo1 >= 0) { + // Keep a range assertion of >=0. + lo1 = 0; hi1 = max_jint; + } else if (hi1 < 0) { + // Keep a range assertion of <0. + lo1 = min_jint; hi1 = -1; + } else { + lo1 = min_jint; hi1 = max_jint; + } + const TypeLong* wtype = TypeLong::make(MAX2((jlong)in_type->_lo, lo1), + MIN2((jlong)in_type->_hi, hi1), + MAX2((int)in_type->_widen, w1)); + if (wtype != type()) { + set_type(wtype); + // Note: this_type still has old type value, for the logic below. + this_changed = this; + } + } + } + +#ifdef _LP64 + // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) , + // but only if x and y have subranges that cannot cause 32-bit overflow, + // under the assumption that x+y is in my own subrange this->type(). + + // This assumption is based on a constraint (i.e., type assertion) + // established in Parse::array_addressing or perhaps elsewhere. + // This constraint has been adjoined to the "natural" type of + // the incoming argument in(0). We know (because of runtime + // checks) - that the result value I2L(x+y) is in the joined range. + // Hence we can restrict the incoming terms (x, y) to values such + // that their sum also lands in that range. + + // This optimization is useful only on 64-bit systems, where we hope + // the addition will end up subsumed in an addressing mode. + // It is necessary to do this when optimizing an unrolled array + // copy loop such as x[i++] = y[i++]. + + // On 32-bit systems, it's better to perform as much 32-bit math as + // possible before the I2L conversion, because 32-bit math is cheaper. + // There's no common reason to "leak" a constant offset through the I2L. + // Addressing arithmetic will not absorb it as part of a 64-bit AddL. + + Node* z = in(1); + int op = z->Opcode(); + if (op == Op_AddI || op == Op_SubI) { + Node* x = z->in(1); + Node* y = z->in(2); + assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal"); + if (phase->type(x) == Type::TOP) return this_changed; + if (phase->type(y) == Type::TOP) return this_changed; + const TypeInt* tx = phase->type(x)->is_int(); + const TypeInt* ty = phase->type(y)->is_int(); + const TypeLong* tz = this_type; + jlong xlo = tx->_lo; + jlong xhi = tx->_hi; + jlong ylo = ty->_lo; + jlong yhi = ty->_hi; + jlong zlo = tz->_lo; + jlong zhi = tz->_hi; + jlong vbit = CONST64(1) << BitsPerInt; + int widen = MAX2(tx->_widen, ty->_widen); + if (op == Op_SubI) { + jlong ylo0 = ylo; + ylo = -yhi; + yhi = -ylo0; + } + // See if x+y can cause positive overflow into z+2**32 + if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo+vbit, zhi+vbit)) { + return this_changed; + } + // See if x+y can cause negative overflow into z-2**32 + if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo-vbit, zhi-vbit)) { + return this_changed; + } + // Now it's always safe to assume x+y does not overflow. + // This is true even if some pairs x,y might cause overflow, as long + // as that overflow value cannot fall into [zlo,zhi]. + + // Confident that the arithmetic is "as if infinite precision", + // we can now use z's range to put constraints on those of x and y. + // The "natural" range of x [xlo,xhi] can perhaps be narrowed to a + // more "restricted" range by intersecting [xlo,xhi] with the + // range obtained by subtracting y's range from the asserted range + // of the I2L conversion. Here's the interval arithmetic algebra: + // x == z-y == [zlo,zhi]-[ylo,yhi] == [zlo,zhi]+[-yhi,-ylo] + // => x in [zlo-yhi, zhi-ylo] + // => x in [zlo-yhi, zhi-ylo] INTERSECT [xlo,xhi] + // => x in [xlo MAX zlo-yhi, xhi MIN zhi-ylo] + jlong rxlo = MAX2(xlo, zlo - yhi); + jlong rxhi = MIN2(xhi, zhi - ylo); + // And similarly, x changing place with y: + jlong rylo = MAX2(ylo, zlo - xhi); + jlong ryhi = MIN2(yhi, zhi - xlo); + if (rxlo > rxhi || rylo > ryhi) { + return this_changed; // x or y is dying; don't mess w/ it + } + if (op == Op_SubI) { + jlong rylo0 = rylo; + rylo = -ryhi; + ryhi = -rylo0; + } + + Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) ); + Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) ); + switch (op) { + case Op_AddI: return new (phase->C) AddLNode(cx, cy); + case Op_SubI: return new (phase->C) SubLNode(cx, cy); + default: ShouldNotReachHere(); + } + } +#endif //_LP64 + + return this_changed; +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvL2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if( tl->is_con() ) return TypeD::make( (double)tl->get_con() ); + return bottom_type(); +} + +//============================================================================= +//------------------------------Value------------------------------------------ +const Type *ConvL2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if( tl->is_con() ) return TypeF::make( (float)tl->get_con() ); + return bottom_type(); +} + +//============================================================================= +//----------------------------Identity----------------------------------------- +Node *ConvL2INode::Identity( PhaseTransform *phase ) { + // Convert L2I(I2L(x)) => x + if (in(1)->Opcode() == Op_ConvI2L) return in(1)->in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *ConvL2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if (tl->is_con()) + // Easy case. + return TypeInt::make((jint)tl->get_con()); + return bottom_type(); +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Blow off prior masking to int +Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node *andl = in(1); + uint andl_op = andl->Opcode(); + if( andl_op == Op_AndL ) { + // Blow off prior masking to int + if( phase->type(andl->in(2)) == TypeLong::make( 0xFFFFFFFF ) ) { + set_req(1,andl->in(1)); + return this; + } + } + + // Swap with a prior add: convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) + // This replaces an 'AddL' with an 'AddI'. + if( andl_op == Op_AddL ) { + // Don't do this for nodes which have more than one user since + // we'll end up computing the long add anyway. + if (andl->outcnt() > 1) return NULL; + + Node* x = andl->in(1); + Node* y = andl->in(2); + assert( x != andl && y != andl, "dead loop in ConvL2INode::Ideal" ); + if (phase->type(x) == Type::TOP) return NULL; + if (phase->type(y) == Type::TOP) return NULL; + Node *add1 = phase->transform(new (phase->C) ConvL2INode(x)); + Node *add2 = phase->transform(new (phase->C) ConvL2INode(y)); + return new (phase->C) AddINode(add1,add2); + } + + // Disable optimization: LoadL->ConvL2I ==> LoadI. + // It causes problems (sizes of Load and Store nodes do not match) + // in objects initialization code and Escape Analysis. + return NULL; +} + + + +//============================================================================= +//------------------------------Identity--------------------------------------- +// Remove redundant roundings +Node *RoundFloatNode::Identity( PhaseTransform *phase ) { + assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); + // Do not round constants + if (phase->type(in(1))->base() == Type::FloatCon) return in(1); + int op = in(1)->Opcode(); + // Redundant rounding + if( op == Op_RoundFloat ) return in(1); + // Already rounded + if( op == Op_Parm ) return in(1); + if( op == Op_LoadF ) return in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *RoundFloatNode::Value( PhaseTransform *phase ) const { + return phase->type( in(1) ); +} + +//============================================================================= +//------------------------------Identity--------------------------------------- +// Remove redundant roundings. Incoming arguments are already rounded. +Node *RoundDoubleNode::Identity( PhaseTransform *phase ) { + assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel"); + // Do not round constants + if (phase->type(in(1))->base() == Type::DoubleCon) return in(1); + int op = in(1)->Opcode(); + // Redundant rounding + if( op == Op_RoundDouble ) return in(1); + // Already rounded + if( op == Op_Parm ) return in(1); + if( op == Op_LoadD ) return in(1); + if( op == Op_ConvF2D ) return in(1); + if( op == Op_ConvI2D ) return in(1); + return this; +} + +//------------------------------Value------------------------------------------ +const Type *RoundDoubleNode::Value( PhaseTransform *phase ) const { + return phase->type( in(1) ); +} + + diff --git a/hotspot/src/share/vm/opto/convertnode.hpp b/hotspot/src/share/vm/opto/convertnode.hpp new file mode 100644 index 00000000000..ff19db51e55 --- /dev/null +++ b/hotspot/src/share/vm/opto/convertnode.hpp @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2014, 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_OPTO_CONVERTNODE_HPP +#define SHARE_VM_OPTO_CONVERTNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + + +//------------------------------Conv2BNode------------------------------------- +// Convert int/pointer to a Boolean. Map zero to zero, all else to 1. +class Conv2BNode : public Node { + public: + Conv2BNode( Node *i ) : Node(0,i) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::BOOL; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegI; } +}; + +// The conversions operations are all Alpha sorted. Please keep it that way! +//------------------------------ConvD2FNode------------------------------------ +// Convert double to float +class ConvD2FNode : public Node { + public: + ConvD2FNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegF; } +}; + +//------------------------------ConvD2INode------------------------------------ +// Convert Double to Integer +class ConvD2INode : public Node { + public: + ConvD2INode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------ConvD2LNode------------------------------------ +// Convert Double to Long +class ConvD2LNode : public Node { + public: + ConvD2LNode( Node *dbl ) : Node(0,dbl) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegL; } +}; + +//------------------------------ConvF2DNode------------------------------------ +// Convert Float to a Double. +class ConvF2DNode : public Node { + public: + ConvF2DNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegD; } +}; + +//------------------------------ConvF2INode------------------------------------ +// Convert float to integer +class ConvF2INode : public Node { + public: + ConvF2INode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//------------------------------ConvF2LNode------------------------------------ +// Convert float to long +class ConvF2LNode : public Node { + public: + ConvF2LNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegL; } +}; + +//------------------------------ConvI2DNode------------------------------------ +// Convert Integer to Double +class ConvI2DNode : public Node { + public: + ConvI2DNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegD; } +}; + +//------------------------------ConvI2FNode------------------------------------ +// Convert Integer to Float +class ConvI2FNode : public Node { + public: + ConvI2FNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + virtual uint ideal_reg() const { return Op_RegF; } +}; + +//------------------------------ConvI2LNode------------------------------------ +// Convert integer to long +class ConvI2LNode : public TypeNode { + public: + ConvI2LNode(Node *in1, const TypeLong* t = TypeLong::INT) + : TypeNode(t, 2) + { init_req(1, in1); } + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegL; } +}; + +//------------------------------ConvL2DNode------------------------------------ +// Convert Long to Double +class ConvL2DNode : public Node { + public: + ConvL2DNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegD; } +}; + +//------------------------------ConvL2FNode------------------------------------ +// Convert Long to Float +class ConvL2FNode : public Node { + public: + ConvL2FNode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type *Value( PhaseTransform *phase ) const; + virtual uint ideal_reg() const { return Op_RegF; } +}; + +//------------------------------ConvL2INode------------------------------------ +// Convert long to integer +class ConvL2INode : public Node { + public: + ConvL2INode( Node *in1 ) : Node(0,in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//-----------------------------RoundFloatNode---------------------------------- +class RoundFloatNode: public Node { + public: + RoundFloatNode(Node* c, Node *in1): Node(c, in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + + +//-----------------------------RoundDoubleNode--------------------------------- +class RoundDoubleNode: public Node { + public: + RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + + +#endif // SHARE_VM_OPTO_CONVERTNODE_HPP diff --git a/hotspot/src/share/vm/opto/countbitsnode.cpp b/hotspot/src/share/vm/opto/countbitsnode.cpp new file mode 100644 index 00000000000..152c7699ca7 --- /dev/null +++ b/hotspot/src/share/vm/opto/countbitsnode.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 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 "opto/countbitsnode.hpp" +#include "opto/opcodes.hpp" +#include "opto/phaseX.hpp" +#include "opto/type.hpp" + +//------------------------------Value------------------------------------------ +const Type* CountLeadingZerosINode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeInt* ti = t->isa_int(); + if (ti && ti->is_con()) { + jint i = ti->get_con(); + // HD, Figure 5-6 + if (i == 0) + return TypeInt::make(BitsPerInt); + int n = 1; + unsigned int x = i; + if (x >> 16 == 0) { n += 16; x <<= 16; } + if (x >> 24 == 0) { n += 8; x <<= 8; } + if (x >> 28 == 0) { n += 4; x <<= 4; } + if (x >> 30 == 0) { n += 2; x <<= 2; } + n -= x >> 31; + return TypeInt::make(n); + } + return TypeInt::INT; +} + +//------------------------------Value------------------------------------------ +const Type* CountLeadingZerosLNode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeLong* tl = t->isa_long(); + if (tl && tl->is_con()) { + jlong l = tl->get_con(); + // HD, Figure 5-6 + if (l == 0) + return TypeInt::make(BitsPerLong); + int n = 1; + unsigned int x = (((julong) l) >> 32); + if (x == 0) { n += 32; x = (int) l; } + if (x >> 16 == 0) { n += 16; x <<= 16; } + if (x >> 24 == 0) { n += 8; x <<= 8; } + if (x >> 28 == 0) { n += 4; x <<= 4; } + if (x >> 30 == 0) { n += 2; x <<= 2; } + n -= x >> 31; + return TypeInt::make(n); + } + return TypeInt::INT; +} + +//------------------------------Value------------------------------------------ +const Type* CountTrailingZerosINode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeInt* ti = t->isa_int(); + if (ti && ti->is_con()) { + jint i = ti->get_con(); + // HD, Figure 5-14 + int y; + if (i == 0) + return TypeInt::make(BitsPerInt); + int n = 31; + y = i << 16; if (y != 0) { n = n - 16; i = y; } + y = i << 8; if (y != 0) { n = n - 8; i = y; } + y = i << 4; if (y != 0) { n = n - 4; i = y; } + y = i << 2; if (y != 0) { n = n - 2; i = y; } + y = i << 1; if (y != 0) { n = n - 1; } + return TypeInt::make(n); + } + return TypeInt::INT; +} + +//------------------------------Value------------------------------------------ +const Type* CountTrailingZerosLNode::Value(PhaseTransform* phase) const { + const Type* t = phase->type(in(1)); + if (t == Type::TOP) return Type::TOP; + const TypeLong* tl = t->isa_long(); + if (tl && tl->is_con()) { + jlong l = tl->get_con(); + // HD, Figure 5-14 + int x, y; + if (l == 0) + return TypeInt::make(BitsPerLong); + int n = 63; + y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32); + y = x << 16; if (y != 0) { n = n - 16; x = y; } + y = x << 8; if (y != 0) { n = n - 8; x = y; } + y = x << 4; if (y != 0) { n = n - 4; x = y; } + y = x << 2; if (y != 0) { n = n - 2; x = y; } + y = x << 1; if (y != 0) { n = n - 1; } + return TypeInt::make(n); + } + return TypeInt::INT; +} diff --git a/hotspot/src/share/vm/opto/countbitsnode.hpp b/hotspot/src/share/vm/opto/countbitsnode.hpp new file mode 100644 index 00000000000..0ead252ee89 --- /dev/null +++ b/hotspot/src/share/vm/opto/countbitsnode.hpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, 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_OPTO_COUNTBITSNODE_HPP +#define SHARE_VM_OPTO_COUNTBITSNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + +class PhaseTransform; + +//---------- CountBitsNode ----------------------------------------------------- +class CountBitsNode : public Node { + public: + CountBitsNode(Node* in1) : Node(0, in1) {} + const Type* bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } +}; + +//---------- CountLeadingZerosINode -------------------------------------------- +// Count leading zeros (0-bit count starting from MSB) of an integer. +class CountLeadingZerosINode : public CountBitsNode { + public: + CountLeadingZerosINode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- CountLeadingZerosLNode -------------------------------------------- +// Count leading zeros (0-bit count starting from MSB) of a long. +class CountLeadingZerosLNode : public CountBitsNode { + public: + CountLeadingZerosLNode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- CountTrailingZerosINode ------------------------------------------- +// Count trailing zeros (0-bit count starting from LSB) of an integer. +class CountTrailingZerosINode : public CountBitsNode { + public: + CountTrailingZerosINode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- CountTrailingZerosLNode ------------------------------------------- +// Count trailing zeros (0-bit count starting from LSB) of a long. +class CountTrailingZerosLNode : public CountBitsNode { + public: + CountTrailingZerosLNode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; + virtual const Type* Value(PhaseTransform* phase) const; +}; + +//---------- PopCountINode ----------------------------------------------------- +// Population count (bit count) of an integer. +class PopCountINode : public CountBitsNode { + public: + PopCountINode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; +}; + +//---------- PopCountLNode ----------------------------------------------------- +// Population count (bit count) of a long. +class PopCountLNode : public CountBitsNode { + public: + PopCountLNode(Node* in1) : CountBitsNode(in1) {} + virtual int Opcode() const; +}; + + +#endif // SHARE_VM_OPTO_COUNTBITSNODE_HPP diff --git a/hotspot/src/share/vm/opto/divnode.cpp b/hotspot/src/share/vm/opto/divnode.cpp index 24f4fcb7e9e..f577c8b5125 100644 --- a/hotspot/src/share/vm/opto/divnode.cpp +++ b/hotspot/src/share/vm/opto/divnode.cpp @@ -26,8 +26,10 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/machnode.hpp" +#include "opto/movenode.hpp" #include "opto/matcher.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index 2816f2d0a94..4eb462d9c5e 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -31,6 +31,7 @@ #include "interpreter/linkResolver.hpp" #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 028aa2467f2..286216ca7b5 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -33,6 +33,7 @@ #include "opto/compile.hpp" #include "opto/escape.hpp" #include "opto/phaseX.hpp" +#include "opto/movenode.hpp" #include "opto/rootnode.hpp" ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : diff --git a/hotspot/src/share/vm/opto/generateOptoStub.cpp b/hotspot/src/share/vm/opto/generateOptoStub.cpp index ff501f2bee4..f75110842b9 100644 --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp @@ -27,7 +27,7 @@ #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" #include "opto/compile.hpp" -#include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/locknode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 838e9758da7..3a171e9e7a2 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -30,10 +30,14 @@ #include "memory/barrierSet.hpp" #include "memory/cardTableModRefBS.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" +#include "opto/convertnode.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" diff --git a/hotspot/src/share/vm/opto/idealKit.hpp b/hotspot/src/share/vm/opto/idealKit.hpp index 7581570557d..f20d6bfee57 100644 --- a/hotspot/src/share/vm/opto/idealKit.hpp +++ b/hotspot/src/share/vm/opto/idealKit.hpp @@ -27,6 +27,7 @@ #include "opto/addnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/castnode.hpp" #include "opto/connode.hpp" #include "opto/divnode.hpp" #include "opto/graphKit.hpp" diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index b84ea45abb7..825a7a25533 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -31,7 +31,6 @@ #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" #include "opto/coalesce.hpp" -#include "opto/connode.hpp" #include "opto/indexSet.hpp" #include "opto/machnode.hpp" #include "opto/memnode.hpp" diff --git a/hotspot/src/share/vm/opto/intrinsicnode.cpp b/hotspot/src/share/vm/opto/intrinsicnode.cpp new file mode 100644 index 00000000000..683cad55fed --- /dev/null +++ b/hotspot/src/share/vm/opto/intrinsicnode.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, 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 "opto/intrinsicnode.hpp" +#include "opto/memnode.hpp" +#include "opto/phaseX.hpp" + +//============================================================================= +// Do not match memory edge. +uint StrIntrinsicNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if (remove_dead_region(phase, can_reshape)) return this; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; + + if (can_reshape) { + Node* mem = phase->transform(in(MemNode::Memory)); + // If transformed to a MergeMem, get the desired slice + uint alias_idx = phase->C->get_alias_index(adr_type()); + mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem; + if (mem != in(MemNode::Memory)) { + set_req(MemNode::Memory, mem); + return this; + } + } + return NULL; +} + +//------------------------------Value------------------------------------------ +const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const { + if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; + return bottom_type(); +} + +//============================================================================= +//------------------------------match_edge------------------------------------- +// Do not match memory edge +uint EncodeISOArrayNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len) +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { + return remove_dead_region(phase, can_reshape) ? this : NULL; +} + +//------------------------------Value------------------------------------------ +const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const { + if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; + return bottom_type(); +} + diff --git a/hotspot/src/share/vm/opto/intrinsicnode.hpp b/hotspot/src/share/vm/opto/intrinsicnode.hpp new file mode 100644 index 00000000000..2f19db6474b --- /dev/null +++ b/hotspot/src/share/vm/opto/intrinsicnode.hpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2014, 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_OPTO_INTRINSICNODE_HPP +#define SHARE_VM_OPTO_INTRINSICNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + + +//----------------------PartialSubtypeCheckNode-------------------------------- +// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass +// array for an instance of the superklass. Set a hidden internal cache on a +// hit (cache is checked with exposed code in gen_subtype_check()). Return +// not zero for a miss or zero for a hit. +class PartialSubtypeCheckNode : public Node { + public: + PartialSubtypeCheckNode(Node* c, Node* sub, Node* super) : Node(c,sub,super) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } + virtual uint ideal_reg() const { return Op_RegP; } +}; + +//------------------------------StrIntrinsic------------------------------- +// Base class for Ideal nodes used in String instrinsic code. +class StrIntrinsicNode: public Node { + public: + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + Node(control, char_array_mem, s1, c1, s2, c2) { + } + + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2, Node* c): + Node(control, char_array_mem, s1, s2, c) { + } + + StrIntrinsicNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2): + Node(control, char_array_mem, s1, s2) { + } + + virtual bool depends_only_on_test() const { return false; } + virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value(PhaseTransform *phase) const; +}; + +//------------------------------StrComp------------------------------------- +class StrCompNode: public StrIntrinsicNode { + public: + StrCompNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } +}; + +//------------------------------StrEquals------------------------------------- +class StrEqualsNode: public StrIntrinsicNode { + public: + StrEqualsNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2, Node* c): + StrIntrinsicNode(control, char_array_mem, s1, s2, c) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } +}; + +//------------------------------StrIndexOf------------------------------------- +class StrIndexOfNode: public StrIntrinsicNode { + public: + StrIndexOfNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, Node* s2, Node* c2): + StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::INT; } +}; + +//------------------------------AryEq--------------------------------------- +class AryEqNode: public StrIntrinsicNode { + public: + AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2): + StrIntrinsicNode(control, char_array_mem, s1, s2) {}; + virtual int Opcode() const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } +}; + + +//------------------------------EncodeISOArray-------------------------------- +// encode char[] to byte[] in ISO_8859_1 +class EncodeISOArrayNode: public Node { + public: + EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {}; + virtual int Opcode() const; + virtual bool depends_only_on_test() const { return false; } + virtual const Type* bottom_type() const { return TypeInt::INT; } + virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual uint match_edge(uint idx) const; + virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value(PhaseTransform *phase) const; +}; + +#endif // SHARE_VM_OPTO_INTRINSICNODE_HPP diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index af27b0a9899..f2bbfa97caf 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -30,10 +30,16 @@ #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/callGenerator.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/convertnode.hpp" +#include "opto/countbitsnode.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/idealKit.hpp" #include "opto/mathexactnode.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp index 2fbfba0f48c..0e86e403473 100644 --- a/hotspot/src/share/vm/opto/loopPredicate.cpp +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp @@ -27,8 +27,10 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/mulnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index fcf623ca7ac..040345b66eb 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -28,9 +28,12 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/loopnode.hpp" #include "opto/mulnode.hpp" +#include "opto/movenode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index 047c00e8021..06e17664efe 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -25,7 +25,9 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" //================= Loop Unswitching ===================== diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 719a1fb34f1..401d40e7177 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -30,6 +30,7 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/loopnode.hpp" diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index f9a87bbac57..661a9bc6cfa 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -30,6 +30,8 @@ #include "opto/loopnode.hpp" #include "opto/matcher.hpp" #include "opto/mulnode.hpp" +#include "opto/movenode.hpp" +#include "opto/opaquenode.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 6e18c773e36..afaa4e858d4 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -27,14 +27,17 @@ #include "libadt/vectset.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/compile.hpp" -#include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/macro.hpp" #include "opto/memnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/node.hpp" +#include "opto/opaquenode.hpp" #include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index f263a3c5044..0e650639d0c 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -26,10 +26,10 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" -#include "opto/connode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" +#include "opto/movenode.hpp" #include "opto/opcodes.hpp" #include "opto/regmask.hpp" #include "opto/rootnode.hpp" diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 3a6d4998b06..6ffd0186d01 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -31,11 +31,13 @@ #include "opto/cfgnode.hpp" #include "opto/compile.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" +#include "opto/narrowptrnode.hpp" #include "opto/phaseX.hpp" #include "opto/regmask.hpp" @@ -2903,59 +2905,6 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, return mem; } -//============================================================================= -// Do not match memory edge. -uint StrIntrinsicNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (remove_dead_region(phase, can_reshape)) return this; - // Don't bother trying to transform a dead node - if (in(0) && in(0)->is_top()) return NULL; - - if (can_reshape) { - Node* mem = phase->transform(in(MemNode::Memory)); - // If transformed to a MergeMem, get the desired slice - uint alias_idx = phase->C->get_alias_index(adr_type()); - mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem; - if (mem != in(MemNode::Memory)) { - set_req(MemNode::Memory, mem); - return this; - } - } - return NULL; -} - -//------------------------------Value------------------------------------------ -const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const { - if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; - return bottom_type(); -} - -//============================================================================= -//------------------------------match_edge------------------------------------- -// Do not match memory edge -uint EncodeISOArrayNode::match_edge(uint idx) const { - return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len) -} - -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { - return remove_dead_region(phase, can_reshape) ? this : NULL; -} - -//------------------------------Value------------------------------------------ -const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const { - if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; - return bottom_type(); -} - //============================================================================= MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) : MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)), diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 9be4b6e9c4b..6808875fdc1 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -866,88 +866,6 @@ public: static bool step_through(Node** np, uint instance_id, PhaseTransform* phase); }; -//------------------------------StrIntrinsic------------------------------- -// Base class for Ideal nodes used in String instrinsic code. -class StrIntrinsicNode: public Node { -public: - StrIntrinsicNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, Node* s2, Node* c2): - Node(control, char_array_mem, s1, c1, s2, c2) { - } - - StrIntrinsicNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2, Node* c): - Node(control, char_array_mem, s1, s2, c) { - } - - StrIntrinsicNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2): - Node(control, char_array_mem, s1, s2) { - } - - virtual bool depends_only_on_test() const { return false; } - virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type *Value(PhaseTransform *phase) const; -}; - -//------------------------------StrComp------------------------------------- -class StrCompNode: public StrIntrinsicNode { -public: - StrCompNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, Node* s2, Node* c2): - StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } -}; - -//------------------------------StrEquals------------------------------------- -class StrEqualsNode: public StrIntrinsicNode { -public: - StrEqualsNode(Node* control, Node* char_array_mem, - Node* s1, Node* s2, Node* c): - StrIntrinsicNode(control, char_array_mem, s1, s2, c) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } -}; - -//------------------------------StrIndexOf------------------------------------- -class StrIndexOfNode: public StrIntrinsicNode { -public: - StrIndexOfNode(Node* control, Node* char_array_mem, - Node* s1, Node* c1, Node* s2, Node* c2): - StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::INT; } -}; - -//------------------------------AryEq--------------------------------------- -class AryEqNode: public StrIntrinsicNode { -public: - AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2): - StrIntrinsicNode(control, char_array_mem, s1, s2) {}; - virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } -}; - - -//------------------------------EncodeISOArray-------------------------------- -// encode char[] to byte[] in ISO_8859_1 -class EncodeISOArrayNode: public Node { -public: - EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {}; - virtual int Opcode() const; - virtual bool depends_only_on_test() const { return false; } - virtual const Type* bottom_type() const { return TypeInt::INT; } - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } - virtual uint match_edge(uint idx) const; - virtual uint ideal_reg() const { return Op_RegI; } - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); - virtual const Type *Value(PhaseTransform *phase) const; -}; - //------------------------------MemBar----------------------------------------- // There are different flavors of Memory Barriers to match the Java Memory // Model. Monitor-enter and volatile-load act as Aquires: no following ref diff --git a/hotspot/src/share/vm/opto/movenode.cpp b/hotspot/src/share/vm/opto/movenode.cpp new file mode 100644 index 00000000000..bf2a83712c1 --- /dev/null +++ b/hotspot/src/share/vm/opto/movenode.cpp @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2014, 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 "opto/addnode.hpp" +#include "opto/connode.hpp" +#include "opto/convertnode.hpp" +#include "opto/movenode.hpp" +#include "opto/phaseX.hpp" +#include "opto/subnode.hpp" + +//============================================================================= +/* + The major change is for CMoveP and StrComp. They have related but slightly + different problems. They both take in TWO oops which are both null-checked + independently before the using Node. After CCP removes the CastPP's they need + to pick up the guarding test edge - in this case TWO control edges. I tried + various solutions, all have problems: + + (1) Do nothing. This leads to a bug where we hoist a Load from a CMoveP or a + StrComp above a guarding null check. I've seen both cases in normal -Xcomp + testing. + + (2) Plug the control edge from 1 of the 2 oops in. Apparent problem here is + to figure out which test post-dominates. The real problem is that it doesn't + matter which one you pick. After you pick up, the dominating-test elider in + IGVN can remove the test and allow you to hoist up to the dominating test on + the chosen oop bypassing the test on the not-chosen oop. Seen in testing. + Oops. + + (3) Leave the CastPP's in. This makes the graph more accurate in some sense; + we get to keep around the knowledge that an oop is not-null after some test. + Alas, the CastPP's interfere with GVN (some values are the regular oop, some + are the CastPP of the oop, all merge at Phi's which cannot collapse, etc). + This cost us 10% on SpecJVM, even when I removed some of the more trivial + cases in the optimizer. Removing more useless Phi's started allowing Loads to + illegally float above null checks. I gave up on this approach. + + (4) Add BOTH control edges to both tests. Alas, too much code knows that + control edges are in slot-zero ONLY. Many quick asserts fail; no way to do + this one. Note that I really want to allow the CMoveP to float and add both + control edges to the dependent Load op - meaning I can select early but I + cannot Load until I pass both tests. + + (5) Do not hoist CMoveP and StrComp. To this end I added the v-call + depends_only_on_test(). No obvious performance loss on Spec, but we are + clearly conservative on CMoveP (also so on StrComp but that's unlikely to + matter ever). + + */ + + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Move constants to the right. +Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if( in(0) && remove_dead_region(phase, can_reshape) ) return this; + // Don't bother trying to transform a dead node + if( in(0) && in(0)->is_top() ) return NULL; + assert( !phase->eqv(in(Condition), this) && + !phase->eqv(in(IfFalse), this) && + !phase->eqv(in(IfTrue), this), "dead loop in CMoveNode::Ideal" ); + if( phase->type(in(Condition)) == Type::TOP ) + return NULL; // return NULL when Condition is dead + + if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) { + if( in(Condition)->is_Bool() ) { + BoolNode* b = in(Condition)->as_Bool(); + BoolNode* b2 = b->negate(phase); + return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type ); + } + } + return NULL; +} + +//------------------------------is_cmove_id------------------------------------ +// Helper function to check for CMOVE identity. Shared with PhiNode::Identity +Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ) { + // Check for Cmp'ing and CMove'ing same values + if( (phase->eqv(cmp->in(1),f) && + phase->eqv(cmp->in(2),t)) || + // Swapped Cmp is OK + (phase->eqv(cmp->in(2),f) && + phase->eqv(cmp->in(1),t)) ) { + // Give up this identity check for floating points because it may choose incorrect + // value around 0.0 and -0.0 + if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD ) + return NULL; + // Check for "(t==f)?t:f;" and replace with "f" + if( b->_test._test == BoolTest::eq ) + return f; + // Allow the inverted case as well + // Check for "(t!=f)?t:f;" and replace with "t" + if( b->_test._test == BoolTest::ne ) + return t; + } + return NULL; +} + +//------------------------------Identity--------------------------------------- +// Conditional-move is an identity if both inputs are the same, or the test +// true or false. +Node *CMoveNode::Identity( PhaseTransform *phase ) { + if( phase->eqv(in(IfFalse),in(IfTrue)) ) // C-moving identical inputs? + return in(IfFalse); // Then it doesn't matter + if( phase->type(in(Condition)) == TypeInt::ZERO ) + return in(IfFalse); // Always pick left(false) input + if( phase->type(in(Condition)) == TypeInt::ONE ) + return in(IfTrue); // Always pick right(true) input + + // Check for CMove'ing a constant after comparing against the constant. + // Happens all the time now, since if we compare equality vs a constant in + // the parser, we "know" the variable is constant on one path and we force + // it. Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a + // conditional move: "x = (x==0)?0:x;". Yucko. This fix is slightly more + // general in that we don't need constants. + if( in(Condition)->is_Bool() ) { + BoolNode *b = in(Condition)->as_Bool(); + Node *cmp = b->in(1); + if( cmp->is_Cmp() ) { + Node *id = is_cmove_id( phase, cmp, in(IfTrue), in(IfFalse), b ); + if( id ) return id; + } + } + + return this; +} + +//------------------------------Value------------------------------------------ +// Result is the meet of inputs +const Type *CMoveNode::Value( PhaseTransform *phase ) const { + if( phase->type(in(Condition)) == Type::TOP ) + return Type::TOP; + return phase->type(in(IfFalse))->meet_speculative(phase->type(in(IfTrue))); +} + +//------------------------------make------------------------------------------- +// Make a correctly-flavored CMove. Since _type is directly determined +// from the inputs we do not need to specify it here. +CMoveNode *CMoveNode::make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ) { + switch( t->basic_type() ) { + case T_INT: return new (C) CMoveINode( bol, left, right, t->is_int() ); + case T_FLOAT: return new (C) CMoveFNode( bol, left, right, t ); + case T_DOUBLE: return new (C) CMoveDNode( bol, left, right, t ); + case T_LONG: return new (C) CMoveLNode( bol, left, right, t->is_long() ); + case T_OBJECT: return new (C) CMovePNode( c, bol, left, right, t->is_oopptr() ); + case T_ADDRESS: return new (C) CMovePNode( c, bol, left, right, t->is_ptr() ); + case T_NARROWOOP: return new (C) CMoveNNode( c, bol, left, right, t ); + default: + ShouldNotReachHere(); + return NULL; + } +} + +//============================================================================= +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Check for conversions to boolean +Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) { + // Try generic ideal's first + Node *x = CMoveNode::Ideal(phase, can_reshape); + if( x ) return x; + + // If zero is on the left (false-case, no-move-case) it must mean another + // constant is on the right (otherwise the shared CMove::Ideal code would + // have moved the constant to the right). This situation is bad for Intel + // and a don't-care for Sparc. It's bad for Intel because the zero has to + // be manifested in a register with a XOR which kills flags, which are live + // on input to the CMoveI, leading to a situation which causes excessive + // spilling on Intel. For Sparc, if the zero in on the left the Sparc will + // zero a register via G0 and conditionally-move the other constant. If the + // zero is on the right, the Sparc will load the first constant with a + // 13-bit set-lo and conditionally move G0. See bug 4677505. + if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) { + if( in(Condition)->is_Bool() ) { + BoolNode* b = in(Condition)->as_Bool(); + BoolNode* b2 = b->negate(phase); + return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type ); + } + } + + // Now check for booleans + int flip = 0; + + // Check for picking from zero/one + if( phase->type(in(IfFalse)) == TypeInt::ZERO && phase->type(in(IfTrue)) == TypeInt::ONE ) { + flip = 1 - flip; + } else if( phase->type(in(IfFalse)) == TypeInt::ONE && phase->type(in(IfTrue)) == TypeInt::ZERO ) { + } else return NULL; + + // Check for eq/ne test + if( !in(1)->is_Bool() ) return NULL; + BoolNode *bol = in(1)->as_Bool(); + if( bol->_test._test == BoolTest::eq ) { + } else if( bol->_test._test == BoolTest::ne ) { + flip = 1-flip; + } else return NULL; + + // Check for vs 0 or 1 + if( !bol->in(1)->is_Cmp() ) return NULL; + const CmpNode *cmp = bol->in(1)->as_Cmp(); + if( phase->type(cmp->in(2)) == TypeInt::ZERO ) { + } else if( phase->type(cmp->in(2)) == TypeInt::ONE ) { + // Allow cmp-vs-1 if the other input is bounded by 0-1 + if( phase->type(cmp->in(1)) != TypeInt::BOOL ) + return NULL; + flip = 1 - flip; + } else return NULL; + + // Convert to a bool (flipped) + // Build int->bool conversion +#ifndef PRODUCT + if( PrintOpto ) tty->print_cr("CMOV to I2B"); +#endif + Node *n = new (phase->C) Conv2BNode( cmp->in(1) ); + if( flip ) + n = new (phase->C) XorINode( phase->transform(n), phase->intcon(1) ); + + return n; +} + +//============================================================================= +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Check for absolute value +Node *CMoveFNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // Try generic ideal's first + Node *x = CMoveNode::Ideal(phase, can_reshape); + if( x ) return x; + + int cmp_zero_idx = 0; // Index of compare input where to look for zero + int phi_x_idx = 0; // Index of phi input where to find naked x + + // Find the Bool + if( !in(1)->is_Bool() ) return NULL; + BoolNode *bol = in(1)->as_Bool(); + // Check bool sense + switch( bol->_test._test ) { + case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; + case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; + case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; + case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; + default: return NULL; break; + } + + // Find zero input of CmpF; the other input is being abs'd + Node *cmpf = bol->in(1); + if( cmpf->Opcode() != Op_CmpF ) return NULL; + Node *X = NULL; + bool flip = false; + if( phase->type(cmpf->in(cmp_zero_idx)) == TypeF::ZERO ) { + X = cmpf->in(3 - cmp_zero_idx); + } else if (phase->type(cmpf->in(3 - cmp_zero_idx)) == TypeF::ZERO) { + // The test is inverted, we should invert the result... + X = cmpf->in(cmp_zero_idx); + flip = true; + } else { + return NULL; + } + + // If X is found on the appropriate phi input, find the subtract on the other + if( X != in(phi_x_idx) ) return NULL; + int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; + Node *sub = in(phi_sub_idx); + + // Allow only SubF(0,X) and fail out for all others; NegF is not OK + if( sub->Opcode() != Op_SubF || + sub->in(2) != X || + phase->type(sub->in(1)) != TypeF::ZERO ) return NULL; + + Node *abs = new (phase->C) AbsFNode( X ); + if( flip ) + abs = new (phase->C) SubFNode(sub->in(1), phase->transform(abs)); + + return abs; +} + +//============================================================================= +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. +// Check for absolute value +Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) { + // Try generic ideal's first + Node *x = CMoveNode::Ideal(phase, can_reshape); + if( x ) return x; + + int cmp_zero_idx = 0; // Index of compare input where to look for zero + int phi_x_idx = 0; // Index of phi input where to find naked x + + // Find the Bool + if( !in(1)->is_Bool() ) return NULL; + BoolNode *bol = in(1)->as_Bool(); + // Check bool sense + switch( bol->_test._test ) { + case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break; + case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break; + case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break; + case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break; + default: return NULL; break; + } + + // Find zero input of CmpD; the other input is being abs'd + Node *cmpd = bol->in(1); + if( cmpd->Opcode() != Op_CmpD ) return NULL; + Node *X = NULL; + bool flip = false; + if( phase->type(cmpd->in(cmp_zero_idx)) == TypeD::ZERO ) { + X = cmpd->in(3 - cmp_zero_idx); + } else if (phase->type(cmpd->in(3 - cmp_zero_idx)) == TypeD::ZERO) { + // The test is inverted, we should invert the result... + X = cmpd->in(cmp_zero_idx); + flip = true; + } else { + return NULL; + } + + // If X is found on the appropriate phi input, find the subtract on the other + if( X != in(phi_x_idx) ) return NULL; + int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue; + Node *sub = in(phi_sub_idx); + + // Allow only SubD(0,X) and fail out for all others; NegD is not OK + if( sub->Opcode() != Op_SubD || + sub->in(2) != X || + phase->type(sub->in(1)) != TypeD::ZERO ) return NULL; + + Node *abs = new (phase->C) AbsDNode( X ); + if( flip ) + abs = new (phase->C) SubDNode(sub->in(1), phase->transform(abs)); + + return abs; +} + +//------------------------------Value------------------------------------------ +const Type *MoveL2DNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeLong *tl = t->is_long(); + if( !tl->is_con() ) return bottom_type(); + JavaValue v; + v.set_jlong(tl->get_con()); + return TypeD::make( v.get_jdouble() ); +} + +//------------------------------Value------------------------------------------ +const Type *MoveI2FNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + const TypeInt *ti = t->is_int(); + if( !ti->is_con() ) return bottom_type(); + JavaValue v; + v.set_jint(ti->get_con()); + return TypeF::make( v.get_jfloat() ); +} + +//------------------------------Value------------------------------------------ +const Type *MoveF2INode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::FLOAT ) return TypeInt::INT; + const TypeF *tf = t->is_float_constant(); + JavaValue v; + v.set_jfloat(tf->getf()); + return TypeInt::make( v.get_jint() ); +} + +//------------------------------Value------------------------------------------ +const Type *MoveD2LNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return Type::TOP; + if( t == Type::DOUBLE ) return TypeLong::LONG; + const TypeD *td = t->is_double_constant(); + JavaValue v; + v.set_jdouble(td->getd()); + return TypeLong::make( v.get_jlong() ); +} + diff --git a/hotspot/src/share/vm/opto/movenode.hpp b/hotspot/src/share/vm/opto/movenode.hpp new file mode 100644 index 00000000000..8aac944ed92 --- /dev/null +++ b/hotspot/src/share/vm/opto/movenode.hpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014, 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_OPTO_MOVENODE_HPP +#define SHARE_VM_OPTO_MOVENODE_HPP + +#include "opto/node.hpp" + +//------------------------------CMoveNode-------------------------------------- +// Conditional move +class CMoveNode : public TypeNode { + public: + enum { Control, // When is it safe to do this cmove? + Condition, // Condition controlling the cmove + IfFalse, // Value if condition is false + IfTrue }; // Value if condition is true + CMoveNode( Node *bol, Node *left, Node *right, const Type *t ) : TypeNode(t,4) + { + init_class_id(Class_CMove); + // all inputs are nullified in Node::Node(int) + // init_req(Control,NULL); + init_req(Condition,bol); + init_req(IfFalse,left); + init_req(IfTrue,right); + } + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); + static CMoveNode *make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ); + // Helper function to spot cmove graph shapes + static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ); +}; + +//------------------------------CMoveDNode------------------------------------- +class CMoveDNode : public CMoveNode { + public: + CMoveDNode( Node *bol, Node *left, Node *right, const Type* t) : CMoveNode(bol,left,right,t){} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------CMoveFNode------------------------------------- +class CMoveFNode : public CMoveNode { + public: + CMoveFNode( Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) {} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------CMoveINode------------------------------------- +class CMoveINode : public CMoveNode { + public: + CMoveINode( Node *bol, Node *left, Node *right, const TypeInt *ti ) : CMoveNode(bol,left,right,ti){} + virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); +}; + +//------------------------------CMoveLNode------------------------------------- +class CMoveLNode : public CMoveNode { + public: + CMoveLNode(Node *bol, Node *left, Node *right, const TypeLong *tl ) : CMoveNode(bol,left,right,tl){} + virtual int Opcode() const; +}; + +//------------------------------CMovePNode------------------------------------- +class CMovePNode : public CMoveNode { + public: + CMovePNode( Node *c, Node *bol, Node *left, Node *right, const TypePtr* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } + virtual int Opcode() const; +}; + +//------------------------------CMoveNNode------------------------------------- +class CMoveNNode : public CMoveNode { + public: + CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); } + virtual int Opcode() const; +}; + +// +class MoveI2FNode : public Node { + public: + MoveI2FNode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual uint ideal_reg() const { return Op_RegF; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +class MoveL2DNode : public Node { + public: + MoveL2DNode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual uint ideal_reg() const { return Op_RegD; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +class MoveF2INode : public Node { + public: + MoveF2INode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual uint ideal_reg() const { return Op_RegI; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +class MoveD2LNode : public Node { + public: + MoveD2LNode( Node *value ) : Node(0,value) {} + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual uint ideal_reg() const { return Op_RegL; } + virtual const Type* Value( PhaseTransform *phase ) const; +}; + +//------------------------------BinaryNode------------------------------------- +// Place holder for the 2 conditional inputs to a CMove. CMove needs 4 +// inputs: the Bool (for the lt/gt/eq/ne bits), the flags (result of some +// compare), and the 2 values to select between. The Matcher requires a +// binary tree so we break it down like this: +// (CMove (Binary bol cmp) (Binary src1 src2)) +class BinaryNode : public Node { + public: + BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { } + virtual int Opcode() const; + virtual uint ideal_reg() const { return 0; } +}; + + +#endif // SHARE_VM_OPTO_MOVENODE_HPP + diff --git a/hotspot/src/share/vm/opto/mulnode.cpp b/hotspot/src/share/vm/opto/mulnode.cpp index 4896e98a7f0..861149afca5 100644 --- a/hotspot/src/share/vm/opto/mulnode.cpp +++ b/hotspot/src/share/vm/opto/mulnode.cpp @@ -26,6 +26,7 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/connode.hpp" +#include "opto/convertnode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/narrowptrnode.cpp b/hotspot/src/share/vm/opto/narrowptrnode.cpp new file mode 100644 index 00000000000..197d748f407 --- /dev/null +++ b/hotspot/src/share/vm/opto/narrowptrnode.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014, 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 "opto/narrowptrnode.hpp" +#include "opto/phaseX.hpp" + +Node* DecodeNNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_EncodeP()) { + // (DecodeN (EncodeP p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *DecodeNNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + if (t == TypeNarrowOop::NULL_PTR) return TypePtr::NULL_PTR; + + assert(t->isa_narrowoop(), "only narrowoop here"); + return t->make_ptr(); +} + +Node* EncodePNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_DecodeN()) { + // (EncodeP (DecodeN p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *EncodePNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + if (t == TypePtr::NULL_PTR) return TypeNarrowOop::NULL_PTR; + + assert(t->isa_oop_ptr(), "only oopptr here"); + return t->make_narrowoop(); +} + + +Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { + return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1)); +} + +Node* DecodeNKlassNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_EncodePKlass()) { + // (DecodeNKlass (EncodePKlass p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *DecodeNKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + assert(t != TypeNarrowKlass::NULL_PTR, "null klass?"); + + assert(t->isa_narrowklass(), "only narrow klass ptr here"); + return t->make_ptr(); +} + +Node* EncodePKlassNode::Identity(PhaseTransform* phase) { + const Type *t = phase->type( in(1) ); + if( t == Type::TOP ) return in(1); + + if (in(1)->is_DecodeNKlass()) { + // (EncodePKlass (DecodeNKlass p)) -> p + return in(1)->in(1); + } + return this; +} + +const Type *EncodePKlassNode::Value( PhaseTransform *phase ) const { + const Type *t = phase->type( in(1) ); + if (t == Type::TOP) return Type::TOP; + assert (t != TypePtr::NULL_PTR, "null klass?"); + + assert(UseCompressedClassPointers && t->isa_klassptr(), "only klass ptr here"); + return t->make_narrowklass(); +} + diff --git a/hotspot/src/share/vm/opto/narrowptrnode.hpp b/hotspot/src/share/vm/opto/narrowptrnode.hpp new file mode 100644 index 00000000000..9b737f59837 --- /dev/null +++ b/hotspot/src/share/vm/opto/narrowptrnode.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, 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_OPTO_NARROWPTRNODE_HPP +#define SHARE_VM_OPTO_NARROWPTRNODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + +//------------------------------EncodeNarrowPtr-------------------------------- +class EncodeNarrowPtrNode : public TypeNode { + protected: + EncodeNarrowPtrNode(Node* value, const Type* type): + TypeNode(type, 2) { + init_class_id(Class_EncodeNarrowPtr); + init_req(0, NULL); + init_req(1, value); + } + public: + virtual uint ideal_reg() const { return Op_RegN; } + virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp ); +}; + +//------------------------------EncodeP-------------------------------- +// Encodes an oop pointers into its compressed form +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class EncodePNode : public EncodeNarrowPtrNode { + public: + EncodePNode(Node* value, const Type* type): + EncodeNarrowPtrNode(value, type) { + init_class_id(Class_EncodeP); + } + virtual int Opcode() const; + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + +//------------------------------EncodePKlass-------------------------------- +// Encodes a klass pointer into its compressed form +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class EncodePKlassNode : public EncodeNarrowPtrNode { + public: + EncodePKlassNode(Node* value, const Type* type): + EncodeNarrowPtrNode(value, type) { + init_class_id(Class_EncodePKlass); + } + virtual int Opcode() const; + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; +}; + +//------------------------------DecodeNarrowPtr-------------------------------- +class DecodeNarrowPtrNode : public TypeNode { + protected: + DecodeNarrowPtrNode(Node* value, const Type* type): + TypeNode(type, 2) { + init_class_id(Class_DecodeNarrowPtr); + init_req(0, NULL); + init_req(1, value); + } + public: + virtual uint ideal_reg() const { return Op_RegP; } +}; + +//------------------------------DecodeN-------------------------------- +// Converts a narrow oop into a real oop ptr. +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class DecodeNNode : public DecodeNarrowPtrNode { + public: + DecodeNNode(Node* value, const Type* type): + DecodeNarrowPtrNode(value, type) { + init_class_id(Class_DecodeN); + } + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); +}; + +//------------------------------DecodeNKlass-------------------------------- +// Converts a narrow klass pointer into a real klass ptr. +// Takes an extra argument which is the real heap base as a long which +// may be useful for code generation in the backend. +class DecodeNKlassNode : public DecodeNarrowPtrNode { + public: + DecodeNKlassNode(Node* value, const Type* type): + DecodeNarrowPtrNode(value, type) { + init_class_id(Class_DecodeNKlass); + } + virtual int Opcode() const; + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Identity( PhaseTransform *phase ); +}; + +#endif // SHARE_VM_OPTO_NARROWPTRNODE_HPP + diff --git a/hotspot/src/share/vm/opto/opaquenode.cpp b/hotspot/src/share/vm/opto/opaquenode.cpp new file mode 100644 index 00000000000..b2cd073b131 --- /dev/null +++ b/hotspot/src/share/vm/opto/opaquenode.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, 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 "opto/opaquenode.hpp" +#include "opto/phaseX.hpp" + +//============================================================================= +// Do not allow value-numbering +uint Opaque1Node::hash() const { return NO_HASH; } +uint Opaque1Node::cmp( const Node &n ) const { + return (&n == this); // Always fail except on self +} + +//------------------------------Identity--------------------------------------- +// If _major_progress, then more loop optimizations follow. Do NOT remove +// the opaque Node until no more loop ops can happen. Note the timing of +// _major_progress; it's set in the major loop optimizations THEN comes the +// call to IterGVN and any chance of hitting this code. Hence there's no +// phase-ordering problem with stripping Opaque1 in IGVN followed by some +// more loop optimizations that require it. +Node *Opaque1Node::Identity( PhaseTransform *phase ) { + return phase->C->major_progress() ? this : in(1); +} + +//============================================================================= +// A node to prevent unwanted optimizations. Allows constant folding. Stops +// value-numbering, most Ideal calls or Identity functions. This Node is +// specifically designed to prevent the pre-increment value of a loop trip +// counter from being live out of the bottom of the loop (hence causing the +// pre- and post-increment values both being live and thus requiring an extra +// temp register and an extra move). If we "accidentally" optimize through +// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus +// it's OK to be slightly sloppy on optimizations here. + +// Do not allow value-numbering +uint Opaque2Node::hash() const { return NO_HASH; } +uint Opaque2Node::cmp( const Node &n ) const { + return (&n == this); // Always fail except on self +} + + diff --git a/hotspot/src/share/vm/opto/opaquenode.hpp b/hotspot/src/share/vm/opto/opaquenode.hpp new file mode 100644 index 00000000000..2f92a4a37aa --- /dev/null +++ b/hotspot/src/share/vm/opto/opaquenode.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, 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_OPTO_OPAQUENODE_HPP +#define SHARE_VM_OPTO_OPAQUENODE_HPP + +#include "opto/node.hpp" +#include "opto/opcodes.hpp" + +//------------------------------Opaque1Node------------------------------------ +// A node to prevent unwanted optimizations. Allows constant folding. +// Stops value-numbering, Ideal calls or Identity functions. +class Opaque1Node : public Node { + virtual uint hash() const ; // { return NO_HASH; } + virtual uint cmp( const Node &n ) const; + public: + Opaque1Node( Compile* C, Node *n ) : Node(0,n) { + // Put it on the Macro nodes list to removed during macro nodes expansion. + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + // Special version for the pre-loop to hold the original loop limit + // which is consumed by range check elimination. + Opaque1Node( Compile* C, Node *n, Node* orig_limit ) : Node(0,n,orig_limit) { + // Put it on the Macro nodes list to removed during macro nodes expansion. + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + Node* original_loop_limit() { return req()==3 ? in(2) : NULL; } + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual Node *Identity( PhaseTransform *phase ); +}; + +//------------------------------Opaque2Node------------------------------------ +// A node to prevent unwanted optimizations. Allows constant folding. Stops +// value-numbering, most Ideal calls or Identity functions. This Node is +// specifically designed to prevent the pre-increment value of a loop trip +// counter from being live out of the bottom of the loop (hence causing the +// pre- and post-increment values both being live and thus requiring an extra +// temp register and an extra move). If we "accidentally" optimize through +// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus +// it's OK to be slightly sloppy on optimizations here. +class Opaque2Node : public Node { + virtual uint hash() const ; // { return NO_HASH; } + virtual uint cmp( const Node &n ) const; + public: + Opaque2Node( Compile* C, Node *n ) : Node(0,n) { + // Put it on the Macro nodes list to removed during macro nodes expansion. + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + virtual int Opcode() const; + virtual const Type *bottom_type() const { return TypeInt::INT; } +}; + +//------------------------------Opaque3Node------------------------------------ +// A node to prevent unwanted optimizations. Will be optimized only during +// macro nodes expansion. +class Opaque3Node : public Opaque2Node { + int _opt; // what optimization it was used for + public: + enum { RTM_OPT }; + Opaque3Node(Compile* C, Node *n, int opt) : Opaque2Node(C, n), _opt(opt) {} + virtual int Opcode() const; + bool rtm_opt() const { return (_opt == RTM_OPT); } +}; + +#endif // SHARE_VM_OPTO_OPAQUENODE_HPP + diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index cae980512b1..9d7bef8edbd 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -27,9 +27,11 @@ #include "interpreter/linkResolver.hpp" #include "oops/method.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/locknode.hpp" #include "opto/memnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 2b038172021..cce96328b9b 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -30,6 +30,8 @@ #include "interpreter/linkResolver.hpp" #include "memory/universe.inline.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/matcher.hpp" diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index 1f7ea1d3f8b..b76eec74073 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -28,6 +28,7 @@ #include "memory/universe.inline.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" +#include "opto/castnode.hpp" #include "opto/memnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index b3b30850d19..61918f4da57 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -27,7 +27,6 @@ #include "opto/block.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index e1b671ffd29..877090e087a 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -48,7 +48,6 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/graphKit.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" diff --git a/hotspot/src/share/vm/opto/split_if.cpp b/hotspot/src/share/vm/opto/split_if.cpp index 134c8734798..9b99313f2ac 100644 --- a/hotspot/src/share/vm/opto/split_if.cpp +++ b/hotspot/src/share/vm/opto/split_if.cpp @@ -25,8 +25,8 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" #include "opto/callnode.hpp" -#include "opto/connode.hpp" #include "opto/loopnode.hpp" +#include "opto/movenode.hpp" //------------------------------split_thru_region------------------------------ diff --git a/hotspot/src/share/vm/opto/subnode.cpp b/hotspot/src/share/vm/opto/subnode.cpp index 71ffed86691..469d4141e32 100644 --- a/hotspot/src/share/vm/opto/subnode.cpp +++ b/hotspot/src/share/vm/opto/subnode.cpp @@ -28,9 +28,9 @@ #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/matcher.hpp" +#include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 9363caa1da4..cd53a971bff 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -27,11 +27,14 @@ #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/opcodes.hpp" +#include "opto/opaquenode.hpp" #include "opto/superword.hpp" #include "opto/vectornode.hpp" diff --git a/hotspot/src/share/vm/opto/superword.hpp b/hotspot/src/share/vm/opto/superword.hpp index 5081586474d..05d079ca2ca 100644 --- a/hotspot/src/share/vm/opto/superword.hpp +++ b/hotspot/src/share/vm/opto/superword.hpp @@ -24,7 +24,6 @@ #ifndef SHARE_VM_OPTO_SUPERWORD_HPP #define SHARE_VM_OPTO_SUPERWORD_HPP -#include "opto/connode.hpp" #include "opto/loopnode.hpp" #include "opto/node.hpp" #include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index 4026c0eb29f..5118a398f13 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -254,18 +254,24 @@ # include "opto/block.hpp" # include "opto/c2_globals.hpp" # include "opto/callnode.hpp" +# include "opto/castnode.hpp" # include "opto/cfgnode.hpp" # include "opto/compile.hpp" # include "opto/connode.hpp" +# include "opto/convertnode.hpp" +# include "opto/countbitsnode.hpp" # include "opto/idealGraphPrinter.hpp" +# include "opto/intrinsicnode.hpp" # include "opto/loopnode.hpp" # include "opto/machnode.hpp" # include "opto/matcher.hpp" # include "opto/memnode.hpp" +# include "opto/movenode.hpp" # include "opto/mulnode.hpp" # include "opto/multnode.hpp" -# include "opto/node.hpp" +# include "opto/narrowptrnode.hpp" # include "opto/opcodes.hpp" +# include "opto/opaquenode.hpp" # include "opto/optoreg.hpp" # include "opto/phase.hpp" # include "opto/phaseX.hpp" diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 2475de0480a..62ddd43b82d 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -171,15 +171,21 @@ #include "opto/addnode.hpp" #include "opto/block.hpp" #include "opto/callnode.hpp" +#include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" +#include "opto/convertnode.hpp" #include "opto/divnode.hpp" +#include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" #include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" +#include "opto/movenode.hpp" +#include "opto/narrowptrnode.hpp" +#include "opto/opaquenode.hpp" #include "opto/phaseX.hpp" #include "opto/parse.hpp" #include "opto/regalloc.hpp" From d9d9742c758ca579a46086a03d693d56b126373b Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Tue, 1 Apr 2014 10:00:43 -0700 Subject: [PATCH 106/170] 8031425: Two langtools/javac tests fail by timeout on Windows Reviewed-by: jjg, vromero --- .../static/hiding/InterfaceMethodHidingTest.java | 3 ++- .../tools/javac/lambda/FunctionalInterfaceConversionTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java b/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java index ba69bd614aa..52f912b6ecb 100644 --- a/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java +++ b/langtools/test/tools/javac/defaultMethods/static/hiding/InterfaceMethodHidingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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 @@ -26,6 +26,7 @@ * @bug 8005166 * @summary Add support for static interface methods * Smoke test for static interface method hiding + * @run main/timeout=600 InterfaceMethodHidingTest */ import com.sun.source.util.JavacTask; diff --git a/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java index 06db21564f6..8e50868f8a0 100644 --- a/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java +++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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 @@ -30,7 +30,7 @@ * @author Maurizio Cimadamore * @library ../lib * @build JavacTestingAbstractThreadedTest - * @run main/othervm FunctionalInterfaceConversionTest + * @run main/timeout=600/othervm FunctionalInterfaceConversionTest */ // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) From befb7157c912d2897d9c79dbfbb71042696c94be Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Wed, 2 Apr 2014 10:05:16 +0400 Subject: [PATCH 107/170] 8034044: Class.getModifiers() returns "static" for anonymous classes Javac sets ACC_STATIC bit for anonymous classes which contradicts the JLS Reviewed-by: jfranck --- .../com/sun/tools/javac/comp/Attr.java | 7 +-- .../com/sun/tools/javac/comp/Check.java | 3 - .../sun/tools/javac/parser/JavacParser.java | 2 +- langtools/test/tools/javac/T8034044.java | 60 +++++++++++++++++++ 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 langtools/test/tools/javac/T8034044.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 1ab10af50e0..0234f252a7c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -2112,10 +2112,8 @@ public class Attr extends JCTree.Visitor { // // This expression is then *transformed* as follows: // - // (1) add a STATIC flag to the class definition - // if the current environment is static - // (2) add an extends or implements clause - // (3) add a constructor. + // (1) add an extends or implements clause + // (2) add a constructor. // // For instance, if C is a class, and ET is the type of E, // the expression @@ -2132,7 +2130,6 @@ public class Attr extends JCTree.Visitor { // } // ... // } - if (Resolve.isStatic(env)) cdef.mods.flags |= STATIC; if (clazztype.tsym.isInterface()) { cdef.implementing = List.of(clazz); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 0e0f0c59a70..ccc19f44157 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -1072,9 +1072,6 @@ public class Check { if (sym.isLocal()) { mask = LocalClassFlags; if (sym.name.isEmpty()) { // Anonymous class - // Anonymous classes in static methods are themselves static; - // that's why we admit STATIC here. - mask |= STATIC; // JLS: Anonymous classes are final. implicit |= FINAL; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 14ea64f81fa..c8a26f35f61 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -3360,7 +3360,7 @@ public class JavacParser implements Parser { ? arguments() : List.nil(); JCClassDecl body = null; if (token.kind == LBRACE) { - JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC); + JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM); List defs = classOrInterfaceBody(names.empty, false); body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); } diff --git a/langtools/test/tools/javac/T8034044.java b/langtools/test/tools/javac/T8034044.java new file mode 100644 index 00000000000..47d92870e3b --- /dev/null +++ b/langtools/test/tools/javac/T8034044.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014, 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 8034044 + * @summary An anonymous class should not be static + */ + +import static java.lang.reflect.Modifier.*; + +public class T8034044 { + enum En { + V() {} + } + + static class InnStat { + static Object o = new Object() {}; + } + + public static void main(String[] args) + throws Throwable { + Object o = new Object() {}; + test(o.getClass()); + test(En.V.getClass()); + test(InnStat.o.getClass()); + new T8034044().f(); + } + + public void f() { + Object o = new Object() {}; + test(o.getClass()); + } + + static void test(Class clazz) { + if ((clazz.getModifiers() & STATIC) != 0) + throw new AssertionError(clazz.toString() + + " should not be static"); + } +} From e231918e582d0f198907c9e4a9b4f8868a0bddb8 Mon Sep 17 00:00:00 2001 From: Paul Govereau Date: Tue, 1 Apr 2014 23:52:10 -0700 Subject: [PATCH 108/170] 8034933: Update documentation for Types.directSupertypes to clarify behavior Reviewed-by: darcy --- .../classes/javax/lang/model/util/Types.java | 7 +- .../model/util/DirectSuperOfInt.java | 66 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.java diff --git a/langtools/src/share/classes/javax/lang/model/util/Types.java b/langtools/src/share/classes/javax/lang/model/util/Types.java index 7dc7652a400..e4bc4e8b66f 100644 --- a/langtools/src/share/classes/javax/lang/model/util/Types.java +++ b/langtools/src/share/classes/javax/lang/model/util/Types.java @@ -132,12 +132,15 @@ public interface Types { boolean isSubsignature(ExecutableType m1, ExecutableType m2); /** - * Returns the direct supertypes of a type. The interface types, if any, - * will appear last in the list. + * Returns the direct supertypes of a type. The interface types, if any, + * will appear last in the list. For an interface type with no direct + * super-interfaces, a type mirror representing {@code java.lang.Object} + * is returned. * * @param t the type being examined * @return the direct supertypes, or an empty list if none * @throws IllegalArgumentException if given an executable or package type + * @jls 4.10 Subtyping */ List directSupertypes(TypeMirror t); diff --git a/langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.java b/langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.java new file mode 100644 index 00000000000..08483ea9a11 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/util/DirectSuperOfInt.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, 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 8034933 + * @summary Types.directSupertypes should return Object as the super type of interfaces + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor DirectSuperOfInt + * @compile -processor DirectSuperOfInt -proc:only DirectSuperOfInt.java + */ + +import java.util.Set; +import java.util.List; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import static javax.lang.model.util.ElementFilter.*; + +public class DirectSuperOfInt extends JavacTestingAbstractProcessor { + public boolean process(Set tes, + RoundEnvironment round) { + if (round.processingOver()) + return true; + + boolean tested = false; + for (TypeElement te : typesIn(round.getRootElements())) { + if (!te.getSimpleName().contentEquals("DirectSuperOfIntI")) + continue; + + tested = true; + List supers = types.directSupertypes(te.asType()); + if (supers.size() != 1) + throw new AssertionError("test failed"); + + if (!elements.getTypeElement("java.lang.Object").asType().equals((supers.get(0)))) + throw new AssertionError("test failed"); + } + if (!tested) + throw new AssertionError("test failed"); + return true; + } +} + +interface DirectSuperOfIntI {} From d642f92759b33fad53b1efd40033528b4b352d91 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Tue, 1 Apr 2014 23:58:04 -0700 Subject: [PATCH 109/170] 8032066: Serialized form has broken links to non private inner classes of package private Reviewed-by: jjg --- .../html/SerializedFormWriterImpl.java | 18 +++- .../TestSerializedForm.java | 84 ++++++++++++++++--- .../pkg1/NestedInnerClass.java | 62 ++++++++++++++ .../pkg1/PrivateIncludeInnerClass.java | 62 ++++++++++++++ .../pkg1/ProtectedInnerClass.java | 59 +++++++++++++ .../pkg1/PublicExcludeInnerClass.java | 62 ++++++++++++++ 6 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java create mode 100644 langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java create mode 100644 langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.java create mode 100644 langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java index 23ef78005bf..a6bbc6e0da2 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SerializedFormWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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 @@ -26,6 +26,7 @@ package com.sun.tools.doclets.formats.html; import java.io.*; +import java.util.*; import com.sun.javadoc.*; import com.sun.tools.doclets.formats.html.markup.*; import com.sun.tools.doclets.internal.toolkit.*; @@ -45,6 +46,8 @@ import com.sun.tools.doclets.internal.toolkit.util.DocletAbortException; public class SerializedFormWriterImpl extends SubWriterHolderWriter implements SerializedFormWriter { + List visibleClasses; + /** * @param configuration the configuration data for the doclet * @throws IOException @@ -53,6 +56,7 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter public SerializedFormWriterImpl(ConfigurationImpl configuration) throws IOException { super(configuration, DocPaths.SERIALIZED_FORM); + visibleClasses = Arrays.asList(configuration.root.classes()); } /** @@ -120,6 +124,16 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter return ul; } + /** + * Checks if a class is generated and is visible. + * + * @param classDoc the class being processed. + * @return true if the class, that is being processed, is generated and is visible. + */ + public boolean isVisibleClass(ClassDoc classDoc) { + return visibleClasses.contains(classDoc) && configuration.isGeneratedDoc(classDoc); + } + /** * Get the serializable class heading. * @@ -127,7 +141,7 @@ public class SerializedFormWriterImpl extends SubWriterHolderWriter * @return a content tree for the class header */ public Content getClassHeader(ClassDoc classDoc) { - Content classLink = (classDoc.isPublic() || classDoc.isProtected()) ? + Content classLink = (isVisibleClass(classDoc)) ? getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.DEFAULT, classDoc) .label(configuration.getClassName(classDoc))) : new StringContent(classDoc.qualifiedName()); diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java b/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java index 7749bb92b67..bfc19852a1a 100644 --- a/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java +++ b/langtools/test/com/sun/javadoc/testSerializedForm/TestSerializedForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -26,7 +26,7 @@ import java.io.*; /* * @test - * @bug 4341304 4485668 4966728 + * @bug 4341304 4485668 4966728 8032066 * @summary Test that methods readResolve and writeReplace show * up in serialized-form.html the same way that readObject and writeObject do. * If the doclet includes readResolve and writeReplace in the serialized-form @@ -54,12 +54,70 @@ public class TestSerializedForm extends JavadocTester implements Serializable { "protected java.lang.Object readObjectNoData()"}, {BUG_ID + FS + "serialized-form.html", "See Also"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.PrivateIncludeInnerClass.PriInnerClass extends " + + "java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.ProtectedInnerClass.ProInnerClass extends " + + "java.lang.Object implements Serializable

"} + }; + + private static final String[][] TEST_PRIVATE = { + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class " + + "pkg1.PrivateIncludeInnerClass.PriInnerClass extends java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class " + + "pkg1.ProtectedInnerClass.ProInnerClass extends java.lang.Object implements Serializable

"} + }; + + private static final String[][] NEGATED_TEST = { + {BUG_ID + "/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class " + + "pkg1.PrivateInnerClass.PriInnerClass extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class " + + "pkg1.ProtectedInnerClass.ProInnerClass extends java.lang.Object implements Serializable

"}, + {BUG_ID + "/serialized-form.html", + "

Class pkg1.PublicExcludeInnerClass.PubInnerClass extends java.lang.Object implements " + + "Serializable

"} + }; + + private static final String[][] NEGATED_TEST_PRIVATE = { + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.NestedInnerClass.InnerClass.ProNestedInnerClass " + + "extends java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.PrivateInnerClass.PriInnerClass extends " + + "java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.ProtectedInnerClass.ProInnerClass extends " + + "java.lang.Object implements Serializable

"}, + {BUG_ID + "-1/serialized-form.html", + "

Class pkg1.PublicExcludeInnerClass.PubInnerClass " + + "extends java.lang.Object implements Serializable

"} }; - private static final String[][] NEGATED_TEST = NO_TEST; private static final String[] ARGS = new String[] { "-d", BUG_ID, "-sourcepath", SRC_DIR, - SRC_DIR + FS + "TestSerializedForm.java" + SRC_DIR + "/TestSerializedForm.java", "pkg1" + }; + + private static final String[] ARGS_PRIVATE = new String[] { + "-private", "-d", BUG_ID + "-1", "-sourcepath", SRC_DIR, + SRC_DIR + "/TestSerializedForm.java", "pkg1" }; /** @@ -74,7 +132,8 @@ public class TestSerializedForm extends JavadocTester implements Serializable { */ public static void main(String[] args) { TestSerializedForm tester = new TestSerializedForm(); - int actualExitCode = run(tester, ARGS, TEST, NEGATED_TEST); + run(tester, ARGS, TEST, NEGATED_TEST); + run(tester, ARGS_PRIVATE, TEST_PRIVATE, NEGATED_TEST_PRIVATE); tester.printSummary(); } @@ -93,34 +152,39 @@ public class TestSerializedForm extends JavadocTester implements Serializable { } /** + * @param s ObjectInputStream. * @throws IOException when there is an I/O error. * @serial */ - private void readObject(ObjectInputStream s) {} + private void readObject(ObjectInputStream s) throws IOException {} /** + * @param s ObjectOutputStream. * @throws IOException when there is an I/O error. * @serial */ - private void writeObject(ObjectOutputStream s) {} + private void writeObject(ObjectOutputStream s) throws IOException {} /** * @throws IOException when there is an I/O error. * @serialData This is a serial data comment. + * @return an object. */ - protected Object readResolve(){return null;} + protected Object readResolve() throws IOException {return null;} /** * @throws IOException when there is an I/O error. * @serialData This is a serial data comment. + * @return an object. */ - protected Object writeReplace(){return null;} + protected Object writeReplace() throws IOException {return null;} /** * @throws IOException when there is an I/O error. * @serialData This is a serial data comment. + * @return an object. */ - protected Object readObjectNoData() { + protected Object readObjectNoData() throws IOException { return null; } diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java new file mode 100644 index 00000000000..2b7e2912894 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/NestedInnerClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 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. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where the outer class is package private and the inner class is private + * and a nested inner class is protected. + * + * @author Bhavesh Patel + */ + +class NestedInnerClass { + + private static class InnerClass { + + protected static class ProNestedInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java new file mode 100644 index 00000000000..e81ba1862c0 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PrivateIncludeInnerClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 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. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where the outer class is package private and inner class + * is private which is included using the tag. + * + * @author Bhavesh Patel + */ + +class PrivateIncludeInnerClass { + + /** + * @serial include + */ + private static class PriInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.java new file mode 100644 index 00000000000..8eee8e18d37 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/ProtectedInnerClass.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where outer class is package private and the inner class is + * protected. + * + * @author Bhavesh Patel + */ + +class ProtectedInnerClass { + + protected static class ProInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } +} diff --git a/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java new file mode 100644 index 00000000000..0c110600380 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSerializedForm/pkg1/PublicExcludeInnerClass.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 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. + */ + +package pkg1; + +import java.io.*; + +/** + * A test class where the outer class is package private and inner class + * is public which is excluded using the tag. + * + * @author Bhavesh Patel + */ + +class PublicExcludeInnerClass { + + /** + * @serial exclude + */ + public static class PubInnerClass implements java.io.Serializable { + + public final int SERIALIZABLE_CONSTANT = 1; + + /** + * @param s ObjectInputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void readObject(ObjectInputStream s) throws IOException { + } + + /** + * @param s ObjectOutputStream. + * @throws IOException when there is an I/O error. + * @serial + */ + private void writeObject(ObjectOutputStream s) throws IOException { + } + } +} From 419ae8206b409f5754b87dc78ceeddbd440a3143 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 2 Apr 2014 10:16:46 +0200 Subject: [PATCH 110/170] 8039045: PPC64: need include in adl generated files after 8001532 Reviewed-by: kvn --- hotspot/src/share/vm/adlc/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/adlc/main.cpp b/hotspot/src/share/vm/adlc/main.cpp index 0e0ea74dc1a..614f0d43f10 100644 --- a/hotspot/src/share/vm/adlc/main.cpp +++ b/hotspot/src/share/vm/adlc/main.cpp @@ -243,7 +243,6 @@ int main(int argc, char *argv[]) AD.addInclude(AD._CPP_file, "vmreg_arm.inline.hpp"); #endif #ifdef TARGET_ARCH_ppc - AD.addInclude(AD._CPP_file, "assembler_ppc.inline.hpp"); AD.addInclude(AD._CPP_file, "nativeInst_ppc.hpp"); AD.addInclude(AD._CPP_file, "vmreg_ppc.inline.hpp"); #endif @@ -274,6 +273,7 @@ int main(int argc, char *argv[]) AD.addInclude(AD._DFA_file, "opto/cfgnode.hpp"); // Use PROB_MAX in predicate. AD.addInclude(AD._DFA_file, "opto/matcher.hpp"); AD.addInclude(AD._DFA_file, "opto/opcodes.hpp"); + AD.addInclude(AD._DFA_file, "opto/convertnode.hpp"); // Make sure each .cpp file starts with include lines: // files declaring and defining generators for Mach* Objects (hpp,cpp) // Generate the result files: From 79fba7993d6a1273ea9947c053f652f268cfd35e Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 2 Apr 2014 15:52:31 +0530 Subject: [PATCH 111/170] 8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed Reviewed-by: lagergren, attila --- .../jdk/nashorn/internal/parser/Parser.java | 6 ++-- nashorn/test/script/error/JDK-8039047.js | 35 +++++++++++++++++++ .../test/script/error/JDK-8039047.js.EXPECTED | 6 ++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 nashorn/test/script/error/JDK-8039047.js create mode 100644 nashorn/test/script/error/JDK-8039047.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index f6b962a93e1..08ff725a175 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -1700,9 +1700,11 @@ loop: // ECMA 12.4.1 strict mode restrictions verifyStrictIdent(exception, "catch argument"); - // Check for conditional catch. + // Nashorn extension: catch clause can have optional + // condition. So, a single try can have more than one + // catch clause each with it's own condition. final Expression ifExpression; - if (type == IF) { + if (!env._no_syntax_extensions && type == IF) { next(); // Get the exception condition. ifExpression = expression(); diff --git a/nashorn/test/script/error/JDK-8039047.js b/nashorn/test/script/error/JDK-8039047.js new file mode 100644 index 00000000000..8cbd51fdf5e --- /dev/null +++ b/nashorn/test/script/error/JDK-8039047.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * JDK-8039047: Parser accepts conditional catch clauses even when --no-syntax-extensions / -nse option is passed + * + * @option --no-syntax-extensions + * @test/compile-error + */ + +try { + func() +} catch (e if e instanceof ReferenceError) { + print("Got ReferenceError " + e); +} diff --git a/nashorn/test/script/error/JDK-8039047.js.EXPECTED b/nashorn/test/script/error/JDK-8039047.js.EXPECTED new file mode 100644 index 00000000000..b1d2f1705b0 --- /dev/null +++ b/nashorn/test/script/error/JDK-8039047.js.EXPECTED @@ -0,0 +1,6 @@ +test/script/error/JDK-8039047.js:33:11 Expected ) but found if +} catch (e if e instanceof ReferenceError) { + ^ +test/script/error/JDK-8039047.js:35:0 Expected eof but found } +} +^ From a52fd3388d40e726e413f1063bc40f49f6821089 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Wed, 2 Apr 2014 14:17:34 +0200 Subject: [PATCH 112/170] 8037959: BitMap::resize frees old map before copying memory if !in_resource_area Add reallocate functionality to ArrayAllocator and use it from BitMap::resize Reviewed-by: brutisso, tschatzl --- hotspot/src/share/vm/memory/allocation.hpp | 7 ++ .../src/share/vm/memory/allocation.inline.hpp | 52 +++++++---- hotspot/src/share/vm/prims/jni.cpp | 2 + hotspot/src/share/vm/utilities/bitMap.cpp | 90 +++++++++++++++++-- 4 files changed, 129 insertions(+), 22 deletions(-) diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index 487762201f1..fbfff65dad4 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -748,6 +748,12 @@ class ArrayAllocator VALUE_OBJ_CLASS_SPEC { bool _use_malloc; size_t _size; bool _free_in_destructor; + + static bool should_use_malloc(size_t size) { + return size < ArrayAllocatorMallocLimit; + } + + static char* allocate_inner(size_t& size, bool& use_malloc); public: ArrayAllocator(bool free_in_destructor = true) : _addr(NULL), _use_malloc(false), _size(0), _free_in_destructor(free_in_destructor) { } @@ -759,6 +765,7 @@ class ArrayAllocator VALUE_OBJ_CLASS_SPEC { } E* allocate(size_t length); + E* reallocate(size_t new_length); void free(); }; diff --git a/hotspot/src/share/vm/memory/allocation.inline.hpp b/hotspot/src/share/vm/memory/allocation.inline.hpp index d8f1940a6d4..806088b9bae 100644 --- a/hotspot/src/share/vm/memory/allocation.inline.hpp +++ b/hotspot/src/share/vm/memory/allocation.inline.hpp @@ -122,35 +122,57 @@ template void CHeapObj::operator delete [](void* p){ } template -E* ArrayAllocator::allocate(size_t length) { - assert(_addr == NULL, "Already in use"); +char* ArrayAllocator::allocate_inner(size_t &size, bool &use_malloc) { + char* addr = NULL; - _size = sizeof(E) * length; - _use_malloc = _size < ArrayAllocatorMallocLimit; - - if (_use_malloc) { - _addr = AllocateHeap(_size, F); - if (_addr == NULL && _size >= (size_t)os::vm_allocation_granularity()) { + if (use_malloc) { + addr = AllocateHeap(size, F); + if (addr == NULL && size >= (size_t)os::vm_allocation_granularity()) { // malloc failed let's try with mmap instead - _use_malloc = false; + use_malloc = false; } else { - return (E*)_addr; + return addr; } } int alignment = os::vm_allocation_granularity(); - _size = align_size_up(_size, alignment); + size = align_size_up(size, alignment); - _addr = os::reserve_memory(_size, NULL, alignment, F); - if (_addr == NULL) { - vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)"); + addr = os::reserve_memory(size, NULL, alignment, F); + if (addr == NULL) { + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)"); } - os::commit_memory_or_exit(_addr, _size, !ExecMem, "Allocator (commit)"); + os::commit_memory_or_exit(addr, size, !ExecMem, "Allocator (commit)"); + return addr; +} + +template +E* ArrayAllocator::allocate(size_t length) { + assert(_addr == NULL, "Already in use"); + + _size = sizeof(E) * length; + _use_malloc = should_use_malloc(_size); + _addr = allocate_inner(_size, _use_malloc); return (E*)_addr; } +template +E* ArrayAllocator::reallocate(size_t new_length) { + size_t new_size = sizeof(E) * new_length; + bool use_malloc = should_use_malloc(new_size); + char* new_addr = allocate_inner(new_size, use_malloc); + + memcpy(new_addr, _addr, MIN2(new_size, _size)); + + free(); + _size = new_size; + _use_malloc = use_malloc; + _addr = new_addr; + return (E*)new_addr; +} + template void ArrayAllocator::free() { if (_addr != NULL) { diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 3f06633e612..4d385321254 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3878,6 +3878,7 @@ void TestMetachunk_test(); void TestVirtualSpaceNode_test(); void TestNewSize_test(); void TestKlass_test(); +void TestBitMap_test(); #if INCLUDE_ALL_GCS void TestOldFreeSpaceCalculation_test(); void TestG1BiasedArray_test(); @@ -3903,6 +3904,7 @@ void execute_internal_vm_tests() { run_unit_test(test_loggc_filename()); run_unit_test(TestNewSize_test()); run_unit_test(TestKlass_test()); + run_unit_test(TestBitMap_test()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif diff --git a/hotspot/src/share/vm/utilities/bitMap.cpp b/hotspot/src/share/vm/utilities/bitMap.cpp index b2a2ab7b2d5..024e35e374d 100644 --- a/hotspot/src/share/vm/utilities/bitMap.cpp +++ b/hotspot/src/share/vm/utilities/bitMap.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/copy.hpp" #ifdef TARGET_OS_FAMILY_linux @@ -67,16 +68,14 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { idx_t new_size_in_words = size_in_words(); if (in_resource_area) { _map = NEW_RESOURCE_ARRAY(bm_word_t, new_size_in_words); + Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, + MIN2(old_size_in_words, new_size_in_words)); } else { - if (old_map != NULL) { - _map_allocator.free(); - } - _map = _map_allocator.allocate(new_size_in_words); + _map = _map_allocator.reallocate(new_size_in_words); } - Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, - MIN2(old_size_in_words, new_size_in_words)); + if (new_size_in_words > old_size_in_words) { - clear_range_of_words(old_size_in_words, size_in_words()); + clear_range_of_words(old_size_in_words, new_size_in_words); } } @@ -536,6 +535,83 @@ void BitMap::print_on(outputStream* st) const { tty->cr(); } +class TestBitMap : public AllStatic { + const static BitMap::idx_t BITMAP_SIZE = 1024; + static void fillBitMap(BitMap& map) { + map.set_bit(1); + map.set_bit(3); + map.set_bit(17); + map.set_bit(512); + } + + static void testResize(bool in_resource_area) { + { + BitMap map(0, in_resource_area); + map.resize(BITMAP_SIZE, in_resource_area); + fillBitMap(map); + + BitMap map2(BITMAP_SIZE, in_resource_area); + fillBitMap(map2); + assert(map.is_same(map2), "could be"); + } + + { + BitMap map(128, in_resource_area); + map.resize(BITMAP_SIZE, in_resource_area); + fillBitMap(map); + + BitMap map2(BITMAP_SIZE, in_resource_area); + fillBitMap(map2); + assert(map.is_same(map2), "could be"); + } + + { + BitMap map(BITMAP_SIZE, in_resource_area); + map.resize(BITMAP_SIZE, in_resource_area); + fillBitMap(map); + + BitMap map2(BITMAP_SIZE, in_resource_area); + fillBitMap(map2); + assert(map.is_same(map2), "could be"); + } + } + + static void testResizeResource() { + ResourceMark rm; + testResize(true); + } + + static void testResizeNonResource() { + const uintx bitmap_bytes = BITMAP_SIZE / BitsPerByte; + + // Test the default behavior + testResize(false); + + { + // Make sure that AllocatorMallocLimit is larger than our allocation request + // forcing it to call standard malloc() + UIntFlagSetting fs(ArrayAllocatorMallocLimit, bitmap_bytes * 4); + testResize(false); + } + { + // Make sure that AllocatorMallocLimit is smaller than our allocation request + // forcing it to call mmap() (or equivalent) + UIntFlagSetting fs(ArrayAllocatorMallocLimit, bitmap_bytes / 4); + testResize(false); + } + } + + public: + static void test() { + testResizeResource(); + testResizeNonResource(); + } + +}; + +void TestBitMap_test() { + TestBitMap::test(); +} #endif From d801fbbc9d324a5da137c7256086b21cbb56346a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 2 Apr 2014 18:26:57 +0200 Subject: [PATCH 113/170] 8038638: Persistent store for compiled scripts Reviewed-by: lagergren, sundar --- .../internal/codegen/CodeGenerator.java | 2 +- .../nashorn/internal/codegen/Compiler.java | 37 +--- .../nashorn/internal/codegen/MapCreator.java | 4 +- .../internal/runtime/AccessorProperty.java | 38 +++- .../internal/runtime/CodeInstaller.java | 12 +- .../nashorn/internal/runtime/CodeStore.java | 179 ++++++++++++++++++ .../internal/runtime/CompiledScript.java | 127 +++++++++++++ .../jdk/nashorn/internal/runtime/Context.java | 142 ++++++++++++-- .../nashorn/internal/runtime/Property.java | 12 +- .../nashorn/internal/runtime/PropertyMap.java | 54 ++++-- .../RecompilableScriptFunctionData.java | 105 +++++++--- .../internal/runtime/ScriptEnvironment.java | 4 + .../internal/runtime/ScriptFunctionData.java | 6 +- .../jdk/nashorn/internal/runtime/Source.java | 39 ++++ .../runtime/UserAccessorProperty.java | 5 + .../runtime/resources/Options.properties | 8 + 16 files changed, 682 insertions(+), 92 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index e0ca67a4a92..9cf0adb949f 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3228,7 +3228,7 @@ final class CodeGenerator extends NodeOperatorVisitor install(final String className, final byte[] code) { - LOG.fine("Installing class ", className); - - final Class clazz = installer.install(Compiler.binaryName(className), code); - - try { - final Object[] constants = getConstantData().toArray(); - // Need doPrivileged because these fields are private - AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public Void run() throws Exception { - //use reflection to write source and constants table to installed classes - final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName()); - final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName()); - sourceField.setAccessible(true); - constantsField.setAccessible(true); - sourceField.set(null, source); - constantsField.set(null, constants); - return null; - } - }); - } catch (final PrivilegedActionException e) { - throw new RuntimeException(e); - } - - return clazz; + private Class install(final String className, final byte[] code, final Object[] constants) { + return installer.install(className, code, source, constants); } /** @@ -444,10 +420,15 @@ public final class Compiler { assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; final Map> installedClasses = new HashMap<>(); + final Object[] constants = getConstantData().toArray(); final String rootClassName = firstCompileUnitName(); final byte[] rootByteCode = bytecode.get(rootClassName); - final Class rootClass = install(rootClassName, rootByteCode); + final Class rootClass = install(rootClassName, rootByteCode, constants); + + if (!isLazy()) { + installer.storeCompiledScript(source, rootClassName, bytecode, constants); + } int length = rootByteCode.length; @@ -461,7 +442,7 @@ public final class Compiler { final byte[] code = entry.getValue(); length += code.length; - installedClasses.put(className, install(className, code)); + installedClasses.put(className, install(className, code, constants)); } for (final CompileUnit unit : compileUnits) { diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java index 8012adf5065..436622bd7ff 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java @@ -83,7 +83,7 @@ public class MapCreator { } } - return PropertyMap.newMap(properties, fieldCount, fieldMaximum, 0); + return PropertyMap.newMap(properties, structure.getName(), fieldCount, fieldMaximum, 0); } PropertyMap makeSpillMap(final boolean hasArguments) { @@ -100,7 +100,7 @@ public class MapCreator { } } - return PropertyMap.newMap(properties, 0, 0, spillIndex); + return PropertyMap.newMap(properties, structure.getName(), 0, 0, spillIndex); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java index d22a956760b..e8ff153da5e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java @@ -39,6 +39,9 @@ import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getNumberOfAcces import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -51,11 +54,12 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory; * An AccessorProperty is the most generic property type. An AccessorProperty is * represented as fields in a ScriptObject class. */ -public final class AccessorProperty extends Property { +public final class AccessorProperty extends Property implements Serializable { private static final MethodHandles.Lookup lookup = MethodHandles.lookup(); private static final MethodHandle REPLACE_MAP = findOwnMH("replaceMap", Object.class, Object.class, PropertyMap.class, String.class, Class.class, Class.class); private static final int NOOF_TYPES = getNumberOfAccessorTypes(); + private static final long serialVersionUID = 3371720170182154920L; /** * Properties in different maps for the same structure class will share their field getters and setters. This could @@ -71,7 +75,7 @@ public final class AccessorProperty extends Property { }; /** Property getter cache */ - private MethodHandle[] getters = new MethodHandle[NOOF_TYPES]; + private transient MethodHandle[] getters = new MethodHandle[NOOF_TYPES]; private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES]; private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES]; @@ -122,16 +126,16 @@ public final class AccessorProperty extends Property { } /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */ - private MethodHandle primitiveGetter; + private transient MethodHandle primitiveGetter; /** Seed setter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */ - private MethodHandle primitiveSetter; + private transient MethodHandle primitiveSetter; /** Seed getter for the Object version of this field */ - private MethodHandle objectGetter; + private transient MethodHandle objectGetter; /** Seed setter for the Object version of this field */ - private MethodHandle objectSetter; + private transient MethodHandle objectSetter; /** * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode @@ -243,6 +247,12 @@ public final class AccessorProperty extends Property { public AccessorProperty(final String key, final int flags, final Class structure, final int slot) { super(key, flags, slot); + initGetterSetter(structure); + } + + private void initGetterSetter(final Class structure) { + final int slot = getSlot(); + final String key = getKey(); /* * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also * works in dual field mode, it only means that the property never has a primitive @@ -305,6 +315,12 @@ public final class AccessorProperty extends Property { setCurrentType(property.getCurrentType()); } + private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { + s.defaultReadObject(); + // Restore getters array + getters = new MethodHandle[NOOF_TYPES]; + } + private static MethodHandle bindTo(final MethodHandle mh, final Object receiver) { if (mh == null) { return null; @@ -363,6 +379,16 @@ public final class AccessorProperty extends Property { return objectSetter; } + @Override + void initMethodHandles(final Class structure) { + if (!ScriptObject.class.isAssignableFrom(structure) || !StructureLoader.isStructureClass(structure.getName())) { + throw new IllegalArgumentException(); + } + if (!isSpill()) { + initGetterSetter(structure); + } + } + @Override public MethodHandle getGetter(final Class type) { final int i = getAccessorTypeIndex(type); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java index 28c9630ea54..579b6f3efbf 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime; +import java.util.Map; import jdk.nashorn.internal.codegen.ClassEmitter; /** @@ -52,7 +53,7 @@ public interface CodeInstaller { * @param bytecode bytecode * @return the installed class */ - public Class install(final String className, final byte[] bytecode); + public Class install(final String className, final byte[] bytecode, final Source source, final Object[] constants); /** * Verify generated bytecode before emission. This is called back from the @@ -74,4 +75,13 @@ public interface CodeInstaller { * @return unique eval id */ public long getUniqueEvalId(); + + /** + * Store a compiled script for later reuse + * @param source the script source + * @param mainClassName the main class name + * @param classBytes map of class names to class bytes + * @param constants constants array + */ + public void storeCompiledScript(Source source, String mainClassName, Map classBytes, Object[] constants); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java new file mode 100644 index 00000000000..1299c71f1f2 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2010, 2014, 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. + */ + +package jdk.nashorn.internal.runtime; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Base64; +import java.util.Map; + +/** + * A code cache for persistent caching of compiled scripts. + */ +final class CodeStore { + + private final File dir; + private final int minSize; + + // Message digest to file name encoder + private final static Base64.Encoder BASE64 = Base64.getUrlEncoder().withoutPadding(); + + // Default minimum size for storing a compiled script class + private final static int DEFAULT_MIN_SIZE = 1000; + + /** + * Constructor + * @param path directory to store code in + * @throws IOException + */ + public CodeStore(final String path) throws IOException { + this(path, DEFAULT_MIN_SIZE); + } + + /** + * Constructor + * @param path directory to store code in + * @param minSize minimum file size for caching scripts + * @throws IOException + */ + public CodeStore(final String path, final int minSize) throws IOException { + this.dir = new File(path); + this.minSize = minSize; + checkDirectory(this.dir); + } + + private static void checkDirectory(final File dir) throws IOException { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws IOException { + if (!dir.exists() && !dir.mkdirs()) { + throw new IOException("Could not create directory: " + dir); + } else if (!dir.isDirectory()) { + throw new IOException("Not a directory: " + dir); + } else if (!dir.canRead() || !dir.canWrite()) { + throw new IOException("Directory not readable or writable: " + dir); + } + return null; + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } + } + + /** + * Return a compiled script from the cache, or null if it isn't found. + * + * @param source the source + * @return the compiled script or null + * @throws IOException + * @throws ClassNotFoundException + */ + public CompiledScript getScript(final Source source) throws IOException, ClassNotFoundException { + if (source.getLength() < minSize) { + return null; + } + + final String digest = BASE64.encodeToString(source.getDigest()); + final File file = new File(dir, digest); + + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public CompiledScript run() throws IOException, ClassNotFoundException { + if (!file.exists()) { + return null; + } + try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { + CompiledScript compiledScript = (CompiledScript) in.readObject(); + compiledScript.setSource(source); + return compiledScript; + } + } + }); + } catch (PrivilegedActionException e) { + final Exception ex = e.getException(); + if (ex instanceof IOException) { + throw (IOException) ex; + } else if (ex instanceof ClassNotFoundException) { + throw (ClassNotFoundException) ex; + } + throw (new RuntimeException(ex)); + } + } + + /** + * Store a compiled script in the cache. + * + * @param source the source + * @param mainClassName the main class name + * @param classBytes a map of class bytes + * @param constants the constants array + * @throws IOException + */ + public void putScript(final Source source, final String mainClassName, final Map classBytes, final Object[] constants) + throws IOException { + if (source.getLength() < minSize) { + return; + } + for (final Object constant : constants) { + // Make sure all constant data is serializable + if (! (constant instanceof Serializable)) { + return; + } + } + + final String digest = BASE64.encodeToString(source.getDigest()); + final File file = new File(dir, digest); + final CompiledScript script = new CompiledScript(source, mainClassName, classBytes, constants); + + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws IOException { + try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { + out.writeObject(script); + } + return null; + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } + } +} + diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java b/nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java new file mode 100644 index 00000000000..6bb8e9a0f37 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledScript.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010, 2014, 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. + */ + +package jdk.nashorn.internal.runtime; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Map; + +/** + * Class representing a compiled script. + */ +final class CompiledScript implements Serializable { + + /** Main class name. */ + private final String mainClassName; + + /** Map of class names to class bytes. */ + private final Map classBytes; + + /** Constants array. */ + private final Object[] constants; + + /** The source */ + private transient Source source; + + private static final long serialVersionUID = 2958227232195298340L; + + /** + * Constructor. + * + * @param mainClassName main class name + * @param classBytes map of class names to class bytes + * @param constants constants array + */ + CompiledScript(final Source source, final String mainClassName, final Map classBytes, final Object[] constants) { + this.source = source; + this.mainClassName = mainClassName; + this.classBytes = classBytes; + this.constants = constants; + } + + /** + * Returns the main class name. + * @return the main class name + */ + public String getMainClassName() { + return mainClassName; + } + + /** + * Returns a map of class names to class bytes. + * @return map of class bytes + */ + public Map getClassBytes() { + return classBytes; + } + + /** + * Returns the constants array. + * @return constants array + */ + public Object[] getConstants() { + return constants; + } + + /** + * Returns the source of this cached script. + * @return the source + */ + public Source getSource() { + return source; + } + + /** + * Sets the source of this cached script. + * @param source the source + */ + void setSource(final Source source) { + this.source = source; + } + + @Override + public int hashCode() { + int hash = mainClassName.hashCode(); + hash = 31 * hash + classBytes.hashCode(); + hash = 31 * hash + Arrays.hashCode(constants); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof CompiledScript)) { + return false; + } + + final CompiledScript cs = (CompiledScript) obj; + return mainClassName.equals(cs.mainClassName) + && classBytes.equals(cs.classBytes) + && Arrays.equals(constants, cs.constants); + } +} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index f3ec08757d1..19c5c5c1036 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -25,7 +25,9 @@ package jdk.nashorn.internal.runtime; +import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT; +import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; @@ -38,6 +40,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; @@ -47,7 +50,10 @@ import java.security.CodeSigner; import java.security.CodeSource; import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; @@ -133,8 +139,32 @@ public final class Context { } @Override - public Class install(final String className, final byte[] bytecode) { - return loader.installClass(className, bytecode, codeSource); + public Class install(final String className, final byte[] bytecode, final Source source, final Object[] constants) { + Compiler.LOG.fine("Installing class ", className); + + final String binaryName = Compiler.binaryName(className); + final Class clazz = loader.installClass(binaryName, bytecode, codeSource); + + try { + // Need doPrivileged because these fields are private + AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + //use reflection to write source and constants table to installed classes + final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName()); + final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName()); + sourceField.setAccessible(true); + constantsField.setAccessible(true); + sourceField.set(null, source); + constantsField.set(null, constants); + return null; + } + }); + } catch (final PrivilegedActionException e) { + throw new RuntimeException(e); + } + + return clazz; } @Override @@ -151,6 +181,18 @@ public final class Context { public long getUniqueEvalId() { return context.getUniqueEvalId(); } + + @Override + public void storeCompiledScript(final Source source, final String mainClassName, + final Map classBytes, final Object[] constants) { + if (context.codeStore != null) { + try { + context.codeStore.putScript(source, mainClassName, classBytes, constants); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + } } /** Is Context global debug mode enabled ? */ @@ -158,9 +200,12 @@ public final class Context { private static final ThreadLocal currentGlobal = new ThreadLocal<>(); - // class cache + // in-memory cache for loaded classes private ClassCache classCache; + // persistent code store + private CodeStore codeStore; + /** * Get the current global scope * @return the current global scope @@ -368,6 +413,19 @@ public final class Context { classCache = new ClassCache(cacheSize); } + if (env._persistent_cache) { + if (env._lazy_compilation || env._specialize_calls != null) { + getErr().println("Can not use persistent class caching with lazy compilation or call specialization."); + } else { + try { + final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"); + codeStore = new CodeStore(cacheDir); + } catch (IOException e) { + throw new RuntimeException("Error initializing code cache", e); + } + } + } + // print version info if asked. if (env._version) { getErr().println("nashorn " + Version.version()); @@ -932,17 +990,32 @@ public final class Context { return script; } - final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse(); - if (errors.hasErrors()) { - return null; + CompiledScript compiledScript = null; + FunctionNode functionNode = null; + + if (!env._parse_only && codeStore != null) { + try { + compiledScript = codeStore.getScript(source); + } catch (IOException | ClassNotFoundException e) { + Compiler.LOG.warning("Error loading ", source, " from cache: ", e); + // Fall back to normal compilation + } } - if (env._print_ast) { - getErr().println(new ASTWriter(functionNode)); - } + if (compiledScript == null) { + functionNode = new Parser(env, source, errMan, strict).parse(); - if (env._print_parse) { - getErr().println(new PrintVisitor(functionNode)); + if (errors.hasErrors()) { + return null; + } + + if (env._print_ast) { + getErr().println(new ASTWriter(functionNode)); + } + + if (env._print_parse) { + getErr().println(new PrintVisitor(functionNode)); + } } if (env._parse_only) { @@ -954,12 +1027,15 @@ public final class Context { final CodeSource cs = new CodeSource(url, (CodeSigner[])null); final CodeInstaller installer = new ContextCodeInstaller(this, loader, cs); - final Compiler compiler = new Compiler(installer, strict); + if (functionNode != null) { + final Compiler compiler = new Compiler(installer, strict); + final FunctionNode newFunctionNode = compiler.compile(functionNode); + script = compiler.install(newFunctionNode); + } else { + script = install(compiledScript, installer); + } - final FunctionNode newFunctionNode = compiler.compile(functionNode); - script = compiler.install(newFunctionNode); cacheClass(source, script); - return script; } @@ -981,6 +1057,42 @@ public final class Context { return uniqueScriptId.getAndIncrement(); } + + /** + * Install a previously compiled class from the code cache. + * + * @param compiledScript cached script containing class bytes and constants + * @return main script class + */ + private Class install(final CompiledScript compiledScript, final CodeInstaller installer) { + + final Map> installedClasses = new HashMap<>(); + final Source source = compiledScript.getSource(); + final Object[] constants = compiledScript.getConstants(); + final String rootClassName = compiledScript.getMainClassName(); + final byte[] rootByteCode = compiledScript.getClassBytes().get(rootClassName); + final Class rootClass = installer.install(rootClassName, rootByteCode, source, constants); + + installedClasses.put(rootClassName, rootClass); + + for (final Map.Entry entry : compiledScript.getClassBytes().entrySet()) { + final String className = entry.getKey(); + if (className.equals(rootClassName)) { + continue; + } + final byte[] code = entry.getValue(); + + installedClasses.put(className, installer.install(className, code, source, constants)); + } + for (Object constant : constants) { + if (constant instanceof RecompilableScriptFunctionData) { + ((RecompilableScriptFunctionData) constant).setCodeAndSource(installedClasses, source); + } + } + + return rootClass; + } + /** * Cache for compiled script classes. */ diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk/nashorn/internal/runtime/Property.java index 885fa712a13..b3f1e0af48d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java @@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE; import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.util.Objects; import jdk.nashorn.internal.codegen.ObjectClassGenerator; @@ -43,7 +44,7 @@ import jdk.nashorn.internal.codegen.types.Type; * @see AccessorProperty * @see UserAccessorProperty */ -public abstract class Property { +public abstract class Property implements Serializable { /* * ECMA 8.6.1 Property Attributes * @@ -100,6 +101,8 @@ public abstract class Property { /** Property field number or spill slot. */ private final int slot; + private static final long serialVersionUID = 2099814273074501176L; + /** * Constructor * @@ -357,6 +360,13 @@ public abstract class Property { */ public abstract MethodHandle getGetter(final Class type); + /** + * Hook to initialize method handles after deserialization. + * + * @param structure the structure class + */ + abstract void initMethodHandles(final Class structure); + /** * Get the key for this property. This key is an ordinary string. The "name". * @return key for property diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 77bcc83fea3..e2e07fdf2fc 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -29,6 +29,10 @@ import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.lang.invoke.SwitchPoint; import java.lang.ref.SoftReference; import java.util.Arrays; @@ -37,6 +41,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.WeakHashMap; +import jdk.nashorn.internal.scripts.JO; /** * Map of object properties. The PropertyMap is the "template" for JavaScript object @@ -47,7 +52,7 @@ import java.util.WeakHashMap; * All property maps are immutable. If a property is added, modified or removed, the mutator * will return a new map. */ -public final class PropertyMap implements Iterable { +public final class PropertyMap implements Iterable, Serializable { /** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */ public static final int NOT_EXTENSIBLE = 0b0000_0001; /** Does this map contain valid array keys? */ @@ -57,7 +62,7 @@ public final class PropertyMap implements Iterable { private int flags; /** Map of properties. */ - private final PropertyHashMap properties; + private transient PropertyHashMap properties; /** Number of fields in use. */ private int fieldCount; @@ -68,17 +73,22 @@ public final class PropertyMap implements Iterable { /** Length of spill in use. */ private int spillLength; + /** Structure class name */ + private String className; + /** {@link SwitchPoint}s for gets on inherited properties. */ - private HashMap protoGetSwitches; + private transient HashMap protoGetSwitches; /** History of maps, used to limit map duplication. */ - private WeakHashMap> history; + private transient WeakHashMap> history; /** History of prototypes, used to limit map duplication. */ - private WeakHashMap> protoHistory; + private transient WeakHashMap> protoHistory; /** property listeners */ - private PropertyListeners listeners; + private transient PropertyListeners listeners; + + private static final long serialVersionUID = -7041836752008732533L; /** * Constructor. @@ -89,8 +99,10 @@ public final class PropertyMap implements Iterable { * @param spillLength Number of spill slots used. * @param containsArrayKeys True if properties contain numeric keys */ - private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) { + private PropertyMap(final PropertyHashMap properties, final String className, final int fieldCount, + final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) { this.properties = properties; + this.className = className; this.fieldCount = fieldCount; this.fieldMaximum = fieldMaximum; this.spillLength = spillLength; @@ -145,7 +157,25 @@ public final class PropertyMap implements Iterable { if (Context.DEBUG) { duplicatedCount++; } - return new PropertyMap(this.properties, 0, 0, 0, containsArrayKeys()); + return new PropertyMap(this.properties, this.className, 0, 0, 0, containsArrayKeys()); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(properties.getProperties()); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + + final Property[] props = (Property[]) in.readObject(); + this.properties = EMPTY_HASHMAP.immutableAdd(props); + + assert className != null; + final Class structure = Context.forStructureClass(className); + for (Property prop : props) { + prop.initMethodHandles(structure); + } } /** @@ -160,9 +190,9 @@ public final class PropertyMap implements Iterable { * @param spillLength Number of used spill slots. * @return New {@link PropertyMap}. */ - public static PropertyMap newMap(final Collection properties, final int fieldCount, final int fieldMaximum, final int spillLength) { + public static PropertyMap newMap(final Collection properties, final String className, final int fieldCount, final int fieldMaximum, final int spillLength) { PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties); - return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength, false); + return new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength, false); } /** @@ -175,7 +205,7 @@ public final class PropertyMap implements Iterable { * @return New {@link PropertyMap}. */ public static PropertyMap newMap(final Collection properties) { - return (properties == null || properties.isEmpty())? newMap() : newMap(properties, 0, 0, 0); + return (properties == null || properties.isEmpty())? newMap() : newMap(properties, JO.class.getName(), 0, 0, 0); } /** @@ -184,7 +214,7 @@ public final class PropertyMap implements Iterable { * @return New empty {@link PropertyMap}. */ public static PropertyMap newMap() { - return new PropertyMap(EMPTY_HASHMAP, 0, 0, 0, false); + return new PropertyMap(EMPTY_HASHMAP, JO.class.getName(), 0, 0, 0, false); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 7e1a516aa6d..9088544454a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -27,14 +27,15 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.lookup.Lookup.MH; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; +import java.util.Map; import jdk.internal.dynalink.support.NameCodec; - import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.FunctionSignature; @@ -43,6 +44,7 @@ import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.TokenType; +import jdk.nashorn.internal.scripts.JS; /** * This is a subclass that represents a script function that may be regenerated, @@ -50,13 +52,19 @@ import jdk.nashorn.internal.parser.TokenType; * The common denominator is that it can get new invokers during its lifespan, * unlike {@code FinalScriptFunctionData} */ -public final class RecompilableScriptFunctionData extends ScriptFunctionData { +public final class RecompilableScriptFunctionData extends ScriptFunctionData implements Serializable { /** FunctionNode with the code for this ScriptFunction */ - private FunctionNode functionNode; + private transient FunctionNode functionNode; /** Source from which FunctionNode was parsed. */ - private final Source source; + private transient Source source; + + /** The line number where this function begins. */ + private final int lineNumber; + + /** Allows us to retrieve the method handle for this function once the code is compiled */ + private MethodLocator methodLocator; /** Token of this function within the source. */ private final long token; @@ -65,13 +73,13 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { private final PropertyMap allocatorMap; /** Code installer used for all further recompilation/specialization of this ScriptFunction */ - private CodeInstaller installer; + private transient CodeInstaller installer; /** Name of class where allocator function resides */ private final String allocatorClassName; /** lazily generated allocator */ - private MethodHandle allocator; + private transient MethodHandle allocator; private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); @@ -79,7 +87,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * Used for specialization based on runtime arguments. Whenever we specialize on * callsite parameter types at runtime, we need to use a parameter type guard to * ensure that the specialized version of the script function continues to be - * applicable for a particular callsite * + * applicable for a particular callsite. */ private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Object[].class); @@ -88,10 +96,12 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * (or java.lang.Number instance) to specialize the parameter to an integer, if the * parameter in question can be represented as one. The double typically only exists * because the compiler doesn't know any better than "a number type" and conservatively - * picks doubles when it can't prove that an integer addition wouldn't overflow + * picks doubles when it can't prove that an integer addition wouldn't overflow. */ private static final MethodHandle ENSURE_INT = findOwnMH("ensureInt", int.class, Object.class); + private static final long serialVersionUID = 4914839316174633726L; + /** * Constructor - public as scripts use it * @@ -104,13 +114,16 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { super(functionName(functionNode), functionNode.getParameters().size(), getFlags(functionNode)); - this.functionNode = functionNode; this.source = functionNode.getSource(); + this.lineNumber = functionNode.getLineNumber(); this.token = tokenFor(functionNode); this.installer = installer; this.allocatorClassName = allocatorClassName; this.allocatorMap = allocatorMap; + if (!functionNode.isLazy()) { + methodLocator = new MethodLocator(functionNode); + } } @Override @@ -122,16 +135,19 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { return "function " + (name == null ? "" : name) + "() { [native code] }"; } + public void setCodeAndSource(final Map> code, final Source source) { + this.source = source; + if (methodLocator != null) { + methodLocator.setClass(code.get(methodLocator.getClassName())); + } + } + @Override public String toString() { final StringBuilder sb = new StringBuilder(); if (source != null) { - sb.append(source.getName()); - if (functionNode != null) { - sb.append(':').append(functionNode.getLineNumber()); - } - sb.append(' '); + sb.append(source.getName()).append(':').append(lineNumber).append(' '); } return sb.toString() + super.toString(); @@ -204,8 +220,13 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { functionNode = compiler.compile(functionNode); assert !functionNode.isLazy(); compiler.install(functionNode); + methodLocator = new MethodLocator(functionNode); flags = getFlags(functionNode); } + + if (functionNode != null) { + methodLocator.setClass(functionNode.getCompileUnit().getCode()); + } } @Override @@ -221,12 +242,13 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * eager compilation or from running a lazy compile on the lines above */ - assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); + assert functionNode == null || functionNode.hasState(CompilationState.EMITTED) : + functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); // code exists - look it up and add it into the automatically sorted invoker list addCode(functionNode); - if (! functionNode.canSpecialize()) { + if (functionNode != null && !functionNode.canSpecialize()) { // allow GC to claim IR stuff that is not needed anymore functionNode = null; installer = null; @@ -238,13 +260,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { } private MethodHandle addCode(final FunctionNode fn, final MethodType runtimeType, final MethodHandle guard, final MethodHandle fallback) { - final MethodType targetType = new FunctionSignature(fn).getMethodType(); - MethodHandle target = - MH.findStatic( - LOOKUP, - fn.getCompileUnit().getCode(), - fn.getName(), - targetType); + assert methodLocator != null; + MethodHandle target = methodLocator.getMethodHandle(); + final MethodType targetType = methodLocator.getMethodType(); /* * For any integer argument. a double that is representable as an integer is OK. @@ -424,7 +442,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { Compiler.LOG.info("Callsite specialized ", name, " runtimeType=", runtimeType, " parameters=", snapshot.getParameters(), " args=", Arrays.asList(args)); - assert snapshot != null; assert snapshot != functionNode; final Compiler compiler = new Compiler(installer); @@ -450,5 +467,45 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types)); } + /** + * Helper class that allows us to retrieve the method handle for this function once it has been generated. + */ + private static class MethodLocator implements Serializable { + private transient Class clazz; + private final String className; + private final String methodName; + private final MethodType methodType; + + private static final long serialVersionUID = -5420835725902966692L; + + MethodLocator(final FunctionNode functionNode) { + this.className = functionNode.getCompileUnit().getUnitClassName(); + this.methodName = functionNode.getName(); + this.methodType = new FunctionSignature(functionNode).getMethodType(); + + assert className != null; + assert methodName != null; + } + + void setClass(final Class clazz) { + if (!JS.class.isAssignableFrom(clazz)) { + throw new IllegalArgumentException(); + } + this.clazz = clazz; + } + + String getClassName() { + return className; + } + + MethodType getMethodType() { + return methodType; + } + + MethodHandle getMethodHandle() { + return MH.findStatic(LOOKUP, clazz, methodName, methodType); + } + } + } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index 5327471051a..96982011dbe 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -134,6 +134,9 @@ public final class ScriptEnvironment { /** Only parse the source code, do not compile */ public final boolean _parse_only; + /** Enable disk cache for compiled scripts */ + public final boolean _persistent_cache; + /** Print the AST before lowering */ public final boolean _print_ast; @@ -218,6 +221,7 @@ public final class ScriptEnvironment { _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); _no_typed_arrays = options.getBoolean("no.typed.arrays"); _parse_only = options.getBoolean("parse.only"); + _persistent_cache = options.getBoolean("persistent.code.cache"); _print_ast = options.getBoolean("print.ast"); _print_lower_ast = options.getBoolean("print.lower.ast"); _print_code = options.getBoolean("print.code"); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index aee367d65ba..ad40d622d7e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -29,10 +29,10 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; +import java.io.Serializable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; /** @@ -40,7 +40,7 @@ import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; * Instances of this class are created during codegen and stored in script classes' * constants array to reduce function instantiation overhead during runtime. */ -public abstract class ScriptFunctionData { +public abstract class ScriptFunctionData implements Serializable { /** Name of the function or "" for anonynous functions */ protected final String name; @@ -74,6 +74,8 @@ public abstract class ScriptFunctionData { /** Flag for strict constructors */ public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR; + private static final long serialVersionUID = 4252901245508769114L; + /** * Constructor * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Source.java b/nashorn/src/jdk/nashorn/internal/runtime/Source.java index 0455a86c6d2..f57874bc18f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java @@ -39,6 +39,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Objects; import jdk.nashorn.internal.parser.Token; @@ -71,6 +73,9 @@ public final class Source { /** Cached hash code */ private int hash; + /** Message digest */ + private byte[] digest; + /** Source URL if available */ private final URL url; @@ -416,6 +421,40 @@ public final class Source { return readFully(url.openStream(), cs); } + /** + * Get a message digest for this source. + * + * @return a message digest for this source + */ + public synchronized byte[] getDigest() { + if (digest == null) { + + final byte[] bytes = new byte[content.length * 2]; + + for (int i = 0; i < content.length; i++) { + bytes[i * 2] = (byte) (content[i] & 0x00ff); + bytes[i * 2 + 1] = (byte) ((content[i] & 0xff00) >> 8); + } + + try { + final MessageDigest md = MessageDigest.getInstance("SHA-1"); + if (name != null) { + md.update(name.getBytes(StandardCharsets.UTF_8)); + } + if (base != null) { + md.update(base.getBytes(StandardCharsets.UTF_8)); + } + if (url != null) { + md.update(url.toString().getBytes(StandardCharsets.UTF_8)); + } + digest = md.digest(bytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + return digest; + } + /** * Get the base url. This is currently used for testing only * @param url a URL diff --git a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java index a69de45ca3d..5b21f6eea91 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java @@ -186,6 +186,11 @@ public final class UserAccessorProperty extends Property { return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type); } + @Override + void initMethodHandles(final Class structure) { + throw new UnsupportedOperationException(); + } + @Override public ScriptFunction getGetterFunction(final ScriptObject obj) { final Object value = obj.getSpill(getterSlot); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties index 2726211151a..033fcc2546e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties @@ -230,6 +230,14 @@ nashorn.option.parse.only = { \ desc="Parse without compiling." \ } +nashorn.option.persistent.code.cache = { \ + name="--persistent-code-cache", \ + short_name="-pcc", \ + desc="Enable disk cache for compiled scripts.", \ + is_undocumented=true, \ + default=false \ +} + nashorn.option.profile.callsites = { \ name="--profile-callsites", \ short_name="-pcs", \ From 011792fa3448cd3681fe34773fddca0f91bddb09 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Wed, 2 Apr 2014 18:21:23 +0100 Subject: [PATCH 114/170] 8035618: Four api/org_omg/CORBA TCK tests fail under plugin only Reviewed-by: alanb, mchung, dfuchs, msheppar --- .../classes/com/sun/corba/se/spi/orb/ORB.java | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java index 91a691e2b25..e837a6d6878 100644 --- a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java +++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, 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 @@ -97,8 +97,7 @@ import com.sun.corba.se.impl.logging.OMGSystemException ; import com.sun.corba.se.impl.presentation.rmi.PresentationManagerImpl ; -import sun.awt.AppContext; -import sun.corba.SharedSecrets; +import sun.misc.JavaAWTAccess; public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB implements Broker, TypeCodeFactory @@ -170,6 +169,13 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB // representing LogDomain and ExceptionGroup. private Map wrapperMap ; + static class Holder { + static final PresentationManager defaultPresentationManager = + setupPresentationManager(); + } + + private static final Map pmContexts = new HashMap<>(); + private static Map staticWrapperMap = new ConcurrentHashMap(); protected MonitoringManager monitoringManager; @@ -201,8 +207,9 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB try { // First try the configured class name, if any - Class cls = SharedSecrets.getJavaCorbaAccess().loadClass( className ) ; - sff = (PresentationManager.StubFactoryFactory)cls.newInstance() ; + Class cls = + sun.corba.SharedSecrets.getJavaCorbaAccess().loadClass(className); + sff = (PresentationManager.StubFactoryFactory)cls.newInstance(); } catch (Exception exc) { // Use the default. Log the error as a warning. staticWrapper.errorInSettingDynamicStubFactoryFactory( @@ -235,13 +242,24 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB */ public static PresentationManager getPresentationManager() { - AppContext ac = AppContext.getAppContext(); - PresentationManager pm = (PresentationManager) ac.get(PresentationManager.class); - if (pm == null) { - pm = setupPresentationManager(); - ac.put(PresentationManager.class, pm); + SecurityManager sm = System.getSecurityManager(); + JavaAWTAccess javaAwtAccess = sun.misc.SharedSecrets.getJavaAWTAccess(); + if (sm != null && javaAwtAccess != null) { + final Object appletContext = javaAwtAccess.getAppletContext(); + if (appletContext != null) { + synchronized (pmContexts) { + PresentationManager pm = pmContexts.get(appletContext); + if (pm == null) { + pm = setupPresentationManager(); + pmContexts.put(appletContext, pm); + } + return pm; + } + } } - return pm; + + // No security manager or AppletAppContext + return Holder.defaultPresentationManager; } /** Get the appropriate StubFactoryFactory. This From dd193f4eb2debd81a09c886e30a85199c395d324 Mon Sep 17 00:00:00 2001 From: Alexander Smundak Date: Wed, 2 Apr 2014 11:24:44 -0700 Subject: [PATCH 115/170] 8036767: PPC64: Support for little endian execution model Reviewed-by: goetz, kvn, dholmes, simonis --- hotspot/make/linux/Makefile | 4 +- hotspot/make/linux/makefiles/defs.make | 5 + hotspot/make/linux/makefiles/ppc64.make | 28 ++-- hotspot/src/cpu/ppc/vm/assembler_ppc.hpp | 11 +- hotspot/src/cpu/ppc/vm/bytes_ppc.hpp | 126 ++++++++++++++++++ hotspot/src/os/linux/vm/os_linux.cpp | 4 + .../linux_ppc/vm/bytes_linux_ppc.inline.hpp | 39 ++++++ 7 files changed, 201 insertions(+), 16 deletions(-) create mode 100644 hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index 8321f8e15db..df450934810 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -66,8 +66,8 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif -# C1 is not ported on ppc64(le), so we cannot build a tiered VM: -ifneq (,$(filter $(ARCH),ppc64 pp64le)) +# C1 is not ported on ppc64, so we cannot build a tiered VM: +ifeq ($(ARCH),ppc64) FORCE_TIERED=0 endif diff --git a/hotspot/make/linux/makefiles/defs.make b/hotspot/make/linux/makefiles/defs.make index 377d4f9c59f..8922fdd8728 100644 --- a/hotspot/make/linux/makefiles/defs.make +++ b/hotspot/make/linux/makefiles/defs.make @@ -33,6 +33,11 @@ SLASH_JAVA ?= /java # ARCH can be set explicitly in spec.gmk ifndef ARCH ARCH := $(shell uname -m) + # Fold little endian PowerPC64 into big-endian (if ARCH is set in + # hotspot-spec.gmk, this will be done by the configure script). + ifeq ($(ARCH),ppc64le) + ARCH := ppc64 + endif endif PATH_SEP ?= : diff --git a/hotspot/make/linux/makefiles/ppc64.make b/hotspot/make/linux/makefiles/ppc64.make index b3e6f27b65e..f3392de49a6 100644 --- a/hotspot/make/linux/makefiles/ppc64.make +++ b/hotspot/make/linux/makefiles/ppc64.make @@ -26,14 +26,26 @@ # make c code know it is on a 64 bit platform. CFLAGS += -D_LP64=1 -# fixes `relocation truncated to fit' error for gcc 4.1. -CFLAGS += -mminimal-toc +ifeq ($(origin OPENJDK_TARGET_CPU_ENDIAN),undefined) + # This can happen during hotspot standalone build. Set endianness from + # uname. We assume build and target machines are the same. + OPENJDK_TARGET_CPU_ENDIAN:=$(if $(filter ppc64le,$(shell uname -m)),little,big) +endif -# finds use ppc64 instructions, but schedule for power5 -CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +ifeq ($(filter $(OPENJDK_TARGET_CPU_ENDIAN),big little),) + $(error OPENJDK_TARGET_CPU_ENDIAN value should be 'big' or 'little') +endif -# let linker find external 64 bit libs. -LFLAGS_VM += -L/lib64 +ifeq ($(OPENJDK_TARGET_CPU_ENDIAN),big) + # fixes `relocation truncated to fit' error for gcc 4.1. + CFLAGS += -mminimal-toc -# specify lib format. -LFLAGS_VM += -Wl,-melf64ppc + # finds use ppc64 instructions, but schedule for power5 + CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +else + # Little endian machine uses ELFv2 ABI. + CFLAGS += -DVM_LITTLE_ENDIAN -DABI_ELFv2 + + # Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI. + CFLAGS += -mcpu=power7 -mtune=power8 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string +endif diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 56b0b92db73..5a1c0f1d9c8 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -1025,15 +1025,14 @@ class Assembler : public AbstractAssembler { } static void set_imm(int* instr, short s) { - short* p = ((short *)instr) + 1; - *p = s; + // imm is always in the lower 16 bits of the instruction, + // so this is endian-neutral. Same for the get_imm below. + uint32_t w = *(uint32_t *)instr; + *instr = (int)((w & ~0x0000FFFF) | (s & 0x0000FFFF)); } static int get_imm(address a, int instruction_number) { - short imm; - short *p =((short *)a)+2*instruction_number+1; - imm = *p; - return (int)imm; + return (short)((int *)a)[instruction_number]; } static inline int hi16_signed( int x) { return (int)(int16_t)(x >> 16); } diff --git a/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp b/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp index 872aa6b2624..2a8fc59c892 100644 --- a/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/bytes_ppc.hpp @@ -35,6 +35,126 @@ class Bytes: AllStatic { // Can I count on address always being a pointer to an unsigned char? Yes. +#if defined(VM_LITTLE_ENDIAN) + + // Returns true, if the byte ordering used by Java is different from the native byte ordering + // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc. + static inline bool is_Java_byte_ordering_different() { return true; } + + // Forward declarations of the compiler-dependent implementation + static inline u2 swap_u2(u2 x); + static inline u4 swap_u4(u4 x); + static inline u8 swap_u8(u8 x); + + static inline u2 get_native_u2(address p) { + return (intptr_t(p) & 1) == 0 + ? *(u2*)p + : ( u2(p[1]) << 8 ) + | ( u2(p[0]) ); + } + + static inline u4 get_native_u4(address p) { + switch (intptr_t(p) & 3) { + case 0: return *(u4*)p; + + case 2: return ( u4( ((u2*)p)[1] ) << 16 ) + | ( u4( ((u2*)p)[0] ) ); + + default: return ( u4(p[3]) << 24 ) + | ( u4(p[2]) << 16 ) + | ( u4(p[1]) << 8 ) + | u4(p[0]); + } + } + + static inline u8 get_native_u8(address p) { + switch (intptr_t(p) & 7) { + case 0: return *(u8*)p; + + case 4: return ( u8( ((u4*)p)[1] ) << 32 ) + | ( u8( ((u4*)p)[0] ) ); + + case 2: return ( u8( ((u2*)p)[3] ) << 48 ) + | ( u8( ((u2*)p)[2] ) << 32 ) + | ( u8( ((u2*)p)[1] ) << 16 ) + | ( u8( ((u2*)p)[0] ) ); + + default: return ( u8(p[7]) << 56 ) + | ( u8(p[6]) << 48 ) + | ( u8(p[5]) << 40 ) + | ( u8(p[4]) << 32 ) + | ( u8(p[3]) << 24 ) + | ( u8(p[2]) << 16 ) + | ( u8(p[1]) << 8 ) + | u8(p[0]); + } + } + + + + static inline void put_native_u2(address p, u2 x) { + if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x; + else { + p[1] = x >> 8; + p[0] = x; + } + } + + static inline void put_native_u4(address p, u4 x) { + switch ( intptr_t(p) & 3 ) { + case 0: *(u4*)p = x; + break; + + case 2: ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + + static inline void put_native_u8(address p, u8 x) { + switch ( intptr_t(p) & 7 ) { + case 0: *(u8*)p = x; + break; + + case 4: ((u4*)p)[1] = x >> 32; + ((u4*)p)[0] = x; + break; + + case 2: ((u2*)p)[3] = x >> 48; + ((u2*)p)[2] = x >> 32; + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: ((u1*)p)[7] = x >> 56; + ((u1*)p)[6] = x >> 48; + ((u1*)p)[5] = x >> 40; + ((u1*)p)[4] = x >> 32; + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + } + } + + // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) + // (no byte-order reversal is needed since Power CPUs are big-endian oriented). + static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); } + static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); } + static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); } + + static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); } + static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); } + static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); } + +#else // !defined(VM_LITTLE_ENDIAN) + // Returns true, if the byte ordering used by Java is different from the nativ byte ordering // of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc. static inline bool is_Java_byte_ordering_different() { return false; } @@ -150,6 +270,12 @@ class Bytes: AllStatic { static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } + +#endif // VM_LITTLE_ENDIAN }; +#if defined(TARGET_OS_ARCH_linux_ppc) +#include "bytes_linux_ppc.inline.hpp" +#endif + #endif // CPU_PPC_VM_BYTES_PPC_HPP diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 77dfc54bd7b..2d3cf35bea5 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1963,7 +1963,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, +#if defined(VM_LITTLE_ENDIAN) + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"}, +#else {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, +#endif {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, {EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"}, {EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"}, diff --git a/hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp b/hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp new file mode 100644 index 00000000000..d1a9e98d677 --- /dev/null +++ b/hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Google Inc. 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 OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP +#define OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP + +#if defined(VM_LITTLE_ENDIAN) +#include + +// Efficient swapping of data bytes from Java byte +// ordering to native byte ordering and vice versa. +inline u2 Bytes::swap_u2(u2 x) { return bswap_16(x); } +inline u4 Bytes::swap_u4(u4 x) { return bswap_32(x); } +inline u8 Bytes::swap_u8(u8 x) { return bswap_64(x); } +#endif // VM_LITTLE_ENDIAN + +#endif // OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP From 6428c0a397d3c136c87877e85ea2d004cfe3fe9b Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Wed, 2 Apr 2014 11:24:51 -0700 Subject: [PATCH 116/170] 8039043: Implicit null check is in the wrong place in C1 -UseCompressedOops Null check is placed in a wrong place when storing a null to an object field on x64 with compressed oops off Reviewed-by: roland, vlivanov, kvn --- .../src/cpu/x86/vm/c1_LIRAssembler_x86.cpp | 6 ++ .../codegen/C1NullCheckOfNullStore.java | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 39c130fdf06..d6dff7bb47a 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -799,7 +799,13 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi if (UseCompressedOops && !wide) { __ movl(as_Address(addr), (int32_t)NULL_WORD); } else { +#ifdef _LP64 + __ xorptr(rscratch1, rscratch1); + null_check_here = code_offset(); + __ movptr(as_Address(addr), rscratch1); +#else __ movptr(as_Address(addr), NULL_WORD); +#endif } } else { if (is_literal_address(addr)) { diff --git a/hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java b/hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java new file mode 100644 index 00000000000..0bec2c1ab42 --- /dev/null +++ b/hotspot/test/compiler/codegen/C1NullCheckOfNullStore.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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 8039043 + * @summary Null check is placed in a wrong place when storing a null to an object field on x64 with compressed oops off + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CompileCommand=compileonly,C1NullCheckOfNullStore::test -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-UseCompressedOops C1NullCheckOfNullStore + * + */ + +public class C1NullCheckOfNullStore { + private static class Foo { + Object bar; + } + static private void test(Foo x) { + x.bar = null; + } + static public void main(String args[]) { + Foo x = new Foo(); + for (int i = 0; i < 10000; i++) { + test(x); + } + boolean gotNPE = false; + try { + for (int i = 0; i < 10000; i++) { + test(null); + } + } + catch(NullPointerException e) { + gotNPE = true; + } + if (!gotNPE) { + throw new Error("Expecting a NullPointerException"); + } + } +} From e6e9f14a7285698a0f7ffd578dc29692d452086d Mon Sep 17 00:00:00 2001 From: Alexander Smundak Date: Wed, 2 Apr 2014 11:28:32 -0700 Subject: [PATCH 117/170] 8036767: PPC64: Support for little endian execution model Reviewed-by: ihse, erikj, simonis --- common/autoconf/build-aux/config.guess | 10 ++++++++++ common/autoconf/generated-configure.sh | 14 +++++++++++++- common/autoconf/platform.m4 | 6 ++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/common/autoconf/build-aux/config.guess b/common/autoconf/build-aux/config.guess index b0c03a79629..355c91e4ebb 100644 --- a/common/autoconf/build-aux/config.guess +++ b/common/autoconf/build-aux/config.guess @@ -76,4 +76,14 @@ if test $? = 0; then OUT=powerpc$KERNEL_BITMODE`echo $OUT | sed -e 's/[^-]*//'` fi +# Test and fix little endian PowerPC64. +# TODO: should be handled by autoconf-config.guess. +if [ "x$OUT" = x ]; then + if [ `uname -m` = ppc64le ]; then + if [ `uname -s` = Linux ]; then + OUT=powerpc64le-unknown-linux-gnu + fi + fi +fi + echo $OUT diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 6b7a52bd273..9c41329657c 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -4233,7 +4233,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1395652496 +DATE_WHEN_GENERATED=1396463189 ############################################################################### # @@ -13508,6 +13508,12 @@ test -n "$target_alias" && VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + powerpc64le) + VAR_CPU=ppc64 + VAR_CPU_ARCH=ppc + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; s390) VAR_CPU=s390 VAR_CPU_ARCH=s390 @@ -13633,6 +13639,12 @@ $as_echo "$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU" >&6; } VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + powerpc64le) + VAR_CPU=ppc64 + VAR_CPU_ARCH=ppc + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; s390) VAR_CPU=s390 VAR_CPU_ARCH=s390 diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index d1b1573b101..1f06f0ce7d5 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -60,6 +60,12 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_CPU], VAR_CPU_BITS=64 VAR_CPU_ENDIAN=big ;; + powerpc64le) + VAR_CPU=ppc64 + VAR_CPU_ARCH=ppc + VAR_CPU_BITS=64 + VAR_CPU_ENDIAN=little + ;; s390) VAR_CPU=s390 VAR_CPU_ARCH=s390 From aa1964b8d6e39612d43b815589dac8e7f51968aa Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Wed, 2 Apr 2014 20:15:59 +0100 Subject: [PATCH 118/170] 8039108: Build Broken: 8035618 fix breaks corba build Reviewed-by: alanb --- .../share/classes/com/sun/corba/se/spi/orb/ORB.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java index e837a6d6878..a347f5d63f7 100644 --- a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java +++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java @@ -25,6 +25,8 @@ package com.sun.corba.se.spi.orb; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Map ; import java.util.HashMap ; import java.util.Properties ; @@ -245,7 +247,15 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB SecurityManager sm = System.getSecurityManager(); JavaAWTAccess javaAwtAccess = sun.misc.SharedSecrets.getJavaAWTAccess(); if (sm != null && javaAwtAccess != null) { - final Object appletContext = javaAwtAccess.getAppletContext(); + Object appletContext; + try { + Class clazz = JavaAWTAccess.class; + Method method = clazz.getMethod("getAppletContext"); + appletContext = method.invoke(javaAwtAccess); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new InternalError(e); + } + if (appletContext != null) { synchronized (pmContexts) { PresentationManager pm = pmContexts.get(appletContext); From 811be0cb68081ef58b1096de4b46205bf86cf89c Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Wed, 2 Apr 2014 21:45:26 +0100 Subject: [PATCH 119/170] 8039114: Build failure: JDK-8039108 issue Reviewed-by: alanb --- corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java index a347f5d63f7..a73a20b3d6c 100644 --- a/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java +++ b/corba/src/share/classes/com/sun/corba/se/spi/orb/ORB.java @@ -253,7 +253,9 @@ public abstract class ORB extends com.sun.corba.se.org.omg.CORBA.ORB Method method = clazz.getMethod("getAppletContext"); appletContext = method.invoke(javaAwtAccess); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new InternalError(e); + InternalError err = new InternalError(); + err.initCause(e); + throw err; } if (appletContext != null) { From 3df443cf36f26588d1fe376e178f0373d15856c6 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 21:59:39 -0700 Subject: [PATCH 120/170] Added tag jdk9-b07 for changeset ed0f4bbe852d --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index eccf997b9eb..b35a11c862e 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -249,3 +249,4 @@ fd8d51bdf9aadf7ae83e65e8655c53581017c363 jdk9-b03 cb4c3440bc2748101923e2488506e61009ab1bf5 jdk9-b04 8c63f0b6ada282f27e3a80125e53c3be603f9af7 jdk9-b05 d0b525cd31b87abeb6d5b7e3516953eeb13b323c jdk9-b06 +0ea015c298b201c07fa33990f2445b6d0ef3566d jdk9-b07 From c82a421d68cc01e5d26040d9b8220ee4ae83c16b Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 21:59:43 -0700 Subject: [PATCH 121/170] Added tag jdk9-b07 for changeset fd3ce35a9d5c --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index f152584aeb3..c34ef474c7d 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -249,3 +249,4 @@ d338b892a13db19b093f85cf5f949a4504e4d31f jdk9-b03 1ed19de263e1e0772da0269118cdd9deeb9fff04 jdk9-b04 167c39eb44731a5d66770d0f00e231164653a2ff jdk9-b05 a4bf701ac316946c2e5e83138ad8e687da6a4b30 jdk9-b06 +6c8563600a71394c949405189ddd66267a88d8cd jdk9-b07 From 299644b0397f6f6cf3eb587d5ed7a227b2348814 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 21:59:51 -0700 Subject: [PATCH 122/170] Added tag jdk9-b07 for changeset f00a1292f3ab --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 3e5fb22b551..856ce390fa1 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -409,3 +409,4 @@ b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03 3812c088b9456ee22c933e88aee1ece71f4e783a jdk9-b04 bdc5311e1db7598589b77015119b821bf8c828bd jdk9-b05 52377a30a3f87b62d6135706997b8c7a47366e37 jdk9-b06 +52f7edf2589d9f9d35db3008bc5377f279de9c18 jdk9-b07 From 34e1399df96a40e97b59514b1852bcb4c344d800 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 21:59:59 -0700 Subject: [PATCH 123/170] Added tag jdk9-b07 for changeset 8c109399a3da --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index ee71c38a814..e7dc2ecc96a 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -249,3 +249,4 @@ fb92ed0399424193f444489ad49a16748816dc12 jdk9-b03 2846d8fc31490897817a122a668af4f44fc913d0 jdk9-b04 b92a20e303d24c74078888cd7084b14d7626d48f jdk9-b05 46e4951b2a267e98341613a3b796f2c7554eb831 jdk9-b06 +389f4094fd603c17e215997b0b40171179629007 jdk9-b07 From b3c487bf854a57d74dfd024064354286fde0f5fb Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 22:00:00 -0700 Subject: [PATCH 124/170] Added tag jdk9-b07 for changeset 5d95c3684e9f --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 705ba65194d..a7525e9cd6a 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -252,3 +252,4 @@ efe2bc258c78af49de9517a4a5699d3a2e630c44 jdk9-b02 da44a8bdf1f3fdd518e7d785d60cc1b15983b176 jdk9-b04 eae966c8133fec0a8bf9e16d1274a4ede3c0fb52 jdk9-b05 cf0a6e41670f990414cd337000ad5f3bd1908073 jdk9-b06 +856a9132f506cafe2f251c1a16a0b14e4d16048d jdk9-b07 From c003df80e7f74df6f96324e93d66228746acfd6c Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 22:00:02 -0700 Subject: [PATCH 125/170] Added tag jdk9-b07 for changeset ddf6ebcc99da --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 11331a15a8e..118a09481e8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -249,3 +249,4 @@ d31cd980e1da31fa496a359caaf1a165aeb5791a jdk8-b120 627deed79b595a4789fc9151455b663a47381257 jdk9-b04 263198a1d8f1f4cb97d35f40c61704b08ebd3686 jdk9-b05 cac7b28b8b1e0e11d7a8e1ac1fe75a03b3749eab jdk9-b06 +f4e624447514f12dd7c51f1e5b0cb97efcd15be2 jdk9-b07 From cf7bfef8983b62418ecef675cfab1cc3f9b6f18b Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 22:00:13 -0700 Subject: [PATCH 126/170] Added tag jdk9-b07 for changeset a70a71ac79f3 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index f651ed43a29..0f2ed6e96c3 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -249,3 +249,4 @@ f2c58a337c8aaa1ce84dfa8a8e8c5d4c8c1e12fa jdk9-b02 fa2ec6b6b1697ae4a78b03b609664dc6b47dee86 jdk9-b04 1d5e6fc88a4cca287090c16b0530a0d5849a5603 jdk9-b05 31946c0a3f4dc2c78f6f09a0524aaa2a0dad1c78 jdk9-b06 +e25d44c21b29e155734f8d832f2edac3d0debe35 jdk9-b07 From e97f5d38184304eeb6c25f8341573a00c95cffbc Mon Sep 17 00:00:00 2001 From: David Katleman Date: Wed, 2 Apr 2014 22:00:15 -0700 Subject: [PATCH 127/170] Added tag jdk9-b07 for changeset dd19ff015a33 --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index c7e5d51e490..34584cf61e4 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -240,3 +240,4 @@ b3517e51f40477f10db8bc30a557aa0ea712c274 jdk9-b02 3f6ef92cd7823372c45e79125adba4cbf1c9f7b2 jdk9-b04 2a1cac93c33317d828d4a5b81239204a9927cc4a jdk9-b05 1f75bcbe74e315470dc0b75b7d5bcd209e287c39 jdk9-b06 +9a34d2a0a5bdaf0bf0d81d6fe6324aa0cfb35bfe jdk9-b07 From a9fb361904db715ae1e4e5547ff4dc61a3e353b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 3 Apr 2014 17:35:13 +0200 Subject: [PATCH 128/170] 8039181: Persistent code store does not use absolute paths internally Reviewed-by: sundar, lagergren --- .../src/jdk/nashorn/internal/runtime/CodeStore.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java index 1299c71f1f2..8f5959993cf 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -70,16 +70,16 @@ final class CodeStore { * @throws IOException */ public CodeStore(final String path, final int minSize) throws IOException { - this.dir = new File(path); + this.dir = checkDirectory(path); this.minSize = minSize; - checkDirectory(this.dir); } - private static void checkDirectory(final File dir) throws IOException { + private static File checkDirectory(final String path) throws IOException { try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override - public Void run() throws IOException { + public File run() throws IOException { + final File dir = new File(path).getAbsoluteFile(); if (!dir.exists() && !dir.mkdirs()) { throw new IOException("Could not create directory: " + dir); } else if (!dir.isDirectory()) { @@ -87,7 +87,7 @@ final class CodeStore { } else if (!dir.canRead() || !dir.canWrite()) { throw new IOException("Directory not readable or writable: " + dir); } - return null; + return dir; } }); } catch (PrivilegedActionException e) { From def40f4158dc7e255a84a02151f3c0c35a2f377d Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Thu, 3 Apr 2014 12:04:58 -0700 Subject: [PATCH 129/170] 8037881: javax.crypto is not listed in the compact* profiles javadoc Reviewed-by: jjg --- .../classes/com/sun/tools/javac/sym/Profiles.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java index fe36e9ff54a..daf84b948ca 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java +++ b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2014, 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 @@ -172,6 +172,14 @@ public abstract class Profiles { } } } + /* + * A hack to force javax/crypto package into the compact1 profile, + * because this package exists in jce.jar, and therefore not in + * ct.sym. Note javax/crypto should exist in a profile along with + * javax/net/ssl package. Thus, this package is added to compact1, + * implying that it should exist in all three profiles. + */ + includePackage(1, "javax/crypto"); } @Override From 73d4a30eded100d8a42afbbeee06f257f12eea7d Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 4 Apr 2014 18:36:16 -0700 Subject: [PATCH 130/170] 8039231: [javadoc] test failure caused by javax.crypto fix Reviewed-by: jjg --- .../share/classes/com/sun/tools/javac/sym/Profiles.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java index daf84b948ca..6591d95ba96 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java +++ b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java @@ -147,6 +147,8 @@ public abstract class Profiles { final int maxProfile = 4; // Three compact profiles plus full JRE MakefileProfiles(Properties p) { + // consider crypto, only if java/lang package exists + boolean foundJavaLang = false; for (int profile = 1; profile <= maxProfile; profile++) { String prefix = (profile < maxProfile ? "PROFILE_" + profile : "FULL_JRE"); String inclPackages = p.getProperty(prefix + "_RTJAR_INCLUDE_PACKAGES"); @@ -155,6 +157,8 @@ public abstract class Profiles { for (String pkg: inclPackages.substring(1).trim().split("\\s+")) { if (pkg.endsWith("/")) pkg = pkg.substring(0, pkg.length() - 1); + if (foundJavaLang == false && pkg.equals("java/lang")) + foundJavaLang = true; includePackage(profile, pkg); } String inclTypes = p.getProperty(prefix + "_RTJAR_INCLUDE_TYPES"); @@ -179,7 +183,8 @@ public abstract class Profiles { * javax/net/ssl package. Thus, this package is added to compact1, * implying that it should exist in all three profiles. */ - includePackage(1, "javax/crypto"); + if (foundJavaLang) + includePackage(1, "javax/crypto"); } @Override From 8e6660eb564f55aaadf1d501a87059f1aaded369 Mon Sep 17 00:00:00 2001 From: Paul Govereau Date: Fri, 4 Apr 2014 19:13:53 -0400 Subject: [PATCH 131/170] 8023945: javac wrongly allows a subclass of an anonymous class Reviewed-by: jjg --- .../com/sun/tools/javac/comp/Attr.java | 4 + .../tools/javac/resources/compiler.properties | 3 + .../tools/javac/AnonymousSubclassTest.java | 91 +++++++++++++++++++ .../tools/javac/diags/examples.not-yet.txt | 1 + 4 files changed, 99 insertions(+) create mode 100644 langtools/test/tools/javac/AnonymousSubclassTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 0234f252a7c..1db0f325214 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -804,6 +804,10 @@ public class Attr extends JCTree.Visitor { boolean classExpected, boolean interfaceExpected, boolean checkExtensible) { + if (t.tsym.isAnonymous()) { + log.error(tree.pos(), "cant.inherit.from.anon"); + return types.createErrorType(t); + } if (t.isErroneous()) return t; if (t.hasTag(TYPEVAR) && !classExpected && !interfaceExpected) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index bbaac453bc7..8f792bd15e8 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -123,6 +123,9 @@ compiler.err.anon.class.impl.intf.no.typeargs=\ compiler.err.anon.class.impl.intf.no.qual.for.new=\ anonymous class implements interface; cannot have qualifier for new +compiler.err.cant.inherit.from.anon=\ + cannot inherit from anonymous class + # 0: symbol, 1: symbol, 2: symbol compiler.err.array.and.varargs=\ cannot declare both {0} and {1} in {2} diff --git a/langtools/test/tools/javac/AnonymousSubclassTest.java b/langtools/test/tools/javac/AnonymousSubclassTest.java new file mode 100644 index 00000000000..6545c75b5f7 --- /dev/null +++ b/langtools/test/tools/javac/AnonymousSubclassTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, 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 8023945 + * @summary javac wrongly allows a subclass of an anonymous class + * @library /tools/javac/lib + * @build ToolBox + * @run main AnonymousSubclassTest + */ + +import java.util.ArrayList; +import java.io.IOException; + +public class AnonymousSubclassTest { + public static void main(String... args) throws Exception { + new AnonymousSubclassTest().run(); + } + + // To trigger the error we want, first we need to compile + // a class with an anonymous inner class: Foo$1. + final String foo = + "public class Foo {" + + " void m() { Foo f = new Foo() {}; }" + + "}"; + + // Then, we try to subclass the anonymous class + // Note: we must do this in two classes because a different + // error will be generated if we don't load Foo$1 through the + // class reader. + final String test1 = + "public class Test1 {" + + " void m() {"+ + " Foo f1 = new Foo();"+ + " Foo f2 = new Foo$1(f1) {};"+ + " }" + + "}"; + + final String test2 = + "public class Test2 {" + + " class T extends Foo$1 {" + + " public T(Foo f) { super(f); }" + + " }"+ + "}"; + + void compOk(String code) throws Exception { + ToolBox.javac(new ToolBox.JavaToolArgs().setSources(code)); + } + + void compFail(String code) throws Exception { + ArrayList errors = new ArrayList<>(); + ToolBox.JavaToolArgs args = new ToolBox.JavaToolArgs(); + args.setSources(code) + .appendArgs("-cp", ".", "-XDrawDiagnostics") + .set(ToolBox.Expect.FAIL) + .setErrOutput(errors); + ToolBox.javac(args); + + if (!errors.get(0).contains("cant.inherit.from.anon")) { + System.out.println(errors.get(0)); + throw new Exception("test failed"); + } + } + + void run() throws Exception { + compOk(foo); + compFail(test1); + compFail(test2); + } +} diff --git a/langtools/test/tools/javac/diags/examples.not-yet.txt b/langtools/test/tools/javac/diags/examples.not-yet.txt index 0db17ba5d23..fc60fb0091a 100644 --- a/langtools/test/tools/javac/diags/examples.not-yet.txt +++ b/langtools/test/tools/javac/diags/examples.not-yet.txt @@ -111,4 +111,5 @@ compiler.warn.unknown.enum.constant # in bad class file compiler.warn.unknown.enum.constant.reason # in bad class file compiler.warn.override.equals.but.not.hashcode # when a class overrides equals but not hashCode method from Object compiler.warn.file.from.future # warning for future modification times on files +compiler.err.cant.inherit.from.anon # error for subclass of anonymous class compiler.misc.bad.class.file # class file is malformed From e5c81018946876d91f89a10999d3582eb592c340 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 8 Apr 2014 14:06:11 +0200 Subject: [PATCH 132/170] 8038455: Use single Context for all rounds of annotation processing One set of javac services, as well as created ClassSymbols, is reused for all rounds of processing now. Reviewed-by: jjg, jfranck, darcy, vromero --- .../sun/tools/javac/api/BasicJavacTask.java | 9 +- .../sun/tools/javac/api/JavacTaskImpl.java | 4 +- .../com/sun/tools/javac/code/Symbol.java | 26 ++ .../com/sun/tools/javac/code/Types.java | 8 + .../com/sun/tools/javac/comp/Check.java | 4 + .../com/sun/tools/javac/comp/Enter.java | 8 + .../tools/javac/file/ZipFileIndexArchive.java | 13 +- .../sun/tools/javac/main/JavaCompiler.java | 151 ++++----- .../sun/tools/javac/model/JavacElements.java | 23 +- .../com/sun/tools/javac/model/JavacTypes.java | 17 +- .../tools/javac/processing/JavacFiler.java | 6 +- .../tools/javac/processing/JavacMessager.java | 5 +- .../JavacProcessingEnvironment.java | 291 ++++++++---------- .../com/sun/tools/javac/util/Context.java | 20 +- .../classes/com/sun/tools/javac/util/Log.java | 15 +- .../tools/javac/6668794/badSource/Test.out | 1 + langtools/test/tools/javac/T6358168.java | 7 +- .../javac/diags/ArgTypeCompilerFactory.java | 9 +- langtools/test/tools/javac/lib/ToolBox.java | 113 ++++++- .../processing/errors/TestBadProcessor.java | 5 +- .../model/trees/OnDemandAttribution.java | 78 +++++ .../rounds/BaseClassesNotReRead.java | 166 ++++++++++ .../rounds/BaseClassesNotReReadSource.java | 40 +++ .../rounds/ClassDependingOnGenerated.java | 66 ++++ .../ClassDependingOnGeneratedSource.java | 29 ++ .../processing/rounds/ClassWithSuperType.java | 26 ++ .../processing/rounds/CompleteOnClosed.java | 64 ++++ .../rounds/CompleteOnClosedOther.java | 26 ++ .../rounds/MethodsDroppedBetweenRounds.java | 69 +++++ .../rounds/OverwriteBetweenCompilations.java | 118 +++++++ .../OverwriteBetweenCompilationsSource.java | 25 ++ .../rounds/OverwriteBetweenCompilations_1.out | 45 +++ .../rounds/OverwriteBetweenCompilations_2.out | 57 ++++ .../rounds/OverwriteBetweenCompilations_3.out | 61 ++++ .../processing/rounds/TypesCachesCleared.java | 111 +++++++ .../processing/warnings/gold_unsp_warn.out | 1 + .../tools/javac/util/context/T7021650.java | 42 +-- 37 files changed, 1394 insertions(+), 365 deletions(-) create mode 100644 langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java create mode 100644 langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.java create mode 100644 langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java create mode 100644 langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.java create mode 100644 langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java create mode 100644 langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java create mode 100644 langtools/test/tools/javac/processing/rounds/CompleteOnClosed.java create mode 100644 langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java create mode 100644 langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java create mode 100644 langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java create mode 100644 langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java create mode 100644 langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out create mode 100644 langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out create mode 100644 langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out create mode 100644 langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java index e44bca373fc..e056df50a1e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/BasicJavacTask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -151,11 +151,4 @@ public class BasicJavacTask extends JavacTask { return context; } - /** - * For internal use only. This method will be - * removed without warning. - */ - public void updateContext(Context newContext) { - context = newContext; - } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 3b39e405ec2..9dba0badced 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -316,7 +316,7 @@ public class JavacTaskImpl extends BasicJavacTask { List units = compiler.enterTrees(roots.toList()); if (notYetEntered.isEmpty()) - compiler = compiler.processAnnotations(units); + compiler.processAnnotations(units); ListBuffer elements = new ListBuffer<>(); for (JCCompilationUnit unit : units) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index 1af2b332cc0..ecc7de9e64e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -905,6 +905,12 @@ public abstract class Symbol extends AnnoConstruct implements Element { public R accept(Symbol.Visitor v, P p) { return v.visitPackageSymbol(this, p); } + + /**Resets the Symbol into the state good for next round of annotation processing.*/ + public void reset() { + metadata = null; + } + } /** A class for class symbols @@ -1154,6 +1160,26 @@ public abstract class Symbol extends AnnoConstruct implements Element { public R accept(Symbol.Visitor v, P p) { return v.visitClassSymbol(this, p); } + + /**Resets the Symbol into the state good for next round of annotation processing.*/ + public void reset() { + kind = TYP; + erasure_field = null; + members_field = null; + flags_field = 0; + if (type instanceof ClassType) { + ClassType t = (ClassType)type; + t.setEnclosingType(Type.noType); + t.rank_field = -1; + t.typarams_field = null; + t.allparams_field = null; + t.supertype_field = null; + t.interfaces_field = null; + t.all_interfaces_field = null; + } + metadata = null; + } + } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java index 4e011f04368..1ac90cd88c0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java @@ -4684,4 +4684,12 @@ public class Types { } } // + + public void newRound() { + descCache._map.clear(); + isDerivedRawCache.clear(); + implCache._map.clear(); + membersCache._map.clear(); + closureCache.clear(); + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index ccc19f44157..6c2d1de3ded 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -425,6 +425,10 @@ public class Check { } } + public void newRound() { + compiled.clear(); + } + /* ************************************************************************* * Type Checking **************************************************************************/ diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java index cb2d88e6f1f..c9985f7c997 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java @@ -154,6 +154,10 @@ public class Enter extends JCTree.Visitor { return typeEnvs.get(sym); } + public Iterable> getEnvs() { + return typeEnvs.values(); + } + public Env getClassEnv(TypeSymbol sym) { Env localEnv = getEnv(sym); Env lintEnv = localEnv; @@ -514,4 +518,8 @@ public class Enter extends JCTree.Visitor { annotate.enterDone(); } } + + public void newRound() { + typeEnvs.clear(); + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java index 48d1f13fdcc..c7b92919886 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -107,10 +107,6 @@ public class ZipFileIndexArchive implements Archive { */ ZipFileIndex.Entry entry; - /** The InputStream for this zip entry (file.) - */ - InputStream inputStream = null; - /** The name of the zip file where this entry resides. */ File zipName; @@ -146,11 +142,8 @@ public class ZipFileIndexArchive implements Archive { @Override public InputStream openInputStream() throws IOException { - if (inputStream == null) { - Assert.checkNonNull(entry); // see constructor - inputStream = new ByteArrayInputStream(zfIndex.read(entry)); - } - return inputStream; + Assert.checkNonNull(entry); // see constructor + return new ByteArrayInputStream(zfIndex.read(entry)); } @Override diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java index cd30dbcd0df..18db5cf5554 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -298,12 +298,6 @@ public class JavaCompiler { */ protected MultiTaskListener taskListener; - /** - * Annotation processing may require and provide a new instance - * of the compiler to be used for the analyze and generate phases. - */ - protected JavaCompiler delegateCompiler; - /** * SourceCompleter that delegates to the complete-method of this class. */ @@ -567,12 +561,8 @@ public class JavaCompiler { /** The number of errors reported so far. */ public int errorCount() { - if (delegateCompiler != null && delegateCompiler != this) - return delegateCompiler.errorCount(); - else { - if (werror && log.nerrors == 0 && log.nwarnings > 0) { - log.error("warnings.and.werror"); - } + if (werror && log.nerrors == 0 && log.nwarnings > 0) { + log.error("warnings.and.werror"); } return log.nerrors; } @@ -588,10 +578,7 @@ public class JavaCompiler { /** The number of warnings reported so far. */ public int warningCount() { - if (delegateCompiler != null && delegateCompiler != this) - return delegateCompiler.warningCount(); - else - return log.nwarnings; + return log.nwarnings; } /** Try to open input stream with given name. @@ -759,21 +746,32 @@ public class JavaCompiler { * @param c The class the source file of which needs to be compiled. */ public void complete(ClassSymbol c) throws CompletionFailure { + complete(null, c); + } + + /** Complete a ClassSymbol from source, optionally using the given compilation unit as + * the source tree. + * @param tree the compilation unit int which the given ClassSymbol resides, + * or null if should be parsed from source + * @param c the ClassSymbol to complete + */ + public void complete(JCCompilationUnit tree, ClassSymbol c) throws CompletionFailure { // System.err.println("completing " + c);//DEBUG if (completionFailureName == c.fullname) { throw new CompletionFailure(c, "user-selected completion failure by class name"); } - JCCompilationUnit tree; JavaFileObject filename = c.classfile; JavaFileObject prev = log.useSource(filename); - try { - tree = parse(filename, filename.getCharContent(false)); - } catch (IOException e) { - log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); - tree = make.TopLevel(List.nil(), null, List.nil()); - } finally { - log.useSource(prev); + if (tree == null) { + try { + tree = parse(filename, filename.getCharContent(false)); + } catch (IOException e) { + log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); + tree = make.TopLevel(List.nil(), null, List.nil()); + } finally { + log.useSource(prev); + } } if (!taskListener.isEmpty()) { @@ -851,35 +849,16 @@ public class JavaCompiler { initProcessAnnotations(processors); // These method calls must be chained to avoid memory leaks - delegateCompiler = - processAnnotations( - enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), - classnames); + processAnnotations( + enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))), + classnames); // If it's safe to do so, skip attr / flow / gen for implicit classes if (taskListener.isEmpty() && implicitSourcePolicy == ImplicitSourcePolicy.NONE) { - delegateCompiler.todo.retainFiles(delegateCompiler.inputFiles); + todo.retainFiles(inputFiles); } - delegateCompiler.compile2(); - delegateCompiler.close(); - elapsed_msec = delegateCompiler.elapsed_msec; - } catch (Abort ex) { - if (devVerbose) - ex.printStackTrace(System.err); - } finally { - if (procEnvImpl != null) - procEnvImpl.close(); - } - } - - /** - * The phases following annotation processing: attribution, - * desugar, and finally code generation. - */ - private void compile2() { - try { switch (compilePolicy) { case ATTR_ONLY: attribute(todo); @@ -912,18 +891,21 @@ public class JavaCompiler { } catch (Abort ex) { if (devVerbose) ex.printStackTrace(System.err); - } + } finally { + if (verbose) { + elapsed_msec = elapsed(start_msec); + log.printVerbose("total", Long.toString(elapsed_msec)); + } - if (verbose) { - elapsed_msec = elapsed(start_msec); - log.printVerbose("total", Long.toString(elapsed_msec)); - } + reportDeferredDiagnostics(); - reportDeferredDiagnostics(); - - if (!log.hasDiagnosticListener()) { - printCount("error", errorCount()); - printCount("warn", warningCount()); + if (!log.hasDiagnosticListener()) { + printCount("error", errorCount()); + printCount("warn", warningCount()); + } + close(); + if (procEnvImpl != null) + procEnvImpl.close(); } } @@ -1069,8 +1051,8 @@ public class JavaCompiler { } // TODO: called by JavacTaskImpl - public JavaCompiler processAnnotations(List roots) { - return processAnnotations(roots, List.nil()); + public void processAnnotations(List roots) { + processAnnotations(roots, List.nil()); } /** @@ -1084,8 +1066,8 @@ public class JavaCompiler { // By the time this method exits, log.deferDiagnostics must be set back to false, // and all deferredDiagnostics must have been handled: i.e. either reported // or determined to be transient, and therefore suppressed. - public JavaCompiler processAnnotations(List roots, - List classnames) { + public void processAnnotations(List roots, + List classnames) { if (shouldStop(CompileState.PROCESS)) { // Errors were encountered. // Unless all the errors are resolve errors, the errors were parse errors @@ -1094,7 +1076,7 @@ public class JavaCompiler { if (unrecoverableError()) { deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; + return ; } } @@ -1117,7 +1099,7 @@ public class JavaCompiler { classnames); } Assert.checkNull(deferredDiagnosticHandler); - return this; // continue regular compilation + return ; // continue regular compilation } Assert.checkNonNull(deferredDiagnosticHandler); @@ -1133,7 +1115,7 @@ public class JavaCompiler { classnames); deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; // TODO: Will this halt compilation? + return ; // TODO: Will this halt compilation? } else { boolean errors = false; for (String nameStr : classnames) { @@ -1167,25 +1149,26 @@ public class JavaCompiler { if (errors) { deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; + return ; } } } try { - JavaCompiler c = procEnvImpl.doProcessing(context, roots, classSymbols, pckSymbols, - deferredDiagnosticHandler); - if (c != this) - annotationProcessingOccurred = c.annotationProcessingOccurred = true; + annotationProcessingOccurred = + procEnvImpl.doProcessing(roots, + classSymbols, + pckSymbols, + deferredDiagnosticHandler); // doProcessing will have handled deferred diagnostics - return c; } finally { procEnvImpl.close(); } } catch (CompletionFailure ex) { log.error("cant.access", ex.sym, ex.getDetailValue()); - deferredDiagnosticHandler.reportDeferredDiagnostics(); - log.popDiagnosticHandler(deferredDiagnosticHandler); - return this; + if (deferredDiagnosticHandler != null) { + deferredDiagnosticHandler.reportDeferredDiagnostics(); + log.popDiagnosticHandler(deferredDiagnosticHandler); + } } } @@ -1213,6 +1196,10 @@ public class JavaCompiler { options.isSet(XPRINT); } + public void setDeferredDiagnosticHandler(Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { + this.deferredDiagnosticHandler = deferredDiagnosticHandler; + } + /** * Attribute a list of parse trees, such as found on the "todo" list. * Note that attributing classes may cause additional files to be @@ -1674,10 +1661,6 @@ public class JavaCompiler { /** Close the compiler, flushing the logs */ public void close() { - close(true); - } - - public void close(boolean disposeNames) { rootClasses = null; reader = null; make = null; @@ -1704,7 +1687,7 @@ public class JavaCompiler { } catch (IOException e) { throw new Abort(e); } finally { - if (names != null && disposeNames) + if (names != null) names.dispose(); names = null; @@ -1750,14 +1733,8 @@ public class JavaCompiler { return now() - then; } - public void initRound(JavaCompiler prev) { - genEndPos = prev.genEndPos; - keepComments = prev.keepComments; - start_msec = prev.start_msec; - hasBeenUsed = true; - closeables = prev.closeables; - prev.closeables = List.nil(); - shouldStopPolicyIfError = prev.shouldStopPolicyIfError; - shouldStopPolicyIfNoError = prev.shouldStopPolicyIfNoError; + public void newRound() { + inputFiles.clear(); + todo.clear(); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java index b1a6cd19ba7..dbe7bb59d7c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -60,11 +60,11 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; */ public class JavacElements implements Elements { - private JavaCompiler javaCompiler; - private Symtab syms; - private Names names; - private Types types; - private Enter enter; + private final JavaCompiler javaCompiler; + private final Symtab syms; + private final Names names; + private final Types types; + private final Enter enter; public static JavacElements instance(Context context) { JavacElements instance = context.get(JavacElements.class); @@ -73,18 +73,7 @@ public class JavacElements implements Elements { return instance; } - /** - * Public for use only by JavacProcessingEnvironment - */ protected JavacElements(Context context) { - setContext(context); - } - - /** - * Use a new context. May be called from outside to update - * internal state for a new annotation-processing round. - */ - public void setContext(Context context) { context.put(JavacElements.class, this); javaCompiler = JavaCompiler.instance(context); syms = Symtab.instance(context); diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java index e56eedd7a9a..5b780ede81d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java +++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -48,8 +48,8 @@ import com.sun.tools.javac.util.*; */ public class JavacTypes implements javax.lang.model.util.Types { - private Symtab syms; - private Types types; + private final Symtab syms; + private final Types types; public static JavacTypes instance(Context context) { JavacTypes instance = context.get(JavacTypes.class); @@ -58,18 +58,7 @@ public class JavacTypes implements javax.lang.model.util.Types { return instance; } - /** - * Public for use only by JavacProcessingEnvironment - */ protected JavacTypes(Context context) { - setContext(context); - } - - /** - * Use a new context. May be called from outside to update - * internal state for a new annotation-processing round. - */ - public void setContext(Context context) { context.put(JavacTypes.class, this); syms = Symtab.instance(context); types = Types.instance(context); diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java index fc830c40e51..06e033c8b5c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacFiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -564,9 +564,7 @@ public class JavacFiler implements Filer, Closeable { /** * Update internal state for a new round. */ - public void newRound(Context context) { - this.context = context; - this.log = Log.instance(context); + public void newRound() { clearRoundState(); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java index bc6acc1a096..0cb3c8f3e6f 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacMessager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -176,8 +176,7 @@ public class JavacMessager implements Messager { return warningCount; } - public void newRound(Context context) { - log = Log.instance(context); + public void newRound() { errorCount = 0; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index c53a60d73e7..a0b3fe64a21 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -38,27 +38,27 @@ import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.lang.model.util.*; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import static javax.tools.StandardLocation.*; -import com.sun.source.util.JavacTask; import com.sun.source.util.TaskEvent; -import com.sun.tools.javac.api.BasicJavacTask; -import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.api.MultiTaskListener; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.file.FSInfo; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Check; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.jvm.ClassReader.BadClassFile; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.model.JavacTypes; -import com.sun.tools.javac.parser.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Abort; @@ -103,6 +103,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private final JavacMessager messager; private final JavacElements elementUtils; private final JavacTypes typeUtils; + private final Types types; + private final JavaCompiler compiler; /** * Holds relevant state history of which processors have been @@ -131,7 +133,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** The log to be used for error reporting. */ - Log log; + final Log log; /** Diagnostic factory. */ @@ -151,8 +153,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private JavacMessages messages; private MultiTaskListener taskListener; + private final Symtab symtab; + private final Names names; + private final Enter enter; + private final Completer initialCompleter; + private final Check chk; - private Context context; + private final Context context; /** Get the JavacProcessingEnvironment instance for this context. */ public static JavacProcessingEnvironment instance(Context context) { @@ -173,8 +180,8 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea printRounds = options.isSet(XPRINTROUNDS); verbose = options.isSet(VERBOSE); lint = Lint.instance(context).isEnabled(PROCESSING); + compiler = JavaCompiler.instance(context); if (options.isSet(PROC, "only") || options.isSet(XPRINT)) { - JavaCompiler compiler = JavaCompiler.instance(context); compiler.shouldStopPolicyIfNoError = CompileState.PROCESS; } fatalErrors = options.isSet("fatalEnterError"); @@ -188,16 +195,22 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea messager = new JavacMessager(context, this); elementUtils = JavacElements.instance(context); typeUtils = JavacTypes.instance(context); - processorOptions = initProcessorOptions(context); + types = Types.instance(context); + processorOptions = initProcessorOptions(); unmatchedProcessorOptions = initUnmatchedProcessorOptions(); messages = JavacMessages.instance(context); taskListener = MultiTaskListener.instance(context); + symtab = Symtab.instance(context); + names = Names.instance(context); + enter = Enter.instance(context); + initialCompleter = ClassReader.instance(context).getCompleter(); + chk = Check.instance(context); initProcessorClassLoader(); } public void setProcessors(Iterable processors) { Assert.checkNull(discoveredProcs); - initProcessorIterator(context, processors); + initProcessorIterator(processors); } private Set initPlatformAnnotations() { @@ -221,7 +234,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea : fileManager.getClassLoader(CLASS_PATH); if (processorClassLoader != null && processorClassLoader instanceof Closeable) { - JavaCompiler compiler = JavaCompiler.instance(context); compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader); } } catch (SecurityException e) { @@ -229,8 +241,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - private void initProcessorIterator(Context context, Iterable processors) { - Log log = Log.instance(context); + private void initProcessorIterator(Iterable processors) { Iterator processorIterator; if (options.isSet(XPRINT)) { @@ -447,8 +458,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea return discoveredProcs.iterator().hasNext(); } - private Map initProcessorOptions(Context context) { - Options options = Options.instance(context); + private Map initProcessorOptions() { Set keySet = options.keySet(); Map tempOptions = new LinkedHashMap<>(); @@ -653,8 +663,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - private void discoverAndRunProcs(Context context, - Set annotationsPresent, + private void discoverAndRunProcs(Set annotationsPresent, List topLevelClasses, List packageInfoFiles) { Map unmatchedAnnotations = new HashMap<>(annotationsPresent.size()); @@ -724,7 +733,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // Remove annotations processed by javac unmatchedAnnotations.keySet().removeAll(platformAnnotations); if (unmatchedAnnotations.size() > 0) { - log = Log.instance(context); log.warning("proc.annotations.without.processors", unmatchedAnnotations.keySet()); } @@ -812,17 +820,13 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea class Round { /** The round number. */ final int number; - /** The context for the round. */ - final Context context; - /** The compiler for the round. */ - final JavaCompiler compiler; - /** The log for the round. */ - final Log log; /** The diagnostic handler for the round. */ final Log.DeferredDiagnosticHandler deferredDiagnosticHandler; /** The ASTs to be compiled. */ List roots; + /** The trees that need to be cleaned - includes roots and implicitly parsed trees. */ + Set treesToClean; /** The classes to be compiler that have were generated. */ Map genClassFiles; @@ -834,39 +838,33 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea List packageInfoFiles; /** Create a round (common code). */ - private Round(Context context, int number, int priorErrors, int priorWarnings, + private Round(int number, Set treesToClean, Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { - this.context = context; this.number = number; - compiler = JavaCompiler.instance(context); - log = Log.instance(context); - log.nerrors = priorErrors; - log.nwarnings = priorWarnings; if (number == 1) { Assert.checkNonNull(deferredDiagnosticHandler); this.deferredDiagnosticHandler = deferredDiagnosticHandler; } else { this.deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log); + compiler.setDeferredDiagnosticHandler(this.deferredDiagnosticHandler); } - // the following is for the benefit of JavacProcessingEnvironment.getContext() - JavacProcessingEnvironment.this.context = context; - // the following will be populated as needed topLevelClasses = List.nil(); packageInfoFiles = List.nil(); + this.treesToClean = treesToClean; } /** Create the first round. */ - Round(Context context, List roots, List classSymbols, - Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { - this(context, 1, 0, 0, deferredDiagnosticHandler); + Round(List roots, + List classSymbols, + Set treesToClean, + Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { + this(1, treesToClean, deferredDiagnosticHandler); this.roots = roots; genClassFiles = new HashMap<>(); - compiler.todo.clear(); // free the compiler's resources - // The reverse() in the following line is to maintain behavioural // compatibility with the previous revision of the code. Strictly speaking, // it should not be necessary, but a javah golden file test fails without it. @@ -881,15 +879,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** Create a new round. */ private Round(Round prev, Set newSourceFiles, Map newClassFiles) { - this(prev.nextContext(), - prev.number+1, - prev.compiler.log.nerrors, - prev.compiler.log.nwarnings, - null); + this(prev.number+1, prev.treesToClean, null); + prev.newRound(); this.genClassFiles = prev.genClassFiles; List parsedFiles = compiler.parseFiles(newSourceFiles); - roots = cleanTrees(prev.roots).appendList(parsedFiles); + roots = prev.roots.appendList(parsedFiles); // Check for errors after parsing if (unrecoverableError()) @@ -916,24 +911,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** Create the next round to be used. */ Round next(Set newSourceFiles, Map newClassFiles) { - try { - return new Round(this, newSourceFiles, newClassFiles); - } finally { - compiler.close(false); - } + return new Round(this, newSourceFiles, newClassFiles); } - /** Create the compiler to be used for the final compilation. */ - JavaCompiler finalCompiler() { - try { - Context nextCtx = nextContext(); - JavacProcessingEnvironment.this.context = nextCtx; - JavaCompiler c = JavaCompiler.instance(nextCtx); - c.log.initRound(compiler.log); - return c; - } finally { - compiler.close(false); - } + /** Prepare the compiler for the final compilation. */ + void finalCompiler() { + newRound(); } /** Return the number of errors found so far in this round. @@ -984,8 +967,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea /** Enter a set of generated class files. */ private List enterClassFiles(Map classFiles) { - Symtab symtab = Symtab.instance(context); - Names names = Names.instance(context); List list = List.nil(); for (Map.Entry entry : classFiles.entrySet()) { @@ -1000,10 +981,16 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (p.package_info == null) p.package_info = symtab.enterClass(Convert.shortName(name), p); cs = p.package_info; + cs.reset(); if (cs.classfile == null) cs.classfile = file; - } else - cs = symtab.enterClass(name, file); + cs.completer = initialCompleter; + } else { + cs = symtab.enterClass(name); + cs.reset(); + cs.classfile = file; + cs.completer = initialCompleter; + } list = list.prepend(cs); } return list.reverse(); @@ -1031,7 +1018,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea JavacProcessingEnvironment.this); discoveredProcs.iterator().runContributingProcs(renv); } else { - discoverAndRunProcs(context, annotationsPresent, topLevelClasses, packageInfoFiles); + discoverAndRunProcs(annotationsPresent, topLevelClasses, packageInfoFiles); } } catch (Throwable t) { // we're specifically expecting Abort here, but if any Throwable @@ -1039,6 +1026,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // drop them on the ground. deferredDiagnosticHandler.reportDeferredDiagnostics(); log.popDiagnosticHandler(deferredDiagnosticHandler); + compiler.setDeferredDiagnosticHandler(null); throw t; } finally { if (!taskListener.isEmpty()) @@ -1054,6 +1042,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } deferredDiagnosticHandler.reportDeferredDiagnostics(kinds); log.popDiagnosticHandler(deferredDiagnosticHandler); + compiler.setDeferredDiagnosticHandler(null); } /** Print info about this round. */ @@ -1069,104 +1058,68 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } } - /** Get the context for the next round of processing. - * Important values are propagated from round to round; - * other values are implicitly reset. + /** Prepare for new round of annotation processing. Cleans trees, resets symbols, and + * asks selected services to prepare to a new round of annotation processing. */ - private Context nextContext() { - Context next = new Context(context); + private void newRound() { + //ensure treesToClean contains all trees, including implicitly parsed ones + for (Env env : enter.getEnvs()) { + treesToClean.add(env.toplevel); + } + for (JCCompilationUnit node : treesToClean) { + treeCleaner.scan(node); + } + chk.newRound(); + enter.newRound(); + filer.newRound(); + messager.newRound(); + compiler.newRound(); + types.newRound(); - Options options = Options.instance(context); - Assert.checkNonNull(options); - next.put(Options.optionsKey, options); + boolean foundError = false; - Locale locale = context.get(Locale.class); - if (locale != null) - next.put(Locale.class, locale); - - Assert.checkNonNull(messages); - next.put(JavacMessages.messagesKey, messages); - - final boolean shareNames = true; - if (shareNames) { - Names names = Names.instance(context); - Assert.checkNonNull(names); - next.put(Names.namesKey, names); + for (ClassSymbol cs : symtab.classes.values()) { + if (cs.kind == Kinds.ERR) { + foundError = true; + break; + } } - DiagnosticListener dl = context.get(DiagnosticListener.class); - if (dl != null) - next.put(DiagnosticListener.class, dl); - - MultiTaskListener mtl = context.get(MultiTaskListener.taskListenerKey); - if (mtl != null) - next.put(MultiTaskListener.taskListenerKey, mtl); - - FSInfo fsInfo = context.get(FSInfo.class); - if (fsInfo != null) - next.put(FSInfo.class, fsInfo); - - JavaFileManager jfm = context.get(JavaFileManager.class); - Assert.checkNonNull(jfm); - next.put(JavaFileManager.class, jfm); - if (jfm instanceof JavacFileManager) { - ((JavacFileManager)jfm).setContext(next); + if (foundError) { + for (ClassSymbol cs : symtab.classes.values()) { + if (cs.classfile != null || cs.kind == Kinds.ERR) { + cs.reset(); + cs.type = new ClassType(cs.type.getEnclosingType(), null, cs); + if (cs.completer == null) { + cs.completer = initialCompleter; + } + } + } } - - Names names = Names.instance(context); - Assert.checkNonNull(names); - next.put(Names.namesKey, names); - - Tokens tokens = Tokens.instance(context); - Assert.checkNonNull(tokens); - next.put(Tokens.tokensKey, tokens); - - Log nextLog = Log.instance(next); - nextLog.initRound(log); - - JavaCompiler oldCompiler = JavaCompiler.instance(context); - JavaCompiler nextCompiler = JavaCompiler.instance(next); - nextCompiler.initRound(oldCompiler); - - filer.newRound(next); - messager.newRound(next); - elementUtils.setContext(next); - typeUtils.setContext(next); - - JavacTask task = context.get(JavacTask.class); - if (task != null) { - next.put(JavacTask.class, task); - if (task instanceof BasicJavacTask) - ((BasicJavacTask) task).updateContext(next); - } - - JavacTrees trees = context.get(JavacTrees.class); - if (trees != null) { - next.put(JavacTrees.class, trees); - trees.updateContext(next); - } - - context.clear(); - return next; } } // TODO: internal catch clauses?; catch and rethrow an annotation // processing error - public JavaCompiler doProcessing(Context context, - List roots, - List classSymbols, - Iterable pckSymbols, - Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { - log = Log.instance(context); + public boolean doProcessing(List roots, + List classSymbols, + Iterable pckSymbols, + Log.DeferredDiagnosticHandler deferredDiagnosticHandler) { + final Set treesToClean = + Collections.newSetFromMap(new IdentityHashMap()); + + //fill already attributed implicit trees: + for (Env env : enter.getEnvs()) { + treesToClean.add(env.toplevel); + } Set specifiedPackages = new LinkedHashSet<>(); for (PackageSymbol psym : pckSymbols) specifiedPackages.add(psym); this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages); - Round round = new Round(context, roots, classSymbols, deferredDiagnosticHandler); + Round round = new Round(roots, classSymbols, treesToClean, deferredDiagnosticHandler); boolean errorStatus; boolean moreToDo; @@ -1217,9 +1170,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea Set newSourceFiles = new LinkedHashSet<>(filer.getGeneratedSourceFileObjects()); - roots = cleanTrees(round.roots); + roots = round.roots; - JavaCompiler compiler = round.finalCompiler(); + errorStatus = errorStatus || (compiler.errorCount() > 0); + + if (!errorStatus) + round.finalCompiler(); if (newSourceFiles.size() > 0) roots = roots.appendList(compiler.parseFiles(newSourceFiles)); @@ -1235,12 +1191,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (errorStatus) { if (compiler.errorCount() == 0) compiler.log.nerrors++; - return compiler; + return true; } compiler.enterTreesIfNeeded(roots); - return compiler; + return true; } private void warnIfUnmatchedOptions() { @@ -1342,23 +1298,46 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea return false; } - private static List cleanTrees(List nodes) { - for (T node : nodes) - treeCleaner.scan(node); - return nodes; + class ImplicitCompleter implements Completer { + + private final JCCompilationUnit topLevel; + + public ImplicitCompleter(JCCompilationUnit topLevel) { + this.topLevel = topLevel; + } + + @Override public void complete(Symbol sym) throws CompletionFailure { + compiler.complete(topLevel, (ClassSymbol) sym); + } } - private static final TreeScanner treeCleaner = new TreeScanner() { + private final TreeScanner treeCleaner = new TreeScanner() { public void scan(JCTree node) { super.scan(node); if (node != null) node.type = null; } + JCCompilationUnit topLevel; public void visitTopLevel(JCCompilationUnit node) { + if (node.packge != null) { + if (node.packge.package_info != null) { + node.packge.package_info.reset(); + } + node.packge.reset(); + } node.packge = null; - super.visitTopLevel(node); + topLevel = node; + try { + super.visitTopLevel(node); + } finally { + topLevel = null; + } } public void visitClassDef(JCClassDecl node) { + if (node.sym != null) { + node.sym.reset(); + node.sym.completer = new ImplicitCompleter(topLevel); + } node.sym = null; super.visitClassDef(node); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Context.java b/langtools/src/share/classes/com/sun/tools/javac/util/Context.java index 8216d1e49bf..3768afad935 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Context.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Context.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -119,7 +119,7 @@ public class Context { * or * {@literal Key -> Factory } */ - private Map,Object> ht = new HashMap<>(); + private final Map,Object> ht = new HashMap<>(); /** Set the factory for the key in this context. */ public void put(Key key, Factory fac) { @@ -166,18 +166,12 @@ public class Context { /** * The table of preregistered factories. */ - private Map,Factory> ft = new HashMap<>(); - - public Context(Context prev) { - kt.putAll(prev.kt); // retain all implicit keys - ft.putAll(prev.ft); // retain all factory objects - ht.putAll(prev.ft); // init main table with factories - } + private final Map,Factory> ft = new HashMap<>(); /* * The key table, providing a unique Key for each Class. */ - private Map, Key> kt = new HashMap<>(); + private final Map, Key> kt = new HashMap<>(); private Key key(Class clss) { checkState(kt); @@ -214,12 +208,6 @@ public class Context { System.err.println(value == null ? null : value.getClass()); } - public void clear() { - ht = null; - kt = null; - ft = null; - } - private static void checkState(Map t) { if (t == null) throw new IllegalStateException(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java index 710a8310e1b..2bd1ee5b9e9 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, 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 @@ -390,19 +390,6 @@ public class Log extends AbstractLog { noticeWriter = warnWriter = errWriter = pw; } - /** - * Propagate the previous log's information. - */ - public void initRound(Log other) { - this.noticeWriter = other.noticeWriter; - this.warnWriter = other.warnWriter; - this.errWriter = other.errWriter; - this.sourceMap = other.sourceMap; - this.recorded = other.recorded; - this.nerrors = other.nerrors; - this.nwarnings = other.nwarnings; - } - /** * Replace the specified diagnostic handler with the * handler that was current at the time this handler was created. diff --git a/langtools/test/tools/javac/6668794/badSource/Test.out b/langtools/test/tools/javac/6668794/badSource/Test.out index 94e1416d7a7..2c8d26b4b4c 100644 --- a/langtools/test/tools/javac/6668794/badSource/Test.out +++ b/langtools/test/tools/javac/6668794/badSource/Test.out @@ -1 +1,2 @@ Test.java:10:6: compiler.err.cant.access: p.A, (compiler.misc.bad.source.file.header: A.java, (compiler.misc.file.doesnt.contain.class: p.A)) +1 error diff --git a/langtools/test/tools/javac/T6358168.java b/langtools/test/tools/javac/T6358168.java index fe7fec2417d..9023e9d1855 100644 --- a/langtools/test/tools/javac/T6358168.java +++ b/langtools/test/tools/javac/T6358168.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2014, 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 @@ -99,10 +99,9 @@ public class T6358168 extends AbstractProcessor { "-d", "."}); JavaCompiler compiler = JavaCompiler.instance(context); - compiler.initProcessAnnotations(null); - JavaCompiler compiler2 = compiler.processAnnotations(compiler.enterTrees(compiler.parseFiles(List.of(f)))); + compiler.compile(List.of(f)); try { - compiler2.compile(List.of(f)); + compiler.compile(List.of(f)); throw new Error("Error: AssertionError not thrown after second call of compile"); } catch (AssertionError e) { System.err.println("Exception from compiler (expected): " + e); diff --git a/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java index 6c5ef038382..f8cab930697 100644 --- a/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java +++ b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2014, 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 @@ -135,12 +135,7 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory { args.add(f.getPath()); Main main = new Main("javac", out); - Context c = new Context() { - @Override public void clear() { - ((JavacFileManager) get(JavaFileManager.class)).close(); - super.clear(); - } - }; + Context c = new Context(); JavacFileManager.preRegister(c); // can't create it until Log has been set up ArgTypeJavaCompiler.preRegister(c); ArgTypeMessages.preRegister(c); diff --git a/langtools/test/tools/javac/lib/ToolBox.java b/langtools/test/tools/javac/lib/ToolBox.java index 73db0a42d2f..b933ab54de0 100644 --- a/langtools/test/tools/javac/lib/ToolBox.java +++ b/langtools/test/tools/javac/lib/ToolBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -22,11 +22,14 @@ */ import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; +import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URI; @@ -40,15 +43,22 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import com.sun.source.util.JavacTask; @@ -453,6 +463,45 @@ public class ToolBox { throw new AssertionError("javac command has been invoked with less parameters than needed"); } + /** + * Run javac and return the resulting classfiles. + */ + public static Map compile(JavaToolArgs params) + throws CommandExecutionException, IOException { + if (params.hasMinParams()) { + if (params.argsArr != null) { + throw new AssertionError("setAllArgs is not supported for compile"); + } + + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + MemoryFileManager mfm = new MemoryFileManager(fm); + StringWriter sw = null; + boolean rc; + + try (PrintWriter pw = (params.errOutput == null) ? + null : new PrintWriter(sw = new StringWriter())) { + JavacTask ct = (JavacTask)comp.getTask(pw, mfm, null, + params.args, null, params.sources); + rc = ct.call(); + } + + String out = (sw == null) ? null : sw.toString(); + + if (params.errOutput != null && (out != null) && !out.isEmpty()) { + params.errOutput.addAll(splitLines(out, lineSeparator)); + } + + if ( ( rc && params.whatToExpect == Expect.SUCCESS) || + (!rc && params.whatToExpect == Expect.FAIL) ) { + return mfm.classes; + } + + throw new CommandExecutionException(JavaCMD.JAVAC_API.getExceptionMsgContent(params), + params.whatToExpect); + } + throw new AssertionError("compile command has been invoked with less parameters than needed"); + } + /** * A javap calling method. */ @@ -964,4 +1013,66 @@ public class ToolBox { return source; } } + + /** + * A file manager for compiling strings to byte arrays. + * This file manager delegates to another file manager + * to lookup classes on boot class path. + */ + public static final class MemoryFileManager extends ForwardingJavaFileManager { + /** + * Maps binary class names to class files stored as byte arrays. + */ + private final Map classes; + + /** + * Construct a memory file manager which delegates to the specified + * file manager for unknown sources. + * @param fileManager a file manager used to look up class files on class path, etc. + */ + public MemoryFileManager(JavaFileManager fileManager) { + super(fileManager); + classes = new HashMap<>(); + } + + @java.lang.Override + public JavaFileObject getJavaFileForOutput(Location location, + String name, + Kind kind, + FileObject sibling) + throws UnsupportedOperationException + { + return new JavaClassInArray(name); + } + + /** + * A file object representing a Java class file stored in a byte array. + */ + private class JavaClassInArray extends SimpleJavaFileObject { + + private final String name; + + /** + * Constructs a JavaClassInArray object. + * @param name binary name of the class to be stored in this file object + */ + JavaClassInArray(String name) { + super(URI.create("mfm:///" + name.replace('.','/') + Kind.CLASS.extension), + Kind.CLASS); + this.name = name; + } + + public OutputStream openOutputStream() { + return new FilterOutputStream(new ByteArrayOutputStream()) { + public void close() throws IOException { + out.close(); + ByteArrayOutputStream bos = (ByteArrayOutputStream)out; + classes.put(name, bos.toByteArray()); + } + }; + } + } + + } + } diff --git a/langtools/test/tools/javac/processing/errors/TestBadProcessor.java b/langtools/test/tools/javac/processing/errors/TestBadProcessor.java index 881b2d8b643..44e21821b0e 100644 --- a/langtools/test/tools/javac/processing/errors/TestBadProcessor.java +++ b/langtools/test/tools/javac/processing/errors/TestBadProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -73,7 +73,8 @@ public class TestBadProcessor { String expect = "error: Bad service configuration file, " + "or exception thrown while constructing Processor object: " + "javax.annotation.processing.Processor: " + - "Provider AnnoProc could not be instantiated: java.lang.Error"; + "Provider AnnoProc could not be instantiated: java.lang.Error\n" + + "1 error"; if (!out.trim().equals(expect)) { System.err.println("expected: " + expect); error("output not as expected"); diff --git a/langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java b/langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java new file mode 100644 index 00000000000..e541deed822 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/trees/OnDemandAttribution.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Verify that in-method ClassSymbols from one round do not affect ClassSymbols in + * following rounds. + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor OnDemandAttribution + * @compile/process -processor OnDemandAttribution OnDemandAttribution.java + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import static javax.lang.model.util.ElementFilter.*; +import com.sun.source.tree.*; +import com.sun.source.util.*; + +public class OnDemandAttribution extends JavacTestingAbstractProcessor { + + public OnDemandAttribution() { + class Local { } + new Object() { }; + } + + public boolean process(Set annos,RoundEnvironment rEnv) { + TypeElement currentClass = elements.getTypeElement("OnDemandAttribution"); + ExecutableElement constr = constructorsIn(currentClass.getEnclosedElements()).get(0); + Trees trees = Trees.instance(processingEnv); + TreePath path = trees.getPath(constr); + + new TreePathScanner() { + @Override public Void visitClass(ClassTree node, Void p) { + if (node.getSimpleName().contentEquals("Local")) { + //will also attribute the body on demand: + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el); + if (!binaryName.contentEquals("OnDemandAttribution$1Local")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + } + return super.visitClass(node, p); + } + @Override public Void visitNewClass(NewClassTree node, Void p) { + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el.getEnclosingElement()); + if (!binaryName.contentEquals("OnDemandAttribution$1")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + return super.visitNewClass(node, p); + } + }.scan(path, null); + + return true; + } +} diff --git a/langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.java b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.java new file mode 100644 index 00000000000..ebdc9c809e3 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReRead.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Check that classfiles are read only once in common cases despite several rounds of + * annotation processing. + * @clean * + * @run main BaseClassesNotReRead + */ + +import java.io.*; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.tools.*; +import javax.tools.JavaFileObject.Kind; +import com.sun.source.util.JavacTask; + + +@SupportedAnnotationTypes("*") +public class BaseClassesNotReRead extends AbstractProcessor { + public static void main(String... args) throws IOException { + new BaseClassesNotReRead().run(); + } + + void run() throws IOException { + File sources = new File(System.getProperty("test.src")); + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null); + Iterable files = + fm.getJavaFileObjects(new File(sources, "BaseClassesNotReReadSource.java")); + DiagnosticListener noErrors = new DiagnosticListener() { + @Override + public void report(Diagnostic diagnostic) { + throw new IllegalStateException(diagnostic.toString()); + } + }; + JavaFileManager manager = new OnlyOneReadFileManager(fm); + Iterable options = Arrays.asList("-processor", "BaseClassesNotReRead"); + JavacTask task = (JavacTask) compiler.getTask(null, manager, noErrors, options, null, files); + task.analyze(); + } + + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + if (round++ == 1) { + for (int c = 1; c <= 6; c++) { + generateSource("GenClass" + c, + "public class GenClass" + c + " { public void test() { } }"); + } + for (int c = 1; c <= 3; c++) { + generateSource("GenIntf" + c, + "public interface GenIntf" + c + " { public void test(); }"); + } + generateSource("GenAnnotation", + "public @interface GenAnnotation { }"); + generateSource("GenException", + "public class GenException extends Exception { }"); + } + + return false; + } + + private void generateSource(String name, String code) { + Filer filer = processingEnv.getFiler(); + try (Writer out = filer.createSourceFile(name).openWriter()) { + out.write(code); + out.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + final class OnlyOneReadFileManager extends ForwardingJavaFileManager { + + public OnlyOneReadFileManager(JavaFileManager fileManager) { + super(fileManager); + } + + @Override + public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) + throws IOException { + return new OnlyOneReadJavaFileObject(super.getJavaFileForInput(location, className, kind)); + } + + @Override + public Iterable list(Location location, String packageName, Set kinds, + boolean recurse) throws IOException { + List result = new ArrayList<>(); + for (JavaFileObject jfo : super.list(location, packageName, kinds, recurse)) { + result.add(new OnlyOneReadJavaFileObject(jfo)); + } + return result; + } + + @Override + public String inferBinaryName(Location location, JavaFileObject file) { + return super.inferBinaryName(location, + ((OnlyOneReadJavaFileObject) file).getFileObject()); + } + + } + + final class OnlyOneReadJavaFileObject extends ForwardingJavaFileObject { + + public OnlyOneReadJavaFileObject(JavaFileObject fileObject) { + super(fileObject); + } + + boolean used; + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + if (used) throw new IllegalStateException("Already read."); + used = true; + return super.getCharContent(ignoreEncodingErrors); + } + + @Override + public InputStream openInputStream() throws IOException { + if (used) throw new IllegalStateException("Already read."); + used = true; + return super.openInputStream(); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + if (used) throw new IllegalStateException("Already read."); + used = true; + return super.openReader(ignoreEncodingErrors); + } + + public JavaFileObject getFileObject() { + return fileObject; + } + } +} diff --git a/langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java new file mode 100644 index 00000000000..feaaa251134 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/BaseClassesNotReReadSource.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.util.List; + +public class BaseClassesNotReReadSource extends GenClass2 + implements GenIntf2 { + public GenClass3 f; + @GenAnnotation + public GenClass4 get(GenClass5 i, List l) throws GenException { + return null; + } + @Override + public void test() { + } + @FunctionalInterface + interface FI extends GenIntf3 { + + } +} diff --git a/langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.java b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.java new file mode 100644 index 00000000000..e5f1c437275 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGenerated.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Verify situation when a classfile depends on another type, which is missing and + * generated by an annotation processor, is handled properly + * @library /tools/javac/lib/ + * @clean * + * @build ClassWithSuperType ClassDependingOnGenerated JavacTestingAbstractProcessor + * @clean SuperClass + * @compile -processor ClassDependingOnGenerated ClassDependingOnGeneratedSource.java + */ + +import java.io.*; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.*; +import com.sun.tools.javac.code.Symbol.CompletionFailure; + +public class ClassDependingOnGenerated extends JavacTestingAbstractProcessor { + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + + try { + processingEnv.getElementUtils().getTypeElement("SuperClass"); + } catch (CompletionFailure cf) { + cf.printStackTrace(); + } + if (round++ == 1) { + try (Writer out = filer.createSourceFile("SuperClass").openWriter()) { + String code = "class SuperClass { public int get() { return 0; } }"; + out.write(code); + out.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + } + + return false; + } + +} diff --git a/langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java new file mode 100644 index 00000000000..a7dbc386324 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/ClassDependingOnGeneratedSource.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 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. + */ + +public abstract class ClassDependingOnGeneratedSource { + ClassWithSuperType f; + public int get() { + return f.get(); + } +} diff --git a/langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java b/langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java new file mode 100644 index 00000000000..bd46b52a54e --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/ClassWithSuperType.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, 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. + */ + +public class ClassWithSuperType extends SuperClass { +} +class SuperClass {} diff --git a/langtools/test/tools/javac/processing/rounds/CompleteOnClosed.java b/langtools/test/tools/javac/processing/rounds/CompleteOnClosed.java new file mode 100644 index 00000000000..5de980774ee --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/CompleteOnClosed.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Ensure that formatting diagnostics with an already closed JavaCompiler won't crash + * the compiler. + * @library /tools/javac/lib + * @build CompleteOnClosed ToolBox JavacTestingAbstractProcessor + * @run main CompleteOnClosed + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; + +public class CompleteOnClosed extends JavacTestingAbstractProcessor { + public static void main(String... args) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector collector = new DiagnosticCollector<>(); + String source = "class Test extends CompleteOnClosedOther {" + + " class Inner extends Undefined { }" + + "}"; + Iterable files = Arrays.asList(new ToolBox.JavaSource(source)); + Iterable options = Arrays.asList("-processor", "CompleteOnClosed"); + CompilationTask task = compiler.getTask(null, null, collector, options, null, files); + task.call(); + for (Diagnostic d : collector.getDiagnostics()) { + System.out.println(d.toString()); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } +} diff --git a/langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java b/langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java new file mode 100644 index 00000000000..836eb29778a --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/CompleteOnClosedOther.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, 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. + */ + +class CompleteOnClosedOther { + Undefined2 undef; +} diff --git a/langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java b/langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java new file mode 100644 index 00000000000..668d05cef17 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/MethodsDroppedBetweenRounds.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Ensure that Symbols for members (methods and fields) are dropped across annotation + * processing rounds. ClassSymbols need to be kept. + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor MethodsDroppedBetweenRounds + * @compile/process -processor MethodsDroppedBetweenRounds MethodsDroppedBetweenRounds.java + */ + +import java.lang.ref.WeakReference; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; + +public class MethodsDroppedBetweenRounds extends JavacTestingAbstractProcessor { + private static TypeElement currentClassSymbol; + private static WeakReference keptMethod = null; + public boolean process(Set annos,RoundEnvironment rEnv) { + if (keptMethod != null) { + //force GC: + List hold = new ArrayList<>(); + try { + while (true) + hold.add(new byte[1024 * 1024 * 1024]); + } catch (OutOfMemoryError err) { } + hold.clear(); + if (keptMethod.get() != null) { + throw new IllegalStateException("Holds method across rounds."); + } + } + + TypeElement currentClass = elements.getTypeElement("MethodsDroppedBetweenRounds"); + + if (currentClassSymbol != null && currentClassSymbol != currentClass) { + throw new IllegalStateException("Different ClassSymbols across rounds"); + } + + ExecutableElement method = ElementFilter.methodsIn(currentClass.getEnclosedElements()).get(0); + + keptMethod = new WeakReference<>(method); + + return true; + } +} diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java new file mode 100644 index 00000000000..c814315a28e --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Verify that annotation processor can overwrite source and class files it generated + * during previous compilations, and that the Symbols are updated appropriatelly. + * @library /tools/javac/lib/ + * @clean * + * @build OverwriteBetweenCompilations ToolBox JavacTestingAbstractProcessor + * @compile/ref=OverwriteBetweenCompilations_1.out -processor OverwriteBetweenCompilations -Apass=1 -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_2.out -processor OverwriteBetweenCompilations -Apass=2 -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_3.out -processor OverwriteBetweenCompilations -Apass=3 -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + */ + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.*; + +import com.sun.tools.javac.processing.JavacProcessingEnvironment; +import com.sun.tools.javac.processing.PrintingProcessor.PrintingElementVisitor; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Log.WriterKind; + +@SupportedOptions("pass") +public class OverwriteBetweenCompilations extends JavacTestingAbstractProcessor { + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + Log log = Log.instance(((JavacProcessingEnvironment) processingEnv).getContext()); + PrintWriter pw = log.getWriter(WriterKind.NOTICE); + + pw.println("round: " + round); + + TypeElement generatedSource = + processingEnv.getElementUtils().getTypeElement("GeneratedSource"); + + if (generatedSource != null) { + new PrintingElementVisitor(pw, processingEnv.getElementUtils()).visit(generatedSource); + pw.flush(); + } + + TypeElement generatedClass = + processingEnv.getElementUtils().getTypeElement("GeneratedClass"); + + if (generatedClass != null) { + new PrintingElementVisitor(pw, processingEnv.getElementUtils()).visit(generatedClass); + pw.flush(); + } + + int pass = Integer.parseInt(processingEnv.getOptions().get("pass")); + + if (round++ == 1) { + try (Writer out = filer.createSourceFile("GeneratedSource").openWriter()) { + String code = pass != 2 ? GENERATED_INIT : GENERATED_UPDATE; + code = code.replace("NAME", "GeneratedSource"); + out.write(code); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + try (OutputStream out = filer.createClassFile("GeneratedClass").openOutputStream()) { + String code = pass != 2 ? GENERATED_INIT : GENERATED_UPDATE; + code = code.replace("NAME", "GeneratedClass"); + ToolBox.JavaToolArgs args = + new ToolBox.JavaToolArgs().appendArgs("-parameters").setSources(code); + Map codeMap = ToolBox.compile(args); + out.write(codeMap.get("GeneratedClass")); + } catch (IOException | ToolBox.CommandExecutionException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.toString()); + } + } + + return false; + } + + //the initial generated class - "NAME" will be replaced with either "GeneratedSource" or + //"GeneratedClass" while generating the class: + private static final String GENERATED_INIT = + "@Deprecated\n" + + "public class NAME extends java.util.ArrayList\n" + + " implements Runnable {\n" + + " public void test(int a) { }\n" + + " public void run() { }\n" + + "}"; + + //generated class update- "NAME" will be replaced with either "GeneratedSource" or + //"GeneratedClass" while generating the class: + private static final String GENERATED_UPDATE = + "@javax.annotation.processing.SupportedAnnotationTypes(\"*\")\n" + + "public abstract class NAME extends java.util.LinkedList" + + " implements Runnable, CharSequence {\n" + + " public void test(long a) { }\n" + + "}"; +} diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java new file mode 100644 index 00000000000..6d07007f334 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilationsSource.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014, 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. + */ + +public abstract class OverwriteBetweenCompilationsSource extends GeneratedSource { +} diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out new file mode 100644 index 00000000000..1840ca9205e --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out @@ -0,0 +1,45 @@ +round: 1 +round: 2 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +round: 3 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java +- compiler.note.deprecated.recompile diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out new file mode 100644 index 00000000000..d1bf374bb74 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out @@ -0,0 +1,57 @@ +round: 1 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +round: 2 + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedSource(); + + public void test(long a); +} + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedClass(); + + public void test(long a); +} +round: 3 + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedSource(); + + public void test(long a); +} + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedClass(); + + public void test(long a); +} +- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java +- compiler.note.deprecated.recompile diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out new file mode 100644 index 00000000000..39b044ec78a --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out @@ -0,0 +1,61 @@ +round: 1 + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedSource(); + + public void test(long a); +} + +@javax.annotation.processing.SupportedAnnotationTypes({"*"}) +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { + + public GeneratedClass(); + + public void test(long a); +} +round: 2 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +round: 3 + +@java.lang.Deprecated +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedSource(); + + public void test(int a); + + public void run(); +} + +@java.lang.Deprecated +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { + + public GeneratedClass(); + + public void test(int a); + + public void run(); +} +- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java +- compiler.note.deprecated.recompile diff --git a/langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java b/langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java new file mode 100644 index 00000000000..743f6762848 --- /dev/null +++ b/langtools/test/tools/javac/processing/rounds/TypesCachesCleared.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, 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 8038455 + * @summary Verify that Types caches (in particular MembersClosureCache) get cleared between rounds. + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor TypesCachesCleared + * @compile/process -processor TypesCachesCleared TypesCachesCleared.java + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import static javax.lang.model.util.ElementFilter.constructorsIn; +import javax.lang.model.util.Elements; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; + +public class TypesCachesCleared extends JavacTestingAbstractProcessor { + int round = 1; + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + new TestPathScanner() { + @Override + public void visit(Void t) { + } + }; + TypeElement currentClass = elements.getTypeElement("TypesCachesCleared"); + Trees trees = Trees.instance(processingEnv); + TreePath path = trees.getPath(currentClass); + new TreePathScanner() { + @Override public Void visitClass(ClassTree node, Void p) { + trees.getElement(getCurrentPath()); + return super.visitClass(node, p); + } + }.scan(path, null); + return false; + } + + public TypesCachesCleared() { + class Local { } + new Object() { }; + } + + public boolean process(Elements elements) { + TypeElement currentClass = elements.getTypeElement("OnDemandAttribution"); + ExecutableElement constr = constructorsIn(currentClass.getEnclosedElements()).get(0); + Trees trees = Trees.instance(processingEnv); + TreePath path = trees.getPath(constr); + + new TreePathScanner() { + @Override public Void visitClass(ClassTree node, Void p) { + if (node.getSimpleName().contentEquals("Local")) { + //will also attribute the body on demand: + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el); + if (!binaryName.contentEquals("OnDemandAttribution$1Local")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + } + return super.visitClass(node, p); + } + @Override public Void visitNewClass(NewClassTree node, Void p) { + Element el = trees.getElement(getCurrentPath()); + Name binaryName = elements.getBinaryName((TypeElement) el.getEnclosingElement()); + if (!binaryName.contentEquals("OnDemandAttribution$1")) { + throw new IllegalStateException("Incorrect binary name=" + binaryName); + } + return super.visitNewClass(node, p); + } + }.scan(path, null); + + return true; + } + public static interface TestVisitor { + public void visit(T t); + } + + public static class TestScanner implements TestVisitor { + public void visit(T t) { } + } + + public static class TestPathScanner extends TestScanner { + public void visit(T t) { } + } +} diff --git a/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out b/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out index bd1f2766ea0..f76a3c011a1 100644 --- a/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out +++ b/langtools/test/tools/javac/processing/warnings/gold_unsp_warn.out @@ -1 +1,2 @@ - compiler.warn.proc.unmatched.processor.options: [unsupported] +1 warning diff --git a/langtools/test/tools/javac/util/context/T7021650.java b/langtools/test/tools/javac/util/context/T7021650.java index 5801b03b2f5..4bc314b2089 100644 --- a/langtools/test/tools/javac/util/context/T7021650.java +++ b/langtools/test/tools/javac/util/context/T7021650.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -56,7 +56,7 @@ public class T7021650 extends JavacTestingAbstractProcessor { * and verify that corresponding objects are created in each round. */ void run() throws Exception { - Counter demoCounter = new Counter(); + Counter myDemoCounter = new Counter(); Counter myAttrCounter = new Counter(); Context context = new Context(); @@ -76,7 +76,7 @@ public class T7021650 extends JavacTestingAbstractProcessor { } }); - Demo.preRegister(context, demoCounter); + MyDemo.preRegister(context, myDemoCounter); MyAttr.preRegister(context, myAttrCounter); String[] args = { @@ -88,13 +88,9 @@ public class T7021650 extends JavacTestingAbstractProcessor { compile(context, args); - // Expect to create Demo for initial round, then MAX_ROUNDS in which - // GenX files are generated, then standard final round of processing. - checkEqual("demoCounter", demoCounter.count, MAX_ROUNDS + 2); - - // Expect to create MyAttr for same processing rounds as for Demo, - // plus additional context for final compilation. - checkEqual("myAttrCounter", myAttrCounter.count, MAX_ROUNDS + 3); + // the services should only be created once in the current scheme: + checkEqual("demoCounter", myDemoCounter.count, 1); + checkEqual("myAttrCounter", myAttrCounter.count, 1); } void compile(Context context, String... args) throws Exception { @@ -123,15 +119,6 @@ public class T7021650 extends JavacTestingAbstractProcessor { * A custom class unknown to javac but nonetheless registered in the context. */ static class Demo { - static void preRegister(Context context, final Counter counter) { - context.put(Demo.class, new Context.Factory() { - public Demo make(Context c) { - counter.count++; - return new Demo(c); - } - }); - } - Demo(Context c) { c.put(Demo.class, this); } @@ -141,6 +128,21 @@ public class T7021650 extends JavacTestingAbstractProcessor { } } + static class MyDemo extends Demo { + static void preRegister(Context context, final Counter counter) { + context.put(Demo.class, new Context.Factory() { + public Demo make(Context c) { + counter.count++; + return new MyDemo(c); + } + }); + } + + MyDemo(Context c) { + super(c); + } + } + /** * A custom version of a standard javac component. */ @@ -174,7 +176,7 @@ public class T7021650 extends JavacTestingAbstractProcessor { Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); // verify items in context as expected - check("Demo", Demo.instance(context), Demo.class); + check("Demo", Demo.instance(context), MyDemo.class); check("Attr", Attr.instance(context), MyAttr.class); // For a few rounds, generate new source files, so that we can check whether From 5905e8f494cefe7adfd9d91a9918d35b99ef1845 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 8 Apr 2014 23:33:50 +0200 Subject: [PATCH 133/170] 8039466: Tests failing in langtools repository Fixing tests broken by JDK-8038455. Reviewed-by: jjg --- .../tools/javac/processing/errors/TestBadProcessor.java | 3 ++- .../processing/rounds/OverwriteBetweenCompilations.java | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/langtools/test/tools/javac/processing/errors/TestBadProcessor.java b/langtools/test/tools/javac/processing/errors/TestBadProcessor.java index 44e21821b0e..065c7bfbf7c 100644 --- a/langtools/test/tools/javac/processing/errors/TestBadProcessor.java +++ b/langtools/test/tools/javac/processing/errors/TestBadProcessor.java @@ -75,7 +75,8 @@ public class TestBadProcessor { "javax.annotation.processing.Processor: " + "Provider AnnoProc could not be instantiated: java.lang.Error\n" + "1 error"; - if (!out.trim().equals(expect)) { + String lineSeparator = System.getProperty("line.separator"); + if (!out.trim().replace(lineSeparator, "\n").equals(expect)) { System.err.println("expected: " + expect); error("output not as expected"); } diff --git a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java index c814315a28e..e2bde26e5e1 100644 --- a/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java +++ b/langtools/test/tools/javac/processing/rounds/OverwriteBetweenCompilations.java @@ -29,9 +29,9 @@ * @library /tools/javac/lib/ * @clean * * @build OverwriteBetweenCompilations ToolBox JavacTestingAbstractProcessor - * @compile/ref=OverwriteBetweenCompilations_1.out -processor OverwriteBetweenCompilations -Apass=1 -XDrawDiagnostics OverwriteBetweenCompilationsSource.java - * @compile/ref=OverwriteBetweenCompilations_2.out -processor OverwriteBetweenCompilations -Apass=2 -XDrawDiagnostics OverwriteBetweenCompilationsSource.java - * @compile/ref=OverwriteBetweenCompilations_3.out -processor OverwriteBetweenCompilations -Apass=3 -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_1.out -processor OverwriteBetweenCompilations -Apass=1 -parameters -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_2.out -processor OverwriteBetweenCompilations -Apass=2 -parameters -XDrawDiagnostics OverwriteBetweenCompilationsSource.java + * @compile/ref=OverwriteBetweenCompilations_3.out -processor OverwriteBetweenCompilations -Apass=3 -parameters -XDrawDiagnostics OverwriteBetweenCompilationsSource.java */ import java.io.*; From c654c5a23e67bac590a9fe3fb054fc1a1d223f60 Mon Sep 17 00:00:00 2001 From: Paul Govereau Date: Wed, 9 Apr 2014 17:41:27 +0100 Subject: [PATCH 134/170] 8015499: javac, Gen is generating extra checkcast instructions in some corner cases Reviewed-by: vromero, jjg --- .../com/sun/tools/javac/comp/TransTypes.java | 2 +- .../tools/javac/T7053059/DoubleCastTest.java | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/T7053059/DoubleCastTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java index 9c30d1b9834..29f0215137c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -748,7 +748,7 @@ public class TransTypes extends TreeTranslator { tree.clazz = translate(tree.clazz, null); Type originalTarget = tree.type; tree.type = erasure(tree.type); - tree.expr = translate(tree.expr, tree.type); + tree.expr = translate(tree.expr, erasure(tree.expr.type)); if (originalTarget.isCompound()) { Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget; for (Type c : ict.getExplicitComponents()) { diff --git a/langtools/test/tools/javac/T7053059/DoubleCastTest.java b/langtools/test/tools/javac/T7053059/DoubleCastTest.java new file mode 100644 index 00000000000..6c96bd930d3 --- /dev/null +++ b/langtools/test/tools/javac/T7053059/DoubleCastTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 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 8015499 + * @summary javac, Gen is generating extra checkcast instructions in some corner cases + * @run main DoubleCastTest + */ + +import java.util.List; +import java.util.ArrayList; +import com.sun.tools.classfile.*; +import com.sun.tools.javac.util.Assert; + +public class DoubleCastTest { + class C { + Object x; + Object m() { return null; } + void m1(byte[] b) {} + void m2() { + Object o; + Object[] os = null; + m1((byte[])(o = null)); + m1((byte[])o); + m1((byte[])(o == null ? o : o)); + m1((byte[])m()); + m1((byte[])os[0]); + m1((byte[])this.x); + } + } + + public static void main(String... cmdline) throws Exception { + + ClassFile cls = ClassFile.read(DoubleCastTest.class.getResourceAsStream("DoubleCastTest$C.class")); + for (Method m: cls.methods) + check(m); + } + + static void check(Method m) throws Exception { + boolean last_is_cast = false; + int last_ref = 0; + Code_attribute ea = (Code_attribute)m.attributes.get(Attribute.Code); + for (Instruction i : ea.getInstructions()) { + if (i.getOpcode() == Opcode.CHECKCAST) { + Assert.check + (!(last_is_cast && last_ref == i.getUnsignedShort(1)), + "Double cast found - Test failed"); + last_is_cast = true; + last_ref = i.getUnsignedShort(1); + } else { + last_is_cast = false; + } + } + } +} From b3439195261f36835966d551fb50cfcff447a67b Mon Sep 17 00:00:00 2001 From: Eric McCorkle Date: Thu, 3 Apr 2014 20:28:23 -0400 Subject: [PATCH 135/170] 8038263: Refactor annotation handling after actualEnterAnnotations Move all repeating annotations code into Annotate, rework annotations pipeline into a more completer-like design, eliminate a cast from enterAnnotations/enterTypeAnnotations Reviewed-by: jjg, jfranck --- .../com/sun/tools/javac/code/Symbol.java | 9 - .../sun/tools/javac/code/SymbolMetadata.java | 213 --------- .../com/sun/tools/javac/comp/Annotate.java | 409 ++++++++++++------ 3 files changed, 282 insertions(+), 349 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index ecc7de9e64e..6e0f5ad2369 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -34,7 +34,6 @@ import javax.lang.model.element.*; import javax.tools.JavaFileObject; import com.sun.tools.javac.code.Type.*; -import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; @@ -153,10 +152,6 @@ public abstract class Symbol extends AnnoConstruct implements Element { } } - public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - initedMetadata().appendTypeAttributesWithCompletion(ctx); - } - public void appendUniqueTypeAttributes(List l) { if (l.nonEmpty()) { initedMetadata().appendUniqueTypes(l); @@ -211,10 +206,6 @@ public abstract class Symbol extends AnnoConstruct implements Element { } } - public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - initedMetadata().setDeclarationAttributesWithCompletion(ctx); - } - public void setTypeAttributes(List a) { if (metadata != null || a.nonEmpty()) { if (metadata == null) diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java b/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java index f41dae9f5cf..ca7c9ff634b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/SymbolMetadata.java @@ -25,19 +25,9 @@ package com.sun.tools.javac.code; -import java.util.Map; -import javax.tools.JavaFileObject; - -import com.sun.tools.javac.comp.Annotate; -import com.sun.tools.javac.comp.AttrContext; -import com.sun.tools.javac.comp.Env; -import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Pair; -import static com.sun.tools.javac.code.Kinds.PCK; /** * Container for all annotations (attributes in javac) on a Symbol. @@ -157,70 +147,6 @@ public class SymbolMetadata { setClassInitTypeAttributes(other.getClassInitTypeAttributes()); } - public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); - this.setDeclarationAttributes(getAttributesForCompletion(ctx)); - } - - public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { - this.appendUniqueTypes(getAttributesForCompletion(ctx)); - } - - private List getAttributesForCompletion( - final Annotate.AnnotateRepeatedContext ctx) { - - Map> annotated = ctx.annotated; - boolean atLeastOneRepeated = false; - List buf = List.nil(); - for (ListBuffer lb : annotated.values()) { - if (lb.size() == 1) { - buf = buf.prepend(lb.first()); - } else { // repeated - // This will break when other subtypes of Attributs.Compound - // are introduced, because PlaceHolder is a subtype of TypeCompound. - T res; - @SuppressWarnings("unchecked") - T ph = (T) new Placeholder<>(ctx, lb.toList(), sym); - res = ph; - buf = buf.prepend(res); - atLeastOneRepeated = true; - } - } - - if (atLeastOneRepeated) { - // The Symbol s is now annotated with a combination of - // finished non-repeating annotations and placeholders for - // repeating annotations. - // - // We need to do this in two passes because when creating - // a container for a repeating annotation we must - // guarantee that the @Repeatable on the - // contained annotation is fully annotated - // - // The way we force this order is to do all repeating - // annotations in a pass after all non-repeating are - // finished. This will work because @Repeatable - // is non-repeating and therefore will be annotated in the - // fist pass. - - // Queue a pass that will replace Attribute.Placeholders - // with Attribute.Compound (made from synthesized containers). - ctx.annotateRepeated(new Annotate.Worker() { - @Override - public String toString() { - return "repeated annotation pass of: " + sym + " in: " + sym.owner; - } - - @Override - public void run() { - complete(ctx); - } - }); - } - // Add non-repeating attributes - return buf.reverse(); - } - public SymbolMetadata reset() { attributes = DECL_IN_PROGRESS; return this; @@ -313,143 +239,4 @@ public class SymbolMetadata { private boolean isStarted() { return attributes != DECL_NOT_STARTED; } - - private List getPlaceholders() { - List res = List.nil(); - for (Attribute.Compound a : filterDeclSentinels(attributes)) { - if (a instanceof Placeholder) { - res = res.prepend(a); - } - } - return res.reverse(); - } - - private List getTypePlaceholders() { - List res = List.nil(); - for (Attribute.TypeCompound a : type_attributes) { - if (a instanceof Placeholder) { - res = res.prepend(a); - } - } - return res.reverse(); - } - - /* - * Replace Placeholders for repeating annotations with their containers - */ - private void complete(Annotate.AnnotateRepeatedContext ctx) { - Log log = ctx.log; - Env env = ctx.env; - JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); - try { - // TODO: can we reduce duplication in the following branches? - if (ctx.isTypeCompound) { - Assert.check(!isTypesEmpty()); - - if (isTypesEmpty()) { - return; - } - - List result = List.nil(); - for (Attribute.TypeCompound a : getTypeAttributes()) { - if (a instanceof Placeholder) { - @SuppressWarnings("unchecked") - Placeholder ph = (Placeholder) a; - Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext()); - - if (null != replacement) { - result = result.prepend(replacement); - } - } else { - result = result.prepend(a); - } - } - - type_attributes = result.reverse(); - - Assert.check(SymbolMetadata.this.getTypePlaceholders().isEmpty()); - } else { - Assert.check(!pendingCompletion()); - - if (isEmpty()) { - return; - } - - List result = List.nil(); - for (Attribute.Compound a : getDeclarationAttributes()) { - if (a instanceof Placeholder) { - @SuppressWarnings("unchecked") - Attribute.Compound replacement = replaceOne((Placeholder) a, ctx); - - if (null != replacement) { - result = result.prepend(replacement); - } - } else { - result = result.prepend(a); - } - } - - attributes = result.reverse(); - - Assert.check(SymbolMetadata.this.getPlaceholders().isEmpty()); - } - } finally { - log.useSource(oldSource); - } - } - - private T replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) { - Log log = ctx.log; - - // Process repeated annotations - T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); - - if (validRepeated != null) { - // Check that the container isn't manually - // present along with repeated instances of - // its contained annotation. - ListBuffer manualContainer = ctx.annotated.get(validRepeated.type.tsym); - if (manualContainer != null) { - log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", - manualContainer.first().type.tsym); - } - } - - // A null return will delete the Placeholder - return validRepeated; - } - - private static class Placeholder extends Attribute.TypeCompound { - - private final Annotate.AnnotateRepeatedContext ctx; - private final List placeholderFor; - private final Symbol on; - - public Placeholder(Annotate.AnnotateRepeatedContext ctx, - List placeholderFor, Symbol on) { - super(on.type, List.>nil(), - ctx.isTypeCompound ? - ((Attribute.TypeCompound)placeholderFor.head).position : - // TODO: Eventually, we will need to get rid of this - // use of unknown, either by using null, or by - // throwing an assertion failure here. - TypeAnnotationPosition.unknown); - this.ctx = ctx; - this.placeholderFor = placeholderFor; - this.on = on; - } - - @Override - public String toString() { - return ""; - } - - public List getPlaceholderFor() { - return placeholderFor; - } - - public Annotate.AnnotateRepeatedContext getRepeatedContext() { - return ctx; - } - } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java index 1a9e0626b1c..04e475e7b3c 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -189,53 +189,72 @@ public class Annotate { * This context contains all the information needed to synthesize new * annotations trees by the completer for repeating annotations. */ - public class AnnotateRepeatedContext { + private class AnnotationContext { public final Env env; public final Map> annotated; public final Map pos; - public final Log log; public final boolean isTypeCompound; - public AnnotateRepeatedContext(Env env, - Map> annotated, - Map pos, - Log log, - boolean isTypeCompound) { + public AnnotationContext(Env env, + Map> annotated, + Map pos, + boolean isTypeCompound) { Assert.checkNonNull(env); Assert.checkNonNull(annotated); Assert.checkNonNull(pos); - Assert.checkNonNull(log); this.env = env; this.annotated = annotated; this.pos = pos; - this.log = log; this.isTypeCompound = isTypeCompound; } - /** - * Process a list of repeating annotations returning a new - * Attribute.Compound that is the attribute for the synthesized tree - * for the container. - * - * @param repeatingAnnotations a List of repeating annotations - * @return a new Attribute.Compound that is the container for the repeatingAnnotations - */ - public T processRepeatedAnnotations(List repeatingAnnotations, Symbol sym) { - return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym); - } - - /** - * Queue the Worker a on the repeating annotations queue of the - * Annotate instance this context belongs to. - * - * @param a the Worker to enqueue for repeating annotation annotating - */ - public void annotateRepeated(Worker a) { - Annotate.this.repeated(a); + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RepeatedContext["); + for (Map.Entry> entry : + annotated.entrySet()) { + sb.append(" "); + sb.append(entry.getKey()); + sb.append(" = { "); + sb.append(entry.getValue()); + sb.append(" }"); + } + sb.append(" ]"); + return sb.toString(); } } + private static class Placeholder extends Attribute.Compound { + + private final Annotate.AnnotationContext ctx; + private final List placeholderFor; + private final Symbol on; + + public Placeholder(Annotate.AnnotationContext ctx, + List placeholderFor, Symbol on) { + super(on.type, List.>nil(), + placeholderFor.head.position); + this.ctx = ctx; + this.placeholderFor = placeholderFor; + this.on = on; + } + + @Override + public String toString() { + return ""; + } + + public List getPlaceholderFor() { + return placeholderFor; + } + + public Annotate.AnnotationContext getRepeatedContext() { + return ctx; + } + } + + /* ******************************************************************** * Compute an attribute from its annotation. *********************************************************************/ @@ -247,24 +266,44 @@ public class Annotate { Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, Env env) { - return enterAnnotation(a, expected, env, false); + List> elems = + enterAttributeValues(a, expected, env); + Attribute.Compound ac = new Attribute.Compound(a.type, elems); + a.attribute = ac; + + return ac; } Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a, - Type expected, - Env env) { - return (Attribute.TypeCompound) enterAnnotation(a, expected, env, true); + Type expected, + Env env) { + List> elems = + enterAttributeValues(a, expected, env); + + if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { + // Create a new TypeCompound + + Attribute.TypeCompound tc = + new Attribute.TypeCompound(a.type, elems, + // TODO: Eventually, we will get rid of this use of + // unknown, because we'll get a position from + // MemberEnter (task 8027262). + TypeAnnotationPosition.unknown); + a.attribute = tc; + return tc; + } else { + // Use an existing TypeCompound + return (Attribute.TypeCompound)a.attribute; + } } - // boolean typeAnnotation determines whether the method returns - // a Compound (false) or TypeCompound (true). - Attribute.Compound enterAnnotation(JCAnnotation a, - Type expected, - Env env, - boolean typeAnnotation) { - // The annotation might have had its type attributed (but not checked) - // by attr.attribAnnotationTypes during MemberEnter, in which case we do not - // need to do it again. + private List> + enterAttributeValues(JCAnnotation a, + Type expected, + Env env) { + // The annotation might have had its type attributed (but not + // checked) by attr.attribAnnotationTypes during MemberEnter, + // in which case we do not need to do it again. Type at = (a.annotationType.type != null ? a.annotationType.type : attr.attribType(a.annotationType, env)); a.type = chk.checkType(a.annotationType.pos(), at, expected); @@ -312,27 +351,7 @@ public class Annotate { buf.append(new Pair<>((MethodSymbol)method, value)); t.type = result; } - if (typeAnnotation) { - if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { - // Create a new TypeCompound - - Attribute.TypeCompound tc = - new Attribute.TypeCompound(a.type, buf.toList(), - // TODO: Eventually, we will get rid of this use of - // unknown, because we'll get a position from - // MemberEnter (task 8027262). - TypeAnnotationPosition.unknown); - a.attribute = tc; - return tc; - } else { - // Use an existing TypeCompound - return a.attribute; - } - } else { - Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList()); - a.attribute = ac; - return ac; - } + return buf.toList(); } Attribute enterAttributeValue(Type expected, @@ -459,7 +478,7 @@ public class Annotate { * annotation are invalid. This method reports errors/warnings. */ private T processRepeatedAnnotations(List annotations, - AnnotateRepeatedContext ctx, + AnnotationContext ctx, Symbol on) { T firstOccurrence = annotations.head; List repeated = List.nil(); @@ -686,6 +705,172 @@ public class Annotate { return fatalError ? null : containerValueSymbol; } + private AnnotationContext + prepareEnterAnnotations(List annotations, + Env env, + Symbol sym, + AttributeCreator creator, + boolean isTypeCompound) { + Map> annotated = new LinkedHashMap<>(); + Map pos = new HashMap<>(); + + for (List al = annotations; !al.isEmpty(); al = al.tail) { + JCAnnotation a = al.head; + T c = creator.create(a, syms.annotationType, env); + + Assert.checkNonNull(c, "Failed to create annotation"); + + if (annotated.containsKey(a.type.tsym)) { + if (!allowRepeatedAnnos) { + log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); + allowRepeatedAnnos = true; + } + ListBuffer l = annotated.get(a.type.tsym); + l = l.append(c); + annotated.put(a.type.tsym, l); + pos.put(c, a.pos()); + } else { + annotated.put(a.type.tsym, ListBuffer.of(c)); + pos.put(c, a.pos()); + } + + // Note: @Deprecated has no effect on local variables and parameters + if (!c.type.isErroneous() + && sym.owner.kind != MTH + && types.isSameType(c.type, syms.deprecatedType)) { + sym.flags_field |= Flags.DEPRECATED; + } + } + + return new AnnotationContext<>(env, annotated, pos, + isTypeCompound); + } + + // Gather up annotations into a map from type symbols to lists of + // Compound attributes, then continue on with repeating + // annotations processing + private + void attachAttributesLater(final List annotations, + final Env env, + final Symbol sym, + final boolean isTypeCompound, + final AttributeCreator creator, + final AttributeAttacher attacher) { + final AnnotationContext ctx = + prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound); + final Map> annotated = + ctx.annotated; + boolean hasRepeated = false; + + List buf = List.nil(); + for (ListBuffer lb : annotated.values()) { + if (lb.size() == 1) { + buf = buf.prepend(lb.first()); + } else { + @SuppressWarnings("unchecked") + T res = (T) new Placeholder<>(ctx, lb.toList(), sym); + buf = buf.prepend(res); + hasRepeated = true; + } + } + + final List attrs = buf.reverse(); + + if (!isTypeCompound) { + // Attach declaration attributes early, so + // that @Repeatable and other annotations get attached. + // Since the attacher uses setDeclarationAttributes, this + // will be overwritten later. + attacher.attach(sym, attrs); + } + if (hasRepeated) { + repeated(new Annotate.Worker() { + @Override + public String toString() { + return "repeated annotation pass of: " + sym + " in: " + sym.owner; + } + + @Override + public void run() { + JavaFileObject oldSource = + log.useSource(env.toplevel.sourcefile); + try { + attacher.attach(sym, replacePlaceholders(attrs, ctx, sym)); + } finally { + log.useSource(oldSource); + } + } + }); + } else { + attacher.attach(sym, attrs); + } + } + + private interface AttributeAttacher { + public void attach(Symbol sym, List attrs); + } + + private final AttributeAttacher declAnnotationsAttacher = + new AttributeAttacher() { + @Override + public void attach(Symbol sym, List attrs) { + sym.resetAnnotations(); + sym.setDeclarationAttributes(attrs); + } + }; + + private final AttributeAttacher typeAnnotationsAttacher = + new AttributeAttacher() { + @Override + public void attach(Symbol sym, List attrs) { + sym.appendUniqueTypeAttributes(attrs); + } + }; + + private List + replacePlaceholders(List buf, + Annotate.AnnotationContext ctx, + Symbol sym) { + List result = List.nil(); + for (T a : buf) { + if (a instanceof Placeholder) { + @SuppressWarnings("unchecked") + T replacement = replaceOne((Placeholder) a, ctx, sym); + + if (null != replacement) { + result = result.prepend(replacement); + } + } else { + result = result.prepend(a); + } + } + + return result.reverse(); + } + + private T replaceOne(Placeholder placeholder, + Annotate.AnnotationContext ctx, + Symbol sym) { + // Process repeated annotations + T validRepeated = + processRepeatedAnnotations(placeholder.getPlaceholderFor(), + ctx, sym); + + if (validRepeated != null) { + // Check that the container isn't manually + // present along with repeated instances of + // its contained annotation. + ListBuffer manualContainer = ctx.annotated.get(validRepeated.type.tsym); + if (manualContainer != null) { + log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", + manualContainer.first().type.tsym); + } + } + + // A null return will delete the Placeholder + return validRepeated; + } + /* ******************************************************************** * Annotation processing *********************************************************************/ @@ -745,44 +930,39 @@ public class Annotate { }); } + private interface AttributeCreator { + public T create(JCAnnotation a, Type expected, Env env); + } + + // TODO: When SE8 features can be used, these can go away and be + // replaced by method refs. + private final AttributeCreator enterAnnotationsCreator = + new AttributeCreator() { + @Override + public Attribute.Compound create(JCAnnotation a, + Type expected, + Env env) { + return enterAnnotation(a, syms.annotationType, env); + } + }; + private final AttributeCreator enterTypeAnnotationsCreator = + new AttributeCreator() { + @Override + public Attribute.TypeCompound create(JCAnnotation a, + Type expected, + Env env) { + return enterTypeAnnotation(a, syms.annotationType, env); + } + }; + /** Enter a set of annotations. */ private void actualEnterAnnotations(List annotations, Env env, Symbol s) { - Map> annotated = new LinkedHashMap<>(); - Map pos = new HashMap<>(); - - for (List al = annotations; !al.isEmpty(); al = al.tail) { - JCAnnotation a = al.head; - Attribute.Compound c = enterAnnotation(a, syms.annotationType, env); - if (c == null) { - continue; - } - - if (annotated.containsKey(a.type.tsym)) { - if (!allowRepeatedAnnos) { - log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); - allowRepeatedAnnos = true; - } - ListBuffer l = annotated.get(a.type.tsym); - l = l.append(c); - annotated.put(a.type.tsym, l); - pos.put(c, a.pos()); - } else { - annotated.put(a.type.tsym, ListBuffer.of(c)); - pos.put(c, a.pos()); - } - - // Note: @Deprecated has no effect on local variables and parameters - if (!c.type.isErroneous() - && s.owner.kind != MTH - && types.isSameType(c.type, syms.deprecatedType)) { - s.flags_field |= Flags.DEPRECATED; - } - } - - s.setDeclarationAttributesWithCompletion( - new AnnotateRepeatedContext<>(env, annotated, pos, log, false)); + Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null"); + attachAttributesLater(annotations, env, s, false, + enterAnnotationsCreator, + declAnnotationsAttacher); } /* @@ -792,9 +972,7 @@ public class Annotate { final Env env, final Symbol s, final DiagnosticPosition deferPos) { - Map> annotated = new LinkedHashMap<>(); - Map pos = new HashMap<>(); - + Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); DiagnosticPosition prevLintPos = null; @@ -802,32 +980,9 @@ public class Annotate { prevLintPos = deferredLintHandler.setPos(deferPos); } try { - - for (List al = annotations; !al.isEmpty(); al = al.tail) { - JCAnnotation a = al.head; - Attribute.TypeCompound tc = - enterTypeAnnotation(a, syms.annotationType, env); - - Assert.checkNonNull(tc, "Failed to create type annotation"); - - if (annotated.containsKey(a.type.tsym)) { - if (!allowRepeatedAnnos) { - log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); - allowRepeatedAnnos = true; - } - ListBuffer l = annotated.get(a.type.tsym); - l = l.append(tc); - annotated.put(a.type.tsym, l); - pos.put(tc, a.pos()); - } else { - annotated.put(a.type.tsym, ListBuffer.of(tc)); - pos.put(tc, a.pos()); - } - } - - Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is null"); - s.appendTypeAttributesWithCompletion( - new AnnotateRepeatedContext<>(env, annotated, pos, log, true)); + attachAttributesLater(annotations, env, s, true, + enterTypeAnnotationsCreator, + typeAnnotationsAttacher); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); From 213f53d60d885bdac3975f582cb7a2519936688a Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Fri, 4 Apr 2014 14:58:04 +0400 Subject: [PATCH 136/170] 8029073: (corba) New connection reclaimed when number of connection is greater than highwatermark Reviewed-by: coffeys --- .../se/impl/transport/SocketOrChannelAcceptorImpl.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/corba/src/share/classes/com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.java b/corba/src/share/classes/com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.java index e5fb14c754f..18023b5b9de 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/transport/SocketOrChannelAcceptorImpl.java @@ -253,6 +253,13 @@ public class SocketOrChannelAcceptorImpl // registered with the selector. Otherwise if the bytes // are read on the connection it will attempt a time stamp // but the cache will be null, resulting in NPE. + + // A connection needs to be timestamped before putting to the cache. + // Otherwise the newly created connection (with 0 timestamp) could be + // incorrectly reclaimed by concurrent reclaim() call OR if there + // will be no events on this connection then it could be reclaimed + // by upcoming reclaim() call. + getConnectionCache().stampTime(connection); getConnectionCache().put(this, connection); if (connection.shouldRegisterServerReadEvent()) { From 9c4f5b069bda54fe94fcdf54d3ddfc3643194b0f Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 4 Apr 2014 17:10:44 +0200 Subject: [PATCH 137/170] 8039030: 9-dev windows-i586 build failed with mktemp: command not found Reviewed-by: alanb, katleman --- common/autoconf/generated-configure.sh | 5 ++++- common/autoconf/toolchain_windows.m4 | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 120e944331f..49daece9891 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -4243,7 +4243,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++" #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1396297437 +DATE_WHEN_GENERATED=1396624161 ############################################################################### # @@ -27449,6 +27449,9 @@ $as_echo "ok" >&6; } VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'` WindowsSDKDir=`$ECHO "$WindowsSDKDir" | $SED 's/\\\\* *$//'` WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'` + # Remove any paths containing # (typically F#) as that messes up make. This + # is needed if visual studio was installed with F# support. + VS_PATH=`$ECHO "$VS_PATH" | $SED 's/[^:#]*#[^:]*://g'` diff --git a/common/autoconf/toolchain_windows.m4 b/common/autoconf/toolchain_windows.m4 index 81d0a964a4d..b4888a46ac5 100644 --- a/common/autoconf/toolchain_windows.m4 +++ b/common/autoconf/toolchain_windows.m4 @@ -211,6 +211,9 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV], VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'` WindowsSDKDir=`$ECHO "$WindowsSDKDir" | $SED 's/\\\\* *$//'` WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'` + # Remove any paths containing # (typically F#) as that messes up make. This + # is needed if visual studio was installed with F# support. + VS_PATH=`$ECHO "$VS_PATH" | $SED 's/[[^:#]]*#[^:]*://g'` AC_SUBST(VS_PATH) AC_SUBST(VS_INCLUDE) From fbd69476956ecd8131850aeeb2a04b22d6743f87 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Mon, 7 Apr 2014 08:09:55 +0200 Subject: [PATCH 138/170] 8039256: Add sun/jvmstat/monitor/MonitoredVm/CR6672135.java to ProblemList.txt Reviewed-by: mgronlun, alanb --- jdk/test/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 729a0d852dd..2b18741c05b 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -273,4 +273,7 @@ java/lang/instrument/NativeMethodPrefixAgent.java generic-all # 8031482 sun/tools/jcmd/TestJcmdSanity.java windows-all +# 8033104 +sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all + ############################################################################ From ffbb7125b25a88f4495d94c9c8fb25af89af1856 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 7 Apr 2014 10:59:50 +0200 Subject: [PATCH 139/170] 8035134: JDK9 unix debug bundle manifest file list issue Reviewed-by: ihse --- make/common/NativeCompilation.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 6dabbb4f53e..1b513ad7ce2 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -482,7 +482,7 @@ define SetupNativeCompilation # to be rebuilt properly. $$($1_DEBUGINFO_ZIP): $$($1_DEBUGINFO_FILES) $$($1_TARGET) $(CD) $$($1_OBJECT_DIR) \ - && $(ZIP) -q $$@ $$($1_DEBUGINFO_FILES) + && $(ZIP) -q $$@ $$(notdir $$($1_DEBUGINFO_FILES)) else $1 += $$(subst $$($1_OBJECT_DIR),$$($1_OUTPUT_DIR),$$($1_DEBUGINFO_FILES)) From f046294abc1c5505ad203fa20de3a488463632a5 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 7 Apr 2014 13:16:17 +0100 Subject: [PATCH 140/170] 8039253: Remove undocumented com.oracle.net Reviewed-by: chegar --- jdk/src/share/classes/com/oracle/net/Sdp.java | 201 ------------------ .../share/classes/java/net/SdpSocketImpl.java | 49 ----- jdk/test/TEST.groups | 1 - jdk/test/com/oracle/net/Sanity.java | 142 ------------- jdk/test/com/oracle/net/sanity.sh | 66 ------ 5 files changed, 459 deletions(-) delete mode 100644 jdk/src/share/classes/com/oracle/net/Sdp.java delete mode 100644 jdk/src/share/classes/java/net/SdpSocketImpl.java delete mode 100644 jdk/test/com/oracle/net/Sanity.java delete mode 100644 jdk/test/com/oracle/net/sanity.sh diff --git a/jdk/src/share/classes/com/oracle/net/Sdp.java b/jdk/src/share/classes/com/oracle/net/Sdp.java deleted file mode 100644 index d22a95ed120..00000000000 --- a/jdk/src/share/classes/com/oracle/net/Sdp.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2010, 2014, 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. - */ - -package com.oracle.net; - -import java.net.Socket; -import java.net.ServerSocket; -import java.net.SocketImpl; -import java.net.SocketImplFactory; -import java.net.SocketException; -import java.nio.channels.SocketChannel; -import java.nio.channels.ServerSocketChannel; -import java.io.IOException; -import java.io.FileDescriptor; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.lang.reflect.Constructor; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.InvocationTargetException; - -import sun.net.sdp.SdpSupport; - -/** - * This class consists exclusively of static methods that Sockets or Channels to - * sockets that support the InfiniBand Sockets Direct Protocol (SDP). - */ - -public final class Sdp { - private Sdp() { } - - /** - * The package-privage ServerSocket(SocketImpl) constructor - */ - private static final Constructor serverSocketCtor; - static { - try { - serverSocketCtor = - ServerSocket.class.getDeclaredConstructor(SocketImpl.class); - setAccessible(serverSocketCtor); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } - - /** - * The package-private SdpSocketImpl() constructor - */ - private static final Constructor socketImplCtor; - static { - try { - Class cl = Class.forName("java.net.SdpSocketImpl", true, null); - socketImplCtor = (Constructor)cl.getDeclaredConstructor(); - setAccessible(socketImplCtor); - } catch (ClassNotFoundException e) { - throw new AssertionError(e); - } catch (NoSuchMethodException e) { - throw new AssertionError(e); - } - } - - private static void setAccessible(final AccessibleObject o) { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - o.setAccessible(true); - return null; - } - }); - } - - /** - * SDP enabled Socket. - */ - private static class SdpSocket extends Socket { - SdpSocket(SocketImpl impl) throws SocketException { - super(impl); - } - } - - /** - * Creates a SDP enabled SocketImpl - */ - private static SocketImpl createSocketImpl() { - try { - return socketImplCtor.newInstance(); - } catch (InstantiationException x) { - throw new AssertionError(x); - } catch (IllegalAccessException x) { - throw new AssertionError(x); - } catch (InvocationTargetException x) { - throw new AssertionError(x); - } - } - - /** - * Creates an unconnected and unbound SDP socket. The {@code Socket} is - * associated with a {@link java.net.SocketImpl} of the system-default type. - * - * @return a new Socket - * - * @throws UnsupportedOperationException - * If SDP is not supported - * @throws IOException - * If an I/O error occurs - */ - public static Socket openSocket() throws IOException { - SocketImpl impl = createSocketImpl(); - return new SdpSocket(impl); - } - - /** - * Creates an unbound SDP server socket. The {@code ServerSocket} is - * associated with a {@link java.net.SocketImpl} of the system-default type. - * - * @return a new ServerSocket - * - * @throws UnsupportedOperationException - * If SDP is not supported - * @throws IOException - * If an I/O error occurs - */ - public static ServerSocket openServerSocket() throws IOException { - // create ServerSocket via package-private constructor - SocketImpl impl = createSocketImpl(); - try { - return serverSocketCtor.newInstance(impl); - } catch (IllegalAccessException x) { - throw new AssertionError(x); - } catch (InstantiationException x) { - throw new AssertionError(x); - } catch (InvocationTargetException x) { - Throwable cause = x.getCause(); - if (cause instanceof IOException) - throw (IOException)cause; - if (cause instanceof RuntimeException) - throw (RuntimeException)cause; - throw new RuntimeException(x); - } - } - - /** - * Opens a socket channel to a SDP socket. - * - *

The channel will be associated with the system-wide default - * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. - * - * @return a new SocketChannel - * - * @throws UnsupportedOperationException - * If SDP is not supported or not supported by the default selector - * provider - * @throws IOException - * If an I/O error occurs. - */ - public static SocketChannel openSocketChannel() throws IOException { - FileDescriptor fd = SdpSupport.createSocket(); - return sun.nio.ch.Secrets.newSocketChannel(fd); - } - - /** - * Opens a socket channel to a SDP socket. - * - *

The channel will be associated with the system-wide default - * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. - * - * @return a new ServerSocketChannel - * - * @throws UnsupportedOperationException - * If SDP is not supported or not supported by the default selector - * provider - * @throws IOException - * If an I/O error occurs - */ - public static ServerSocketChannel openServerSocketChannel() - throws IOException - { - FileDescriptor fd = SdpSupport.createSocket(); - return sun.nio.ch.Secrets.newServerSocketChannel(fd); - } -} diff --git a/jdk/src/share/classes/java/net/SdpSocketImpl.java b/jdk/src/share/classes/java/net/SdpSocketImpl.java deleted file mode 100644 index b5b023e2433..00000000000 --- a/jdk/src/share/classes/java/net/SdpSocketImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2010, 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. - */ - -package java.net; - -import java.io.IOException; -import java.io.FileDescriptor; - -import sun.net.sdp.SdpSupport; - -/** - * SocketImpl that supports the SDP protocol - */ -class SdpSocketImpl extends PlainSocketImpl { - SdpSocketImpl() { } - - @Override - protected void create(boolean stream) throws IOException { - if (!stream) - throw new UnsupportedOperationException("Must be a stream socket"); - fd = SdpSupport.createSocket(); - if (socket != null) - socket.setCreated(); - if (serverSocket != null) - serverSocket.setCreated(); - } -} diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 8e45f1998f7..12b1ba79322 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -102,7 +102,6 @@ jdk_nio = \ jdk_net = \ java/net \ com/sun/net/httpserver \ - com/oracle/net \ sun/net jdk_time = \ diff --git a/jdk/test/com/oracle/net/Sanity.java b/jdk/test/com/oracle/net/Sanity.java deleted file mode 100644 index c4c97152779..00000000000 --- a/jdk/test/com/oracle/net/Sanity.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2010, 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. - */ - -import com.oracle.net.Sdp; - -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.*; - -/** - * Exercise com.oracle.net.Sdp with each IP address plumbed to InfiniBand - * interfaces listed in a given file. - */ - -public class Sanity { - public static void main(String[] args) throws Exception { - // The file is a list of interfaces to test. - Scanner s = new Scanner(new File(args[0])); - try { - while (s.hasNextLine()) { - String link = s.nextLine(); - NetworkInterface ni = NetworkInterface.getByName(link); - if (ni != null) { - Enumeration addrs = ni.getInetAddresses(); - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - System.out.format("Testing %s: %s\n", link, addr.getHostAddress()); - test(addr); - } - } - } - } finally { - s.close(); - } - } - - static void test(InetAddress addr) throws Exception { - // Test SocketChannel and ServerSocketChannel - ServerSocketChannel ssc = Sdp.openServerSocketChannel(); - try { - ssc.socket().bind(new InetSocketAddress(addr, 0)); - int port = ssc.socket().getLocalPort(); - - // SocketChannel.connect (implicit bind) - SocketChannel client = Sdp.openSocketChannel(); - try { - client.connect(new InetSocketAddress(addr, port)); - SocketChannel peer = ssc.accept(); - try { - testConnection(Channels.newOutputStream(client), - Channels.newInputStream(peer)); - } finally { - peer.close(); - } - } finally { - client.close(); - } - - // SocketChannel.connect (explicit bind) - client = Sdp.openSocketChannel(); - try { - client.socket().bind(new InetSocketAddress(addr, 0)); - client.connect(new InetSocketAddress(addr, port)); - ssc.accept().close(); - } finally { - client.close(); - } - } finally { - ssc.close(); - } - - // Test Socket and ServerSocket - ServerSocket ss = Sdp.openServerSocket(); - try { - ss.bind(new InetSocketAddress(addr, 0)); - int port = ss.getLocalPort(); - - // Socket.connect (implicit bind) - Socket s = Sdp.openSocket(); - try { - s.connect(new InetSocketAddress(addr, port)); - Socket peer = ss.accept(); - try { - testConnection(s.getOutputStream(), peer.getInputStream()); - } finally { - peer.close(); - } - } finally { - s.close(); - } - - // Socket.connect (explicit bind) - s = Sdp.openSocket(); - try { - s.bind(new InetSocketAddress(addr, 0)); - s.connect(new InetSocketAddress(addr, port)); - ss.accept().close(); - } finally { - s.close(); - } - } finally { - ss.close(); - } - } - - static void testConnection(OutputStream out, InputStream in) - throws IOException - { - byte[] msg = "hello".getBytes(); - out.write(msg); - - byte[] ba = new byte[100]; - int nread = 0; - while (nread < msg.length) { - int n = in.read(ba); - if (n < 0) - throw new IOException("EOF not expected!"); - nread += n; - } - } -} diff --git a/jdk/test/com/oracle/net/sanity.sh b/jdk/test/com/oracle/net/sanity.sh deleted file mode 100644 index b4c26acce02..00000000000 --- a/jdk/test/com/oracle/net/sanity.sh +++ /dev/null @@ -1,66 +0,0 @@ -# -# Copyright (c) 2010, 2012, 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 6965072 -# @summary Unit test for SDP support -# @build Sanity -# @run shell sanity.sh - -IB_LINKS=ib.links - -OS=`uname -s` -case "$OS" in - SunOS ) - /usr/sbin/dladm show-part -o LINK -p > ${IB_LINKS} - if [ $? != 0 ]; then - echo "Unable to get InfiniBand parition link information" - exit 0 - fi - ;; - Linux ) - if [ ! -f /proc/net/sdp ]; then - echo "InfiniBand SDP module not installed" - exit 0 - fi - egrep "^[ \t]+ib" /proc/net/dev|cut -d':' -f1|tr -d '\t ' > ${IB_LINKS} - ;; - * ) - echo "This test only runs on Solaris or Linux" - exit 0 - ;; -esac - -if [ -z "$TESTJAVA" ]; then - JAVA=java - TESTCLASSES=. - TESTSRC=. -else - JAVA="${TESTJAVA}/bin/java" -fi - -CLASSPATH=${TESTCLASSES}:${TESTSRC} -export CLASSPATH - -# Run sanity test (IPv4-only for now) -$JAVA ${TESTVMOPTS} -Djava.net.preferIPv4Stack=true Sanity ${IB_LINKS} From 60249f90a2f424cf8c6c1af2a7e56d27196b727e Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Mon, 7 Apr 2014 16:13:43 +0200 Subject: [PATCH 141/170] 8031766: jstatd nightly tests failing with Expected one jstatd process, got 2. Test will be canceled Reviewed-by: jbachorik, sla --- jdk/test/sun/tools/jstatd/JstatdTest.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/jdk/test/sun/tools/jstatd/JstatdTest.java b/jdk/test/sun/tools/jstatd/JstatdTest.java index f07ce6b1742..0c003cfcb5e 100644 --- a/jdk/test/sun/tools/jstatd/JstatdTest.java +++ b/jdk/test/sun/tools/jstatd/JstatdTest.java @@ -27,6 +27,7 @@ import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.util.Arrays; +import java.util.regex.Pattern; import static jdk.testlibrary.Asserts.*; import jdk.testlibrary.JDKToolLauncher; @@ -34,6 +35,7 @@ import jdk.testlibrary.OutputAnalyzer; import jdk.testlibrary.ProcessThread; import jdk.testlibrary.TestThread; import jdk.testlibrary.Utils; +import jdk.testlibrary.ProcessTools; /** * The base class for tests of jstatd. @@ -93,8 +95,11 @@ public final class JstatdTest { if (tool == "rmiregistry") { processName = "registryimpl"; } + + Pattern toolInJpsPattern = + Pattern.compile("^\\d+\\s{1}" + processName + "\\s{1}.*-dparent\\.pid\\." + ProcessTools.getProcessId() + ".*"); for (String line : lines) { - if (line.toLowerCase().matches("^\\d+\\s{1}" + processName + "$")) { + if (toolInJpsPattern.matcher(line.toLowerCase()).matches()) { pid = line.split(" ")[0]; count++; } @@ -167,6 +172,8 @@ public final class JstatdTest { private OutputAnalyzer runJps() throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps"); launcher.addVMArg("-XX:+UsePerfData"); + // Run jps with -v flag to obtain -Dparent.pid. + launcher.addToolArg("-v"); launcher.addToolArg(getDestination()); String[] cmd = launcher.getCommand(); @@ -286,7 +293,7 @@ public final class JstatdTest { * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -n serverName * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -n serverName */ - private String[] getJstatdCmd() throws UnknownHostException { + private String[] getJstatdCmd() throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstatd"); launcher.addVMArg("-XX:+UsePerfData"); String testSrc = System.getProperty("test.src"); @@ -294,6 +301,8 @@ public final class JstatdTest { assertTrue(policy.exists() && policy.isFile(), "Security policy " + policy.getAbsolutePath() + " does not exist or not a file"); launcher.addVMArg("-Djava.security.policy=" + policy.getAbsolutePath()); + // -Dparent.pid. will help to identify jstad process started by this test + launcher.addVMArg("-Dparent.pid." + ProcessTools.getProcessId()); if (port != null) { launcher.addToolArg("-p"); launcher.addToolArg(port); From f4f394efb5f37c29318ee2a945c708668ef3e683 Mon Sep 17 00:00:00 2001 From: Pavel Reppo Date: Mon, 7 Apr 2014 15:40:05 +0100 Subject: [PATCH 142/170] 8037396: URI getQuery() and getFragment() don't decode properly Reviewed-by: chegar, michaelm --- jdk/src/share/classes/java/net/URI.java | 18 ++++++--- jdk/test/java/net/URI/Test.java | 53 ++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java index 813de5cf453..0a05793b9a9 100644 --- a/jdk/src/share/classes/java/net/URI.java +++ b/jdk/src/share/classes/java/net/URI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -1337,7 +1337,7 @@ public final class URI */ public String getQuery() { if ((decodedQuery == null) && (query != null)) - decodedQuery = decode(query); + decodedQuery = decode(query, false); return decodedQuery; } @@ -1366,7 +1366,7 @@ public final class URI */ public String getFragment() { if ((decodedFragment == null) && (fragment != null)) - decodedFragment = decode(fragment); + decodedFragment = decode(fragment, false); return decodedFragment; } @@ -2764,6 +2764,12 @@ public final class URI // with a scope_id // private static String decode(String s) { + return decode(s, true); + } + + // This method was introduced as a generalization of URI.decode method + // to provide a fix for JDK-8037396 + private static String decode(String s, boolean ignorePercentInBrackets) { if (s == null) return s; int n = s.length(); @@ -2776,8 +2782,8 @@ public final class URI ByteBuffer bb = ByteBuffer.allocate(n); CharBuffer cb = CharBuffer.allocate(n); CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8") - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); // This is not horribly efficient, but it will do for now char c = s.charAt(0); @@ -2790,7 +2796,7 @@ public final class URI } else if (betweenBrackets && c == ']') { betweenBrackets = false; } - if (c != '%' || betweenBrackets) { + if (c != '%' || (betweenBrackets && ignorePercentInBrackets)) { sb.append(c); if (++i >= n) break; diff --git a/jdk/test/java/net/URI/Test.java b/jdk/test/java/net/URI/Test.java index 05d4cdbbfac..8e0e9247acd 100644 --- a/jdk/test/java/net/URI/Test.java +++ b/jdk/test/java/net/URI/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -1367,6 +1367,17 @@ public class Test { cmp0(u, v, true); } + static void eq(String expected, String actual) { + if (expected == null && actual == null) { + return; + } + if (expected != null && expected.equals(actual)) { + return; + } + throw new AssertionError(String.format( + "Strings are not equal: '%s', '%s'", expected, actual)); + } + static void eqeq(URI u, URI v) { testCount++; if (u != v) @@ -1588,7 +1599,12 @@ public class Test { // miscellaneous bugs/rfes that don't fit in with the test framework static void bugs() { - // 6339649 - include detail message from nested exception + b6339649(); + b8037396(); + } + + // 6339649 - include detail message from nested exception + private static void b6339649() { try { URI uri = URI.create("http://nowhere.net/should not be permitted"); } catch (IllegalArgumentException e) { @@ -1598,6 +1614,39 @@ public class Test { } } + private static void b8037396() { + + // primary checks: + + URI u; + try { + u = new URI("http", "example.org", "/[a b]", "[a b]", "[a b]"); + } catch (URISyntaxException e) { + throw new AssertionError("shouldn't ever happen", e); + } + eq("/[a b]", u.getPath()); + eq("[a b]", u.getQuery()); + eq("[a b]", u.getFragment()); + + // additional checks: + // * '%' symbols are still decoded outside square brackets + // * the getRawXXX() functionality left intact + + try { + u = new URI("http", "example.org", "/a b[c d]", "a b[c d]", "a b[c d]"); + } catch (URISyntaxException e) { + throw new AssertionError("shouldn't ever happen", e); + } + + eq("/a b[c d]", u.getPath()); + eq("a b[c d]", u.getQuery()); + eq("a b[c d]", u.getFragment()); + + eq("/a%20b%5Bc%20d%5D", u.getRawPath()); + eq("a%20b[c%20d]", u.getRawQuery()); + eq("a%20b[c%20d]", u.getRawFragment()); + } + public static void main(String[] args) throws Exception { switch (args.length) { From 319aa4c4c50912b7476a92b38c7c8e4976204476 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 7 Apr 2014 21:57:33 +0530 Subject: [PATCH 143/170] 8039387: Nashorn supports indexed access of List elements, but length property is not supported Reviewed-by: lagergren, jlaskey --- .../internal/dynalink/beans/BeanLinker.java | 2 + nashorn/test/script/basic/JDK-8039387.js | 39 +++++++++++++++++++ .../test/script/basic/JDK-8039387.js.EXPECTED | 4 ++ nashorn/test/script/basic/list.js | 2 +- nashorn/test/script/basic/list.js.EXPECTED | 2 +- 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8039387.js create mode 100644 nashorn/test/script/basic/JDK-8039387.js.EXPECTED diff --git a/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java index 519036b37cc..d0ad96bad21 100644 --- a/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java +++ b/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java @@ -113,6 +113,8 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL // explicit property is beneficial for them. // REVISIT: is it maybe a code smell that "dyn:getLength" is not needed? setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY); + } else if(List.class.isAssignableFrom(clazz)) { + setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF); } } diff --git a/nashorn/test/script/basic/JDK-8039387.js b/nashorn/test/script/basic/JDK-8039387.js new file mode 100644 index 00000000000..8f903c1af96 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8039387.js @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * JDK-8039387: Nashorn supports indexed access of List elements, but length property is not supported + * + * @test + * @run + */ + +var ArrayList = Java.type("java.util.ArrayList") +var list = new ArrayList(3) +list.add("nashorn") +list.add("js") +list.add("ecmascript") +var len = list.length +print("length = " + len) +for (var i = 0; i < len; i++) + print(list[i]) diff --git a/nashorn/test/script/basic/JDK-8039387.js.EXPECTED b/nashorn/test/script/basic/JDK-8039387.js.EXPECTED new file mode 100644 index 00000000000..5b9ce56d56b --- /dev/null +++ b/nashorn/test/script/basic/JDK-8039387.js.EXPECTED @@ -0,0 +1,4 @@ +length = 3 +nashorn +js +ecmascript diff --git a/nashorn/test/script/basic/list.js b/nashorn/test/script/basic/list.js index 72ae0be7617..59136c0b2ee 100644 --- a/nashorn/test/script/basic/list.js +++ b/nashorn/test/script/basic/list.js @@ -33,7 +33,7 @@ print("l.class.name=" + Java.typeName(l.class)) // Has "class" property like any l.add("foo") l.add("bar") -print("l.length=" + l.length) // doesn't work, returns undefined +print("l.length=" + l.length) // works, maps to l.size() print("l.size()=" + l.size()) // this will work print("l[0]=" + l[0]) diff --git a/nashorn/test/script/basic/list.js.EXPECTED b/nashorn/test/script/basic/list.js.EXPECTED index 18feade2b4e..47f3bd4fec1 100644 --- a/nashorn/test/script/basic/list.js.EXPECTED +++ b/nashorn/test/script/basic/list.js.EXPECTED @@ -1,5 +1,5 @@ l.class.name=java.util.ArrayList -l.length=undefined +l.length=2 l.size()=2 l[0]=foo l[1]=bar From 5eb8520ff197db3c2b1b4c84c785045e21fdb998 Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Tue, 8 Apr 2014 11:25:56 +0100 Subject: [PATCH 144/170] 8033113: wsimport fails on WSDL:header parameter name customization Reviewed-by: chegar --- .../xml/ws/8033113/Organization_List.wsdl | 77 +++++++++ .../javax/xml/ws/8033113/WsImportTest.java | 152 ++++++++++++++++++ .../javax/xml/ws/8033113/customization.xml | 23 +++ 3 files changed, 252 insertions(+) create mode 100644 jdk/test/javax/xml/ws/8033113/Organization_List.wsdl create mode 100644 jdk/test/javax/xml/ws/8033113/WsImportTest.java create mode 100644 jdk/test/javax/xml/ws/8033113/customization.xml diff --git a/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl b/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl new file mode 100644 index 00000000000..ae19b565b72 --- /dev/null +++ b/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jdk/test/javax/xml/ws/8033113/WsImportTest.java b/jdk/test/javax/xml/ws/8033113/WsImportTest.java new file mode 100644 index 00000000000..aa1cf860ab4 --- /dev/null +++ b/jdk/test/javax/xml/ws/8033113/WsImportTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014, 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 8033113 + * @summary wsimport fails on WSDL:header parameter name customization + * @run main/othervm WsImportTest + */ + +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import static java.nio.file.FileVisitResult.*; + +public class WsImportTest { + + public static void main(String[] args) throws IOException { + + String wsimport = getWsImport(); + String customization = getWSDLFilePath("customization.xml"); + String wsdl = getWSDLFilePath("Organization_List.wsdl"); + + try { + log("Importing wsdl: " + wsdl); + String[] wsargs = { + wsimport, + "-keep", + "-verbose", + "-extension", + "-XadditionalHeaders", + "-Xdebug", + "-b", + customization, + wsdl + }; + + ProcessBuilder pb = new ProcessBuilder(wsargs); + pb.redirectErrorStream(true); + Process p = pb.start(); + logOutput(p); + int result = p.waitFor(); + p.destroy(); + + if (result != 0) { + fail("WsImport failed. TEST FAILED."); + } else { + log("Test PASSED."); + } + + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + deleteGeneratedFiles(); + } + } + + private static void fail(String message) { + throw new RuntimeException(message); + } + + private static void log(String msg) { + System.out.println(msg); + } + + private static void logOutput(Process p) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); + String s = r.readLine(); + while (s != null) { + log(s.trim()); + s = r.readLine(); + } + } + + private static void deleteGeneratedFiles() { + Path p = Paths.get("generated"); + if (Files.exists(p)) { + try { + Files.walkFileTree(p, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + + Files.delete(file); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException exc) throws IOException { + + if (exc == null) { + Files.delete(dir); + return CONTINUE; + } else { + throw exc; + } + } + }); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + } + + private static String getWSDLFilePath(String filename) { + String testSrc = System.getProperty("test.src"); + if (testSrc == null) testSrc = "."; + return Paths.get(testSrc).resolve(filename).toString(); + } + + private static String getWsImport() { + String javaHome = System.getProperty("java.home"); + if (javaHome.endsWith("jre")) { + javaHome = new File(javaHome).getParent(); + } + String wsimport = javaHome + File.separator + "bin" + File.separator + "wsimport"; + if (System.getProperty("os.name").startsWith("Windows")) { + wsimport = wsimport.concat(".exe"); + } + return wsimport; + } +} diff --git a/jdk/test/javax/xml/ws/8033113/customization.xml b/jdk/test/javax/xml/ws/8033113/customization.xml new file mode 100644 index 00000000000..e754c4275c0 --- /dev/null +++ b/jdk/test/javax/xml/ws/8033113/customization.xml @@ -0,0 +1,23 @@ + + false + + + + + + + + From 805cbfba8859f3770d9866f26a5a43a831119d2c Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Tue, 8 Apr 2014 11:26:40 +0100 Subject: [PATCH 145/170] 8033113: wsimport fails on WSDL:header parameter name customization Reviewed-by: chegar --- .../com/sun/tools/internal/ws/processor/model/Message.java | 5 +++-- .../internal/ws/processor/modeler/wsdl/WSDLModeler.java | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java index b3fff34c764..8d1386f5094 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/model/Message.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -177,7 +177,8 @@ public abstract class Message extends ModelObject { throw new AbortException(); } _parameters.add(p); - _parametersByName.put(p.getName(), p); + String name = p.getCustomName() != null ? p.getCustomName() : p.getName(); + _parametersByName.put(name, p); } public Parameter getParameterByName(String name) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/WSDLModeler.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/WSDLModeler.java index d13bf989c8d..1aa0f5fb23e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/WSDLModeler.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/processor/modeler/wsdl/WSDLModeler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -1791,9 +1791,9 @@ public class WSDLModeler extends WSDLModelerBase { } if (part.isIN()) { - setCustomizedParameterName(info.portTypeOperation, inMsg, part, param, false); + setCustomizedParameterName(info.bindingOperation, inMsg, part, param, false); } else if (outMsg != null) { - setCustomizedParameterName(info.portTypeOperation, outMsg, part, param, false); + setCustomizedParameterName(info.bindingOperation, outMsg, part, param, false); } params.add(param); From f963ced878c2f43f2388ebf6963e34ba989cb064 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Tue, 8 Apr 2014 17:36:13 +0200 Subject: [PATCH 146/170] 6815126: intermittent SimulResumerTest.java failure Reviewed-by: jbachorik, sla --- jdk/test/com/sun/jdi/SimulResumerTest.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/jdk/test/com/sun/jdi/SimulResumerTest.java b/jdk/test/com/sun/jdi/SimulResumerTest.java index f652494be45..83e74cb7cb4 100644 --- a/jdk/test/com/sun/jdi/SimulResumerTest.java +++ b/jdk/test/com/sun/jdi/SimulResumerTest.java @@ -177,12 +177,18 @@ public class SimulResumerTest extends TestScaffold { List frames = thr.frames(); // no failure return value here; could cause an NPE - int nframes = frames.size(); - if (nframes > 0) { - // hmm, how could it ever be 0? - kind = "frames(0, size - 1)"; + kind = "frames(0, size - 1)"; System.out.println("kind = " + kind); - thr.frames(0, frames.size() - 1); + int nframes = frames.size(); + while (nframes > 0) { + try { + thr.frames(0, nframes - 1); + break; + } catch (IndexOutOfBoundsException iobe) { + // 6815126. let's try to get less frames + iobe.printStackTrace(); + nframes--; + } } kind = "frameCount()"; From fa633bad052ac337386ed7d5f22895ff068ca90b Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Tue, 8 Apr 2014 11:57:57 -0400 Subject: [PATCH 147/170] 8038431: Close InputStream when finished retrieving XML Signature HTTP References Reviewed-by: xuelei --- .../implementations/ResolverDirectHTTP.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java b/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java index a3359bdc675..137a5d4ae25 100644 --- a/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java +++ b/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/implementations/ResolverDirectHTTP.java @@ -108,6 +108,7 @@ public class ResolverDirectHTTP extends ResourceResolverSpi { @Override public XMLSignatureInput engineResolveURI(ResourceResolverContext context) throws ResourceResolverException { + InputStream inputStream = null; try { // calculate new URI @@ -139,7 +140,7 @@ public class ResolverDirectHTTP extends ResourceResolverSpi { } String mimeType = urlConnection.getHeaderField("Content-Type"); - InputStream inputStream = urlConnection.getInputStream(); + inputStream = urlConnection.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte buf[] = new byte[4096]; int read = 0; @@ -168,6 +169,16 @@ public class ResolverDirectHTTP extends ResourceResolverSpi { throw new ResourceResolverException("generic.EmptyMessage", ex, context.attr, context.baseUri); } catch (IllegalArgumentException e) { throw new ResourceResolverException("generic.EmptyMessage", e, context.attr, context.baseUri); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + if (log.isLoggable(java.util.logging.Level.FINE)) { + log.log(java.util.logging.Level.FINE, e.getMessage(), e); + } + } + } } } From 900591b4ed2b9f5b0c2f28047926b04006b99a0a Mon Sep 17 00:00:00 2001 From: Matherey Nunez Date: Wed, 9 Apr 2014 10:14:34 +0200 Subject: [PATCH 148/170] 8039403: Write sanity tests for persistent caching Reviewed-by: hannesw, sundar --- .../runtime/CodeStoreAndPathTest.java | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java new file mode 100644 index 00000000000..a2d72ebfd99 --- /dev/null +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/CodeStoreAndPathTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, 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. + */ +package jdk.nashorn.internal.runtime; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.DirectoryStream; +import java.nio.file.Path; +import java.nio.file.FileSystems; +import javax.script.ScriptException; +import org.testng.annotations.Test; +import javax.script.ScriptEngine; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertEquals; + +/** + * @test + * @bug 8039185 8039403 + * @summary Test for persistent code cache and path handling + * @run testng jdk.nashorn.internal.runtime.CodeStoreAndPathTest + */ + +public class CodeStoreAndPathTest { + + final String code1 = "var code1; var x = 'Hello Script'; var x1 = 'Hello Script'; " + + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; " + + "var x4 = 'Hello Script'; var x5 = 'Hello Script';" + + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; " + + "var x8 = 'Hello Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';" + + "function f() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function g() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function h() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function i() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}"; + final String code2 = "var code2; var x = 'Hello Script'; var x1 = 'Hello Script'; " + + "var x2 = 'Hello Script'; var x3 = 'Hello Script'; " + + "var x4 = 'Hello Script'; var x5 = 'Hello Script';" + + "var x6 = 'Hello Script'; var x7 = 'Hello Script'; " + + "var x8 = 'Hello Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';" + + "function f() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function g() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function h() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}" + + "function i() {x ='Bye Script'; x1 ='Bye Script'; x2='Bye Script';" + + "x3='Bye Script'; x4='Bye Script'; x5='Bye Script'; x6='Bye Script';" + + "x7='Bye Script'; x8='Bye Script'; var x9 = 'Hello Script'; " + + "var x10 = 'Hello Script';}"; + // Script size < Default minimum size for storing a compiled script class + final String code3 = "var code3; var x = 'Hello Script'; var x1 = 'Hello Script'; "; + final String codeCache = "build/nashorn_code_cache"; + final String oldUserDir = System.getProperty("user.dir"); + + public void checkCompiledScripts(DirectoryStream stream, int numberOfScripts) throws IOException { + for (Path file : stream) { + numberOfScripts--; + } + stream.close(); + assertEquals(numberOfScripts,0); + } + + @Test + public void pathHandlingTest() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + String[] options = new String[]{"--persistent-code-cache"}; + NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + ScriptEngine e = fac.getScriptEngine(options); + Path expectedCodeCachePath = FileSystems.getDefault().getPath(oldUserDir + File.separator + codeCache); + Path actualCodeCachePath = FileSystems.getDefault().getPath(System.getProperty( + "nashorn.persistent.code.cache")).toAbsolutePath(); + // Check that nashorn code cache is created in current working directory + assertEquals(actualCodeCachePath, expectedCodeCachePath); + // Check that code cache dir exists and it's not empty + File file = new File(actualCodeCachePath.toUri()); + assertFalse(!file.isDirectory(), "No code cache directory was created!"); + assertFalse(file.list().length == 0, "Code cache directory is empty!"); + } + + @Test + public void changeUserDirTest() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + String[] options = new String[]{"--persistent-code-cache"}; + NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + ScriptEngine e = fac.getScriptEngine(options); + Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty( + "nashorn.persistent.code.cache")).toAbsolutePath(); + String newUserDir = "build/newUserDir"; + // Now changing current working directory + System.setProperty("user.dir", System.getProperty("user.dir") + File.separator + newUserDir); + // Check that a new compiled script is stored in exisitng code cache + e.eval(code1); + DirectoryStream stream = Files.newDirectoryStream(codeCachePath); + // Already one compiled script has been stored in the cache during initialization + checkCompiledScripts(stream, 2); + // Setting to default current working dir + System.setProperty("user.dir", oldUserDir); + } + + @Test + public void codeCacheTest() throws ScriptException, IOException { + System.setProperty("nashorn.persistent.code.cache", codeCache); + String[] options = new String[]{"--persistent-code-cache"}; + NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + ScriptEngine e = fac.getScriptEngine(options); + Path codeCachePath = FileSystems.getDefault().getPath(System.getProperty( + "nashorn.persistent.code.cache")).toAbsolutePath(); + e.eval(code1); + e.eval(code2); + e.eval(code3);// less than minimum size for storing + // Already one compiled script has been stored in the cache during initialization + // adding code1 and code2. + DirectoryStream stream = Files.newDirectoryStream(codeCachePath); + checkCompiledScripts(stream, 3); + } +} From 3344a6c353087f7f5bf1d2fc2d8630652a413653 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 9 Apr 2014 17:08:37 +0800 Subject: [PATCH 149/170] 8039132: cleanup @ignore JAAS/krb5 tests Reviewed-by: xuelei --- .../krb5/auto/AddressesAndNameType.java | 85 +++++++++++++++++++ jdk/test/sun/security/krb5/auto/UdpTcp.java | 65 ++++++++++++++ .../krb5/etype/UnsupportedKeyType.java | 77 +++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 jdk/test/sun/security/krb5/auto/AddressesAndNameType.java create mode 100644 jdk/test/sun/security/krb5/auto/UdpTcp.java create mode 100644 jdk/test/sun/security/krb5/etype/UnsupportedKeyType.java diff --git a/jdk/test/sun/security/krb5/auto/AddressesAndNameType.java b/jdk/test/sun/security/krb5/auto/AddressesAndNameType.java new file mode 100644 index 00000000000..de0dc89491c --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/AddressesAndNameType.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014, 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 4501327 4868379 8039132 + * @run main/othervm AddressesAndNameType 1 + * @run main/othervm AddressesAndNameType 2 + * @run main/othervm AddressesAndNameType 3 + * @summary noaddresses settings and server name type + */ + +import java.net.InetAddress; +import java.util.Set; +import sun.security.krb5.Config; + +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.kerberos.KerberosTicket; + +public class AddressesAndNameType { + + public static void main(String[] args) + throws Exception { + + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + String extraLine; + switch (args[0]) { + case "1": extraLine = "noaddresses = false"; break; + case "2": extraLine = "noaddresses = true"; break; + default: extraLine = ""; break; + } + + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + extraLine); + Config.refresh(); + + Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Set tickets = + c.s().getPrivateCredentials(KerberosTicket.class); + + if (tickets.isEmpty()) throw new Exception(); + KerberosTicket ticket = tickets.iterator().next(); + InetAddress[] addresses = ticket.getClientAddresses(); + + switch (args[0]) { + case "1": + if (addresses == null || addresses.length == 0) { + throw new Exception("No addresses"); + } + if (ticket.getServer().getNameType() + != KerberosPrincipal.KRB_NT_SRV_INST) { + throw new Exception( + "Wrong type: " + ticket.getServer().getNameType()); + } + break; + default: + if (addresses != null && addresses.length != 0) { + throw new Exception("See addresses"); + } + break; + } + } +} diff --git a/jdk/test/sun/security/krb5/auto/UdpTcp.java b/jdk/test/sun/security/krb5/auto/UdpTcp.java new file mode 100644 index 00000000000..e66f5d459fb --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/UdpTcp.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 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 4966382 8039132 + * @run main/othervm UdpTcp UDP + * @run main/othervm UdpTcp TCP + * @summary udp or tcp + */ + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import sun.security.krb5.Config; + +public class UdpTcp { + + public static void main(String[] args) + throws Exception { + + System.setProperty("sun.security.krb5.debug", "true"); + + OneKDC kdc = new OneKDC(null); + kdc.writeJAASConf(); + + KDC.saveConfig(OneKDC.KRB5_CONF, kdc, + "udp_preference_limit = " + + (args[0].equals("UDP") ? "1000" : "100")); + Config.refresh(); + + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + System.setOut(oldout); + + for (String line: new String(bo.toByteArray()).split("\n")) { + if (line.contains(">>> KDCCommunication")) { + if (!line.contains(args[0])) { + throw new Exception("No " + args[0] + " in: " + line); + } + } + } + } +} diff --git a/jdk/test/sun/security/krb5/etype/UnsupportedKeyType.java b/jdk/test/sun/security/krb5/etype/UnsupportedKeyType.java new file mode 100644 index 00000000000..c54a73d9536 --- /dev/null +++ b/jdk/test/sun/security/krb5/etype/UnsupportedKeyType.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 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 5006629 + * @summary Kerberos library should only select keys of types that it supports + */ + +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.kerberos.KeyTab; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class UnsupportedKeyType { + + // Homemade keytab files: + // + // String KVNO Timestamp Principal (etype) + // -------- ---- -------------- ----------------------- + // camellia 4 4/3/14 9:58 AM u1@K1 (25:camellia128-cts-cmac) + // aes 5 4/3/14 9:58 AM u1@K1 (17:aes128-cts-hmac-sha1-96) + + static String aes = + "050200000027000100024b310002753100000001533cc04f0500110010e0eab6" + + "7f31608df2b2f8fffc6b21cc91"; + static String camellia = + "050200000027000100024b310002753100000001533cc03e0400190010d88678" + + "14e478b6b7d2d97375163b971e"; + + public static void main(String[] args) throws Exception { + + byte[] data = new byte[aes.length()/2]; + KerberosPrincipal kp = new KerberosPrincipal("u1@K1"); + + // aes128 + for (int i=0; i Date: Wed, 9 Apr 2014 17:19:19 +0800 Subject: [PATCH 150/170] 8035986: KerberosKey algorithm names are not specified Reviewed-by: xuelei --- .../security/auth/kerberos/KerberosKey.java | 46 ++++++-- .../javax/security/auth/kerberos/KeyImpl.java | 26 +++-- .../sun/security/krb5/EncryptionKey.java | 17 ++- .../security/auth/kerberos/StandardNames.java | 108 ++++++++++++++++++ 4 files changed, 169 insertions(+), 28 deletions(-) create mode 100644 jdk/test/javax/security/auth/kerberos/StandardNames.java diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java index 5c8b65f2703..a8d12131aaf 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java @@ -52,7 +52,20 @@ import javax.security.auth.DestroyFailedException; * application depends on the default JGSS Kerberos mechanism to access the * KerberosKey. In that case, however, the application will need an * appropriate - * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}. + * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.

+ * + * When creating a {@code KerberosKey} using the + * {@link #KerberosKey(KerberosPrincipal, char[], String)} constructor, + * an implementation may accept non-IANA algorithm names (For example, + * "ArcFourMac" for "rc4-hmac"), but the {@link #getAlgorithm} method + * must always return the IANA algorithm name.

+ * + * @implNote Old algorithm names used before JDK 9 are supported in the + * {@link #KerberosKey(KerberosPrincipal, char[], String)} constructor in this + * implementation for compatibility reasons, which are "DES" (and null) for + * "des-cbc-md5", "DESede" for "des3-cbc-sha1-kd", "ArcFourHmac" for "rc4-hmac", + * "AES128" for "aes128-cts-hmac-sha1-96", and "AES256" for + * "aes256-cts-hmac-sha1-96". * * @author Mayank Upadhyay * @since 1.4 @@ -73,7 +86,7 @@ public class KerberosKey implements SecretKey, Destroyable { * * @serial */ - private int versionNum; + private final int versionNum; /** * {@code KeyImpl} is serialized by writing out the ASN1 Encoded bytes @@ -113,13 +126,16 @@ public class KerberosKey implements SecretKey, Destroyable { } /** - * Constructs a KerberosKey from a principal's password. + * Constructs a KerberosKey from a principal's password using the specified + * algorithm name. The algorithm name (case insensitive) should be provided + * as the encryption type string defined on the IANA + * Kerberos Encryption Type Numbers + * page. The version number of the key generated will be 0. * * @param principal the principal that this password belongs to * @param password the password that should be used to compute the key * @param algorithm the name for the algorithm that this key will be - * used for. This parameter may be null in which case the default - * algorithm "DES" will be assumed. + * used for * @throws IllegalArgumentException if the name of the * algorithm passed is unsupported. */ @@ -128,6 +144,7 @@ public class KerberosKey implements SecretKey, Destroyable { String algorithm) { this.principal = principal; + this.versionNum = 0; // Pass principal in for salt key = new KeyImpl(principal, password, algorithm); } @@ -170,13 +187,18 @@ public class KerberosKey implements SecretKey, Destroyable { */ /** - * Returns the standard algorithm name for this key. For - * example, "DES" would indicate that this key is a DES key. - * See Appendix A in the - * Java Cryptography Architecture API Specification & Reference - * - * for information about standard algorithm names. + * Returns the standard algorithm name for this key. The algorithm names + * are the encryption type string defined on the IANA + * Kerberos Encryption Type Numbers + * page. + *

+ * This method can return the following value not defined on the IANA page: + *

    + *
  1. none: for etype equal to 0
  2. + *
  3. unknown: for etype greater than 0 but unsupported by + * the implementation
  4. + *
  5. private: for etype smaller than 0
  6. + *
* * @return the name of the algorithm associated with this key. */ diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java index f4ee947212b..9d36d1e9ee1 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java @@ -36,7 +36,6 @@ import sun.security.krb5.PrincipalName; import sun.security.krb5.EncryptionKey; import sun.security.krb5.EncryptedData; import sun.security.krb5.KrbException; -import sun.security.krb5.KrbCryptoException; import sun.security.util.DerValue; /** @@ -86,8 +85,12 @@ class KeyImpl implements SecretKey, Destroyable, Serializable { try { PrincipalName princ = new PrincipalName(principal.getName()); - EncryptionKey key = - new EncryptionKey(password, princ.getSalt(), algorithm); + EncryptionKey key; + if ("none".equalsIgnoreCase(algorithm)) { + key = EncryptionKey.NULL_KEY; + } else { + key = new EncryptionKey(password, princ.getSalt(), algorithm); + } this.keyBytes = key.getBytes(); this.keyType = key.getEType(); } catch (KrbException e) { @@ -118,27 +121,28 @@ class KeyImpl implements SecretKey, Destroyable, Serializable { switch (eType) { case EncryptedData.ETYPE_DES_CBC_CRC: + return "des-cbc-crc"; + case EncryptedData.ETYPE_DES_CBC_MD5: - return "DES"; + return "des-cbc-md5"; case EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD: - return "DESede"; + return "des3-cbc-sha1-kd"; case EncryptedData.ETYPE_ARCFOUR_HMAC: - return "ArcFourHmac"; + return "rc4-hmac"; case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96: - return "AES128"; + return "aes128-cts-hmac-sha1-96"; case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: - return "AES256"; + return "aes256-cts-hmac-sha1-96"; case EncryptedData.ETYPE_NULL: - return "NULL"; + return "none"; default: - throw new IllegalArgumentException( - "Unsupported encryption type: " + eType); + return eType > 0 ? "unknown" : "private"; } } diff --git a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java index b83fe8c8611..6887f85524c 100644 --- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java +++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java @@ -271,15 +271,22 @@ public class EncryptionKey String salt, String algorithm) throws KrbCryptoException { - if (algorithm == null || algorithm.equalsIgnoreCase("DES")) { + if (algorithm == null || algorithm.equalsIgnoreCase("DES") + || algorithm.equalsIgnoreCase("des-cbc-md5")) { keyType = EncryptedData.ETYPE_DES_CBC_MD5; - } else if (algorithm.equalsIgnoreCase("DESede")) { + } else if (algorithm.equalsIgnoreCase("des-cbc-crc")) { + keyType = EncryptedData.ETYPE_DES_CBC_CRC; + } else if (algorithm.equalsIgnoreCase("DESede") + || algorithm.equalsIgnoreCase("des3-cbc-sha1-kd")) { keyType = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD; - } else if (algorithm.equalsIgnoreCase("AES128")) { + } else if (algorithm.equalsIgnoreCase("AES128") + || algorithm.equalsIgnoreCase("aes128-cts-hmac-sha1-96")) { keyType = EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96; - } else if (algorithm.equalsIgnoreCase("ArcFourHmac")) { + } else if (algorithm.equalsIgnoreCase("ArcFourHmac") + || algorithm.equalsIgnoreCase("rc4-hmac")) { keyType = EncryptedData.ETYPE_ARCFOUR_HMAC; - } else if (algorithm.equalsIgnoreCase("AES256")) { + } else if (algorithm.equalsIgnoreCase("AES256") + || algorithm.equalsIgnoreCase("aes256-cts-hmac-sha1-96")) { keyType = EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96; // validate if AES256 is enabled if (!EType.isSupported(keyType)) { diff --git a/jdk/test/javax/security/auth/kerberos/StandardNames.java b/jdk/test/javax/security/auth/kerberos/StandardNames.java new file mode 100644 index 00000000000..40590f6d080 --- /dev/null +++ b/jdk/test/javax/security/auth/kerberos/StandardNames.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, 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 8035986 + * @summary KerberosKey algorithm names are not specified + */ + +import sun.security.krb5.EncryptedData; + +import javax.crypto.Cipher; +import javax.security.auth.kerberos.KerberosKey; +import javax.security.auth.kerberos.KerberosPrincipal; +import java.util.Locale; + +public class StandardNames { + static KerberosPrincipal kp = new KerberosPrincipal("user@REALM"); + static char[] pass = "secret".toCharArray(); + static byte[] keyBytes = new byte[1]; + + public static void main(String[] args) throws Exception { + for (EncType e: EncType.values()) { + if (e == EncType.e18) { + if (Cipher.getMaxAllowedKeyLength("AES") < 256) { + System.out.println("Skipping aes256-cts-hmac-sha1-96"); + continue; + } + } + checkByName(e.name, e); + checkByName(e.name.toUpperCase(Locale.US), e); + for (String n: e.oldnames) { + checkByName(n, e); + if (n != null) { + checkByName(n.toLowerCase(Locale.US), e); + } + } + checkByEType(e.etype, e.name); + } + checkByEType(100, "unknown"); + checkByEType(-1, "private"); + + try { + System.out.println("unsupported"); + new KerberosKey(kp, pass, "unsupported"); + throw new Exception("unsupported"); + } catch (IllegalArgumentException iae) { + // Expected + } + } + + private static void checkByName(String n, EncType e) throws Exception { + System.out.println("CheckByName " + n); + KerberosKey k = new KerberosKey(kp, pass, n); + if (!k.getAlgorithm().equals(e.name)) throw new Exception(n); + if (k.getKeyType() != e.etype) throw new Exception(n); + if (k.getVersionNumber() != 0) throw new Exception(n); + } + + private static void checkByEType(int i, String n) throws Exception { + System.out.println("CheckByInt " + i); + KerberosKey k = new KerberosKey(kp, keyBytes, i, 13); + if (!k.getAlgorithm().equals(n)) throw new Exception("" + i); + if (k.getKeyType() != i) throw new Exception("" + i); + if (k.getVersionNumber() != 13) throw new Exception("" + i); + } +} + +enum EncType { + e0("none", EncryptedData.ETYPE_NULL), + e1("des-cbc-crc", EncryptedData.ETYPE_DES_CBC_CRC), + e3("des-cbc-md5", EncryptedData.ETYPE_DES_CBC_MD5, "DES", null), + e16("des3-cbc-sha1-kd", EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, "DESede"), + e17("aes128-cts-hmac-sha1-96", EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, "AES128"), + e18("aes256-cts-hmac-sha1-96", EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96, "AES256"), + e23("rc4-hmac", EncryptedData.ETYPE_ARCFOUR_HMAC, "ArcFourHmac"), + ; + + final String name; + final int etype; + final String[] oldnames; + + EncType(String name, int etype, String... oldnames) { + this.name = name; + this.etype = etype; + this.oldnames = oldnames; + } +} From 2f501cd8a5db4b6c56c0f4acedda4f528f3731ea Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Wed, 9 Apr 2014 12:49:51 +0000 Subject: [PATCH 151/170] 8028192: Use of PKCS11-NSS provider in FIPS mode broken Reviewed-by: ahgross, ascarpino, asmotrak --- .../com/sun/crypto/provider/RSACipher.java | 61 +++++-- .../TlsRsaPremasterSecretGenerator.java | 21 ++- .../TlsRsaPremasterSecretParameterSpec.java | 144 ++++++++------- .../sun/security/pkcs11/P11RSACipher.java | 154 ++++++++++++++-- .../P11TlsRsaPremasterSecretGenerator.java | 44 ++--- .../classes/sun/security/pkcs11/Token.java | 34 ++++ .../security/ssl/RSAClientKeyExchange.java | 166 ++---------------- .../classes/sun/security/util/KeyUtil.java | 76 +++++++- .../sun/security/mscapi/RSACipher.java | 83 ++++++--- .../crypto/provider/TLS/TestPremaster.java | 55 ++++-- .../sun/security/pkcs11/fips/CipherTest.java | 15 +- .../pkcs11/fips/ClientJSSEServerJSSE.java | 12 +- .../security/pkcs11/tls/TestPremaster.java | 55 ++++-- 13 files changed, 574 insertions(+), 346 deletions(-) diff --git a/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java b/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java index 6902d4b8b31..d1d8cf3ef23 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/RSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -39,6 +39,8 @@ import javax.crypto.spec.OAEPParameterSpec; import sun.security.rsa.*; import sun.security.jca.Providers; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; /** * RSA cipher implementation. Supports RSA en/decryption and signing/verifying @@ -91,8 +93,8 @@ public final class RSACipher extends CipherSpi { // padding object private RSAPadding padding; - // cipher parameter for OAEP padding - private OAEPParameterSpec spec = null; + // cipher parameter for OAEP padding and TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; // buffer for the data private byte[] buffer; @@ -110,6 +112,9 @@ public final class RSACipher extends CipherSpi { // hash algorithm for OAEP private String oaepHashAlgorithm = "SHA-1"; + // the source of randomness + private SecureRandom random; + public RSACipher() { paddingType = PAD_PKCS1; } @@ -175,7 +180,7 @@ public final class RSACipher extends CipherSpi { // see JCE spec protected AlgorithmParameters engineGetParameters() { - if (spec != null) { + if (spec != null && spec instanceof OAEPParameterSpec) { try { AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP", @@ -276,8 +281,13 @@ public final class RSACipher extends CipherSpi { buffer = new byte[n]; } else if (paddingType == PAD_PKCS1) { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + + spec = params; + this.random = random; // for TLS RSA premaster secret } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 : RSAPadding.PAD_BLOCKTYPE_1; @@ -293,19 +303,18 @@ public final class RSACipher extends CipherSpi { throw new InvalidKeyException ("OAEP cannot be used to sign or verify signatures"); } - OAEPParameterSpec myParams; if (params != null) { if (!(params instanceof OAEPParameterSpec)) { throw new InvalidAlgorithmParameterException ("Wrong Parameters for OAEP Padding"); } - myParams = (OAEPParameterSpec) params; + spec = params; } else { - myParams = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", + spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); } padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n, - random, myParams); + random, (OAEPParameterSpec)spec); if (encrypt) { int k = padding.getMaxDataSize(); buffer = new byte[k]; @@ -420,17 +429,40 @@ public final class RSACipher extends CipherSpi { if (wrappedKey.length > buffer.length) { throw new InvalidKeyException("Key is too long for unwrapping"); } + + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + byte[] encoded = null; + update(wrappedKey, 0, wrappedKey.length); try { - byte[] encoded = doFinal(); - return ConstructKeys.constructKey(encoded, algorithm, type); + encoded = doFinal(); } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Unwrapping failed", e); + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } } catch (IllegalBlockSizeException e) { // should not occur, handled with length check above throw new InvalidKeyException("Unwrapping failed", e); } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), + random, encoded, (failover != null)); + } + + return ConstructKeys.constructKey(encoded, algorithm, type); } // see JCE spec @@ -438,5 +470,4 @@ public final class RSACipher extends CipherSpi { RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); return rsaKey.getModulus().bitLength(); } - } diff --git a/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java b/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java index ef9098f24f7..2a25cb64d5c 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -56,7 +56,7 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsRsaPremasterSecretParameterSpec == false) { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsRsaPremasterSecretParameterSpec)params; @@ -67,21 +67,20 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { throw new InvalidParameterException(MSG); } + // Only can be used in client side to generate TLS RSA premaster secret. protected SecretKey engineGenerateKey() { if (spec == null) { throw new IllegalStateException( "TlsRsaPremasterSecretGenerator must be initialized"); } - byte[] b = spec.getEncodedSecret(); - if (b == null) { - if (random == null) { - random = new SecureRandom(); - } - b = new byte[48]; - random.nextBytes(b); - b[0] = (byte)spec.getMajorVersion(); - b[1] = (byte)spec.getMinorVersion(); + + if (random == null) { + random = new SecureRandom(); } + byte[] b = new byte[48]; + random.nextBytes(b); + b[0] = (byte)spec.getMajorVersion(); + b[1] = (byte)spec.getMinorVersion(); return new SecretKeySpec(b, "TlsRsaPremasterSecret"); } diff --git a/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java b/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java index a38a7faecf2..0741499b9a7 100644 --- a/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java +++ b/jdk/src/share/classes/sun/security/internal/spec/TlsRsaPremasterSecretParameterSpec.java @@ -26,11 +26,11 @@ package sun.security.internal.spec; import java.security.spec.AlgorithmParameterSpec; +import java.security.AccessController; +import java.security.PrivilegedAction; /** - * Parameters for SSL/TLS RSA Premaster secret generation. - * This class is used by SSL/TLS client to initialize KeyGenerators of the - * type "TlsRsaPremasterSecret". + * Parameters for SSL/TLS RSA premaster secret. * *

Instances of this class are immutable. * @@ -43,90 +43,108 @@ import java.security.spec.AlgorithmParameterSpec; public class TlsRsaPremasterSecretParameterSpec implements AlgorithmParameterSpec { - private final int majorVersion; - private final int minorVersion; - private final byte[] encodedSecret; + /* + * The TLS spec says that the version in the RSA premaster secret must + * be the maximum version supported by the client (i.e. the version it + * requested in its client hello version). However, we (and other + * implementations) used to send the active negotiated version. The + * system property below allows to toggle the behavior. + */ + private final static String PROP_NAME = + "com.sun.net.ssl.rsaPreMasterSecretFix"; + + /* + * Default is "false" (old behavior) for compatibility reasons in + * SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property. + */ + private final static boolean rsaPreMasterSecretFix = + AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + String value = System.getProperty(PROP_NAME); + if (value != null && value.equalsIgnoreCase("true")) { + return Boolean.TRUE; + } + + return Boolean.FALSE; + } + }); + + private final int clientVersion; + private final int serverVersion; /** * Constructs a new TlsRsaPremasterSecretParameterSpec. - *

- * The version numbers will be placed inside the premaster secret to - * detect version rollbacks attacks as described in the TLS specification. - * Note that they do not indicate the protocol version negotiated for - * the handshake. * - * @param majorVersion the major number of the protocol version - * @param minorVersion the minor number of the protocol version + * @param clientVersion the version of the TLS protocol by which the + * client wishes to communicate during this session + * @param serverVersion the negotiated version of the TLS protocol which + * contains the lower of that suggested by the client in the client + * hello and the highest supported by the server. * - * @throws IllegalArgumentException if minorVersion or majorVersion are - * negative or larger than 255 + * @throws IllegalArgumentException if clientVersion or serverVersion are + * negative or larger than (2^16 - 1) */ - public TlsRsaPremasterSecretParameterSpec(int majorVersion, - int minorVersion) { - this.majorVersion = - TlsMasterSecretParameterSpec.checkVersion(majorVersion); - this.minorVersion = - TlsMasterSecretParameterSpec.checkVersion(minorVersion); - this.encodedSecret = null; + public TlsRsaPremasterSecretParameterSpec( + int clientVersion, int serverVersion) { + + this.clientVersion = checkVersion(clientVersion); + this.serverVersion = checkVersion(serverVersion); } /** - * Constructs a new TlsRsaPremasterSecretParameterSpec. - *

- * The version numbers will be placed inside the premaster secret to - * detect version rollbacks attacks as described in the TLS specification. - * Note that they do not indicate the protocol version negotiated for - * the handshake. - *

- * Usually, the encoded secret key is a random number that acts as - * dummy pre_master_secret to avoid vulnerabilities described by - * section 7.4.7.1, RFC 5246. + * Returns the version of the TLS protocol by which the client wishes to + * communicate during this session. * - * @param majorVersion the major number of the protocol version - * @param minorVersion the minor number of the protocol version - * @param encodedSecret the encoded secret key - * - * @throws IllegalArgumentException if minorVersion or majorVersion are - * negative or larger than 255, or encodedSecret is not exactly 48 bytes. + * @return the version of the TLS protocol in ClientHello message */ - public TlsRsaPremasterSecretParameterSpec(int majorVersion, - int minorVersion, byte[] encodedSecret) { - this.majorVersion = - TlsMasterSecretParameterSpec.checkVersion(majorVersion); - this.minorVersion = - TlsMasterSecretParameterSpec.checkVersion(minorVersion); - - if (encodedSecret == null || encodedSecret.length != 48) { - throw new IllegalArgumentException( - "Encoded secret is not exactly 48 bytes"); - } - this.encodedSecret = encodedSecret.clone(); + public int getClientVersion() { + return clientVersion; } /** - * Returns the major version. + * Returns the negotiated version of the TLS protocol which contains the + * lower of that suggested by the client in the client hello and the + * highest supported by the server. * - * @return the major version. + * @return the negotiated version of the TLS protocol in ServerHello message + */ + public int getServerVersion() { + return serverVersion; + } + + /** + * Returns the major version used in RSA premaster secret. + * + * @return the major version used in RSA premaster secret. */ public int getMajorVersion() { - return majorVersion; + if (rsaPreMasterSecretFix || clientVersion >= 0x0302) { + // 0x0302: TLSv1.1 + return (clientVersion >>> 8) & 0xFF; + } + + return (serverVersion >>> 8) & 0xFF; } /** - * Returns the minor version. + * Returns the minor version used in RSA premaster secret. * - * @return the minor version. + * @return the minor version used in RSA premaster secret. */ public int getMinorVersion() { - return minorVersion; + if (rsaPreMasterSecretFix || clientVersion >= 0x0302) { + // 0x0302: TLSv1.1 + return clientVersion & 0xFF; + } + + return serverVersion & 0xFF; } - /** - * Returns the encoded secret. - * - * @return the encoded secret, may be null if no encoded secret. - */ - public byte[] getEncodedSecret() { - return encodedSecret == null ? null : encodedSecret.clone(); + private int checkVersion(int version) { + if ((version < 0) || (version > 0xFFFF)) { + throw new IllegalArgumentException( + "Version must be between 0 and 65,535"); + } + return version; } } diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java index e2ff0fc73e4..253b8913a82 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java @@ -37,6 +37,8 @@ import javax.crypto.spec.*; import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; /** * RSA Cipher implementation class. We currently only support @@ -102,6 +104,12 @@ final class P11RSACipher extends CipherSpi { // maximum output size. this is the length of the key private int outputSize; + // cipher parameter for TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; + + // the source of randomness + private SecureRandom random; + P11RSACipher(Token token, String algorithm, long mechanism) throws PKCS11Exception { super(); @@ -165,8 +173,12 @@ final class P11RSACipher extends CipherSpi { AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + spec = params; + this.random = random; // for TLS RSA premaster secret } implInit(opmode, key); } @@ -176,8 +188,8 @@ final class P11RSACipher extends CipherSpi { SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); } implInit(opmode, key); } @@ -452,21 +464,101 @@ final class P11RSACipher extends CipherSpi { protected Key engineUnwrap(byte[] wrappedKey, String algorithm, int type) throws InvalidKeyException, NoSuchAlgorithmException { - // XXX implement unwrap using C_Unwrap() for all keys - implInit(Cipher.DECRYPT_MODE, p11Key); - if (wrappedKey.length > maxInputSize) { - throw new InvalidKeyException("Key is too long for unwrapping"); + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + + SecureRandom secureRandom = random; + if (secureRandom == null && isTlsRsaPremasterSecret) { + secureRandom = new SecureRandom(); } - implUpdate(wrappedKey, 0, wrappedKey.length); - try { - byte[] encoded = doFinal(); + + // Should C_Unwrap be preferred for non-TLS RSA premaster secret? + if (token.supportsRawSecretKeyImport()) { + // XXX implement unwrap using C_Unwrap() for all keys + implInit(Cipher.DECRYPT_MODE, p11Key); + if (wrappedKey.length > maxInputSize) { + throw new InvalidKeyException("Key is too long for unwrapping"); + } + + byte[] encoded = null; + implUpdate(wrappedKey, 0, wrappedKey.length); + try { + encoded = doFinal(); + } catch (BadPaddingException e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } + } catch (IllegalBlockSizeException e) { + // should not occur, handled with length check above + throw new InvalidKeyException("Unwrapping failed", e); + } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + TlsRsaPremasterSecretParameterSpec psps = + (TlsRsaPremasterSecretParameterSpec)spec; + encoded = KeyUtil.checkTlsPreMasterSecretKey( + psps.getClientVersion(), psps.getServerVersion(), + secureRandom, encoded, (failover != null)); + } + return ConstructKeys.constructKey(encoded, algorithm, type); - } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Unwrapping failed", e); - } catch (IllegalBlockSizeException e) { - // should not occur, handled with length check above - throw new InvalidKeyException("Unwrapping failed", e); + } else { + Session s = null; + SecretKey secretKey = null; + try { + try { + s = token.getObjSession(); + long keyType = CKK_GENERIC_SECRET; + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { + new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), + new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType), + }; + attributes = token.getAttributes( + O_IMPORT, CKO_SECRET_KEY, keyType, attributes); + long keyID = token.p11.C_UnwrapKey(s.id(), + new CK_MECHANISM(mechanism), p11Key.keyID, + wrappedKey, attributes); + secretKey = P11Key.secretKey(s, keyID, + algorithm, 48 << 3, attributes); + } catch (PKCS11Exception e) { + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("unwrap() failed", e); + } + } + + if (isTlsRsaPremasterSecret) { + byte[] replacer = new byte[48]; + if (failover == null) { + // Does smart compiler dispose this operation? + secureRandom.nextBytes(replacer); + } + + TlsRsaPremasterSecretParameterSpec psps = + (TlsRsaPremasterSecretParameterSpec)spec; + + // Please use the tricky failover and replacer byte array + // as the parameters so that smart compiler won't dispose + // the unused variable . + secretKey = polishPreMasterSecretKey(token, s, + failover, replacer, secretKey, + psps.getClientVersion(), psps.getServerVersion()); + } + + return secretKey; + } finally { + token.releaseSession(s); + } } } @@ -475,6 +567,34 @@ final class P11RSACipher extends CipherSpi { int n = P11KeyFactory.convertKey(token, key, algorithm).length(); return n; } + + private static SecretKey polishPreMasterSecretKey( + Token token, Session session, + Exception failover, byte[] replacer, SecretKey secretKey, + int clientVersion, int serverVersion) { + + if (failover != null) { + CK_VERSION version = new CK_VERSION( + (clientVersion >>> 8) & 0xFF, clientVersion & 0xFF); + try { + CK_ATTRIBUTE[] attributes = token.getAttributes( + O_GENERATE, CKO_SECRET_KEY, + CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_GenerateKey(session.id(), + // new CK_MECHANISM(CKM_TLS_PRE_MASTER_KEY_GEN, version), + new CK_MECHANISM(CKM_SSL3_PRE_MASTER_KEY_GEN, version), + attributes); + return P11Key.secretKey(session, + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + } catch (PKCS11Exception e) { + throw new ProviderException( + "Could not generate premaster secret", e); + } + } + + return secretKey; + } + } final class ConstructKeys { diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java b/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java index ff9b183ee26..21c853794bc 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java +++ b/jdk/src/share/classes/sun/security/pkcs11/P11TlsRsaPremasterSecretGenerator.java @@ -73,7 +73,7 @@ final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof TlsRsaPremasterSecretParameterSpec == false) { + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { throw new InvalidAlgorithmParameterException(MSG); } this.spec = (TlsRsaPremasterSecretParameterSpec)params; @@ -83,38 +83,32 @@ final class P11TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi { throw new InvalidParameterException(MSG); } + // Only can be used in client side to generate TLS RSA premaster secret. protected SecretKey engineGenerateKey() { if (spec == null) { throw new IllegalStateException ("TlsRsaPremasterSecretGenerator must be initialized"); } - byte[] b = spec.getEncodedSecret(); - if (b == null) { - CK_VERSION version = new CK_VERSION( + CK_VERSION version = new CK_VERSION( spec.getMajorVersion(), spec.getMinorVersion()); - Session session = null; - try { - session = token.getObjSession(); - CK_ATTRIBUTE[] attributes = token.getAttributes( - O_GENERATE, CKO_SECRET_KEY, - CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); - long keyID = token.p11.C_GenerateKey(session.id(), - new CK_MECHANISM(mechanism, version), attributes); - SecretKey key = P11Key.secretKey(session, - keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); - return key; - } catch (PKCS11Exception e) { - throw new ProviderException( - "Could not generate premaster secret", e); - } finally { - token.releaseSession(session); - } + Session session = null; + try { + session = token.getObjSession(); + CK_ATTRIBUTE[] attributes = token.getAttributes( + O_GENERATE, CKO_SECRET_KEY, + CKK_GENERIC_SECRET, new CK_ATTRIBUTE[0]); + long keyID = token.p11.C_GenerateKey(session.id(), + new CK_MECHANISM(mechanism, version), attributes); + SecretKey key = P11Key.secretKey(session, + keyID, "TlsRsaPremasterSecret", 48 << 3, attributes); + return key; + } catch (PKCS11Exception e) { + throw new ProviderException( + "Could not generate premaster secret", e); + } finally { + token.releaseSession(session); } - - // Won't worry, the TlsRsaPremasterSecret will be soon converted to - // TlsMasterSecret. - return new SecretKeySpec(b, "TlsRsaPremasterSecret"); } } diff --git a/jdk/src/share/classes/sun/security/pkcs11/Token.java b/jdk/src/share/classes/sun/security/pkcs11/Token.java index b97ab0cc998..39d301ae7b8 100644 --- a/jdk/src/share/classes/sun/security/pkcs11/Token.java +++ b/jdk/src/share/classes/sun/security/pkcs11/Token.java @@ -36,6 +36,7 @@ import javax.security.auth.login.LoginException; import sun.security.jca.JCAUtil; import sun.security.pkcs11.wrapper.*; +import static sun.security.pkcs11.TemplateManager.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** @@ -122,6 +123,9 @@ class Token implements Serializable { private final static CK_MECHANISM_INFO INVALID_MECH = new CK_MECHANISM_INFO(0, 0, 0); + // flag indicating whether the token supports raw secret key material import + private Boolean supportsRawSecretKeyImport; + Token(SunPKCS11 provider) throws PKCS11Exception { this.provider = provider; this.removable = provider.removable; @@ -160,6 +164,36 @@ class Token implements Serializable { return writeProtected; } + // return whether the token supports raw secret key material import + boolean supportsRawSecretKeyImport() { + if (supportsRawSecretKeyImport == null) { + SecureRandom random = JCAUtil.getSecureRandom(); + byte[] encoded = new byte[48]; + random.nextBytes(encoded); + + CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3]; + attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); + attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET); + attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded); + + Session session = null; + try { + attributes = getAttributes(O_IMPORT, + CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes); + session = getObjSession(); + long keyID = p11.C_CreateObject(session.id(), attributes); + + supportsRawSecretKeyImport = Boolean.TRUE; + } catch (PKCS11Exception e) { + supportsRawSecretKeyImport = Boolean.FALSE; + } finally { + releaseSession(session); + } + } + + return supportsRawSecretKeyImport; + } + // return whether we are logged in // uses cached result if current. session is optional and may be null boolean isLoggedIn(Session session) throws PKCS11Exception { diff --git a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java index 36e4310fef1..11da51e56d7 100644 --- a/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java @@ -48,23 +48,6 @@ import sun.security.util.KeyUtil; */ final class RSAClientKeyExchange extends HandshakeMessage { - /** - * The TLS spec says that the version in the RSA premaster secret must - * be the maximum version supported by the client (i.e. the version it - * requested in its client hello version). However, we (and other - * implementations) used to send the active negotiated version. The - * system property below allows to toggle the behavior. - */ - private final static String PROP_NAME = - "com.sun.net.ssl.rsaPreMasterSecretFix"; - - /* - * Default is "false" (old behavior) for compatibility reasons in - * SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property. - */ - private final static boolean rsaPreMasterSecretFix = - Debug.getBooleanProperty(PROP_NAME, false); - /* * The following field values were encrypted with the server's public * key (or temp key from server key exchange msg) and are presented @@ -88,22 +71,12 @@ final class RSAClientKeyExchange extends HandshakeMessage { } this.protocolVersion = protocolVersion; - int major, minor; - - if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) { - major = maxVersion.major; - minor = maxVersion.minor; - } else { - major = protocolVersion.major; - minor = protocolVersion.minor; - } - try { String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ? "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor), - generator); + kg.init(new TlsRsaPremasterSecretParameterSpec( + maxVersion.v, protocolVersion.v), generator); preMaster = kg.generateKey(); Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); @@ -138,18 +111,17 @@ final class RSAClientKeyExchange extends HandshakeMessage { } } - Exception failover = null; - byte[] encoded = null; try { Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); // Cannot generate key here, please don't use Cipher.UNWRAP_MODE! - cipher.init(Cipher.DECRYPT_MODE, privateKey); - encoded = cipher.doFinal(encrypted); - } catch (BadPaddingException bpe) { - failover = bpe; - encoded = null; - } catch (IllegalBlockSizeException ibse) { - // the message it too big to process with RSA + cipher.init(Cipher.UNWRAP_MODE, privateKey, + new TlsRsaPremasterSecretParameterSpec( + maxVersion.v, currentVersion.v), + generator); + preMaster = (SecretKey)cipher.unwrap(encrypted, + "TlsRsaPremasterSecret", Cipher.SECRET_KEY); + } catch (InvalidKeyException ibk) { + // the message is too big to process with RSA throw new SSLProtocolException( "Unable to process PreMasterSecret, may be too big"); } catch (Exception e) { @@ -160,124 +132,6 @@ final class RSAClientKeyExchange extends HandshakeMessage { } throw new RuntimeException("Could not generate dummy secret", e); } - - // polish the premaster secret - preMaster = polishPreMasterSecretKey( - currentVersion, maxVersion, generator, encoded, failover); - } - - /** - * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246, - * treating incorrectly formatted message blocks and/or mismatched - * version numbers in a manner indistinguishable from correctly - * formatted RSA blocks. - * - * RFC 5246 describes the approach as : - * - * 1. Generate a string R of 48 random bytes - * - * 2. Decrypt the message to recover the plaintext M - * - * 3. If the PKCS#1 padding is not correct, or the length of message - * M is not exactly 48 bytes: - * pre_master_secret = R - * else If ClientHello.client_version <= TLS 1.0, and version - * number check is explicitly disabled: - * premaster secret = M - * else If M[0..1] != ClientHello.client_version: - * premaster secret = R - * else: - * premaster secret = M - * - * Note that #2 has completed before the call of this method. - */ - private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion, - ProtocolVersion clientHelloVersion, SecureRandom generator, - byte[] encoded, Exception failoverException) { - - this.protocolVersion = clientHelloVersion; - if (generator == null) { - generator = new SecureRandom(); - } - byte[] random = new byte[48]; - generator.nextBytes(random); - - if (failoverException == null && encoded != null) { - // check the length - if (encoded.length != 48) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "incorrect length of premaster secret: " + - encoded.length); - } - - return generatePreMasterSecret( - clientHelloVersion, random, generator); - } - - if (clientHelloVersion.major != encoded[0] || - clientHelloVersion.minor != encoded[1]) { - - if (clientHelloVersion.v <= ProtocolVersion.TLS10.v && - currentVersion.major == encoded[0] && - currentVersion.minor == encoded[1]) { - /* - * For compatibility, we maintain the behavior that the - * version in pre_master_secret can be the negotiated - * version for TLS v1.0 and SSL v3.0. - */ - this.protocolVersion = currentVersion; - } else { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Mismatching Protocol Versions, " + - "ClientHello.client_version is " + - clientHelloVersion + - ", while PreMasterSecret.client_version is " + - ProtocolVersion.valueOf(encoded[0], encoded[1])); - } - - encoded = random; - } - } - - return generatePreMasterSecret( - clientHelloVersion, encoded, generator); - } - - if (debug != null && Debug.isOn("handshake") && - failoverException != null) { - System.out.println("Error decrypting premaster secret:"); - failoverException.printStackTrace(System.out); - } - - return generatePreMasterSecret(clientHelloVersion, random, generator); - } - - // generate a premaster secret with the specified version number - private static SecretKey generatePreMasterSecret( - ProtocolVersion version, byte[] encodedSecret, - SecureRandom generator) { - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Generating a random fake premaster secret"); - } - - try { - String s = ((version.v >= ProtocolVersion.TLS12.v) ? - "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); - KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec( - version.major, version.minor, encodedSecret), generator); - return kg.generateKey(); - } catch (InvalidAlgorithmParameterException | - NoSuchAlgorithmException iae) { - // unlikely to happen, otherwise, must be a provider exception - if (debug != null && Debug.isOn("handshake")) { - System.out.println("RSA premaster secret generation error:"); - iae.printStackTrace(System.out); - } - throw new RuntimeException("Could not generate dummy secret", iae); - } } @Override diff --git a/jdk/src/share/classes/sun/security/util/KeyUtil.java b/jdk/src/share/classes/sun/security/util/KeyUtil.java index cbaa8a5e23a..9c881b8031c 100644 --- a/jdk/src/share/classes/sun/security/util/KeyUtil.java +++ b/jdk/src/share/classes/sun/security/util/KeyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014, 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,6 +32,7 @@ import java.security.InvalidKeyException; import java.security.interfaces.ECKey; import java.security.interfaces.RSAKey; import java.security.interfaces.DSAKey; +import java.security.SecureRandom; import java.security.spec.KeySpec; import javax.crypto.SecretKey; import javax.crypto.interfaces.DHKey; @@ -156,6 +157,79 @@ public final class KeyUtil { providerName.startsWith("SunPKCS11")); } + /** + * Check the format of TLS PreMasterSecret. + *

+ * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246, + * treating incorrectly formatted message blocks and/or mismatched + * version numbers in a manner indistinguishable from correctly + * formatted RSA blocks. + * + * RFC 5246 describes the approach as : + * + * 1. Generate a string R of 48 random bytes + * + * 2. Decrypt the message to recover the plaintext M + * + * 3. If the PKCS#1 padding is not correct, or the length of message + * M is not exactly 48 bytes: + * pre_master_secret = R + * else If ClientHello.client_version <= TLS 1.0, and version + * number check is explicitly disabled: + * premaster secret = M + * else If M[0..1] != ClientHello.client_version: + * premaster secret = R + * else: + * premaster secret = M + * + * Note that #2 should have completed before the call to this method. + * + * @param clientVersion the version of the TLS protocol by which the + * client wishes to communicate during this session + * @param serverVersion the negotiated version of the TLS protocol which + * contains the lower of that suggested by the client in the client + * hello and the highest supported by the server. + * @param encoded the encoded key in its "RAW" encoding format + * @param isFailover whether or not the previous decryption of the + * encrypted PreMasterSecret message run into problem + * @return the polished PreMasterSecret key in its "RAW" encoding format + */ + public static byte[] checkTlsPreMasterSecretKey( + int clientVersion, int serverVersion, SecureRandom random, + byte[] encoded, boolean isFailOver) { + + if (random == null) { + random = new SecureRandom(); + } + byte[] replacer = new byte[48]; + random.nextBytes(replacer); + + if (!isFailOver && (encoded != null)) { + // check the length + if (encoded.length != 48) { + // private, don't need to clone the byte array. + return replacer; + } + + int encodedVersion = + ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); + if (clientVersion != encodedVersion) { + if (clientVersion > 0x0301 || // 0x0301: TLSv1 + serverVersion != encodedVersion) { + encoded = replacer; + } // Otherwise, For compatibility, we maintain the behavior + // that the version in pre_master_secret can be the + // negotiated version for TLS v1.0 and SSL v3.0. + } + + // private, don't need to clone the byte array. + return encoded; + } + + // private, don't need to clone the byte array. + return replacer; + } + /** * Returns whether the Diffie-Hellman public key is valid or not. * diff --git a/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java b/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java index 7ab29629a18..023725b6205 100644 --- a/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java +++ b/jdk/src/windows/classes/sun/security/mscapi/RSACipher.java @@ -35,6 +35,8 @@ import javax.crypto.*; import javax.crypto.spec.*; import sun.security.rsa.RSAKeyFactory; +import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; +import sun.security.util.KeyUtil; /** * RSA cipher implementation using the Microsoft Crypto API. @@ -92,9 +94,16 @@ public final class RSACipher extends CipherSpi { // the public key, if we were initialized using a public key private sun.security.mscapi.Key publicKey; + // the private key, if we were initialized using a private key private sun.security.mscapi.Key privateKey; + // cipher parameter for TLS RSA premaster secret + private AlgorithmParameterSpec spec = null; + + // the source of randomness + private SecureRandom random; + public RSACipher() { paddingType = PAD_PKCS1; } @@ -155,8 +164,12 @@ public final class RSACipher extends CipherSpi { throws InvalidKeyException, InvalidAlgorithmParameterException { if (params != null) { - throw new InvalidAlgorithmParameterException - ("Parameters not supported"); + if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new InvalidAlgorithmParameterException( + "Parameters not supported"); + } + spec = params; + this.random = random; // for TLS RSA premaster secret } init(opmode, key); } @@ -356,39 +369,47 @@ public final class RSACipher extends CipherSpi { } // see JCE spec - protected java.security.Key engineUnwrap(byte[] wrappedKey, String algorithm, + protected java.security.Key engineUnwrap(byte[] wrappedKey, + String algorithm, int type) throws InvalidKeyException, NoSuchAlgorithmException { if (wrappedKey.length > buffer.length) { throw new InvalidKeyException("Key is too long for unwrapping"); } + + boolean isTlsRsaPremasterSecret = + algorithm.equals("TlsRsaPremasterSecret"); + Exception failover = null; + byte[] encoded = null; + update(wrappedKey, 0, wrappedKey.length); - try { - byte[] encoding = doFinal(); - - switch (type) { - case Cipher.PUBLIC_KEY: - return constructPublicKey(encoding, algorithm); - - case Cipher.PRIVATE_KEY: - return constructPrivateKey(encoding, algorithm); - - case Cipher.SECRET_KEY: - return constructSecretKey(encoding, algorithm); - - default: - throw new InvalidKeyException("Unknown key type " + type); - } - + encoded = doFinal(); } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Unwrapping failed", e); - + if (isTlsRsaPremasterSecret) { + failover = e; + } else { + throw new InvalidKeyException("Unwrapping failed", e); + } } catch (IllegalBlockSizeException e) { // should not occur, handled with length check above throw new InvalidKeyException("Unwrapping failed", e); } + + if (isTlsRsaPremasterSecret) { + if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), + random, encoded, (failover != null)); + } + + return constructKey(encoded, algorithm, type); } // see JCE spec @@ -452,6 +473,22 @@ public final class RSACipher extends CipherSpi { return new SecretKeySpec(encodedKey, encodedKeyAlgorithm); } + private static Key constructKey(byte[] encodedKey, + String encodedKeyAlgorithm, + int keyType) throws InvalidKeyException, NoSuchAlgorithmException { + + switch (keyType) { + case Cipher.PUBLIC_KEY: + return constructPublicKey(encodedKey, encodedKeyAlgorithm); + case Cipher.PRIVATE_KEY: + return constructPrivateKey(encodedKey, encodedKeyAlgorithm); + case Cipher.SECRET_KEY: + return constructSecretKey(encodedKey, encodedKeyAlgorithm); + default: + throw new InvalidKeyException("Unknown key type " + keyType); + } + } + /* * Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY. * It expects and returns ciphertext data in big-endian form. diff --git a/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java b/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java index bbbfbb6bdb3..f19e7546ddd 100644 --- a/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java +++ b/jdk/test/com/sun/crypto/provider/TLS/TestPremaster.java @@ -33,6 +33,7 @@ import java.security.Provider; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import java.util.Formatter; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; @@ -52,27 +53,51 @@ public class TestPremaster { System.out.println("OK: " + e); } - test(kg, 3, 0); - test(kg, 3, 1); - test(kg, 3, 2); - test(kg, 4, 0); + int[] protocolVersions = {0x0300, 0x0301, 0x0302, 0x0400}; + for (int clientVersion : protocolVersions) { + for (int serverVersion : protocolVersions) { + test(kg, clientVersion, serverVersion); + if (serverVersion >= clientVersion) { + break; + } + } + } System.out.println("Done."); } - private static void test(KeyGenerator kg, int major, int minor) - throws Exception { + private static void test(KeyGenerator kg, + int clientVersion, int serverVersion) throws Exception { + + System.out.printf( + "Testing RSA pre-master secret key generation between " + + "client (0x%04X) and server(0x%04X)%n", + clientVersion, serverVersion); + kg.init(new TlsRsaPremasterSecretParameterSpec( + clientVersion, serverVersion)); - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor)); SecretKey key = kg.generateKey(); byte[] encoded = key.getEncoded(); - if (encoded.length != 48) { - throw new Exception("length: " + encoded.length); - } - if ((encoded[0] != major) || (encoded[1] != minor)) { - throw new Exception("version mismatch: " + encoded[0] + - "." + encoded[1]); - } - System.out.println("OK: " + major + "." + minor); + if (encoded != null) { // raw key material may be not extractable + if (encoded.length != 48) { + throw new Exception("length: " + encoded.length); + } + int v = versionOf(encoded[0], encoded[1]); + if (clientVersion != v) { + if (serverVersion != v || clientVersion >= 0x0302) { + throw new Exception(String.format( + "version mismatch: (0x%04X) rather than (0x%04X) " + + "is used in pre-master secret", v, clientVersion)); + } + System.out.printf("Use compatible version (0x%04X)%n", v); + } + System.out.println("Passed, version matches!"); + } else { + System.out.println("Raw key material is not extractable"); + } + } + + private static int versionOf(int major, int minor) { + return ((major & 0xFF) << 8) | (minor & 0xFF); } } diff --git a/jdk/test/sun/security/pkcs11/fips/CipherTest.java b/jdk/test/sun/security/pkcs11/fips/CipherTest.java index e85a3a6853f..dd627d356b5 100644 --- a/jdk/test/sun/security/pkcs11/fips/CipherTest.java +++ b/jdk/test/sun/security/pkcs11/fips/CipherTest.java @@ -472,8 +472,21 @@ public class CipherTest { return false; } + // No ECDH-capable certificate in key store. May restructure + // this in the future. + if (cipherSuite.contains("ECDHE_ECDSA") || + cipherSuite.contains("ECDH_ECDSA") || + cipherSuite.contains("ECDH_RSA")) { + System.out.println("Skipping unsupported test for " + + cipherSuite + " of " + protocol); + return false; + } + // skip SSLv2Hello protocol - if (protocol.equals("SSLv2Hello")) { + // + // skip TLSv1.2 protocol, we have not implement "SunTls12Prf" and + // SunTls12RsaPremasterSecret in SunPKCS11 provider + if (protocol.equals("SSLv2Hello") || protocol.equals("TLSv1.2")) { System.out.println("Skipping unsupported test for " + cipherSuite + " of " + protocol); return false; diff --git a/jdk/test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java b/jdk/test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java index f7f288da44b..ed5d9aa567e 100644 --- a/jdk/test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java +++ b/jdk/test/sun/security/pkcs11/fips/ClientJSSEServerJSSE.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6313675 6323647 + * @bug 6313675 6323647 8028192 * @summary Verify that all ciphersuites work in FIPS mode * @library .. * @author Andreas Sterbenz @@ -47,9 +47,13 @@ public class ClientJSSEServerJSSE extends SecmodTest { return; } - if ("sparc".equals(System.getProperty("os.arch")) == false) { - // we have not updated other platforms with the proper NSS libraries yet - System.out.println("Test currently works only on solaris-sparc, skipping"); + String arch = System.getProperty("os.arch"); + if (!("sparc".equals(arch) || "sparcv9".equals(arch))) { + // we have not updated other platforms with the proper NSS + // libraries yet + System.out.println( + "Test currently works only on solaris-sparc " + + "and solaris-sparcv9. Skipping on " + arch); return; } diff --git a/jdk/test/sun/security/pkcs11/tls/TestPremaster.java b/jdk/test/sun/security/pkcs11/tls/TestPremaster.java index f7a51041ead..05e8efb0f28 100644 --- a/jdk/test/sun/security/pkcs11/tls/TestPremaster.java +++ b/jdk/test/sun/security/pkcs11/tls/TestPremaster.java @@ -34,6 +34,7 @@ import java.security.Provider; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import java.util.Formatter; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; @@ -59,27 +60,51 @@ public class TestPremaster extends PKCS11Test { System.out.println("OK: " + e); } - test(kg, 3, 0); - test(kg, 3, 1); - test(kg, 3, 2); - test(kg, 4, 0); + int[] protocolVersions = {0x0300, 0x0301, 0x0302, 0x0400}; + for (int clientVersion : protocolVersions) { + for (int serverVersion : protocolVersions) { + test(kg, clientVersion, serverVersion); + if (serverVersion >= clientVersion) { + break; + } + } + } System.out.println("Done."); } - private static void test(KeyGenerator kg, int major, int minor) - throws Exception { + private static void test(KeyGenerator kg, + int clientVersion, int serverVersion) throws Exception { - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor)); + System.out.printf( + "Testing RSA pre-master secret key generation between " + + "client (0x%04X) and server(0x%04X)%n", + clientVersion, serverVersion); + kg.init(new TlsRsaPremasterSecretParameterSpec( + clientVersion, serverVersion)); SecretKey key = kg.generateKey(); byte[] encoded = key.getEncoded(); - if (encoded.length != 48) { - throw new Exception("length: " + encoded.length); - } - if ((encoded[0] != major) || (encoded[1] != minor)) { - throw new Exception("version mismatch: " + encoded[0] + - "." + encoded[1]); - } - System.out.println("OK: " + major + "." + minor); + if (encoded != null) { // raw key material may be not extractable + if (encoded.length != 48) { + throw new Exception("length: " + encoded.length); + } + int v = versionOf(encoded[0], encoded[1]); + if (clientVersion != v) { + if (serverVersion != v || clientVersion >= 0x0302) { + throw new Exception(String.format( + "version mismatch: (0x%04X) rather than (0x%04X) " + + "is used in pre-master secret", v, clientVersion)); + } + System.out.printf("Use compatible version (0x%04X)%n", v); + } + System.out.println("Passed, version matches!"); + } else { + System.out.println("Raw key material is not extractable"); + } } + + private static int versionOf(int major, int minor) { + return ((major & 0xFF) << 8) | (minor & 0xFF); + } + } From 55d8dc5d85ab949743d8481595a56b68265e6201 Mon Sep 17 00:00:00 2001 From: Jeremy Manson Date: Wed, 9 Apr 2014 09:36:19 -0700 Subject: [PATCH 152/170] 8039124: j.u.regex.Matcher.appendReplace/Tail() should support StringBuilder variant To add the StringBuilder variant Co-authored-by: Peter Levart Reviewed-by: alanb, sherman --- .../classes/java/util/regex/Matcher.java | 154 ++++++- jdk/test/java/util/regex/RegExTest.java | 378 +++++++++++++++++- 2 files changed, 510 insertions(+), 22 deletions(-) diff --git a/jdk/src/share/classes/java/util/regex/Matcher.java b/jdk/src/share/classes/java/util/regex/Matcher.java index ebab02e3b82..e841294ed8e 100644 --- a/jdk/src/share/classes/java/util/regex/Matcher.java +++ b/jdk/src/share/classes/java/util/regex/Matcher.java @@ -65,9 +65,10 @@ import java.util.Objects; * new strings whose contents can, if desired, be computed from the match * result. The {@link #appendReplacement appendReplacement} and {@link * #appendTail appendTail} methods can be used in tandem in order to collect - * the result into an existing string buffer, or the more convenient {@link - * #replaceAll replaceAll} method can be used to create a string in which every - * matching subsequence in the input sequence is replaced. + * the result into an existing string buffer or string builder. Alternatively, + * the more convenient {@link #replaceAll replaceAll} method can be used to + * create a string in which every matching subsequence in the input sequence + * is replaced. * *

The explicit state of a matcher includes the start and end indices of * the most recent successful match. It also includes the start and end @@ -792,15 +793,115 @@ public final class Matcher implements MatchResult { * that does not exist in the pattern */ public Matcher appendReplacement(StringBuffer sb, String replacement) { - // If no match, return error if (first < 0) throw new IllegalStateException("No match available"); - - // Process substitution string to replace group references with groups - int cursor = 0; StringBuilder result = new StringBuilder(); + appendExpandedReplacement(replacement, result); + // Append the intervening text + sb.append(text, lastAppendPosition, first); + // Append the match substitution + sb.append(result); + lastAppendPosition = last; + return this; + } + /** + * Implements a non-terminal append-and-replace step. + * + *

This method performs the following actions:

+ * + *
    + * + *
  1. It reads characters from the input sequence, starting at the + * append position, and appends them to the given string builder. It + * stops after reading the last character preceding the previous match, + * that is, the character at index {@link + * #start()} - 1.

  2. + * + *
  3. It appends the given replacement string to the string builder. + *

  4. + * + *
  5. It sets the append position of this matcher to the index of + * the last character matched, plus one, that is, to {@link #end()}. + *

  6. + * + *
+ * + *

The replacement string may contain references to subsequences + * captured during the previous match: Each occurrence of + * $g will be replaced by the result of + * evaluating {@link #group(int) group}(g). + * The first number after the $ is always treated as part of + * the group reference. Subsequent numbers are incorporated into g if + * they would form a legal group reference. Only the numerals '0' + * through '9' are considered as potential components of the group + * reference. If the second group matched the string "foo", for + * example, then passing the replacement string "$2bar" would + * cause "foobar" to be appended to the string builder. A dollar + * sign ($) may be included as a literal in the replacement + * string by preceding it with a backslash (\$). + * + *

Note that backslashes (\) and dollar signs ($) in + * the replacement string may cause the results to be different than if it + * were being treated as a literal replacement string. Dollar signs may be + * treated as references to captured subsequences as described above, and + * backslashes are used to escape literal characters in the replacement + * string. + * + *

This method is intended to be used in a loop together with the + * {@link #appendTail appendTail} and {@link #find find} methods. The + * following code, for example, writes one dog two dogs in the + * yard to the standard-output stream:

+ * + *
+     * Pattern p = Pattern.compile("cat");
+     * Matcher m = p.matcher("one cat two cats in the yard");
+     * StringBuilder sb = new StringBuilder();
+     * while (m.find()) {
+     *     m.appendReplacement(sb, "dog");
+     * }
+     * m.appendTail(sb);
+     * System.out.println(sb.toString());
+ * + * @param sb + * The target string builder + * @param replacement + * The replacement string + * @return This matcher + * + * @throws IllegalStateException + * If no match has yet been attempted, + * or if the previous match operation failed + * @throws IllegalArgumentException + * If the replacement string refers to a named-capturing + * group that does not exist in the pattern + * @throws IndexOutOfBoundsException + * If the replacement string refers to a capturing group + * that does not exist in the pattern + * @since 1.9 + */ + public Matcher appendReplacement(StringBuilder sb, String replacement) { + // If no match, return error + if (first < 0) + throw new IllegalStateException("No match available"); + StringBuilder result = new StringBuilder(); + appendExpandedReplacement(replacement, result); + // Append the intervening text + sb.append(text, lastAppendPosition, first); + // Append the match substitution + sb.append(result); + lastAppendPosition = last; + return this; + } + + /** + * Processes replacement string to replace group references with + * groups. + */ + private StringBuilder appendExpandedReplacement( + String replacement, StringBuilder result) { + int cursor = 0; while (cursor < replacement.length()) { char nextChar = replacement.charAt(cursor); if (nextChar == '\\') { @@ -852,8 +953,8 @@ public final class Matcher implements MatchResult { cursor++; } else { // The first number is always a group - refNum = (int)nextChar - '0'; - if ((refNum < 0)||(refNum > 9)) + refNum = nextChar - '0'; + if ((refNum < 0) || (refNum > 9)) throw new IllegalArgumentException( "Illegal group reference"); cursor++; @@ -864,7 +965,7 @@ public final class Matcher implements MatchResult { break; } int nextDigit = replacement.charAt(cursor) - '0'; - if ((nextDigit < 0)||(nextDigit > 9)) { // not a number + if ((nextDigit < 0) || (nextDigit > 9)) { // not a number break; } int newRefNum = (refNum * 10) + nextDigit; @@ -884,13 +985,7 @@ public final class Matcher implements MatchResult { cursor++; } } - // Append the intervening text - sb.append(text, lastAppendPosition, first); - // Append the match substitution - sb.append(result); - - lastAppendPosition = last; - return this; + return result; } /** @@ -912,6 +1007,27 @@ public final class Matcher implements MatchResult { return sb; } + /** + * Implements a terminal append-and-replace step. + * + *

This method reads characters from the input sequence, starting at + * the append position, and appends them to the given string builder. It is + * intended to be invoked after one or more invocations of the {@link + * #appendReplacement appendReplacement} method in order to copy the + * remainder of the input sequence.

+ * + * @param sb + * The target string builder + * + * @return The target string builder + * + * @since 1.9 + */ + public StringBuilder appendTail(StringBuilder sb) { + sb.append(text, lastAppendPosition, getTextLength()); + return sb; + } + /** * Replaces every subsequence of the input sequence that matches the * pattern with the given replacement string. @@ -950,7 +1066,7 @@ public final class Matcher implements MatchResult { reset(); boolean result = find(); if (result) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); do { appendReplacement(sb, replacement); result = find(); @@ -1000,7 +1116,7 @@ public final class Matcher implements MatchResult { reset(); if (!find()) return text.toString(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); appendReplacement(sb, replacement); appendTail(sb); return sb.toString(); diff --git a/jdk/test/java/util/regex/RegExTest.java b/jdk/test/java/util/regex/RegExTest.java index cd6abd9be07..7cc7c784cf2 100644 --- a/jdk/test/java/util/regex/RegExTest.java +++ b/jdk/test/java/util/regex/RegExTest.java @@ -32,7 +32,7 @@ * 6358731 6178785 6284152 6231989 6497148 6486934 6233084 6504326 6635133 * 6350801 6676425 6878475 6919132 6931676 6948903 6990617 7014645 7039066 * 7067045 7014640 7189363 8007395 8013252 8013254 8012646 8023647 6559590 - * 8027645 8035076 + * 8027645 8035076 8039124 */ import java.util.regex.*; @@ -75,7 +75,10 @@ public class RegExTest { // Substitition tests on randomly generated sequences globalSubstitute(); stringbufferSubstitute(); + stringbuilderSubstitute(); + substitutionBasher(); + substitutionBasher2(); // Canonical Equivalence ceTest(); @@ -296,10 +299,12 @@ public class RegExTest { final Matcher m = Pattern.compile("xyz").matcher("xyz"); m.matches(); - check(new Runnable() { public void run() { m.appendTail(null);}}); + check(new Runnable() { public void run() { m.appendTail((StringBuffer)null);}}); + check(new Runnable() { public void run() { m.appendTail((StringBuilder)null);}}); check(new Runnable() { public void run() { m.replaceAll(null);}}); check(new Runnable() { public void run() { m.replaceFirst(null);}}); - check(new Runnable() { public void run() { m.appendReplacement(null, null);}}); + check(new Runnable() { public void run() { m.appendReplacement((StringBuffer)null, null);}}); + check(new Runnable() { public void run() { m.appendReplacement((StringBuilder)null, null);}}); check(new Runnable() { public void run() { m.reset(null);}}); check(new Runnable() { public void run() { Matcher.quoteReplacement(null);}}); //check(new Runnable() { public void run() { m.usePattern(null);}}); @@ -2973,6 +2978,286 @@ public class RegExTest { report("SB Substitution"); } + /** + * Tests the usage of Matcher.appendReplacement() with literal + * and group substitutions. + */ + private static void stringbuilderSubstitute() throws Exception { + // SB substitution with literal + String blah = "zzzblahzzz"; + Pattern p = Pattern.compile("blah"); + Matcher m = p.matcher(blah); + StringBuilder result = new StringBuilder(); + try { + m.appendReplacement(result, "blech"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "blech"); + if (!result.toString().equals("zzzblech")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzblechzzz")) + failCount++; + + // SB substitution with groups + blah = "zzzabcdzzz"; + p = Pattern.compile("(ab)(cd)*"); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzz")) + failCount++; + + // SB substitution with 3 groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1w$2w$3"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1w$2w$3"); + if (!result.toString().equals("zzzabwcdwef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabwcdwefzzz")) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = "zzzabcdzzzabcddzzzabcdzzz"; + p = Pattern.compile("(ab)(cd*)"); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals("zzzabzzzabcddzzzcd")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzzabcddzzzcdzzz")) + failCount++; + + // Check to make sure escaped $ is ignored + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, "$1w\\$2w$3"); + if (!result.toString().equals("zzzabw$2wef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabw$2wefzzz")) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + try { + m.appendReplacement(result, "$1w$5w$3"); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + + // Check double digit group references + blah = "zzz123456789101112zzz"; + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, "$1w$11w$3"); + if (!result.toString().equals("zzz1w11w3")) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, "$1w$15w$3"); + if (!result.toString().equals("zzzabwab5wef")) + failCount++; + + + // Supplementary character test + // SB substitution with literal + blah = toSupplementaries("zzzblahzzz"); + p = Pattern.compile(toSupplementaries("blah")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, toSupplementaries("blech")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("blech")); + if (!result.toString().equals(toSupplementaries("zzzblech"))) + failCount++; + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzblechzzz"))) + failCount++; + + // SB substitution with groups + blah = toSupplementaries("zzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzz"))) + failCount++; + + // SB substitution with 3 groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwcdwef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz"))) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd*)")); + m = p.matcher(blah); + result = new StringBuilder(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz"))) + failCount++; + + // Check to make sure escaped $ is ignored + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w\\$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabw$2wef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz"))) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + try { + m.appendReplacement(result, toSupplementaries("$1w$5w$3")); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + // Check double digit group references + blah = toSupplementaries("zzz123456789101112zzz"); + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$11w$3")); + if (!result.toString().equals(toSupplementaries("zzz1w11w3"))) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuilder(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$15w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwab5wef"))) + failCount++; + // Check nothing has been appended into the output buffer if + // the replacement string triggers IllegalArgumentException. + p = Pattern.compile("(abc)"); + m = p.matcher("abcd"); + result = new StringBuilder(); + m.find(); + try { + m.appendReplacement(result, ("xyz$g")); + failCount++; + } catch (IllegalArgumentException iae) { + if (result.length() != 0) + failCount++; + } + report("SB Substitution 2"); + } + /* * 5 groups of characters are created to make a substitution string. * A base string will be created including random lead chars, the @@ -3059,6 +3344,93 @@ public class RegExTest { report("Substitution Basher"); } + /* + * 5 groups of characters are created to make a substitution string. + * A base string will be created including random lead chars, the + * substitution string, and random trailing chars. + * A pattern containing the 5 groups is searched for and replaced with: + * random group + random string + random group. + * The results are checked for correctness. + */ + private static void substitutionBasher2() { + for (int runs = 0; runs<1000; runs++) { + // Create a base string to work in + int leadingChars = generator.nextInt(10); + StringBuilder baseBuffer = new StringBuilder(100); + String leadingString = getRandomAlphaString(leadingChars); + baseBuffer.append(leadingString); + + // Create 5 groups of random number of random chars + // Create the string to substitute + // Create the pattern string to search for + StringBuilder bufferToSub = new StringBuilder(25); + StringBuilder bufferToPat = new StringBuilder(50); + String[] groups = new String[5]; + for(int i=0; i<5; i++) { + int aGroupSize = generator.nextInt(5)+1; + groups[i] = getRandomAlphaString(aGroupSize); + bufferToSub.append(groups[i]); + bufferToPat.append('('); + bufferToPat.append(groups[i]); + bufferToPat.append(')'); + } + String stringToSub = bufferToSub.toString(); + String pattern = bufferToPat.toString(); + + // Place sub string into working string at random index + baseBuffer.append(stringToSub); + + // Append random chars to end + int trailingChars = generator.nextInt(10); + String trailingString = getRandomAlphaString(trailingChars); + baseBuffer.append(trailingString); + String baseString = baseBuffer.toString(); + + // Create test pattern and matcher + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(baseString); + + // Reject candidate if pattern happens to start early + m.find(); + if (m.start() < leadingChars) + continue; + + // Reject candidate if more than one match + if (m.find()) + continue; + + // Construct a replacement string with : + // random group + random string + random group + StringBuilder bufferToRep = new StringBuilder(); + int groupIndex1 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex1 + 1)); + String randomMidString = getRandomAlphaString(5); + bufferToRep.append(randomMidString); + int groupIndex2 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex2 + 1)); + String replacement = bufferToRep.toString(); + + // Do the replacement + String result = m.replaceAll(replacement); + + // Construct expected result + StringBuilder bufferToRes = new StringBuilder(); + bufferToRes.append(leadingString); + bufferToRes.append(groups[groupIndex1]); + bufferToRes.append(randomMidString); + bufferToRes.append(groups[groupIndex2]); + bufferToRes.append(trailingString); + String expectedResult = bufferToRes.toString(); + + // Check results + if (!result.equals(expectedResult)) { + failCount++; + } + } + + report("Substitution Basher 2"); + } + /** * Checks the handling of some escape sequences that the Pattern * class should process instead of the java compiler. These are From 87cb02ac81f1f3129a14dc4c5a0cfde579344417 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 10 Apr 2014 10:31:05 +0800 Subject: [PATCH 153/170] 8039575: liberate two manual kerberos tests Reviewed-by: xuelei --- .../share/classes/java/security/Provider.java | 2 +- .../security/jgss/krb5/Krb5MechFactory.java | 4 ++ .../jgss/spnego/SpNegoMechFactory.java | 4 ++ .../auth/kerberos/KerberosHashEqualsTest.java | 49 ++++++++++--------- .../auth/kerberos/KerberosTixDateTest.java | 5 +- 5 files changed, 37 insertions(+), 27 deletions(-) diff --git a/jdk/src/share/classes/java/security/Provider.java b/jdk/src/share/classes/java/security/Provider.java index e8c7a081b5a..05f670c29bd 100644 --- a/jdk/src/share/classes/java/security/Provider.java +++ b/jdk/src/share/classes/java/security/Provider.java @@ -1332,7 +1332,7 @@ public abstract class Provider extends Properties { addEngine("SSLContext", false, null); addEngine("TrustManagerFactory", false, null); // JGSS - addEngine("GssApiMechanism", false, null); + addEngine("GssApiMechanism", true, "sun.security.jgss.GSSCaller"); // SASL addEngine("SaslClientFactory", false, null); addEngine("SaslServerFactory", false, null); diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java index ffae2cdc2fa..cc9626c14f7 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java @@ -86,6 +86,10 @@ public final class Krb5MechFactory implements MechanismFactory { return result; } + public Krb5MechFactory() { + this(GSSCaller.CALLER_UNKNOWN); + } + public Krb5MechFactory(GSSCaller caller) { this.caller = caller; } diff --git a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java index cb60230d4f9..511547b8a78 100644 --- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java +++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoMechFactory.java @@ -96,6 +96,10 @@ public final class SpNegoMechFactory implements MechanismFactory { return result; } + public SpNegoMechFactory() { + this(GSSCaller.CALLER_UNKNOWN); + } + public SpNegoMechFactory(GSSCaller caller) { manager = new GSSManagerImpl(caller, false); Oid[] mechs = manager.getMechs(); diff --git a/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java b/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java index 906700c71cc..9578a59547a 100644 --- a/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java +++ b/jdk/test/javax/security/auth/kerberos/KerberosHashEqualsTest.java @@ -25,7 +25,6 @@ * @test * @bug 4641821 * @summary hashCode() and equals() for KerberosKey and KerberosTicket - * @run main/manual KerberosHashEqualsTest */ /* @@ -60,8 +59,8 @@ public class KerberosHashEqualsTest { void check() throws Exception { KerberosKey k1, k2; - k1 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 1, 1); - k2 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 1, 1); + k1 = new KerberosKey(newKP("A"), "pass".getBytes(), 1, 1); + k2 = new KerberosKey(newKP("A"), "pass".getBytes(), 1, 1); checkSame(k1, k1); // me to me checkSame(k1, k2); // same @@ -73,13 +72,13 @@ public class KerberosHashEqualsTest { checkSame(k2, k2); // a little different - k2 = new KerberosKey(new KerberosPrincipal("B"), "pass".getBytes(), 1, 1); + k2 = new KerberosKey(newKP("B"), "pass".getBytes(), 1, 1); checkNotSame(k1, k2); - k2 = new KerberosKey(new KerberosPrincipal("A"), "ssap".getBytes(), 1, 1); + k2 = new KerberosKey(newKP("A"), "ssap".getBytes(), 1, 1); checkNotSame(k1, k2); - k2 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 2, 1); + k2 = new KerberosKey(newKP("A"), "pass".getBytes(), 2, 1); checkNotSame(k1, k2); - k2 = new KerberosKey(new KerberosPrincipal("A"), "pass".getBytes(), 1, 2); + k2 = new KerberosKey(newKP("A"), "pass".getBytes(), 1, 2); checkNotSame(k1, k2); k1 = new KerberosKey(null, "pass".getBytes(), 1, 2); @@ -90,33 +89,33 @@ public class KerberosHashEqualsTest { checkNotSame(k1, "Another Object"); KerberosTicket t1, t2; - t1 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t1 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkSame(t1, t1); checkSame(t1, t2); - t2 = new KerberosTicket("asn11".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn11".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client1"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client1"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server1"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server1"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass1".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass1".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 2, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 2, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {false, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {false, true}, new Date(0), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(1), new Date(0), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(1), new Date(0), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(1), new Date(0), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(1), new Date(0), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(1), new Date(0), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(1), new Date(0), null); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), new InetAddress[2]); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(0), new InetAddress[2]); checkNotSame(t1, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); - t1 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); + t1 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); checkSame(t1, t2); // renewtill is useless t2.destroy(); @@ -126,11 +125,15 @@ public class KerberosHashEqualsTest { checkNotSame(t2, t1); checkSame(t2, t2); - t2 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); - t1 = new KerberosTicket("asn1".getBytes(), new KerberosPrincipal("client"), new KerberosPrincipal("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); + t2 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(1), null); + t1 = new KerberosTicket("asn1".getBytes(), newKP("client"), newKP("server"), "pass".getBytes(), 1, new boolean[] {true, true, true, true, true, true, true, true, true, true}, new Date(0), new Date(0), new Date(0), new Date(2), null); checkNotSame(t1, t2); // renewtill is useful checkNotSame(t1, "Another Object"); System.out.println("Good!"); } + + KerberosPrincipal newKP(String s) { + return new KerberosPrincipal(s + "@JLABS.SFBAY.SUN.COM"); + } } diff --git a/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java b/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java index 2fed8d083cb..53b5ec8068a 100644 --- a/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java +++ b/jdk/test/javax/security/auth/kerberos/KerberosTixDateTest.java @@ -25,7 +25,6 @@ * @test * @bug 6659990 * @summary test the immutability of the Date fields in KerberosTicket class. - * @run main/manual KerberosTixDateTest */ /* @@ -64,8 +63,8 @@ public class KerberosTixDateTest { public static void main(String[] args) throws Exception { byte[] asn1Bytes = "asn1".getBytes(); - KerberosPrincipal client = new KerberosPrincipal("client"); - KerberosPrincipal server = new KerberosPrincipal("server"); + KerberosPrincipal client = new KerberosPrincipal("client@JLABS.SFBAY.SUN.COM"); + KerberosPrincipal server = new KerberosPrincipal("server@JLABS.SFBAY.SUN.COM"); byte[] keyBytes = "sessionKey".getBytes(); long originalTime = 12345678L; Date inDate = new Date(originalTime); From b8e32d8ca54f4216f830bc17081725703470315f Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 10 Apr 2014 11:01:15 +0100 Subject: [PATCH 154/170] 8039527: Broken links in ConcurrentMap javadoc Reviewed-by: martin, alanb --- jdk/src/share/classes/java/util/Map.java | 64 ++++++++++++------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/jdk/src/share/classes/java/util/Map.java b/jdk/src/share/classes/java/util/Map.java index de8bbce01a2..19840b268fe 100644 --- a/jdk/src/share/classes/java/util/Map.java +++ b/jdk/src/share/classes/java/util/Map.java @@ -157,10 +157,10 @@ public interface Map { * key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ boolean containsKey(Object key); @@ -177,10 +177,10 @@ public interface Map { * specified value * @throws ClassCastException if the value is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified value is null and this * map does not permit null values - * (optional) + * (optional) */ boolean containsValue(Object value); @@ -204,10 +204,10 @@ public interface Map { * {@code null} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ V get(Object key); @@ -264,10 +264,10 @@ public interface Map { * is not supported by this map * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this * map does not permit null keys - * (optional) + * (optional) */ V remove(Object key); @@ -577,10 +577,10 @@ public interface Map { * {@code defaultValue} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) * @since 1.8 */ default V getOrDefault(Object key, V defaultValue) { @@ -659,13 +659,13 @@ public interface Map { * values * @throws ClassCastException if a replacement value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if function or a replacement value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a replacement value * prevents it from being stored in this map - * (optional) + * (optional) * @throws ConcurrentModificationException if an entry is found to be * removed during iteration * @since 1.8 @@ -726,16 +726,16 @@ public interface Map { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V putIfAbsent(K key, V value) { @@ -772,13 +772,13 @@ public interface Map { * @return {@code true} if the value was removed * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @since 1.8 */ default boolean remove(Object key, Object value) { @@ -821,14 +821,14 @@ public interface Map { * @return {@code true} if the value was replaced * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of a specified key or value * prevents it from being stored in this map * @throws NullPointerException if a specified key or newValue is null, * and this map does not permit null keys or values * @throws NullPointerException if oldValue is null and this map does not * permit null values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a specified key * or value prevents it from being stored in this map * @since 1.8 @@ -871,10 +871,10 @@ public interface Map { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key @@ -942,10 +942,10 @@ public interface Map { * is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfAbsent(K key, @@ -1003,10 +1003,10 @@ public interface Map { * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfPresent(K key, @@ -1079,10 +1079,10 @@ public interface Map { * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V compute(K key, @@ -1157,10 +1157,10 @@ public interface Map { * value is associated with the key * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not support null keys or the value or remappingFunction is * null From 34b9e5a9bbc867295c36ef0eb9004d90948c4049 Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Thu, 10 Apr 2014 07:09:13 -0700 Subject: [PATCH 155/170] 8039368: Remove testcase from npt utf.c Don't compile testcase by default Reviewed-by: sla, vkempik --- jdk/src/share/npt/utf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/npt/utf.c b/jdk/src/share/npt/utf.c index e4695597bd6..a3b437d346d 100644 --- a/jdk/src/share/npt/utf.c +++ b/jdk/src/share/npt/utf.c @@ -396,7 +396,7 @@ utf8mToUtf8s(struct UtfInst *ui, jbyte *string, int length, jbyte *newString, in /* ================================================================= */ -#if 1 /* Test program */ +#ifdef COMPILE_WITH_UTF_TEST /* Test program */ /* * Convert any byte array into a printable string. From 002e08e73db63112884a1726220d918795f28840 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 10 Apr 2014 08:43:46 -0700 Subject: [PATCH 156/170] 8039864: Fix fallthrough lint warnings in other libs Reviewed-by: alanb, lancea --- jdk/src/share/classes/sun/tools/java/Environment.java | 1 + jdk/src/share/classes/sun/tools/java/Scanner.java | 5 +++++ jdk/src/share/classes/sun/tools/javac/Main.java | 1 + jdk/src/share/classes/sun/tools/jinfo/JInfo.java | 2 ++ jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java | 2 +- .../share/classes/sun/tools/tree/NewInstanceExpression.java | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/tools/java/Environment.java b/jdk/src/share/classes/sun/tools/java/Environment.java index 51b09dcb736..76f9c01e9a7 100644 --- a/jdk/src/share/classes/sun/tools/java/Environment.java +++ b/jdk/src/share/classes/sun/tools/java/Environment.java @@ -648,6 +648,7 @@ public class Environment implements Constants { * Return true if an implicit cast from this type to * the given type is allowed. */ + @SuppressWarnings("fallthrough") public boolean implicitCast(Type from, Type to) throws ClassNotFound { if (from == to) return true; diff --git a/jdk/src/share/classes/sun/tools/java/Scanner.java b/jdk/src/share/classes/sun/tools/java/Scanner.java index 9152f48b24f..7dfa6ee37c8 100644 --- a/jdk/src/share/classes/sun/tools/java/Scanner.java +++ b/jdk/src/share/classes/sun/tools/java/Scanner.java @@ -511,6 +511,7 @@ class Scanner implements Constants { * Scan a number. The first digit of the number should be the current * character. We may be scanning hex, decimal, or octal at this point */ + @SuppressWarnings("fallthrough") private void scanNumber() throws IOException { boolean seenNonOctal = false; boolean overflow = false; @@ -532,6 +533,7 @@ class Scanner implements Constants { // We can't yet throw an error if reading an octal. We might // discover we're really reading a real. seenNonOctal = true; + // Fall through case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': seenDigit = true; @@ -668,6 +670,7 @@ class Scanner implements Constants { * Scan a float. Should be called with the current character is either * the 'e', 'E' or '.' */ + @SuppressWarnings("fallthrough") private void scanReal() throws IOException { boolean seenExponent = false; boolean isSingleFloat = false; @@ -984,6 +987,7 @@ class Scanner implements Constants { return xscan(); } + @SuppressWarnings("fallthrough") protected long xscan() throws IOException { final ScannerInputReader in = this.in; long retPos = pos; @@ -1006,6 +1010,7 @@ class Scanner implements Constants { token = COMMENT; return retPos; } + // Fall through case ' ': case '\t': case '\f': diff --git a/jdk/src/share/classes/sun/tools/javac/Main.java b/jdk/src/share/classes/sun/tools/javac/Main.java index 2c50e3a3972..94308c5a0f3 100644 --- a/jdk/src/share/classes/sun/tools/javac/Main.java +++ b/jdk/src/share/classes/sun/tools/javac/Main.java @@ -192,6 +192,7 @@ class Main implements Constants { /** * Run the compiler */ + @SuppressWarnings("fallthrough") public synchronized boolean compile(String argv[]) { String sourcePathArg = null; String classPathArg = null; diff --git a/jdk/src/share/classes/sun/tools/jinfo/JInfo.java b/jdk/src/share/classes/sun/tools/jinfo/JInfo.java index c1e9d5ffb82..f02eb27d2e2 100644 --- a/jdk/src/share/classes/sun/tools/jinfo/JInfo.java +++ b/jdk/src/share/classes/sun/tools/jinfo/JInfo.java @@ -41,6 +41,7 @@ import sun.tools.attach.HotSpotVirtualMachine; */ public class JInfo { + @SuppressWarnings("fallthrough") public static void main(String[] args) throws Exception { if (args.length == 0) { usage(1); // no arguments @@ -118,6 +119,7 @@ public class JInfo { case "-help": case "-h": usage(0); + // Fall through default: if (args.length == 1) { // no flags specified, we do -sysprops and -flags diff --git a/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java b/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java index fdde301667e..b3493bc7d9a 100644 --- a/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java +++ b/jdk/src/share/classes/sun/tools/tree/AssignOpExpression.java @@ -53,7 +53,7 @@ class AssignOpExpression extends BinaryAssignExpression { * Select the type * */ - + @SuppressWarnings("fallthrough") final void selectType(Environment env, Context ctx, int tm) { Type rtype = null; // special conversion type for RHS switch(op) { diff --git a/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java b/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java index cb018a0f51a..0347c41efbf 100644 --- a/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java +++ b/jdk/src/share/classes/sun/tools/tree/NewInstanceExpression.java @@ -487,6 +487,7 @@ class NewInstanceExpression extends NaryExpression { public void codeValue(Environment env, Context ctx, Assembler asm) { codeCommon(env, ctx, asm, true); } + @SuppressWarnings("fallthrough") private void codeCommon(Environment env, Context ctx, Assembler asm, boolean forValue) { asm.add(where, opc_new, field.getClassDeclaration()); From c34e0869d0fc15286edd86ea5671b593c70dbd61 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Thu, 10 Apr 2014 20:01:52 +0100 Subject: [PATCH 157/170] 8038491: Improve synchronization in ZipFile.read() Reviewed-by: alanb, chegar --- .../share/classes/java/util/zip/ZipFile.java | 30 +++--- .../zip/ZipFile/MultiThreadedReadTest.java | 92 +++++++++++++++++++ 2 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.java diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java index 12aa0dcfaba..b101c33b04c 100644 --- a/jdk/src/share/classes/java/util/zip/ZipFile.java +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java @@ -700,24 +700,26 @@ class ZipFile implements ZipConstants, Closeable { } public int read(byte b[], int off, int len) throws IOException { - if (rem == 0) { - return -1; - } - if (len <= 0) { - return 0; - } - if (len > rem) { - len = (int) rem; - } synchronized (ZipFile.this) { - ensureOpenOrZipException(); + long rem = this.rem; + long pos = this.pos; + if (rem == 0) { + return -1; + } + if (len <= 0) { + return 0; + } + if (len > rem) { + len = (int) rem; + } + ensureOpenOrZipException(); len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b, off, len); - } - if (len > 0) { - pos += len; - rem -= len; + if (len > 0) { + this.pos = (pos + len); + this.rem = (rem - len); + } } if (rem == 0) { close(); diff --git a/jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.java b/jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.java new file mode 100644 index 00000000000..c1f69a90587 --- /dev/null +++ b/jdk/test/java/util/zip/ZipFile/MultiThreadedReadTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, 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 8038491 + * @summary Crash in ZipFile.read() when ZipFileInputStream is shared between threads + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils + * @run main MultiThreadedReadTest + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.Random; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; +import jdk.testlibrary.FileUtils; + +public class MultiThreadedReadTest extends Thread { + + private static final int NUM_THREADS = 10; + private static final String ZIPFILE_NAME = "large.zip"; + private static final String ZIPENTRY_NAME = "random.txt"; + private static InputStream is = null; + + public static void main(String args[]) throws Exception { + createZipFile(); + try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) { + is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME)); + Thread[] threadArray = new Thread[NUM_THREADS]; + for (int i = 0; i < threadArray.length; i++) { + threadArray[i] = new MultiThreadedReadTest(); + } + for (int i = 0; i < threadArray.length; i++) { + threadArray[i].start(); + } + for (int i = 0; i < threadArray.length; i++) { + threadArray[i].join(); + } + } finally { + FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME)); + } + } + + private static void createZipFile() throws Exception { + try (ZipOutputStream zos = + new ZipOutputStream(new FileOutputStream(ZIPFILE_NAME))) { + + zos.putNextEntry(new ZipEntry(ZIPENTRY_NAME)); + StringBuilder sb = new StringBuilder(); + Random rnd = new Random(); + for(int i = 0; i < 1000; i++) { + // append some random string for ZipEntry + sb.append(Long.toString(rnd.nextLong())); + } + byte[] b = sb.toString().getBytes(); + zos.write(b, 0, b.length); + } + } + + @Override + public void run() { + try { + while (is.read() != -1) { } + } catch (Exception e) { + // Swallow any Exceptions (which are expected) - we're only interested in the crash + } + } +} From a8ce9efc15a02fc3acb0f14b5a5738c7b221eb83 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 10 Apr 2014 13:19:29 -0700 Subject: [PATCH 158/170] 8039474: sun.misc.CharacterDecoder.decodeBuffer should use getBytes(iso8859-1) Specify ISO-8859-1 as charset of String to decode. Reviewed-by: chegar, sherman, mduigou, mchung --- jdk/src/share/classes/sun/misc/CharacterDecoder.java | 2 +- jdk/src/share/classes/sun/misc/CharacterEncoder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/sun/misc/CharacterDecoder.java b/jdk/src/share/classes/sun/misc/CharacterDecoder.java index 76329ec8e39..c076f46df28 100644 --- a/jdk/src/share/classes/sun/misc/CharacterDecoder.java +++ b/jdk/src/share/classes/sun/misc/CharacterDecoder.java @@ -184,7 +184,7 @@ public abstract class CharacterDecoder { * @exception CEFormatException An error has occurred while decoding */ public byte[] decodeBuffer(String inputString) throws IOException { - byte inputBuffer[] = inputString.getBytes(); + byte inputBuffer[] = inputString.getBytes("ISO-8859-1"); ByteArrayInputStream inStream = new ByteArrayInputStream(inputBuffer); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); decodeBuffer(inStream, outStream); diff --git a/jdk/src/share/classes/sun/misc/CharacterEncoder.java b/jdk/src/share/classes/sun/misc/CharacterEncoder.java index 70c5ff90a44..d152f954cf9 100644 --- a/jdk/src/share/classes/sun/misc/CharacterEncoder.java +++ b/jdk/src/share/classes/sun/misc/CharacterEncoder.java @@ -190,7 +190,7 @@ public abstract class CharacterEncoder { try { encode(inStream, outStream); // explicit ascii->unicode conversion - retVal = outStream.toString("8859_1"); + retVal = outStream.toString("ISO-8859-1"); } catch (Exception IOException) { // This should never happen. throw new Error("CharacterEncoder.encode internal error"); From 48815fa5120675d4a9f1a39f904a2d157fce26d1 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Thu, 10 Apr 2014 14:35:49 -0700 Subject: [PATCH 159/170] 8039411: Enhance fixpath to allow environment variable assignments Reviewed-by: tbell, erikj --- common/src/fixpath.c | 246 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 201 insertions(+), 45 deletions(-) diff --git a/common/src/fixpath.c b/common/src/fixpath.c index a85bf4cc68e..b30f58d6b51 100644 --- a/common/src/fixpath.c +++ b/common/src/fixpath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -29,7 +29,7 @@ #include #include -void report_error() +void report_error(char const * msg) { LPVOID lpMsgBuf; DWORD dw = GetLastError(); @@ -46,8 +46,8 @@ void report_error() NULL); fprintf(stderr, - "Could not start process! Failed with error %d: %s\n", - dw, lpMsgBuf); + "%s Failed with error %d: %s\n", + msg, dw, lpMsgBuf); LocalFree(lpMsgBuf); } @@ -56,7 +56,7 @@ void report_error() * Test if pos points to /cygdrive/_/ where _ can * be any character. */ -int is_cygdrive_here(int pos, char *in, int len) +int is_cygdrive_here(int pos, char const *in, int len) { // Length of /cygdrive/c/ is 12 if (pos+12 > len) return 0; @@ -81,16 +81,17 @@ int is_cygdrive_here(int pos, char *in, int len) * Works in place since drive letter is always * shorter than /cygdrive/ */ -char *replace_cygdrive_cygwin(char *in) +char *replace_cygdrive_cygwin(char const *in) { - int len = strlen(in); - char *out = malloc(len+1); + size_t len = strlen(in); + char *out = (char*) malloc(len+1); int i,j; if (len < 12) { - strcpy(out, in); + memmove(out, in, len + 1); return out; } + for (i = 0, j = 0; i *bl) { *bl *= 2; - *b = realloc(*b, *bl); + *b = (char*) realloc(*b, *bl); } memcpy(*b+*u, add, addlen); *u += addlen; @@ -125,7 +126,7 @@ char *replace_substring(char *in, char *sub, char *rep) int in_len = strlen(in); int sub_len = strlen(sub); int rep_len = strlen(rep); - char *out = malloc(in_len - sub_len + rep_len + 1); + char *out = (char *) malloc(in_len - sub_len + rep_len + 1); char *p; if (!(p = strstr(in, sub))) { @@ -145,7 +146,7 @@ char *replace_substring(char *in, char *sub, char *rep) char* msys_path_list; // @-separated list of paths prefix to look for char* msys_path_list_end; // Points to last \0 in msys_path_list. -void setup_msys_path_list(char* argument) +void setup_msys_path_list(char const * argument) { char* p; char* drive_letter_pos; @@ -173,7 +174,7 @@ void setup_msys_path_list(char* argument) } while (p != NULL); } -char *replace_cygdrive_msys(char *in) +char *replace_cygdrive_msys(char const *in) { char* str; char* prefix; @@ -195,12 +196,12 @@ char *replace_cygdrive_msys(char *in) return str; } -char*(*replace_cygdrive)(char *in) = NULL; +char*(*replace_cygdrive)(char const *in) = NULL; char *files_to_delete[1024]; int num_files_to_delete = 0; -char *fix_at_file(char *in) +char *fix_at_file(char const *in) { char *tmpdir; char name[2048]; @@ -222,9 +223,13 @@ char *fix_at_file(char *in) exit(-1); } - tmpdir = getenv("TMP"); + tmpdir = getenv("TEMP"); if (tmpdir == NULL) { +#if _WIN64 + tmpdir = "c:/cygwin64/tmp"; +#else tmpdir = "c:/cygwin/tmp"; +#endif } _snprintf(name, sizeof(name), "%s\\atfile_XXXXXX", tmpdir); @@ -240,7 +245,7 @@ char *fix_at_file(char *in) exit(-1); } - buffer = malloc(buflen); + buffer = (char*) malloc(buflen); while((blocklen = fread(block,1,sizeof(block),atin)) > 0) { append(&buffer, &buflen, &used, block, blocklen); } @@ -257,84 +262,229 @@ char *fix_at_file(char *in) fclose(atout); free(fixed); free(buffer); - files_to_delete[num_files_to_delete] = malloc(strlen(name)+1); + files_to_delete[num_files_to_delete] = (char*) malloc(strlen(name)+1); strcpy(files_to_delete[num_files_to_delete], name); num_files_to_delete++; - atname = malloc(strlen(name)+2); + atname = (char*) malloc(strlen(name)+2); atname[0] = '@'; strcpy(atname+1, name); return atname; } -int main(int argc, char **argv) +// given an argument, convert it to the windows command line safe quoted version +// using rules from: +// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx +// caller is responsible for freeing both input and output. +char * quote_arg(char const * in_arg) { + char *quoted = NULL; + char *current = quoted; + int pass; + + if(strpbrk(in_arg, " \t\n\v\r\\\"") == NULL) { + return _strdup(in_arg); + } + + // process the arg twice. Once to calculate the size and then to copy it. + for(pass=1; pass<=2; pass++) { + char const *arg = in_arg; + + // initial " + if(pass == 2) { + *current = '\"'; + } + current++; + + // process string to be quoted until NUL + do { + int escapes = 0; + + while (*arg == '\\') { + // count escapes. + escapes++; + arg++; + } + + if (*arg == '\0') { + // escape the escapes before final " + escapes *= 2; + } else if (*arg == '"') { + // escape the escapes and the " + escapes = escapes * 2 + 1; + } else { + // escapes aren't special, just echo them. + } + + // emit some escapes + while (escapes > 0) { + if (pass == 2) { + *current = '\\'; + } + current++; + escapes--; + } + + // and the current char + if (pass == 2) { + *current = *arg; + } + current++; + } while( *arg++ != '\0'); + + // allocate the buffer + if (pass == 1) { + size_t alloc = (size_t) (current - quoted + (ptrdiff_t) 2); + current = quoted = (char*) calloc(alloc, sizeof(char)); + } + } + + // final " and \0 + *(current - 1) = '"'; + *current = '\0'; + + return quoted; +} + +int main(int argc, char const ** argv) { STARTUPINFO si; PROCESS_INFORMATION pi; unsigned short rc; - char *new_at_file; - char *old_at_file; char *line; - int i; + char *current; + int i, cmd; DWORD exitCode; - if (argc<3 || argv[1][0] != '-' || (argv[1][1] != 'c' && argv[1][1] != 'm')) { - fprintf(stderr, "Usage: fixpath -c|m /cygdrive/c/WINDOWS/notepad.exe /cygdrive/c/x/test.txt\n"); + if (argc<2 || argv[1][0] != '-' || (argv[1][1] != 'c' && argv[1][1] != 'm')) { + fprintf(stderr, "Usage: fixpath -c|m /cygdrive/c/WINDOWS/notepad.exe [/cygdrive/c/x/test.txt|@/cygdrive/c/x/atfile]\n"); exit(0); } if (getenv("DEBUG_FIXPATH") != NULL) { - fprintf(stderr, "fixpath input line >%s<\n", strstr(GetCommandLine(), argv[1])); + char const * cmdline = GetCommandLine(); + fprintf(stderr, "fixpath input line >%s<\n", strstr( cmdline , argv[1])); } if (argv[1][1] == 'c' && argv[1][2] == '\0') { if (getenv("DEBUG_FIXPATH") != NULL) { - fprintf(stderr, "using cygwin mode\n"); + fprintf(stderr, "fixpath using cygwin mode\n"); } replace_cygdrive = replace_cygdrive_cygwin; } else if (argv[1][1] == 'm') { if (getenv("DEBUG_FIXPATH") != NULL) { - fprintf(stderr, "using msys mode, with path list: %s\n", &argv[1][2]); + fprintf(stderr, "fixpath using msys mode, with path list: %s\n", &argv[1][2]); } setup_msys_path_list(argv[1]); replace_cygdrive = replace_cygdrive_msys; } else { - fprintf(stderr, "Unknown mode: %s\n", argv[1]); + fprintf(stderr, "fixpath Unknown mode: %s\n", argv[1]); exit(-1); } - line = replace_cygdrive(strstr(GetCommandLine(), argv[2])); - for (i=1; i%s< to >%s<\n", var, val); + } + + rc = SetEnvironmentVariable(var, val); + if(!rc) { + // Could not set var for some reason. Try to report why. + const int msg_len = 80 + var_len + strlen(val); + char * msg = (char *) alloca(msg_len); + _snprintf_s(msg, msg_len, _TRUNCATE, "Could not set environment variable [%s=%s]", var, val); + report_error(msg); + exit(1); + } + free(var); + free(val); + } else { + // no more assignments; + break; + } + i++; } + // remember index of the command + cmd = i; + + // handle command and it's args. + while (i < argc) { + char const *replaced = replace_cygdrive(argv[i]); + if(replaced[0] == '@') { + // Found at-file! Fix it! + replaced = fix_at_file(replaced); + } + argv[i] = quote_arg(replaced); + i++; + } + + // determine the length of the line + line = NULL; + // args + for(i = cmd; i < argc; i++) { + line += (ptrdiff_t) strlen(argv[i]); + } + // spaces and null + line += (ptrdiff_t) (argc - cmd + 1); + // allocate + line = (char*) calloc(line - (char*) NULL, sizeof(char)); + + // copy in args. + current = line; + for(i = cmd; i < argc; i++) { + ptrdiff_t len = strlen(argv[i]); + if (i != cmd) { + *current++ = ' '; + } + memmove(current, argv[i], len); + current += len; + } + *current = '\0'; + if (getenv("DEBUG_FIXPATH") != NULL) { fprintf(stderr, "fixpath converted line >%s<\n", line); } + if(cmd == argc) { + if (getenv("DEBUG_FIXPATH") != NULL) { + fprintf(stderr, "fixpath no command provided!\n"); + } + exit(0); + } + ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); + fflush(stderr); + fflush(stdout); + rc = CreateProcess(NULL, line, 0, 0, TRUE, 0, - 0, - 0, + NULL, + NULL, &si, &pi); if(!rc) { // Could not start process for some reason. Try to report why: - report_error(); - exit(rc); + report_error("Could not start process!"); + exit(126); } WaitForSingleObject(pi.hProcess,INFINITE); @@ -342,15 +492,21 @@ int main(int argc, char **argv) if (getenv("DEBUG_FIXPATH") != NULL) { for (i=0; i Date: Fri, 11 Apr 2014 03:10:44 +0000 Subject: [PATCH 160/170] 8037557: test SessionCacheSizeTests.java timeout Reviewed-by: weijun --- .../ssl/SSLSession/SessionCacheSizeTests.java | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java b/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java index 4001f83ed47..ccb90c6c182 100644 --- a/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java +++ b/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, 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 @@ -28,7 +28,7 @@ /* * @test - * @bug 4366807 + * @bug 4366807 * @summary Need new APIs to get/set session timeout and session cache size. * @run main/othervm SessionCacheSizeTests */ @@ -110,6 +110,7 @@ public class SessionCacheSizeTests { SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); + sslServerSocket.setSoTimeout(45000); // timeout to accept a connection serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); /* @@ -128,16 +129,22 @@ public class SessionCacheSizeTests { SSLSession sessions [] = new SSLSession [serverConns]; SSLSessionContext sessCtx = sslctx.getServerSessionContext(); - while (nConnections < serverConns) { - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); - read = sslIS.read(); - sessions[nConnections] = sslSocket.getSession(); - sslOS.write(85); - sslOS.flush(); - sslSocket.close(); - nConnections++; + try { + while (nConnections < serverConns) { + try (SSLSocket sslSocket = + (SSLSocket)sslServerSocket.accept()) { + sslSocket.setSoTimeout(90000); // timeout to read + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); + read = sslIS.read(); + sessions[nConnections] = sslSocket.getSession(); + sslOS.write(85); + sslOS.flush(); + nConnections++; + } + } + } finally { + sslServerSocket.close(); } } From fa37e2a252518a9467fe90addf501d6c1a0d55e8 Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Fri, 11 Apr 2014 09:25:36 +0100 Subject: [PATCH 161/170] 8039899: Missing licence headers in test for JDK-8033113 Reviewed-by: chegar --- .../xml/ws/8033113/Organization_List.wsdl | 104 +++++++++++------- .../javax/xml/ws/8033113/customization.xml | 68 ++++++++---- 2 files changed, 108 insertions(+), 64 deletions(-) diff --git a/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl b/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl index ae19b565b72..df87852f240 100644 --- a/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl +++ b/jdk/test/javax/xml/ws/8033113/Organization_List.wsdl @@ -1,56 +1,78 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + @@ -65,13 +87,13 @@ - + - + - + diff --git a/jdk/test/javax/xml/ws/8033113/customization.xml b/jdk/test/javax/xml/ws/8033113/customization.xml index e754c4275c0..6f17e2f0a42 100644 --- a/jdk/test/javax/xml/ws/8033113/customization.xml +++ b/jdk/test/javax/xml/ws/8033113/customization.xml @@ -1,23 +1,45 @@ - - false - - - - - - - - + + + false + + + + + + + + From 598a814fc0e44dff7b3a56b7d8975fc48351a7bf Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Fri, 11 Apr 2014 09:35:03 +0100 Subject: [PATCH 162/170] 8039990: Add sequential operation support to hgforest Reviewed-by: mduigou --- common/bin/hgforest.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index aae55ea12a7..3ada41ee0cd 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -29,6 +29,7 @@ global_opts="" status_output="/dev/stdout" qflag="false" vflag="false" +sflag="false" while [ $# -gt 0 ] do case $1 in @@ -43,6 +44,10 @@ do global_opts="${global_opts} -v" ;; + -s | --sequential ) + sflag="true" + ;; + '--' ) # no more options shift; break ;; @@ -63,7 +68,7 @@ command="$1"; shift command_args="$@" usage() { - echo "usage: $0 [-q|--quiet] [-v|--verbose] [--] [commands...]" > ${status_output} + echo "usage: $0 [-q|--quiet] [-v|--verbose] [-s|--sequential] [--] [commands...]" > ${status_output} exit 1 } @@ -243,11 +248,15 @@ else ) 2>&1 | sed -e "s@^@${reponame}: @" > ${status_output} ) & - if [ `expr ${n} '%' ${at_a_time}` -eq 0 ] ; then + if [ `expr ${n} '%' ${at_a_time}` -eq 0 -a "${sflag}" = "false" ] ; then sleep 2 echo "Waiting 5 secs before spawning next background command." > ${status_output} sleep 3 fi + + if [ "${sflag}" = "true" ] ; then + wait + fi done fi From 9e71840a875c48657cebe70153619424e706a114 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 11 Apr 2014 13:12:11 -0700 Subject: [PATCH 163/170] 8035427: Math.random() JavaDoc: missing maximum returned value Add some documentation amplifying the description of Math.random(). Reviewed-by: psandoz --- jdk/src/share/classes/java/lang/Math.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/jdk/src/share/classes/java/lang/Math.java b/jdk/src/share/classes/java/lang/Math.java index 98e901ac942..4114076ed2d 100644 --- a/jdk/src/share/classes/java/lang/Math.java +++ b/jdk/src/share/classes/java/lang/Math.java @@ -765,8 +765,19 @@ public final class Math { * pseudorandom numbers at a great rate, it may reduce contention * for each thread to have its own pseudorandom-number generator. * + * @apiNote + * As the largest {@code double} value less than {@code 1.0} + * is {@code Math.nextDown(1.0)}, a value {@code x} in the closed range + * {@code [x1,x2]} where {@code x1<=x2} may be defined by the statements + * + *
{@code
+     * double f = Math.random()/Math.nextDown(1.0);
+     * double x = x1*(1.0 - f) + x2*f;
+     * }
+ * * @return a pseudorandom {@code double} greater than or equal * to {@code 0.0} and less than {@code 1.0}. + * @see #nextDown(double) * @see Random#nextDouble() */ public static double random() { From c78cb9b1c56a514a1ddc7229164526efddb55fd2 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Fri, 11 Apr 2014 14:07:25 -0700 Subject: [PATCH 164/170] 8035284: Remove redundant null initialization Reviewed-by: lancea, martin, chegar, shade --- .../share/classes/java/util/AbstractMap.java | 4 ++-- .../share/classes/java/util/Collections.java | 22 +++++++++---------- jdk/src/share/classes/java/util/EnumMap.java | 4 ++-- .../share/classes/java/util/Hashtable.java | 10 ++++----- .../classes/java/util/IdentityHashMap.java | 4 ++-- .../share/classes/java/util/LinkedList.java | 2 +- jdk/src/share/classes/java/util/TreeMap.java | 18 +++++++-------- .../share/classes/java/util/WeakHashMap.java | 10 ++++----- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/jdk/src/share/classes/java/util/AbstractMap.java b/jdk/src/share/classes/java/util/AbstractMap.java index a68a77b9870..143f228f904 100644 --- a/jdk/src/share/classes/java/util/AbstractMap.java +++ b/jdk/src/share/classes/java/util/AbstractMap.java @@ -305,8 +305,8 @@ public abstract class AbstractMap implements Map { * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. */ - transient volatile Set keySet = null; - transient volatile Collection values = null; + transient volatile Set keySet; + transient volatile Collection values; /** * {@inheritDoc} diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index c172c95f49b..e229f5f5dd4 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -1466,9 +1466,9 @@ public class Collections { throw new UnsupportedOperationException(); } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; public Set keySet() { if (keySet==null) @@ -2597,9 +2597,9 @@ public class Collections { synchronized (mutex) {m.clear();} } - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; public Set keySet() { synchronized (mutex) { @@ -3082,7 +3082,7 @@ public class Collections { return c.add(e); } - private E[] zeroLengthElementArray = null; // Lazily initialized + private E[] zeroLengthElementArray; // Lazily initialized private E[] zeroLengthElementArray() { return zeroLengthElementArray != null ? zeroLengthElementArray : @@ -3643,7 +3643,7 @@ public class Collections { m.put(e.getKey(), e.getValue()); } - private transient Set> entrySet = null; + private transient Set> entrySet; public Set> entrySet() { if (entrySet==null) @@ -4877,9 +4877,9 @@ public class Collections { public boolean containsValue(Object value) {return eq(value, v);} public V get(Object key) {return (eq(key, k) ? v : null);} - private transient Set keySet = null; - private transient Set> entrySet = null; - private transient Collection values = null; + private transient Set keySet; + private transient Set> entrySet; + private transient Collection values; public Set keySet() { if (keySet==null) diff --git a/jdk/src/share/classes/java/util/EnumMap.java b/jdk/src/share/classes/java/util/EnumMap.java index 21be62d8d0b..7357ee381f3 100644 --- a/jdk/src/share/classes/java/util/EnumMap.java +++ b/jdk/src/share/classes/java/util/EnumMap.java @@ -367,7 +367,7 @@ public class EnumMap, V> extends AbstractMap * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns a {@link Set} view of the keys contained in this map. @@ -562,7 +562,7 @@ public class EnumMap, V> extends AbstractMap } private class EntryIterator extends EnumMapIterator> { - private Entry lastReturnedEntry = null; + private Entry lastReturnedEntry; public Map.Entry next() { if (!hasNext()) diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java index ce706130070..4a89bd5816d 100644 --- a/jdk/src/share/classes/java/util/Hashtable.java +++ b/jdk/src/share/classes/java/util/Hashtable.java @@ -617,9 +617,9 @@ public class Hashtable * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. */ - private transient volatile Set keySet = null; - private transient volatile Set> entrySet = null; - private transient volatile Collection values = null; + private transient volatile Set keySet; + private transient volatile Set> entrySet; + private transient volatile Collection values; /** * Returns a {@link Set} view of the keys contained in this map. @@ -1300,8 +1300,8 @@ public class Hashtable private class Enumerator implements Enumeration, Iterator { Entry[] table = Hashtable.this.table; int index = table.length; - Entry entry = null; - Entry lastReturned = null; + Entry entry; + Entry lastReturned; int type; /** diff --git a/jdk/src/share/classes/java/util/IdentityHashMap.java b/jdk/src/share/classes/java/util/IdentityHashMap.java index 2b4f19d09b2..f96055bc6c1 100644 --- a/jdk/src/share/classes/java/util/IdentityHashMap.java +++ b/jdk/src/share/classes/java/util/IdentityHashMap.java @@ -842,7 +842,7 @@ public class IdentityHashMap private class EntryIterator extends IdentityHashMapIterator> { - private Entry lastReturnedEntry = null; + private Entry lastReturnedEntry; public Map.Entry next() { lastReturnedEntry = new Entry(nextIndex()); @@ -928,7 +928,7 @@ public class IdentityHashMap * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns an identity-based set view of the keys contained in this map. diff --git a/jdk/src/share/classes/java/util/LinkedList.java b/jdk/src/share/classes/java/util/LinkedList.java index 43ab9dfca2e..18a8b21ba80 100644 --- a/jdk/src/share/classes/java/util/LinkedList.java +++ b/jdk/src/share/classes/java/util/LinkedList.java @@ -869,7 +869,7 @@ public class LinkedList } private class ListItr implements ListIterator { - private Node lastReturned = null; + private Node lastReturned; private Node next; private int nextIndex; private int expectedModCount = modCount; diff --git a/jdk/src/share/classes/java/util/TreeMap.java b/jdk/src/share/classes/java/util/TreeMap.java index fda3e2a8e42..c04053656cf 100644 --- a/jdk/src/share/classes/java/util/TreeMap.java +++ b/jdk/src/share/classes/java/util/TreeMap.java @@ -120,7 +120,7 @@ public class TreeMap */ private final Comparator comparator; - private transient Entry root = null; + private transient Entry root; /** * The number of entries in the tree @@ -781,9 +781,9 @@ public class TreeMap * the first time this view is requested. Views are stateless, so * there's no reason to create more than one. */ - private transient EntrySet entrySet = null; - private transient KeySet navigableKeySet = null; - private transient NavigableMap descendingMap = null; + private transient EntrySet entrySet; + private transient KeySet navigableKeySet; + private transient NavigableMap descendingMap; /** * Returns a {@link Set} view of the keys contained in this map. @@ -1583,9 +1583,9 @@ public class TreeMap } // Views - transient NavigableMap descendingMapView = null; - transient EntrySetView entrySetView = null; - transient KeySet navigableKeySetView = null; + transient NavigableMap descendingMapView; + transient EntrySetView entrySetView; + transient KeySet navigableKeySetView; public final NavigableSet navigableKeySet() { KeySet nksv = navigableKeySetView; @@ -2046,8 +2046,8 @@ public class TreeMap static final class Entry implements Map.Entry { K key; V value; - Entry left = null; - Entry right = null; + Entry left; + Entry right; Entry parent; boolean color = BLACK; diff --git a/jdk/src/share/classes/java/util/WeakHashMap.java b/jdk/src/share/classes/java/util/WeakHashMap.java index 270c2d9c2bd..4dd8e99053d 100644 --- a/jdk/src/share/classes/java/util/WeakHashMap.java +++ b/jdk/src/share/classes/java/util/WeakHashMap.java @@ -759,21 +759,21 @@ public class WeakHashMap private abstract class HashIterator implements Iterator { private int index; - private Entry entry = null; - private Entry lastReturned = null; + private Entry entry; + private Entry lastReturned; private int expectedModCount = modCount; /** * Strong reference needed to avoid disappearance of key * between hasNext and next */ - private Object nextKey = null; + private Object nextKey; /** * Strong reference needed to avoid disappearance of key * between nextEntry() and any use of the entry */ - private Object currentKey = null; + private Object currentKey; HashIterator() { index = isEmpty() ? 0 : table.length; @@ -848,7 +848,7 @@ public class WeakHashMap // Views - private transient Set> entrySet = null; + private transient Set> entrySet; /** * Returns a {@link Set} view of the keys contained in this map. From 7a7a00379be6d049bd1ef96c36559e78a1201253 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 19:34:37 +0200 Subject: [PATCH 165/170] Added tag jdk9-b07 for changeset c826d05f1fb0 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 99b55cd1110..31681df35e7 100644 --- a/.hgtags +++ b/.hgtags @@ -249,3 +249,4 @@ b32e2219736e42baaf45daf0ad67ed34f6033799 jdk9-b02 099891b1d86f3719e116ac717ffdafc90d037fb7 jdk9-b04 dd311791ad6895a3989020dd6c6c46db87972ab8 jdk9-b05 85dbdc227c5e11429b4fc4a8ba763f50107edd6e jdk9-b06 +c826d05f1fb0773f6a28caa763307dd30d90d36e jdk9-b07 From e90c029bad0753dac37d2f750607d78d0e4ee722 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Sat, 12 Apr 2014 20:21:09 +0100 Subject: [PATCH 166/170] 8036979: Support java.net.SocketOption<> in java.net socket types Reviewed-by: alanb, chegar --- jdk/make/mapfiles/libnet/mapfile-vers | 4 + .../classes/java/net/DatagramSocket.java | 93 +++++ .../classes/java/net/DatagramSocketImpl.java | 128 +++++++ .../share/classes/java/net/ServerSocket.java | 90 +++++ jdk/src/share/classes/java/net/Socket.java | 91 +++++ .../share/classes/java/net/SocketImpl.java | 105 ++++++ .../jdk/net/ExtendedSocketOptions.java | 62 ++++ .../classes/jdk/net/NetworkPermission.java | 93 +++++ jdk/src/share/classes/jdk/net/SocketFlow.java | 169 +++++++++ jdk/src/share/classes/jdk/net/Sockets.java | 311 ++++++++++++++++ .../share/classes/jdk/net/package-info.java | 34 ++ .../classes/sun/net/ExtendedOptionsImpl.java | 92 +++++ .../nio/ch/AsynchronousSocketChannelImpl.java | 4 + .../sun/nio/ch/DatagramChannelImpl.java | 4 + jdk/src/share/classes/sun/nio/ch/Net.java | 22 ++ .../classes/sun/nio/ch/SocketChannelImpl.java | 4 + jdk/src/share/native/java/net/net_util.h | 2 +- .../java/net/PlainDatagramSocketImpl.java | 41 +++ .../classes/java/net/PlainSocketImpl.java | 43 ++- .../native/java/net/ExtendedOptionsImpl.c | 337 ++++++++++++++++++ jdk/src/solaris/native/java/net/net_util_md.h | 41 +++ .../native/java/net/ExtendedOptionsImpl.c | 65 ++++ jdk/test/TEST.groups | 11 +- .../java/net/SocketOption/OptionsTest.java | 244 +++++++++++++ jdk/test/jdk/net/Sockets/Test.java | 130 +++++++ jdk/test/jdk/net/Sockets/policy.fail | 4 + jdk/test/jdk/net/Sockets/policy.success | 6 + 27 files changed, 2223 insertions(+), 7 deletions(-) create mode 100644 jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java create mode 100644 jdk/src/share/classes/jdk/net/NetworkPermission.java create mode 100644 jdk/src/share/classes/jdk/net/SocketFlow.java create mode 100644 jdk/src/share/classes/jdk/net/Sockets.java create mode 100644 jdk/src/share/classes/jdk/net/package-info.java create mode 100644 jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java create mode 100644 jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c create mode 100644 jdk/src/windows/native/java/net/ExtendedOptionsImpl.c create mode 100644 jdk/test/java/net/SocketOption/OptionsTest.java create mode 100644 jdk/test/jdk/net/Sockets/Test.java create mode 100644 jdk/test/jdk/net/Sockets/policy.fail create mode 100644 jdk/test/jdk/net/Sockets/policy.success diff --git a/jdk/make/mapfiles/libnet/mapfile-vers b/jdk/make/mapfiles/libnet/mapfile-vers index 879fff4a850..ab621a923a8 100644 --- a/jdk/make/mapfiles/libnet/mapfile-vers +++ b/jdk/make/mapfiles/libnet/mapfile-vers @@ -94,6 +94,10 @@ SUNWprivate_1.1 { Java_sun_net_sdp_SdpSupport_create0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; + Java_sun_net_ExtendedOptionsImpl_init; + Java_sun_net_ExtendedOptionsImpl_setFlowOption; + Java_sun_net_ExtendedOptionsImpl_getFlowOption; + Java_sun_net_ExtendedOptionsImpl_flowSupported; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/jdk/src/share/classes/java/net/DatagramSocket.java b/jdk/src/share/classes/java/net/DatagramSocket.java index 31344b4391c..99565bb7aea 100644 --- a/jdk/src/share/classes/java/net/DatagramSocket.java +++ b/jdk/src/share/classes/java/net/DatagramSocket.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.nio.channels.DatagramChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; +import java.util.Set; +import java.util.Collections; /** * This class represents a socket for sending and receiving datagram packets. @@ -315,6 +317,7 @@ class DatagramSocket implements java.io.Closeable { } // creates a udp socket impl.create(); + impl.setDatagramSocket(this); created = true; } @@ -1258,4 +1261,94 @@ class DatagramSocket implements java.io.Closeable { } factory = fac; } + + /** + * Sets the value of a socket option. + * + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @return this DatagramSocket + * + * @throws UnsupportedOperationException if the datagram socket + * does not support the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @throws NullPointerException if name is {@code null} + * + * @since 1.9 + */ + public DatagramSocket setOption(SocketOption name, T value) + throws IOException + { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the datagram socket + * does not support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's DatagramSocketImpl cannot be created. + * + * @since 1.9 + */ + public Set> supportedOptions() { + synchronized(DatagramSocket.class) { + if (optionsSet) { + return options; + } + try { + DatagramSocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jdk/src/share/classes/java/net/DatagramSocketImpl.java b/jdk/src/share/classes/java/net/DatagramSocketImpl.java index 524f06b83ca..07b2724a2c7 100644 --- a/jdk/src/share/classes/java/net/DatagramSocketImpl.java +++ b/jdk/src/share/classes/java/net/DatagramSocketImpl.java @@ -28,6 +28,8 @@ package java.net; import java.io.FileDescriptor; import java.io.IOException; import java.io.InterruptedIOException; +import java.util.Set; +import java.util.HashSet; /** * Abstract datagram and multicast socket implementation base class. @@ -47,6 +49,20 @@ public abstract class DatagramSocketImpl implements SocketOptions { */ protected FileDescriptor fd; + /** + * The DatagramSocket or MulticastSocket + * that owns this impl + */ + DatagramSocket socket; + + void setDatagramSocket(DatagramSocket socket) { + this.socket = socket; + } + + DatagramSocket getDatagramSocket() { + return socket; + } + /** * Creates a datagram socket. * @exception SocketException if there is an error in the @@ -241,4 +257,116 @@ public abstract class DatagramSocketImpl implements SocketOptions { protected FileDescriptor getFileDescriptor() { return fd; } + + /** + * Called to set a socket option. + * + * @param name The socket option + * + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @throws UnsupportedOperationException if the DatagramSocketImpl does not + * support the option + * + * @throws NullPointerException if name is {@code null} + * + * @since 1.9 + */ + protected void setOption(SocketOption name, T value) throws IOException { + if (name == StandardSocketOptions.SO_SNDBUF) { + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.IP_TOS) { + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF && + (getDatagramSocket() instanceof MulticastSocket)) { + setOption(SocketOptions.IP_MULTICAST_IF2, value); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && + (getDatagramSocket() instanceof MulticastSocket)) { + if (! (value instanceof Integer)) { + throw new IllegalArgumentException("not an integer"); + } + setTimeToLive((Integer)value); + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && + (getDatagramSocket() instanceof MulticastSocket)) { + setOption(SocketOptions.IP_MULTICAST_LOOP, value); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + /** + * Called to get a socket option. + * + * @param name The socket option + * + * @throws UnsupportedOperationException if the DatagramSocketImpl does not + * support the option + * + * @throws NullPointerException if name is {@code null} + * + * @since 1.9 + */ + protected T getOption(SocketOption name) throws IOException { + if (name == StandardSocketOptions.SO_SNDBUF) { + return (T) getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T) getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T) getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T) getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.IP_MULTICAST_IF && + (getDatagramSocket() instanceof MulticastSocket)) { + return (T) getOption(SocketOptions.IP_MULTICAST_IF2); + } else if (name == StandardSocketOptions.IP_MULTICAST_TTL && + (getDatagramSocket() instanceof MulticastSocket)) { + Integer ttl = getTimeToLive(); + return (T)ttl; + } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP && + (getDatagramSocket() instanceof MulticastSocket)) { + return (T) getOption(SocketOptions.IP_MULTICAST_LOOP); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + private static final Set> dgSocketOptions = + new HashSet<>(); + + private static final Set> mcSocketOptions = + new HashSet<>(); + + static { + dgSocketOptions.add(StandardSocketOptions.SO_SNDBUF); + dgSocketOptions.add(StandardSocketOptions.SO_RCVBUF); + dgSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); + dgSocketOptions.add(StandardSocketOptions.IP_TOS); + + mcSocketOptions.add(StandardSocketOptions.SO_SNDBUF); + mcSocketOptions.add(StandardSocketOptions.SO_RCVBUF); + mcSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); + mcSocketOptions.add(StandardSocketOptions.IP_TOS); + mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_IF); + mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL); + mcSocketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP); + }; + + /** + * Returns a set of SocketOptions supported by this impl + * and by this impl's socket (DatagramSocket or MulticastSocket) + * + * @return a Set of SocketOptions + */ + protected Set> supportedOptions() { + if (getDatagramSocket() instanceof MulticastSocket) { + return mcSocketOptions; + } else { + return dgSocketOptions; + } + } } diff --git a/jdk/src/share/classes/java/net/ServerSocket.java b/jdk/src/share/classes/java/net/ServerSocket.java index e94790dd620..e60719eeb5a 100644 --- a/jdk/src/share/classes/java/net/ServerSocket.java +++ b/jdk/src/share/classes/java/net/ServerSocket.java @@ -30,6 +30,8 @@ import java.io.IOException; import java.nio.channels.ServerSocketChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; +import java.util.Set; +import java.util.Collections; /** * This class implements server sockets. A server socket waits for @@ -919,4 +921,92 @@ class ServerSocket implements java.io.Closeable { /* Not implemented yet */ } + /** + * Sets the value of a socket option. + * + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * @return this ServerSocket + * + * @throws UnsupportedOperationException if the server socket does not + * support the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public ServerSocket setOption(SocketOption name, T value) + throws IOException + { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the server socket does not + * support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this server socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's SocketImpl cannot be created. + * + * @since 1.9 + */ + public Set> supportedOptions() { + synchronized (ServerSocket.class) { + if (optionsSet) { + return options; + } + try { + SocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jdk/src/share/classes/java/net/Socket.java b/jdk/src/share/classes/java/net/Socket.java index b6df988d14b..d4b7656ce5e 100644 --- a/jdk/src/share/classes/java/net/Socket.java +++ b/jdk/src/share/classes/java/net/Socket.java @@ -32,6 +32,8 @@ import java.nio.channels.SocketChannel; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedAction; +import java.util.Set; +import java.util.Collections; /** * This class implements client sockets (also called just @@ -1720,4 +1722,93 @@ class Socket implements java.io.Closeable { { /* Not implemented yet */ } + + + /** + * Sets the value of a socket option. + * + * @param name The socket option + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * @return this Socket + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + public Socket setOption(SocketOption name, T value) throws IOException { + getImpl().setOption(name, value); + return this; + } + + /** + * Returns the value of a socket option. + * + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @throws NullPointerException if name is {@code null} + * + * @throws SecurityException if a security manager is set and if the socket + * option requires a security permission and if the caller does + * not have the required permission. + * {@link java.net.StandardSocketOptions StandardSocketOptions} + * do not require any security permission. + * + * @since 1.9 + */ + @SuppressWarnings("unchecked") + public T getOption(SocketOption name) throws IOException { + return getImpl().getOption(name); + } + + private static Set> options; + private static boolean optionsSet = false; + + /** + * Returns a set of the socket options supported by this socket. + * + * This method will continue to return the set of options even after + * the socket has been closed. + * + * @return A set of the socket options supported by this socket. This set + * may be empty if the socket's SocketImpl cannot be created. + * + * @since 1.9 + */ + public Set> supportedOptions() { + synchronized (Socket.class) { + if (optionsSet) { + return options; + } + try { + SocketImpl impl = getImpl(); + options = Collections.unmodifiableSet(impl.supportedOptions()); + } catch (IOException e) { + options = Collections.emptySet(); + } + optionsSet = true; + return options; + } + } } diff --git a/jdk/src/share/classes/java/net/SocketImpl.java b/jdk/src/share/classes/java/net/SocketImpl.java index 67286a1cd60..4aadf09182d 100644 --- a/jdk/src/share/classes/java/net/SocketImpl.java +++ b/jdk/src/share/classes/java/net/SocketImpl.java @@ -29,6 +29,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.FileDescriptor; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; /** * The abstract class {@code SocketImpl} is a common superclass @@ -355,4 +358,106 @@ public abstract class SocketImpl implements SocketOptions { { /* Not implemented yet */ } + + /** + * Called to set a socket option. + * + * @param name The socket option + * + * @param value The value of the socket option. A value of {@code null} + * may be valid for some options. + * + * @throws UnsupportedOperationException if the SocketImpl does not + * support the option + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @since 1.9 + */ + protected void setOption(SocketOption name, T value) throws IOException { + if (name == StandardSocketOptions.SO_KEEPALIVE) { + setOption(SocketOptions.SO_KEEPALIVE, value); + } else if (name == StandardSocketOptions.SO_SNDBUF) { + setOption(SocketOptions.SO_SNDBUF, value); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + setOption(SocketOptions.SO_RCVBUF, value); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_LINGER) { + setOption(SocketOptions.SO_LINGER, value); + } else if (name == StandardSocketOptions.IP_TOS) { + setOption(SocketOptions.IP_TOS, value); + } else if (name == StandardSocketOptions.TCP_NODELAY) { + setOption(SocketOptions.TCP_NODELAY, value); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + /** + * Called to get a socket option. + * + * @param name The socket option + * + * @return the value of the named option + * + * @throws UnsupportedOperationException if the SocketImpl does not + * support the option. + * + * @throws IOException if an I/O error occurs, or if the socket is closed. + * + * @since 1.9 + */ + protected T getOption(SocketOption name) throws IOException { + if (name == StandardSocketOptions.SO_KEEPALIVE) { + return (T)getOption(SocketOptions.SO_KEEPALIVE); + } else if (name == StandardSocketOptions.SO_SNDBUF) { + return (T)getOption(SocketOptions.SO_SNDBUF); + } else if (name == StandardSocketOptions.SO_RCVBUF) { + return (T)getOption(SocketOptions.SO_RCVBUF); + } else if (name == StandardSocketOptions.SO_REUSEADDR) { + return (T)getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_LINGER) { + return (T)getOption(SocketOptions.SO_LINGER); + } else if (name == StandardSocketOptions.IP_TOS) { + return (T)getOption(SocketOptions.IP_TOS); + } else if (name == StandardSocketOptions.TCP_NODELAY) { + return (T)getOption(SocketOptions.TCP_NODELAY); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } + + private static final Set> socketOptions = + new HashSet<>(); + + private static final Set> serverSocketOptions = + new HashSet<>(); + + static { + socketOptions.add(StandardSocketOptions.SO_KEEPALIVE); + socketOptions.add(StandardSocketOptions.SO_SNDBUF); + socketOptions.add(StandardSocketOptions.SO_RCVBUF); + socketOptions.add(StandardSocketOptions.SO_REUSEADDR); + socketOptions.add(StandardSocketOptions.SO_LINGER); + socketOptions.add(StandardSocketOptions.IP_TOS); + socketOptions.add(StandardSocketOptions.TCP_NODELAY); + + serverSocketOptions.add(StandardSocketOptions.SO_RCVBUF); + serverSocketOptions.add(StandardSocketOptions.SO_REUSEADDR); + }; + + /** + * Returns a set of SocketOptions supported by this impl + * and by this impl's socket (Socket or ServerSocket) + * + * @return a Set of SocketOptions + */ + protected Set> supportedOptions() { + if (getSocket() != null) { + return socketOptions; + } else { + return serverSocketOptions; + } + } } diff --git a/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java new file mode 100644 index 00000000000..8be1fe6a5dc --- /dev/null +++ b/jdk/src/share/classes/jdk/net/ExtendedSocketOptions.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 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. + */ + +package jdk.net; + +import java.net.SocketOption; + +/** + * Defines extended socket options, beyond those defined in + * {@link java.net.StandardSocketOptions}. These options may be platform + * specific. + * + * @since 1.9 + */ +@jdk.Exported +public final class ExtendedSocketOptions { + + private static class ExtSocketOption implements SocketOption { + private final String name; + private final Class type; + ExtSocketOption(String name, Class type) { + this.name = name; + this.type = type; + } + @Override public String name() { return name; } + @Override public Class type() { return type; } + @Override public String toString() { return name; } + } + + private ExtendedSocketOptions() {} + + /** + * Service level properties. When a security manager is installed, + * setting or getting this option requires a {@link NetworkPermission} + * {@code ("setOption.SO_FLOW_SLA")} or {@code "getOption.SO_FLOW_SLA"} + * respectively. + */ + public static final SocketOption SO_FLOW_SLA = new + ExtSocketOption("SO_FLOW_SLA", SocketFlow.class); +} diff --git a/jdk/src/share/classes/jdk/net/NetworkPermission.java b/jdk/src/share/classes/jdk/net/NetworkPermission.java new file mode 100644 index 00000000000..0e853f0d527 --- /dev/null +++ b/jdk/src/share/classes/jdk/net/NetworkPermission.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, 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. + */ + +package jdk.net; + +import java.security.BasicPermission; + +/** + * Represents permission to access the extended networking capabilities + * defined in the jdk.net package. These permissions contain a target + * name, but no actions list. Callers either possess the permission or not. + *

+ * The following targets are defined: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Permission Target NameWhat the Permission AllowsRisks of Allowing this Permission
setOption.SO_FLOW_SLAset the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} option + * on any socket that supports itallows caller to set a higher priority or bandwidth allocation + * to sockets it creates, than they might otherwise be allowed.
getOption.SO_FLOW_SLAretrieve the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} + * setting from any socket that supports the optionallows caller access to SLA information that it might not + * otherwise have
+ * + * @see jdk.net.ExtendedSocketOptions + * + * @since 1.9 + */ + +@jdk.Exported +public final class NetworkPermission extends BasicPermission { + + private static final long serialVersionUID = -2012939586906722291L; + + /** + * Creates a NetworkPermission with the given target name. + * + * @param name the permission target name + * @throws NullPointerException if {@code name} is {@code null}. + * @throws IllegalArgumentException if {@code name} is empty. + */ + public NetworkPermission(String name) + { + super(name); + } + + /** + * Creates a NetworkPermission with the given target name. + * + * @param name the permission target name + * @param actions should be {@code null}. Is ignored if not. + * @throws NullPointerException if {@code name} is {@code null}. + * @throws IllegalArgumentException if {@code name} is empty. + */ + public NetworkPermission(String name, String actions) + { + super(name, actions); + } +} diff --git a/jdk/src/share/classes/jdk/net/SocketFlow.java b/jdk/src/share/classes/jdk/net/SocketFlow.java new file mode 100644 index 00000000000..a102a3f35a0 --- /dev/null +++ b/jdk/src/share/classes/jdk/net/SocketFlow.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2014, 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. + */ + +package jdk.net; + +import java.lang.annotation.Native; + +/** + * Represents the service level properties for the platform specific socket + * option {@link ExtendedSocketOptions#SO_FLOW_SLA}. + *

+ * The priority and bandwidth parameters must be set before + * setting the socket option. + *

+ * When the {@code SO_FLOW_SLA} option is set then it may not take effect + * immediately. If the value of the socket option is obtained with + * {@code getOption()} then the status may be returned as {@code INPROGRESS} + * until it takes effect. The priority and bandwidth values are only valid when + * the status is returned as OK. + *

+ * When a security manager is installed, a {@link NetworkPermission} + * is required to set or get this option. + * + * @since 1.9 + */ +@jdk.Exported +public class SocketFlow { + + private static final int UNSET = -1; + @Native public static final int NORMAL_PRIORITY = 1; + @Native public static final int HIGH_PRIORITY = 2; + + private int priority = NORMAL_PRIORITY; + + private long bandwidth = UNSET; + + private Status status = Status.NO_STATUS; + + private SocketFlow() {} + + /** + * Enumeration of the return values from the SO_FLOW_SLA + * socket option. Both setting and getting the option return + * one of these statuses, which reflect the state of socket's + * flow. + * + * @since 1.9 + */ + @jdk.Exported + public enum Status { + /** + * Set or get socket option has not been called yet. Status + * values can only be retrieved after calling set or get. + */ + NO_STATUS, + /** + * Flow successfully created. + */ + OK, + /** + * Caller has no permission to create flow. + */ + NO_PERMISSION, + /** + * Flow can not be created because socket is not connected. + */ + NOT_CONNECTED, + /** + * Flow creation not supported for this socket. + */ + NOT_SUPPORTED, + /** + * A flow already exists with identical attributes. + */ + ALREADY_CREATED, + /** + * A flow is being created. + */ + IN_PROGRESS, + /** + * Some other unspecified error. + */ + OTHER + } + + /** + * Creates a new SocketFlow that can be used to set the SO_FLOW_SLA + * socket option and create a socket flow. + */ + public static SocketFlow create() { + return new SocketFlow(); + } + + /** + * Sets this SocketFlow's priority. Must be either NORMAL_PRIORITY + * HIGH_PRIORITY. If not set, a flow's priority is normal. + * + * @throws IllegalArgumentException if priority is not NORMAL_PRIORITY or + * HIGH_PRIORITY. + */ + public SocketFlow priority(int priority) { + if (priority != NORMAL_PRIORITY && priority != HIGH_PRIORITY) { + throw new IllegalArgumentException("invalid priority"); + } + this.priority = priority; + return this; + } + + /** + * Sets this SocketFlow's bandwidth. Must be greater than or equal to zero. + * A value of zero drops all packets for the socket. + * + * @throws IllegalArgumentException if bandwidth is less than zero. + */ + public SocketFlow bandwidth(long bandwidth) { + if (bandwidth < 0) { + throw new IllegalArgumentException("invalid bandwidth"); + } else { + this.bandwidth = bandwidth; + } + return this; + } + + /** + * Returns this SocketFlow's priority. + */ + public int priority() { + return priority; + } + + /** + * Returns this SocketFlow's bandwidth. + * + * @return this SocketFlow's bandwidth, or {@code -1} if status is not OK. + */ + public long bandwidth() { + return bandwidth; + } + + /** + * Returns the Status value of this SocketFlow. NO_STATUS is returned + * if the object was not used in a call to set or get the option. + */ + public Status status() { + return status; + } +} diff --git a/jdk/src/share/classes/jdk/net/Sockets.java b/jdk/src/share/classes/jdk/net/Sockets.java new file mode 100644 index 00000000000..9f7d94a0323 --- /dev/null +++ b/jdk/src/share/classes/jdk/net/Sockets.java @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2014, 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. + */ + +package jdk.net; + +import java.net.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.lang.reflect.Field; +import java.util.Set; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Collections; +import sun.net.ExtendedOptionsImpl; + +/** + * Defines static methods to set and get socket options defined by the + * {@link java.net.SocketOption} interface. All of the standard options defined + * by {@link java.net.Socket}, {@link java.net.ServerSocket}, and + * {@link java.net.DatagramSocket} can be set this way, as well as additional + * or platform specific options supported by each socket type. + *

+ * The {@link #supportedOptions(Class)} method can be called to determine + * the complete set of options available (per socket type) on the + * current system. + *

+ * When a security manager is installed, some non-standard socket options + * may require a security permission before being set or get. + * The details are specified in {@link ExtendedSocketOptions}. No permission + * is required for {@link java.net.StandardSocketOption}s. + * + * @see java.nio.channels.NetworkChannel + */ +@jdk.Exported +public class Sockets { + + private final static HashMap,Set>> + options = new HashMap<>(); + + static { + initOptionSets(); + } + + private Sockets() {} + + /** + * Sets the value of a socket option on a {@link java.net.Socket} + * + * @param s the socket + * @param name The socket option + * @param value The value of the socket option. May be null for some + * options. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs, or socket is closed. + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @throws NullPointerException if name is null + * + * @see java.net.StandardSocketOptions + */ + public static void setOption(Socket s, SocketOption name, T value) throws IOException + { + s.setOption(name, value); + } + + /** + * Returns the value of a socket option from a {@link java.net.Socket} + * + * @param s the socket + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @throws NullPointerException if name is null + * + * @see java.net.StandardSocketOptions + */ + public static T getOption(Socket s, SocketOption name) throws IOException + { + return s.getOption(name); + } + + /** + * Sets the value of a socket option on a {@link java.net.ServerSocket} + * + * @param s the socket + * @param name The socket option + * @param value The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static void setOption(ServerSocket s, SocketOption name, T value) throws IOException + { + s.setOption(name, value); + } + + /** + * Returns the value of a socket option from a {@link java.net.ServerSocket} + * + * @param s the socket + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static T getOption(ServerSocket s, SocketOption name) throws IOException + { + return s.getOption(name); + } + + /** + * Sets the value of a socket option on a {@link java.net.DatagramSocket} + * or {@link java.net.MulticastSocket} + * + * @param s the socket + * @param name The socket option + * @param value The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IllegalArgumentException if the value is not valid for + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static void setOption(DatagramSocket s, SocketOption name, T value) throws IOException + { + s.setOption(name, value); + } + + /** + * Returns the value of a socket option from a + * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket} + * + * @param s the socket + * @param name The socket option + * + * @return The value of the socket option. + * + * @throws UnsupportedOperationException if the socket does not support + * the option. + * + * @throws IOException if an I/O error occurs + * + * @throws NullPointerException if name is null + * + * @throws SecurityException if a security manager is set and the + * caller does not have any required permission. + * + * @see java.net.StandardSocketOptions + */ + public static T getOption(DatagramSocket s, SocketOption name) throws IOException + { + return s.getOption(name); + } + + /** + * Returns a set of {@link java.net.SocketOption}s supported by the + * given socket type. This set may include standard options and also + * non standard extended options. + * + * @param socketType the type of java.net socket + * + * @throws IllegalArgumentException if socketType is not a valid + * socket type from the java.net package. + */ + public static Set> supportedOptions(Class socketType) { + Set> set = options.get(socketType); + if (set == null) { + throw new IllegalArgumentException("unknown socket type"); + } + return set; + } + + private static void checkValueType(Object value, Class type) { + if (!type.isAssignableFrom(value.getClass())) { + String s = "Found: " + value.getClass().toString() + " Expected: " + + type.toString(); + throw new IllegalArgumentException(s); + } + } + + private static void initOptionSets() { + boolean flowsupported = ExtendedOptionsImpl.flowSupported(); + + // Socket + + Set> set = new HashSet<>(); + set.add(StandardSocketOptions.SO_KEEPALIVE); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.SO_LINGER); + set.add(StandardSocketOptions.IP_TOS); + set.add(StandardSocketOptions.TCP_NODELAY); + if (flowsupported) { + set.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + set = Collections.unmodifiableSet(set); + options.put(Socket.class, set); + + // ServerSocket + + set = new HashSet<>(); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set = Collections.unmodifiableSet(set); + options.put(ServerSocket.class, set); + + // DatagramSocket + + set = new HashSet<>(); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.IP_TOS); + if (flowsupported) { + set.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + set = Collections.unmodifiableSet(set); + options.put(DatagramSocket.class, set); + + // MulticastSocket + + set = new HashSet<>(); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); + set.add(StandardSocketOptions.IP_TOS); + set.add(StandardSocketOptions.IP_MULTICAST_IF); + set.add(StandardSocketOptions.IP_MULTICAST_TTL); + set.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (flowsupported) { + set.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + set = Collections.unmodifiableSet(set); + options.put(MulticastSocket.class, set); + } +} diff --git a/jdk/src/share/classes/jdk/net/package-info.java b/jdk/src/share/classes/jdk/net/package-info.java new file mode 100644 index 00000000000..236d640dbfa --- /dev/null +++ b/jdk/src/share/classes/jdk/net/package-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * Platform specific socket options for the {@code java.net} and {@code java.nio.channels} + * socket classes. + * + * @since 1.9 + */ + +@jdk.Exported +package jdk.net; diff --git a/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java new file mode 100644 index 00000000000..8fbcdd7b49d --- /dev/null +++ b/jdk/src/share/classes/sun/net/ExtendedOptionsImpl.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, 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. + */ + +package sun.net; + +import java.net.*; +import jdk.net.*; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.lang.reflect.Field; +import java.util.Set; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Collections; + +/** + * Contains the native implementation for extended socket options + * together with some other static utilities + */ +public class ExtendedOptionsImpl { + + static { + AccessController.doPrivileged((PrivilegedAction)() -> { + System.loadLibrary("net"); + return null; + }); + init(); + } + + private ExtendedOptionsImpl() {} + + public static void checkSetOptionPermission(SocketOption option) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return; + } + String check = "setOption." + option.name(); + sm.checkPermission(new NetworkPermission(check)); + } + + public static void checkGetOptionPermission(SocketOption option) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return; + } + String check = "getOption." + option.name(); + sm.checkPermission(new NetworkPermission(check)); + } + + public static void checkValueType(Object value, Class type) { + if (!type.isAssignableFrom(value.getClass())) { + String s = "Found: " + value.getClass().toString() + " Expected: " + + type.toString(); + throw new IllegalArgumentException(s); + } + } + + private static native void init(); + + /* + * Extension native implementations + * + * SO_FLOW_SLA + */ + public static native void setFlowOption(FileDescriptor fd, SocketFlow f); + public static native void getFlowOption(FileDescriptor fd, SocketFlow f); + public static native boolean flowSupported(); +} diff --git a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java index d28bf90b83f..9899d759b71 100644 --- a/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.concurrent.*; import java.util.concurrent.locks.*; import sun.net.NetHooks; +import sun.net.ExtendedOptionsImpl; /** * Base implementation of AsynchronousSocketChannel @@ -508,6 +509,9 @@ abstract class AsynchronousSocketChannelImpl set.add(StandardSocketOptions.SO_KEEPALIVE); set.add(StandardSocketOptions.SO_REUSEADDR); set.add(StandardSocketOptions.TCP_NODELAY); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index c151afe570b..fe32f63880b 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -33,6 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.ResourceManager; +import sun.net.ExtendedOptionsImpl; /** * An implementation of DatagramChannels. @@ -317,6 +318,9 @@ class DatagramChannelImpl set.add(StandardSocketOptions.IP_MULTICAST_IF); set.add(StandardSocketOptions.IP_MULTICAST_TTL); set.add(StandardSocketOptions.IP_MULTICAST_LOOP); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java index 79ebb2f36a5..753e5417310 100644 --- a/jdk/src/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/share/classes/sun/nio/ch/Net.java @@ -27,11 +27,13 @@ package sun.nio.ch; import java.io.*; import java.net.*; +import jdk.net.*; import java.nio.channels.*; import java.util.*; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; +import sun.net.ExtendedOptionsImpl; public class Net { @@ -297,6 +299,16 @@ public class Net { // only simple values supported by this method Class type = name.type(); + + if (type == SocketFlow.class) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA")); + } + ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value); + return; + } + if (type != Integer.class && type != Boolean.class) throw new AssertionError("Should not reach here"); @@ -349,6 +361,16 @@ public class Net { { Class type = name.type(); + if (type == SocketFlow.class) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA")); + } + SocketFlow flow = SocketFlow.create(); + ExtendedOptionsImpl.getFlowOption(fd, flow); + return flow; + } + // only simple values supported by this method if (type != Integer.class && type != Boolean.class) throw new AssertionError("Should not reach here"); diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index a977ced312b..1e36aed74d0 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -33,6 +33,7 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; import sun.net.NetHooks; +import sun.net.ExtendedOptionsImpl; /** @@ -237,6 +238,9 @@ class SocketChannelImpl // additional options required by socket adaptor set.add(StandardSocketOptions.IP_TOS); set.add(ExtendedSocketOption.SO_OOBINLINE); + if (ExtendedOptionsImpl.flowSupported()) { + set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/share/native/java/net/net_util.h b/jdk/src/share/native/java/net/net_util.h index a31d849e0b9..43739a2c498 100644 --- a/jdk/src/share/native/java/net/net_util.h +++ b/jdk/src/share/native/java/net/net_util.h @@ -40,7 +40,7 @@ #define IPv6 2 #define NET_ERROR(env, ex, msg) \ -{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg) } +{ if (!(*env)->ExceptionOccurred(env)) JNU_ThrowByName(env, ex, msg); } /************************************************************************ * Cached field IDs diff --git a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java index 20bc6fbc394..1779cfb0663 100644 --- a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java +++ b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java @@ -25,6 +25,11 @@ package java.net; import java.io.IOException; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import jdk.net.*; +import static sun.net.ExtendedOptionsImpl.*; /* * On Unix systems we simply delegate to native methods. @@ -38,6 +43,42 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl init(); } + protected void setOption(SocketOption name, T value) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + super.setOption(name, value); + } else { + if (isClosed()) { + throw new SocketException("Socket closed"); + } + checkSetOptionPermission(name); + checkValueType(value, SocketFlow.class); + setFlowOption(getFileDescriptor(), (SocketFlow)value); + } + } + + protected T getOption(SocketOption name) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + return super.getOption(name); + } + if (isClosed()) { + throw new SocketException("Socket closed"); + } + checkGetOptionPermission(name); + SocketFlow flow = SocketFlow.create(); + getFlowOption(getFileDescriptor(), flow); + return (T)flow; + } + + protected Set> supportedOptions() { + HashSet> options = new HashSet( + super.supportedOptions()); + + if (flowSupported()) { + options.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + return options; + } + protected synchronized native void bind0(int lport, InetAddress laddr) throws SocketException; diff --git a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java index 4846689a3e2..b0dfd0255dd 100644 --- a/jdk/src/solaris/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/solaris/classes/java/net/PlainSocketImpl.java @@ -26,6 +26,12 @@ package java.net; import java.io.IOException; import java.io.FileDescriptor; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import jdk.net.*; + +import static sun.net.ExtendedOptionsImpl.*; /* * On Unix systems we simply delegate to native methods. @@ -51,6 +57,42 @@ class PlainSocketImpl extends AbstractPlainSocketImpl this.fd = fd; } + protected void setOption(SocketOption name, T value) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + super.setOption(name, value); + } else { + if (isClosedOrPending()) { + throw new SocketException("Socket closed"); + } + checkSetOptionPermission(name); + checkValueType(value, SocketFlow.class); + setFlowOption(getFileDescriptor(), (SocketFlow)value); + } + } + + protected T getOption(SocketOption name) throws IOException { + if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { + return super.getOption(name); + } + if (isClosedOrPending()) { + throw new SocketException("Socket closed"); + } + checkGetOptionPermission(name); + SocketFlow flow = SocketFlow.create(); + getFlowOption(getFileDescriptor(), flow); + return (T)flow; + } + + protected Set> supportedOptions() { + HashSet> options = new HashSet( + super.supportedOptions()); + + if (getSocket() != null && flowSupported()) { + options.add(ExtendedSocketOptions.SO_FLOW_SLA); + } + return options; + } + native void socketCreate(boolean isServer) throws IOException; native void socketConnect(InetAddress address, int port, int timeout) @@ -77,5 +119,4 @@ class PlainSocketImpl extends AbstractPlainSocketImpl native int socketGetOption(int opt, Object iaContainerObj) throws SocketException; native void socketSendUrgentData(int data) throws IOException; - } diff --git a/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c new file mode 100644 index 00000000000..086ac9f9dc6 --- /dev/null +++ b/jdk/src/solaris/native/java/net/ExtendedOptionsImpl.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2014, 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 +#include + +#include "net_util.h" +#include "jdk_net_SocketFlow.h" + +static jclass sf_status_class; /* Status enum type */ + +static jfieldID sf_status; +static jfieldID sf_priority; +static jfieldID sf_bandwidth; + +static jfieldID sf_fd_fdID; /* FileDescriptor.fd */ + +/* References to the literal enum values */ + +static jobject sfs_NOSTATUS; +static jobject sfs_OK; +static jobject sfs_NOPERMISSION; +static jobject sfs_NOTCONNECTED; +static jobject sfs_NOTSUPPORTED; +static jobject sfs_ALREADYCREATED; +static jobject sfs_INPROGRESS; +static jobject sfs_OTHER; + +static jobject getEnumField(JNIEnv *env, char *name); +static void setStatus(JNIEnv *env, jobject obj, int errval); + +/* OS specific code is implemented in these three functions */ + +static jboolean flowSupported0() ; + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init + (JNIEnv *env, jclass UNUSED) +{ + static int initialized = 0; + jclass c; + + /* Global class references */ + + if (initialized) { + return; + } + + c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status"); + CHECK_NULL(c); + sf_status_class = (*env)->NewGlobalRef(env, c); + CHECK_NULL(sf_status_class); + + /* int "fd" field of java.io.FileDescriptor */ + + c = (*env)->FindClass(env, "java/io/FileDescriptor"); + CHECK_NULL(c); + sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I"); + CHECK_NULL(sf_fd_fdID); + + + /* SocketFlow fields */ + + c = (*env)->FindClass(env, "jdk/net/SocketFlow"); + + /* status */ + + sf_status = (*env)->GetFieldID(env, c, "status", + "Ljdk/net/SocketFlow$Status;"); + CHECK_NULL(sf_status); + + /* priority */ + + sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); + CHECK_NULL(sf_priority); + + /* bandwidth */ + + sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); + CHECK_NULL(sf_bandwidth); + + /* Initialize the static enum values */ + + sfs_NOSTATUS = getEnumField(env, "NO_STATUS"); + CHECK_NULL(sfs_NOSTATUS); + sfs_OK = getEnumField(env, "OK"); + CHECK_NULL(sfs_OK); + sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION"); + CHECK_NULL(sfs_NOPERMISSION); + sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED"); + CHECK_NULL(sfs_NOTCONNECTED); + sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED"); + CHECK_NULL(sfs_NOTSUPPORTED); + sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED"); + CHECK_NULL(sfs_ALREADYCREATED); + sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS"); + CHECK_NULL(sfs_INPROGRESS); + sfs_OTHER = getEnumField(env, "OTHER"); + CHECK_NULL(sfs_OTHER); + initialized = JNI_TRUE; +} + +static jobject getEnumField(JNIEnv *env, char *name) +{ + jobject f; + jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name, + "Ljdk/net/SocketFlow$Status;"); + CHECK_NULL_RETURN(fID, NULL); + + f = (*env)->GetStaticObjectField(env, sf_status_class, fID); + CHECK_NULL_RETURN(f, NULL); + f = (*env)->NewGlobalRef(env, f); + CHECK_NULL_RETURN(f, NULL); + return f; +} + +/* + * Retrieve the int file-descriptor from a public socket type object. + * Gets impl, then the FileDescriptor from the impl, and then the fd + * from that. + */ +static int getFD(JNIEnv *env, jobject fileDesc) { + return (*env)->GetIntField(env, fileDesc, sf_fd_fdID); +} + +/** + * Sets the status field of a SocketFlow to one of the + * canned enum values + */ +static void setStatus (JNIEnv *env, jobject obj, int errval) +{ + switch (errval) { + case 0: /* OK */ + (*env)->SetObjectField(env, obj, sf_status, sfs_OK); + break; + case EPERM: + (*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION); + break; + case ENOTCONN: + (*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED); + break; + case EOPNOTSUPP: + (*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED); + break; + case EALREADY: + (*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED); + break; + case EINPROGRESS: + (*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS); + break; + default: + (*env)->SetObjectField(env, obj, sf_status, sfs_OTHER); + break; + } +} + +#ifdef __solaris__ + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: setFlowOption + * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + int fd = getFD(env, fileDesc); + + if (fd < 0) { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); + return; + } else { + sock_flow_props_t props; + jlong bandwidth; + int rv; + + jint priority = (*env)->GetIntField(env, flow, sf_priority); + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; + + if (priority != jdk_net_SocketFlow_UNSET) { + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = priority; + } + bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth); + if (bandwidth > -1) { + props.sfp_mask |= SFP_MAXBW; + props.sfp_maxbw = (uint64_t) bandwidth; + } + rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", + "set option SO_FLOW_SLA failed"); + } + return; + } + setStatus(env, flow, props.sfp_status); + } +} + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: getFlowOption + * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + int fd = getFD(env, fileDesc); + + if (fd < 0) { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); + return; + } else { + sock_flow_props_t props; + int status; + socklen_t sz = sizeof(props); + + int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", + "set option SO_FLOW_SLA failed"); + } + return; + } + /* first check status to see if flow exists */ + status = props.sfp_status; + setStatus(env, flow, status); + if (status == 0) { /* OK */ + /* can set the other fields now */ + if (props.sfp_mask & SFP_PRIORITY) { + (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); + } + if (props.sfp_mask & SFP_MAXBW) { + (*env)->SetLongField(env, flow, sf_bandwidth, + (jlong)props.sfp_maxbw); + } + } + } +} + +static jboolean flowsupported; +static jboolean flowsupported_set = JNI_FALSE; + +static jboolean flowSupported0() +{ + /* Do a simple dummy call, and try to figure out from that */ + sock_flow_props_t props; + int rv, s; + if (flowsupported_set) { + return flowsupported; + } + s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s < 0) { + flowsupported = JNI_FALSE; + flowsupported_set = JNI_TRUE; + return JNI_FALSE; + } + memset(&props, 0, sizeof(props)); + props.sfp_version = SOCK_FLOW_PROP_VERSION1; + props.sfp_mask |= SFP_PRIORITY; + props.sfp_priority = SFP_PRIO_NORMAL; + rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); + if (rv != 0 && errno == ENOPROTOOPT) { + rv = JNI_FALSE; + } else { + rv = JNI_TRUE; + } + close(s); + flowsupported = rv; + flowsupported_set = JNI_TRUE; + return flowsupported; +} + +#else /* __solaris__ */ + +/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +static jboolean flowSupported0() { + return JNI_FALSE; +} + +#endif /* __solaris__ */ + +JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported + (JNIEnv *env, jclass UNUSED) +{ + return flowSupported0(); +} diff --git a/jdk/src/solaris/native/java/net/net_util_md.h b/jdk/src/solaris/native/java/net/net_util_md.h index e7150da6018..31ed3f808eb 100644 --- a/jdk/src/solaris/native/java/net/net_util_md.h +++ b/jdk/src/solaris/native/java/net/net_util_md.h @@ -107,6 +107,47 @@ int getDefaultIPv6Interface(struct in6_addr *target_addr); #ifdef __solaris__ int net_getParam(char *driver, char *param); + +#ifndef SO_FLOW_SLA +#define SO_FLOW_SLA 0x1018 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack(4) #endif +/* + * Used with the setsockopt(SO_FLOW_SLA, ...) call to set + * per socket service level properties. + * When the application uses per-socket API, we will enforce the properties + * on both outbound and inbound packets. + * + * For now, only priority and maxbw are supported in SOCK_FLOW_PROP_VERSION1. + */ +typedef struct sock_flow_props_s { + int sfp_version; + uint32_t sfp_mask; + int sfp_priority; /* flow priority */ + uint64_t sfp_maxbw; /* bandwidth limit in bps */ + int sfp_status; /* flow create status for getsockopt */ +} sock_flow_props_t; + +#define SOCK_FLOW_PROP_VERSION1 1 + +/* bit mask values for sfp_mask */ +#define SFP_MAXBW 0x00000001 /* Flow Bandwidth Limit */ +#define SFP_PRIORITY 0x00000008 /* Flow priority */ + +/* possible values for sfp_priority */ +#define SFP_PRIO_NORMAL 1 +#define SFP_PRIO_HIGH 2 + +#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 +#pragma pack() +#endif /* _LONG_LONG_ALIGNMENT */ + +#endif /* SO_FLOW_SLA */ +#endif /* __solaris__ */ + +JNIEXPORT jboolean JNICALL NET_IsFlowSupported(); + #endif /* NET_UTILS_MD_H */ diff --git a/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c new file mode 100644 index 00000000000..2bd955cd13e --- /dev/null +++ b/jdk/src/windows/native/java/net/ExtendedOptionsImpl.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 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 +#include + +#include "net_util.h" + +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init + (JNIEnv *env, jclass UNUSED) +{ +} + +/* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */ + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +static jboolean flowSupported0() { + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported + (JNIEnv *env, jclass UNUSED) +{ + return JNI_FALSE; +} diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 12b1ba79322..1d5895044da 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -102,7 +102,8 @@ jdk_nio = \ jdk_net = \ java/net \ com/sun/net/httpserver \ - sun/net + sun/net \ + jdk/net jdk_time = \ java/time @@ -284,7 +285,7 @@ jdk_stable = \ javax/accessibility \ com/sun/java/swing \ sun/pisces \ - com/sun/awt + com/sun/awt ############################################################################### @@ -294,7 +295,7 @@ jdk_stable = \ # - compact1, compact2, compact3, full JRE, JDK # # In addition they support testing of the minimal VM on compact1 and compact2. -# Essentially this defines groups based around the specified API's and VM +# Essentially this defines groups based around the specified API's and VM # services available in the runtime. # # The groups are defined hierarchically in two forms: @@ -506,7 +507,7 @@ compact2 = \ -:needs_jdk # Tests that require compact2 API's and a full VM -# +# needs_full_vm_compact2 = # Minimal VM on Compact 2 adds in some compact2 tests @@ -590,7 +591,7 @@ needs_compact2 = \ javax/crypto/Cipher/CipherStreamClose.java \ sun/misc/URLClassPath/ClassnameCharTest.java \ sun/net/www/protocol/https/HttpsURLConnection/HttpsCreateSockTest.java \ - sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java + sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java # Compact 1 adds full VM tests # diff --git a/jdk/test/java/net/SocketOption/OptionsTest.java b/jdk/test/java/net/SocketOption/OptionsTest.java new file mode 100644 index 00000000000..f0952fc8377 --- /dev/null +++ b/jdk/test/java/net/SocketOption/OptionsTest.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014, 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 8036979 + * @run main/othervm -Xcheck:jni OptionsTest + */ + +import java.net.*; +import java.util.*; + +public class OptionsTest { + + static class Test { + Test(SocketOption option, Object testValue) { + this.option = option; + this.testValue = testValue; + } + static Test create (SocketOption option, Object testValue) { + return new Test(option, testValue); + } + Object option; + Object testValue; + }; + + // The tests set the option using the new API, read back the set value + // which could be diferent, and then use the legacy get API to check + // these values are the same + + static Test[] socketTests = new Test[] { + Test.create(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE), + Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), + Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), + Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)), + Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) + }; + + static Test[] serverSocketTests = new Test[] { + Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), + Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE) + }; + + static Test[] dgSocketTests = new Test[] { + Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), + Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), + Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) + }; + + static Test[] mcSocketTests = new Test[] { + Test.create(StandardSocketOptions.IP_MULTICAST_IF, getNetworkInterface()), + Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(10)), + Test.create(StandardSocketOptions.IP_MULTICAST_LOOP, Boolean.TRUE) + }; + + static NetworkInterface getNetworkInterface() { + try { + Enumeration nifs = NetworkInterface.getNetworkInterfaces(); + if (nifs.hasMoreElements()) { + return (NetworkInterface)nifs.nextElement(); + } + } catch (Exception e) { + } + return null; + } + + static void doSocketTests() throws Exception { + try ( + ServerSocket srv = new ServerSocket(0); + Socket c = new Socket("127.0.0.1", srv.getLocalPort()); + Socket s = srv.accept(); + ) { + for (int i=0; i type, Object s, Object option) + + throws Exception + { + if (type.equals(Socket.class)) { + Socket socket = (Socket)s; + + if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) { + return Boolean.valueOf(socket.getKeepAlive()); + } else if (option.equals(StandardSocketOptions.SO_SNDBUF)) { + return Integer.valueOf(socket.getSendBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.SO_LINGER)) { + return Integer.valueOf(socket.getSoLinger()); + } else if (option.equals(StandardSocketOptions.IP_TOS)) { + return Integer.valueOf(socket.getTrafficClass()); + } else if (option.equals(StandardSocketOptions.TCP_NODELAY)) { + return Boolean.valueOf(socket.getTcpNoDelay()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + } else if (type.equals(ServerSocket.class)) { + ServerSocket socket = (ServerSocket)s; + if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + } else if (type.equals(DatagramSocket.class)) { + DatagramSocket socket = (DatagramSocket)s; + + if (option.equals(StandardSocketOptions.SO_SNDBUF)) { + return Integer.valueOf(socket.getSendBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.IP_TOS)) { + return Integer.valueOf(socket.getTrafficClass()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + + } else if (type.equals(MulticastSocket.class)) { + MulticastSocket socket = (MulticastSocket)s; + + if (option.equals(StandardSocketOptions.SO_SNDBUF)) { + return Integer.valueOf(socket.getSendBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { + return Integer.valueOf(socket.getReceiveBufferSize()); + } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { + return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.IP_TOS)) { + return Integer.valueOf(socket.getTrafficClass()); + } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) { + return socket.getNetworkInterface(); + } else if (option.equals(StandardSocketOptions.IP_MULTICAST_TTL)) { + return Integer.valueOf(socket.getTimeToLive()); + } else if (option.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) { + return Boolean.valueOf(socket.getLoopbackMode()); + } else { + throw new RuntimeException("unexecpted socket option"); + } + } + throw new RuntimeException("unexecpted socket type"); + } + + public static void main(String args[]) throws Exception { + doSocketTests(); + doServerSocketTests(); + doDgSocketTests(); + doMcSocketTests(); + } +} diff --git a/jdk/test/jdk/net/Sockets/Test.java b/jdk/test/jdk/net/Sockets/Test.java new file mode 100644 index 00000000000..da609bf7501 --- /dev/null +++ b/jdk/test/jdk/net/Sockets/Test.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, 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 8032808 + * @run main/othervm -Xcheck:jni Test + * @run main/othervm/policy=policy.fail -Xcheck:jni Test fail + * @run main/othervm/policy=policy.success -Xcheck:jni Test success + */ + +import java.net.*; +import java.nio.channels.*; +import java.util.concurrent.*; +import jdk.net.*; + +public class Test { + + static boolean security; + static boolean success; + + interface Runner { + public void run() throws Exception; + } + + public static void main(String[] args) throws Exception { + + // quick check to see if supportedOptions() working before + // creating any sockets and libnet loaded + + Sockets.supportedOptions(Socket.class); + + security = System.getSecurityManager() != null; + success = security && args[0].equals("success"); + + // Main thing is to check for JNI problems + // Doesn't matter if current system does not support the option + // and currently setting the option with the loopback interface + // doesn't work either + + System.out.println ("Security Manager enabled: " + security); + if (security) { + System.out.println ("Success expected: " + success); + } + + final SocketFlow flowIn = SocketFlow.create() + .bandwidth(1000) + .priority(SocketFlow.HIGH_PRIORITY); + + ServerSocket ss = new ServerSocket(0); + int tcp_port = ss.getLocalPort(); + final InetAddress loop = InetAddress.getByName("127.0.0.1"); + final InetSocketAddress loopad = new InetSocketAddress(loop, tcp_port); + + DatagramSocket dg = new DatagramSocket(0); + final int udp_port = dg.getLocalPort(); + + final Socket s = new Socket("127.0.0.1", tcp_port); + final SocketChannel sc = SocketChannel.open(); + sc.connect (new InetSocketAddress("127.0.0.1", tcp_port)); + + doTest(()->{ + Sockets.setOption(s, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + Sockets.getOption(s, ExtendedSocketOptions.SO_FLOW_SLA); + }); + doTest(()->{ + sc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + sc.getOption(ExtendedSocketOptions.SO_FLOW_SLA); + }); + doTest(()->{ + DatagramSocket dg1 = new DatagramSocket(0); + dg1.connect(loop, udp_port); + Sockets.setOption(dg1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + DatagramChannel dg2 = DatagramChannel.open(); + dg2.bind(new InetSocketAddress(loop, 0)); + dg2.connect(new InetSocketAddress(loop, udp_port)); + dg2.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + MulticastSocket mc1 = new MulticastSocket(0); + mc1.connect(loop, udp_port); + Sockets.setOption(mc1, ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + doTest(()->{ + AsynchronousSocketChannel asc = AsynchronousSocketChannel.open(); + Future f = asc.connect(loopad); + f.get(); + asc.setOption(ExtendedSocketOptions.SO_FLOW_SLA, flowIn); + }); + } + + static void doTest(Runner func) throws Exception { + try { + func.run(); + if (security && !success) { + throw new RuntimeException("Test failed"); + } + } catch (SecurityException e) { + if (success) { + throw new RuntimeException("Test failed"); + } + } catch (UnsupportedOperationException e) {} + } +} diff --git a/jdk/test/jdk/net/Sockets/policy.fail b/jdk/test/jdk/net/Sockets/policy.fail new file mode 100644 index 00000000000..29d1215e708 --- /dev/null +++ b/jdk/test/jdk/net/Sockets/policy.fail @@ -0,0 +1,4 @@ +grant { + permission java.net.SocketPermission "127.0.0.1", "connect,accept" ; + permission java.net.SocketPermission "localhost", "listen" ; +}; diff --git a/jdk/test/jdk/net/Sockets/policy.success b/jdk/test/jdk/net/Sockets/policy.success new file mode 100644 index 00000000000..6f99151a38f --- /dev/null +++ b/jdk/test/jdk/net/Sockets/policy.success @@ -0,0 +1,6 @@ +grant { + permission java.net.SocketPermission "127.0.0.1", "connect,accept" ; + permission java.net.SocketPermission "localhost", "listen" ; + permission jdk.net.NetworkPermission "setOption.SO_FLOW_SLA"; + permission jdk.net.NetworkPermission "getOption.SO_FLOW_SLA"; +}; From 8decb5de90d313b1441f7b0bc3ed2668e59d6c33 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Sat, 12 Apr 2014 14:38:50 -0700 Subject: [PATCH 167/170] 8039751: UTF-8 decoder fails to handle some edge cases correctly To update decoder.isMalformed4_2() to correctly detect out of range 2nd byte Reviewed-by: alanb --- jdk/src/share/classes/sun/nio/cs/UTF_8.java | 23 ++++++++++---- jdk/test/sun/nio/cs/TestUTF8.java | 33 +++++++++++++++++++-- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/classes/sun/nio/cs/UTF_8.java b/jdk/src/share/classes/sun/nio/cs/UTF_8.java index bfb7b7a977b..3ee2341f000 100644 --- a/jdk/src/share/classes/sun/nio/cs/UTF_8.java +++ b/jdk/src/share/classes/sun/nio/cs/UTF_8.java @@ -111,12 +111,18 @@ class UTF_8 extends Unicode (b4 & 0xc0) != 0x80; } - // only used when there is less than 4 bytes left in src buffer + // only used when there is less than 4 bytes left in src buffer. + // both b1 and b2 should be "& 0xff" before passed in. private static boolean isMalformed4_2(int b1, int b2) { - return (b1 == 0xf0 && b2 == 0x90) || + return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || (b2 & 0xc0) != 0x80; } + // tests if b1 and b2 are malformed as the first 2 bytes of a + // legal`4-byte utf-8 byte sequence. + // only used when there is less than 4 bytes left in src buffer, + // after isMalformed4_2 has been invoked. private static boolean isMalformed4_3(int b3) { return (b3 & 0xc0) != 0x80; } @@ -280,7 +286,9 @@ class UTF_8 extends Unicode // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int srcRemaining = sl - sp; if (srcRemaining < 4 || dl - dp < 2) { - if (srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1])) + b1 &= 0xff; + if (b1 > 0xf4 || + srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1] & 0xff)) return malformedForLength(src, sp, dst, dp, 1); if (srcRemaining > 2 && isMalformed4_3(sa[sp + 2])) return malformedForLength(src, sp, dst, dp, 2); @@ -363,7 +371,9 @@ class UTF_8 extends Unicode // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int srcRemaining = limit - mark; if (srcRemaining < 4 || dst.remaining() < 2) { - if (srcRemaining > 1 && isMalformed4_2(b1, src.get())) + b1 &= 0xff; + if (b1 > 0xf4 || + srcRemaining > 1 && isMalformed4_2(b1, src.get() & 0xff)) return malformedForLength(src, mark, 1); if (srcRemaining > 2 && isMalformed4_3(src.get())) return malformedForLength(src, mark, 2); @@ -518,8 +528,9 @@ class UTF_8 extends Unicode } if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; - - if (sp < sl && isMalformed4_2(b1, sa[sp])) { + b1 &= 0xff; + if (b1 > 0xf4 || + sp < sl && isMalformed4_2(b1, sa[sp] & 0xff)) { da[dp++] = replacement().charAt(0); continue; } diff --git a/jdk/test/sun/nio/cs/TestUTF8.java b/jdk/test/sun/nio/cs/TestUTF8.java index c54ae66f4d9..010fbf17b43 100644 --- a/jdk/test/sun/nio/cs/TestUTF8.java +++ b/jdk/test/sun/nio/cs/TestUTF8.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4486841 7040220 7096080 + * @bug 4486841 7040220 7096080 8039751 * @summary Test UTF-8 charset */ @@ -291,14 +291,18 @@ public class TestUTF8 { {1, (byte)0xE0, (byte)0xC0, (byte)0xBF }, // invalid second byte {2, (byte)0xE0, (byte)0xA0, (byte)0x7F }, // invalid third byte {2, (byte)0xE0, (byte)0xA0, (byte)0xC0 }, // invalid third byte + {2, (byte)0xE1, (byte)0x80, (byte)0x42}, // invalid third byte + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones {1, (byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte {1, (byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid first byte {1, (byte)0xE0, (byte)0x41,}, // invalid second byte & 2 bytes + {1, (byte)0xE1, (byte)0x40,}, // invalid second byte & 2 bytes {3, (byte)0xED, (byte)0xAE, (byte)0x80 }, // 3 bytes surrogate {3, (byte)0xED, (byte)0xB0, (byte)0x80 }, // 3 bytes surrogate + // Four-byte sequences {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded {1, (byte)0xF0, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded @@ -323,6 +327,32 @@ public class TestUTF8 { {1, (byte)0xF4, (byte)0xC0, (byte)0x80, (byte)0xC0 }, // out-range 4-byte {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + // #8039751 + {1, (byte)0xF6, (byte)0x80, (byte)0x80, (byte)0x80 }, // out-range 1st byte + {1, (byte)0xF6, (byte)0x80, (byte)0x80, }, + {1, (byte)0xF6, (byte)0x80, }, + {1, (byte)0xF6, }, + {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0x80 }, // out-range 1st byte + {1, (byte)0xF5, (byte)0x80, (byte)0x80, }, + {1, (byte)0xF5, (byte)0x80, }, + {1, (byte)0xF5 }, + + {1, (byte)0xF4, (byte)0x90, (byte)0x80, (byte)0x80 }, // out-range 2nd byte + {1, (byte)0xF4, (byte)0x90, (byte)0x80 }, + {1, (byte)0xF4, (byte)0x90 }, + + {1, (byte)0xF4, (byte)0x7f, (byte)0x80, (byte)0x80 }, // out-range/ascii 2nd byte + {1, (byte)0xF4, (byte)0x7f, (byte)0x80 }, + {1, (byte)0xF4, (byte)0x7f }, + + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // out-range 2nd byte + {1, (byte)0xF0, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF0, (byte)0x80 }, + + {1, (byte)0xF0, (byte)0xc0, (byte)0x80, (byte)0x80 }, // out-range 2nd byte + {1, (byte)0xF0, (byte)0xc0, (byte)0x80 }, + {1, (byte)0xF0, (byte)0xc0 }, + // Five-byte sequences {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded @@ -553,7 +583,6 @@ public class TestUTF8 { check4ByteSurrs("UTF-8"); checkMalformed("UTF-8", malformed); checkUnderOverflow("UTF-8"); - checkRoundtrip("CESU-8"); check6ByteSurrs("CESU-8"); checkMalformed("CESU-8", malformed_cesu8); From 6ca57a22cae70af57f7a06ecea0b61a1e004b289 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Wed, 2 Apr 2014 12:03:25 +0200 Subject: [PATCH 168/170] 8038963: com/sun/jdi tests fail because cygwin's ps sometimes misses processes Reviewed-by: dcubed, jbachorik --- jdk/test/com/sun/jdi/ShellScaffold.sh | 59 ++++++++++----------------- 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/jdk/test/com/sun/jdi/ShellScaffold.sh b/jdk/test/com/sun/jdi/ShellScaffold.sh index 16c41eae056..193aabcb907 100644 --- a/jdk/test/com/sun/jdi/ShellScaffold.sh +++ b/jdk/test/com/sun/jdi/ShellScaffold.sh @@ -199,30 +199,26 @@ findPid() return 1 fi - if [ -z "$isWin98" ] ; then - if [ "$osname" = SunOS ] ; then - # Solaris and OpenSolaris use pgrep and not ps in psCmd - findPidCmd="$psCmd" - elif [ "$osname" = AIX ] ; then - findPidCmd="$psCmd" - else + case "$osname" in + SunOS | AIX) + $psCmd | $grep '^ *'"$1 " > $devnull 2>&1 + res=$? + ;; + Windows* | CYGWIN*) + # Don't use ps on cygwin since it sometimes misses + # some processes (!). + tasklist /NH | $grep " $1 " > $devnull 2>&1 + res=$? + ;; + *) # Never use plain 'ps', which requires a "controlling terminal" # and will fail with a "ps: no controlling terminal" error. # Running under 'rsh' will cause this ps error. - # cygwin ps puts an I in column 1 for some reason. - findPidCmd="$psCmd -e" - fi - $findPidCmd | $grep '^I* *'"$1 " > $devnull 2>&1 - return $? - fi - - # mks 6.2a on win98 has $! getting a negative - # number and in ps, it shows up as 0x... - # Thus, we can't search in ps output for - # PIDs gotten via $! - # We don't know if it is running or not - assume it is. - # We don't really care about win98 anymore. - return 0 + $psCmd -e | $grep '^ *'"$1 " > $devnull 2>&1 + res=$? + ;; + esac + return $res } setup() @@ -252,16 +248,10 @@ setup() ulimitCmd= osname=`uname -s` - isWin98= isCygwin= case "$osname" in Windows* | CYGWIN*) devnull=NUL - if [ "$osname" = Windows_98 -o "$osname" = Windows_ME ]; then - isWin98=1 - debuggeeKeyword='we_cant_kill_debuggees_on_win98' - jdbKeyword='jdb\.exe' - fi case "$osname" in CYGWIN*) isCygwin=1 @@ -772,7 +762,7 @@ waitForJdbMsg() sleep ${sleep_seconds} findPid $topPid if [ $? != 0 ] ; then - # Top process is dead. We better die too + echo "--Top process ($topPid) is dead. We better die too" >&2 dojstack exit 1 fi @@ -977,19 +967,12 @@ waitForFinish() break fi - if [ ! -z "$isWin98" ] ; then - $psCmd | $grep -i 'JDB\.EXE' >$devnull 2>&1 - if [ $? != 0 ] ; then - break - fi - fi - # (Don't use jdbFailIfPresent here since it is not safe # to call from different processes) - $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1 - if [ $? = 0 ] ; then + $grep -s 'Input stream closed' $jdbOutFile > $devnull 2>&1 + if [ $? = 0 ] ; then dofail "jdb input stream closed prematurely" - fi + fi # If a failure has occured, quit if [ -r "$failFile" ] ; then From 998176c65e05e8f10a834d7a4ed858d5dff86bac Mon Sep 17 00:00:00 2001 From: Ivan Gerasimov Date: Mon, 14 Apr 2014 16:15:10 +0400 Subject: [PATCH 169/170] 8009637: Some error messages are missing a space Reviewed-by: alanb --- .../com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java | 2 +- jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java | 2 +- jdk/src/share/classes/java/util/logging/Logging.java | 2 +- jdk/src/share/classes/javax/naming/NameImpl.java | 2 +- jdk/src/windows/classes/sun/print/Win32PrintService.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java index d7acd36ae08..47b95927307 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java @@ -1220,7 +1220,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { throw new RuntimeOperationsException(new IllegalArgumentException(listener.getCanonicalName()), "The MBean " + listener.getCanonicalName() + - "does not implement the NotificationListener interface") ; + " does not implement the NotificationListener interface") ; } // ---------------- diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java b/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java index 7bb77cd52c6..50f6ac69f5f 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapAttribute.java @@ -188,7 +188,7 @@ final class LdapAttribute extends BasicAttribute { if(syntaxAttr == null || syntaxAttr.size() == 0) { throw new NameNotFoundException( - getID() + "does not have a syntax associated with it"); + getID() + " does not have a syntax associated with it"); } String syntaxName = (String)syntaxAttr.get(); diff --git a/jdk/src/share/classes/java/util/logging/Logging.java b/jdk/src/share/classes/java/util/logging/Logging.java index 740a533063d..88624fc83e2 100644 --- a/jdk/src/share/classes/java/util/logging/Logging.java +++ b/jdk/src/share/classes/java/util/logging/Logging.java @@ -87,7 +87,7 @@ class Logging implements LoggingMXBean { Logger logger = logManager.getLogger(loggerName); if (logger == null) { throw new IllegalArgumentException("Logger " + loggerName + - "does not exist"); + " does not exist"); } Level level = null; diff --git a/jdk/src/share/classes/javax/naming/NameImpl.java b/jdk/src/share/classes/javax/naming/NameImpl.java index f9643054dfe..65a67677677 100644 --- a/jdk/src/share/classes/javax/naming/NameImpl.java +++ b/jdk/src/share/classes/javax/naming/NameImpl.java @@ -232,7 +232,7 @@ class NameImpl { syntaxDirection = FLAT; } else { throw new IllegalArgumentException(syntaxDirectionStr + - "is not a valid value for the jndi.syntax.direction property"); + " is not a valid value for the jndi.syntax.direction property"); } if (syntaxDirection != FLAT) { diff --git a/jdk/src/windows/classes/sun/print/Win32PrintService.java b/jdk/src/windows/classes/sun/print/Win32PrintService.java index b8b4dfda1b5..6ddbdba969f 100644 --- a/jdk/src/windows/classes/sun/print/Win32PrintService.java +++ b/jdk/src/windows/classes/sun/print/Win32PrintService.java @@ -1585,7 +1585,7 @@ public class Win32PrintService implements PrintService, AttributeUpdater, if (flavor != null && !isDocFlavorSupported(flavor)) { throw new IllegalArgumentException("flavor " + flavor + - "is not supported"); + " is not supported"); } if (attributes == null) { From 34ace4a41ae76cab5f4f2e9ea63450c0298695df Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Mon, 14 Apr 2014 13:40:45 +0000 Subject: [PATCH 170/170] 8040062: Need to add new methods in BaseSSLSocketImpl Reviewed-by: mullan --- .../sun/security/ssl/BaseSSLSocketImpl.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java index 240bc052d47..d816a580ae4 100644 --- a/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java @@ -28,6 +28,7 @@ package sun.security.ssl; import java.io.*; import java.nio.channels.SocketChannel; import java.net.*; +import java.util.Set; import javax.net.ssl.*; @@ -634,6 +635,34 @@ abstract class BaseSSLSocketImpl extends SSLSocket { } } + @Override + public Socket setOption(SocketOption name, + T value) throws IOException { + if (self == this) { + return super.setOption(name, value); + } else { + return self.setOption(name, value); + } + } + + @Override + public T getOption(SocketOption name) throws IOException { + if (self == this) { + return super.getOption(name); + } else { + return self.getOption(name); + } + } + + @Override + public Set> supportedOptions() { + if (self == this) { + return super.supportedOptions(); + } else { + return self.supportedOptions(); + } + } + boolean isLayered() { return (self != this); }